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    
021    package org.granite.messaging.jmf;
022    
023    import java.util.ArrayList;
024    import java.util.Collections;
025    import java.util.List;
026    
027    import javax.servlet.ServletContext;
028    import javax.servlet.ServletContextEvent;
029    import javax.servlet.ServletContextListener;
030    import javax.servlet.ServletException;
031    
032    import org.granite.config.GraniteConfigListener;
033    import org.granite.logging.Logger;
034    import org.granite.messaging.jmf.codec.ExtendedObjectCodec;
035    import org.granite.util.JMFAMFUtil;
036    
037    /**
038     * @author Franck WOLFF
039     */
040    public 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    }