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 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}