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
021 package org.granite.cdi;
022
023 import java.util.Iterator;
024 import java.util.Map;
025
026 import javax.enterprise.context.Conversation;
027 import javax.enterprise.inject.spi.Bean;
028 import javax.enterprise.inject.spi.BeanManager;
029 import javax.servlet.ServletRequestEvent;
030
031 import org.granite.context.GraniteContext;
032 import org.granite.logging.Logger;
033 import org.granite.messaging.amf.process.AMF3MessageInterceptor;
034 import org.granite.messaging.service.ServiceException;
035 import org.granite.messaging.webapp.HttpGraniteContext;
036 import org.granite.messaging.webapp.HttpServletRequestParamWrapper;
037 import org.granite.tide.cdi.ConversationState;
038 import org.granite.tide.cdi.EventState;
039 import org.granite.tide.cdi.SessionState;
040 import org.granite.util.TypeUtil;
041 import org.jboss.weld.servlet.WeldListener;
042
043 import flex.messaging.messages.Message;
044
045
046 public class CDIInterceptor implements AMF3MessageInterceptor {
047
048 private static final Logger log = Logger.getLogger(CDIInterceptor.class);
049
050 private static final String CONVERSATION_ID = "conversationId";
051 private static final String IS_LONG_RUNNING_CONVERSATION = "isLongRunningConversation";
052 private static final String WAS_LONG_RUNNING_CONVERSATION_CREATED = "wasLongRunningConversationCreated";
053 private static final String WAS_LONG_RUNNING_CONVERSATION_ENDED = "wasLongRunningConversationEnded";
054
055 private CDIConversationManager conversationManager;
056
057
058 public CDIInterceptor() {
059 try {
060 Thread.currentThread().getContextClassLoader().loadClass("org.jboss.weld.context.http.HttpConversationContext");
061 conversationManager = TypeUtil.newInstance("org.granite.cdi.Weld11ConversationManager", CDIConversationManager.class);
062 log.info("Detected Weld 1.1");
063 }
064 catch (Exception e) {
065 try {
066 conversationManager = TypeUtil.newInstance("org.granite.cdi.Weld10ConversationManager", CDIConversationManager.class);
067 log.info("Detected Weld 1.0");
068 }
069 catch (Exception f) {
070 throw new RuntimeException("Could not load conversation manager for CDI implementation", f);
071 }
072 }
073 }
074
075
076 private WeldListener listener = new WeldListener();
077
078 private static final String MESSAGECOUNT_ATTR = CDIInterceptor.class.getName() + "_messageCount";
079 private static final String REQUESTWRAPPER_ATTR = CDIInterceptor.class.getName() + "_requestWrapper";
080
081
082 public void before(Message amf3RequestMessage) {
083 if (log.isTraceEnabled())
084 log.trace("Pre processing of request message: %s", amf3RequestMessage);
085
086 try {
087 GraniteContext context = GraniteContext.getCurrentInstance();
088
089 if (context instanceof HttpGraniteContext) {
090 HttpGraniteContext httpContext = ((HttpGraniteContext)context);
091 Integer wrapCount = (Integer)httpContext.getRequest().getAttribute(MESSAGECOUNT_ATTR);
092 if (wrapCount == null) {
093 log.debug("Clearing default Weld request context");
094 ServletRequestEvent event = new ServletRequestEvent(httpContext.getServletContext(), httpContext.getRequest());
095 listener.requestDestroyed(event);
096 httpContext.getRequest().setAttribute(MESSAGECOUNT_ATTR, 1);
097 }
098 else
099 httpContext.getRequest().setAttribute(MESSAGECOUNT_ATTR, wrapCount+1);
100
101 log.debug("Initializing wrapped AMF request");
102
103 HttpServletRequestParamWrapper requestWrapper = new HttpServletRequestParamWrapper(httpContext.getRequest());
104 httpContext.getRequest().setAttribute(REQUESTWRAPPER_ATTR, requestWrapper);
105
106 // Now export the headers - copy the headers to request object
107 Map<String, Object> headerMap = amf3RequestMessage.getHeaders();
108 if (headerMap != null && headerMap.size() > 0) {
109 Iterator<String> headerKeys = headerMap.keySet().iterator();
110 while (headerKeys.hasNext()) {
111 String key = headerKeys.next();
112 String value = headerMap.get(key) == null ? null : headerMap.get(key).toString();
113 if (value != null)
114 requestWrapper.setParameter(key, value);
115 }
116 }
117
118 ServletRequestEvent event = new ServletRequestEvent(((HttpGraniteContext)context).getServletContext(), requestWrapper);
119 listener.requestInitialized(event);
120
121 // Initialize CDI Context
122 String conversationId = (String)amf3RequestMessage.getHeader(CONVERSATION_ID);
123
124 BeanManager beanManager = CDIUtils.lookupBeanManager(((HttpGraniteContext)context).getServletContext());
125
126 Conversation conversation = conversationManager.initConversation(beanManager, conversationId);
127
128 @SuppressWarnings("unchecked")
129 Bean<EventState> eventBean = (Bean<EventState>)beanManager.getBeans(EventState.class).iterator().next();
130 EventState eventState = (EventState)beanManager.getReference(eventBean, EventState.class, beanManager.createCreationalContext(eventBean));
131 if (!conversation.isTransient())
132 eventState.setWasLongRunning(true);
133
134 if (conversationId != null && conversation.isTransient()) {
135 log.debug("Starting conversation " + conversationId);
136 conversation.begin(conversationId);
137 }
138
139 if (Boolean.TRUE.toString().equals(amf3RequestMessage.getHeader("org.granite.tide.isFirstCall"))) {
140 @SuppressWarnings("unchecked")
141 Bean<SessionState> ssBean = (Bean<SessionState>)beanManager.getBeans(SessionState.class).iterator().next();
142 ((SessionState)beanManager.getReference(ssBean, SessionState.class, beanManager.createCreationalContext(ssBean))).setFirstCall(true);
143 }
144
145 if (Boolean.TRUE.toString().equals(amf3RequestMessage.getHeader("org.granite.tide.isFirstConversationCall")) && !conversation.isTransient()) {
146 @SuppressWarnings("unchecked")
147 Bean<ConversationState> csBean = (Bean<ConversationState>)beanManager.getBeans(ConversationState.class).iterator().next();
148 ((ConversationState)beanManager.getReference(csBean, ConversationState.class, beanManager.createCreationalContext(csBean))).setFirstCall(true);
149 }
150 }
151 }
152 catch(Exception e) {
153 log.error(e, "Exception while pre processing the request message.");
154 throw new ServiceException("Error while pre processing the request message - " + e.getMessage());
155 }
156 }
157
158
159 public void after(Message amf3RequestMessage, Message amf3ResponseMessage) {
160 try {
161 if (log.isTraceEnabled())
162 log.trace("Post processing of response message: %s", amf3ResponseMessage);
163
164 GraniteContext context = GraniteContext.getCurrentInstance();
165
166 if (context instanceof HttpGraniteContext) {
167 BeanManager beanManager = CDIUtils.lookupBeanManager(((HttpGraniteContext)context).getServletContext());
168 try {
169 // Add conversation management headers to response
170 if (amf3ResponseMessage != null) {
171 @SuppressWarnings("unchecked")
172 Bean<Conversation> conversationBean = (Bean<Conversation>)beanManager.getBeans(Conversation.class).iterator().next();
173 Conversation conversation = (Conversation)beanManager.getReference(conversationBean, Conversation.class, beanManager.createCreationalContext(conversationBean));
174
175 @SuppressWarnings("unchecked")
176 Bean<EventState> eventBean = (Bean<EventState>)beanManager.getBeans(EventState.class).iterator().next();
177 EventState eventState = (EventState)beanManager.getReference(eventBean, EventState.class, beanManager.createCreationalContext(eventBean));
178 if (eventState.wasLongRunning() && !conversation.isTransient())
179 amf3ResponseMessage.setHeader(WAS_LONG_RUNNING_CONVERSATION_ENDED, true);
180
181 if (eventState.wasCreated() && !conversation.isTransient())
182 amf3ResponseMessage.setHeader(WAS_LONG_RUNNING_CONVERSATION_CREATED, true);
183
184 amf3ResponseMessage.setHeader(CONVERSATION_ID, conversation.getId());
185
186 amf3ResponseMessage.setHeader(IS_LONG_RUNNING_CONVERSATION, !conversation.isTransient());
187 }
188 }
189 finally {
190 conversationManager.destroyConversation(beanManager);
191
192 HttpGraniteContext httpContext = ((HttpGraniteContext)context);
193
194 // Destroy the CDI context
195 HttpServletRequestParamWrapper requestWrapper = (HttpServletRequestParamWrapper)httpContext.getRequest().getAttribute(REQUESTWRAPPER_ATTR);
196 httpContext.getRequest().removeAttribute(REQUESTWRAPPER_ATTR);
197 ServletRequestEvent event = new ServletRequestEvent(httpContext.getServletContext(), requestWrapper);
198 listener.requestDestroyed(event);
199
200 log.debug("Destroying wrapped CDI AMF request");
201
202 Integer wrapCount = (Integer)httpContext.getRequest().getAttribute(MESSAGECOUNT_ATTR);
203 if (wrapCount == 1) {
204 log.debug("Restoring default Weld request context");
205 event = new ServletRequestEvent(((HttpGraniteContext)context).getServletContext(), httpContext.getRequest());
206 listener.requestInitialized(event);
207 httpContext.getRequest().removeAttribute(MESSAGECOUNT_ATTR);
208 }
209 else
210 httpContext.getRequest().setAttribute(MESSAGECOUNT_ATTR, wrapCount-1);
211
212 }
213 }
214 }
215 catch (Exception e) {
216 log.error(e, "Exception while post processing the response message.");
217 throw new ServiceException("Error while post processing the response message - " + e.getMessage());
218 }
219 }
220 }