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.util.Utils; 024 import org.crsh.vfs.spi.FSMountFactory; 025 import org.crsh.vfs.spi.file.FileMountFactory; 026 import org.crsh.vfs.spi.servlet.WarMountFactory; 027 import org.crsh.vfs.spi.url.ClassPathMountFactory; 028 029 import javax.servlet.ServletContext; 030 import javax.servlet.ServletContextEvent; 031 import javax.servlet.ServletContextListener; 032 import java.util.HashMap; 033 import java.util.Map; 034 import java.util.logging.Level; 035 036 public class WebPluginLifeCycle extends Embedded implements ServletContextListener { 037 038 /** . */ 039 private static final Object lock = new Object(); 040 041 /** . */ 042 private static final Map<String, PluginContext> contextMap = new HashMap<String, PluginContext>(); 043 044 /** . */ 045 private boolean registered = false; 046 047 /** . */ 048 private Map<String, FSMountFactory<?>> mountContexts = new HashMap<String, FSMountFactory<?>>(3); 049 050 /** . */ 051 private ServletContext context; 052 053 /** 054 * Returns a plugin context associated with the servlet context or null if such context does not exist. 055 * 056 * @param contextPath the context path 057 * @return the associated plugin context 058 * @throws NullPointerException if the servlet context argument is null 059 */ 060 public static PluginContext getPluginContext(String contextPath) throws NullPointerException { 061 synchronized (lock) { 062 return contextMap.get(contextPath); 063 } 064 } 065 066 /** 067 * This implementation register three file system drivers: 068 * <ul> 069 * <li><code>file</code> : the current file system</li> 070 * <li><code>classpath</code> : the classpath</li> 071 * <li><code>war</code> : the war content</li> 072 * </ul> 073 * 074 * @return the drivers 075 */ 076 @Override 077 protected Map<String, FSMountFactory<?>> getMountFactories() { 078 return mountContexts; 079 } 080 081 /** 082 * Create the service loader discovery, this can be subclassed to provide an implementation, the current 083 * implementation returns a {@link ServiceLoaderDiscovery} instance. 084 * 085 * @param context the servlet context 086 * @param classLoader the class loader 087 * @return the plugin discovery 088 */ 089 protected PluginDiscovery createDiscovery(ServletContext context, ClassLoader classLoader) { 090 return new ServiceLoaderDiscovery(classLoader); 091 } 092 093 public void contextInitialized(ServletContextEvent sce) { 094 context = sce.getServletContext(); 095 096 // Use JVM properties as external config 097 setConfig(System.getProperties()); 098 099 // Initialise the registerable drivers 100 try { 101 mountContexts.put("classpath", new ClassPathMountFactory(context.getClassLoader())); 102 mountContexts.put("file", new FileMountFactory(Utils.getCurrentDirectory())); 103 mountContexts.put("war", new WarMountFactory(context)); 104 } 105 catch (Exception e) { 106 log.log(Level.SEVERE, "Coult not initialize classpath driver", e); 107 return; 108 } 109 110 // 111 String contextPath = context.getContextPath(); 112 synchronized (lock) { 113 if (!contextMap.containsKey(contextPath)) { 114 ClassLoader webAppLoader = Thread.currentThread().getContextClassLoader(); 115 PluginDiscovery discovery = createDiscovery(context, webAppLoader); 116 PluginContext pluginContext = start(new ServletContextMap(context), discovery, context.getClassLoader()); 117 contextMap.put(contextPath, pluginContext); 118 registered = true; 119 } 120 } 121 } 122 123 /** 124 * The path property is resolved from the servlet context parameters. When the parameter does not exist, 125 * the <code>defaultValue</code> argument is used instead, so it should not be null. 126 * After the path is resolved, it is interpolated using the JVM system properties and the syntax 127 * defined by the {@link org.crsh.util.Utils#interpolate(String, java.util.Map)} function. 128 * 129 * @param propertyName the property name to resolve 130 * @param defaultValue the default property value 131 * @return the path value 132 */ 133 private String resolvePathProperty(String propertyName, String defaultValue) { 134 String path = context.getInitParameter(propertyName); 135 if (path == null) { 136 path = defaultValue; 137 } 138 return Utils.interpolate(path, System.getProperties()); 139 } 140 141 /** 142 * @return the value returned by {@link #resolvePathProperty(String, String)} with the <code>crash.mountpointconfig.conf</code> name 143 * and the {@link #getDefaultConfMountPointConfig()} default value 144 */ 145 @Override 146 protected String resolveConfMountPointConfig() { 147 return resolvePathProperty("crash.mountpointconfig.conf", getDefaultConfMountPointConfig()); 148 } 149 150 /** 151 * @return the value returned by {@link #resolvePathProperty(String, String)} with the <code>crash.mountpointconfig.cmd</code> name 152 * and the {@link #getDefaultCmdMountPointConfig()} default value 153 */ 154 @Override 155 protected String resolveCmdMountPointConfig() { 156 return resolvePathProperty("crash.mountpointconfig.cmd", getDefaultCmdMountPointConfig()); 157 } 158 159 /** 160 * @return <code>war:/WEB-INF/crash/commands/</code> 161 */ 162 protected String getDefaultCmdMountPointConfig() { 163 return "war:/WEB-INF/crash/commands/"; 164 } 165 166 /** 167 * @return <code>war:/WEB-INF/crash/</code> 168 */ 169 protected String getDefaultConfMountPointConfig() { 170 return "war:/WEB-INF/crash"; 171 } 172 173 public void contextDestroyed(ServletContextEvent sce) { 174 if (registered) { 175 176 // 177 ServletContext sc = sce.getServletContext(); 178 String contextPath = sc.getContextPath(); 179 180 // 181 synchronized (lock) { 182 183 // 184 contextMap.remove(contextPath); 185 registered = false; 186 187 // 188 stop(); 189 } 190 } 191 } 192 }