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 contextPath the context path
047 * @return the associated plugin context
048 * @throws NullPointerException if the servlet context argument is null
049 */
050 public static PluginContext getPluginContext(String contextPath) throws NullPointerException {
051 synchronized (lock) {
052 return contextMap.get(contextPath);
053 }
054 }
055
056 /**
057 * Create the service loader discovery, this can be subclassed to provide an implementation, the current
058 * implementation returns a {@link ServiceLoaderDiscovery} instance.
059 *
060 * @param context the servlet context
061 * @param classLoader the class loader
062 * @return the plugin discovery
063 */
064 protected PluginDiscovery createDiscovery(ServletContext context, ClassLoader classLoader) {
065 return new ServiceLoaderDiscovery(classLoader);
066 }
067
068 public void contextInitialized(ServletContextEvent sce) {
069 ServletContext context = sce.getServletContext();
070 String contextPath = context.getContextPath();
071
072 // Use JVM properties as external config
073 setConfig(System.getProperties());
074
075 //
076 synchronized (lock) {
077 if (!contextMap.containsKey(contextPath)) {
078
079 //
080 FS cmdFS = createCommandFS(context);
081 FS confFS = createConfFS(context);
082 ClassLoader webAppLoader = Thread.currentThread().getContextClassLoader();
083 PluginDiscovery discovery = createDiscovery(context, webAppLoader);
084
085 //
086 PluginContext pluginContext = createPluginContext(context, cmdFS, confFS, discovery);
087
088 //
089 contextMap.put(contextPath, pluginContext);
090 registered = true;
091
092 //
093 start(pluginContext);
094 }
095 }
096 }
097
098 /**
099 * Create the plugin context, allowing subclasses to provide a custom configuration.
100 *
101 * @param context the servlet context
102 * @param cmdFS the command file system
103 * @param confFS the conf file system
104 * @param discovery the plugin discovery
105 * @return the plugin context
106 */
107 protected PluginContext createPluginContext(ServletContext context, FS cmdFS, FS confFS, PluginDiscovery discovery) {
108 return new PluginContext(discovery, new ServletContextMap(context), cmdFS, confFS, context.getClassLoader());
109 }
110
111 /**
112 * Create the command file system, this method binds the <code>/WEB-INF/crash/commands/</code> path of the
113 * servlet context.
114 *
115 * @param context the servlet context
116 * @return the command file system
117 */
118 protected FS createCommandFS(ServletContext context) {
119 return new FS().mount(new ServletContextDriver(context, "/WEB-INF/crash/commands/"));
120 }
121
122 /**
123 * Create the conf file system, this method binds the <code>/WEB-INF/crash/</code> path of the
124 * servlet context.
125 *
126 * @param context the servlet context
127 * @return the conf file system
128 */
129 protected FS createConfFS(ServletContext context) {
130 return new FS().mount(new ServletContextDriver(context, "/WEB-INF/crash/"));
131 }
132
133 public void contextDestroyed(ServletContextEvent sce) {
134 if (registered) {
135
136 //
137 ServletContext sc = sce.getServletContext();
138 String contextPath = sc.getContextPath();
139
140 //
141 synchronized (lock) {
142
143 //
144 contextMap.remove(contextPath);
145 registered = false;
146
147 //
148 stop();
149 }
150 }
151 }
152 }