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