001 /**
002 * GRANITE DATA SERVICES
003 * Copyright (C) 2006-2013 GRANITE DATA SERVICES S.A.S.
004 *
005 * This file is part of the Granite Data Services Platform.
006 *
007 * Granite Data Services is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * Granite Data Services is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
015 * General Public License for more details.
016 *
017 * You should have received a copy of the GNU Lesser General Public
018 * License along with this library; if not, write to the Free Software
019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
020 * USA, or see <http://www.gnu.org/licenses/>.
021 */
022 package org.granite.config;
023
024 import java.util.ArrayList;
025 import java.util.Arrays;
026 import java.util.List;
027 import java.util.Map;
028 import java.util.concurrent.ConcurrentHashMap;
029
030 import javax.servlet.ServletContext;
031 import javax.servlet.ServletContextEvent;
032 import javax.servlet.ServletContextListener;
033 import javax.servlet.ServletException;
034 import javax.servlet.http.HttpSession;
035 import javax.servlet.http.HttpSessionEvent;
036 import javax.servlet.http.HttpSessionListener;
037
038 import org.granite.config.GraniteConfig.JMF_EXTENSIONS_MODE;
039 import org.granite.config.flex.ServletServicesConfig;
040 import org.granite.jmx.GraniteMBeanInitializer;
041 import org.granite.logging.Logger;
042 import org.granite.messaging.AliasRegistry;
043 import org.granite.messaging.DefaultAliasRegistry;
044 import org.granite.messaging.jmf.DefaultCodecRegistry;
045 import org.granite.messaging.jmf.DefaultSharedContext;
046 import org.granite.messaging.jmf.SharedContext;
047 import org.granite.messaging.jmf.codec.ExtendedObjectCodec;
048 import org.granite.messaging.jmf.codec.ExtendedObjectCodecService;
049 import org.granite.messaging.reflect.Reflection;
050 import org.granite.scan.ServiceLoader;
051 import org.granite.util.JMFAMFUtil;
052 import org.granite.util.ServletParams;
053
054
055 /**
056 * @author William DRAI
057 */
058 public class GraniteConfigListener implements ServletContextListener, HttpSessionListener {
059
060 private static final String GRANITE_CONFIG_SHUTDOWN_KEY = GraniteConfig.class.getName() + "_SHUTDOWN";
061 public static final String GRANITE_CONFIG_ATTRIBUTE = "org.granite.config.serverFilter";
062 public static final String GRANITE_CONFIG_PROVIDER_ATTRIBUTE = "org.granite.config.configProvider";
063 public static final String GRANITE_MBEANS_ATTRIBUTE = "registerGraniteMBeans";
064
065 public static final String GRANITE_SESSION_TRACKING = "org.granite.config.sessionTracking";
066 public static final String GRANITE_SESSION_MAP = "org.granite.config.sessionMap";
067
068 public static final String JMF_INITIALIZATION = "jmf-initialization";
069 public static final String SHARED_CONTEXT_KEY = SharedContext.class.getName();
070 public static final String DUMP_SHARED_CONTEXT_KEY = SharedContext.class.getName() + ":DUMP";
071
072 private static final Logger log = Logger.getLogger(GraniteConfigListener.class);
073
074 public void contextInitialized(ServletContextEvent sce) {
075 ServletContext context = sce.getServletContext();
076 try {
077 log.info("Initializing GraniteDS...");
078
079 ServiceConfigurator serviceConfigurator = (ServiceConfigurator)context.getAttribute(GRANITE_CONFIG_ATTRIBUTE);
080 if (serviceConfigurator != null)
081 serviceConfigurator.initialize(context);
082
083 GraniteConfig gConfig = ServletGraniteConfig.loadConfig(context);
084
085 if (serviceConfigurator != null)
086 serviceConfigurator.configureServices(context);
087 else
088 ServletServicesConfig.loadConfig(context);
089
090 if ("true".equals(context.getInitParameter(GRANITE_SESSION_TRACKING))) {
091 Map<String, HttpSession> sessionMap = new ConcurrentHashMap<String, HttpSession>(200);
092 context.setAttribute(GRANITE_SESSION_MAP, sessionMap);
093 }
094
095 if (gConfig.isRegisterMBeans()) {
096 GraniteMBeanInitializer.registerMBeans(context,
097 ServletGraniteConfig.getServletConfig(context),
098 ServletServicesConfig.getServletConfig(context));
099 }
100
101 String jmfInitialization = context.getInitParameter(JMF_INITIALIZATION);
102 if (jmfInitialization == null || "true".equals(jmfInitialization))
103 loadJMFSharedContext(context, gConfig);
104
105 log.info("GraniteDS initialized");
106 }
107 catch (Exception e) {
108 throw new RuntimeException("Could not initialize Granite environment", e);
109 }
110 }
111
112 public void contextDestroyed(ServletContextEvent sce) {
113 ServletContext context = sce.getServletContext();
114
115 log.info("Stopping GraniteDS...");
116
117 @SuppressWarnings("unchecked")
118 List<ShutdownListener> listeners = (List<ShutdownListener>)sce.getServletContext().getAttribute(GRANITE_CONFIG_SHUTDOWN_KEY);
119 if (listeners != null) {
120 try {
121 for (ShutdownListener listener : listeners)
122 listener.stop();
123 }
124 catch (Exception e) {
125 throw new RuntimeException("Could not destroy Granite environment", e);
126 }
127 }
128
129 if (ServletParams.get(context, GRANITE_MBEANS_ATTRIBUTE, Boolean.TYPE, false))
130 GraniteMBeanInitializer.unregisterMBeans(context);
131
132 log.info("GraniteDS stopped");
133 }
134
135 public static synchronized void registerShutdownListener(ServletContext context, ShutdownListener listener) {
136 @SuppressWarnings("unchecked")
137 List<ShutdownListener> listeners = (List<ShutdownListener>)context.getAttribute(GRANITE_CONFIG_SHUTDOWN_KEY);
138 if (listeners == null) {
139 listeners = new ArrayList<ShutdownListener>();
140 context.setAttribute(GRANITE_CONFIG_SHUTDOWN_KEY, listeners);
141 }
142 listeners.add(listener);
143 }
144
145
146 public static interface ServiceConfigurator {
147
148 public void initialize(ServletContext context);
149
150 public void configureServices(ServletContext context) throws ServletException;
151 }
152
153
154 private static void loadJMFSharedContext(ServletContext servletContext, GraniteConfig graniteConfig) {
155 log.info("Loading JMF shared context");
156
157 List<ExtendedObjectCodec> extendedObjectCodecs = null;
158
159 if (graniteConfig.getJmfExtendedCodecsMode() == JMF_EXTENSIONS_MODE.REPLACE)
160 extendedObjectCodecs = graniteConfig.getJmfExtendedCodecs();
161 else {
162 extendedObjectCodecs = new ArrayList<ExtendedObjectCodec>();
163
164 if (graniteConfig.getJmfExtendedCodecsMode() == JMF_EXTENSIONS_MODE.PREPPEND)
165 extendedObjectCodecs.addAll(graniteConfig.getJmfExtendedCodecs());
166
167 for (ExtendedObjectCodecService service : ServiceLoader.load(ExtendedObjectCodecService.class))
168 extendedObjectCodecs.addAll(Arrays.asList(service.getExtensions()));
169
170 if (graniteConfig.getJmfExtendedCodecsMode() == JMF_EXTENSIONS_MODE.APPEND)
171 extendedObjectCodecs.addAll(graniteConfig.getJmfExtendedCodecs());
172 }
173
174 log.debug("Using JMF extended codecs: %s", extendedObjectCodecs);
175
176 List<String> defaultStoredStrings = null;
177 if (graniteConfig.getJmfDefaultStoredStringsMode() == JMF_EXTENSIONS_MODE.REPLACE)
178 defaultStoredStrings = graniteConfig.getJmfDefaultStoredStrings();
179 else {
180 defaultStoredStrings = new ArrayList<String>();
181
182 if (graniteConfig.getJmfDefaultStoredStringsMode() == JMF_EXTENSIONS_MODE.PREPPEND)
183 defaultStoredStrings.addAll(graniteConfig.getJmfDefaultStoredStrings());
184
185 defaultStoredStrings.addAll(JMFAMFUtil.AMF_DEFAULT_STORED_STRINGS);
186
187 if (graniteConfig.getJmfDefaultStoredStringsMode() == JMF_EXTENSIONS_MODE.APPEND)
188 defaultStoredStrings.addAll(graniteConfig.getJmfDefaultStoredStrings());
189 }
190
191 log.debug("Using JMF default stored strings: %s", defaultStoredStrings);
192
193 Reflection reflection = graniteConfig.getJmfReflection();
194
195 log.debug("Using JMF reflection: %s", reflection.getClass().getName());
196
197 AliasRegistry aliasRegistry = new DefaultAliasRegistry();
198
199 SharedContext sharedContext = new DefaultSharedContext(new DefaultCodecRegistry(extendedObjectCodecs), defaultStoredStrings, reflection, aliasRegistry);
200 servletContext.setAttribute(SHARED_CONTEXT_KEY, sharedContext);
201
202 SharedContext dumpSharedContext = new DefaultSharedContext(new DefaultCodecRegistry(), defaultStoredStrings, reflection, aliasRegistry);
203 servletContext.setAttribute(DUMP_SHARED_CONTEXT_KEY, dumpSharedContext);
204
205 log.info("JMF shared context loaded");
206 }
207
208 public static SharedContext getSharedContext(ServletContext servletContext) {
209 return (SharedContext)servletContext.getAttribute(SHARED_CONTEXT_KEY);
210 }
211
212 public static SharedContext getDumpSharedContext(ServletContext servletContext) {
213 return (SharedContext)servletContext.getAttribute(DUMP_SHARED_CONTEXT_KEY);
214 }
215
216 public static ServletException newSharedContextNotInitializedException() {
217 return new ServletException(
218 "JMF shared context not initialized (remove or set to true '" + JMF_INITIALIZATION + "' param in your web.xml)"
219 );
220 }
221
222 public void sessionCreated(HttpSessionEvent se) {
223 @SuppressWarnings("unchecked")
224 Map<String, HttpSession> sessionMap = (Map<String, HttpSession>)se.getSession().getServletContext().getAttribute(GRANITE_SESSION_MAP);
225 if (sessionMap != null)
226 sessionMap.put(se.getSession().getId(), se.getSession());
227 }
228
229 public void sessionDestroyed(HttpSessionEvent se) {
230 @SuppressWarnings("unchecked")
231 Map<String, HttpSession> sessionMap = (Map<String, HttpSession>)se.getSession().getServletContext().getAttribute(GRANITE_SESSION_MAP);
232 if (sessionMap != null)
233 sessionMap.remove(se.getSession().getId());
234 }
235 }