//----------------------------BEGIN LICENSE----------------------------
/*
* Willow : the Open Source WorkFlow Project
* Distributable under GNU LGPL license by gun.org
*
* Copyright (C) 2004-2010 huihoo.org
* Copyright (C) 2004-2010 ZosaTapo <dertyang@hotmail.com>
*
* ====================================================================
* Project Homepage : http://www.huihoo.org/willow
* Source Forge : http://sourceforge.net/projects/huihoo
* Mailing list : willow@lists.sourceforge.net
*/
//----------------------------END LICENSE-----------------------------
package org.huihoo.willow.startup;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.huihoo.willow.Container;
import org.huihoo.willow.Context;
import org.huihoo.willow.Engine;
import org.huihoo.willow.Globals;
import org.huihoo.willow.Lifecycle;
import org.huihoo.willow.LifecycleException;
import org.huihoo.willow.LifecycleListener;
import org.huihoo.willow.Loader;
import org.huihoo.willow.Logger;
import org.huihoo.willow.NamingServer;
import org.huihoo.willow.Provider;
import org.huihoo.willow.core.StandardContext;
import org.huihoo.willow.core.StandardEngine;
import org.huihoo.willow.core.StandardNamingServer;
import org.huihoo.willow.core.StandardService;
import org.huihoo.willow.loader.WorkflowLoader;
import org.huihoo.willow.logger.FileLogger;
import org.huihoo.willow.util.LifecycleSupport;
import org.huihoo.willow.util.StringManager;
import com.zosatapo.commons.util.IntrospectionUtils;
/**
* @author Administrator
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class Embedded extends StandardService implements Lifecycle
{
private static Log log = LogFactory.getLog(Embedded.class);
// ----------------------------------------------------------- Constructors
/**
* Construct a new instance of this class with default properties.
*/
public Embedded()
{
this(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)
{
super();
setLogger(logger);
}
// ----------------------------------------------------- Instance Variables
/**
* The set of Provider that have been deployed in this server.
*/
protected Provider providers[] = new Provider[0];
/**
* The debugging detail level for this component.
*/
protected int debug = 0;
/**
* The shared extensions class loader for this server.
*/
protected ClassLoader parentClassLoader = Willow.class.getClassLoader();
/**
* Descriptive information about this server implementation.
*/
protected final String info = "org.huihoo.willow.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 string manager for this package.
*/
protected static StringManager sm = StringManager.getManager(Constants.PACKAGE);
/**
* Has this component been started yet?
*/
protected boolean started = false;
/**
* Use await.
*/
protected boolean await = 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);
}
public void setAwait(boolean b)
{
await = b;
}
public boolean isAwait()
{
return await;
}
public void setHome(String s)
{
System.setProperty(Globals.PROPS_WILLOW_HOME, s);
}
public String getHome()
{
return System.getProperty(Globals.PROPS_WILLOW_HOME);
}
/**
* Set the shared extensions class loader.
*
* @param parentClassLoader The shared extensions class loader.
*/
public void setParentClassLoader(ClassLoader parentClassLoader)
{
this.parentClassLoader = parentClassLoader;
}
// --------------------------------------------------------- Public Methods
/**
* Add a new Provider to the set of defined Providers. The newly
* added Provider will be associated with the most recently added Engine.
*
* @param provider The provider to be added
*
* @exception IllegalStateException if no engines have been added yet
*/
public synchronized void addProvider(Provider provider)
{
log.debug("Adding Provider (" + provider.getInfo() + ")");
// Make sure we have a Container to send requests to
if (getEngine() == null)
{
throw new IllegalStateException(sm.getString("embedded.noEngines"));
}
// Configure this Provider as needed
provider.setEngine(getEngine());
// Add this Provider to our set of defined Providers
Provider results[] = new Provider[providers.length + 1];
for (int i = 0; i < providers.length; i++)
{
results[i] = providers[i];
}
results[providers.length] = provider;
providers = results;
// Start this Provider if necessary
if (started)
{
try
{
provider.initialize();
if (provider instanceof Lifecycle)
{
((Lifecycle) provider).start();
}
}
catch (LifecycleException e)
{
log.error("Providers.start", e);
}
}
}
/**
* Add a property change listener to this component.
*
* @param listener The listener to add
*/
public void addPropertyChangeListener(PropertyChangeListener listener)
{
support.addPropertyChangeListener(listener);
}
public Provider createProvider(InetAddress address, int port)
{
Provider provider = null;
String literal_IP = null;
if (address != null)
{
/*
* InetAddress.toString() returns a string of the form
* "<hostname>/<literal_IP>". Get the latter part, so that the
* address can be parsed (back) into an InetAddress using
* InetAddress.getByName().
*/
int index = address.toString().indexOf('/');
if (index != -1)
{
literal_IP = address.toString().substring(index + 1);
}
}
log.debug("Creating Provider for address='" + ((address == null) ? "ALL" : literal_IP) + "' port='" + port + "'");
try
{
Class clazz = Class.forName("org.huihoo.willow.core.StandardNamingprovider");
provider = (Provider) clazz.newInstance();
if (literal_IP != null)
{
IntrospectionUtils.setProperty(provider, "address", "" + literal_IP);
}
IntrospectionUtils.setProperty(provider, "port", "" + port);
}
catch (Exception e)
{
log.error("Couldn't create provider.");
}
return (provider);
}
public Context createContext(String name, String appBase)
{
log.debug("Creating context '" + name + "' with appBase '" + appBase + "'");
StandardContext context = new StandardContext();
context.setDebug(debug);
context.setName(name);
context.setAppBase(appBase);
ContextConfig config = new ContextConfig();
config.setDebug(debug);
((Lifecycle) context).addLifecycleListener(config);
return (context);
}
/**
* Create, configure, and return an Engine
*/
public Engine createEngine()
{
log.debug("Creating engine");
StandardEngine engine = new StandardEngine();
engine.setDebug(debug);
engine.setLogger(logger); // Inherited by all children
return (engine);
}
/**
* Create, configure, and return an NamingServer
*/
public NamingServer createNamingServer(InetAddress address, int port)
{
return createNamingServer(address, port, Globals.PROTOCOL_WORKFLOW_LIVE);
}
/**
* Create, configure, and return an NamingServer
*/
public NamingServer createNamingServer(InetAddress address, int port, String scheme)
{
return createNamingServer((address == null) ? null : address.toString(), port, scheme);
}
/**
* Create, configure, and return an NamingServer
*/
public NamingServer createNamingServer(String address, int port, String scheme)
{
log.debug("Creating namingServer");
StandardNamingServer namingServer = new StandardNamingServer();
namingServer.setDebug(debug);
namingServer.setPort(port);
namingServer.setScheme(scheme);
if (address != null)
{
/*
* InetAddress.toString() returns a string of the form
* "<hostname>/<literal_IP>". Get the latter part, so that the
* address can be parsed (back) into an InetAddress using
* InetAddress.getByName().
*/
int index = address.indexOf('/');
if (index != -1)
{
address = address.substring(index + 1);
}
}
if (address != null)
{
namingServer.setAddress(address);
}
log.debug(
"Creating connector for address='" + ((address == null) ? "ALL" : address.toString()) + "' port='" + port + "' scheme='" + scheme + "'");
return (namingServer);
}
/**
* Create and return a class loader manager that can be customized, and
* then attached to a Container, before it is started.
*
* @param parent ClassLoader that will be the parent of the one
* created by this Loader
*/
public Loader createLoader(ClassLoader parent)
{
log.debug("Creating Loader with parent class loader '" + parent + "'");
WorkflowLoader loader = new WorkflowLoader(parent);
return (loader);
}
/**
* Return descriptive information about this NamingServer implementation and
* the corresponding version number, in the format
* <code><description>/<version></code>.
*/
public String getInfo()
{
return (this.info);
}
/**
* Remove the specified Provider from the set of defined providers.
*
* @param provider The Provider to be removed
*/
public synchronized void removeProvider(Provider provider)
{
log.debug("Removing Provider (" + provider.getInfo() + ")");
// Is the specified Provider actually defined?
int j = -1;
for (int i = 0; i < providers.length; i++)
{
if (provider == providers[i])
{
j = i;
break;
}
}
if (j < 0)
return;
// Stop this Connector if necessary
if (provider instanceof Lifecycle)
{
log.debug(" Stopping this Provider");
try
{
((Lifecycle) provider).stop();
}
catch (LifecycleException e)
{
log.error("Provider.stop", e);
}
}
// Remove this Provider from our set of defined Providers
log.debug(" Removing this Provider");
int k = 0;
Provider results[] = new Provider[providers.length - 1];
for (int i = 0; i < providers.length; i++)
{
if (i != j)
{
results[k++] = providers[i];
}
}
providers = 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)
{
log.debug("Removing context[" + context.getName() + "]");
// Is this Context actually among those that are defined?
boolean found = false;
Container contexts[] = getEngine().findChildren();
for (int k = 0; k < contexts.length; k++)
{
if (context == (Context) contexts[k])
{
found = true;
break;
}
}
if (!found)
{
return;
}
// Remove this Context from the associated Host
log.debug(" Removing this Context");
context.getEngine().removeChild(context);
}
/**
* 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);
}
/**
* Get the lifecycle listeners associated with this lifecycle. If this
* Lifecycle has no listeners registered, a zero-length array is returned.
*/
public LifecycleListener[] findLifecycleListeners()
{
return lifecycle.findLifecycleListeners();
}
/**
* 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 LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
public void start() throws LifecycleException
{
log.info("Starting willow server");
// Validate the setup of our required system properties
initDirs();
// Validate and update our current component state
if (started)
{
throw new LifecycleException(sm.getString("embedded.alreadyStarted"));
}
lifecycle.fireLifecycleEvent(START_EVENT, null);
super.start();
started = true;
}
/**
* 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 LifecycleException if this component detects a fatal error
* that needs to be reported
*/
public void stop() throws LifecycleException
{
log.debug("Stopping embedded server");
// Validate and update our current component state
if (!started)
{
throw new LifecycleException(sm.getString("embedded.notStarted"));
}
lifecycle.fireLifecycleEvent(STOP_EVENT, null);
super.stop();
started = false;
}
// ------------------------------------------------------ Protected Methods
protected void initDirs()
{
String willowHome = System.getProperty(Globals.PROPS_WILLOW_HOME);
if (willowHome == null)
{
// Use IntrospectionUtils and guess the dir
willowHome = IntrospectionUtils.guessHome(Globals.PROPS_WILLOW_HOME, Globals.PROPS_WILLOW_JAR);
}
if (willowHome != null)
{
File home = new File(willowHome);
if (!home.isAbsolute())
{
try
{
willowHome = home.getCanonicalPath();
}
catch (IOException e)
{
willowHome = home.getAbsolutePath();
}
}
System.setProperty(Globals.PROPS_WILLOW_HOME, willowHome);
}
}
// -------------------------------------------------------- Private Methods
/**
* 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 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.getName();
FileLogger special = new FileLogger();
special.setPrefix(basename + "_log.");
special.setSuffix(".txt");
special.setTimestamp(true);
// Override the default logger for this context
context.setLogger(special);
}
}