0001: /*
0002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/ContainerBase.java,v 1.21 2002/06/09 02:19:42 remm Exp $
0003: * $Revision: 1.21 $
0004: * $Date: 2002/06/09 02:19:42 $
0005: *
0006: * ====================================================================
0007: *
0008: * The Apache Software License, Version 1.1
0009: *
0010: * Copyright (c) 1999-2001 The Apache Software Foundation. All rights
0011: * reserved.
0012: *
0013: * Redistribution and use in source and binary forms, with or without
0014: * modification, are permitted provided that the following conditions
0015: * are met:
0016: *
0017: * 1. Redistributions of source code must retain the above copyright
0018: * notice, this list of conditions and the following disclaimer.
0019: *
0020: * 2. Redistributions in binary form must reproduce the above copyright
0021: * notice, this list of conditions and the following disclaimer in
0022: * the documentation and/or other materials provided with the
0023: * distribution.
0024: *
0025: * 3. The end-user documentation included with the redistribution, if
0026: * any, must include the following acknowlegement:
0027: * "This product includes software developed by the
0028: * Apache Software Foundation (http://www.apache.org/)."
0029: * Alternately, this acknowlegement may appear in the software itself,
0030: * if and wherever such third-party acknowlegements normally appear.
0031: *
0032: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0033: * Foundation" must not be used to endorse or promote products derived
0034: * from this software without prior written permission. For written
0035: * permission, please contact apache@apache.org.
0036: *
0037: * 5. Products derived from this software may not be called "Apache"
0038: * nor may "Apache" appear in their names without prior written
0039: * permission of the Apache Group.
0040: *
0041: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0042: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0043: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0044: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0045: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0046: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0047: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0048: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0049: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0050: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0051: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0052: * SUCH DAMAGE.
0053: * ====================================================================
0054: *
0055: * This software consists of voluntary contributions made by many
0056: * individuals on behalf of the Apache Software Foundation. For more
0057: * information on the Apache Software Foundation, please see
0058: * <http://www.apache.org/>.
0059: *
0060: * [Additional notices, if required by prior licensing conditions]
0061: *
0062: */
0063:
0064: package org.apache.catalina.core;
0065:
0066: import java.beans.PropertyChangeListener;
0067: import java.beans.PropertyChangeSupport;
0068: import java.io.IOException;
0069: import java.security.AccessController;
0070: import java.security.PrivilegedAction;
0071: import java.util.ArrayList;
0072: import java.util.HashMap;
0073: import java.util.Hashtable;
0074: import java.util.Iterator;
0075: import javax.servlet.ServletException;
0076: import javax.naming.directory.DirContext;
0077: import org.apache.naming.resources.ProxyDirContext;
0078: import org.apache.catalina.Cluster;
0079: import org.apache.catalina.Container;
0080: import org.apache.catalina.ContainerEvent;
0081: import org.apache.catalina.ContainerListener;
0082: import org.apache.catalina.Lifecycle;
0083: import org.apache.catalina.LifecycleEvent;
0084: import org.apache.catalina.LifecycleException;
0085: import org.apache.catalina.LifecycleListener;
0086: import org.apache.catalina.Loader;
0087: import org.apache.catalina.Logger;
0088: import org.apache.catalina.Manager;
0089: import org.apache.catalina.Mapper;
0090: import org.apache.catalina.Pipeline;
0091: import org.apache.catalina.Realm;
0092: import org.apache.catalina.Request;
0093: import org.apache.catalina.Response;
0094: import org.apache.catalina.Valve;
0095: import org.apache.catalina.util.LifecycleSupport;
0096: import org.apache.catalina.util.StringManager;
0097:
0098: /**
0099: * Abstract implementation of the <b>Container</b> interface, providing common
0100: * functionality required by nearly every implementation. Classes extending
0101: * this base class must implement <code>getInfo()</code>, and may implement
0102: * a replacement for <code>invoke()</code>.
0103: * <p>
0104: * All subclasses of this abstract base class will include support for a
0105: * Pipeline object that defines the processing to be performed for each request
0106: * received by the <code>invoke()</code> method of this class, utilizing the
0107: * "Chain of Responsibility" design pattern. A subclass should encapsulate its
0108: * own processing functionality as a <code>Valve</code>, and configure this
0109: * Valve into the pipeline by calling <code>setBasic()</code>.
0110: * <p>
0111: * This implementation fires property change events, per the JavaBeans design
0112: * pattern, for changes in singleton properties. In addition, it fires the
0113: * following <code>ContainerEvent</code> events to listeners who register
0114: * themselves with <code>addContainerListener()</code>:
0115: * <table border=1>
0116: * <tr>
0117: * <th>Type</th>
0118: * <th>Data</th>
0119: * <th>Description</th>
0120: * </tr>
0121: * <tr>
0122: * <td align=center><code>addChild</code></td>
0123: * <td align=center><code>Container</code></td>
0124: * <td>Child container added to this Container.</td>
0125: * </tr>
0126: * <tr>
0127: * <td align=center><code>addValve</code></td>
0128: * <td align=center><code>Valve</code></td>
0129: * <td>Valve added to this Container.</td>
0130: * </tr>
0131: * <tr>
0132: * <td align=center><code>removeChild</code></td>
0133: * <td align=center><code>Container</code></td>
0134: * <td>Child container removed from this Container.</td>
0135: * </tr>
0136: * <tr>
0137: * <td align=center><code>removeValve</code></td>
0138: * <td align=center><code>Valve</code></td>
0139: * <td>Valve removed from this Container.</td>
0140: * </tr>
0141: * <tr>
0142: * <td align=center><code>start</code></td>
0143: * <td align=center><code>null</code></td>
0144: * <td>Container was started.</td>
0145: * </tr>
0146: * <tr>
0147: * <td align=center><code>stop</code></td>
0148: * <td align=center><code>null</code></td>
0149: * <td>Container was stopped.</td>
0150: * </tr>
0151: * </table>
0152: * Subclasses that fire additional events should document them in the
0153: * class comments of the implementation class.
0154: *
0155: * @author Craig R. McClanahan
0156: * @version $Revision: 1.21 $ $Date: 2002/06/09 02:19:42 $
0157: */
0158:
0159: public abstract class ContainerBase implements Container, Lifecycle,
0160: Pipeline {
0161:
0162: /**
0163: * Perform addChild with the permissions of this class.
0164: * addChild can be called with the XML parser on the stack,
0165: * this allows the XML parser to have fewer privileges than
0166: * Tomcat.
0167: */
0168: protected class PrivilegedAddChild implements PrivilegedAction {
0169:
0170: private Container child;
0171:
0172: PrivilegedAddChild(Container child) {
0173: this .child = child;
0174: }
0175:
0176: public Object run() {
0177: addChildInternal(child);
0178: return null;
0179: }
0180:
0181: }
0182:
0183: // ----------------------------------------------------- Instance Variables
0184:
0185: /**
0186: * The child Containers belonging to this Container, keyed by name.
0187: */
0188: protected HashMap children = new HashMap();
0189:
0190: /**
0191: * The debugging detail level for this component.
0192: */
0193: protected int debug = 0;
0194:
0195: /**
0196: * The lifecycle event support for this component.
0197: */
0198: protected LifecycleSupport lifecycle = new LifecycleSupport(this );
0199:
0200: /**
0201: * The container event listeners for this Container.
0202: */
0203: protected ArrayList listeners = new ArrayList();
0204:
0205: /**
0206: * The Loader implementation with which this Container is associated.
0207: */
0208: protected Loader loader = null;
0209:
0210: /**
0211: * The Logger implementation with which this Container is associated.
0212: */
0213: protected Logger logger = null;
0214:
0215: /**
0216: * The Manager implementation with which this Container is associated.
0217: */
0218: protected Manager manager = null;
0219:
0220: /**
0221: * The cluster with which this Container is associated.
0222: */
0223: protected Cluster cluster = null;
0224:
0225: /**
0226: * The one and only Mapper associated with this Container, if any.
0227: */
0228: protected Mapper mapper = null;
0229:
0230: /**
0231: * The set of Mappers associated with this Container, keyed by protocol.
0232: */
0233: protected HashMap mappers = new HashMap();
0234:
0235: /**
0236: * The Java class name of the default Mapper class for this Container.
0237: */
0238: protected String mapperClass = null;
0239:
0240: /**
0241: * The human-readable name of this Container.
0242: */
0243: protected String name = null;
0244:
0245: /**
0246: * The parent Container to which this Container is a child.
0247: */
0248: protected Container parent = null;
0249:
0250: /**
0251: * The parent class loader to be configured when we install a Loader.
0252: */
0253: protected ClassLoader parentClassLoader = null;
0254:
0255: /**
0256: * The Pipeline object with which this Container is associated.
0257: */
0258: protected Pipeline pipeline = new StandardPipeline(this );
0259:
0260: /**
0261: * The Realm with which this Container is associated.
0262: */
0263: protected Realm realm = null;
0264:
0265: /**
0266: * The resources DirContext object with which this Container is associated.
0267: */
0268: protected DirContext resources = null;
0269:
0270: /**
0271: * The string manager for this package.
0272: */
0273: protected static StringManager sm = StringManager
0274: .getManager(Constants.Package);
0275:
0276: /**
0277: * Has this component been started?
0278: */
0279: protected boolean started = false;
0280:
0281: /**
0282: * The property change support for this component.
0283: */
0284: protected PropertyChangeSupport support = new PropertyChangeSupport(
0285: this );
0286:
0287: // ------------------------------------------------------------- Properties
0288:
0289: /**
0290: * Return the debugging detail level for this component.
0291: */
0292: public int getDebug() {
0293:
0294: return (this .debug);
0295:
0296: }
0297:
0298: /**
0299: * Set the debugging detail level for this component.
0300: *
0301: * @param debug The new debugging detail level
0302: */
0303: public void setDebug(int debug) {
0304:
0305: int oldDebug = this .debug;
0306: this .debug = debug;
0307: support.firePropertyChange("debug", new Integer(oldDebug),
0308: new Integer(this .debug));
0309:
0310: }
0311:
0312: /**
0313: * Return descriptive information about this Container implementation and
0314: * the corresponding version number, in the format
0315: * <code><description>/<version></code>.
0316: */
0317: public abstract String getInfo();
0318:
0319: /**
0320: * Return the Loader with which this Container is associated. If there is
0321: * no associated Loader, return the Loader associated with our parent
0322: * Container (if any); otherwise, return <code>null</code>.
0323: */
0324: public Loader getLoader() {
0325:
0326: if (loader != null)
0327: return (loader);
0328: if (parent != null)
0329: return (parent.getLoader());
0330: return (null);
0331:
0332: }
0333:
0334: /**
0335: * Set the Loader with which this Container is associated.
0336: *
0337: * @param loader The newly associated loader
0338: */
0339: public synchronized void setLoader(Loader loader) {
0340:
0341: // Change components if necessary
0342: Loader oldLoader = this .loader;
0343: if (oldLoader == loader)
0344: return;
0345: this .loader = loader;
0346:
0347: // Stop the old component if necessary
0348: if (started && (oldLoader != null)
0349: && (oldLoader instanceof Lifecycle)) {
0350: try {
0351: ((Lifecycle) oldLoader).stop();
0352: } catch (LifecycleException e) {
0353: log("ContainerBase.setLoader: stop: ", e);
0354: }
0355: }
0356:
0357: // Start the new component if necessary
0358: if (loader != null)
0359: loader.setContainer(this );
0360: if (started && (loader != null)
0361: && (loader instanceof Lifecycle)) {
0362: try {
0363: ((Lifecycle) loader).start();
0364: } catch (LifecycleException e) {
0365: log("ContainerBase.setLoader: start: ", e);
0366: }
0367: }
0368:
0369: // Report this property change to interested listeners
0370: support.firePropertyChange("loader", oldLoader, this .loader);
0371:
0372: }
0373:
0374: /**
0375: * Return the Logger with which this Container is associated. If there is
0376: * no associated Logger, return the Logger associated with our parent
0377: * Container (if any); otherwise return <code>null</code>.
0378: */
0379: public Logger getLogger() {
0380:
0381: if (logger != null)
0382: return (logger);
0383: if (parent != null)
0384: return (parent.getLogger());
0385: return (null);
0386:
0387: }
0388:
0389: /**
0390: * Set the Logger with which this Container is associated.
0391: *
0392: * @param logger The newly associated Logger
0393: */
0394: public synchronized void setLogger(Logger logger) {
0395:
0396: // Change components if necessary
0397: Logger oldLogger = this .logger;
0398: if (oldLogger == logger)
0399: return;
0400: this .logger = logger;
0401:
0402: // Stop the old component if necessary
0403: if (started && (oldLogger != null)
0404: && (oldLogger instanceof Lifecycle)) {
0405: try {
0406: ((Lifecycle) oldLogger).stop();
0407: } catch (LifecycleException e) {
0408: log("ContainerBase.setLogger: stop: ", e);
0409: }
0410: }
0411:
0412: // Start the new component if necessary
0413: if (logger != null)
0414: logger.setContainer(this );
0415: if (started && (logger != null)
0416: && (logger instanceof Lifecycle)) {
0417: try {
0418: ((Lifecycle) logger).start();
0419: } catch (LifecycleException e) {
0420: log("ContainerBase.setLogger: start: ", e);
0421: }
0422: }
0423:
0424: // Report this property change to interested listeners
0425: support.firePropertyChange("logger", oldLogger, this .logger);
0426:
0427: }
0428:
0429: /**
0430: * Return the Manager with which this Container is associated. If there is
0431: * no associated Manager, return the Manager associated with our parent
0432: * Container (if any); otherwise return <code>null</code>.
0433: */
0434: public Manager getManager() {
0435:
0436: if (manager != null)
0437: return (manager);
0438: if (parent != null)
0439: return (parent.getManager());
0440: return (null);
0441:
0442: }
0443:
0444: /**
0445: * Set the Manager with which this Container is associated.
0446: *
0447: * @param manager The newly associated Manager
0448: */
0449: public synchronized void setManager(Manager manager) {
0450:
0451: // Change components if necessary
0452: Manager oldManager = this .manager;
0453: if (oldManager == manager)
0454: return;
0455: this .manager = manager;
0456:
0457: // Stop the old component if necessary
0458: if (started && (oldManager != null)
0459: && (oldManager instanceof Lifecycle)) {
0460: try {
0461: ((Lifecycle) oldManager).stop();
0462: } catch (LifecycleException e) {
0463: log("ContainerBase.setManager: stop: ", e);
0464: }
0465: }
0466:
0467: // Start the new component if necessary
0468: if (manager != null)
0469: manager.setContainer(this );
0470: if (started && (manager != null)
0471: && (manager instanceof Lifecycle)) {
0472: try {
0473: ((Lifecycle) manager).start();
0474: } catch (LifecycleException e) {
0475: log("ContainerBase.setManager: start: ", e);
0476: }
0477: }
0478:
0479: // Report this property change to interested listeners
0480: support.firePropertyChange("manager", oldManager, this .manager);
0481:
0482: }
0483:
0484: /**
0485: * Return the Cluster with which this Container is associated. If there is
0486: * no associated Cluster, return the Cluster associated with our parent
0487: * Container (if any); otherwise return <code>null</code>.
0488: */
0489: public Cluster getCluster() {
0490: if (cluster != null)
0491: return (cluster);
0492:
0493: if (parent != null)
0494: return (parent.getCluster());
0495:
0496: return (null);
0497: }
0498:
0499: /**
0500: * Set the Cluster with which this Container is associated.
0501: *
0502: * @param manager The newly associated Cluster
0503: */
0504: public synchronized void setCluster(Cluster cluster) {
0505: // Change components if necessary
0506: Cluster oldCluster = this .cluster;
0507: if (oldCluster == cluster)
0508: return;
0509: this .cluster = cluster;
0510:
0511: // Stop the old component if necessary
0512: if (started && (oldCluster != null)
0513: && (oldCluster instanceof Lifecycle)) {
0514: try {
0515: ((Lifecycle) oldCluster).stop();
0516: } catch (LifecycleException e) {
0517: log("ContainerBase.setCluster: stop: ", e);
0518: }
0519: }
0520:
0521: // Start the new component if necessary
0522: if (cluster != null)
0523: cluster.setContainer(this );
0524:
0525: if (started && (cluster != null)
0526: && (cluster instanceof Lifecycle)) {
0527: try {
0528: ((Lifecycle) cluster).start();
0529: } catch (LifecycleException e) {
0530: log("ContainerBase.setCluster: start: ", e);
0531: }
0532: }
0533:
0534: // Report this property change to interested listeners
0535: support.firePropertyChange("cluster", oldCluster, this .cluster);
0536: }
0537:
0538: /**
0539: * Return a name string (suitable for use by humans) that describes this
0540: * Container. Within the set of child containers belonging to a particular
0541: * parent, Container names must be unique.
0542: */
0543: public String getName() {
0544:
0545: return (name);
0546:
0547: }
0548:
0549: /**
0550: * Set a name string (suitable for use by humans) that describes this
0551: * Container. Within the set of child containers belonging to a particular
0552: * parent, Container names must be unique.
0553: *
0554: * @param name New name of this container
0555: *
0556: * @exception IllegalStateException if this Container has already been
0557: * added to the children of a parent Container (after which the name
0558: * may not be changed)
0559: */
0560: public void setName(String name) {
0561:
0562: String oldName = this .name;
0563: this .name = name;
0564: support.firePropertyChange("name", oldName, this .name);
0565:
0566: }
0567:
0568: /**
0569: * Return the Container for which this Container is a child, if there is
0570: * one. If there is no defined parent, return <code>null</code>.
0571: */
0572: public Container getParent() {
0573:
0574: return (parent);
0575:
0576: }
0577:
0578: /**
0579: * Set the parent Container to which this Container is being added as a
0580: * child. This Container may refuse to become attached to the specified
0581: * Container by throwing an exception.
0582: *
0583: * @param container Container to which this Container is being added
0584: * as a child
0585: *
0586: * @exception IllegalArgumentException if this Container refuses to become
0587: * attached to the specified Container
0588: */
0589: public void setParent(Container container) {
0590:
0591: Container oldParent = this .parent;
0592: this .parent = container;
0593: support.firePropertyChange("parent", oldParent, this .parent);
0594:
0595: }
0596:
0597: /**
0598: * Return the parent class loader (if any) for this web application.
0599: * This call is meaningful only <strong>after</strong> a Loader has
0600: * been configured.
0601: */
0602: public ClassLoader getParentClassLoader() {
0603:
0604: if (parentClassLoader != null)
0605: return (parentClassLoader);
0606: if (parent != null)
0607: return (parent.getParentClassLoader());
0608: return (ClassLoader.getSystemClassLoader());
0609:
0610: }
0611:
0612: /**
0613: * Set the parent class loader (if any) for this web application.
0614: * This call is meaningful only <strong>before</strong> a Loader has
0615: * been configured, and the specified value (if non-null) should be
0616: * passed as an argument to the class loader constructor.
0617: *
0618: *
0619: * @param parent The new parent class loader
0620: */
0621: public void setParentClassLoader(ClassLoader parent) {
0622:
0623: ClassLoader oldParentClassLoader = this .parentClassLoader;
0624: this .parentClassLoader = parent;
0625: support.firePropertyChange("parentClassLoader",
0626: oldParentClassLoader, this .parentClassLoader);
0627:
0628: }
0629:
0630: /**
0631: * Return the Pipeline object that manages the Valves associated with
0632: * this Container.
0633: */
0634: public Pipeline getPipeline() {
0635:
0636: return (this .pipeline);
0637:
0638: }
0639:
0640: /**
0641: * Return the Realm with which this Container is associated. If there is
0642: * no associated Realm, return the Realm associated with our parent
0643: * Container (if any); otherwise return <code>null</code>.
0644: */
0645: public Realm getRealm() {
0646:
0647: if (realm != null)
0648: return (realm);
0649: if (parent != null)
0650: return (parent.getRealm());
0651: return (null);
0652:
0653: }
0654:
0655: /**
0656: * Set the Realm with which this Container is associated.
0657: *
0658: * @param realm The newly associated Realm
0659: */
0660: public synchronized void setRealm(Realm realm) {
0661:
0662: // Change components if necessary
0663: Realm oldRealm = this .realm;
0664: if (oldRealm == realm)
0665: return;
0666: this .realm = realm;
0667:
0668: // Stop the old component if necessary
0669: if (started && (oldRealm != null)
0670: && (oldRealm instanceof Lifecycle)) {
0671: try {
0672: ((Lifecycle) oldRealm).stop();
0673: } catch (LifecycleException e) {
0674: log("ContainerBase.setRealm: stop: ", e);
0675: }
0676: }
0677:
0678: // Start the new component if necessary
0679: if (realm != null)
0680: realm.setContainer(this );
0681: if (started && (realm != null) && (realm instanceof Lifecycle)) {
0682: try {
0683: ((Lifecycle) realm).start();
0684: } catch (LifecycleException e) {
0685: log("ContainerBase.setRealm: start: ", e);
0686: }
0687: }
0688:
0689: // Report this property change to interested listeners
0690: support.firePropertyChange("realm", oldRealm, this .realm);
0691:
0692: }
0693:
0694: /**
0695: * Return the resources DirContext object with which this Container is
0696: * associated. If there is no associated resources object, return the
0697: * resources associated with our parent Container (if any); otherwise
0698: * return <code>null</code>.
0699: */
0700: public DirContext getResources() {
0701:
0702: if (resources != null)
0703: return (resources);
0704: if (parent != null)
0705: return (parent.getResources());
0706: return (null);
0707:
0708: }
0709:
0710: /**
0711: * Set the resources DirContext object with which this Container is
0712: * associated.
0713: *
0714: * @param resources The newly associated DirContext
0715: */
0716: public synchronized void setResources(DirContext resources) {
0717:
0718: // Change components if necessary
0719: DirContext oldResources = this .resources;
0720: if (oldResources == resources)
0721: return;
0722: Hashtable env = new Hashtable();
0723: if (getParent() != null)
0724: env.put(ProxyDirContext.HOST, getParent().getName());
0725: env.put(ProxyDirContext.CONTEXT, getName());
0726: this .resources = new ProxyDirContext(env, resources);
0727: // Report this property change to interested listeners
0728: support.firePropertyChange("resources", oldResources,
0729: this .resources);
0730:
0731: }
0732:
0733: // ------------------------------------------------------ Container Methods
0734:
0735: /**
0736: * Add a new child Container to those associated with this Container,
0737: * if supported. Prior to adding this Container to the set of children,
0738: * the child's <code>setParent()</code> method must be called, with this
0739: * Container as an argument. This method may thrown an
0740: * <code>IllegalArgumentException</code> if this Container chooses not
0741: * to be attached to the specified Container, in which case it is not added
0742: *
0743: * @param child New child Container to be added
0744: *
0745: * @exception IllegalArgumentException if this exception is thrown by
0746: * the <code>setParent()</code> method of the child Container
0747: * @exception IllegalArgumentException if the new child does not have
0748: * a name unique from that of existing children of this Container
0749: * @exception IllegalStateException if this Container does not support
0750: * child Containers
0751: */
0752: public void addChild(Container child) {
0753: if (System.getSecurityManager() != null) {
0754: PrivilegedAction dp = new PrivilegedAddChild(child);
0755: AccessController.doPrivileged(dp);
0756: } else {
0757: addChildInternal(child);
0758: }
0759: }
0760:
0761: private void addChildInternal(Container child) {
0762:
0763: synchronized (children) {
0764: if (children.get(child.getName()) != null)
0765: throw new IllegalArgumentException(
0766: "addChild: Child name '" + child.getName()
0767: + "' is not unique");
0768: child.setParent((Container) this ); // May throw IAE
0769: if (started && (child instanceof Lifecycle)) {
0770: try {
0771: ((Lifecycle) child).start();
0772: } catch (LifecycleException e) {
0773: log("ContainerBase.addChild: start: ", e);
0774: throw new IllegalStateException(
0775: "ContainerBase.addChild: start: " + e);
0776: }
0777: }
0778: children.put(child.getName(), child);
0779: fireContainerEvent(ADD_CHILD_EVENT, child);
0780: }
0781:
0782: }
0783:
0784: /**
0785: * Add a container event listener to this component.
0786: *
0787: * @param listener The listener to add
0788: */
0789: public void addContainerListener(ContainerListener listener) {
0790:
0791: synchronized (listeners) {
0792: listeners.add(listener);
0793: }
0794:
0795: }
0796:
0797: /**
0798: * Add the specified Mapper associated with this Container.
0799: *
0800: * @param mapper The corresponding Mapper implementation
0801: *
0802: * @exception IllegalArgumentException if this exception is thrown by
0803: * the <code>setContainer()</code> method of the Mapper
0804: */
0805: public void addMapper(Mapper mapper) {
0806:
0807: synchronized (mappers) {
0808: if (mappers.get(mapper.getProtocol()) != null)
0809: throw new IllegalArgumentException(
0810: "addMapper: Protocol '" + mapper.getProtocol()
0811: + "' is not unique");
0812: mapper.setContainer((Container) this ); // May throw IAE
0813: if (started && (mapper instanceof Lifecycle)) {
0814: try {
0815: ((Lifecycle) mapper).start();
0816: } catch (LifecycleException e) {
0817: log("ContainerBase.addMapper: start: ", e);
0818: throw new IllegalStateException(
0819: "ContainerBase.addMapper: start: " + e);
0820: }
0821: }
0822: mappers.put(mapper.getProtocol(), mapper);
0823: if (mappers.size() == 1)
0824: this .mapper = mapper;
0825: else
0826: this .mapper = null;
0827: fireContainerEvent(ADD_MAPPER_EVENT, mapper);
0828: }
0829:
0830: }
0831:
0832: /**
0833: * Add a property change listener to this component.
0834: *
0835: * @param listener The listener to add
0836: */
0837: public void addPropertyChangeListener(
0838: PropertyChangeListener listener) {
0839:
0840: support.addPropertyChangeListener(listener);
0841:
0842: }
0843:
0844: /**
0845: * Return the child Container, associated with this Container, with
0846: * the specified name (if any); otherwise, return <code>null</code>
0847: *
0848: * @param name Name of the child Container to be retrieved
0849: */
0850: public Container findChild(String name) {
0851:
0852: if (name == null)
0853: return (null);
0854: synchronized (children) { // Required by post-start changes
0855: return ((Container) children.get(name));
0856: }
0857:
0858: }
0859:
0860: /**
0861: * Return the set of children Containers associated with this Container.
0862: * If this Container has no children, a zero-length array is returned.
0863: */
0864: public Container[] findChildren() {
0865:
0866: synchronized (children) {
0867: Container results[] = new Container[children.size()];
0868: return ((Container[]) children.values().toArray(results));
0869: }
0870:
0871: }
0872:
0873: /**
0874: * Return the set of container listeners associated with this Container.
0875: * If this Container has no registered container listeners, a zero-length
0876: * array is returned.
0877: */
0878: public ContainerListener[] findContainerListeners() {
0879:
0880: synchronized (listeners) {
0881: ContainerListener[] results = new ContainerListener[listeners
0882: .size()];
0883: return ((ContainerListener[]) listeners.toArray(results));
0884: }
0885:
0886: }
0887:
0888: /**
0889: * Return the Mapper associated with the specified protocol, if there
0890: * is one. If there is only one defined Mapper, use it for all protocols.
0891: * If there is no matching Mapper, return <code>null</code>.
0892: *
0893: * @param protocol Protocol for which to find a Mapper
0894: */
0895: public Mapper findMapper(String protocol) {
0896:
0897: if (mapper != null)
0898: return (mapper);
0899: else
0900: synchronized (mappers) {
0901: return ((Mapper) mappers.get(protocol));
0902: }
0903:
0904: }
0905:
0906: /**
0907: * Return the set of Mappers associated with this Container. If this
0908: * Container has no Mappers, a zero-length array is returned.
0909: */
0910: public Mapper[] findMappers() {
0911:
0912: synchronized (mappers) {
0913: Mapper results[] = new Mapper[mappers.size()];
0914: return ((Mapper[]) mappers.values().toArray(results));
0915: }
0916:
0917: }
0918:
0919: /**
0920: * Process the specified Request, to produce the corresponding Response,
0921: * by invoking the first Valve in our pipeline (if any), or the basic
0922: * Valve otherwise.
0923: *
0924: * @param request Request to be processed
0925: * @param response Response to be produced
0926: *
0927: * @exception IllegalStateException if neither a pipeline or a basic
0928: * Valve have been configured for this Container
0929: * @exception IOException if an input/output error occurred while
0930: * processing
0931: * @exception ServletException if a ServletException was thrown
0932: * while processing this request
0933: */
0934: public void invoke(Request request, Response response)
0935: throws IOException, ServletException {
0936:
0937: pipeline.invoke(request, response);
0938:
0939: }
0940:
0941: /**
0942: * Return the child Container that should be used to process this Request,
0943: * based upon its characteristics. If no such child Container can be
0944: * identified, return <code>null</code> instead.
0945: *
0946: * @param request Request being processed
0947: * @param update Update the Request to reflect the mapping selection?
0948: */
0949: public Container map(Request request, boolean update) {
0950:
0951: // Select the Mapper we will use
0952: Mapper mapper = findMapper(request.getRequest().getProtocol());
0953: if (mapper == null)
0954: return (null);
0955:
0956: // Use this Mapper to perform this mapping
0957: return (mapper.map(request, update));
0958:
0959: }
0960:
0961: /**
0962: * Remove an existing child Container from association with this parent
0963: * Container.
0964: *
0965: * @param child Existing child Container to be removed
0966: */
0967: public void removeChild(Container child) {
0968:
0969: synchronized (children) {
0970: if (children.get(child.getName()) == null)
0971: return;
0972: children.remove(child.getName());
0973: }
0974: if (started && (child instanceof Lifecycle)) {
0975: try {
0976: ((Lifecycle) child).stop();
0977: } catch (LifecycleException e) {
0978: log("ContainerBase.removeChild: stop: ", e);
0979: }
0980: }
0981: fireContainerEvent(REMOVE_CHILD_EVENT, child);
0982: child.setParent(null);
0983:
0984: }
0985:
0986: /**
0987: * Remove a container event listener from this component.
0988: *
0989: * @param listener The listener to remove
0990: */
0991: public void removeContainerListener(ContainerListener listener) {
0992:
0993: synchronized (listeners) {
0994: listeners.remove(listener);
0995: }
0996:
0997: }
0998:
0999: /**
1000: * Remove a Mapper associated with this Container, if any.
1001: *
1002: * @param mapper The Mapper to be removed
1003: */
1004: public void removeMapper(Mapper mapper) {
1005:
1006: synchronized (mappers) {
1007:
1008: if (mappers.get(mapper.getProtocol()) == null)
1009: return;
1010: mappers.remove(mapper.getProtocol());
1011: if (started && (mapper instanceof Lifecycle)) {
1012: try {
1013: ((Lifecycle) mapper).stop();
1014: } catch (LifecycleException e) {
1015: log("ContainerBase.removeMapper: stop: ", e);
1016: throw new IllegalStateException(
1017: "ContainerBase.removeMapper: stop: " + e);
1018: }
1019: }
1020: if (mappers.size() != 1)
1021: this .mapper = null;
1022: else {
1023: Iterator values = mappers.values().iterator();
1024: this .mapper = (Mapper) values.next();
1025: }
1026: fireContainerEvent(REMOVE_MAPPER_EVENT, mapper);
1027: }
1028:
1029: }
1030:
1031: /**
1032: * Remove a property change listener from this component.
1033: *
1034: * @param listener The listener to remove
1035: */
1036: public void removePropertyChangeListener(
1037: PropertyChangeListener listener) {
1038:
1039: support.removePropertyChangeListener(listener);
1040:
1041: }
1042:
1043: // ------------------------------------------------------ Lifecycle Methods
1044:
1045: /**
1046: * Add a lifecycle event listener to this component.
1047: *
1048: * @param listener The listener to add
1049: */
1050: public void addLifecycleListener(LifecycleListener listener) {
1051:
1052: lifecycle.addLifecycleListener(listener);
1053:
1054: }
1055:
1056: /**
1057: * Get the lifecycle listeners associated with this lifecycle. If this
1058: * Lifecycle has no listeners registered, a zero-length array is returned.
1059: */
1060: public LifecycleListener[] findLifecycleListeners() {
1061:
1062: return lifecycle.findLifecycleListeners();
1063:
1064: }
1065:
1066: /**
1067: * Remove a lifecycle event listener from this component.
1068: *
1069: * @param listener The listener to remove
1070: */
1071: public void removeLifecycleListener(LifecycleListener listener) {
1072:
1073: lifecycle.removeLifecycleListener(listener);
1074:
1075: }
1076:
1077: /**
1078: * Prepare for active use of the public methods of this Component.
1079: *
1080: * @exception LifecycleException if this component detects a fatal error
1081: * that prevents it from being started
1082: */
1083: public synchronized void start() throws LifecycleException {
1084:
1085: // Validate and update our current component state
1086: if (started)
1087: throw new LifecycleException(sm.getString(
1088: "containerBase.alreadyStarted", logName()));
1089:
1090: // Notify our interested LifecycleListeners
1091: lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
1092:
1093: addDefaultMapper(this .mapperClass);
1094: started = true;
1095:
1096: // Start our subordinate components, if any
1097: if ((loader != null) && (loader instanceof Lifecycle))
1098: ((Lifecycle) loader).start();
1099: if ((logger != null) && (logger instanceof Lifecycle))
1100: ((Lifecycle) logger).start();
1101: if ((manager != null) && (manager instanceof Lifecycle))
1102: ((Lifecycle) manager).start();
1103: if ((cluster != null) && (cluster instanceof Lifecycle))
1104: ((Lifecycle) cluster).start();
1105: if ((realm != null) && (realm instanceof Lifecycle))
1106: ((Lifecycle) realm).start();
1107: if ((resources != null) && (resources instanceof Lifecycle))
1108: ((Lifecycle) resources).start();
1109:
1110: // Start our Mappers, if any
1111: Mapper mappers[] = findMappers();
1112: for (int i = 0; i < mappers.length; i++) {
1113: if (mappers[i] instanceof Lifecycle)
1114: ((Lifecycle) mappers[i]).start();
1115: }
1116:
1117: // Start our child containers, if any
1118: Container children[] = findChildren();
1119: for (int i = 0; i < children.length; i++) {
1120: if (children[i] instanceof Lifecycle)
1121: ((Lifecycle) children[i]).start();
1122: }
1123:
1124: // Start the Valves in our pipeline (including the basic), if any
1125: if (pipeline instanceof Lifecycle)
1126: ((Lifecycle) pipeline).start();
1127:
1128: // Notify our interested LifecycleListeners
1129: lifecycle.fireLifecycleEvent(START_EVENT, null);
1130:
1131: // Notify our interested LifecycleListeners
1132: lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
1133:
1134: }
1135:
1136: /**
1137: * Gracefully shut down active use of the public methods of this Component.
1138: *
1139: * @exception LifecycleException if this component detects a fatal error
1140: * that needs to be reported
1141: */
1142: public synchronized void stop() throws LifecycleException {
1143:
1144: // Validate and update our current component state
1145: if (!started)
1146: throw new LifecycleException(sm.getString(
1147: "containerBase.notStarted", logName()));
1148:
1149: // Notify our interested LifecycleListeners
1150: lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
1151:
1152: // Notify our interested LifecycleListeners
1153: lifecycle.fireLifecycleEvent(STOP_EVENT, null);
1154: started = false;
1155:
1156: // Stop the Valves in our pipeline (including the basic), if any
1157: if (pipeline instanceof Lifecycle) {
1158: ((Lifecycle) pipeline).stop();
1159: }
1160:
1161: // Stop our child containers, if any
1162: Container children[] = findChildren();
1163: for (int i = 0; i < children.length; i++) {
1164: if (children[i] instanceof Lifecycle)
1165: ((Lifecycle) children[i]).stop();
1166: }
1167:
1168: // Stop our Mappers, if any
1169: Mapper mappers[] = findMappers();
1170: for (int i = 0; i < mappers.length; i++) {
1171: if (mappers[(mappers.length - 1) - i] instanceof Lifecycle)
1172: ((Lifecycle) mappers[(mappers.length - 1) - i]).stop();
1173: }
1174:
1175: // Stop our subordinate components, if any
1176: if ((resources != null) && (resources instanceof Lifecycle)) {
1177: ((Lifecycle) resources).stop();
1178: }
1179: if ((realm != null) && (realm instanceof Lifecycle)) {
1180: ((Lifecycle) realm).stop();
1181: }
1182: if ((cluster != null) && (cluster instanceof Lifecycle)) {
1183: ((Lifecycle) cluster).stop();
1184: }
1185: if ((manager != null) && (manager instanceof Lifecycle)) {
1186: ((Lifecycle) manager).stop();
1187: }
1188: if ((logger != null) && (logger instanceof Lifecycle)) {
1189: ((Lifecycle) logger).stop();
1190: }
1191: if ((loader != null) && (loader instanceof Lifecycle)) {
1192: ((Lifecycle) loader).stop();
1193: }
1194:
1195: // Notify our interested LifecycleListeners
1196: lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
1197:
1198: }
1199:
1200: // ------------------------------------------------------- Pipeline Methods
1201:
1202: /**
1203: * Add a new Valve to the end of the pipeline associated with this
1204: * Container. Prior to adding the Valve, the Valve's
1205: * <code>setContainer</code> method must be called, with this Container
1206: * as an argument. The method may throw an
1207: * <code>IllegalArgumentException</code> if this Valve chooses not to
1208: * be associated with this Container, or <code>IllegalStateException</code>
1209: * if it is already associated with a different Container.
1210: *
1211: * @param valve Valve to be added
1212: *
1213: * @exception IllegalArgumentException if this Container refused to
1214: * accept the specified Valve
1215: * @exception IllegalArgumentException if the specifie Valve refuses to be
1216: * associated with this Container
1217: * @exception IllegalStateException if the specified Valve is already
1218: * associated with a different Container
1219: */
1220: public synchronized void addValve(Valve valve) {
1221:
1222: pipeline.addValve(valve);
1223: fireContainerEvent(ADD_VALVE_EVENT, valve);
1224:
1225: }
1226:
1227: /**
1228: * <p>Return the Valve instance that has been distinguished as the basic
1229: * Valve for this Pipeline (if any).
1230: */
1231: public Valve getBasic() {
1232:
1233: return (pipeline.getBasic());
1234:
1235: }
1236:
1237: /**
1238: * Return the set of Valves in the pipeline associated with this
1239: * Container, including the basic Valve (if any). If there are no
1240: * such Valves, a zero-length array is returned.
1241: */
1242: public Valve[] getValves() {
1243:
1244: return (pipeline.getValves());
1245:
1246: }
1247:
1248: /**
1249: * Remove the specified Valve from the pipeline associated with this
1250: * Container, if it is found; otherwise, do nothing.
1251: *
1252: * @param valve Valve to be removed
1253: */
1254: public synchronized void removeValve(Valve valve) {
1255:
1256: pipeline.removeValve(valve);
1257: fireContainerEvent(REMOVE_VALVE_EVENT, valve);
1258:
1259: }
1260:
1261: /**
1262: * <p>Set the Valve instance that has been distinguished as the basic
1263: * Valve for this Pipeline (if any). Prioer to setting the basic Valve,
1264: * the Valve's <code>setContainer()</code> will be called, if it
1265: * implements <code>Contained</code>, with the owning Container as an
1266: * argument. The method may throw an <code>IllegalArgumentException</code>
1267: * if this Valve chooses not to be associated with this Container, or
1268: * <code>IllegalStateException</code> if it is already associated with
1269: * a different Container.</p>
1270: *
1271: * @param valve Valve to be distinguished as the basic Valve
1272: */
1273: public void setBasic(Valve valve) {
1274:
1275: pipeline.setBasic(valve);
1276:
1277: }
1278:
1279: // ------------------------------------------------------ Protected Methods
1280:
1281: /**
1282: * Add a default Mapper implementation if none have been configured
1283: * explicitly.
1284: *
1285: * @param mapperClass Java class name of the default Mapper
1286: */
1287: protected void addDefaultMapper(String mapperClass) {
1288:
1289: // Do we need a default Mapper?
1290: if (mapperClass == null)
1291: return;
1292: if (mappers.size() >= 1)
1293: return;
1294:
1295: // Instantiate and add a default Mapper
1296: try {
1297: Class clazz = Class.forName(mapperClass);
1298: Mapper mapper = (Mapper) clazz.newInstance();
1299: mapper.setProtocol("http");
1300: addMapper(mapper);
1301: } catch (Exception e) {
1302: log(sm.getString("containerBase.addDefaultMapper",
1303: mapperClass), e);
1304: }
1305:
1306: }
1307:
1308: /**
1309: * Notify all container event listeners that a particular event has
1310: * occurred for this Container. The default implementation performs
1311: * this notification synchronously using the calling thread.
1312: *
1313: * @param type Event type
1314: * @param data Event data
1315: */
1316: public void fireContainerEvent(String type, Object data) {
1317:
1318: if (listeners.size() < 1)
1319: return;
1320: ContainerEvent event = new ContainerEvent(this , type, data);
1321: ContainerListener list[] = new ContainerListener[0];
1322: synchronized (listeners) {
1323: list = (ContainerListener[]) listeners.toArray(list);
1324: }
1325: for (int i = 0; i < list.length; i++)
1326: ((ContainerListener) list[i]).containerEvent(event);
1327:
1328: }
1329:
1330: /**
1331: * Log the specified message to our current Logger (if any).
1332: *
1333: * @param message Message to be logged
1334: */
1335: protected void log(String message) {
1336:
1337: Logger logger = getLogger();
1338: if (logger != null)
1339: logger.log(logName() + ": " + message);
1340: else
1341: System.out.println(logName() + ": " + message);
1342:
1343: }
1344:
1345: /**
1346: * Log the specified message and exception to our current Logger
1347: * (if any).
1348: *
1349: * @param message Message to be logged
1350: * @param throwable Related exception
1351: */
1352: protected void log(String message, Throwable throwable) {
1353:
1354: Logger logger = getLogger();
1355: if (logger != null)
1356: logger.log(logName() + ": " + message, throwable);
1357: else {
1358: System.out.println(logName() + ": " + message + ": "
1359: + throwable);
1360: throwable.printStackTrace(System.out);
1361: }
1362:
1363: }
1364:
1365: /**
1366: * Return the abbreviated name of this container for logging messsages
1367: */
1368: protected String logName() {
1369:
1370: String className = this .getClass().getName();
1371: int period = className.lastIndexOf(".");
1372: if (period >= 0)
1373: className = className.substring(period + 1);
1374: return (className + "[" + getName() + "]");
1375:
1376: }
1377:
1378: }
|