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 021package org.granite.config; 022 023import java.io.InputStream; 024import java.lang.annotation.Annotation; 025import java.lang.reflect.Method; 026import java.math.BigDecimal; 027import java.math.BigInteger; 028import java.util.ArrayList; 029import java.util.Arrays; 030import java.util.HashMap; 031import java.util.HashSet; 032import java.util.List; 033import java.util.Map; 034import java.util.Set; 035import java.util.concurrent.ConcurrentHashMap; 036 037import javax.servlet.ServletContext; 038import javax.servlet.ServletContextEvent; 039import javax.servlet.ServletContextListener; 040import javax.servlet.http.HttpSession; 041import javax.servlet.http.HttpSessionEvent; 042import javax.servlet.http.HttpSessionListener; 043import javax.servlet.ServletException; 044 045import org.granite.config.flex.Channel; 046import org.granite.config.flex.Destination; 047import org.granite.config.flex.EndPoint; 048import org.granite.config.flex.Factory; 049import org.granite.config.flex.Service; 050import org.granite.config.flex.ServicesConfig; 051import org.granite.config.flex.ServletServicesConfig; 052import org.granite.config.servlet3.ServerFilter; 053import org.granite.jmx.GraniteMBeanInitializer; 054import org.granite.logging.Logger; 055import org.granite.messaging.amf.io.util.externalizer.BigDecimalExternalizer; 056import org.granite.messaging.amf.io.util.externalizer.BigIntegerExternalizer; 057import org.granite.messaging.amf.io.util.externalizer.LongExternalizer; 058import org.granite.messaging.amf.process.AMF3MessageInterceptor; 059import org.granite.messaging.service.ExceptionConverter; 060import org.granite.messaging.service.ServiceFactory; 061import org.granite.messaging.service.SimpleServiceFactory; 062import org.granite.messaging.service.security.RemotingDestinationSecurizer; 063import org.granite.messaging.service.security.SecurityService; 064import org.granite.messaging.service.tide.TideComponentAnnotatedWithMatcher; 065import org.granite.messaging.service.tide.TideComponentInstanceOfMatcher; 066import org.granite.messaging.service.tide.TideComponentNameMatcher; 067import org.granite.messaging.service.tide.TideComponentTypeMatcher; 068import org.granite.util.TypeUtil; 069import org.granite.util.ServletParams; 070import org.granite.util.XMap; 071 072 073/** 074 * @author William DRAI 075 */ 076public 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}