blob: a2e6a3a30a060203c3991a6c55dc1f6323faefe9 [file]
/*
* $Id$
* $Revision$
* $Date$
*
* ================================================================================
* Copyright (c)
* All rechten voorbehouden.
*/
package nl.openedge.util.jetty;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import org.apache.commons.logging.LogFactory;
import org.mortbay.http.SocketListener;
import org.mortbay.jetty.Server;
import org.mortbay.util.Log;
import org.mortbay.util.MultiException;
import org.mortbay.util.OutputStreamLogSink;
/**
* Helperclass for Jetty.
*
* @author Eelco Hillenius
*/
public final class JettyHelper
{
/** confidential port. */
private static final int CONFIDENTIALPORT = 8443;
/** low resource persist time. */
private static final int LOW_RESOURCE_PERSIST_TIME = 2000;
/** maximum idle time. */
private static final int MAX_IDLE_TIME = 30000;
/** maximum threads. */
private static final int MAX_THREADS = 10;
/** Log. */
private static org.apache.commons.logging.Log log = LogFactory.getLog(JettyHelper.class);
/**
* Hidden utility constructor.
*/
private JettyHelper()
{
super();
}
/**
* Get an instance of Jetty using the config url to load the Jetty configuration from.
*
* @param config
* configuration url
* @param useJettyPlus
* Whether to use JettyPlus; if true, org.mortbay.jetty.plus.Server will be
* instantiated, if false, org.mortbay.jetty.Server will be instantiated
* @return an instance of Jetty (not started)
* @throws JettyHelperException when the instance could not be created
*/
public static Server getJettyServerInstance(URL config, boolean useJettyPlus)
throws JettyHelperException
{
Server server = null;
try
{
if (useJettyPlus)
{
// dynamically load the class to avoid dependency loading problems
Class clazz = Class.forName("org.mortbay.jetty.plus.Server");
Constructor constructor = clazz.getConstructor(new Class[]
{URL.class});
server = (Server) constructor.newInstance(new Object[]
{config});
}
else
{
server = new Server(config);
}
}
catch (ClassNotFoundException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (NoSuchMethodException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (InstantiationException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (IllegalAccessException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (InvocationTargetException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (IOException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
return server;
}
/**
* Get an instance of Jetty using the given arguments.
*
* @param port
* port to listener
* @param webappContextRoot
* (possibly relative) path to use as webapp context root
* @param contextPath
* webapp context path
* @param useJettyPlus
* whether to use JettyPlus
* @return jetty server instance
* @throws JettyHelperException when the instance could not be created
*/
public static Server getJettyServerInstance(int port, String webappContextRoot,
String contextPath, boolean useJettyPlus) throws JettyHelperException
{
Server server = null;
if (useJettyPlus)
{
// dynamically load the class to avoid dependency loading problem with the runner
try
{
Class clazz = Class.forName("org.mortbay.jetty.plus.Server");
server = (Server) clazz.newInstance();
}
catch (ClassNotFoundException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (InstantiationException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (IllegalAccessException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
}
else
{
server = new Server();
}
try
{
Log logInstance = Log.instance();
OutputStreamLogSink sink = new OutputStreamLogSink();
sink.start();
logInstance.add(sink);
SocketListener listener = new SocketListener();
listener.setPort(port);
listener.setMaxThreads(MAX_THREADS);
listener.setMaxIdleTimeMs(MAX_IDLE_TIME);
listener.setLowResourcePersistTimeMs(LOW_RESOURCE_PERSIST_TIME);
listener.setConfidentialPort(CONFIDENTIALPORT);
server.addListener(listener);
server.addWebApplication(contextPath, webappContextRoot);
}
catch (IllegalArgumentException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (IOException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
return server;
}
/**
* Start Jetty with arguments.
*
* @param port
* port to listen to http requests
* @param webappContextRoot
* the web application context root
* @param contextPath
* the context path (webapp name)
* @param useJettyPlus
* whether to use JettyPlus
* @return Server started instance of Jetty server
* @throws JettyHelperException when the instance could not be created
*/
public static Server startJetty(int port, String webappContextRoot, String contextPath,
boolean useJettyPlus) throws JettyHelperException
{
log.info("Starting Jetty with arguments {port == "
+ port + ", webappContextRoot == " + webappContextRoot + ", contextPath == "
+ contextPath + "}");
Server server = getJettyServerInstance(port, webappContextRoot, contextPath, useJettyPlus);
log.info(server + " created");
try
{
server.start();
}
catch (MultiException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
log.info("Jetty started");
return server;
}
/**
* Start Jetty with XML file.
*
* @param jettyConfig
* the url to the configuration file (can be a classpath location)
* @param useJettyPlus
* whether to use JettyPlus
* @return Server instance of Jetty server
* @throws JettyHelperException when the instance could not be created
*/
public static Server startJetty(String jettyConfig, boolean useJettyPlus)
throws JettyHelperException
{
URL jettyConfigURL = null;
Server server;
try
{
jettyConfigURL = URLHelper.convertToURL(jettyConfig, JettyStarterPrg.class);
log.info("Starting Jetty with configuration " + jettyConfigURL);
server = getJettyServerInstance(jettyConfigURL, useJettyPlus);
log.info(server + " created");
server.start();
log.info("Jetty started");
}
catch (MalformedURLException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (JettyHelperException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
catch (MultiException e)
{
log.error(e.getMessage(), e);
throw new JettyHelperException(e);
}
return server;
}
/**
* Ping remote Jetty server until success or maxTries.
*
* @param commKey
* auth key
* @param host
* host to ping
* @param monitorPort
* port admin monitor
* @param maxTries
* maximum number of tries
* @param sleepBetweenTries
* miliseconds to pause between tries
* @return boolean true if started succesfully, false otherwise
*/
public static boolean pingMonitorForServerStarted(String commKey, String host, int monitorPort,
int maxTries, long sleepBetweenTries)
{
boolean jettyStarted = false;
int tries = 0;
log.info("ping server on " + host + ":" + monitorPort);
while ((!jettyStarted) && ((tries++) < maxTries))
{
try
{
jettyStarted = pingMonitorForServerStarted(commKey, host, monitorPort);
}
catch (IOException e)
{
if (log.isDebugEnabled())
{
log.debug(e.getMessage(), e);
}
else
{
log.error(e.getMessage());
}
}
try
{
Thread.sleep(sleepBetweenTries);
}
catch (InterruptedException e)
{
log.warn(e);
}
}
return jettyStarted;
}
/**
* Ping remote Jetty server until success or maxTries.
*
* @param commKey
* auth key
* @param host
* host to ping
* @param monitorPort
* port admin monitor
* @return boolean true if started succesfully, false otherwise
* @throws IOException when the socket could not be created
*/
public static boolean pingMonitorForServerStarted(
String commKey, String host, int monitorPort) throws IOException
{
boolean jettyStarted = false;
Socket socket = null;
try
{
socket = new Socket(InetAddress.getByName(host), monitorPort);
OutputStream out = socket.getOutputStream();
out.write((commKey + "\r\nstatus\r\n").getBytes());
out.flush();
InputStream is = socket.getInputStream();
String response = readFromInputStream(is).trim();
if ("OK".equalsIgnoreCase(response))
{
jettyStarted = true;
log.info("Jetty has been started");
}
else if ("STARTING".equalsIgnoreCase(response))
{
log.info("Jetty is starting...");
}
else
{
String msg = "received an unknown socket result: " + response;
log.error(msg);
return false;
}
}
catch (IOException e)
{
throw e;
}
finally
{
if (socket != null)
{
socket.shutdownOutput();
socket.close();
}
}
return jettyStarted;
}
/**
* Stop Jetty with socket call to the monitor.
*
* @param commKey
* auth key
* @param host
* host of monitor
* @param monitorPort
* port of monitor
* @throws IOException when the socket could not be created
* @throws JettyMonitorException when the Jetty Monitor threw an exception
*/
public static void issueStopCommandToMonitor(
String commKey, String host, int monitorPort)
throws IOException, JettyMonitorException
{
Socket socket = null;
try
{
socket = new Socket(InetAddress.getByName(host), monitorPort);
OutputStream out = socket.getOutputStream();
out.write((commKey + "\r\nstop\r\n").getBytes());
out.flush();
InputStream is = socket.getInputStream();
String response = readFromInputStream(is).trim();
if ("ACK_STOP".equalsIgnoreCase(response))
{
log.info("Monitor acknowledged stop command");
}
else if ("".equalsIgnoreCase(response))
{
throw new JettyMonitorException("monitor did not respond with a valid ack");
}
else
{
throw new JettyMonitorException("unknown response from monitor: " + response);
}
}
catch (JettyMonitorException e)
{
log.error(e.getMessage(), e);
throw e;
}
finally
{
if (socket != null)
{
socket.shutdownOutput();
socket.close();
}
}
}
/**
* Read string from inputstream.
*
* @param inputStream
* inputstream
* @return String string from inputstream
* @throws IOException see except doc
*/
private static String readFromInputStream(InputStream inputStream) throws IOException
{
StringBuffer b = new StringBuffer("");
int i;
while ((i = inputStream.read()) != -1)
{
b.append((char) i);
}
return b.toString();
}
}