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
020package org.crsh.plugin;
021
022import org.crsh.util.ServletContextMap;
023import org.crsh.vfs.FS;
024import org.crsh.vfs.spi.servlet.ServletContextDriver;
025
026import javax.servlet.ServletContext;
027import javax.servlet.ServletContextEvent;
028import javax.servlet.ServletContextListener;
029import java.util.HashMap;
030import java.util.Map;
031
032public 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}