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 }