001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2011 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    package org.granite.cdi;
021    
022    import java.lang.reflect.Method;
023    
024    import javax.enterprise.context.Conversation;
025    import javax.enterprise.inject.spi.Bean;
026    import javax.enterprise.inject.spi.BeanManager;
027    import javax.servlet.http.HttpSession;
028    
029    import org.granite.context.GraniteContext;
030    import org.granite.logging.Logger;
031    import org.granite.messaging.webapp.HttpGraniteContext;
032    import org.granite.util.TypeUtil;
033    import org.jboss.weld.bootstrap.api.Service;
034    import org.jboss.weld.manager.api.WeldManager;
035    
036    
037    public class Weld10ConversationManager implements CDIConversationManager {
038            
039            private static final Logger log = Logger.getLogger(Weld10ConversationManager.class);
040            
041            private Class<?> conversationManagerClass;
042            private Class<Service> contextLifecycleClass;
043            
044            @SuppressWarnings("unchecked")
045            public Weld10ConversationManager() {
046                    try {
047                            conversationManagerClass = TypeUtil.forName("org.jboss.weld.conversation.ConversationManager");
048                            contextLifecycleClass = (Class<Service>)TypeUtil.forName("org.jboss.weld.context.ContextLifecycle");
049                    }
050                    catch (Exception e) {
051                            log.error(e, "Could not load ConversationManager class");
052                    }
053            }
054    
055            public Conversation initConversation(BeanManager beanManager, String conversationId) {
056                    try {
057                        Bean<?> conversationManagerBean = beanManager.getBeans(conversationManagerClass).iterator().next();
058                        Object conversationManager = beanManager.getReference(conversationManagerBean, conversationManagerClass, beanManager.createCreationalContext(conversationManagerBean));
059                        conversationManagerClass.getMethod("beginOrRestoreConversation", String.class).invoke(conversationManager, conversationId);
060                        
061                        @SuppressWarnings("unchecked")
062                        Bean<Conversation> conversationBean = (Bean<Conversation>)beanManager.getBeans(Conversation.class).iterator().next();
063                        Conversation conversation = (Conversation)beanManager.getReference(conversationBean, Conversation.class, beanManager.createCreationalContext(conversationBean)); 
064                        
065                        HttpGraniteContext context = (HttpGraniteContext)GraniteContext.getCurrentInstance();
066                        String cid = (String)conversation.getClass().getMethod("getUnderlyingId").invoke(conversation);
067                        Object conversationContext = lookupConversationContext((WeldManager)beanManager);
068                        Object beanStore = TypeUtil.newInstance("org.jboss.weld.servlet.ConversationBeanStore", new Class<?>[] { HttpSession.class, boolean.class, String.class },
069                                    new Object[] { context.getSession(true), false, cid });
070                        for (Method m : conversationContext.getClass().getMethods()) {
071                            if ("setBeanStore".equals(m.getName())) {
072                                    m.invoke(conversationContext, beanStore);
073                                    break;
074                            }
075                        }
076                        conversationContext.getClass().getMethod("setActive", boolean.class).invoke(conversationContext, true);
077                        return conversation;
078                    }
079                    catch (Exception e) {
080                            throw new RuntimeException("Could not init conversation", e);
081                    }
082            }
083            
084            public void destroyConversation(BeanManager beanManager) {
085            try {
086                        Object conversationContext = lookupConversationContext((WeldManager)beanManager);
087                        if ((Boolean)conversationContext.getClass().getMethod("isActive").invoke(conversationContext)) {
088                                Bean<?> conversationManagerBean = beanManager.getBeans(conversationManagerClass).iterator().next();
089                                Object conversationManager = beanManager.getReference(conversationManagerBean, conversationManagerClass, beanManager.createCreationalContext(conversationManagerBean));
090                                conversationManagerClass.getMethod("cleanupConversation").invoke(conversationManager);
091                    }
092                }
093                    catch (Exception e) {
094                            throw new RuntimeException("Could not destroy conversation", e);
095                    }
096            }
097            
098            private Object lookupConversationContext(WeldManager beanManager) throws Exception {
099                    Object contextLifecycle = beanManager.getServices().get(contextLifecycleClass);         
100                return contextLifecycle.getClass().getMethod("getConversationContext").invoke(contextLifecycle);
101            }
102    }