/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ package org.apache.ignite.startup.servlet; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.IgnitionEx; import org.apache.ignite.internal.processors.resource.GridSpringResourceContext; import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiTuple; /** * This class defines servlet-based Ignite startup. This startup can be used to start Ignite * inside any web container as servlet. * <p> * This startup must be defined in {@code web.xml} file. * <pre name="code" class="xml"> * <servlet> * <servlet-name>Ignite</servlet-name> * <servlet-class>org.apache.ignite.startup.servlet.ServletStartup</servlet-class> * <init-param> * <param-name>cfgFilePath</param-name> * <param-value>config/default-config.xml</param-value> * </init-param> * <load-on-startup>1</load-on-startup> * </servlet> * </pre> * <p> * Servlet-based startup may be used in any web container like Tomcat, Jetty and etc. * Depending on the way this startup is deployed the Ignite instance can be accessed * by either all web applications or by only one. See web container class loading architecture: * <ul> * <li><a target=_blank href="http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html">http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html</a></li> * <li><a target=_blank href="http://docs.codehaus.org/display/JETTY/Classloading">http://docs.codehaus.org/display/JETTY/Classloading</a></li> * </ul> * <p> * <h2 class="header">Tomcat</h2> * There are two ways to start Ignite on Tomcat. * <ul> * <li>Ignite started when web container starts and Ignite instance is accessible only to all web applications. * <ol> * <li>Add Ignite libraries in Tomcat common loader. * Add in file {@code $TOMCAT_HOME/conf/catalina.properties} for property {@code shared.loader} * the following {@code $IGNITE_HOME/ignite.jar,$IGNITE_HOME/libs/*.jar} * (replace {@code $IGNITE_HOME} with absolute path). * </li> * <li>Configure startup in {@code $TOMCAT_HOME/conf/web.xml} * <pre name="code" class="xml"> * <servlet> * <servlet-name>Ignite</servlet-name> * <servlet-class>org.apache.ignite.startup.servlet.ServletStartup</servlet-class> * <init-param> * <param-name>cfgFilePath</param-name> * <param-value>config/default-config.xml</param-value> * </init-param> * <load-on-startup>1</load-on-startup> * </servlet> * </pre> * </li> * </ol> * </li> * <li> * Ignite started from WAR-file and Ignite instance is accessible only to that web application. * Difference with approach described above is that {@code web.xml} file and all libraries should * be added in WAR file without changes in Tomcat configuration files. * </li> * </ul> * <p> * <h2 class="header">Jetty</h2> * Below is Java code example with Jetty API: * <pre name="code" class="java"> * Server service = new Server(); * * service.addListener("localhost:8090"); * * ServletHttpContext ctx = (ServletHttpContext)service.getContext("/"); * * ServletHolder servlet = ctx.addServlet("Ignite", "/IgniteStartup", * "org.apache.ignite.startup.servlet.ServletStartup"); * * servlet.setInitParameter("cfgFilePath", "config/default-config.xml"); * * servlet.setInitOrder(1); * * servlet.start(); * * service.start(); * </pre> */ public class ServletStartup extends HttpServlet { /** */ private static final long serialVersionUID = 0L; /** Grid loaded flag. */ private static boolean loaded; /** Configuration file path variable name. */ private static final String cfgFilePathParam = "cfgFilePath"; /** */ private Collection<String> igniteInstanceNames = new ArrayList<>(); /** {@inheritDoc} */ @SuppressWarnings({"unchecked"}) @Override public void init() throws ServletException { // Avoid multiple servlet instances. Ignite should be loaded once. if (loaded) return; String cfgFile = getServletConfig().getInitParameter(cfgFilePathParam); if (cfgFile == null) throw new ServletException("Failed to read property: " + cfgFilePathParam); URL cfgUrl = U.resolveIgniteUrl(cfgFile); if (cfgUrl == null) throw new ServletException("Failed to find Spring configuration file (path provided should be " + "either absolute, relative to IGNITE_HOME, or relative to META-INF folder): " + cfgFile); try { IgniteBiTuple<Collection<IgniteConfiguration>, ? extends GridSpringResourceContext> t = IgnitionEx.loadConfigurations(cfgUrl); Collection<IgniteConfiguration> cfgs = t.get1(); if (cfgs == null) throw new ServletException("Failed to find a single grid factory configuration in: " + cfgUrl); for (IgniteConfiguration cfg : cfgs) { assert cfg != null; IgniteConfiguration adapter = new IgniteConfiguration(cfg); Ignite ignite = IgnitionEx.start(adapter, t.get2()); // Test if grid is not null - started properly. if (ignite != null) igniteInstanceNames.add(ignite.name()); } } catch (IgniteCheckedException e) { // Stop started grids only. for (String name: igniteInstanceNames) G.stop(name, true); throw new ServletException("Failed to start Ignite.", e); } loaded = true; } /** {@inheritDoc} */ @Override public void destroy() { // Stop started grids only. for (String name: igniteInstanceNames) G.stop(name, true); loaded = false; } /** {@inheritDoc} */ @Override public String toString() { return S.toString(ServletStartup.class, this); } }