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 */
022package org.granite.config;
023
024import java.util.ArrayList;
025import java.util.Arrays;
026import java.util.List;
027import java.util.Map;
028import java.util.concurrent.ConcurrentHashMap;
029
030import javax.servlet.ServletContext;
031import javax.servlet.ServletContextEvent;
032import javax.servlet.ServletContextListener;
033import javax.servlet.ServletException;
034import javax.servlet.http.HttpSession;
035import javax.servlet.http.HttpSessionEvent;
036import javax.servlet.http.HttpSessionListener;
037
038import org.granite.config.GraniteConfig.JMF_EXTENSIONS_MODE;
039import org.granite.config.flex.ServletServicesConfig;
040import org.granite.jmx.GraniteMBeanInitializer;
041import org.granite.logging.Logger;
042import org.granite.messaging.AliasRegistry;
043import org.granite.messaging.DefaultAliasRegistry;
044import org.granite.messaging.jmf.DefaultCodecRegistry;
045import org.granite.messaging.jmf.DefaultSharedContext;
046import org.granite.messaging.jmf.SharedContext;
047import org.granite.messaging.jmf.codec.ExtendedObjectCodec;
048import org.granite.messaging.jmf.codec.ExtendedObjectCodecService;
049import org.granite.messaging.reflect.Reflection;
050import org.granite.scan.ServiceLoader;
051import org.granite.util.JMFAMFUtil;
052import org.granite.util.ServletParams;
053
054
055/**
056 * @author William DRAI
057 */
058public 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}