0001: /*
0002: * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/core/StandardServer.java,v 1.30 2002/07/10 09:49:01 remm Exp $
0003: * $Revision: 1.30 $
0004: * $Date: 2002/07/10 09:49:01 $
0005: *
0006: * ====================================================================
0007: *
0008: * The Apache Software License, Version 1.1
0009: *
0010: * Copyright (c) 1999-2002 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.IndexedPropertyDescriptor;
0067: import java.beans.PropertyChangeListener;
0068: import java.beans.PropertyChangeSupport;
0069: import java.beans.PropertyDescriptor;
0070: import java.io.File;
0071: import java.io.FileWriter;
0072: import java.io.InputStream;
0073: import java.io.IOException;
0074: import java.io.PrintWriter;
0075: import java.net.InetAddress;
0076: import java.net.ServerSocket;
0077: import java.net.Socket;
0078: import java.security.AccessControlException;
0079: import java.sql.Timestamp;
0080: import java.util.Enumeration;
0081: import java.util.Hashtable;
0082: import java.util.Iterator;
0083: import java.util.Random;
0084:
0085: import javax.naming.directory.DirContext;
0086:
0087: import org.apache.commons.beanutils.PropertyUtils;
0088:
0089: import org.apache.catalina.Connector;
0090: import org.apache.catalina.Container;
0091: import org.apache.catalina.Context;
0092: import org.apache.catalina.DefaultContext;
0093: import org.apache.catalina.Engine;
0094: import org.apache.catalina.Host;
0095: import org.apache.catalina.Lifecycle;
0096: import org.apache.catalina.LifecycleException;
0097: import org.apache.catalina.LifecycleListener;
0098: import org.apache.catalina.Loader;
0099: import org.apache.catalina.Logger;
0100: import org.apache.catalina.Manager;
0101: import org.apache.catalina.Pipeline;
0102: import org.apache.catalina.Realm;
0103: import org.apache.catalina.Server;
0104: import org.apache.catalina.ServerFactory;
0105: import org.apache.catalina.Service;
0106: import org.apache.catalina.Store;
0107: import org.apache.catalina.Valve;
0108: import org.apache.catalina.core.StandardEngine;
0109: import org.apache.catalina.core.StandardHost;
0110: import org.apache.catalina.deploy.ApplicationParameter;
0111: import org.apache.catalina.deploy.NamingResources;
0112: import org.apache.catalina.deploy.ContextEjb;
0113: import org.apache.catalina.deploy.ContextLocalEjb;
0114: import org.apache.catalina.deploy.ContextResource;
0115: import org.apache.catalina.deploy.ContextResourceLink;
0116: import org.apache.catalina.deploy.ContextEnvironment;
0117: import org.apache.catalina.deploy.ResourceParams;
0118: import org.apache.catalina.loader.WebappLoader;
0119: import org.apache.catalina.net.ServerSocketFactory;
0120: import org.apache.catalina.session.PersistentManager;
0121: import org.apache.catalina.session.StandardManager;
0122: import org.apache.catalina.util.LifecycleSupport;
0123: import org.apache.catalina.util.StringManager;
0124:
0125: /**
0126: * Standard implementation of the <b>Server</b> interface, available for use
0127: * (but not required) when deploying and starting Catalina.
0128: *
0129: * @author Craig R. McClanahan
0130: * @version $Revision: 1.30 $ $Date: 2002/07/10 09:49:01 $
0131: */
0132:
0133: public final class StandardServer implements Lifecycle, Server {
0134:
0135: // -------------------------------------------------------------- Constants
0136:
0137: /**
0138: * The set of class/property combinations that should <strong>NOT</strong>
0139: * be persisted because they are automatically calculated.
0140: */
0141: private static String exceptions[][] = {
0142: { "org.apache.catalina.core.StandardContext", "available" },
0143: { "org.apache.catalina.core.StandardContext", "configured" },
0144: { "org.apache.catalina.core.StandardContext",
0145: "distributable" },
0146: { "org.apache.catalina.core.StandardContext", "name" },
0147: { "org.apache.catalina.core.StandardContext", "override" },
0148: { "org.apache.catalina.core.StandardContext", "publicId" },
0149: { "org.apache.catalina.core.StandardContext",
0150: "replaceWelcomeFiles" },
0151: { "org.apache.catalina.core.StandardContext",
0152: "sessionTimeout" },
0153: { "org.apache.catalina.core.StandardContext", "workDir" },
0154: { "org.apache.catalina.session.StandardManager",
0155: "distributable" },
0156: { "org.apache.catalina.session.StandardManager", "entropy" }, };
0157:
0158: /**
0159: * The set of classes that represent persistable properties.
0160: */
0161: private static Class persistables[] = { String.class,
0162: Integer.class, Integer.TYPE, Boolean.class, Boolean.TYPE,
0163: Byte.class, Byte.TYPE, Character.class, Character.TYPE,
0164: Double.class, Double.TYPE, Float.class, Float.TYPE,
0165: Long.class, Long.TYPE, Short.class, Short.TYPE, };
0166:
0167: /**
0168: * The set of class names that should be skipped when persisting state,
0169: * because the corresponding listeners, valves, etc. are configured
0170: * automatically at startup time.
0171: */
0172: private static String skippables[] = {
0173: "org.apache.catalina.authenticator.BasicAuthenticator",
0174: "org.apache.catalina.authenticator.DigestAuthenticator",
0175: "org.apache.catalina.authenticator.FormAuthenticator",
0176: "org.apache.catalina.authenticator.NonLoginAuthenticator",
0177: "org.apache.catalina.authenticator.SSLAuthenticator",
0178: "org.apache.catalina.core.NamingContextListener",
0179: "org.apache.catalina.core.StandardContextValve",
0180: "org.apache.catalina.core.StandardEngineValve",
0181: "org.apache.catalina.core.StandardHostValve",
0182: "org.apache.catalina.startup.ContextConfig",
0183: "org.apache.catalina.startup.EngineConfig",
0184: "org.apache.catalina.startup.HostConfig",
0185: "org.apache.catalina.valves.CertificatesValve",
0186: "org.apache.catalina.valves.ErrorDispatcherValve",
0187: "org.apache.catalina.valves.ErrorReportValve", };
0188:
0189: /**
0190: * ServerLifecycleListener classname.
0191: */
0192: private static String SERVER_LISTENER_CLASS_NAME = "org.apache.catalina.mbeans.ServerLifecycleListener";
0193:
0194: // ------------------------------------------------------------ Constructor
0195:
0196: /**
0197: * Construct a default instance of this class.
0198: */
0199: public StandardServer() {
0200:
0201: super ();
0202: ServerFactory.setServer(this );
0203:
0204: globalNamingResources = new NamingResources();
0205: globalNamingResources.setContainer(this );
0206:
0207: if (isUseNaming()) {
0208: if (namingContextListener == null) {
0209: namingContextListener = new NamingContextListener();
0210: namingContextListener.setDebug(getDebug());
0211: addLifecycleListener(namingContextListener);
0212: }
0213: }
0214:
0215: }
0216:
0217: // ----------------------------------------------------- Instance Variables
0218:
0219: /**
0220: * Debugging detail level.
0221: */
0222: private int debug = 0;
0223:
0224: /**
0225: * Global naming resources context.
0226: */
0227: private javax.naming.Context globalNamingContext = null;
0228:
0229: /**
0230: * Global naming resources.
0231: */
0232: private NamingResources globalNamingResources = null;
0233:
0234: /**
0235: * Descriptive information about this Server implementation.
0236: */
0237: private static final String info = "org.apache.catalina.core.StandardServer/1.0";
0238:
0239: /**
0240: * The lifecycle event support for this component.
0241: */
0242: private LifecycleSupport lifecycle = new LifecycleSupport(this );
0243:
0244: /**
0245: * The naming context listener for this web application.
0246: */
0247: private NamingContextListener namingContextListener = null;
0248:
0249: /**
0250: * The port number on which we wait for shutdown commands.
0251: */
0252: private int port = 8005;
0253:
0254: /**
0255: * A random number generator that is <strong>only</strong> used if
0256: * the shutdown command string is longer than 1024 characters.
0257: */
0258: private Random random = null;
0259:
0260: /**
0261: * The set of Services associated with this Server.
0262: */
0263: private Service services[] = new Service[0];
0264:
0265: /**
0266: * The shutdown command string we are looking for.
0267: */
0268: private String shutdown = "SHUTDOWN";
0269:
0270: /**
0271: * The string manager for this package.
0272: */
0273: private static final StringManager sm = StringManager
0274: .getManager(Constants.Package);
0275:
0276: /**
0277: * Has this component been started?
0278: */
0279: private boolean started = false;
0280:
0281: /**
0282: * Has this component been initialized?
0283: */
0284: private boolean initialized = false;
0285:
0286: /**
0287: * The property change support for this component.
0288: */
0289: protected PropertyChangeSupport support = new PropertyChangeSupport(
0290: this );
0291:
0292: // ------------------------------------------------------------- Properties
0293:
0294: /**
0295: * Return the debugging detail level.
0296: */
0297: public int getDebug() {
0298:
0299: return (this .debug);
0300:
0301: }
0302:
0303: /**
0304: * Set the debugging detail level.
0305: *
0306: * @param debug The new debugging detail level
0307: */
0308: public void setDebug(int debug) {
0309:
0310: this .debug = debug;
0311:
0312: }
0313:
0314: /**
0315: * Return the global naming resources context.
0316: */
0317: public javax.naming.Context getGlobalNamingContext() {
0318:
0319: return (this .globalNamingContext);
0320:
0321: }
0322:
0323: /**
0324: * Set the global naming resources context.
0325: *
0326: * @param globalNamingContext The new global naming resource context
0327: */
0328: public void setGlobalNamingContext(
0329: javax.naming.Context globalNamingContext) {
0330:
0331: this .globalNamingContext = globalNamingContext;
0332:
0333: }
0334:
0335: /**
0336: * Return the global naming resources.
0337: */
0338: public NamingResources getGlobalNamingResources() {
0339:
0340: return (this .globalNamingResources);
0341:
0342: }
0343:
0344: /**
0345: * Set the global naming resources.
0346: *
0347: * @param namingResources The new global naming resources
0348: */
0349: public void setGlobalNamingResources(
0350: NamingResources globalNamingResources) {
0351:
0352: NamingResources oldGlobalNamingResources = this .globalNamingResources;
0353: this .globalNamingResources = globalNamingResources;
0354: this .globalNamingResources.setContainer(this );
0355: support.firePropertyChange("globalNamingResources",
0356: oldGlobalNamingResources, this .globalNamingResources);
0357:
0358: }
0359:
0360: /**
0361: * Return descriptive information about this Server implementation and
0362: * the corresponding version number, in the format
0363: * <code><description>/<version></code>.
0364: */
0365: public String getInfo() {
0366:
0367: return (info);
0368:
0369: }
0370:
0371: /**
0372: * Return the port number we listen to for shutdown commands.
0373: */
0374: public int getPort() {
0375:
0376: return (this .port);
0377:
0378: }
0379:
0380: /**
0381: * Set the port number we listen to for shutdown commands.
0382: *
0383: * @param port The new port number
0384: */
0385: public void setPort(int port) {
0386:
0387: this .port = port;
0388:
0389: }
0390:
0391: /**
0392: * Return the shutdown command string we are waiting for.
0393: */
0394: public String getShutdown() {
0395:
0396: return (this .shutdown);
0397:
0398: }
0399:
0400: /**
0401: * Set the shutdown command we are waiting for.
0402: *
0403: * @param shutdown The new shutdown command
0404: */
0405: public void setShutdown(String shutdown) {
0406:
0407: this .shutdown = shutdown;
0408:
0409: }
0410:
0411: // --------------------------------------------------------- Server Methods
0412:
0413: /**
0414: * Add a new Service to the set of defined Services.
0415: *
0416: * @param service The Service to be added
0417: */
0418: public void addService(Service service) {
0419:
0420: service.setServer(this );
0421:
0422: synchronized (services) {
0423: Service results[] = new Service[services.length + 1];
0424: System.arraycopy(services, 0, results, 0, services.length);
0425: results[services.length] = service;
0426: services = results;
0427:
0428: if (initialized) {
0429: try {
0430: service.initialize();
0431: } catch (LifecycleException e) {
0432: e.printStackTrace(System.err);
0433: }
0434: }
0435:
0436: if (started && (service instanceof Lifecycle)) {
0437: try {
0438: ((Lifecycle) service).start();
0439: } catch (LifecycleException e) {
0440: ;
0441: }
0442: }
0443:
0444: // Report this property change to interested listeners
0445: support.firePropertyChange("service", null, service);
0446: }
0447:
0448: }
0449:
0450: /**
0451: * Wait until a proper shutdown command is received, then return.
0452: */
0453: public void await() {
0454:
0455: // Set up a server socket to wait on
0456: ServerSocket serverSocket = null;
0457: try {
0458: serverSocket = new ServerSocket(port, 1, InetAddress
0459: .getByName("127.0.0.1"));
0460: } catch (IOException e) {
0461: System.err.println("StandardServer.await: create[" + port
0462: + "]: " + e);
0463: e.printStackTrace();
0464: System.exit(1);
0465: }
0466:
0467: // Loop waiting for a connection and a valid command
0468: while (true) {
0469:
0470: // Wait for the next connection
0471: Socket socket = null;
0472: InputStream stream = null;
0473: try {
0474: socket = serverSocket.accept();
0475: socket.setSoTimeout(10 * 1000); // Ten seconds
0476: stream = socket.getInputStream();
0477: } catch (AccessControlException ace) {
0478: System.err
0479: .println("StandardServer.accept security exception: "
0480: + ace.getMessage());
0481: continue;
0482: } catch (IOException e) {
0483: System.err
0484: .println("StandardServer.await: accept: " + e);
0485: e.printStackTrace();
0486: System.exit(1);
0487: }
0488:
0489: // Read a set of characters from the socket
0490: StringBuffer command = new StringBuffer();
0491: int expected = 1024; // Cut off to avoid DoS attack
0492: while (expected < shutdown.length()) {
0493: if (random == null)
0494: random = new Random(System.currentTimeMillis());
0495: expected += (random.nextInt() % 1024);
0496: }
0497: while (expected > 0) {
0498: int ch = -1;
0499: try {
0500: ch = stream.read();
0501: } catch (IOException e) {
0502: System.err.println("StandardServer.await: read: "
0503: + e);
0504: e.printStackTrace();
0505: ch = -1;
0506: }
0507: if (ch < 32) // Control character or EOF terminates loop
0508: break;
0509: command.append((char) ch);
0510: expected--;
0511: }
0512:
0513: // Close the socket now that we are done with it
0514: try {
0515: socket.close();
0516: } catch (IOException e) {
0517: ;
0518: }
0519:
0520: // Match against our command string
0521: boolean match = command.toString().equals(shutdown);
0522: if (match) {
0523: break;
0524: } else
0525: System.err
0526: .println("StandardServer.await: Invalid command '"
0527: + command.toString() + "' received");
0528:
0529: }
0530:
0531: // Close the server socket and return
0532: try {
0533: serverSocket.close();
0534: } catch (IOException e) {
0535: ;
0536: }
0537:
0538: }
0539:
0540: /**
0541: * Return the specified Service (if it exists); otherwise return
0542: * <code>null</code>.
0543: *
0544: * @param name Name of the Service to be returned
0545: */
0546: public Service findService(String name) {
0547:
0548: if (name == null) {
0549: return (null);
0550: }
0551: synchronized (services) {
0552: for (int i = 0; i < services.length; i++) {
0553: if (name.equals(services[i].getName())) {
0554: return (services[i]);
0555: }
0556: }
0557: }
0558: return (null);
0559:
0560: }
0561:
0562: /**
0563: * Return the set of Services defined within this Server.
0564: */
0565: public Service[] findServices() {
0566:
0567: return (services);
0568:
0569: }
0570:
0571: /**
0572: * Remove the specified Service from the set associated from this
0573: * Server.
0574: *
0575: * @param service The Service to be removed
0576: */
0577: public void removeService(Service service) {
0578:
0579: synchronized (services) {
0580: int j = -1;
0581: for (int i = 0; i < services.length; i++) {
0582: if (service == services[i]) {
0583: j = i;
0584: break;
0585: }
0586: }
0587: if (j < 0)
0588: return;
0589: if (services[j] instanceof Lifecycle) {
0590: try {
0591: ((Lifecycle) services[j]).stop();
0592: } catch (LifecycleException e) {
0593: ;
0594: }
0595: }
0596: int k = 0;
0597: Service results[] = new Service[services.length - 1];
0598: for (int i = 0; i < services.length; i++) {
0599: if (i != j)
0600: results[k++] = services[i];
0601: }
0602: services = results;
0603:
0604: // Report this property change to interested listeners
0605: support.firePropertyChange("service", service, null);
0606: }
0607:
0608: }
0609:
0610: // --------------------------------------------------------- Public Methods
0611:
0612: /**
0613: * Add a property change listener to this component.
0614: *
0615: * @param listener The listener to add
0616: */
0617: public void addPropertyChangeListener(
0618: PropertyChangeListener listener) {
0619:
0620: support.addPropertyChangeListener(listener);
0621:
0622: }
0623:
0624: /**
0625: * Remove a property change listener from this component.
0626: *
0627: * @param listener The listener to remove
0628: */
0629: public void removePropertyChangeListener(
0630: PropertyChangeListener listener) {
0631:
0632: support.removePropertyChangeListener(listener);
0633:
0634: }
0635:
0636: /**
0637: * Return a String representation of this component.
0638: */
0639: public String toString() {
0640:
0641: StringBuffer sb = new StringBuffer("StandardServer[");
0642: sb.append(getPort());
0643: sb.append("]");
0644: return (sb.toString());
0645:
0646: }
0647:
0648: /**
0649: * Write the configuration information for this entire <code>Server</code>
0650: * out to the server.xml configuration file.
0651: *
0652: * @exception InstanceNotFoundException if the managed resource object
0653: * cannot be found
0654: * @exception MBeanException if the initializer of the object throws
0655: * an exception, or persistence is not supported
0656: * @exception RuntimeOperationsException if an exception is reported
0657: * by the persistence mechanism
0658: */
0659: public synchronized void store() throws Exception {
0660:
0661: // Calculate file objects for the old and new configuration files.
0662: String configFile = "conf/server.xml"; // FIXME - configurable?
0663: File configOld = new File(configFile);
0664: if (!configOld.isAbsolute()) {
0665: configOld = new File(System.getProperty("catalina.base"),
0666: configFile);
0667: }
0668: File configNew = new File(configFile + ".new");
0669: if (!configNew.isAbsolute()) {
0670: configNew = new File(System.getProperty("catalina.base"),
0671: configFile + ".new");
0672: }
0673: String ts = (new Timestamp(System.currentTimeMillis()))
0674: .toString();
0675: // yyyy-mm-dd hh:mm:ss
0676: // 0123456789012345678
0677: StringBuffer sb = new StringBuffer(".");
0678: sb.append(ts.substring(0, 10));
0679: sb.append('.');
0680: sb.append(ts.substring(11, 13));
0681: sb.append('-');
0682: sb.append(ts.substring(14, 16));
0683: sb.append('-');
0684: sb.append(ts.substring(17, 19));
0685: File configSave = new File(configFile + sb.toString());
0686: if (!configSave.isAbsolute()) {
0687: configSave = new File(System.getProperty("catalina.base"),
0688: configFile + sb.toString());
0689: }
0690:
0691: // Open an output writer for the new configuration file
0692: PrintWriter writer = null;
0693: try {
0694: writer = new PrintWriter(new FileWriter(configNew));
0695: } catch (IOException e) {
0696: if (writer != null) {
0697: try {
0698: writer.close();
0699: } catch (Throwable t) {
0700: ;
0701: }
0702: }
0703: throw (e);
0704: }
0705:
0706: // Store the state of this Server MBean
0707: // (which will recursively store everything
0708: try {
0709: storeServer(writer, 0, this );
0710: } catch (Exception e) {
0711: if (writer != null) {
0712: try {
0713: writer.close();
0714: } catch (Throwable t) {
0715: ;
0716: }
0717: }
0718: throw (e);
0719: }
0720:
0721: // Flush and close the output file
0722: try {
0723: writer.flush();
0724: } catch (Exception e) {
0725: throw (e);
0726: }
0727: try {
0728: writer.close();
0729: } catch (Exception e) {
0730: throw (e);
0731: }
0732:
0733: // Shuffle old->save and new->old
0734: if (configOld.renameTo(configSave)) {
0735: if (configNew.renameTo(configOld)) {
0736: return;
0737: } else {
0738: configSave.renameTo(configOld);
0739: throw new IOException("Cannot rename "
0740: + configNew.getAbsolutePath() + " to "
0741: + configOld.getAbsolutePath());
0742: }
0743: } else {
0744: throw new IOException("Cannot rename "
0745: + configOld.getAbsolutePath() + " to "
0746: + configSave.getAbsolutePath());
0747: }
0748:
0749: }
0750:
0751: // -------------------------------------------------------- Private Methods
0752:
0753: /** Given a string, this method replaces all occurrences of
0754: * '<', '>', '&', and '"'.
0755: */
0756:
0757: private String convertStr(String input) {
0758:
0759: StringBuffer filtered = new StringBuffer(input.length());
0760: char c;
0761: for (int i = 0; i < input.length(); i++) {
0762: c = input.charAt(i);
0763: if (c == '<') {
0764: filtered.append("<");
0765: } else if (c == '>') {
0766: filtered.append(">");
0767: } else if (c == '\'') {
0768: filtered.append("'");
0769: } else if (c == '"') {
0770: filtered.append(""");
0771: } else if (c == '&') {
0772: filtered.append("&");
0773: } else {
0774: filtered.append(c);
0775: }
0776: }
0777: return (filtered.toString());
0778: }
0779:
0780: /**
0781: * Is this an instance of the default <code>Loader</code> configuration,
0782: * with all-default properties?
0783: *
0784: * @param loader Loader to be tested
0785: */
0786: private boolean isDefaultLoader(Loader loader) {
0787:
0788: if (!(loader instanceof WebappLoader)) {
0789: return (false);
0790: }
0791: WebappLoader wloader = (WebappLoader) loader;
0792: if ((wloader.getCheckInterval() != 15)
0793: || (wloader.getDebug() != 0)
0794: || (wloader.getDelegate() != false)
0795: || !wloader.getLoaderClass().equals(
0796: "org.apache.catalina.loader.WebappClassLoader")) {
0797: return (false);
0798: }
0799: return (true);
0800:
0801: }
0802:
0803: /**
0804: * Is this an instance of the default <code>Manager</code> configuration,
0805: * with all-default properties?
0806: *
0807: * @param manager Manager to be tested
0808: */
0809: private boolean isDefaultManager(Manager manager) {
0810:
0811: if (!(manager instanceof StandardManager)) {
0812: return (false);
0813: }
0814: StandardManager smanager = (StandardManager) manager;
0815: if ((smanager.getDebug() != 0)
0816: || !smanager.getPathname().equals("SESSIONS.ser")
0817: || (smanager.getCheckInterval() != 60)
0818: || !smanager.getRandomClass().equals(
0819: "java.security.SecureRandom")
0820: || (smanager.getMaxActiveSessions() != -1)
0821: || !smanager.getAlgorithm().equals("MD5")) {
0822: return (false);
0823: }
0824: return (true);
0825:
0826: }
0827:
0828: /**
0829: * Is the specified class name + property name combination an
0830: * exception that should not be persisted?
0831: *
0832: * @param className The class name to check
0833: * @param property The property name to check
0834: */
0835: private boolean isException(String className, String property) {
0836:
0837: for (int i = 0; i < exceptions.length; i++) {
0838: if (className.equals(exceptions[i][0])
0839: && property.equals(exceptions[i][1])) {
0840: return (true);
0841: }
0842: }
0843: return (false);
0844:
0845: }
0846:
0847: /**
0848: * Is the specified property type one for which we should generate
0849: * a persistence attribute?
0850: *
0851: * @param clazz Java class to be tested
0852: */
0853: private boolean isPersistable(Class clazz) {
0854:
0855: for (int i = 0; i < persistables.length; i++) {
0856: if (persistables[i] == clazz) {
0857: return (true);
0858: }
0859: }
0860: return (false);
0861:
0862: }
0863:
0864: /**
0865: * Is the specified class name one that should be skipped because
0866: * the corresponding component is configured automatically at
0867: * startup time?
0868: *
0869: * @param className Class name to be tested
0870: */
0871: private boolean isSkippable(String className) {
0872:
0873: for (int i = 0; i < skippables.length; i++) {
0874: if (skippables[i] == className) {
0875: return (true);
0876: }
0877: }
0878: return (false);
0879:
0880: }
0881:
0882: /**
0883: * Store the relevant attributes of the specified JavaBean, plus a
0884: * <code>className</code> attribute defining the fully qualified
0885: * Java class name of the bean.
0886: *
0887: * @param writer PrintWriter to which we are storing
0888: * @param bean Bean whose properties are to be rendered as attributes,
0889: *
0890: * @exception Exception if an exception occurs while storing
0891: */
0892: private void storeAttributes(PrintWriter writer, Object bean)
0893: throws Exception {
0894:
0895: storeAttributes(writer, true, bean);
0896:
0897: }
0898:
0899: /**
0900: * Store the relevant attributes of the specified JavaBean.
0901: *
0902: * @param writer PrintWriter to which we are storing
0903: * @param include Should we include a <code>className</code> attribute?
0904: * @param bean Bean whose properties are to be rendered as attributes,
0905: *
0906: * @exception Exception if an exception occurs while storing
0907: */
0908: private void storeAttributes(PrintWriter writer, boolean include,
0909: Object bean) throws Exception {
0910:
0911: // Render a className attribute if requested
0912: if (include) {
0913: writer.print(" className=\"");
0914: writer.print(bean.getClass().getName());
0915: writer.print("\"");
0916: }
0917:
0918: // Acquire the list of properties for this bean
0919: PropertyDescriptor descriptors[] = PropertyUtils
0920: .getPropertyDescriptors(bean);
0921: if (descriptors == null) {
0922: descriptors = new PropertyDescriptor[0];
0923: }
0924:
0925: // Render the relevant properties of this bean
0926: String className = bean.getClass().getName();
0927: for (int i = 0; i < descriptors.length; i++) {
0928: if (descriptors[i] instanceof IndexedPropertyDescriptor) {
0929: continue; // Indexed properties are not persisted
0930: }
0931: if (!isPersistable(descriptors[i].getPropertyType())
0932: || (descriptors[i].getReadMethod() == null)
0933: || (descriptors[i].getWriteMethod() == null)) {
0934: continue; // Must be a read-write primitive or String
0935: }
0936: Object value = PropertyUtils.getSimpleProperty(bean,
0937: descriptors[i].getName());
0938: if (value == null) {
0939: continue; // Null values are not persisted
0940: }
0941: if (isException(className, descriptors[i].getName())) {
0942: continue; // Skip the specified exceptions
0943: }
0944: if (!(value instanceof String)) {
0945: value = value.toString();
0946: }
0947: writer.print(' ');
0948: writer.print(descriptors[i].getName());
0949: writer.print("=\"");
0950: String strValue = convertStr((String) value);
0951: writer.print(strValue);
0952: writer.print("\"");
0953: }
0954:
0955: }
0956:
0957: /**
0958: * Store the specified Connector properties.
0959: *
0960: * @param writer PrintWriter to which we are storing
0961: * @param indent Number of spaces to indent this element
0962: * @param connector Object whose properties are being stored
0963: *
0964: * @exception Exception if an exception occurs while storing
0965: */
0966: private void storeConnector(PrintWriter writer, int indent,
0967: Connector connector) throws Exception {
0968:
0969: // Store the beginning of this element
0970: for (int i = 0; i < indent; i++) {
0971: writer.print(' ');
0972: }
0973: writer.print("<Connector");
0974: storeAttributes(writer, connector);
0975: writer.println(">");
0976:
0977: // Store nested <Factory> element
0978: ServerSocketFactory factory = connector.getFactory();
0979: if (factory != null) {
0980: storeFactory(writer, indent + 2, factory);
0981: }
0982:
0983: // Store nested <Listener> elements
0984: if (connector instanceof Lifecycle) {
0985: LifecycleListener listeners[] = ((Lifecycle) connector)
0986: .findLifecycleListeners();
0987: if (listeners == null) {
0988: listeners = new LifecycleListener[0];
0989: }
0990: for (int i = 0; i < listeners.length; i++) {
0991: if (listeners[i].getClass().getName().equals(
0992: SERVER_LISTENER_CLASS_NAME)) {
0993: continue;
0994: }
0995: storeListener(writer, indent + 2, listeners[i]);
0996: }
0997: }
0998:
0999: // Store the ending of this element
1000: for (int i = 0; i < indent; i++) {
1001: writer.print(' ');
1002: }
1003: writer.println("</Connector>");
1004:
1005: }
1006:
1007: /**
1008: * Store the specified Context properties.
1009: *
1010: * @param writer PrintWriter to which we are storing
1011: * @param indent Number of spaces to indent this element
1012: * @param context Object whose properties are being stored
1013: *
1014: * @exception Exception if an exception occurs while storing
1015: */
1016: private void storeContext(PrintWriter writer, int indent,
1017: Context context) throws Exception {
1018:
1019: // Store the beginning of this element
1020: for (int i = 0; i < indent; i++) {
1021: writer.print(' ');
1022: }
1023: writer.print("<Context");
1024: storeAttributes(writer, context);
1025: writer.println(">");
1026:
1027: // Store nested <InstanceListener> elements
1028: String iListeners[] = context.findInstanceListeners();
1029: for (int i = 0; i < iListeners.length; i++) {
1030: for (int j = 0; j < indent; j++) {
1031: writer.print(' ');
1032: }
1033: writer.print("<InstanceListener>");
1034: writer.print(iListeners[i]);
1035: writer.println("</InstanceListener>");
1036: }
1037:
1038: // Store nested <Listener> elements
1039: if (context instanceof Lifecycle) {
1040: LifecycleListener listeners[] = ((Lifecycle) context)
1041: .findLifecycleListeners();
1042: for (int i = 0; i < listeners.length; i++) {
1043: if (listeners[i].getClass().getName().equals(
1044: SERVER_LISTENER_CLASS_NAME)) {
1045: continue;
1046: }
1047: storeListener(writer, indent + 2, listeners[i]);
1048: }
1049: }
1050:
1051: // Store nested <Loader> element
1052: Loader loader = context.getLoader();
1053: if (loader != null) {
1054: storeLoader(writer, indent + 2, loader);
1055: }
1056:
1057: // Store nested <Logger> element
1058: Logger logger = context.getLogger();
1059: if (logger != null) {
1060: Logger parentLogger = null;
1061: if (context.getParent() != null) {
1062: parentLogger = context.getParent().getLogger();
1063: }
1064: if (logger != parentLogger) {
1065: storeLogger(writer, indent + 2, logger);
1066: }
1067: }
1068:
1069: // Store nested <Manager> element
1070: Manager manager = context.getManager();
1071: if (manager != null) {
1072: storeManager(writer, indent + 2, manager);
1073: }
1074:
1075: // Store nested <Parameter> elements
1076: ApplicationParameter[] appParams = context
1077: .findApplicationParameters();
1078: for (int i = 0; i < appParams.length; i++) {
1079: for (int j = 0; j < indent + 2; j++) {
1080: writer.print(' ');
1081: }
1082: writer.print("<Parameter");
1083: storeAttributes(writer, false, appParams[i]);
1084: writer.println("/>");
1085: }
1086:
1087: // Store nested <Realm> element
1088: Realm realm = context.getRealm();
1089: if (realm != null) {
1090: Realm parentRealm = null;
1091: if (context.getParent() != null) {
1092: parentRealm = context.getParent().getRealm();
1093: }
1094: if (realm != parentRealm) {
1095: storeRealm(writer, indent + 2, realm);
1096: }
1097: }
1098:
1099: // Store nested <Resources> element
1100: DirContext resources = context.getResources();
1101: if (resources != null) {
1102: storeResources(writer, indent + 2, resources);
1103: }
1104:
1105: // Store nested <Valve> elements
1106: if (context instanceof Pipeline) {
1107: Valve valves[] = ((Pipeline) context).getValves();
1108: for (int i = 0; i < valves.length; i++) {
1109: storeValve(writer, indent + 2, valves[i]);
1110: }
1111: }
1112:
1113: // Store nested <WrapperLifecycle> elements
1114: String wLifecycles[] = context.findWrapperLifecycles();
1115: for (int i = 0; i < wLifecycles.length; i++) {
1116: for (int j = 0; j < indent; j++) {
1117: writer.print(' ');
1118: }
1119: writer.print("<WrapperLifecycle>");
1120: writer.print(wLifecycles[i]);
1121: writer.println("</WrapperLifecycle>");
1122: }
1123:
1124: // Store nested <WrapperListener> elements
1125: String wListeners[] = context.findWrapperListeners();
1126: for (int i = 0; i < wListeners.length; i++) {
1127: for (int j = 0; j < indent; j++) {
1128: writer.print(' ');
1129: }
1130: writer.print("<WrapperListener>");
1131: writer.print(wListeners[i]);
1132: writer.println("</WrapperListener>");
1133: }
1134:
1135: // Store nested naming resources elements
1136: NamingResources nresources = context.getNamingResources();
1137: if (nresources != null) {
1138: storeNamingResources(writer, indent + 2, nresources);
1139: }
1140:
1141: // Store the ending of this element
1142: for (int i = 0; i < indent; i++) {
1143: writer.print(' ');
1144: }
1145: writer.println("</Context>");
1146:
1147: }
1148:
1149: /**
1150: * Store the specified DefaultContext properties.
1151: *
1152: * @param writer PrintWriter to which we are storing
1153: * @param indent Number of spaces to indent this element
1154: * @param dcontext Object whose properties are being stored
1155: *
1156: * @exception Exception if an exception occurs while storing
1157: */
1158: private void storeDefaultContext(PrintWriter writer, int indent,
1159: DefaultContext dcontext) throws Exception {
1160:
1161: // Store the beginning of this element
1162: for (int i = 0; i < indent; i++) {
1163: writer.print(' ');
1164: }
1165: writer.print("<DefaultContext");
1166: storeAttributes(writer, dcontext);
1167: writer.println(">");
1168:
1169: // Store nested <InstanceListener> elements
1170: String iListeners[] = dcontext.findInstanceListeners();
1171: for (int i = 0; i < iListeners.length; i++) {
1172: for (int j = 0; j < indent; j++) {
1173: writer.print(' ');
1174: }
1175: writer.print("<InstanceListener>");
1176: writer.print(iListeners[i]);
1177: writer.println("</InstanceListener>");
1178: }
1179:
1180: // Store nested <Listener> elements
1181: if (dcontext instanceof Lifecycle) {
1182: LifecycleListener listeners[] = ((Lifecycle) dcontext)
1183: .findLifecycleListeners();
1184: for (int i = 0; i < listeners.length; i++) {
1185: if (listeners[i].getClass().getName().equals(
1186: SERVER_LISTENER_CLASS_NAME)) {
1187: continue;
1188: }
1189: storeListener(writer, indent + 2, listeners[i]);
1190: }
1191: }
1192:
1193: // Store nested <Loader> element
1194: Loader loader = dcontext.getLoader();
1195: if (loader != null) {
1196: storeLoader(writer, indent + 2, loader);
1197: }
1198:
1199: // Store nested <Logger> element
1200: /* Nested logger not currently supported on DefaultContext
1201: Logger logger = dcontext.getLogger();
1202: if (logger != null) {
1203: Logger parentLogger = null;
1204: if (dcontext.getParent() != null) {
1205: parentLogger = dcontext.getParent().getLogger();
1206: }
1207: if (logger != parentLogger) {
1208: storeLogger(writer, indent + 2, logger);
1209: }
1210: }
1211: */
1212:
1213: // Store nested <Manager> element
1214: Manager manager = dcontext.getManager();
1215: if (manager != null) {
1216: storeManager(writer, indent + 2, manager);
1217: }
1218:
1219: // Store nested <Parameter> elements
1220: ApplicationParameter[] appParams = dcontext
1221: .findApplicationParameters();
1222: for (int i = 0; i < appParams.length; i++) {
1223: for (int j = 0; j < indent + 2; j++) {
1224: writer.print(' ');
1225: }
1226: writer.print("<Parameter");
1227: storeAttributes(writer, false, appParams[i]);
1228: writer.println("/>");
1229: }
1230:
1231: // Store nested <Realm> element
1232: /* Nested realm not currently supported on DefaultContext
1233: Realm realm = dcontext.getRealm();
1234: if (realm != null) {
1235: Realm parentRealm = null;
1236: if (dcontext.getParent() != null) {
1237: parentRealm = dcontext.getParent().getRealm();
1238: }
1239: if (realm != parentRealm) {
1240: storeRealm(writer, indent + 2, realm);
1241: }
1242: }
1243: */
1244:
1245: // Store nested <Resources> element
1246: DirContext resources = dcontext.getResources();
1247: if (resources != null) {
1248: storeResources(writer, indent + 2, resources);
1249: }
1250:
1251: // Store nested <Valve> elements
1252: if (dcontext instanceof Pipeline) {
1253: Valve valves[] = ((Pipeline) dcontext).getValves();
1254: for (int i = 0; i < valves.length; i++) {
1255: storeValve(writer, indent + 2, valves[i]);
1256: }
1257: }
1258:
1259: // Store nested <WrapperLifecycle> elements
1260: String wLifecycles[] = dcontext.findWrapperLifecycles();
1261: for (int i = 0; i < wLifecycles.length; i++) {
1262: for (int j = 0; j < indent; j++) {
1263: writer.print(' ');
1264: }
1265: writer.print("<WrapperLifecycle>");
1266: writer.print(wLifecycles[i]);
1267: writer.println("</WrapperLifecycle>");
1268: }
1269:
1270: // Store nested <WrapperListener> elements
1271: String wListeners[] = dcontext.findWrapperListeners();
1272: for (int i = 0; i < wListeners.length; i++) {
1273: for (int j = 0; j < indent; j++) {
1274: writer.print(' ');
1275: }
1276: writer.print("<WrapperListener>");
1277: writer.print(wListeners[i]);
1278: writer.println("</WrapperListener>");
1279: }
1280:
1281: // Store nested naming resources elements
1282: /* FIXME - DefaultContext does not have a getNamingResources() method
1283: NamingResources nresources = dcontext.getNamingResources();
1284: if (nresources != null) {
1285: storeNamingResources(writer, indent + 2, nresources);
1286: }
1287: */
1288:
1289: // Store the ending of this element
1290: for (int i = 0; i < indent; i++) {
1291: writer.print(' ');
1292: }
1293: writer.println("</DefaultContext>");
1294:
1295: }
1296:
1297: /**
1298: * Store the specified Engine properties.
1299: *
1300: * @param writer PrintWriter to which we are storing
1301: * @param indent Number of spaces to indent this element
1302: * @param engine Object whose properties are being stored
1303: *
1304: * @exception Exception if an exception occurs while storing
1305: */
1306: private void storeEngine(PrintWriter writer, int indent,
1307: Engine engine) throws Exception {
1308:
1309: // Store the beginning of this element
1310: for (int i = 0; i < indent; i++) {
1311: writer.print(' ');
1312: }
1313: writer.print("<Engine");
1314: storeAttributes(writer, engine);
1315: writer.println(">");
1316:
1317: // Store nested <DefaultContext> element
1318: if (engine instanceof StandardEngine) {
1319: DefaultContext dcontext = ((StandardEngine) engine)
1320: .getDefaultContext();
1321: if (dcontext != null) {
1322: storeDefaultContext(writer, indent + 2, dcontext);
1323: }
1324: }
1325:
1326: // Store nested <Host> elements (or other relevant containers)
1327: Container children[] = engine.findChildren();
1328: for (int i = 0; i < children.length; i++) {
1329: if (children[i] instanceof Context) {
1330: storeContext(writer, indent + 2, (Context) children[i]);
1331: } else if (children[i] instanceof Engine) {
1332: storeEngine(writer, indent + 2, (Engine) children[i]);
1333: } else if (children[i] instanceof Host) {
1334: storeHost(writer, indent + 2, (Host) children[i]);
1335: }
1336: }
1337:
1338: // Store nested <Listener> elements
1339: if (engine instanceof Lifecycle) {
1340: LifecycleListener listeners[] = ((Lifecycle) engine)
1341: .findLifecycleListeners();
1342: for (int i = 0; i < listeners.length; i++) {
1343: if (listeners[i].getClass().getName().equals(
1344: SERVER_LISTENER_CLASS_NAME)) {
1345: continue;
1346: }
1347: storeListener(writer, indent + 2, listeners[i]);
1348: }
1349: }
1350:
1351: // Store nested <Logger> element
1352: Logger logger = engine.getLogger();
1353: if (logger != null) {
1354: Logger parentLogger = null;
1355: if (engine.getParent() != null) {
1356: parentLogger = engine.getParent().getLogger();
1357: }
1358: if (logger != parentLogger) {
1359: storeLogger(writer, indent + 2, logger);
1360: }
1361: }
1362:
1363: // Store nested <Realm> element
1364: Realm realm = engine.getRealm();
1365: if (realm != null) {
1366: Realm parentRealm = null;
1367: if (engine.getParent() != null) {
1368: parentRealm = engine.getParent().getRealm();
1369: }
1370: if (realm != parentRealm) {
1371: storeRealm(writer, indent + 2, realm);
1372: }
1373: }
1374:
1375: // Store nested <Valve> elements
1376: if (engine instanceof Pipeline) {
1377: Valve valves[] = ((Pipeline) engine).getValves();
1378: for (int i = 0; i < valves.length; i++) {
1379: storeValve(writer, indent + 2, valves[i]);
1380: }
1381: }
1382:
1383: // Store the ending of this element
1384: for (int i = 0; i < indent; i++) {
1385: writer.print(' ');
1386: }
1387: writer.println("</Engine>");
1388:
1389: }
1390:
1391: /**
1392: * Store the specified ServerSocketFactory properties.
1393: *
1394: * @param writer PrintWriter to which we are storing
1395: * @param indent Number of spaces to indent this element
1396: * @param factory Object whose properties are being stored
1397: *
1398: * @exception Exception if an exception occurs while storing
1399: */
1400: private void storeFactory(PrintWriter writer, int indent,
1401: ServerSocketFactory factory) throws Exception {
1402:
1403: for (int i = 0; i < indent; i++) {
1404: writer.print(' ');
1405: }
1406: writer.print("<Factory");
1407: storeAttributes(writer, factory);
1408: writer.println("/>");
1409:
1410: }
1411:
1412: /**
1413: * Store the specified Host properties.
1414: *
1415: * @param writer PrintWriter to which we are storing
1416: * @param indent Number of spaces to indent this element
1417: * @param host Object whose properties are being stored
1418: *
1419: * @exception Exception if an exception occurs while storing
1420: */
1421: private void storeHost(PrintWriter writer, int indent, Host host)
1422: throws Exception {
1423:
1424: // Store the beginning of this element
1425: for (int i = 0; i < indent; i++) {
1426: writer.print(' ');
1427: }
1428: writer.print("<Host");
1429: storeAttributes(writer, host);
1430: writer.println(">");
1431:
1432: // Store nested <Alias> elements
1433: String aliases[] = host.findAliases();
1434: for (int i = 0; i < aliases.length; i++) {
1435: for (int j = 0; j < indent; j++) {
1436: writer.print(' ');
1437: }
1438: writer.print("<Alias>");
1439: writer.print(aliases[i]);
1440: writer.println("</Alias>");
1441: }
1442:
1443: // Store nested <Cluster> elements
1444: ; // FIXME - But it's not supported by any standard Host implementation
1445:
1446: // Store nested <Context> elements (or other relevant containers)
1447: Container children[] = host.findChildren();
1448: for (int i = 0; i < children.length; i++) {
1449: if (children[i] instanceof Context) {
1450: storeContext(writer, indent + 2, (Context) children[i]);
1451: } else if (children[i] instanceof Engine) {
1452: storeEngine(writer, indent + 2, (Engine) children[i]);
1453: } else if (children[i] instanceof Host) {
1454: storeHost(writer, indent + 2, (Host) children[i]);
1455: }
1456: }
1457:
1458: // Store nested <DefaultContext> element
1459: if (host instanceof StandardHost) {
1460: DefaultContext dcontext = ((StandardHost) host)
1461: .getDefaultContext();
1462: if (dcontext != null) {
1463: Container parent = host.getParent();
1464: if ((parent != null)
1465: && (parent instanceof StandardEngine)) {
1466: DefaultContext pcontext = ((StandardEngine) parent)
1467: .getDefaultContext();
1468: if (dcontext != pcontext) {
1469: storeDefaultContext(writer, indent + 2,
1470: dcontext);
1471: }
1472: }
1473: }
1474: }
1475:
1476: // Store nested <Listener> elements
1477: if (host instanceof Lifecycle) {
1478: LifecycleListener listeners[] = ((Lifecycle) host)
1479: .findLifecycleListeners();
1480: for (int i = 0; i < listeners.length; i++) {
1481: if (listeners[i].getClass().getName().equals(
1482: SERVER_LISTENER_CLASS_NAME)) {
1483: continue;
1484: }
1485: storeListener(writer, indent + 2, listeners[i]);
1486: }
1487: }
1488:
1489: // Store nested <Logger> element
1490: Logger logger = host.getLogger();
1491: if (logger != null) {
1492: Logger parentLogger = null;
1493: if (host.getParent() != null) {
1494: parentLogger = host.getParent().getLogger();
1495: }
1496: if (logger != parentLogger) {
1497: storeLogger(writer, indent + 2, logger);
1498: }
1499: }
1500:
1501: // Store nested <Realm> element
1502: Realm realm = host.getRealm();
1503: if (realm != null) {
1504: Realm parentRealm = null;
1505: if (host.getParent() != null) {
1506: parentRealm = host.getParent().getRealm();
1507: }
1508: if (realm != parentRealm) {
1509: storeRealm(writer, indent + 2, realm);
1510: }
1511: }
1512:
1513: // Store nested <Valve> elements
1514: if (host instanceof Pipeline) {
1515: Valve valves[] = ((Pipeline) host).getValves();
1516: for (int i = 0; i < valves.length; i++) {
1517: storeValve(writer, indent + 2, valves[i]);
1518: }
1519: }
1520:
1521: // Store the ending of this element
1522: for (int i = 0; i < indent; i++) {
1523: writer.print(' ');
1524: }
1525: writer.println("</Host>");
1526:
1527: }
1528:
1529: /**
1530: * Store the specified Listener properties.
1531: *
1532: * @param writer PrintWriter to which we are storing
1533: * @param indent Number of spaces to indent this element
1534: * @param listener Object whose properties are being stored
1535: *
1536: * @exception Exception if an exception occurs while storing
1537: */
1538: private void storeListener(PrintWriter writer, int indent,
1539: LifecycleListener listener) throws Exception {
1540:
1541: if (isSkippable(listener.getClass().getName())) {
1542: return;
1543: }
1544:
1545: for (int i = 0; i < indent; i++) {
1546: writer.print(' ');
1547: }
1548: writer.print("<Listener");
1549: storeAttributes(writer, listener);
1550: writer.println("/>");
1551:
1552: }
1553:
1554: /**
1555: * Store the specified Loader properties.
1556: *
1557: * @param writer PrintWriter to which we are storing
1558: * @param indent Number of spaces to indent this element
1559: * @param loader Object whose properties are being stored
1560: *
1561: * @exception Exception if an exception occurs while storing
1562: */
1563: private void storeLoader(PrintWriter writer, int indent,
1564: Loader loader) throws Exception {
1565:
1566: if (isDefaultLoader(loader)) {
1567: return;
1568: }
1569: for (int i = 0; i < indent; i++) {
1570: writer.print(' ');
1571: }
1572: writer.print("<Loader");
1573: storeAttributes(writer, loader);
1574: writer.println("/>");
1575:
1576: }
1577:
1578: /**
1579: * Store the specified Logger properties.
1580: *
1581: * @param writer PrintWriter to which we are storing
1582: * @param indent Number of spaces to indent this element
1583: * @param logger Object whose properties are being stored
1584: *
1585: * @exception Exception if an exception occurs while storing
1586: */
1587: private void storeLogger(PrintWriter writer, int indent,
1588: Logger logger) throws Exception {
1589:
1590: for (int i = 0; i < indent; i++) {
1591: writer.print(' ');
1592: }
1593: writer.print("<Logger");
1594: storeAttributes(writer, logger);
1595: writer.println("/>");
1596:
1597: }
1598:
1599: /**
1600: * Store the specified Manager properties.
1601: *
1602: * @param writer PrintWriter to which we are storing
1603: * @param indent Number of spaces to indent this element
1604: * @param manager Object whose properties are being stored
1605: *
1606: * @exception Exception if an exception occurs while storing
1607: */
1608: private void storeManager(PrintWriter writer, int indent,
1609: Manager manager) throws Exception {
1610:
1611: if (isDefaultManager(manager)) {
1612: return;
1613: }
1614:
1615: // Store the beginning of this element
1616: for (int i = 0; i < indent; i++) {
1617: writer.print(' ');
1618: }
1619: writer.print("<Manager");
1620: storeAttributes(writer, manager);
1621: writer.println(">");
1622:
1623: // Store nested <Store> element
1624: if (manager instanceof PersistentManager) {
1625: Store store = ((PersistentManager) manager).getStore();
1626: if (store != null) {
1627: storeStore(writer, indent + 2, store);
1628: }
1629: }
1630:
1631: // Store the ending of this element
1632: for (int i = 0; i < indent; i++) {
1633: writer.print(' ');
1634: }
1635: writer.println("</Manager>");
1636:
1637: }
1638:
1639: /**
1640: * Store the specified NamingResources properties.
1641: *
1642: * @param writer PrintWriter to which we are storing
1643: * @param indent Number of spaces to indent this element
1644: * @param resources Object whose properties are being stored
1645: *
1646: * @exception Exception if an exception occurs while storing
1647: */
1648: private void storeNamingResources(PrintWriter writer, int indent,
1649: NamingResources resources) throws Exception {
1650:
1651: // Store nested <Ejb> elements
1652: ContextEjb[] ejbs = resources.findEjbs();
1653: if (ejbs.length > 0) {
1654: for (int i = 0; i < ejbs.length; i++) {
1655: for (int j = 0; j < indent; j++) {
1656: writer.print(' ');
1657: }
1658: writer.print("<Ejb");
1659: storeAttributes(writer, false, ejbs[i]);
1660: writer.println("/>");
1661: }
1662: }
1663:
1664: // Store nested <Environment> elements
1665: ContextEnvironment[] envs = resources.findEnvironments();
1666: if (envs.length > 0) {
1667: for (int i = 0; i < envs.length; i++) {
1668: for (int j = 0; j < indent; j++) {
1669: writer.print(' ');
1670: }
1671: writer.print("<Environment");
1672: storeAttributes(writer, false, envs[i]);
1673: writer.println("/>");
1674: }
1675: }
1676:
1677: // Store nested <LocalEjb> elements
1678: ContextLocalEjb[] lejbs = resources.findLocalEjbs();
1679: if (lejbs.length > 0) {
1680: for (int i = 0; i < lejbs.length; i++) {
1681: for (int j = 0; j < indent; j++) {
1682: writer.print(' ');
1683: }
1684: writer.print("<LocalEjb");
1685: storeAttributes(writer, false, lejbs[i]);
1686: writer.println("/>");
1687: }
1688: }
1689:
1690: // Store nested <Resource> elements
1691: ContextResource[] dresources = resources.findResources();
1692: for (int i = 0; i < dresources.length; i++) {
1693: for (int j = 0; j < indent; j++) {
1694: writer.print(' ');
1695: }
1696: writer.print("<Resource");
1697: storeAttributes(writer, false, dresources[i]);
1698: writer.println("/>");
1699: }
1700:
1701: // Store nested <ResourceEnvRef> elements
1702: String[] eresources = resources.findResourceEnvRefs();
1703: for (int i = 0; i < eresources.length; i++) {
1704: for (int j = 0; j < indent; j++) {
1705: writer.print(' ');
1706: }
1707: writer.println("<ResourceEnvRef>");
1708: for (int j = 0; j < indent + 2; j++) {
1709: writer.print(' ');
1710: }
1711: writer.print("<name>");
1712: writer.print(eresources[i]);
1713: writer.println("</name>");
1714: for (int j = 0; j < indent + 2; j++) {
1715: writer.print(' ');
1716: }
1717: writer.print("<type>");
1718: writer.print(resources.findResourceEnvRef(eresources[i]));
1719: writer.println("</type>");
1720: for (int j = 0; j < indent; j++) {
1721: writer.print(' ');
1722: }
1723: writer.println("</ResourceEnvRef>");
1724: }
1725:
1726: // Store nested <ResourceParams> elements
1727: ResourceParams[] params = resources.findResourceParams();
1728: for (int i = 0; i < params.length; i++) {
1729: for (int j = 0; j < indent; j++) {
1730: writer.print(' ');
1731: }
1732: writer.print("<ResourceParams");
1733: storeAttributes(writer, false, params[i]);
1734: writer.println(">");
1735: Hashtable resourceParams = params[i].getParameters();
1736: Enumeration nameEnum = resourceParams.keys();
1737: while (nameEnum.hasMoreElements()) {
1738: String name = (String) nameEnum.nextElement();
1739: String value = (String) resourceParams.get(name);
1740: for (int j = 0; j < indent + 2; j++) {
1741: writer.print(' ');
1742: }
1743: writer.println("<parameter>");
1744: for (int j = 0; j < indent + 4; j++) {
1745: writer.print(' ');
1746: }
1747: writer.print("<name>");
1748: writer.print(name);
1749: writer.println("</name>");
1750: for (int j = 0; j < indent + 4; j++) {
1751: writer.print(' ');
1752: }
1753: writer.print("<value>");
1754: writer.print(value);
1755: writer.println("</value>");
1756: for (int j = 0; j < indent + 2; j++) {
1757: writer.print(' ');
1758: }
1759: writer.println("</parameter>");
1760: }
1761: for (int j = 0; j < indent; j++) {
1762: writer.print(' ');
1763: }
1764: writer.println("</ResourceParams>");
1765: }
1766:
1767: // Store nested <ResourceLink> elements
1768: ContextResourceLink[] resourceLinks = resources
1769: .findResourceLinks();
1770: for (int i = 0; i < resourceLinks.length; i++) {
1771: for (int j = 0; j < indent; j++) {
1772: writer.print(' ');
1773: }
1774: writer.print("<ResourceLink");
1775: storeAttributes(writer, false, resourceLinks[i]);
1776: writer.println("/>");
1777: }
1778:
1779: }
1780:
1781: /**
1782: * Store the specified Realm properties.
1783: *
1784: * @param writer PrintWriter to which we are storing
1785: * @param indent Number of spaces to indent this element
1786: * @param realm Object whose properties are being stored
1787: *
1788: * @exception Exception if an exception occurs while storing
1789: */
1790: private void storeRealm(PrintWriter writer, int indent, Realm realm)
1791: throws Exception {
1792:
1793: for (int i = 0; i < indent; i++) {
1794: writer.print(' ');
1795: }
1796: writer.print("<Realm");
1797: storeAttributes(writer, realm);
1798: writer.println("/>");
1799:
1800: }
1801:
1802: /**
1803: * Store the specified Resources properties.
1804: *
1805: * @param writer PrintWriter to which we are storing
1806: * @param indent Number of spaces to indent this element
1807: * @param resources Object whose properties are being stored
1808: *
1809: * @exception Exception if an exception occurs while storing
1810: */
1811: private void storeResources(PrintWriter writer, int indent,
1812: DirContext resources) throws Exception {
1813:
1814: if (resources instanceof org.apache.naming.resources.FileDirContext) {
1815: return;
1816: }
1817: if (resources instanceof org.apache.naming.resources.ProxyDirContext) {
1818: return;
1819: }
1820: if (resources instanceof org.apache.naming.resources.WARDirContext) {
1821: return;
1822: }
1823:
1824: for (int i = 0; i < indent; i++) {
1825: writer.print(' ');
1826: }
1827: writer.print("<Resources");
1828: storeAttributes(writer, resources);
1829: writer.println("/>");
1830:
1831: }
1832:
1833: /**
1834: * Store the specified Server properties.
1835: *
1836: * @param writer PrintWriter to which we are storing
1837: * @param indent Number of spaces to indent this element
1838: * @param server Object to be stored
1839: *
1840: * @exception Exception if an exception occurs while storing
1841: */
1842: private void storeServer(PrintWriter writer, int indent,
1843: Server server) throws Exception {
1844:
1845: // Store the beginning of this element
1846: for (int i = 0; i < indent; i++) {
1847: writer.print(' ');
1848: }
1849: writer.print("<Server");
1850: storeAttributes(writer, server);
1851: writer.println(">");
1852:
1853: // Store nested <Listener> elements
1854: if (server instanceof Lifecycle) {
1855: LifecycleListener listeners[] = ((Lifecycle) server)
1856: .findLifecycleListeners();
1857: for (int i = 0; i < listeners.length; i++) {
1858: storeListener(writer, indent + 2, listeners[i]);
1859: }
1860: }
1861:
1862: // Store nested <GlobalNamingResources> element
1863: NamingResources globalNamingResources = server
1864: .getGlobalNamingResources();
1865: if (globalNamingResources != null) {
1866: for (int i = 0; i < indent + 2; i++) {
1867: writer.print(' ');
1868: }
1869: writer.println("<GlobalNamingResources>");
1870: storeNamingResources(writer, indent + 4,
1871: globalNamingResources);
1872: for (int i = 0; i < indent + 2; i++) {
1873: writer.print(' ');
1874: }
1875: writer.println("</GlobalNamingResources>");
1876: }
1877:
1878: // Store nested <Service> elements
1879: Service services[] = server.findServices();
1880: for (int i = 0; i < services.length; i++) {
1881: storeService(writer, indent + 2, services[i]);
1882: }
1883:
1884: // Store the ending of this element
1885: for (int i = 0; i < indent; i++) {
1886: writer.print(' ');
1887: }
1888: writer.println("</Server>");
1889:
1890: }
1891:
1892: /**
1893: * Store the specified Service properties.
1894: *
1895: * @param writer PrintWriter to which we are storing
1896: * @param indent Number of spaces to indent this element
1897: * @param server Object to be stored
1898: *
1899: * @exception Exception if an exception occurs while storing
1900: */
1901: private void storeService(PrintWriter writer, int indent,
1902: Service service) throws Exception {
1903:
1904: // Store the beginning of this element
1905: for (int i = 0; i < indent; i++) {
1906: writer.print(' ');
1907: }
1908: writer.print("<Service");
1909: storeAttributes(writer, service);
1910: writer.println(">");
1911:
1912: // Store nested <Connector> elements
1913: Connector connectors[] = service.findConnectors();
1914: for (int i = 0; i < connectors.length; i++) {
1915: storeConnector(writer, indent + 2, connectors[i]);
1916: }
1917:
1918: // Store nested <Engine> element (or other appropriate container)
1919: Container container = service.getContainer();
1920: if (container != null) {
1921: if (container instanceof Context) {
1922: storeContext(writer, indent + 2, (Context) container);
1923: } else if (container instanceof Engine) {
1924: storeEngine(writer, indent + 2, (Engine) container);
1925: } else if (container instanceof Host) {
1926: storeHost(writer, indent + 2, (Host) container);
1927: }
1928: }
1929:
1930: // Store nested <Listener> elements
1931: if (service instanceof Lifecycle) {
1932: LifecycleListener listeners[] = ((Lifecycle) service)
1933: .findLifecycleListeners();
1934: for (int i = 0; i < listeners.length; i++) {
1935: if (listeners[i].getClass().getName().equals(
1936: SERVER_LISTENER_CLASS_NAME)) {
1937: continue;
1938: }
1939: storeListener(writer, indent + 2, listeners[i]);
1940: }
1941: }
1942:
1943: // Store the ending of this element
1944: for (int i = 0; i < indent; i++) {
1945: writer.print(' ');
1946: }
1947: writer.println("</Service>");
1948:
1949: }
1950:
1951: /**
1952: * Store the specified Store properties.
1953: *
1954: * @param writer PrintWriter to which we are storing
1955: * @param indent Number of spaces to indent this element
1956: * @param store Object whose properties are being stored
1957: *
1958: * @exception Exception if an exception occurs while storing
1959: */
1960: private void storeStore(PrintWriter writer, int indent, Store store)
1961: throws Exception {
1962:
1963: for (int i = 0; i < indent; i++) {
1964: writer.print(' ');
1965: }
1966: writer.print("<Store");
1967: storeAttributes(writer, store);
1968: writer.println("/>");
1969:
1970: }
1971:
1972: /**
1973: * Store the specified Valve properties.
1974: *
1975: * @param writer PrintWriter to which we are storing
1976: * @param indent Number of spaces to indent this element
1977: * @param valve Object whose properties are being valved
1978: *
1979: * @exception Exception if an exception occurs while storing
1980: */
1981: private void storeValve(PrintWriter writer, int indent, Valve valve)
1982: throws Exception {
1983:
1984: if (isSkippable(valve.getClass().getName())) {
1985: return;
1986: }
1987:
1988: for (int i = 0; i < indent; i++) {
1989: writer.print(' ');
1990: }
1991: writer.print("<Valve");
1992: storeAttributes(writer, valve);
1993: writer.println("/>");
1994:
1995: }
1996:
1997: /**
1998: * Return <code>true</code> if the specified client and server addresses
1999: * are the same. This method works around a bug in the IBM 1.1.8 JVM on
2000: * Linux, where the address bytes are returned reversed in some
2001: * circumstances.
2002: *
2003: * @param server The server's InetAddress
2004: * @param client The client's InetAddress
2005: */
2006: private boolean isSameAddress(InetAddress server, InetAddress client) {
2007:
2008: // Compare the byte array versions of the two addresses
2009: byte serverAddr[] = server.getAddress();
2010: byte clientAddr[] = client.getAddress();
2011: if (serverAddr.length != clientAddr.length)
2012: return (false);
2013: boolean match = true;
2014: for (int i = 0; i < serverAddr.length; i++) {
2015: if (serverAddr[i] != clientAddr[i]) {
2016: match = false;
2017: break;
2018: }
2019: }
2020: if (match)
2021: return (true);
2022:
2023: // Compare the reversed form of the two addresses
2024: for (int i = 0; i < serverAddr.length; i++) {
2025: if (serverAddr[i] != clientAddr[(serverAddr.length - 1) - i])
2026: return (false);
2027: }
2028: return (true);
2029:
2030: }
2031:
2032: /**
2033: * Return true if naming should be used.
2034: */
2035: private boolean isUseNaming() {
2036: boolean useNaming = true;
2037: // Reading the "catalina.useNaming" environment variable
2038: String useNamingProperty = System
2039: .getProperty("catalina.useNaming");
2040: if ((useNamingProperty != null)
2041: && (useNamingProperty.equals("false"))) {
2042: useNaming = false;
2043: }
2044: return useNaming;
2045: }
2046:
2047: // ------------------------------------------------------ Lifecycle Methods
2048:
2049: /**
2050: * Add a LifecycleEvent listener to this component.
2051: *
2052: * @param listener The listener to add
2053: */
2054: public void addLifecycleListener(LifecycleListener listener) {
2055:
2056: lifecycle.addLifecycleListener(listener);
2057:
2058: }
2059:
2060: /**
2061: * Get the lifecycle listeners associated with this lifecycle. If this
2062: * Lifecycle has no listeners registered, a zero-length array is returned.
2063: */
2064: public LifecycleListener[] findLifecycleListeners() {
2065:
2066: return lifecycle.findLifecycleListeners();
2067:
2068: }
2069:
2070: /**
2071: * Remove a LifecycleEvent listener from this component.
2072: *
2073: * @param listener The listener to remove
2074: */
2075: public void removeLifecycleListener(LifecycleListener listener) {
2076:
2077: lifecycle.removeLifecycleListener(listener);
2078:
2079: }
2080:
2081: /**
2082: * Prepare for the beginning of active use of the public methods of this
2083: * component. This method should be called before any of the public
2084: * methods of this component are utilized. It should also send a
2085: * LifecycleEvent of type START_EVENT to any registered listeners.
2086: *
2087: * @exception LifecycleException if this component detects a fatal error
2088: * that prevents this component from being used
2089: */
2090: public void start() throws LifecycleException {
2091:
2092: // Validate and update our current component state
2093: if (started)
2094: throw new LifecycleException(sm
2095: .getString("standardServer.start.started"));
2096:
2097: // Notify our interested LifecycleListeners
2098: lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
2099:
2100: lifecycle.fireLifecycleEvent(START_EVENT, null);
2101: started = true;
2102:
2103: // Start our defined Services
2104: synchronized (services) {
2105: for (int i = 0; i < services.length; i++) {
2106: if (services[i] instanceof Lifecycle)
2107: ((Lifecycle) services[i]).start();
2108: }
2109: }
2110:
2111: // Notify our interested LifecycleListeners
2112: lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
2113:
2114: }
2115:
2116: /**
2117: * Gracefully terminate the active use of the public methods of this
2118: * component. This method should be the last one called on a given
2119: * instance of this component. It should also send a LifecycleEvent
2120: * of type STOP_EVENT to any registered listeners.
2121: *
2122: * @exception LifecycleException if this component detects a fatal error
2123: * that needs to be reported
2124: */
2125: public void stop() throws LifecycleException {
2126:
2127: // Validate and update our current component state
2128: if (!started)
2129: throw new LifecycleException(sm
2130: .getString("standardServer.stop.notStarted"));
2131:
2132: // Notify our interested LifecycleListeners
2133: lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
2134:
2135: lifecycle.fireLifecycleEvent(STOP_EVENT, null);
2136: started = false;
2137:
2138: // Stop our defined Services
2139: for (int i = 0; i < services.length; i++) {
2140: if (services[i] instanceof Lifecycle)
2141: ((Lifecycle) services[i]).stop();
2142: }
2143:
2144: // Notify our interested LifecycleListeners
2145: lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
2146:
2147: }
2148:
2149: /**
2150: * Invoke a pre-startup initialization. This is used to allow connectors
2151: * to bind to restricted ports under Unix operating environments.
2152: */
2153: public void initialize() throws LifecycleException {
2154: if (initialized)
2155: throw new LifecycleException(sm
2156: .getString("standardServer.initialize.initialized"));
2157: initialized = true;
2158:
2159: // Initialize our defined Services
2160: for (int i = 0; i < services.length; i++) {
2161: services[i].initialize();
2162: }
2163: }
2164:
2165: }
|