001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2007-2010 ADEQUATE SYSTEMS SARL
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    
021    package org.granite.cdi;
022    
023    import javax.enterprise.context.Conversation;
024    import javax.enterprise.inject.spi.Bean;
025    import javax.naming.InitialContext;
026    import javax.naming.NameNotFoundException;
027    import javax.servlet.http.HttpSession;
028    
029    import org.granite.context.GraniteContext;
030    import org.granite.logging.Logger;
031    import org.granite.messaging.amf.process.AMF3MessageInterceptor;
032    import org.granite.messaging.service.ServiceException;
033    import org.granite.messaging.webapp.HttpGraniteContext;
034    import org.granite.tide.cdi.ConversationState;
035    import org.granite.tide.cdi.EventState;
036    import org.granite.tide.cdi.SessionState;
037    import org.jboss.weld.context.ContextLifecycle;
038    import org.jboss.weld.context.ConversationContext;
039    import org.jboss.weld.conversation.ConversationImpl;
040    import org.jboss.weld.conversation.ConversationManager;
041    import org.jboss.weld.manager.api.WeldManager;
042    import org.jboss.weld.servlet.ConversationBeanStore;
043    
044    import flex.messaging.messages.Message;
045    
046    
047    public class CDIInterceptor implements AMF3MessageInterceptor {
048            
049            private static final Logger log = Logger.getLogger(CDIInterceptor.class);
050    
051        private static final String CONVERSATION_ID = "conversationId";
052        private static final String IS_LONG_RUNNING_CONVERSATION = "isLongRunningConversation";
053        private static final String WAS_LONG_RUNNING_CONVERSATION_CREATED = "wasLongRunningConversationCreated";
054        private static final String WAS_LONG_RUNNING_CONVERSATION_ENDED = "wasLongRunningConversationEnded";
055        
056        
057        public static WeldManager lookupBeanManager() {
058                    HttpGraniteContext context = (HttpGraniteContext)GraniteContext.getCurrentInstance();
059                    WeldManager manager = (WeldManager)context.getServletContext().getAttribute("javax.enterprise.inject.spi.BeanManager");
060                    if (manager != null)
061                            return manager;
062                    
063                    InitialContext ic = null;
064                try {
065                            ic = new InitialContext();
066                    // Standard JNDI binding
067                    return (WeldManager)ic.lookup("java:comp/BeanManager");
068                }
069                catch (NameNotFoundException e) {
070                    if (ic == null)
071                            throw new RuntimeException("No InitialContext");
072                    
073                    // Weld/Tomcat
074                    try {
075                            return (WeldManager)ic.lookup("java:comp/env/BeanManager"); 
076                    }
077                    catch (Exception e1) {          
078                            // JBoss 5/6 (maybe obsolete in Weld 1.0+)
079                            try {
080                                    return (WeldManager)ic.lookup("java:app/BeanManager");
081                            }
082                        catch (Exception e2) {
083                            throw new RuntimeException("Could not find Bean Manager", e2);
084                        }
085                    }
086                }
087                catch (Exception e) {
088                    throw new RuntimeException("Could not find Bean Manager", e);
089                }
090        }
091        
092        
093            public void before(Message amfReqMessage) {
094                    if (log.isTraceEnabled())
095                            log.trace("Pre processing of request message: %s", amfReqMessage);
096    
097                    try {
098                            GraniteContext context = GraniteContext.getCurrentInstance();
099                            
100                            if (context instanceof HttpGraniteContext) {
101                            // Initialize CDI Context
102                                    HttpSession session = ((HttpGraniteContext)context).getSession();
103                                WeldManager beanManager = lookupBeanManager();
104                                @SuppressWarnings("unchecked")
105                                Bean<ConversationManager> conversationManagerBean = (Bean<ConversationManager>)beanManager.getBeans(ConversationManager.class).iterator().next();
106                                ConversationManager conversationManager = (ConversationManager)beanManager.getReference(conversationManagerBean, ConversationManager.class, beanManager.createCreationalContext(conversationManagerBean));
107                                
108                                String conversationId = (String)amfReqMessage.getHeader(CONVERSATION_ID);
109                                conversationManager.beginOrRestoreConversation(conversationId);
110                                @SuppressWarnings("unchecked")
111                                Bean<Conversation> conversationBean = (Bean<Conversation>)beanManager.getBeans(Conversation.class).iterator().next();
112                                Conversation conversation = (Conversation)beanManager.getReference(conversationBean, Conversation.class, beanManager.createCreationalContext(conversationBean)); 
113                                
114                                String cid = ((ConversationImpl)conversation).getUnderlyingId();
115                                ConversationContext conversationContext = lookupConversationContext(beanManager);
116                                conversationContext.setBeanStore(new ConversationBeanStore(session, false, cid));
117                                conversationContext.setActive(true);
118                                
119                                @SuppressWarnings("unchecked")
120                                Bean<EventState> eventBean = (Bean<EventState>)beanManager.getBeans(EventState.class).iterator().next();
121                                EventState eventState = (EventState)beanManager.getReference(eventBean, EventState.class, beanManager.createCreationalContext(eventBean));
122                                if (!conversation.isTransient())
123                                    eventState.setWasLongRunning(true);
124                                
125                                if (conversationId != null && conversation.isTransient()) {
126                                    log.debug("Starting conversation " + conversationId);
127                                    conversation.begin(conversationId);
128                                }
129                                    
130                            if (Boolean.TRUE.toString().equals(amfReqMessage.getHeader("org.granite.tide.isFirstCall"))) {
131                                    @SuppressWarnings("unchecked")
132                                    Bean<SessionState> ssBean = (Bean<SessionState>)beanManager.getBeans(SessionState.class).iterator().next();
133                                    ((SessionState)beanManager.getReference(ssBean, SessionState.class, beanManager.createCreationalContext(ssBean))).setFirstCall(true);
134                            }
135                                    
136                            if (Boolean.TRUE.toString().equals(amfReqMessage.getHeader("org.granite.tide.isFirstConversationCall")) && !conversation.isTransient()) {
137                                    @SuppressWarnings("unchecked")
138                                    Bean<ConversationState> csBean = (Bean<ConversationState>)beanManager.getBeans(ConversationState.class).iterator().next();
139                                    ((ConversationState)beanManager.getReference(csBean, ConversationState.class, beanManager.createCreationalContext(csBean))).setFirstCall(true);
140                            }
141                            }
142                    }
143                    catch(Exception e) {
144                log.error(e, "Exception while pre processing the request message.");
145                throw new ServiceException("Error while pre processing the request message - " + e.getMessage());
146                    }
147            }
148    
149    
150            public void after(Message amfReqMessage, Message amfRespMessage) {              
151                    try {
152                            if (log.isTraceEnabled())
153                                    log.trace("Post processing of response message: %s", amfReqMessage);
154    
155                            if (GraniteContext.getCurrentInstance() instanceof HttpGraniteContext) {
156                                WeldManager beanManager = lookupBeanManager();
157                                    try {
158                                            // Add conversation management headers to response
159                                            if (amfRespMessage != null) {
160                                                @SuppressWarnings("unchecked")
161                                                Bean<Conversation> conversationBean = (Bean<Conversation>)beanManager.getBeans(Conversation.class).iterator().next();
162                                                Conversation conversation = (Conversation)beanManager.getReference(conversationBean, Conversation.class, beanManager.createCreationalContext(conversationBean));
163                                                
164                                                @SuppressWarnings("unchecked")
165                                                Bean<EventState> eventBean = (Bean<EventState>)beanManager.getBeans(EventState.class).iterator().next();
166                                                EventState eventState = (EventState)beanManager.getReference(eventBean, EventState.class, beanManager.createCreationalContext(eventBean));
167                                                if (eventState.wasLongRunning() && !conversation.isTransient())
168                                                    amfRespMessage.setHeader(WAS_LONG_RUNNING_CONVERSATION_ENDED, true);
169                                                    
170                                        if (eventState.wasCreated() && !conversation.isTransient())
171                                            amfRespMessage.setHeader(WAS_LONG_RUNNING_CONVERSATION_CREATED, true);
172                                        
173                                        amfRespMessage.setHeader(CONVERSATION_ID, conversation.getId());
174                                                    
175                                                    amfRespMessage.setHeader(IS_LONG_RUNNING_CONVERSATION, !conversation.isTransient());
176                                            }
177                                    }
178                                    finally {
179                                            // Destroy the CDI context
180                                        if (((HttpGraniteContext)GraniteContext.getCurrentInstance()).getSession(false) != null) {
181                                                ConversationContext conversationContext = lookupConversationContext(beanManager);
182                                                if (conversationContext.isActive()) {
183                                                        
184                                                        @SuppressWarnings("unchecked")
185                                                        Bean<ConversationManager> conversationManagerBean = (Bean<ConversationManager>)beanManager.getBeans(ConversationManager.class).iterator().next();
186                                                        ConversationManager conversationManager = (ConversationManager)beanManager.getReference(conversationManagerBean, ConversationManager.class, beanManager.createCreationalContext(conversationManagerBean));
187                                                        conversationManager.cleanupConversation();
188                                                }
189                                        }
190                                        
191                                    log.debug("ended request");
192                                    }
193                            }
194                    }
195                    catch (Exception e) {
196                log.error(e, "Exception while post processing the response message.");
197                throw new ServiceException("Error while post processing the response message - " + e.getMessage());
198                    }
199            }
200            
201            private ConversationContext lookupConversationContext(WeldManager beanManager) {
202                return beanManager.getServices().get(ContextLifecycle.class).getConversationContext();
203            }
204    }