001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.plugin;
021    
022    import org.crsh.util.ServletContextMap;
023    import org.crsh.vfs.FS;
024    import org.crsh.vfs.spi.servlet.ServletContextDriver;
025    
026    import javax.servlet.ServletContext;
027    import javax.servlet.ServletContextEvent;
028    import javax.servlet.ServletContextListener;
029    import java.util.HashMap;
030    import java.util.Map;
031    
032    public class WebPluginLifeCycle extends PluginLifeCycle implements ServletContextListener {
033    
034      /** . */
035      private static final Object lock = new Object();
036    
037      /** . */
038      private static final Map<String, PluginContext> contextMap = new HashMap<String, PluginContext>();
039    
040      /** . */
041      private boolean registered = false;
042    
043      /**
044       * Returns a plugin context associated with the servlet context or null if such context does not exist.
045       *
046       * @param sc the servlet context
047       * @return the associated plugin context
048       * @throws NullPointerException if the servlet context argument is null
049       */
050      public static PluginContext getPluginContext(ServletContext sc) throws NullPointerException {
051        String contextPath = sc.getContextPath();
052        synchronized (lock) {
053          return contextMap.get(contextPath);
054        }
055      }
056    
057      /**
058       * Create the service loader discovery, this can be subclassed to provide an implementation, the current
059       * implementation returns a {@link ServiceLoaderDiscovery} instance.
060       *
061       * @param context the servlet context
062       * @param classLoader the class loader
063       * @return the plugin discovery
064       */
065      protected PluginDiscovery createDiscovery(ServletContext context, ClassLoader classLoader) {
066        return new ServiceLoaderDiscovery(classLoader);
067      }
068    
069      public void contextInitialized(ServletContextEvent sce) {
070        ServletContext context = sce.getServletContext();
071        String contextPath = context.getContextPath();
072    
073        // Use JVM properties as external config
074        setConfig(System.getProperties());
075    
076        //
077        synchronized (lock) {
078          if (!contextMap.containsKey(contextPath)) {
079    
080            //
081            FS cmdFS = createCommandFS(context);
082            FS confFS = createConfFS(context);
083            ClassLoader webAppLoader = Thread.currentThread().getContextClassLoader();
084    
085            //
086            PluginContext pluginContext = new PluginContext(
087              createDiscovery(context, webAppLoader),
088              new ServletContextMap(context),
089              cmdFS,
090              confFS,
091              webAppLoader);
092    
093            //
094            contextMap.put(contextPath, pluginContext);
095            registered = true;
096    
097            //
098            start(pluginContext);
099          }
100        }
101      }
102    
103      /**
104       * Create the command file system, this method binds the <code>/WEB-INF/crash/commands/</code> path of the
105       * servlet context.
106       *
107       * @param context the servlet context
108       * @return the command file system
109       */
110      protected FS createCommandFS(ServletContext context) {
111        return new FS().mount(new ServletContextDriver(context, "/WEB-INF/crash/commands/"));
112      }
113    
114      /**
115       * Create the conf file system, this method binds the <code>/WEB-INF/crash/</code> path of the
116       * servlet context.
117       *
118       * @param context the servlet context
119       * @return the conf file system
120       */
121      protected FS createConfFS(ServletContext context) {
122        return new FS().mount(new ServletContextDriver(context, "/WEB-INF/crash/"));
123      }
124    
125      public void contextDestroyed(ServletContextEvent sce) {
126        if (registered) {
127    
128          //
129          ServletContext sc = sce.getServletContext();
130          String contextPath = sc.getContextPath();
131    
132          //
133          synchronized (lock) {
134    
135            //
136            contextMap.remove(contextPath);
137            registered = false;
138    
139            //
140            stop();
141          }
142        }
143      }
144    }