001/* 002 * (C) Copyright 2011-2014 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * Florent Guillaume 018 * Julien Carsique 019 */ 020package org.nuxeo.runtime.deployment; 021 022import static org.nuxeo.common.Environment.JBOSS_HOST; 023import static org.nuxeo.common.Environment.NUXEO_CONFIG_DIR; 024import static org.nuxeo.common.Environment.NUXEO_DATA_DIR; 025import static org.nuxeo.common.Environment.NUXEO_LOG_DIR; 026import static org.nuxeo.common.Environment.NUXEO_RUNTIME_HOME; 027import static org.nuxeo.common.Environment.NUXEO_TMP_DIR; 028import static org.nuxeo.common.Environment.NUXEO_WEB_DIR; 029import static org.nuxeo.common.Environment.TOMCAT_HOST; 030 031import java.io.BufferedReader; 032import java.io.File; 033import java.io.IOException; 034import java.io.InputStream; 035import java.io.InputStreamReader; 036import java.sql.Driver; 037import java.sql.DriverManager; 038import java.sql.SQLException; 039import java.util.ArrayList; 040import java.util.Arrays; 041import java.util.Enumeration; 042import java.util.HashMap; 043import java.util.List; 044import java.util.Map; 045import java.util.Set; 046 047import javax.servlet.ServletContext; 048import javax.servlet.ServletContextEvent; 049import javax.servlet.ServletContextListener; 050 051import org.apache.commons.logging.Log; 052import org.apache.commons.logging.LogFactory; 053import org.nuxeo.osgi.application.loader.FrameworkLoader; 054import org.osgi.framework.BundleException; 055 056/** 057 * This is called at WAR startup and starts the Nuxeo OSGi runtime and registers the Nuxeo bundles with it. 058 * <p> 059 * This class must be configured as a {@code <listener>/<listener-class>} in {@code META-INF/web.xml}. 060 * <p> 061 * It uses servlet init parameters defined through {@code <context-param>/<param-name>/<param-value>} in web.xml. 062 * Allowable parameter names come from {@link org.nuxeo.common.Environment}, mainly 063 * {@link org.nuxeo.common.Environment#NUXEO_RUNTIME_HOME NUXEO_RUNTIME_HOME} and 064 * {@link org.nuxeo.common.Environment#NUXEO_CONFIG_DIR NUXEO_CONFIG_DIR}, but also 065 * {@link org.nuxeo.common.Environment#NUXEO_DATA_DIR NUXEO_DATA_DIR}, 066 * {@link org.nuxeo.common.Environment#NUXEO_LOG_DIR NUXEO_LOG_DIR}, {@link org.nuxeo.common.Environment#NUXEO_TMP_DIR 067 * NUXEO_TMP_DIR} and {@link org.nuxeo.common.Environment#NUXEO_WEB_DIR NUXEO_WEB_DIR}. 068 */ 069public class NuxeoStarter implements ServletContextListener { 070 071 private static final Log log = LogFactory.getLog(NuxeoStarter.class); 072 073 /** Default location of the home in the server current directory. */ 074 private static final String DEFAULT_HOME = "nuxeo"; 075 076 /** 077 * Name of the file listing Nuxeo bundles. If existing, this file will be used at start, else 078 * {@code "/WEB-INF/lib/"} will be scanned. 079 * 080 * @since 5.9.3 081 * @see #findBundles(ServletContext) 082 */ 083 public static final String NUXEO_BUNDLES_LIST = ".nuxeo-bundles"; 084 085 protected final Map<String, Object> env = new HashMap<>(); 086 087 protected List<File> bundleFiles = new ArrayList<>(); 088 089 @Override 090 public void contextInitialized(ServletContextEvent event) { 091 try { 092 long startTime = System.currentTimeMillis(); 093 start(event); 094 long finishedTime = System.currentTimeMillis(); 095 @SuppressWarnings("boxing") 096 Double duration = (finishedTime - startTime) / 1000.0; 097 log.info(String.format("Nuxeo framework started in %.1f sec.", duration)); 098 } catch (IOException | BundleException e) { 099 log.error("Exception during startup", e); 100 throw new RuntimeException(e); 101 } catch (Throwable e) { // NOSONAR 102 log.error("Exception during startup", e); 103 throw e; 104 } 105 } 106 107 @Override 108 public void contextDestroyed(ServletContextEvent event) { 109 try { 110 stop(); 111 } catch (BundleException e) { 112 throw new RuntimeException(e); 113 } 114 } 115 116 protected void start(ServletContextEvent event) throws IOException, BundleException { 117 ServletContext servletContext = event.getServletContext(); 118 findBundles(servletContext); 119 findEnv(servletContext); 120 121 ClassLoader cl = getClass().getClassLoader(); 122 File home = new File((String) env.get(NUXEO_RUNTIME_HOME)); 123 FrameworkLoader.initialize(cl, home, bundleFiles, env); 124 FrameworkLoader.start(); 125 } 126 127 protected void stop() throws BundleException { 128 FrameworkLoader.stop(); 129 Enumeration<Driver> drivers = DriverManager.getDrivers(); 130 while (drivers.hasMoreElements()) { 131 Driver driver = drivers.nextElement(); 132 try { 133 DriverManager.deregisterDriver(driver); 134 log.info(String.format("Deregister JDBC driver: %s", driver)); 135 } catch (SQLException e) { 136 log.error(String.format("Error deregistering JDBC driver %s", driver), e); 137 } 138 } 139 } 140 141 protected void findBundles(ServletContext servletContext) throws IOException { 142 InputStream bundlesListStream = servletContext.getResourceAsStream("/WEB-INF/" + NUXEO_BUNDLES_LIST); 143 if (bundlesListStream != null) { 144 File lib = new File(servletContext.getRealPath("/WEB-INF/lib/")); 145 try (BufferedReader reader = new BufferedReader(new InputStreamReader(bundlesListStream))) { 146 String bundleName; 147 while ((bundleName = reader.readLine()) != null) { 148 bundleFiles.add(new File(lib, bundleName)); 149 } 150 } 151 } 152 if (bundleFiles.isEmpty()) { // Fallback on directory scan 153 File root = new File(servletContext.getRealPath("/")); 154 Set<String> ctxpaths = servletContext.getResourcePaths("/WEB-INF/lib/"); 155 if (ctxpaths != null) { 156 for (String ctxpath : ctxpaths) { 157 if (!ctxpath.endsWith(".jar")) { 158 continue; 159 } 160 bundleFiles.add(new File(root, ctxpath)); 161 } 162 } 163 } 164 } 165 166 protected void findEnv(ServletContext servletContext) { 167 for (String param : Arrays.asList( // 168 NUXEO_RUNTIME_HOME, // 169 NUXEO_CONFIG_DIR, // 170 NUXEO_DATA_DIR, // 171 NUXEO_LOG_DIR, // 172 NUXEO_TMP_DIR, // 173 NUXEO_WEB_DIR)) { 174 String value = servletContext.getInitParameter(param); 175 if (value != null && !"".equals(value.trim())) { 176 env.put(param, value); 177 } 178 } 179 // default env values 180 if (!env.containsKey(NUXEO_CONFIG_DIR)) { 181 String webinf = servletContext.getRealPath("/WEB-INF"); 182 env.put(NUXEO_CONFIG_DIR, webinf); 183 } 184 if (!env.containsKey(NUXEO_RUNTIME_HOME)) { 185 File home = new File(DEFAULT_HOME); 186 env.put(NUXEO_RUNTIME_HOME, home.getAbsolutePath()); 187 } 188 // host 189 if (getClass().getClassLoader().getClass().getName().startsWith("org.jboss.classloader")) { 190 env.put(FrameworkLoader.HOST_NAME, JBOSS_HOST); 191 } else if (servletContext.getClass().getName().startsWith("org.apache.catalina")) { 192 env.put(FrameworkLoader.HOST_NAME, TOMCAT_HOST); 193 } 194 } 195 196}