001/*
002  GRANITE DATA SERVICES
003  Copyright (C) 2013 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.messaging.jmf;
022
023import java.util.ArrayList;
024import java.util.Collections;
025import java.util.List;
026
027import javax.servlet.ServletContext;
028import javax.servlet.ServletContextEvent;
029import javax.servlet.ServletContextListener;
030import javax.servlet.ServletException;
031
032import org.granite.config.GraniteConfigListener;
033import org.granite.logging.Logger;
034import org.granite.messaging.jmf.codec.ExtendedObjectCodec;
035import org.granite.util.JMFAMFUtil;
036
037/**
038 * @author Franck WOLFF
039 */
040public class JMFServletContextListener implements ServletContextListener {
041
042    private static final Logger log = Logger.getLogger(GraniteConfigListener.class);
043    
044    private static final String[] CODEC_EXTENSION_FACTORY_NAMES = {
045        "org.granite.hibernate.jmf.Hibernate3CodecExtensionFactory"
046    };
047
048        public static final String EXTENDED_OBJECT_CODECS_PARAM = "jmf-extended-object-codecs";
049        public static final String DEFAULT_STORED_STRINGS_PARAM = "jmf-default-stored-strings";
050        
051        public static final String SHARED_CONTEXT_KEY = SharedContext.class.getName();
052        public static final String DUMP_SHARED_CONTEXT_KEY = SharedContext.class.getName() + ":DUMP";
053
054        public static SharedContext getSharedContext(ServletContext servletContext) {
055                return (SharedContext)servletContext.getAttribute(SHARED_CONTEXT_KEY);
056        }
057
058        public static SharedContext getDumpSharedContext(ServletContext servletContext) {
059                return (SharedContext)servletContext.getAttribute(DUMP_SHARED_CONTEXT_KEY);
060        }
061        
062        public static ServletException newSharedContextNotInitializedException() {
063                return new ServletException(
064                        "JMF shared context not initialized (configure " + JMFServletContextListener.class.getName() + " in your web.xml)"
065                );
066        }
067        
068        public void contextInitialized(ServletContextEvent event) {
069                log.info("Loading JMF shared context");
070                
071        ServletContext servletContext = event.getServletContext();
072        
073        List<ExtendedObjectCodec> extendedObjectCodecs = loadExtendedObjectCodecs(servletContext);
074        List<String> defaultStoredStrings = loadDefaultStoredStrings(servletContext);
075        
076        SharedContext sharedContext = new DefaultSharedContext(new DefaultCodecRegistry(extendedObjectCodecs), null, defaultStoredStrings);
077        servletContext.setAttribute(SHARED_CONTEXT_KEY, sharedContext);
078        
079        SharedContext dumpSharedContext = new DefaultSharedContext(new DefaultCodecRegistry(), null, defaultStoredStrings);
080        servletContext.setAttribute(DUMP_SHARED_CONTEXT_KEY, dumpSharedContext);
081                
082        log.info("JMF shared context loaded");
083        }
084        
085        protected List<ExtendedObjectCodec> loadExtendedObjectCodecs(ServletContext servletContext) {
086        String extendedObjectCodecsParam = servletContext.getInitParameter(EXTENDED_OBJECT_CODECS_PARAM);
087                
088        if (extendedObjectCodecsParam == null)
089                        return detectExtendedObjectCodecs();
090                
091                ClassLoader classLoader = getClass().getClassLoader();
092        
093                List<ExtendedObjectCodec> extendedObjectCodecs = new ArrayList<ExtendedObjectCodec>();
094        for (String className : extendedObjectCodecsParam.trim().split("\\s*\\,\\s*")) {
095                if (className.length() == 0)
096                        continue;
097                
098                log.info("Loading JMF extended object codec: %s", className);
099                try {
100                        @SuppressWarnings("unchecked")
101                                Class<? extends ExtendedObjectCodec> cls = (Class<? extends ExtendedObjectCodec>)classLoader.loadClass(className);
102                        extendedObjectCodecs.add(cls.getDeclaredConstructor().newInstance());
103                }
104                catch (Throwable t) {
105                        log.warn(t, "Could not load JMF codec: %s", className);
106                }
107        }
108                return extendedObjectCodecs;
109        }
110        
111        protected List<ExtendedObjectCodec> detectExtendedObjectCodecs() {
112        log.info("Auto detecting extended object codec...");
113                
114        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
115                for (String factoryName : CODEC_EXTENSION_FACTORY_NAMES) {
116                        try {
117                                CodecExtensionFactory factory = (CodecExtensionFactory)classLoader.loadClass(factoryName).newInstance();
118                                List<ExtendedObjectCodec> extendedObjectCodecs = factory.getCodecs();
119                                log.info("Using %s: %s", factoryName, extendedObjectCodecs);
120                                return extendedObjectCodecs;
121                        }
122                        catch (Throwable t) {
123                                log.debug(t, "Could not load factory: %s", factoryName);
124                        }
125                }
126                
127                log.info("No extended object codec detected");
128                return Collections.emptyList();
129        }
130        
131        protected List<String> loadDefaultStoredStrings(ServletContext servletContext) {
132        List<String> defaultStoredStrings = new ArrayList<String>(JMFAMFUtil.AMF_DEFAULT_STORED_STRINGS);
133                
134        String defaultStoredStringsParam = servletContext.getInitParameter(DEFAULT_STORED_STRINGS_PARAM);
135                
136        if (defaultStoredStringsParam != null) {
137                for (String value : defaultStoredStringsParam.trim().split("\\s*\\,\\s*")) {
138                if (value.length() > 0)
139                        defaultStoredStrings.add(value);
140                }
141        }
142        
143        return defaultStoredStrings;
144        }
145        
146
147        public void contextDestroyed(ServletContextEvent event) {
148        ServletContext servletContext = event.getServletContext();
149        
150        servletContext.removeAttribute(SHARED_CONTEXT_KEY);
151        }
152}