//----------------------------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.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.Rule;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.huihoo.willow.Container;
import org.huihoo.willow.Globals;
import org.huihoo.willow.Lifecycle;
import org.huihoo.willow.LifecycleException;
import org.huihoo.willow.Server;
import org.huihoo.willow.core.StandardServer;
import org.huihoo.willow.store.DatabaseLoader;
import org.huihoo.willow.util.WillowDigester;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import com.zosatapo.commons.util.log.SystemLogHandler;
import org.huihoo.workflow.impl.xpdl.parser.xmlrules.SetAllPropertiesRule;
/**
* @author zosatapo
*
* To change the template for this generated type comment go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
public class Willow extends Embedded
{
private static Log log = LogFactory.getLog(Willow.class);
// ----------------------------------------------------- Instance Variables
/**
* Pathname to the server configuration file.
*/
protected String configFile = "conf/server.xml";
/**
* The server component we are starting or stopping
*/
protected Server server = null;
/**
* Are we starting a new server?
*/
protected boolean starting = false;
/**
* Are we stopping an existing server?
*/
protected boolean stopping = false;
// ------------------------------------------------------------- Properties
public void setConfig(String file)
{
configFile = file;
}
public void setConfigFile(String file)
{
configFile = file;
}
public String getConfigFile()
{
return configFile;
}
/**
* Set the server instance we are configuring.
*
* @param server The new server
*/
public void setServer(Server server)
{
this.server = server;
}
// ----------------------------------------------------------- Main Program
/**
* The application main program.
*
* @param args Command line arguments
*/
public static void main(String args[])
{
(new Willow()).process(args);
}
/**
* The instance main program.
*
* @param args Command line arguments
*/
public void process(String args[])
{
setAwait(true);
setHome();
try
{
if (arguments(args))
{
if (starting)
{
load(args);
start();
}
else if (stopping)
{
stopServer();
}
}
}
catch (Exception e)
{
e.printStackTrace(System.out);
}
}
// ------------------------------------------------------ Protected Methods
/**
* Process the specified command line arguments, and return
* <code>true</code> if we should continue processing; otherwise
* return <code>false</code>.
*
* @param args Command line arguments to process
*/
protected boolean arguments(String args[])
{
boolean isConfig = false;
if (args.length < 1)
{
usage();
return (false);
}
for (int i = 0; i < args.length; i++)
{
if (isConfig)
{
configFile = args[i];
isConfig = false;
}
else if (args[i].equals("-config"))
{
isConfig = true;
}
else if (args[i].equals("-help"))
{
usage();
return (false);
}
else if (args[i].equals("start"))
{
starting = true;
stopping = false;
}
else if (args[i].equals("stop"))
{
starting = false;
stopping = true;
}
else
{
usage();
return (false);
}
}
return (true);
}
/**
* Return a File object representing our configuration file.
*/
protected File configFile()
{
File file = new File(configFile);
if (!file.isAbsolute())
{
file = new File(System.getProperty(Globals.PROPS_WILLOW_HOME), configFile);
}
return (file);
}
/**
* Create and configure the Digester we will be using for startup.
*/
protected Digester createStartDigester()
{
long t1 = System.currentTimeMillis();
// Initialize the digester
Digester digester = new WillowDigester();
if (debug > 0)
{
digester.setDebug(debug);
}
digester.setValidating(false);
digester.setClassLoader(StandardServer.class.getClassLoader());
// Configure the actions we will be using
digester.addObjectCreate("Server", "org.huihoo.willow.core.StandardServer", "className");
digester.addSetProperties("Server");
digester.addSetNext("Server", "setServer", "org.huihoo.willow.Server");
digester.addObjectCreate("Server/Listener", null, // MUST be specified in the element
"className");
digester.addSetProperties("Server/Listener");
digester.addSetNext(
"Server/Listener",
"addLifecycleListener",
"org.huihoo.willow.LifecycleListener");
digester.addObjectCreate(
"Server/Service",
"org.huihoo.willow.core.StandardService",
"className");
digester.addSetProperties("Server/Service");
digester.addSetNext("Server/Service", "addService", "org.huihoo.willow.Service");
digester.addObjectCreate("Server/Service/Listener", null, // MUST be specified in the element
"className");
digester.addSetProperties("Server/Service/Listener");
digester.addSetNext(
"Server/Service/Listener",
"addLifecycleListener",
"org.huihoo.willow.LifecycleListener");
digester.addObjectCreate(
"Server/Service/NamingServer",
"org.huihoo.willow.core.StandardNamingServer",
"className");
digester.addRule("Server/Service/NamingServer", new SetAllPropertiesRule());
digester.addSetNext(
"Server/Service/NamingServer",
"setNamingServer",
"org.huihoo.willow.NamingServer");
// Add RuleSets for nested elements
digester.addRuleSet(new EngineRuleSet("Server/Service/"));
digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/"));
// When the 'engine' is found, set the parentClassLoader.
digester.addRule(
"Server/Service/Engine",
new SetParentClassLoaderRule(digester, parentClassLoader));
long t2 = System.currentTimeMillis();
log.debug("Digester for server.xml created " + (t2 - t1));
return (digester);
}
/**
* Create and configure the Digester we will be using for shutdown.
*/
protected Digester createStopDigester()
{
// Initialize the digester
Digester digester = new Digester();
if (debug > 0)
{
digester.setDebug(debug);
}
// Configure the rules we need for shutting down
digester.addObjectCreate("Server", "org.huihoo.willow.core.StandardServer", "className");
digester.addSetProperties("Server");
digester.addSetNext("Server", "setServer", "org.huihoo.willow.Server");
return (digester);
}
public void stopServer()
{
if (server == null)
{
// Create and execute our Digester
Digester digester = createStopDigester();
digester.setClassLoader(Thread.currentThread().getContextClassLoader());
File file = configFile();
try
{
InputSource is = new InputSource("file://" + file.getAbsolutePath());
FileInputStream fis = new FileInputStream(file);
is.setByteStream(fis);
digester.push(this);
digester.parse(is);
fis.close();
}
catch (Exception e)
{
System.out.println("Willow.stop: " + e);
e.printStackTrace(System.out);
System.exit(1);
}
}
// Stop the existing server
try
{
Socket socket = new Socket("127.0.0.1", server.getPort());
OutputStream stream = socket.getOutputStream();
String shutdown = server.getShutdown();
for (int i = 0; i < shutdown.length(); i++)
stream.write(shutdown.charAt(i));
stream.flush();
stream.close();
socket.close();
}
catch (IOException e)
{
System.out.println("Willow.stop: " + e);
e.printStackTrace(System.out);
System.exit(1);
}
}
/**
* Set the <code>catalina.home</code> System property to the current
* working directory if it has not been set.
* @deprecated Use initDirs()
*/
public void setHome()
{
initDirs();
}
/**
* Start a new server instance.
*/
public void load()
{
initDirs();
// Create and execute our Digester
Digester digester = createStartDigester();
long t1 = System.currentTimeMillis();
InputSource inputSource = null;
InputStream inputStream = null;
try
{
File file = configFile();
inputStream = new FileInputStream(file);
inputSource = new InputSource("file://" + file.getAbsolutePath());
log.info("Server configuration :"+file.getAbsolutePath());
}
catch (Exception e)
{
;
}
if (inputStream == null)
{
try
{
inputStream = getClass().getClassLoader().getResourceAsStream(getConfigFile());
inputSource =
new InputSource(getClass().getClassLoader().getResource(getConfigFile()).toString());
}
catch (Exception e)
{
;
}
}
if (inputStream == null)
{
System.out.println("Can't load server.xml");
return;
}
try
{
inputSource.setByteStream(inputStream);
digester.push(this);
digester.parse(inputSource);
inputStream.close();
}
catch (Exception e)
{
System.out.println("Willow.start: " + e);
e.printStackTrace(System.out);
return;
}
// Replace System.out and System.err with a custom PrintStream
SystemLogHandler systemlog = new SystemLogHandler(System.out);
System.setOut(systemlog);
System.setErr(systemlog);
DatabaseLoader.loadOnStartup(Constants.DatabaseXml);
long t2 = System.currentTimeMillis();
log.info("Initialization processed in " + (t2 - t1) + " ms");
}
/*
* Load using arguments
*/
public void load(String args[])
{
setHome();
try
{
if (arguments(args))
{
load();
}
}
catch (Exception e)
{
e.printStackTrace(System.out);
}
}
/**
* Start a new server instance.
*/
public void start()
{
if (server == null)
{
load();
}
long t1 = System.currentTimeMillis();
// Start the new server
if (server instanceof Lifecycle)
{
try
{
((Lifecycle) server).start();
}
catch (LifecycleException e)
{
log.error("Willow.start: ", e);
}
}
//
long t2 = System.currentTimeMillis();
log.info("Server startup in " + (t2 - t1) + " ms");
if (await)
{
await();
stop();
}
}
/**
* Stop an existing server instance.
*/
public void stop()
{
// Shut down the server
if (server instanceof Lifecycle)
{
try
{
((Lifecycle) server).stop();
}
catch (LifecycleException e)
{
log.error("Willow.stop", e);
}
}
System.exit(-1);
}
/**
* Await and shutdown.
*/
public void await()
{
server.await();
}
/**
* Print usage information for this application.
*/
protected void usage()
{
System.out.println(
"usage: java org.huihoo.willow.startup.Willow"
+ " [ -config {pathname} ] [ -debug ]"
+ " { start | stop }");
}
// ------------------------------------------------------------ Private Classes
/**
* Rule that sets the parent class loader for the top object on the stack,
* which must be a <code>Container</code>.
*/
final class SetParentClassLoaderRule extends Rule
{
public SetParentClassLoaderRule(Digester digester, ClassLoader parentClassLoader)
{
super(digester);
this.parentClassLoader = parentClassLoader;
}
ClassLoader parentClassLoader = null;
public void begin(Attributes attributes) throws Exception
{
if (digester.getDebug() >= 1)
{
digester.log("Setting parent class loader");
}
Container top = (Container) digester.peek();
top.setParentClassLoader(parentClassLoader);
}
}
}