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.config;
022
023 import java.io.InputStream;
024 import java.lang.annotation.Annotation;
025 import java.lang.reflect.Method;
026 import java.math.BigDecimal;
027 import java.math.BigInteger;
028 import java.util.ArrayList;
029 import java.util.Arrays;
030 import java.util.HashMap;
031 import java.util.HashSet;
032 import java.util.List;
033 import java.util.Map;
034 import java.util.Set;
035 import java.util.concurrent.ConcurrentHashMap;
036
037 import javax.servlet.ServletContext;
038 import javax.servlet.ServletContextEvent;
039 import javax.servlet.ServletContextListener;
040 import javax.servlet.http.HttpSession;
041 import javax.servlet.http.HttpSessionEvent;
042 import javax.servlet.http.HttpSessionListener;
043 import javax.servlet.ServletException;
044
045 import org.granite.config.flex.Channel;
046 import org.granite.config.flex.Destination;
047 import org.granite.config.flex.EndPoint;
048 import org.granite.config.flex.Factory;
049 import org.granite.config.flex.Service;
050 import org.granite.config.flex.ServicesConfig;
051 import org.granite.config.flex.ServletServicesConfig;
052 import org.granite.config.servlet3.ServerFilter;
053 import org.granite.jmx.GraniteMBeanInitializer;
054 import org.granite.logging.Logger;
055 import org.granite.messaging.amf.io.util.externalizer.BigDecimalExternalizer;
056 import org.granite.messaging.amf.io.util.externalizer.BigIntegerExternalizer;
057 import org.granite.messaging.amf.io.util.externalizer.LongExternalizer;
058 import org.granite.messaging.amf.process.AMF3MessageInterceptor;
059 import org.granite.messaging.service.ExceptionConverter;
060 import org.granite.messaging.service.ServiceFactory;
061 import org.granite.messaging.service.SimpleServiceFactory;
062 import org.granite.messaging.service.security.RemotingDestinationSecurizer;
063 import org.granite.messaging.service.security.SecurityService;
064 import org.granite.messaging.service.tide.TideComponentAnnotatedWithMatcher;
065 import org.granite.messaging.service.tide.TideComponentInstanceOfMatcher;
066 import org.granite.messaging.service.tide.TideComponentNameMatcher;
067 import org.granite.messaging.service.tide.TideComponentTypeMatcher;
068 import org.granite.util.TypeUtil;
069 import org.granite.util.ServletParams;
070 import org.granite.util.XMap;
071
072
073 /**
074 * @author William DRAI
075 */
076 public class GraniteConfigListener implements ServletContextListener, HttpSessionListener {
077
078 private static final String GRANITE_CONFIG_SHUTDOWN_KEY = GraniteConfig.class.getName() + "_SHUTDOWN";
079 public static final String GRANITE_CONFIG_ATTRIBUTE = "org.granite.config.serverFilter";
080 public static final String GRANITE_CONFIG_PROVIDER_ATTRIBUTE = "org.granite.config.configProvider";
081 public static final String GRANITE_MBEANS_ATTRIBUTE = "registerGraniteMBeans";
082
083 public static final String GRANITE_SESSION_TRACKING = "org.granite.config.sessionTracking";
084 public static final String GRANITE_SESSION_MAP = "org.granite.config.sessionMap";
085
086 private static final Logger log = Logger.getLogger(GraniteConfigListener.class);
087
088 public void contextInitialized(ServletContextEvent sce) {
089 try {
090 ServletContext context = sce.getServletContext();
091
092 log.info("Initializing GraniteDS...");
093
094 Class<?> serverFilterClass = (Class<?>)context.getAttribute(GRANITE_CONFIG_ATTRIBUTE);
095 if (serverFilterClass != null)
096 context.setAttribute(ServletGraniteConfig.GRANITE_CONFIG_DEFAULT_KEY, "org/granite/config/servlet3/granite-config-servlet3.xml");
097
098 GraniteConfig gConfig = ServletGraniteConfig.loadConfig(context);
099 ServletServicesConfig.loadConfig(context);
100
101 if (serverFilterClass != null)
102 configureServices(context, serverFilterClass);
103
104 if ("true".equals(sce.getServletContext().getInitParameter(GRANITE_SESSION_TRACKING))) {
105 Map<String, HttpSession> sessionMap = new ConcurrentHashMap<String, HttpSession>(200);
106 sce.getServletContext().setAttribute(GRANITE_SESSION_MAP, sessionMap);
107 }
108
109 if (gConfig.isRegisterMBeans()) {
110 GraniteMBeanInitializer.registerMBeans(context,
111 ServletGraniteConfig.getServletConfig(context),
112 ServletServicesConfig.getServletConfig(context));
113 }
114
115 log.info("GraniteDS initialized");
116 }
117 catch (Exception e) {
118 throw new RuntimeException("Could not initialize Granite environment", e);
119 }
120 }
121
122 public void contextDestroyed(ServletContextEvent sce) {
123 ServletContext context = sce.getServletContext();
124
125 log.info("Stopping GraniteDS...");
126
127 @SuppressWarnings("unchecked")
128 List<ShutdownListener> listeners = (List<ShutdownListener>)sce.getServletContext().getAttribute(GRANITE_CONFIG_SHUTDOWN_KEY);
129 if (listeners != null) {
130 try {
131 for (ShutdownListener listener : listeners)
132 listener.stop();
133 }
134 catch (Exception e) {
135 throw new RuntimeException("Could not destroy Granite environment", e);
136 }
137 }
138
139 if (ServletParams.get(context, GRANITE_MBEANS_ATTRIBUTE, Boolean.TYPE, false))
140 GraniteMBeanInitializer.unregisterMBeans(context);
141
142 log.info("GraniteDS stopped");
143 }
144
145 public static synchronized void registerShutdownListener(ServletContext context, ShutdownListener listener) {
146 @SuppressWarnings("unchecked")
147 List<ShutdownListener> listeners = (List<ShutdownListener>)context.getAttribute(GRANITE_CONFIG_SHUTDOWN_KEY);
148 if (listeners == null) {
149 listeners = new ArrayList<ShutdownListener>();
150 context.setAttribute(GRANITE_CONFIG_SHUTDOWN_KEY, listeners);
151 }
152 listeners.add(listener);
153 }
154
155
156 private void configureServices(ServletContext servletContext, Class<?> serverFilterClass) throws ServletException {
157 GraniteConfig graniteConfig = ServletGraniteConfig.loadConfig(servletContext);
158 ServicesConfig servicesConfig = ServletServicesConfig.loadConfig(servletContext);
159
160 ServerFilter serverFilter = serverFilterClass.getAnnotation(ServerFilter.class);
161
162 ConfigProvider configProvider = null;
163
164 boolean useTide = serverFilter.tide();
165 String type = serverFilter.type();
166 Class<?> factoryClass = null;
167 Set<Class<?>> tideInterfaces = new HashSet<Class<?>>(Arrays.asList(serverFilter.tideInterfaces()));
168 Set<Class<? extends Annotation>> tideAnnotations = new HashSet<Class<? extends Annotation>>(Arrays.asList(serverFilter.tideAnnotations()));
169
170 if (!serverFilter.configProviderClass().equals(ConfigProvider.class)) {
171 try {
172 configProvider = TypeUtil.newInstance(serverFilter.configProviderClass(), new Class[] { ServletContext.class }, new Object[] { servletContext });
173
174 servletContext.setAttribute(GRANITE_CONFIG_PROVIDER_ATTRIBUTE, configProvider);
175
176 if (configProvider.useTide() != null)
177 useTide = configProvider.useTide();
178
179 if (configProvider.getType() != null)
180 type = configProvider.getType();
181
182 factoryClass = configProvider.getFactoryClass();
183
184 if (configProvider.getTideInterfaces() != null)
185 tideInterfaces.addAll(Arrays.asList(configProvider.getTideInterfaces()));
186
187 if (configProvider.getTideAnnotations() != null)
188 tideAnnotations.addAll(Arrays.asList(configProvider.getTideAnnotations()));
189 }
190 catch (Exception e) {
191 log.error(e, "Could not set config provider of type %s", serverFilter.configProviderClass().getName());
192 }
193 }
194
195 if (!serverFilter.factoryClass().equals(ServiceFactory.class))
196 factoryClass = serverFilter.factoryClass();
197
198 if (factoryClass == null) {
199 factoryClass = SimpleServiceFactory.class;
200 useTide = false;
201 }
202
203 for (Class<?> ti : tideInterfaces) {
204 try {
205 graniteConfig.getTideComponentMatchers().add(new TideComponentInstanceOfMatcher(ti.getName(), false));
206 log.debug("Enabled components implementing %s for Tide remoting", ti);
207 }
208 catch (Exception e) {
209 log.error(e, "Could not add tide-component interface %s", ti);
210 }
211 }
212 for (Class<? extends Annotation> ta : tideAnnotations) {
213 try {
214 graniteConfig.getTideComponentMatchers().add(new TideComponentAnnotatedWithMatcher(ta.getName(), false));
215 log.debug("Enabled components annotated with %s for Tide remoting", ta);
216 }
217 catch (Exception e) {
218 log.error(e, "Could not add tide-component annotation %s", ta);
219 }
220 }
221 for (String tn : serverFilter.tideNames()) {
222 try {
223 graniteConfig.getTideComponentMatchers().add(new TideComponentNameMatcher(tn, false));
224 log.debug("Enabled components with name %s for Tide remoting", tn);
225 }
226 catch (Exception e) {
227 log.error(e, "Could not add tide-component name %s", tn);
228 }
229 }
230 for (String tt : serverFilter.tideTypes()) {
231 try {
232 graniteConfig.getTideComponentMatchers().add(new TideComponentTypeMatcher(tt, false));
233 log.debug("Enabled components with type %s for Tide remoting", tt);
234 }
235 catch (Exception e) {
236 log.error(e, "Could not add tide-component type %s", tt);
237 }
238 }
239
240 for (Class<? extends ExceptionConverter> ec : serverFilter.exceptionConverters()) {
241 graniteConfig.registerExceptionConverter(ec, true);
242 log.debug("Registered exception converter %s", ec);
243 }
244 if (configProvider != null) {
245 for (ExceptionConverter ec : configProvider.findInstances(ExceptionConverter.class)) {
246 graniteConfig.registerExceptionConverter(ec, true);
247 log.debug("Registered exception converter %s", ec.getClass());
248 }
249 }
250
251 if (serverFilter.useBigDecimal())
252 graniteConfig.setExternalizersByType(BigDecimal.class.getName(), BigDecimalExternalizer.class.getName());
253
254 if (serverFilter.useBigInteger())
255 graniteConfig.setExternalizersByType(BigInteger.class.getName(), BigIntegerExternalizer.class.getName());
256
257 if (serverFilter.useLong())
258 graniteConfig.setExternalizersByType(Long.class.getName(), LongExternalizer.class.getName());
259
260 if (!serverFilter.securityServiceClass().equals(SecurityService.class)) {
261 try {
262 graniteConfig.setSecurityService(TypeUtil.newInstance(serverFilter.securityServiceClass(), SecurityService.class));
263 }
264 catch (Exception e) {
265 throw new ServletException("Could not setup security service", e);
266 }
267 }
268 else if (graniteConfig.getSecurityService() == null && configProvider != null) {
269 SecurityService securityService = configProvider.findInstance(SecurityService.class);
270 graniteConfig.setSecurityService(securityService);
271 }
272 if (graniteConfig.getSecurityService() == null) {
273 String securityServiceClassName = null;
274 // Try auto-detect
275 try {
276 TypeUtil.forName("org.mortbay.jetty.Request");
277 securityServiceClassName = "org.granite.messaging.service.security.Jetty6SecurityService";
278 }
279 catch (ClassNotFoundException e1) {
280 try {
281 TypeUtil.forName("org.eclipse.jetty.server.Request");
282 securityServiceClassName = "org.granite.messaging.service.security.Jetty7SecurityService";
283 }
284 catch (ClassNotFoundException e1b) {
285 try {
286 TypeUtil.forName("weblogic.servlet.security.ServletAuthentication");
287 securityServiceClassName = "org.granite.messaging.service.security.WebLogicSecurityService";
288 }
289 catch (ClassNotFoundException e2) {
290 try {
291 TypeUtil.forName("com.sun.appserv.server.LifecycleEvent");
292 securityServiceClassName = "org.granite.messaging.service.security.GlassFishV3SecurityService";
293 }
294 catch (ClassNotFoundException e3) {
295 securityServiceClassName = "org.granite.messaging.service.security.Tomcat7SecurityService";
296 }
297 }
298 try {
299 graniteConfig.setSecurityService((SecurityService)TypeUtil.newInstance(securityServiceClassName));
300 }
301 catch (Exception e) {
302 throw new ServletException("Could not setup security service " + securityServiceClassName, e);
303 }
304 }
305 }
306 }
307
308 if (!serverFilter.amf3MessageInterceptor().equals(AMF3MessageInterceptor.class)) {
309 try {
310 graniteConfig.setAmf3MessageInterceptor(TypeUtil.newInstance(serverFilter.amf3MessageInterceptor(), AMF3MessageInterceptor.class));
311 }
312 catch (Exception e) {
313 throw new ServletException("Could not setup amf3 message interceptor", e);
314 }
315 }
316 else if (graniteConfig.getAmf3MessageInterceptor() == null && configProvider != null) {
317 AMF3MessageInterceptor amf3MessageInterceptor = configProvider.findInstance(AMF3MessageInterceptor.class);
318 graniteConfig.setAmf3MessageInterceptor(amf3MessageInterceptor);
319 }
320
321 Channel channel = servicesConfig.findChannelById("graniteamf");
322 if (channel == null) {
323 channel = new Channel("graniteamf", "mx.messaging.channels.AMFChannel",
324 new EndPoint("http://{server.name}:{server.port}/{context.root}/graniteamf/amf", "flex.messaging.endpoints.AMFEndpoint"),
325 new XMap());
326 servicesConfig.addChannel(channel);
327 }
328
329 XMap factoryProperties = new XMap();
330 String lookup = null;
331 if (useTide) {
332 lookup = "java:global/{context.root}/{capitalized.component.name}Bean";
333 if (isJBoss6())
334 lookup = "{capitalized.component.name}Bean/local";
335 if (!("".equals(serverFilter.ejbLookup())))
336 lookup = serverFilter.ejbLookup();
337 }
338 else {
339 lookup = "java:global/{context.root}/{capitalized.destination.id}Bean";
340 if (isJBoss6())
341 lookup = "{capitalized.destination.id}Bean/local";
342 if (!("".equals(serverFilter.ejbLookup())))
343 lookup = serverFilter.ejbLookup();
344 }
345 if (lookup.indexOf("{context.root}") >= 0) {
346 try {
347 // Call by reflection because of JDK 1.4
348 Method m = servletContext.getClass().getMethod("getContextPath");
349 String contextPath = (String)m.invoke(servletContext);
350 lookup = lookup.replace("{context.root}", contextPath.substring(1));
351 }
352 catch (Exception e) {
353 log.error(e, "Could not get context path, please define lookup manually in @FlexFilter");
354 }
355 }
356 factoryProperties.put("lookup", lookup);
357
358 if (useTide) {
359 Factory factory = servicesConfig.findFactoryById("tide-" + type + "-factory");
360 if (factory == null) {
361 factory = new Factory("tide-" + type + "-factory", factoryClass.getName(), factoryProperties);
362 servicesConfig.addFactory(factory);
363 }
364
365 Service service = servicesConfig.findServiceById("granite-service");
366 if (service == null) {
367 service = new Service("granite-service", "flex.messaging.services.RemotingService",
368 "flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>());
369 List<String> channelIds = new ArrayList<String>();
370 channelIds.add("graniteamf");
371 List<String> tideRoles = serverFilter.tideRoles().length == 0 ? null : Arrays.asList(serverFilter.tideRoles());
372 Destination destination = new Destination(type, channelIds, new XMap(), tideRoles, null, null);
373 destination.getProperties().put("factory", "tide-" + type + "-factory");
374 if (!("".equals(serverFilter.entityManagerFactoryJndiName())))
375 destination.getProperties().put("entity-manager-factory-jndi-name", serverFilter.entityManagerFactoryJndiName());
376 else if (!("".equals(serverFilter.entityManagerJndiName())))
377 destination.getProperties().put("entity-manager-jndi-name", serverFilter.entityManagerJndiName());
378 if (!("".equals(serverFilter.validatorClassName())))
379 destination.getProperties().put("validator-class-name", serverFilter.validatorClassName());
380 service.getDestinations().put(type, destination);
381
382 if (destination.getSecurizer() == null && configProvider != null) {
383 RemotingDestinationSecurizer securizer = configProvider.findInstance(RemotingDestinationSecurizer.class);
384 destination.setSecurizer(securizer);
385 }
386
387 servicesConfig.addService(service);
388 }
389
390 if (factoryClass.getName().equals("org.granite.tide.ejb.EjbServiceFactory"))
391 servicesConfig.scan(null);
392
393 log.info("Registered Tide " + factoryClass + " service factory and " + type + " destination");
394 }
395 else {
396 Factory factory = new Factory(type + "-factory", factoryClass.getName(), factoryProperties);
397 servicesConfig.addFactory(factory);
398
399 Service service = new Service("granite-service", "flex.messaging.services.RemotingService",
400 "flex.messaging.messages.RemotingMessage", null, null, new HashMap<String, Destination>());
401 servicesConfig.addService(service);
402
403 servicesConfig.scan(null);
404
405 log.info("Registered " + factoryClass + " service factory");
406 }
407 }
408
409 private static boolean isJBoss6() {
410 try {
411 InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("/org/jboss/version.properties");
412 if (is != null)
413 return true;
414 }
415 catch (Throwable t) {
416 }
417 return false;
418 }
419
420
421 public void sessionCreated(HttpSessionEvent se) {
422 @SuppressWarnings("unchecked")
423 Map<String, HttpSession> sessionMap = (Map<String, HttpSession>)se.getSession().getServletContext().getAttribute(GRANITE_SESSION_MAP);
424 if (sessionMap != null)
425 sessionMap.put(se.getSession().getId(), se.getSession());
426 }
427
428 public void sessionDestroyed(HttpSessionEvent se) {
429 @SuppressWarnings("unchecked")
430 Map<String, HttpSession> sessionMap = (Map<String, HttpSession>)se.getSession().getServletContext().getAttribute(GRANITE_SESSION_MAP);
431 if (sessionMap != null)
432 sessionMap.remove(se.getSession().getId());
433 }
434 }