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    }