All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.catalina.core.ContainerBase Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2016 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 *
 *
 * This file incorporates work covered by the following copyright and
 * permission notice:
 *
 * Copyright 2004 The Apache Software Foundation
 *
 * 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.
 */
// Portions Copyright [2019-2021] Payara Foundation and/or affiliates

package org.apache.catalina.core;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.text.MessageFormat;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.naming.directory.DirContext;
import jakarta.servlet.ServletException;

import org.apache.catalina.Container;
import org.apache.catalina.ContainerEvent;
import org.apache.catalina.ContainerListener;
import org.apache.catalina.Context;
import org.apache.catalina.Globals;
import org.apache.catalina.LogFacade;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.Loader;
import org.apache.catalina.Manager;
import org.apache.catalina.Pipeline;
import org.apache.catalina.Realm;
import org.apache.catalina.Request;
import org.apache.catalina.Response;
import org.apache.catalina.Valve;
import org.apache.catalina.Wrapper;
import org.apache.catalina.util.LifecycleSupport;
import org.apache.naming.resources.ProxyDirContext;
import org.glassfish.web.valve.GlassFishValve;


/**
 * Abstract implementation of the Container interface, providing common
 * functionality required by nearly every implementation.  Classes extending
 * this base class must implement getInfo(), and may implement
 * a replacement for invoke().
 * 

* All subclasses of this abstract base class will include support for a * Pipeline object that defines the processing to be performed for each request * received by the invoke() method of this class, utilizing the * "Chain of Responsibility" design pattern. A subclass should encapsulate its * own processing functionality as a Valve, and configure this * Valve into the pipeline by calling setBasic(). *

* This implementation fires property change events, per the JavaBeans design * pattern, for changes in singleton properties. In addition, it fires the * following ContainerEvent events to listeners who register * themselves with addContainerListener(): *

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
TypeDataDescription
addChildContainerChild container added to this Container.
addValveValveValve added to this Container.
removeChildContainerChild container removed from this Container.
removeValveValveValve removed from this Container.
startnullContainer was started.
stopnullContainer was stopped.
* Subclasses that fire additional events should document them in the * class comments of the implementation class. * * @author Craig R. McClanahan */ public abstract class ContainerBase implements Container, Lifecycle, Pipeline { protected static final Logger log = LogFacade.getLogger(); protected static final ResourceBundle rb = log.getResourceBundle(); /** * Perform addChild with the permissions of this class. * addChild can be called with the XML parser on the stack, * this allows the XML parser to have fewer privileges than * Tomcat. */ protected class PrivilegedAddChild implements PrivilegedAction { private final Container child; PrivilegedAddChild(Container child) { this.child = child; } @Override public Void run() { addChildInternal(child); return null; } } // ----------------------------------------------------- Instance Variables /** * The child Containers belonging to this Container, keyed by name. */ protected Map children = new LinkedHashMap(); /** * The debugging detail level for this component. */ protected int debug = 0; /** * The processor delay for this component. */ protected int backgroundProcessorDelay = -1; /** * Flag indicating whether a check to see if the request is secure is * required before adding Pragma and Cache-Control headers when proxy * caching has been disabled */ protected boolean checkIfRequestIsSecure = false; /** * The lifecycle event support for this component. */ protected LifecycleSupport lifecycle = new LifecycleSupport(this); /** * The container event listeners for this Container. */ protected ArrayList listeners = new ArrayList(); private ContainerListener[] listenersArray = new ContainerListener[0]; /** * The Loader implementation with which this Container is associated. */ protected Loader loader = null; private final ReadWriteLock lock = new ReentrantReadWriteLock(); protected Lock readLock = lock.readLock(); protected Lock writeLock = lock.writeLock(); /** * The Logger implementation with which this Container is associated. */ protected org.apache.catalina.Logger logger = null; /** * The Manager implementation with which this Container is associated. */ protected Manager manager = null; /** * The human-readable name of this Container. */ protected String name = null; /** * The parent Container to which this Container is a child. */ protected Container parent = null; /** * The parent class loader to be configured when we install a Loader. */ protected ClassLoader parentClassLoader = null; /** * The Pipeline object with which this Container is associated. */ protected Pipeline pipeline = new StandardPipeline(this); protected boolean hasCustomPipeline = false; /** * The Realm with which this Container is associated. */ protected Realm realm = null; /** * The resources DirContext object with which this Container is associated. */ protected DirContext resources = null; /** * Has this component been started? */ protected volatile boolean started = false; protected boolean initialized=false; /** * The property change support for this component. */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); /** * The background thread. */ private Thread thread = null; /** * The background thread completion semaphore. */ private volatile boolean threadDone = false; /** * Indicates whether ContainerListener instances need to be notified * of a particular configuration event. */ protected boolean notifyContainerListeners = true; // ------------------------------------------------------------- Properties /** * @return true if ContainerListener instances need to be notified * of a particular configuration event, and false otherwise */ boolean isNotifyContainerListeners() { return notifyContainerListeners; } /** * Return the debugging detail level for this component. * @return */ public int getDebug() { return (this.debug); } /** * Set the debugging detail level for this component. * * @param debug The new debugging detail level */ public void setDebug(int debug) { int oldDebug = this.debug; this.debug = debug; support.firePropertyChange("debug", Integer.valueOf(oldDebug), Integer.valueOf(this.debug)); } /** * Get the delay between the invocation of the backgroundProcess method on * this container and its children. Child containers will not be invoked * if their delay value is not negative (which would mean they are using * their own thread). Setting this to a positive value will cause * a thread to be spawn. After waiting the specified amount of time, * the thread will invoke the executePeriodic method on this container * and all its children. * @return */ @Override public int getBackgroundProcessorDelay() { return backgroundProcessorDelay; } /** * Set the delay between the invocation of the execute method on this * container and its children. * * @param delay The delay in seconds between the invocation of * backgroundProcess methods */ @Override public void setBackgroundProcessorDelay(int delay) { backgroundProcessorDelay = delay; } /** * Return descriptive information about this Container implementation and * the corresponding version number, in the format * <description>/<version>. * @return */ @Override public String getInfo() { return this.getClass().getName(); } /** * Return the Loader with which this Container is associated. If there is * no associated Loader, return the Loader associated with our parent * Container (if any); otherwise, return null. * @return */ @Override public Loader getLoader() { try { readLock.lock(); if (loader != null) return (loader); } finally { readLock.unlock(); } if (parent != null) return (parent.getLoader()); return (null); } /** * Set the Loader with which this Container is associated. * * @param loader The newly associated loader */ @Override public void setLoader(Loader loader) { Loader oldLoader; try { writeLock.lock(); // Change components if necessary oldLoader = this.loader; if (oldLoader == loader) return; this.loader = loader; // Stop the old component if necessary if (started && (oldLoader != null) && (oldLoader instanceof Lifecycle)) { try { ((Lifecycle) oldLoader).stop(); } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_SET_LOADER_STOP, e); } } // Start the new component if necessary if (loader != null) loader.setContainer(this); if (started && (loader != null) && (loader instanceof Lifecycle)) { try { ((Lifecycle) loader).start(); } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_SET_LOADER_START, e); } } } finally { writeLock.unlock(); } // Report this property change to interested listeners support.firePropertyChange("loader", oldLoader, this.loader); } /** * Return the Logger with which this Container is associated. If there is * no associated Logger, return the Logger associated with our parent * Container (if any); otherwise return null. * @return */ @Override public org.apache.catalina.Logger getLogger() { try { readLock.lock(); if (logger != null) return (logger); } finally { readLock.unlock(); } if (parent != null) return (parent.getLogger()); return (null); } /** * Set the Logger with which this Container is associated. * * @param logger The newly associated Logger */ @Override public void setLogger(org.apache.catalina.Logger logger) { org.apache.catalina.Logger oldLogger; try { writeLock.lock(); // Change components if necessary oldLogger = this.logger; if (oldLogger == logger) return; this.logger = logger; // Stop the old component if necessary if (started && (oldLogger != null) && (oldLogger instanceof Lifecycle)) { try { ((Lifecycle) oldLogger).stop(); } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_SET_LOGGER_STOP, e); } } // Start the new component if necessary if (logger != null) logger.setContainer(this); if (started && (logger != null) && (logger instanceof Lifecycle)) { try { ((Lifecycle) logger).start(); } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_SET_LOGGER_START, e); } } } finally { writeLock.unlock(); } // Report this property change to interested listeners support.firePropertyChange("logger", oldLogger, this.logger); } /** * Return the Manager with which this Container is associated. If there is * no associated Manager, return the Manager associated with our parent * Container (if any); otherwise return null. * @return */ @Override public Manager getManager() { try { readLock.lock(); if (manager != null) return (manager); } finally { readLock.unlock(); } if (parent != null) return (parent.getManager()); return (null); } /** * Set the Manager with which this Container is associated. * * @param manager The newly associated Manager */ @Override public void setManager(Manager manager) { Manager oldManager; try { writeLock.lock(); // Change components if necessary oldManager = this.manager; if (oldManager == manager) return; this.manager = manager; // Stop the old component if necessary if (started && (oldManager != null) && (oldManager instanceof Lifecycle)) { try { ((Lifecycle) oldManager).stop(); } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_SET_MANAGER_STOP, e); } } // Start the new component if necessary if (manager != null) manager.setContainer(this); if (started && (manager != null) && (manager instanceof Lifecycle)) { try { ((Lifecycle) manager).start(); } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_SET_MANAGER_START, e); } } } finally { writeLock.unlock(); } // Report this property change to interested listeners support.firePropertyChange("manager", oldManager, this.manager); } /** * Return an object which may be utilized for mapping to this component. * @return */ @Override public Object getMappingObject() { return this; } /** * Return a name string (suitable for use by humans) that describes this * Container. Within the set of child containers belonging to a particular * parent, Container names must be unique. * @return */ @Override public String getName() { return (name); } /** * Set a name string (suitable for use by humans) that describes this * Container. Within the set of child containers belonging to a particular * parent, Container names must be unique. * * @param name New name of this container * * @exception IllegalStateException if this Container has already been * added to the children of a parent Container (after which the name * may not be changed) */ @Override public void setName(String name) { String oldName = this.name; this.name = name; support.firePropertyChange("name", oldName, this.name); } /** * Return the Container for which this Container is a child, if there is * one. If there is no defined parent, return null. * @return */ @Override public Container getParent() { return (parent); } /** * Set the parent Container to which this Container is being added as a * child. This Container may refuse to become attached to the specified * Container by throwing an exception. * * @param container Container to which this Container is being added * as a child * * @exception IllegalArgumentException if this Container refuses to become * attached to the specified Container */ @Override public void setParent(Container container) { Container oldParent = this.parent; this.parent = container; support.firePropertyChange("parent", oldParent, this.parent); } /** * Return the parent class loader (if any) for this web application. * This call is meaningful only after a Loader has * been configured. * @return */ @Override public ClassLoader getParentClassLoader() { if (parentClassLoader != null) return (parentClassLoader); if (parent != null) { return (parent.getParentClassLoader()); } return (ClassLoader.getSystemClassLoader()); } /** * Set the parent class loader (if any) for this web application. * This call is meaningful only before a Loader has * been configured, and the specified value (if non-null) should be * passed as an argument to the class loader constructor. * * * @param parent The new parent class loader */ @Override public void setParentClassLoader(ClassLoader parent) { ClassLoader oldParentClassLoader = this.parentClassLoader; this.parentClassLoader = parent; support.firePropertyChange("parentClassLoader", oldParentClassLoader, this.parentClassLoader); } /** * Return the Pipeline object that manages the Valves associated with * this Container. * @return */ @Override public Pipeline getPipeline() { return (this.pipeline); } /** * @return true if this container was configured with a custom pipeline, * false otherwise */ @Override public boolean hasCustomPipeline() { return hasCustomPipeline; } /** * Indicates whether the request will be checked to see if it is secure * before adding Pragma and Cache-control headers when proxy caching has * been disabled. * * @return true if the check is required; false otherwise. */ @Override public boolean isCheckIfRequestIsSecure() { return checkIfRequestIsSecure; } /** * Sets the checkIfRequestIsSecure property of this Container. * * Setting this property to true will check if the request is secure * before adding Pragma and Cache-Control headers when proxy caching has * been disabled. * * @param checkIfRequestIsSecure true if check is required, false * otherwise */ @Override public void setCheckIfRequestIsSecure(boolean checkIfRequestIsSecure) { this.checkIfRequestIsSecure = checkIfRequestIsSecure; } /** * Return the Realm with which this Container is associated. If there is * no associated Realm, return the Realm associated with our parent * Container (if any); otherwise return null. * @return */ @Override public Realm getRealm() { try { readLock.lock(); if (realm != null) return (realm); } finally { readLock.unlock(); } if (parent != null) return (parent.getRealm()); return (null); } /** * Set the Realm with which this Container is associated. * * @param realm The newly associated Realm */ @Override public void setRealm(Realm realm) { Realm oldRealm; try { writeLock.lock(); // Change components if necessary oldRealm = this.realm; if (oldRealm == realm) return; this.realm = realm; // Stop the old component if necessary if (started && (oldRealm != null) && (oldRealm instanceof Lifecycle)) { try { ((Lifecycle) oldRealm).stop(); } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_SET_REALM_STOP, e); } } // Start the new component if necessary if (realm != null) realm.setContainer(this); if (started && (realm != null) && (realm instanceof Lifecycle)) { try { ((Lifecycle) realm).start(); } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_SET_REALM_START, e); } } } finally { writeLock.unlock(); } // Report this property change to interested listeners support.firePropertyChange("realm", oldRealm, this.realm); } /** * Return the resources DirContext object with which this Container is * associated. If there is no associated resources object, return the * resources associated with our parent Container (if any); otherwise * return null. * @return */ @Override public DirContext getResources() { try { readLock.lock(); if (resources != null) return (resources); } finally { readLock.unlock(); } if (parent != null) return (parent.getResources()); return (null); } /** * Set the resources DirContext object with which this Container is * associated. * * @param resources The newly associated DirContext * @throws Exception *///XXX: Is exception ever thrown? @Override public void setResources(DirContext resources) throws Exception { // Called from StandardContext.setResources() // <- StandardContext.start() // <- ContainerBase.addChildInternal() // Change components if necessary DirContext oldResources; try { writeLock.lock(); oldResources = this.resources; if (oldResources == resources) return; Hashtable env = new Hashtable(); if (getParent() != null) env.put(ProxyDirContext.HOST, getParent().getName()); env.put(ProxyDirContext.CONTEXT, getName()); this.resources = new ProxyDirContext(env, resources); // Report this property change to interested listeners } finally { writeLock.unlock(); } support.firePropertyChange("resources", oldResources, this.resources); } // ------------------------------------------------------ Container Methods /** * Add a new child Container to those associated with this Container, * if supported. Prior to adding this Container to the set of children, * the child's setParent() method must be called, with this * Container as an argument. This method may thrown an * IllegalArgumentException if this Container chooses not * to be attached to the specified Container, in which case it is not added * * @param child New child Container to be added * * @exception IllegalArgumentException if this exception is thrown by * the setParent() method of the child Container * @exception IllegalArgumentException if the new child does not have * a name unique from that of existing children of this Container * @exception IllegalStateException if this Container does not support * child Containers */ @Override public void addChild(Container child) { if (Globals.IS_SECURITY_ENABLED) { PrivilegedAction dp = new PrivilegedAddChild(child); AccessController.doPrivileged(dp); } else { addChildInternal(child); } } private void addChildInternal(Container child) { if(log.isLoggable(Level.FINEST)) log.log(Level.FINEST, "Add child {0} {1}", new Object[]{child, this}); synchronized(children) { if (children.get(child.getName()) != null) { String msg = MessageFormat.format(rb.getString(LogFacade.DUPLICATE_CHILD_NAME_EXCEPTION), child.getName()); throw new IllegalArgumentException(msg); } child.setParent(this); // May throw IAE if (started && (child instanceof Lifecycle)) { try { ((Lifecycle) child).start(); } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_ADD_CHILD_START, e); throw new IllegalStateException (rb.getString(LogFacade.CONTAINER_BASE_ADD_CHILD_START) + e); } } children.put(child.getName(), child); if (notifyContainerListeners) { fireContainerEvent(ADD_CHILD_EVENT, child); } } } /** * Add a container event listener to this component. * * @param listener The listener to add */ @Override public void addContainerListener(ContainerListener listener) { synchronized (listeners) { listeners.add(listener); listenersArray = listeners.toArray( new ContainerListener[listeners.size()]); } } /** * Add a property change listener to this component. * * @param listener The listener to add */ @Override public void addPropertyChangeListener(PropertyChangeListener listener) { support.addPropertyChangeListener(listener); } /** * Return the child Container, associated with this Container, with * the specified name (if any); otherwise, return null * * @param name Name of the child Container to be retrieved * @return */ @Override public Container findChild(String name) { if (name == null) return (null); synchronized (children) { // Required by post-start changes return children.get(name); } } /** * Return the set of children Containers associated with this Container. * If this Container has no children, a zero-length array is returned. * @return */ @Override public Container[] findChildren() { synchronized (children) { return children.values().toArray(new Container[children.size()]); } } /** * Return the set of container listeners associated with this Container. * If this Container has no registered container listeners, a zero-length * array is returned. * @return */ @Override public ContainerListener[] findContainerListeners() { synchronized (listeners) { return listenersArray; } } /** * Process the specified Request, to produce the corresponding Response, * by invoking the first Valve in our pipeline (if any), or the basic * Valve otherwise. * * @param request Request to be processed * @param response Response to be produced * * @exception IllegalStateException if neither a pipeline or a basic * Valve have been configured for this Container * @exception IOException if an input/output error occurred while * processing * @exception ServletException if a ServletException was thrown * while processing this request */ @Override public void invoke(Request request, Response response) throws IOException, ServletException { pipeline.invoke(request, response); } /** * Remove an existing child Container from association with this parent * Container. *

* This will also stop the child container. * @param child Existing child Container to be removed */ @Override public void removeChild(Container child) { if (child == null) { return; } synchronized(children) { if (children.get(child.getName()) == null) return; children.remove(child.getName()); } if (started && (child instanceof Lifecycle)) { try { if( child instanceof ContainerBase ) { if( ((ContainerBase)child).started ) { ((Lifecycle) child).stop(); } } else { ((Lifecycle) child).stop(); } } catch (LifecycleException e) { log.log(Level.SEVERE, LogFacade.CONTAINER_BASE_REMOVE_CHILD_STOP, e); } } if (notifyContainerListeners) { fireContainerEvent(REMOVE_CHILD_EVENT, child); } // child.setParent(null); } /** * Remove a container event listener from this component. * * @param listener The listener to remove */ @Override public void removeContainerListener(ContainerListener listener) { synchronized (listeners) { listeners.remove(listener); listenersArray = listeners.toArray( new ContainerListener[listeners.size()]); } } /** * Remove a property change listener from this component. * * @param listener The listener to remove */ @Override public void removePropertyChangeListener(PropertyChangeListener listener) { support.removePropertyChangeListener(listener); } // ------------------------------------------------------ Lifecycle Methods /** * Add a lifecycle event listener to this component. * * @param listener The listener to add */ @Override public void addLifecycleListener(LifecycleListener listener) { lifecycle.addLifecycleListener(listener); } /** * Gets the (possibly empty) list of lifecycle listeners associated * with this Container. * @return */ @Override public List findLifecycleListeners() { return lifecycle.findLifecycleListeners(); } /** * Removes the given lifecycle event listener from this Container. * * @param listener The listener to remove */ @Override public void removeLifecycleListener(LifecycleListener listener) { lifecycle.removeLifecycleListener(listener); } /** * Removes any lifecycle event listeners from this Container. */ public void removeLifecycleListeners() { lifecycle.removeLifecycleListeners(); } /** * Prepare for active use of the public methods of this Component. * * @exception LifecycleException if this component detects a fatal error * that prevents it from being started */ @Override public synchronized void start() throws LifecycleException { // Validate and update our current component state if (started) { if (log.isLoggable(Level.INFO)) { log.log(Level.INFO, LogFacade.CONTAINER_STARTED, logName()); } return; } // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); started = true; // Start our subordinate components, if any if ((loader != null) && (loader instanceof Lifecycle)) ((Lifecycle) loader).start(); if ((logger != null) && (logger instanceof Lifecycle)) ((Lifecycle) logger).start(); if ((manager != null) && (manager instanceof Lifecycle)) ((Lifecycle) manager).start(); if ((realm != null) && (realm instanceof Lifecycle)) ((Lifecycle) realm).start(); if ((resources != null) && (resources instanceof Lifecycle)) ((Lifecycle) resources).start(); // Start our child containers, if any startChildren(); // Start the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle) { ((Lifecycle) pipeline).start(); } // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(START_EVENT, null); // Start our thread threadStart(); // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); } /** * Gracefully shut down active use of the public methods of this Component. * * @exception LifecycleException if this component detects a fatal error * that needs to be reported */ @Override public synchronized void stop() throws LifecycleException { // Validate and update our current component state if (!started) { if (log.isLoggable(Level.INFO)) { log.log(Level.INFO, LogFacade.CONTAINER_NOT_STARTED_EXCEPTION, logName()); } return; } // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); // Stop our thread threadStop(); // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(STOP_EVENT, null); started = false; // Stop the Valves in our pipeline (including the basic), if any if (pipeline instanceof Lifecycle) { ((Lifecycle) pipeline).stop(); } // Stop our child containers, if any for (Container child : findChildren()) { if (child instanceof Lifecycle) { try { ((Lifecycle) child).stop(); } catch (Throwable t) { String msg = MessageFormat.format(rb.getString(LogFacade.ERROR_STOPPING_CONTAINER), child); log.log(Level.SEVERE, msg, t); } } } // Remove children - so next start can work for (Container child : findChildren()) { removeChild(child); } // Stop our subordinate components, if any if ((resources != null) && (resources instanceof Lifecycle)) { ((Lifecycle) resources).stop(); } if ((realm != null) && (realm instanceof Lifecycle)) { ((Lifecycle) realm).stop(); } if ((manager != null) && (manager instanceof Lifecycle)) { ((Lifecycle) manager).stop(); } if ((logger != null) && (logger instanceof Lifecycle)) { ((Lifecycle) logger).stop(); } if ((loader != null) && (loader instanceof Lifecycle)) { ((Lifecycle) loader).stop(); } // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); } /** Init method, part of the MBean lifecycle. * If the container was added via JMX, it'll register itself with the * parent, using the ObjectName conventions to locate the parent. * * If the container was added directly and it doesn't have an ObjectName, * it'll create a name and register itself with the JMX console. On destroy(), * the object will unregister. * * @throws Exception */ public void init() throws Exception { initialized=true; } /** * Gets the name of the parent container * @return null if no parent * @throws MalformedObjectNameException */ public ObjectName getParentName() throws MalformedObjectNameException { return null; } /** * Stops the component and any children and removes all listeners * @throws Exception */ public void destroy() throws Exception { if( started ) { stop(); } initialized=false; // unregister this component if( oname != null ) { try { if( controller == oname ) { if (log.isLoggable(Level.FINE)) { log.log(Level.FINE, "unregistering " + oname); } } } catch( Throwable t ) { log.log(Level.SEVERE, LogFacade.ERROR_UNREGISTERING, t); } } if (parent != null) { parent.removeChild(this); } // Stop our child containers, if any Container children[] = findChildren(); for(Container aChildren : children) { removeChild(aChildren); } // START SJSAS 6330332 // Remove LifecycleListeners removeLifecycleListeners(); // Release realm setRealm(null); // END SJSAS 6330332 } // ------------------------------------------------------- Pipeline Methods /** * Add a new Valve to the end of the pipeline associated with this * Container. Prior to adding the Valve, the Valve's * setContainer method must be called, with this Container * as an argument. The method may throw an * IllegalArgumentException if this Valve chooses not to * be associated with this Container, or IllegalStateException * if it is already associated with a different Container. * * @param valve Valve to be added * * @exception IllegalArgumentException if this Container refused to * accept the specified Valve * @exception IllegalArgumentException if the specified Valve refuses to be * associated with this Container * @exception IllegalStateException if the specified Valve is already * associated with a different Container */ @Override public synchronized void addValve(GlassFishValve valve) { pipeline.addValve(valve); if (notifyContainerListeners) { fireContainerEvent(ADD_VALVE_EVENT, valve); } } /** * Add Tomcat-style valve. */ @Override public synchronized void addValve(Valve valve) { pipeline.addValve(valve); if (notifyContainerListeners) { fireContainerEvent(ADD_VALVE_EVENT, valve); } } /** * Gets the name of all Tomcat valves * @return * @see org.apache.catalina.valves.ValveBase */ public ObjectName[] getValveObjectNames() { return ((StandardPipeline)pipeline).getValveObjectNames(); } /** *

Return the Valve instance that has been distinguished as the basic * Valve for this Pipeline (if any). * @return */ @Override public GlassFishValve getBasic() { return (pipeline.getBasic()); } /** * Return the set of Valves in the pipeline associated with this * Container, including the basic Valve (if any). If there are no * such Valves, a zero-length array is returned. * @return */ @Override public GlassFishValve[] getValves() { return (pipeline.getValves()); } /** * @return true if this pipeline has any non basic valves, false * otherwise */ @Override public boolean hasNonBasicValves() { return pipeline.hasNonBasicValves(); } /** * Remove the specified Valve from the pipeline associated with this * Container, if it is found; otherwise, do nothing. * * @param valve Valve to be removed */ @Override public synchronized void removeValve(GlassFishValve valve) { pipeline.removeValve(valve); if (notifyContainerListeners) { fireContainerEvent(REMOVE_VALVE_EVENT, valve); } } /** *

Set the Valve instance that has been distinguished as the basic * Valve for this Pipeline (if any). Prior to setting the basic Valve, * the Valve's setContainer() will be called, if it * implements Contained, with the owning Container as an * argument. The method may throw an IllegalArgumentException * if this Valve chooses not to be associated with this Container, or * IllegalStateException if it is already associated with * a different Container.

* * @param valve Valve to be distinguished as the basic Valve */ @Override public void setBasic(GlassFishValve valve) { pipeline.setBasic(valve); } /** * Execute a periodic task, such as reloading, etc. This method will be * invoked inside the classloading context of this container. Unexpected * throwables will be caught and logged. */ @Override public void backgroundProcess() { } // ------------------------------------------------------ Protected Methods /** * Notify all container event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param data Event data */ @Override public void fireContainerEvent(String type, Object data) { ContainerListener[] list = null; synchronized (listeners) { if (listeners.isEmpty()) { return; } list = listenersArray; } ContainerEvent event = new ContainerEvent(this, type, data); for (int i = 0; i < list.length; i++) { list[i].containerEvent(event); } } /** * Starts the children of this container. */ protected void startChildren() { for (Container child : findChildren()) { if (child instanceof Lifecycle) { try { ((Lifecycle) child).start(); } catch (Throwable t) { String msg = MessageFormat.format(rb.getString(LogFacade.CONTAINER_NOT_STARTED_EXCEPTION), child); log.log(Level.SEVERE, msg, t); if (child instanceof Context) { ((Context) child).setAvailable(false); } else if (child instanceof Wrapper) { ((Wrapper) child).setAvailable(Long.MAX_VALUE); } } } } } /** * Log the specified message to our current Logger (if any). * * @param message Message to be logged */ protected void log(String message) { // Logger logger = getLogger(); // if (logger != null) // logger.log(logName() + ": " + message); // else log.log(Level.INFO, message); } /** * Log the specified message and exception to our current Logger * (if any). * * @param message Message to be logged * @param throwable Related exception */ protected void log(String message, Throwable throwable) { org.apache.catalina.Logger logger = getLogger(); if (logger != null) logger.log(logName() + ": " + message, throwable); else { log.log(Level.SEVERE, message, throwable); } } /** * Return the abbreviated name of this container for logging messages * @return */ protected String logName() { String className = this.getClass().getName(); int period = className.lastIndexOf('.'); if (period >= 0) className = className.substring(period + 1); return (className + "[" + getName() + "]"); } // -------------------- JMX and Registration -------------------- protected String domain; protected ObjectName oname; protected ObjectName controller; public ObjectName getJmxName() { synchronized (this) { return oname; } } public String getObjectName() { if (oname != null) { return oname.toString(); } else return null; } public String getDomain() { if( domain==null ) { Container parent=this; while( parent != null && !( parent instanceof StandardEngine) ) { parent=parent.getParent(); } if( parent != null ) { // parent will always be an instanceof StandardEngine unless it is null domain=((StandardEngine)parent).getDomain(); } } return domain; } public void setDomain(String domain) { this.domain=domain; } public ObjectName[] getChildren() { synchronized(children) { ObjectName result[]=new ObjectName[children.size()]; Iterator it=children.values().iterator(); int i=0; while( it.hasNext() ) { Object next=it.next(); if( next instanceof ContainerBase ) { result[i++]=((ContainerBase)next).getJmxName(); } } return result; } } public ObjectName createObjectName(String domain, ObjectName parent) throws Exception { if (log.isLoggable(Level.FINE)) log.log(Level.FINE, "Create ObjectName {0} {1}", new Object[]{domain, parent}); return null; } public String getContainerSuffix() { Container container=this; Container context=null; Container host=null; Container servlet=null; StringBuilder suffix=new StringBuilder(); if( container instanceof StandardHost ) { host=container; } else if( container instanceof StandardContext ) { host=container.getParent(); context=container; } else if( container instanceof StandardWrapper ) { context=container.getParent(); host=context.getParent(); servlet=container; } if( context!=null ) { String path=((StandardContext)context).getEncodedPath(); suffix.append(",path=").append((path.equals("")) ? "/" : path); } if( host!=null ) suffix.append(",host=").append( host.getName() ); if (servlet != null) { String containerName = container.getName(); suffix.append(",servlet="); suffix.append("".equals(containerName) ? "/" : containerName); } return suffix.toString(); } /** * Start the background thread that will periodically check for * session timeouts. */ protected void threadStart() { if (thread != null) return; if (backgroundProcessorDelay <= 0) return; threadDone = false; String threadName = "ContainerBackgroundProcessor[" + toString() + "]"; thread = new Thread(new ContainerBackgroundProcessor(), threadName); thread.setDaemon(true); thread.start(); } /** * Stop the background thread that is periodically checking for * session timeouts. */ protected void threadStop() { if (thread == null) return; threadDone = true; thread.interrupt(); try { thread.join(); } catch (InterruptedException e) { // Ignore } thread = null; } // -------------------------------------- ContainerExecuteDelay Inner Class /** * Private thread class to invoke the backgroundProcess method * of this container and its children after a fixed delay. */ protected class ContainerBackgroundProcessor implements Runnable { @Override public void run() { while (!threadDone) { try { Thread.sleep(backgroundProcessorDelay * 1000L); } catch (InterruptedException e) { // Ignore } if (!threadDone) { Container parent = (Container) getMappingObject(); ClassLoader cl = Thread.currentThread().getContextClassLoader(); if (parent.getLoader() != null) { cl = parent.getLoader().getClassLoader(); } processChildren(parent, cl); } } } protected void processChildren(Container container, ClassLoader cl) { try { if (container.getLoader() != null) { Thread.currentThread().setContextClassLoader (container.getLoader().getClassLoader()); } container.backgroundProcess(); } catch (Throwable t) { log.log(Level.SEVERE, LogFacade.EXCEPTION_INVOKES_PERIODIC_OP, t); } finally { Thread.currentThread().setContextClassLoader(cl); } Container[] children = container.findChildren(); for (Container child : children) { if (child.getBackgroundProcessorDelay() <= 0) { processChildren(child, cl); } } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy