/*
* (C) Copyright 2011-2014 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Contributors:
* Florent Guillaume
* Julien Carsique
*/
package org.nuxeo.runtime.deployment;
import static org.nuxeo.common.Environment.JBOSS_HOST;
import static org.nuxeo.common.Environment.NUXEO_CONFIG_DIR;
import static org.nuxeo.common.Environment.NUXEO_DATA_DIR;
import static org.nuxeo.common.Environment.NUXEO_LOG_DIR;
import static org.nuxeo.common.Environment.NUXEO_RUNTIME_HOME;
import static org.nuxeo.common.Environment.NUXEO_TMP_DIR;
import static org.nuxeo.common.Environment.NUXEO_WEB_DIR;
import static org.nuxeo.common.Environment.TOMCAT_HOST;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nuxeo.osgi.application.loader.FrameworkLoader;
import org.osgi.framework.BundleException;
/**
* This is called at WAR startup and starts the Nuxeo OSGi runtime and registers the Nuxeo bundles with it.
* <p>
* This class must be configured as a {@code <listener>/<listener-class>} in {@code META-INF/web.xml}.
* <p>
* It uses servlet init parameters defined through {@code <context-param>/<param-name>/<param-value>} in web.xml.
* Allowable parameter names come from {@link org.nuxeo.common.Environment}, mainly
* {@link org.nuxeo.common.Environment#NUXEO_RUNTIME_HOME NUXEO_RUNTIME_HOME} and
* {@link org.nuxeo.common.Environment#NUXEO_CONFIG_DIR NUXEO_CONFIG_DIR}, but also
* {@link org.nuxeo.common.Environment#NUXEO_DATA_DIR NUXEO_DATA_DIR},
* {@link org.nuxeo.common.Environment#NUXEO_LOG_DIR NUXEO_LOG_DIR}, {@link org.nuxeo.common.Environment#NUXEO_TMP_DIR
* NUXEO_TMP_DIR} and {@link org.nuxeo.common.Environment#NUXEO_WEB_DIR NUXEO_WEB_DIR}.
*/
public class NuxeoStarter implements ServletContextListener {
private static final Log log = LogFactory.getLog(NuxeoStarter.class);
/** Default location of the home in the server current directory. */
private static final String DEFAULT_HOME = "nuxeo";
/**
* Name of the file listing Nuxeo bundles. If existing, this file will be used at start, else
* {@code "/WEB-INF/lib/"} will be scanned.
*
* @since 5.9.3
* @see #findBundles(ServletContext)
*/
public static final String NUXEO_BUNDLES_LIST = ".nuxeo-bundles";
protected final Map<String, Object> env = new HashMap<>();
protected List<File> bundleFiles = new ArrayList<>();
@Override
public void contextInitialized(ServletContextEvent event) {
try {
long startTime = System.currentTimeMillis();
start(event);
long finishedTime = System.currentTimeMillis();
@SuppressWarnings("boxing")
Double duration = (finishedTime - startTime) / 1000.0;
log.info(String.format("Nuxeo framework started in %.1f sec.", duration));
} catch (IOException | BundleException e) {
throw new RuntimeException(e);
}
}
@Override
public void contextDestroyed(ServletContextEvent event) {
try {
stop();
} catch (BundleException e) {
throw new RuntimeException(e);
}
}
protected void start(ServletContextEvent event) throws IOException, BundleException {
ServletContext servletContext = event.getServletContext();
findBundles(servletContext);
findEnv(servletContext);
ClassLoader cl = getClass().getClassLoader();
File home = new File((String) env.get(NUXEO_RUNTIME_HOME));
FrameworkLoader.initialize(cl, home, bundleFiles, env);
FrameworkLoader.start();
}
protected void stop() throws BundleException {
FrameworkLoader.stop();
Enumeration<Driver> drivers = DriverManager.getDrivers();
while (drivers.hasMoreElements()) {
Driver driver = drivers.nextElement();
try {
DriverManager.deregisterDriver(driver);
log.warn(String.format("Deregister JDBC driver: %s", driver));
} catch (SQLException e) {
log.error(String.format("Error deregistering JDBC driver %s", driver), e);
}
}
}
protected void findBundles(ServletContext servletContext) throws IOException {
InputStream bundlesListStream = servletContext.getResourceAsStream("/WEB-INF/" + NUXEO_BUNDLES_LIST);
if (bundlesListStream != null) {
File lib = new File(servletContext.getRealPath("/WEB-INF/lib/"));
try (BufferedReader reader = new BufferedReader(new InputStreamReader(bundlesListStream))) {
String bundleName;
while ((bundleName = reader.readLine()) != null) {
bundleFiles.add(new File(lib, bundleName));
}
}
}
if (bundleFiles.isEmpty()) { // Fallback on directory scan
File root = new File(servletContext.getRealPath("/"));
Set<String> ctxpaths = servletContext.getResourcePaths("/WEB-INF/lib/");
if (ctxpaths != null) {
for (String ctxpath : ctxpaths) {
if (!ctxpath.endsWith(".jar")) {
continue;
}
bundleFiles.add(new File(root, ctxpath));
}
}
}
}
protected void findEnv(ServletContext servletContext) {
for (String param : Arrays.asList( //
NUXEO_RUNTIME_HOME, //
NUXEO_CONFIG_DIR, //
NUXEO_DATA_DIR, //
NUXEO_LOG_DIR, //
NUXEO_TMP_DIR, //
NUXEO_WEB_DIR)) {
String value = servletContext.getInitParameter(param);
if (value != null && !"".equals(value.trim())) {
env.put(param, value);
}
}
// default env values
if (!env.containsKey(NUXEO_CONFIG_DIR)) {
String webinf = servletContext.getRealPath("/WEB-INF");
env.put(NUXEO_CONFIG_DIR, webinf);
}
if (!env.containsKey(NUXEO_RUNTIME_HOME)) {
File home = new File(DEFAULT_HOME);
env.put(NUXEO_RUNTIME_HOME, home.getAbsolutePath());
}
// host
if (getClass().getClassLoader().getClass().getName().startsWith("org.jboss.classloader")) {
env.put(FrameworkLoader.HOST_NAME, JBOSS_HOST);
} else if (servletContext.getClass().getName().startsWith("org.apache.catalina")) {
env.put(FrameworkLoader.HOST_NAME, TOMCAT_HOST);
}
}
}