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