| /******************************************************************************* |
| * 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.ofbiz.catalina.container; |
| |
| import java.io.File; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.concurrent.Callable; |
| import java.util.concurrent.Future; |
| import java.util.concurrent.ScheduledExecutorService; |
| |
| import javax.naming.InitialContext; |
| import javax.naming.NamingException; |
| |
| import org.apache.catalina.Cluster; |
| import org.apache.catalina.Context; |
| import org.apache.catalina.Engine; |
| import org.apache.catalina.Globals; |
| import org.apache.catalina.Host; |
| import org.apache.catalina.LifecycleException; |
| import org.apache.catalina.Manager; |
| import org.apache.catalina.connector.Connector; |
| import org.apache.catalina.core.StandardContext; |
| import org.apache.catalina.core.StandardEngine; |
| import org.apache.catalina.core.StandardHost; |
| import org.apache.catalina.core.StandardServer; |
| import org.apache.catalina.filters.RequestDumperFilter; |
| import org.apache.catalina.ha.tcp.ReplicationValve; |
| import org.apache.catalina.ha.tcp.SimpleTcpCluster; |
| import org.apache.catalina.loader.WebappLoader; |
| import org.apache.catalina.startup.ContextConfig; |
| import org.apache.catalina.startup.Tomcat; |
| import org.apache.catalina.tribes.group.GroupChannel; |
| import org.apache.catalina.tribes.membership.McastService; |
| import org.apache.catalina.tribes.transport.MultiPointSender; |
| import org.apache.catalina.tribes.transport.ReplicationTransmitter; |
| import org.apache.catalina.tribes.transport.nio.NioReceiver; |
| import org.apache.catalina.util.ServerInfo; |
| import org.apache.catalina.valves.AccessLogValve; |
| import org.apache.catalina.webresources.StandardRoot; |
| import org.apache.tomcat.JarScanner; |
| import org.apache.tomcat.util.IntrospectionUtils; |
| import org.apache.tomcat.util.descriptor.web.FilterDef; |
| import org.apache.tomcat.util.descriptor.web.FilterMap; |
| import org.apache.tomcat.util.scan.StandardJarScanner; |
| import org.apache.ofbiz.base.component.ComponentConfig; |
| import org.apache.ofbiz.base.concurrent.ExecutionPool; |
| import org.apache.ofbiz.base.container.Container; |
| import org.apache.ofbiz.base.container.ContainerConfig; |
| import org.apache.ofbiz.base.container.ContainerConfig.Configuration.Property; |
| import org.apache.ofbiz.base.container.ContainerException; |
| import org.apache.ofbiz.base.location.FlexibleLocation; |
| import org.apache.ofbiz.base.start.Start; |
| import org.apache.ofbiz.base.start.StartupCommand; |
| import org.apache.ofbiz.base.util.Debug; |
| import org.apache.ofbiz.base.util.SSLUtil; |
| import org.apache.ofbiz.base.util.UtilValidate; |
| import org.apache.ofbiz.base.util.UtilXml; |
| import org.w3c.dom.Document; |
| |
| /* |
| * --- Access Log Pattern Information - From Tomcat 5 AccessLogValve.java |
| * <p>Patterns for the logged message may include constant text or any of the |
| * following replacement strings, for which the corresponding information |
| * from the specified Response is substituted:</p> |
| * <ul> |
| * <li><b>%a</b> - Remote IP address |
| * <li><b>%A</b> - Local IP address |
| * <li><b>%b</b> - Bytes sent, excluding HTTP headers, or '-' if no bytes |
| * were sent |
| * <li><b>%B</b> - Bytes sent, excluding HTTP headers |
| * <li><b>%h</b> - Remote host name |
| * <li><b>%H</b> - Request protocol |
| * <li><b>%l</b> - Remote logical username from identd (always returns '-') |
| * <li><b>%m</b> - Request method |
| * <li><b>%p</b> - Local port |
| * <li><b>%q</b> - Query string (prepended with a '?' if it exists, otherwise |
| * an empty string |
| * <li><b>%r</b> - First line of the request |
| * <li><b>%s</b> - HTTP status code of the response |
| * <li><b>%S</b> - User session ID |
| * <li><b>%t</b> - Date and time, in Common Log Format format |
| * <li><b>%u</b> - Remote user that was authenticated |
| * <li><b>%U</b> - Requested URL path |
| * <li><b>%v</b> - Local server name |
| * <li><b>%D</b> - Time taken to process the request, in millis |
| * <li><b>%T</b> - Time taken to process the request, in seconds |
| * </ul> |
| * <p>In addition, the caller can specify one of the following aliases for |
| * commonly utilized patterns:</p> |
| * <ul> |
| * <li><b>common</b> - <code>%h %l %u %t "%r" %s %b</code> |
| * <li><b>combined</b> - |
| * <code>%h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i"</code> |
| * </ul> |
| * |
| * <p> |
| * There is also support to write information from the cookie, incoming |
| * header, the Session or something else in the ServletRequest.<br/> |
| * It is modeled after the apache syntax: |
| * <ul> |
| * <li><code>%{xxx}i</code> for incoming headers |
| * <li><code>%{xxx}c</code> for a specific cookie |
| * <li><code>%{xxx}r</code> xxx is an attribute in the ServletRequest |
| * <li><code>%{xxx}s</code> xxx is an attribute in the HttpSession |
| * </ul> |
| * </p> |
| */ |
| |
| /** |
| * CatalinaContainer - Tomcat |
| * |
| */ |
| public class CatalinaContainer implements Container { |
| |
| public static final String CATALINA_HOSTS_HOME = System.getProperty("ofbiz.home") + "/framework/catalina/hosts"; |
| public static final String J2EE_SERVER = "OFBiz Container 3.1"; |
| public static final String J2EE_APP = "OFBiz"; |
| public static final String module = CatalinaContainer.class.getName(); |
| private static final ThreadGroup CATALINA_THREAD_GROUP = new ThreadGroup("CatalinaContainer"); |
| |
| // load the JSSE properties (set the trust store) |
| static { |
| SSLUtil.loadJsseProperties(); |
| } |
| |
| private Tomcat tomcat = null; |
| protected Map<String, ContainerConfig.Configuration.Property> clusterConfig = new HashMap<String, ContainerConfig.Configuration.Property>(); |
| |
| protected boolean contextReloadable = false; |
| protected boolean crossContext = false; |
| protected boolean distribute = false; |
| |
| protected String catalinaRuntimeHome; |
| |
| private String name; |
| |
| @Override |
| public void init(List<StartupCommand> ofbizCommands, String name, String configFile) throws ContainerException { |
| this.name = name; |
| // get the container config |
| ContainerConfig.Configuration cc = ContainerConfig.getConfiguration(name, configFile); |
| if (cc == null) { |
| throw new ContainerException("No catalina-container configuration found in container config!"); |
| } |
| |
| // embedded properties |
| boolean useNaming = ContainerConfig.getPropertyValue(cc, "use-naming", false); |
| //int debug = ContainerConfig.getPropertyValue(cc, "debug", 0); |
| |
| // grab some global context settings |
| this.contextReloadable = ContainerConfig.getPropertyValue(cc, "apps-context-reloadable", false); |
| this.crossContext = ContainerConfig.getPropertyValue(cc, "apps-cross-context", true); |
| this.distribute = ContainerConfig.getPropertyValue(cc, "apps-distributable", true); |
| |
| this.catalinaRuntimeHome = ContainerConfig.getPropertyValue(cc, "catalina-runtime-home", "runtime/catalina"); |
| |
| // set catalina_home |
| System.setProperty(Globals.CATALINA_HOME_PROP, System.getProperty("ofbiz.home") + "/" + this.catalinaRuntimeHome); |
| System.setProperty(Globals.CATALINA_BASE_PROP, System.getProperty(Globals.CATALINA_HOME_PROP)); |
| |
| // create the instance of embedded Tomcat |
| System.setProperty("catalina.useNaming", String.valueOf(useNaming)); |
| tomcat = new Tomcat(); |
| tomcat.setBaseDir(System.getProperty("ofbiz.home")); |
| |
| // configure JNDI in the StandardServer |
| StandardServer server = (StandardServer) tomcat.getServer(); |
| if (useNaming) { |
| tomcat.enableNaming(); |
| } |
| try { |
| server.setGlobalNamingContext(new InitialContext()); |
| } catch (NamingException e) { |
| throw new ContainerException(e); |
| } |
| |
| // create the engine |
| List<ContainerConfig.Configuration.Property> engineProps = cc.getPropertiesWithValue("engine"); |
| if (UtilValidate.isEmpty(engineProps)) { |
| throw new ContainerException("Cannot load CatalinaContainer; no engines defined."); |
| } |
| if (engineProps.size() > 1) { |
| throw new ContainerException("Cannot load CatalinaContainer; more than one engine configuration found; only one is supported."); |
| } |
| createEngine(engineProps.get(0)); |
| |
| // create the connectors |
| List<ContainerConfig.Configuration.Property> connectorProps = cc.getPropertiesWithValue("connector"); |
| if (UtilValidate.isEmpty(connectorProps)) { |
| throw new ContainerException("Cannot load CatalinaContainer; no connectors defined!"); |
| } |
| for (ContainerConfig.Configuration.Property connectorProp: connectorProps) { |
| createConnector(connectorProp); |
| } |
| } |
| |
| public boolean start() throws ContainerException { |
| // load the web applications |
| loadComponents(); |
| |
| // Start the Tomcat server |
| try { |
| tomcat.getServer().start(); |
| } catch (LifecycleException e) { |
| throw new ContainerException(e); |
| } |
| |
| for (Connector con: tomcat.getService().findConnectors()) { |
| Debug.logInfo("Connector " + con.getProtocol() + " @ " + con.getPort() + " - " + |
| (con.getSecure() ? "secure" : "not-secure") + " [" + con.getProtocolHandlerClassName() + "] started.", module); |
| } |
| Debug.logInfo("Started " + ServerInfo.getServerInfo(), module); |
| return true; |
| } |
| |
| private Engine createEngine(ContainerConfig.Configuration.Property engineConfig) throws ContainerException { |
| if (tomcat == null) { |
| throw new ContainerException("Cannot create Engine without Tomcat instance!"); |
| } |
| |
| ContainerConfig.Configuration.Property defaultHostProp = engineConfig.getProperty("default-host"); |
| if (defaultHostProp == null) { |
| throw new ContainerException("default-host element of server property is required for catalina!"); |
| } |
| |
| String engineName = engineConfig.name; |
| String hostName = defaultHostProp.value; |
| |
| tomcat.setHostname(hostName); |
| Engine engine = tomcat.getEngine(); |
| engine.setName(engineName); |
| |
| // set the JVM Route property (JK/JK2) |
| String jvmRoute = ContainerConfig.getPropertyValue(engineConfig, "jvm-route", null); |
| if (jvmRoute != null) { |
| engine.setJvmRoute(jvmRoute); |
| } |
| |
| // create a default virtual host; others will be created as needed |
| Host host = tomcat.getHost(); |
| configureHost(host); |
| |
| // configure clustering |
| List<ContainerConfig.Configuration.Property> clusterProps = engineConfig.getPropertiesWithValue("cluster"); |
| if (clusterProps != null && clusterProps.size() > 1) { |
| throw new ContainerException("Only one cluster configuration allowed per engine"); |
| } |
| |
| if (UtilValidate.isNotEmpty(clusterProps)) { |
| ContainerConfig.Configuration.Property clusterProp = clusterProps.get(0); |
| createCluster(clusterProp, host); |
| clusterConfig.put(engineName, clusterProp); |
| } |
| |
| // configure the CrossSubdomainSessionValve |
| boolean enableSessionValve = ContainerConfig.getPropertyValue(engineConfig, "enable-cross-subdomain-sessions", false); |
| if (enableSessionValve) { |
| CrossSubdomainSessionValve sessionValve = new CrossSubdomainSessionValve(); |
| ((StandardEngine)engine).addValve(sessionValve); |
| } |
| |
| // configure the access log valve |
| String logDir = ContainerConfig.getPropertyValue(engineConfig, "access-log-dir", null); |
| AccessLogValve al = null; |
| if (logDir != null) { |
| al = new AccessLogValve(); |
| if (!logDir.startsWith("/")) { |
| logDir = System.getProperty("ofbiz.home") + "/" + logDir; |
| } |
| File logFile = new File(logDir); |
| if (!logFile.isDirectory()) { |
| throw new ContainerException("Log directory [" + logDir + "] is not available; make sure the directory is created"); |
| } |
| al.setDirectory(logFile.getAbsolutePath()); |
| } |
| |
| // configure the SslAcceleratorValve |
| String sslAcceleratorPortStr = ContainerConfig.getPropertyValue(engineConfig, "ssl-accelerator-port", null); |
| if (UtilValidate.isNotEmpty(sslAcceleratorPortStr)) { |
| Integer sslAcceleratorPort = Integer.valueOf(sslAcceleratorPortStr); |
| SslAcceleratorValve sslAcceleratorValve = new SslAcceleratorValve(); |
| sslAcceleratorValve.setSslAcceleratorPort(sslAcceleratorPort); |
| ((StandardEngine)engine).addValve(sslAcceleratorValve); |
| } |
| |
| |
| String alp2 = ContainerConfig.getPropertyValue(engineConfig, "access-log-pattern", null); |
| if (al != null && UtilValidate.isNotEmpty(alp2)) { |
| al.setPattern(alp2); |
| } |
| |
| String alp3 = ContainerConfig.getPropertyValue(engineConfig, "access-log-prefix", null); |
| if (al != null && UtilValidate.isNotEmpty(alp3)) { |
| al.setPrefix(alp3); |
| } |
| |
| boolean alp5 = ContainerConfig.getPropertyValue(engineConfig, "access-log-rotate", false); |
| if (al != null) { |
| al.setRotatable(alp5); |
| } |
| |
| if (al != null) { |
| ((StandardEngine)engine).addValve(al); |
| } |
| |
| return engine; |
| } |
| |
| private static Host createHost(String hostName) { |
| Host host = new StandardHost(); |
| host.setName(hostName); |
| configureHost(host); |
| return host; |
| } |
| private static void configureHost(Host host) { |
| host.setAppBase(CATALINA_HOSTS_HOME); |
| host.setDeployOnStartup(false); |
| host.setBackgroundProcessorDelay(5); |
| host.setAutoDeploy(false); |
| ((StandardHost)host).setWorkDir(new File(System.getProperty(Globals.CATALINA_HOME_PROP), "work" + File.separator + host.getName()).getAbsolutePath()); |
| } |
| |
| protected Cluster createCluster(ContainerConfig.Configuration.Property clusterProps, Host host) throws ContainerException { |
| String defaultValveFilter = ".*\\.gif;.*\\.js;.*\\.jpg;.*\\.htm;.*\\.html;.*\\.txt;.*\\.png;.*\\.css;.*\\.ico;.*\\.htc;"; |
| |
| ReplicationValve clusterValve = new ReplicationValve(); |
| clusterValve.setFilter(ContainerConfig.getPropertyValue(clusterProps, "rep-valve-filter", defaultValveFilter)); |
| |
| String mcb = ContainerConfig.getPropertyValue(clusterProps, "mcast-bind-addr", null); |
| String mca = ContainerConfig.getPropertyValue(clusterProps, "mcast-addr", null); |
| int mcp = ContainerConfig.getPropertyValue(clusterProps, "mcast-port", -1); |
| int mcf = ContainerConfig.getPropertyValue(clusterProps, "mcast-freq", 500); |
| int mcd = ContainerConfig.getPropertyValue(clusterProps, "mcast-drop-time", 3000); |
| |
| if (mca == null || mcp == -1) { |
| throw new ContainerException("Cluster configuration requires mcast-addr and mcast-port properties"); |
| } |
| |
| McastService mcast = new McastService(); |
| if (mcb != null) { |
| mcast.setMcastBindAddress(mcb); |
| } |
| |
| mcast.setAddress(mca); |
| mcast.setPort(mcp); |
| mcast.setMcastDropTime(mcd); |
| mcast.setFrequency(mcf); |
| |
| String tla = ContainerConfig.getPropertyValue(clusterProps, "tcp-listen-host", "auto"); |
| int tlp = ContainerConfig.getPropertyValue(clusterProps, "tcp-listen-port", 4001); |
| int tlt = ContainerConfig.getPropertyValue(clusterProps, "tcp-sector-timeout", 100); |
| int tlc = ContainerConfig.getPropertyValue(clusterProps, "tcp-thread-count", 6); |
| //String tls = getPropertyValue(clusterProps, "", ""); |
| |
| if (tlp == -1) { |
| throw new ContainerException("Cluster configuration requires tcp-listen-port property"); |
| } |
| |
| NioReceiver listener = new NioReceiver(); |
| listener.setAddress(tla); |
| listener.setPort(tlp); |
| listener.setSelectorTimeout(tlt); |
| listener.setMaxThreads(tlc); |
| listener.setMinThreads(tlc); |
| //listener.setIsSenderSynchronized(false); |
| |
| ReplicationTransmitter trans = new ReplicationTransmitter(); |
| try { |
| MultiPointSender mps = (MultiPointSender)Class.forName(ContainerConfig.getPropertyValue(clusterProps, "replication-mode", "org.apache.catalina.tribes.transport.bio.PooledMultiSender")).newInstance(); |
| trans.setTransport(mps); |
| } catch (Exception exc) { |
| throw new ContainerException("Cluster configuration requires a valid replication-mode property: " + exc.getMessage()); |
| } |
| String mgrClassName = ContainerConfig.getPropertyValue(clusterProps, "manager-class", "org.apache.catalina.ha.session.DeltaManager"); |
| //int debug = ContainerConfig.getPropertyValue(clusterProps, "debug", 0); |
| // removed since 5.5.9? boolean expireSession = ContainerConfig.getPropertyValue(clusterProps, "expire-session", false); |
| // removed since 5.5.9? boolean useDirty = ContainerConfig.getPropertyValue(clusterProps, "use-dirty", true); |
| |
| SimpleTcpCluster cluster = new SimpleTcpCluster(); |
| cluster.setClusterName(clusterProps.name); |
| Manager manager = null; |
| try { |
| manager = (Manager)Class.forName(mgrClassName).newInstance(); |
| } catch (Exception exc) { |
| throw new ContainerException("Cluster configuration requires a valid manager-class property: " + exc.getMessage()); |
| } |
| //cluster.setManagerClassName(mgrClassName); |
| //host.setManager(manager); |
| //cluster.registerManager(manager); |
| cluster.setManagerTemplate((org.apache.catalina.ha.ClusterManager)manager); |
| //cluster.setDebug(debug); |
| // removed since 5.5.9? cluster.setExpireSessionsOnShutdown(expireSession); |
| // removed since 5.5.9? cluster.setUseDirtyFlag(useDirty); |
| |
| GroupChannel channel = new GroupChannel(); |
| channel.setChannelReceiver(listener); |
| channel.setChannelSender(trans); |
| channel.setMembershipService(mcast); |
| |
| cluster.setChannel(channel); |
| cluster.addValve(clusterValve); |
| // removed since 5.5.9? cluster.setPrintToScreen(true); |
| |
| // set the cluster to the host |
| host.setCluster(cluster); |
| Debug.logInfo("Catalina Cluster [" + cluster.getClusterName() + "] configured for host - " + host.getName(), module); |
| |
| return cluster; |
| } |
| |
| protected Connector createConnector(ContainerConfig.Configuration.Property connectorProp) throws ContainerException { |
| if (tomcat == null) { |
| throw new ContainerException("Cannot create Connector without Tomcat instance!"); |
| } |
| Connector connector = null; |
| if (UtilValidate.isNotEmpty(connectorProp.properties)) { |
| String protocol = ContainerConfig.getPropertyValue(connectorProp, "protocol", "HTTP/1.1"); |
| int port = ContainerConfig.getPropertyValue(connectorProp, "port", 0) + Start.getInstance().getConfig().portOffset; |
| |
| // set the protocol and the port first |
| connector = new Connector(protocol); |
| connector.setPort(port); |
| // then set all the other parameters |
| for (ContainerConfig.Configuration.Property prop: connectorProp.properties.values()) { |
| if ("protocol".equals(prop.name) || "port".equals(prop.name)) { |
| // protocol and port are already set |
| continue; |
| } |
| if (IntrospectionUtils.setProperty(connector, prop.name, prop.value)) { |
| if (prop.name.indexOf("Pass") != -1) { |
| // this property may be a password, do not include its value in the logs |
| Debug.logInfo("Tomcat " + connector + ": set " + prop.name, module); |
| } else { |
| Debug.logInfo("Tomcat " + connector + ": set " + prop.name + "=" + prop.value, module); |
| } |
| } else { |
| Debug.logWarning("Tomcat " + connector + ": ignored parameter " + prop.name, module); |
| } |
| } |
| |
| tomcat.getService().addConnector(connector); |
| } |
| return connector; |
| } |
| |
| private Callable<Context> createContext(final ComponentConfig.WebappInfo appInfo) throws ContainerException { |
| Debug.logInfo("Creating context [" + appInfo.name + "]", module); |
| final Engine engine = tomcat.getEngine(); |
| |
| List<String> virtualHosts = appInfo.getVirtualHosts(); |
| final Host host; |
| if (UtilValidate.isEmpty(virtualHosts)) { |
| host = tomcat.getHost(); |
| } else { |
| // assume that the first virtual-host will be the default; additional virtual-hosts will be aliases |
| Iterator<String> vhi = virtualHosts.iterator(); |
| String hostName = vhi.next(); |
| |
| org.apache.catalina.Container childContainer = engine.findChild(hostName); |
| if (childContainer instanceof Host) { |
| host = (Host)childContainer; |
| } else { |
| host = createHost(hostName); |
| engine.addChild(host); |
| } |
| while (vhi.hasNext()) { |
| host.addAlias(vhi.next()); |
| } |
| } |
| return new Callable<Context>() { |
| public Context call() throws ContainerException, LifecycleException { |
| StandardContext context = configureContext(engine, host, appInfo); |
| host.addChild(context); |
| return context; |
| } |
| }; |
| } |
| |
| private StandardContext configureContext(Engine engine, Host host, ComponentConfig.WebappInfo appInfo) throws ContainerException { |
| // webapp settings |
| Map<String, String> initParameters = appInfo.getInitParameters(); |
| |
| // set the root location (make sure we set the paths correctly) |
| String location = appInfo.componentConfig.getRootLocation() + appInfo.location; |
| location = location.replace('\\', '/'); |
| if (location.endsWith("/")) { |
| location = location.substring(0, location.length() - 1); |
| } |
| |
| // get the mount point |
| String mount = appInfo.mountPoint; |
| if (mount.endsWith("/*")) { |
| mount = mount.substring(0, mount.length() - 2); |
| } |
| |
| final String webXmlFilePath = new StringBuilder().append("file:///").append(location).append("/WEB-INF/web.xml").toString(); |
| boolean appIsDistributable = distribute; |
| URL webXmlUrl = null; |
| try { |
| webXmlUrl = FlexibleLocation.resolveLocation(webXmlFilePath); |
| } catch (MalformedURLException e) { |
| throw new ContainerException(e); |
| } |
| File webXmlFile = new File(webXmlUrl.getFile()); |
| if (webXmlFile.exists()) { |
| Document webXmlDoc = null; |
| try { |
| webXmlDoc = UtilXml.readXmlDocument(webXmlUrl); |
| } catch (Exception e) { |
| throw new ContainerException(e); |
| } |
| appIsDistributable = webXmlDoc.getElementsByTagName("distributable").getLength() > 0; |
| } else { |
| Debug.logInfo(webXmlFilePath + " not found.", module); |
| } |
| final boolean contextIsDistributable = distribute && appIsDistributable; |
| |
| // create the web application context |
| StandardContext context = new StandardContext(); |
| context.setParent(host); |
| context.setDocBase(location); |
| context.setPath(mount); |
| context.addLifecycleListener(new ContextConfig()); |
| Tomcat.initWebappDefaults(context); |
| // configure persistent sessions |
| // important: the call to context.setManager(...) must be done after Tomcat.initWebappDefaults(...) |
| Property clusterProp = clusterConfig.get(engine.getName()); |
| if (clusterProp != null && contextIsDistributable) { |
| Manager sessionMgr = null; |
| String mgrClassName = ContainerConfig.getPropertyValue(clusterProp, "manager-class", "org.apache.catalina.ha.session.DeltaManager"); |
| try { |
| sessionMgr = (Manager)Class.forName(mgrClassName).newInstance(); |
| } catch (Exception exc) { |
| throw new ContainerException("Cluster configuration requires a valid manager-class property: " + exc.getMessage()); |
| } |
| context.setManager(sessionMgr); |
| } |
| |
| JarScanner jarScanner = context.getJarScanner(); |
| if (jarScanner instanceof StandardJarScanner) { |
| StandardJarScanner standardJarScanner = (StandardJarScanner) jarScanner; |
| standardJarScanner.setJarScanFilter(new FilterJars()); |
| standardJarScanner.setScanClassPath(true); |
| } |
| |
| context.setJ2EEApplication(J2EE_APP); |
| context.setJ2EEServer(J2EE_SERVER); |
| context.setLoader(new WebappLoader(Thread.currentThread().getContextClassLoader())); |
| |
| context.setDisplayName(appInfo.name); |
| context.setDocBase(location); |
| |
| StandardRoot resources = new StandardRoot(context); |
| resources.setAllowLinking(true); |
| context.setResources(resources); |
| |
| context.setReloadable(contextReloadable); |
| |
| context.setDistributable(contextIsDistributable); |
| |
| context.setCrossContext(crossContext); |
| context.setPrivileged(appInfo.privileged); |
| context.getServletContext().setAttribute("_serverId", appInfo.server); |
| context.getServletContext().setAttribute("componentName", appInfo.componentConfig.getComponentName()); |
| |
| // request dumper filter |
| String enableRequestDump = initParameters.get("enableRequestDump"); |
| if ("true".equals(enableRequestDump)) { |
| // create the Requester Dumper Filter instance |
| FilterDef requestDumperFilterDef = new FilterDef(); |
| requestDumperFilterDef.setFilterClass(RequestDumperFilter.class.getName()); |
| requestDumperFilterDef.setFilterName("RequestDumper"); |
| FilterMap requestDumperFilterMap = new FilterMap(); |
| requestDumperFilterMap.setFilterName("RequestDumper"); |
| requestDumperFilterMap.addURLPattern("*"); |
| context.addFilterMap(requestDumperFilterMap); |
| } |
| |
| // set the init parameters |
| for (Map.Entry<String, String> entry: initParameters.entrySet()) { |
| context.addParameter(entry.getKey(), entry.getValue()); |
| } |
| |
| return context; |
| } |
| |
| protected void loadComponents() throws ContainerException { |
| if (tomcat == null) { |
| throw new ContainerException("Cannot load web applications without Tomcat instance!"); |
| } |
| |
| // load the applications |
| List<ComponentConfig.WebappInfo> webResourceInfos = ComponentConfig.getAllWebappResourceInfos(); |
| List<String> loadedMounts = new ArrayList<String>(); |
| if (webResourceInfos == null) { |
| return; |
| } |
| |
| ScheduledExecutorService executor = ExecutionPool.getScheduledExecutor(CATALINA_THREAD_GROUP, "catalina-startup", Runtime.getRuntime().availableProcessors(), 0, true); |
| try { |
| List<Future<Context>> futures = new ArrayList<Future<Context>>(); |
| |
| for (int i = webResourceInfos.size(); i > 0; i--) { |
| ComponentConfig.WebappInfo appInfo = webResourceInfos.get(i - 1); |
| String engineName = appInfo.server; |
| List<String> virtualHosts = appInfo.getVirtualHosts(); |
| String mount = appInfo.getContextRoot(); |
| List<String> keys = new ArrayList<String>(); |
| if (virtualHosts.isEmpty()) { |
| keys.add(engineName + ":DEFAULT:" + mount); |
| } else { |
| for (String virtualHost: virtualHosts) { |
| keys.add(engineName + ":" + virtualHost + ":" + mount); |
| } |
| } |
| if (!keys.removeAll(loadedMounts)) { |
| // nothing was removed from the new list of keys; this |
| // means there are no existing loaded entries that overlap |
| // with the new set |
| if (!appInfo.location.isEmpty()) { |
| futures.add(executor.submit(createContext(appInfo))); |
| } |
| loadedMounts.addAll(keys); |
| } else { |
| appInfo.setAppBarDisplay(false); // disable app bar display on overridden apps |
| Debug.logInfo("Duplicate webapp mount; not loading : " + appInfo.getName() + " / " + appInfo.getLocation(), module); |
| } |
| } |
| ExecutionPool.getAllFutures(futures); |
| } finally { |
| executor.shutdown(); |
| } |
| } |
| |
| public void stop() throws ContainerException { |
| try { |
| tomcat.stop(); |
| } catch (LifecycleException e) { |
| // don't throw this; or it will kill the rest of the shutdown process |
| Debug.logVerbose(e, module); // happens usually when running tests, disabled unless in verbose |
| } |
| } |
| |
| public String getName() { |
| return name; |
| } |
| } |