You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by cr...@locus.apache.org on 2000/07/28 01:05:35 UTC
cvs commit: jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/startup Embedded.java Authenticators.properties LocalStrings.properties
craigmcc 00/07/27 16:05:34
Modified: proposals/catalina/src/bin catalina.sh
proposals/catalina/src/share/org/apache/tomcat/startup
Authenticators.properties LocalStrings.properties
Added: proposals/catalina/src/share/org/apache/tomcat/startup
Embedded.java
Log:
Add a new startup class that represents one way to embed Catalina inside
another application. The main() method of this class is a simple unit
test that exercizes the various facilities. To run the unit test, build
Catalina as usual and execute (Unix script only has been updated):
cd $CATALINA_HOME
./bin/catalina.sh embedded
Revision Changes Path
1.12 +15 -1 jakarta-tomcat/proposals/catalina/src/bin/catalina.sh
Index: catalina.sh
===================================================================
RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/bin/catalina.sh,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -r1.11 -r1.12
--- catalina.sh 2000/07/15 03:15:33 1.11
+++ catalina.sh 2000/07/27 23:05:34 1.12
@@ -12,7 +12,7 @@
#
# JAVA_HOME Must point at your Java Development Kit installation.
#
-# $Id: catalina.sh,v 1.11 2000/07/15 03:15:33 craigmcc Exp $
+# $Id: catalina.sh,v 1.12 2000/07/27 23:05:34 craigmcc Exp $
# -----------------------------------------------------------------------------
@@ -71,6 +71,20 @@
-classpath $CP -Dcatalina.home=$CATALINA_HOME \
org.apache.tomcat.startup.Bootstrap "$@" start
popd
+
+elif [ "$1" = "embedded" ] ; then
+
+ # NOTE: Embedded does not currently use the boot class path for
+ # separating internal classes from the system class path
+ CP=$CP:$CATALINA_HOME/classes
+ for i in $CATALINA_HOME/lib/*.jar ; do
+ CP=$CP:$i
+ done
+
+ shift
+ java $CATALINA_OPTS -classpath $CP \
+ -Dcatalina.home=$CATALINA_HOME \
+ org.apache.tomcat.startup.Embedded "$@"
elif [ "$1" = "env" ] ; then
1.4 +3 -3 jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/startup/Authenticators.properties
Index: Authenticators.properties
===================================================================
RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/startup/Authenticators.properties,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- Authenticators.properties 2000/07/08 02:53:33 1.3
+++ Authenticators.properties 2000/07/27 23:05:34 1.4
@@ -1,3 +1,3 @@
-BASIC=org.apache.tomcat.security.HttpBasicValve
-DIGEST=org.apache.tomcat.security.HttpDigestValve
-FORM=org.apache.tomcat.security.HttpFormValve
+BASIC=org.apache.tomcat.authenticator.BasicAuthenticator
+DIGEST=org.apache.tomcat.authenticator.DigestAuthenticator
+FORM=org.apache.tomcat.authenticator.FormAuthenticator
1.9 +3 -0 jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/startup/LocalStrings.properties
Index: LocalStrings.properties
===================================================================
RCS file: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/startup/LocalStrings.properties,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- LocalStrings.properties 2000/05/21 23:02:37 1.8
+++ LocalStrings.properties 2000/07/27 23:05:34 1.9
@@ -16,6 +16,9 @@
contextConfig.defaultResources=Configuring default Resources
contextConfig.start=ContextConfig: Processing START
contextConfig.stop=ContextConfig: Processing STOP
+embedded.alreadyStarted=Embedded service has already been started
+embedded.noEngines=No engines have been defined yet
+embedded.notStarted=Embedded service has not yet been started
engineConfig.cce=Lifecycle event data object {0} is not an Engine
engineConfig.start=EngineConfig: Processing START
engineConfig.stop=EngineConfig: Processing STOP
1.1 jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/startup/Embedded.java
Index: Embedded.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat/proposals/catalina/src/share/org/apache/tomcat/startup/Embedded.java,v 1.1 2000/07/27 23:05:34 craigmcc Exp $
* $Revision: 1.1 $
* $Date: 2000/07/27 23:05:34 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.startup;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.net.InetAddress;
import java.util.Enumeration;
import java.util.Properties;
import org.apache.tomcat.Connector;
import org.apache.tomcat.Container;
import org.apache.tomcat.Context;
import org.apache.tomcat.Engine;
import org.apache.tomcat.Host;
import org.apache.tomcat.Lifecycle;
import org.apache.tomcat.LifecycleEvent;
import org.apache.tomcat.LifecycleException;
import org.apache.tomcat.LifecycleListener;
import org.apache.tomcat.Logger;
import org.apache.tomcat.Realm;
import org.apache.tomcat.connector.http.HttpConnector;
import org.apache.tomcat.core.StandardContext;
import org.apache.tomcat.core.StandardEngine;
import org.apache.tomcat.core.StandardHost;
import org.apache.tomcat.logger.FileLogger;
import org.apache.tomcat.logger.SystemOutLogger;
import org.apache.tomcat.util.LifecycleSupport;
import org.apache.tomcat.util.StringManager;
/**
* Convenience class to embed a Catalina servlet container environment
* inside another application. You must call the methods of this class in the
* following order to ensure correct operation.
*
* <ul>
* <li>Instantiate a new instance of this class.</li>
* <li>Set the relevant properties of this object itself. In particular,
* you will want to establish the default Logger to be used, as well
* as the default Realm if you are using container-managed security.</li>
* <li>Call <code>createEngine()</code> to create an Engine object, and then
* call its property setters as desired.</li>
* <li>Call <code>createHost()</code> to create at least one virtual Host
* associated with the newly created Engine, and then call its property
* setters as desired.</li>
* <li>Call <code>createContext()</code> to create at least one Context
* associated with each newly created Host, and then call its property
* setters as desired. You <strong>MUST</strong> create a Context with
* a pathname equal to a zero-length string.</li>
* <li>Call <code>addEngine()</code> to attach this Engine to the set of
* defined Engines for this object.</li>
* <li>Call <code>createConnector()</code> to create at least one TCP/IP
* connector, and then call its property setters as desired.</li>
* <li>Call <code>addConnector()</code> to attach this Connector to the set
* of defined Connectors for this object. The added Connector will use
* the most recently added Engine to process its received requests.</li>
* <li>Repeat the above series of steps as often as required (although there
* will typically be only one Engine instance created).</li>
* <li>Call <code>start()</code> to initiate normal operations of all the
* attached components.</li>
* </ul>
*
* After normal operations have begun, you can add and remove Connectors,
* Engines, Hosts, and Contexts on the fly. However, once you have removed
* a particular component, it must be thrown away -- you can create a new one
* with the same characteristics if you merely want to do a restart.
* <p>
* To initiate a normal shutdown, call the <code>stop()</code> method of
* this object.
* <p>
* <strong>IMPLEMENTATION NOTE</strong>: The <code>main()</code> method of
* this class is a simple example that exercizes the features of dynamically
* starting and stopping various components. You can execute this by executing
* the following steps (on a Unix platform):
* <pre>
* cd $CATALINA_HOME
* ./bin/catalina.sh embedded
* </pre>
*
* @author Craig R. McClanahan
* @version $Revision: 1.1 $ $Date: 2000/07/27 23:05:34 $
*/
public class Embedded implements Lifecycle {
// ----------------------------------------------------------- Constructors
/**
* Construct a new instance of this class with default properties.
*/
public Embedded() {
this(null, null);
}
/**
* Construct a new instance of this class with specified properties.
*
* @param logger Logger implementation to be inherited by all components
* (unless overridden further down the container hierarchy)
* @param realm Realm implementation to be inherited by all components
* (unless overridden further down the container hierarchy)
*/
public Embedded(Logger logger, Realm realm) {
super();
setLogger(logger);
setRealm(realm);
}
// ----------------------------------------------------- Instance Variables
/**
* The set of Connectors that have been deployed in this server.
*/
protected Connector connectors[] = new Connector[0];
/**
* The debugging detail level for this component.
*/
protected int debug = 0;
/**
* The set of Engines that have been deployed in this server. Normally
* there will only be one.
*/
protected Engine engines[] = new Engine[0];
/**
* Descriptive information about this server implementation.
*/
protected static final String info =
"org.apache.tomcat.startup.Embedded/1.0";
/**
* The lifecycle event support for this component.
*/
protected LifecycleSupport lifecycle = new LifecycleSupport(this);
/**
* The default logger to be used by this component itself. Unless this
* is overridden, log messages will be writted to standard output.
*/
protected Logger logger = null;
/**
* The default realm to be used by all containers associated with
* this compoennt.
*/
protected Realm realm = null;
/**
* The string manager for this package.
*/
protected static StringManager sm =
StringManager.getManager(Constants.Package);
/**
* Has this component been started yet?
*/
protected boolean started = false;
/**
* The property change support for this component.
*/
protected PropertyChangeSupport support = new PropertyChangeSupport(this);
// ------------------------------------------------------------- Properties
/**
* Return the debugging detail level for this component.
*/
public int getDebug() {
return (this.debug);
}
/**
* Set the debugging detail level for this component.
*
* @param debug The new debugging detail level
*/
public void setDebug(int debug) {
int oldDebug = this.debug;
this.debug = debug;
support.firePropertyChange("debug", new Integer(oldDebug),
new Integer(this.debug));
}
/**
* Return the Logger for this component.
*/
public Logger getLogger() {
return (this.logger);
}
/**
* Set the Logger for this component.
*
* @param logger The new logger
*/
public void setLogger(Logger logger) {
Logger oldLogger = this.logger;
this.logger = logger;
support.firePropertyChange("logger", oldLogger, this.logger);
}
/**
* Return the default Realm for our Containers.
*/
public Realm getRealm() {
return (this.realm);
}
/**
* Set the default Realm for our Containers.
*
* @param realm The new default realm
*/
public void setRealm(Realm realm) {
Realm oldRealm = this.realm;
this.realm = realm;
support.firePropertyChange("realm", oldRealm, this.realm);
}
// --------------------------------------------------------- Public Methods
/**
* Add a new Connector to the set of defined Connectors. The newly
* added Connector will be associated with the most recently added Engine.
*
* @param connector The connector to be added
*
* @exception IllegalStateException if no engines have been added yet
*/
public synchronized void addConnector(Connector connector) {
if (debug >= 1) {
if (connector instanceof HttpConnector) {
HttpConnector hc = (HttpConnector) connector;
logger.log("Adding connector for address '" +
((hc.getAddress() != null) ? "ALL" : hc.getAddress())
+ "' port='" + hc.getPort() + "'");
} else {
logger.log("Adding connector (" + connector.getInfo() + ")");
}
}
// Make sure we have a Container to send requests to
if (engines.length < 1)
throw new IllegalStateException
(sm.getString("embedded.noEngines"));
// Configure this Connector as needed
connector.setContainer(engines[engines.length - 1]);
// Add this Connector to our set of defined Connectors
Connector results[] = new Connector[connectors.length + 1];
for (int i = 0; i < connectors.length; i++)
results[i] = connectors[i];
results[connectors.length] = connector;
connectors = results;
// Start this Connector if necessary
if (started && (connector instanceof Lifecycle)) {
try {
((Lifecycle) connector).start();
} catch (LifecycleException e) {
logger.log("Connector.start", e);
}
}
}
/**
* Add a new Engine to the set of defined Engines.
*
* @param engine The engine to be added
*/
public synchronized void addEngine(Engine engine) {
if (debug >= 1)
logger.log("Adding engine (" + engine.getInfo() + ")");
// Add this Engine to our set of defined Engines
Engine results[] = new Engine[engines.length + 1];
for (int i = 0; i < engines.length; i++)
results[i] = engines[i];
results[engines.length] = engine;
engines = results;
// Start this Engine if necessary
if (started && (engine instanceof Lifecycle)) {
try {
((Lifecycle) engine).start();
} catch (LifecycleException e) {
logger.log("Engine.start", e);
}
}
}
/**
* Add a property change listener to this component.
*
* @param listener The listener to add
*/
public void addPropertyChangeListener(PropertyChangeListener listener) {
support.addPropertyChangeListener(listener);
}
/**
* Create, configure, and return a new TCP/IP socket connector
* based on the specified properties.
*
* @param address InetAddress to listen to, or <code>null</code>
* to listen on all address on this server
* @param port Port number to listen to
* @param secure Should this port be SSL-enabled?
* @param props Connection properties to be passed to the underlying
* socket factory, or <code>null</code> if no properties are required
*/
public Connector createConnector(InetAddress address, int port,
boolean secure, Properties props) {
if (debug >= 1)
logger.log("Creating connector for address='" +
((address == null) ? "ALL" : address.getHostAddress()) +
"' port='" + port + "' secure='" + secure + "'");
HttpConnector connector = new HttpConnector();
if (address != null)
connector.setAddress(address.getHostAddress());
connector.setDebug(debug);
connector.setPort(port);
if (secure)
connector.setSocketFactory
("org.apache.tomcat.net.SSLSocketFactory");
if (props != null) {
Enumeration names = props.keys();
while (names.hasMoreElements()) {
String name = (String) names.nextElement();
String value = props.getProperty(name);
connector.setParameter(name, value);
}
}
return (connector);
}
/**
* Create, configure, and return a Context that will process all
* HTTP requests received from one of the associated Connectors,
* and directed to the specified context path on the specified virtual
* host.
*
* @param host Host with which this Context will be associated
* @param path Context path of this application ("" for the default
* application for this host, must start with a slash otherwise)
* @param docBase Absolute pathname to the document base directory
* for this web application
*
* @exception IllegalArgumentException if an invalid parameter
* is specified
*/
public Context createContext(Host host, String path, String docBase) {
if (debug >= 1)
logger.log("Creating context for host='" + host.getName() +
"' path='" + path + "' docBase='" + docBase + "'");
StandardContext context = new StandardContext();
context.setDebug(debug);
context.setDocBase(docBase);
context.setPath(path);
ContextConfig config = new ContextConfig();
config.setDebug(debug);
((Lifecycle) context).addLifecycleListener(config);
host.addChild(context);
return (context);
}
/**
* Create, configure, and return an Engine that will process all
* HTTP requests received from one of the associated Connectors,
* based on the specified properties.
*/
public Engine createEngine() {
if (debug >= 1)
logger.log("Creating engine");
StandardEngine engine = new StandardEngine();
engine.setDebug(debug);
// Default host will be set to the first host added
engine.setLogger(logger); // Inherited by all children
engine.setRealm(realm); // Inherited by all children
return (engine);
}
/**
* Create, configure, and return a Host that will process all
* HTTP requests received from one of the associated Connectors,
* and directed to the specified virtual host. The very first
* Host associated with a particular Engine will become the
* default virtual host for that Engine.
*
* @param engine Engine with which this Host will be associated
* @param name Canonical name of this virtual host
* @param appBase Absolute pathname to the application base directory
* for this virtual host
*
* @exception IllegalArgumentException if an invalid parameter
* is specified
*/
public Host createHost(Engine engine, String name, String appBase) {
if (debug >= 1)
logger.log("Creating host for engine='" + engine.getName() +
"' name='" + name + "' appBase='" + appBase + "'");
StandardHost host = new StandardHost();
host.setAppBase(appBase);
host.setDebug(debug);
host.setName(name);
Container hosts[] = engine.findChildren();
if (hosts.length < 1) {
if (debug >= 1)
logger.log("Setting default host to '" + name + "'");
((StandardEngine) engine).setDefaultHost(name);
}
engine.addChild(host);
return (host);
}
/**
* Return descriptive information about this Server implementation and
* the corresponding version number, in the format
* <code><description>/<version></code>.
*/
public String getInfo() {
return (this.info);
}
/**
* Remove the specified Connector from the set of defined Connectors.
*
* @param connector The Connector to be removed
*/
public synchronized void removeConnector(Connector connector) {
if (debug >= 1) {
if (connector instanceof HttpConnector) {
HttpConnector hc = (HttpConnector) connector;
logger.log("Removing connector for address '" +
((hc.getAddress() == null) ? "ALL" : hc.getAddress())
+ "' port='" + hc.getPort() + "'");
} else {
logger.log("Removing connector (" + connector.getInfo() + ")");
}
}
// Is the specified Connector actually defined?
int j = -1;
for (int i = 0; i < connectors.length; i++) {
if (connector == connectors[i]) {
j = i;
break;
}
}
if (j < 0)
return;
// Stop this Connector if necessary
if (connector instanceof Lifecycle) {
if (debug >= 1)
logger.log(" Stopping this Connector");
try {
((Lifecycle) connector).stop();
} catch (LifecycleException e) {
logger.log("Connector.stop", e);
}
}
// Remove this Connector from our set of defined Connectors
if (debug >= 1)
logger.log(" Removing this Connector");
int k = 0;
Connector results[] = new Connector[connectors.length - 1];
for (int i = 0; i < connectors.length; i++) {
if (i != j)
results[k++] = connectors[i];
}
connectors = results;
}
/**
* Remove the specified Context from the set of defined Contexts for its
* associated Host. If this is the last Context for this Host, the Host
* will also be removed.
*
* @param context The Context to be removed
*/
public synchronized void removeContext(Context context) {
if (debug >= 1)
logger.log("Removing context[" + context.getPath() + "]");
// Is this Context actually among those that are defined?
boolean found = false;
for (int i = 0; i < engines.length; i++) {
Container hosts[] = engines[i].findChildren();
for (int j = 0; j < hosts.length; j++) {
Container contexts[] = hosts[j].findChildren();
for (int k = 0; k < contexts.length; k++) {
if (context == (Context) contexts[k]) {
found = true;
break;
}
}
if (found)
break;
}
if (found)
break;
}
if (!found)
return;
// Remove this Context from the associated Host
if (debug >= 1)
logger.log(" Removing this Context");
context.getParent().removeChild(context);
}
/**
* Remove the specified Engine from the set of defined Engines, along with
* all of its related Hosts and Contexts. All associated Connectors are
* also removed.
*
* @param engine The Engine to be removed
*/
public synchronized void removeEngine(Engine engine) {
if (debug >= 1)
logger.log("Removing engine (" + engine.getInfo() + ")");
// Is the specified Engine actually defined?
int j = -1;
for (int i = 0; i < engines.length; i++) {
if (engine == engines[i]) {
j = i;
break;
}
}
if (j < 0)
return;
// Remove any Connector that is using this Engine
if (debug >= 1)
logger.log(" Removing related Containers");
while (true) {
int n = -1;
for (int i = 0; i < connectors.length; i++) {
if (connectors[i].getContainer() == (Container) engine) {
n = i;
break;
}
}
if (n < 0)
break;
removeConnector(connectors[n]);
}
// Stop this Engine if necessary
if (engine instanceof Lifecycle) {
if (debug >= 1)
logger.log(" Stopping this Engine");
try {
((Lifecycle) engine).stop();
} catch (LifecycleException e) {
logger.log("Engine.stop", e);
}
}
// Remove this Engine from our set of defined Engines
if (debug >= 1)
logger.log(" Removing this Engine");
int k = 0;
Engine results[] = new Engine[engines.length - 1];
for (int i = 0; i < engines.length; i++) {
if (i != j)
results[k++] = engines[i];
}
engines = results;
}
/**
* Remove the specified Host, along with all of its related Contexts,
* from the set of defined Hosts for its associated Engine. If this is
* the last Host for this Engine, the Engine will also be removed.
*
* @param host The Host to be removed
*/
public synchronized void removeHost(Host host) {
if (debug >= 1)
logger.log("Removing host[" + host.getName() + "]");
// Is this Host actually among those that are defined?
boolean found = false;
for (int i = 0; i < engines.length; i++) {
Container hosts[] = engines[i].findChildren();
for (int j = 0; j < hosts.length; j++) {
if (host == (Host) hosts[j]) {
found = true;
break;
}
}
if (found)
break;
}
if (!found)
return;
// Remove this Host from the associated Engine
if (debug >= 1)
logger.log(" Removing this Host");
host.getParent().removeChild(host);
}
/**
* Remove a property change listener from this component.
*
* @param listener The listener to remove
*/
public void removePropertyChangeListener(PropertyChangeListener listener) {
support.removePropertyChangeListener(listener);
}
// ------------------------------------------------------ Lifecycle Methods
/**
* Add a lifecycle event listener to this component.
*
* @param listener The listener to add
*/
public void addLifecycleListener(LifecycleListener listener) {
lifecycle.addLifecycleListener(listener);
}
/**
* Remove a lifecycle event listener from this component.
*
* @param listener The listener to remove
*/
public void removeLifecycleListener(LifecycleListener listener) {
lifecycle.removeLifecycleListener(listener);
}
/**
* Prepare for the beginning of active use of the public methods of this
* component. This method should be called after <code>configure()</code>,
* and before any of the public methods of the component are utilized.
*
* @exception IllegalStateException if this component has already been
* started
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
public void start() throws LifecycleException {
if (debug >= 1)
logger.log("Starting embedded server");
// Validate and update our current component state
if (started)
throw new LifecycleException
(sm.getString("embedded.alreadyStarted"));
lifecycle.fireLifecycleEvent(START_EVENT, null);
started = true;
// Start our defined Engines first
for (int i = 0; i < engines.length; i++) {
if (engines[i] instanceof Lifecycle)
((Lifecycle) engines[i]).start();
}
// Start our defined Connectors second
for (int i = 0; i < connectors.length; i++) {
if (connectors[i] instanceof Lifecycle)
((Lifecycle) connectors[i]).start();
}
}
/**
* Gracefully terminate the active use of the public methods of this
* component. This method should be the last one called on a given
* instance of this component.
*
* @exception IllegalStateException if this component has not been started
* @exception LifecycleException if this component detects a fatal error
* that needs to be reported
*/
public void stop() throws LifecycleException {
if (debug >= 1)
logger.log("Stopping embedded server");
// Validate and update our current component state
if (!started)
throw new LifecycleException
(sm.getString("embedded.notStarted"));
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
started = false;
// Stop our defined Connectors first
for (int i = 0; i < connectors.length; i++) {
if (connectors[i] instanceof Lifecycle)
((Lifecycle) connectors[i]).stop();
}
// Stop our defined Engines second
for (int i = 0; i < engines.length; i++) {
if (engines[i] instanceof Lifecycle)
((Lifecycle) engines[i]).stop();
}
}
// ------------------------------------------------------ Protected Methods
// -------------------------------------------------------- Private Methods
// ----------------------------------------------------------- Main Program
/**
* This main program is a unit test to exercize the various methods of
* the Embedded class. It can be used as an example of the type of code
* that would be used in a real environment.
*
* @param args The command line arguments
*/
public static void main(String args[]) {
Embedded embedded = new Embedded();
embedded.setDebug(5);
embedded.setLogger(new SystemOutLogger());
String home = System.getProperty("catalina.home");
// Start up this embedded server (to prove we can dynamically
// add and remove containers and connectors later)
try {
embedded.start();
} catch (LifecycleException e) {
System.err.println("start: " + e.toString());
e.printStackTrace();
}
// Assemble and install a very basic container hierarchy
// that simulates a portion of the one configured in server.xml
// by default
Engine engine = embedded.createEngine();
Host host = embedded.createHost(engine, "localhost",
home + "/webapps");
Context root = embedded.createContext(host, "",
home + "/webapps/ROOT");
Context examples = embedded.createContext(host, "/examples",
home + "/webapps/examples");
customize(examples); // Special customization for this web-app
embedded.addEngine(engine);
// Assemble and install a non-secure connector for port 8080
Connector connector =
embedded.createConnector(null, 8080, false, null);
embedded.addConnector(connector);
// Pause for a while to allow brief testing
// (In reality this would last until the enclosing application
// needs to be shut down)
try {
Thread.sleep(2 * 60 * 1000L); // Two minutes
} catch (InterruptedException e) {
;
}
// Remove the examples context dynamically
embedded.removeContext(examples);
// Remove the engine (which should trigger removing the connector)
embedded.removeEngine(engine);
// Shut down this embedded server (should have nothing left to do)
try {
embedded.stop();
} catch (LifecycleException e) {
System.err.println("stop: " + e.toString());
e.printStackTrace();
}
}
/**
* Customize the specified context to have its own log file instead of
* inheriting the default one. This is just an example of what you can
* do; pretty much anything (such as installing special Valves) can
* be done prior to calling <code>start()</code>.
*
* @param context Context to receive a specialized logger
*/
private static void customize(Context context) {
// Create a customized file logger for this context
String basename = context.getPath();
if (basename.length() < 1)
basename = "ROOT";
else
basename = basename.substring(1);
FileLogger special = new FileLogger();
special.setPrefix(context.getParent().getName() + "_" +
basename + "_log.");
special.setSuffix(".txt");
special.setTimestamp(true);
// Override the default logger for this context
context.setLogger(special);
}
}