Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jetty-runner/pom.xml17
-rw-r--r--jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java424
-rw-r--r--jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java282
-rw-r--r--pom.xml2
4 files changed, 468 insertions, 257 deletions
diff --git a/jetty-runner/pom.xml b/jetty-runner/pom.xml
index 3cf147f030..bee31e217e 100644
--- a/jetty-runner/pom.xml
+++ b/jetty-runner/pom.xml
@@ -82,6 +82,16 @@
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-jaas</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty.websocket</groupId>
+ <artifactId>websocket-server</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jndi</artifactId>
<version>${project.version}</version>
</dependency>
@@ -89,13 +99,6 @@
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jsp</artifactId>
<version>${project.version}</version>
- <exclusions>
- <!-- tlds must be found in jar on path, not inside runner jar -->
- <exclusion>
- <groupId>org.eclipse.jetty.orbit</groupId>
- <artifactId>org.apache.taglibs.standard.glassfish</artifactId>
- </exclusion>
- </exclusions>
</dependency>
</dependencies>
</project>
diff --git a/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java b/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java
index 19883158d3..95d46ff2ef 100644
--- a/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java
+++ b/jetty-runner/src/main/java/org/eclipse/jetty/runner/Runner.java
@@ -18,40 +18,33 @@
package org.eclipse.jetty.runner;
-import java.io.File;
-import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
+import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Properties;
-import java.util.Random;
-import javax.transaction.UserTransaction;
-
-import org.eclipse.jetty.util.security.Constraint;
-import org.eclipse.jetty.plus.jndi.Transaction;
+import org.eclipse.jetty.security.ConstraintMapping;
+import org.eclipse.jetty.security.ConstraintSecurityHandler;
+import org.eclipse.jetty.security.HashLoginService;
+import org.eclipse.jetty.security.authentication.BasicAuthenticator;
+import org.eclipse.jetty.server.AbstractConnector;
import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.ConnectorStatistics;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.NCSARequestLog;
import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.handler.StatisticsHandler;
-import org.eclipse.jetty.server.SelectChannelConnector;
import org.eclipse.jetty.server.session.SessionHandler;
-import org.eclipse.jetty.security.ConstraintMapping;
-import org.eclipse.jetty.security.ConstraintSecurityHandler;
-import org.eclipse.jetty.security.HashLoginService;
-import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.StatisticsServlet;
@@ -59,11 +52,18 @@ import org.eclipse.jetty.util.RolloverFileOutputStream;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
+import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
+/**
+ * Runner
+ *
+ * Combine jetty classes into a single executable jar and run webapps based on the args to it.
+ *
+ */
public class Runner
{
private static final Logger LOG = Log.getLogger(Runner.class);
@@ -79,36 +79,99 @@ public class Runner
org.eclipse.jetty.webapp.JettyWebXmlConfiguration.class.getCanonicalName(),
org.eclipse.jetty.webapp.TagLibConfiguration.class.getCanonicalName()
};
+ public static final String __containerIncludeJarPattern = ".*/jetty-runner-[^/]*\\.jar$";
+ public static final String __defaultContextPath = "/";
+ public static final int __defaultPort = 8080;
protected Server _server;
protected Monitor _monitor;
protected URLClassLoader _classLoader;
- protected List<URL> _classpath=new ArrayList<URL>();
+ protected Classpath _classpath = new Classpath();
protected ContextHandlerCollection _contexts;
protected RequestLogHandler _logHandler;
protected String _logFile;
- protected String _configFile;
- protected UserTransaction _ut;
- protected String _utId;
- protected String _txMgrPropertiesFile;
- protected Random _random = new Random();
- protected boolean _isTxServiceAvailable=false;
- protected boolean _enableStatsGathering=false;
+ protected ArrayList<String> _configFiles;
+ protected boolean _enableStats=false;
protected String _statsPropFile;
- protected boolean _clusteredSessions=true;
+
+ /**
+ * Classpath
+ *
+ *
+ */
+ public class Classpath
+ {
+ private List<URL> _classpath = new ArrayList<URL>();
+
+ public void addJars (Resource lib) throws MalformedURLException, IOException
+ {
+ if (lib == null || !lib.exists())
+ throw new IllegalStateException ("No such lib: "+lib);
+
+ String[] list = lib.list();
+ if (list==null)
+ return;
+
+ for (String path : list)
+ {
+ if (".".equals(path) || "..".equals(path))
+ continue;
+
+ Resource item = lib.addPath(path);
+
+ if (item.isDirectory())
+ addJars(item);
+ else
+ {
+ if (path.toLowerCase().endsWith(".jar") ||
+ path.toLowerCase().endsWith(".zip"))
+ {
+ URL url = item.getURL();
+ _classpath.add(url);
+ }
+ }
+ }
+ }
+
+
+ public void addPath (Resource path)
+ {
+ if (path == null || !path.exists())
+ throw new IllegalStateException ("No such path: "+path);
+ _classpath.add(path.getURL());
+ }
+
+
+ public URL[] asArray ()
+ {
+ return _classpath.toArray(new URL[_classpath.size()]);
+ }
+ }
+
+
+
+
+ /**
+ *
+ */
public Runner()
{
}
+ /**
+ * Generate helpful usage message and exit
+ *
+ * @param error
+ */
public void usage(String error)
{
if (error!=null)
System.err.println("ERROR: "+error);
- System.err.println("Usage: java [-DDEBUG] [-Djetty.home=dir] -jar jetty-runner.jar [--help|--version] [ server opts] [[ context opts] context ...] ");
+ System.err.println("Usage: java [-Djetty.home=dir] -jar jetty-runner.jar [--help|--version] [ server opts] [[ context opts] context ...] ");
System.err.println("Server Options:");
System.err.println(" --version - display version and exit");
System.err.println(" --log file - request log filename (with optional 'yyyy_mm_dd' wildcard");
@@ -117,48 +180,59 @@ public class Runner
System.err.println(" --stop-port n - port to listen for stop command");
System.err.println(" --stop-key n - security string for stop command (required if --stop-port is present)");
System.err.println(" --jar file - a jar to be added to the classloader");
- System.err.println(" --jdbc classname properties jndiname - classname of XADataSource or driver; properties string; name to register in jndi");
System.err.println(" --lib dir - a directory of jars to be added to the classloader");
System.err.println(" --classes dir - a directory of classes to be added to the classloader");
- System.err.println(" --txFile - override properties file for Atomikos");
System.err.println(" --stats [unsecure|realm.properties] - enable stats gathering servlet context");
- System.err.println(" --config file - a jetty xml config file to use instead of command line options");
+ System.err.println(" [--config file]*n - each --config parameter specifies the name of a jetty xml config file to apply (in the order defined)");
System.err.println("Context Options:");
- System.err.println(" --path /path - context path (default /)");
- System.err.println(" context - WAR file, web app dir or context.xml file");
+ System.err.println(" --path /path - context path (default /)");
+ System.err.println(" context - WAR file, web app dir or context xml file");
System.exit(1);
}
+
+ /**
+ * Generate version message and exit
+ */
+ public void version ()
+ {
+ System.err.println("org.eclipse.jetty.runner.Runner: "+Server.getVersion());
+ System.exit(1);
+ }
+
+
+
+ /**
+ * Configure a jetty instance and deploy the webapps presented as args
+ *
+ * @param args
+ * @throws Exception
+ */
public void configure(String[] args) throws Exception
{
// handle classpath bits first so we can initialize the log mechanism.
for (int i=0;i<args.length;i++)
{
- if ("--version".equals(args[i]))
- {
-
- }
-
if ("--lib".equals(args[i]))
{
Resource lib = Resource.newResource(args[++i]);
if (!lib.exists() || !lib.isDirectory())
usage("No such lib directory "+lib);
- expandJars(lib);
+ _classpath.addJars(lib);
}
else if ("--jar".equals(args[i]))
{
Resource jar = Resource.newResource(args[++i]);
if (!jar.exists() || jar.isDirectory())
usage("No such jar "+jar);
- _classpath.add(jar.getURL());
+ _classpath.addPath(jar);
}
else if ("--classes".equals(args[i]))
{
Resource classes = Resource.newResource(args[++i]);
if (!classes.exists() || !classes.isDirectory())
usage("No such classes directory "+classes);
- _classpath.add(classes.getURL());
+ _classpath.addPath(classes);
}
else if (args[i].startsWith("--"))
i++;
@@ -166,28 +240,15 @@ public class Runner
initClassLoader();
- try
- {
- if (Thread.currentThread().getContextClassLoader().loadClass("com.atomikos.icatch.jta.UserTransactionImp")!=null)
- _isTxServiceAvailable=true;
- }
- catch (ClassNotFoundException e)
- {
- _isTxServiceAvailable=false;
- }
- if (System.getProperties().containsKey("DEBUG"))
- Log.getLog().setDebugEnabled(true);
-
LOG.info("Runner");
LOG.debug("Runner classpath {}",_classpath);
- String contextPath="/";
- boolean contextPathSet=false;
- int port=8080;
- int stopPort=0;
- String stopKey=null;
+ String contextPath = __defaultContextPath;
+ boolean contextPathSet = false;
+ int port = __defaultPort;
+ int stopPort = 0;
+ String stopKey = null;
- boolean transactionManagerProcessed = false;
boolean runnerServerInitialized = false;
for (int i=0;i<args.length;i++)
@@ -215,7 +276,9 @@ public class Runner
}
else if ("--config".equals(args[i]))
{
- _configFile=args[++i];
+ if (_configFiles == null)
+ _configFiles = new ArrayList<String>();
+ _configFiles.add(args[++i]);
}
else if ("--lib".equals(args[i]))
{
@@ -231,40 +294,28 @@ public class Runner
}
else if ("--stats".equals( args[i]))
{
- _enableStatsGathering = true;
+ _enableStats = true;
_statsPropFile = args[++i];
_statsPropFile = ("unsecure".equalsIgnoreCase(_statsPropFile)?null:_statsPropFile);
}
- else if ("--txFile".equals(args[i]))
- {
- _txMgrPropertiesFile=args[++i];
- }
- else if ("--jdbc".equals(args[i]))
- {
- i=configJDBC(args,i);
- }
else // process contexts
{
- if ( !transactionManagerProcessed ) // to be executed once upon starting to process contexts
- {
- processTransactionManagement();
- transactionManagerProcessed = true;
- }
-
if (!runnerServerInitialized) // log handlers not registered, server maybe not created, etc
{
if (_server == null) // server not initialized yet
{
// build the server
_server = new Server();
-
}
- //apply a config file if there is one
- if (_configFile != null)
+ //apply jetty config files if there are any
+ if (_configFiles != null)
{
- XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.newResource(_configFile).getURL());
- xmlConfiguration.configure(_server);
+ for (String cfg:_configFiles)
+ {
+ XmlConfiguration xmlConfiguration = new XmlConfiguration(Resource.newResource(cfg).getURL());
+ xmlConfiguration.configure(_server);
+ }
}
//check that everything got configured, and if not, make the handlers
@@ -284,14 +335,19 @@ public class Runner
}
-
- if (_enableStatsGathering)
+ if (_enableStats)
{
//if no stats handler already configured
if (handlers.getChildHandlerByClass(StatisticsHandler.class) == null)
{
StatisticsHandler statsHandler = new StatisticsHandler();
- prependHandler(statsHandler,handlers);
+
+
+ Handler oldHandler = _server.getHandler();
+ statsHandler.setHandler(oldHandler);
+ _server.setHandler(statsHandler);
+
+
ServletContextHandler statsContext = new ServletContextHandler(_contexts, "/stats");
statsContext.addServlet(new ServletHolder(new StatisticsServlet()), "/");
statsContext.setSessionHandler(new SessionHandler());
@@ -335,19 +391,19 @@ public class Runner
Connector[] connectors = _server.getConnectors();
if (connectors == null || connectors.length == 0)
{
- Connector connector = new SelectChannelConnector();
+ ServerConnector connector = new ServerConnector(_server);
connector.setPort(port);
_server.addConnector(connector);
- if (_enableStatsGathering)
- connector.setStatsOn(true);
+ if (_enableStats)
+ connector.addBean(new ConnectorStatistics());
}
else
{
- if (_enableStatsGathering)
+ if (_enableStats)
{
for (int j=0; j<connectors.length; j++)
{
- connectors[j].setStatsOn(true);
+ ((AbstractConnector)connectors[j]).addBean(new ConnectorStatistics());
}
}
}
@@ -359,6 +415,9 @@ public class Runner
Resource ctx = Resource.newResource(args[i]);
if (!ctx.exists())
usage("Context '"+ctx+"' does not exist");
+
+ if (contextPathSet && !(contextPath.startsWith("/")))
+ contextPath = "/"+contextPath;
// Configure the context
if (!ctx.isDirectory() && ctx.toString().toLowerCase().endsWith(".xml"))
@@ -367,25 +426,23 @@ public class Runner
XmlConfiguration xmlConfiguration=new XmlConfiguration(ctx.getURL());
xmlConfiguration.getIdMap().put("Server",_server);
ContextHandler handler=(ContextHandler)xmlConfiguration.configure();
- _contexts.addHandler(handler);
if (contextPathSet)
handler.setContextPath(contextPath);
- handler.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
- ".*/.*jsp-api-[^/]*\\.jar$|.*/.*jsp-[^/]*\\.jar$|.*/.*taglibs[^/]*\\.jar$");
+ _contexts.addHandler(handler);
+ handler.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", __containerIncludeJarPattern);
}
else
{
// assume it is a WAR file
- if (contextPathSet && !(contextPath.startsWith("/")))
- contextPath = "/"+contextPath;
-
- LOG.info("Deploying "+ctx.toString()+" @ "+contextPath);
WebAppContext webapp = new WebAppContext(_contexts,ctx.toString(),contextPath);
webapp.setConfigurationClasses(__plusConfigurationClasses);
webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",
- ".*/.*jsp-api-[^/]*\\.jar$|.*/.*jsp-[^/]*\\.jar$|.*/.*taglibs[^/]*\\.jar$");
- System.err.println(Arrays.asList(_contexts.getHandlers()));
+ __containerIncludeJarPattern);
}
+
+ //reset
+ contextPathSet = false;
+ contextPath = __defaultContextPath;
}
}
@@ -418,6 +475,10 @@ public class Runner
}
+ /**
+ * @param handler
+ * @param handlers
+ */
protected void prependHandler (Handler handler, HandlerCollection handlers)
{
if (handler == null || handlers == null)
@@ -432,72 +493,10 @@ public class Runner
-
- protected int configJDBC(String[] args,int i) throws Exception
- {
- String jdbcClass=null;
- String jdbcProperties=null;
- String jdbcJndiName=null;
-
- if (!_isTxServiceAvailable)
- {
- LOG.warn("JDBC TX support not found on classpath");
- i+=3;
- }
- else
- {
- jdbcClass=args[++i];
- jdbcProperties=args[++i];
- jdbcJndiName=args[++i];
-
- //check for jdbc resources to register
- if (jdbcClass!=null)
- {
- if (isXADataSource(jdbcClass))
- {
- Class simpleDataSourceBeanClass = Thread.currentThread().getContextClassLoader().loadClass("com.atomikos.jdbc.SimpleDataSourceBean");
- Object o = simpleDataSourceBeanClass.newInstance();
- simpleDataSourceBeanClass.getMethod("setXaDataSourceClassName", new Class[] {String.class}).invoke(o, new Object[] {jdbcClass});
- simpleDataSourceBeanClass.getMethod("setXaDataSourceProperties", new Class[] {String.class}).invoke(o, new Object[] {jdbcProperties});
- simpleDataSourceBeanClass.getMethod("setUniqueResourceName", new Class[] {String.class}).invoke(o, new Object[] {jdbcJndiName});
- org.eclipse.jetty.plus.jndi.Resource jdbcResource = new org.eclipse.jetty.plus.jndi.Resource(jdbcJndiName, o);
-
- }
- else
- {
- String[] props = jdbcProperties.split(";");
- String user=null;
- String password=null;
- String url=null;
-
- for (int j=0;props!=null && j<props.length;j++)
- {
- String[] pair = props[j].split("=");
- if (pair!=null && pair[0].equalsIgnoreCase("user"))
- user=pair[1];
- else if (pair!=null && pair[0].equalsIgnoreCase("password"))
- password=pair[1];
- else if (pair!=null && pair[0].equalsIgnoreCase("url"))
- url=pair[1];
-
- }
-
- Class nonXADataSourceBeanClass = Thread.currentThread().getContextClassLoader().loadClass("com.atomikos.jdbc.nonxa.NonXADataSourceBean");
- Object o = nonXADataSourceBeanClass.newInstance();
- nonXADataSourceBeanClass.getMethod("setDriverClassName", new Class[] {String.class}).invoke(o, new Object[] {jdbcClass});
- nonXADataSourceBeanClass.getMethod("setUniqueResourceName", new Class[] {String.class}).invoke(o, new Object[] {jdbcJndiName});
- nonXADataSourceBeanClass.getMethod("setUrl", new Class[] {String.class}).invoke(o, new Object[] {url});
- nonXADataSourceBeanClass.getMethod("setUser", new Class[] {String.class}).invoke(o, new Object[] {user});
- nonXADataSourceBeanClass.getMethod("setPassword", new Class[] {String.class}).invoke(o, new Object[] {password});
- org.eclipse.jetty.plus.jndi.Resource jdbcResource = new org.eclipse.jetty.plus.jndi.Resource(jdbcJndiName, o);
- }
- }
- }
-
- return i;
- }
-
+ /**
+ * @throws Exception
+ */
public void run() throws Exception
{
if (_monitor != null)
@@ -509,106 +508,33 @@ public class Runner
_server.join();
}
- protected void expandJars(Resource lib) throws IOException
- {
- String[] list = lib.list();
- if (list==null)
- return;
-
- for (String path : list)
- {
- if (".".equals(path) || "..".equals(path))
- continue;
-
- Resource item = lib.addPath(path);
-
- if (item.isDirectory())
- expandJars(item);
- else
- {
- if (path.toLowerCase().endsWith(".jar") ||
- path.toLowerCase().endsWith(".zip"))
- {
- URL url = item.getURL();
- _classpath.add(url);
- }
- }
- }
- }
+ /**
+ * Establish a classloader with custom paths (if any)
+ */
protected void initClassLoader()
{
- if (_classLoader==null && _classpath!=null && _classpath.size()>0)
+ URL[] paths = _classpath.asArray();
+
+ if (_classLoader==null && paths !=null && paths.length > 0)
{
ClassLoader context=Thread.currentThread().getContextClassLoader();
if (context==null)
- _classLoader=new URLClassLoader(_classpath.toArray(new URL[_classpath.size()]));
+ _classLoader=new URLClassLoader(paths);
else
- _classLoader=new URLClassLoader(_classpath.toArray(new URL[_classpath.size()]),context);
+ _classLoader=new URLClassLoader(paths, context);
Thread.currentThread().setContextClassLoader(_classLoader);
}
}
- protected boolean isXADataSource (String classname)
- throws Exception
- {
- Class clazz = Thread.currentThread().getContextClassLoader().loadClass(classname);
- boolean isXA=false;
- while (!isXA && clazz!=null)
- {
- Class[] interfaces = clazz.getInterfaces();
- for (int i=0;interfaces!=null &&!isXA && i<interfaces.length; i++)
- {
- if (interfaces[i].getCanonicalName().equals("javax.sql.XADataSource"))
- isXA=true;
- }
- clazz=clazz.getSuperclass();
- }
- LOG.debug(isXA?"XA":"!XA");
- return isXA;
- }
-
- private void processTransactionManagement() throws Exception
- {
- //set up a transaction manager
- if (!_isTxServiceAvailable)
- {
- LOG.warn("No tx manager found");
- }
- else
- {
- //this invocation of jetty needs a unique random number to identify the tx manager
- _utId = Integer.toHexString(_random.nextInt());
- if (_txMgrPropertiesFile == null)
- {
- //Use system properties to config atomikos
- System.setProperty("com.atomikos.icatch.no_file", "true");
- //create a directory for the tx mgr log and console files to go into that will be unique
- File tmpDir = new File(System.getProperty("java.io.tmpdir"));
- tmpDir = new File(tmpDir, _utId);
- tmpDir.mkdir();
- LOG.debug("Made " + tmpDir.getAbsolutePath());
- System.setProperty("com.atomikos.icatch.log_base_dir ", tmpDir.getCanonicalPath());
- System.setProperty("com.atomikos.icatch.console_file_name", "tm-debug.log");
- System.setProperty("com.atomikos.icatch.output_dir", tmpDir.getCanonicalPath());
- System.setProperty("com.atomikos.icatch.tm_unique_name", _utId);
- }
- else
- {
- System.setProperty("com.atomikos.icatch.file", _txMgrPropertiesFile);
- }
-
- //create UserTransaction
- Class utsClass = Thread.currentThread().getContextClassLoader().loadClass("com.atomikos.icatch.jta.UserTransactionImp");
- //register in JNDI
- Transaction txMgrResource = new Transaction((UserTransaction)utsClass.newInstance());
- }
- }
+ /**
+ * @param args
+ */
public static void main(String[] args)
{
Runner runner = new Runner();
@@ -621,13 +547,13 @@ public class Runner
}
else if (args.length>0&&args[0].equalsIgnoreCase("--version"))
{
- System.err.println("org.mortbay.jetty.Runner: "+Server.getVersion());
- System.exit(1);
+ runner.version();
+ }
+ else
+ {
+ runner.configure(args);
+ runner.run();
}
-
- runner.configure(args);
- runner.run();
-
}
catch (Exception e)
{
diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java
new file mode 100644
index 0000000000..ce178efe2d
--- /dev/null
+++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/StatisticsServlet.java
@@ -0,0 +1,282 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
+// ------------------------------------------------------------------------
+// All rights reserved. This program and the accompanying materials
+// are made available under the terms of the Eclipse Public License v1.0
+// and Apache License v2.0 which accompanies this distribution.
+//
+// The Eclipse Public License is available at
+// http://www.eclipse.org/legal/epl-v10.html
+//
+// The Apache License v2.0 is available at
+// http://www.opensource.org/licenses/apache2.0.php
+//
+// You may elect to redistribute this code under either of these licenses.
+// ========================================================================
+//
+
+package org.eclipse.jetty.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.eclipse.jetty.server.AbstractConnector;
+import org.eclipse.jetty.server.Connector;
+import org.eclipse.jetty.server.ConnectorStatistics;
+import org.eclipse.jetty.server.Handler;
+import org.eclipse.jetty.server.Server;
+import org.eclipse.jetty.server.handler.ContextHandler;
+import org.eclipse.jetty.server.handler.StatisticsHandler;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+/**
+ * StatisticsServlet
+ *
+ *
+ */
+public class StatisticsServlet extends HttpServlet
+{
+ private static final Logger LOG = Log.getLogger(StatisticsServlet.class);
+
+ boolean _restrictToLocalhost = true; // defaults to true
+ private StatisticsHandler _statsHandler;
+ private MemoryMXBean _memoryBean;
+ private Connector[] _connectors;
+
+
+
+ /**
+ * @see javax.servlet.GenericServlet#init()
+ */
+ public void init() throws ServletException
+ {
+ ServletContext context = getServletContext();
+ ContextHandler.Context scontext = (ContextHandler.Context) context;
+ Server _server = scontext.getContextHandler().getServer();
+
+ Handler handler = _server.getChildHandlerByClass(StatisticsHandler.class);
+
+ if (handler != null)
+ {
+ _statsHandler = (StatisticsHandler) handler;
+ }
+ else
+ {
+ LOG.warn("Statistics Handler not installed!");
+ return;
+ }
+
+ _memoryBean = ManagementFactory.getMemoryMXBean();
+ _connectors = _server.getConnectors();
+
+ if (getInitParameter("restrictToLocalhost") != null)
+ {
+ _restrictToLocalhost = "true".equals(getInitParameter("restrictToLocalhost"));
+ }
+ }
+
+
+
+ /**
+ * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ public void doPost(HttpServletRequest sreq, HttpServletResponse sres) throws ServletException, IOException
+ {
+ doGet(sreq, sres);
+ }
+
+
+
+ /**
+ * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
+ */
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ if (_statsHandler == null)
+ {
+ LOG.warn("Statistics Handler not installed!");
+ resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ return;
+ }
+ if (_restrictToLocalhost)
+ {
+ if (!"127.0.0.1".equals(req.getRemoteAddr()))
+ {
+ resp.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
+ return;
+ }
+ }
+
+ String wantXml = req.getParameter("xml");
+ if (wantXml == null)
+ wantXml = req.getParameter("XML");
+
+ if (wantXml != null && "true".equalsIgnoreCase(wantXml))
+ {
+ sendXmlResponse(resp);
+ }
+ else
+ {
+ sendTextResponse(resp);
+ }
+
+ }
+
+
+
+ /**
+ * @param response
+ * @throws IOException
+ */
+ private void sendXmlResponse(HttpServletResponse response) throws IOException
+ {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append("<statistics>\n");
+
+ sb.append(" <requests>\n");
+ sb.append(" <statsOnMs>").append(_statsHandler.getStatsOnMs()).append("</statsOnMs>\n");
+
+ sb.append(" <requests>").append(_statsHandler.getRequests()).append("</requests>\n");
+ sb.append(" <requestsActive>").append(_statsHandler.getRequestsActive()).append("</requestsActive>\n");
+ sb.append(" <requestsActiveMax>").append(_statsHandler.getRequestsActiveMax()).append("</requestsActiveMax>\n");
+ sb.append(" <requestsTimeTotal>").append(_statsHandler.getRequestTimeTotal()).append("</requestsTimeTotal>\n");
+ sb.append(" <requestsTimeMean>").append(_statsHandler.getRequestTimeMean()).append("</requestsTimeMean>\n");
+ sb.append(" <requestsTimeMax>").append(_statsHandler.getRequestTimeMax()).append("</requestsTimeMax>\n");
+ sb.append(" <requestsTimeStdDev>").append(_statsHandler.getRequestTimeStdDev()).append("</requestsTimeStdDev>\n");
+
+ sb.append(" <dispatched>").append(_statsHandler.getDispatched()).append("</dispatched>\n");
+ sb.append(" <dispatchedActive>").append(_statsHandler.getDispatchedActive()).append("</dispatchedActive>\n");
+ sb.append(" <dispatchedActiveMax>").append(_statsHandler.getDispatchedActiveMax()).append("</dispatchedActiveMax>\n");
+ sb.append(" <dispatchedTimeTotalMs>").append(_statsHandler.getDispatchedTimeTotal()).append("</dispatchedTimeTotalMs>\n");
+ sb.append(" <dispatchedTimeMeanMs>").append(_statsHandler.getDispatchedTimeMean()).append("</dispatchedTimeMeanMs>\n");
+ sb.append(" <dispatchedTimeMaxMs>").append(_statsHandler.getDispatchedTimeMax()).append("</dispatchedTimeMaxMs>\n");
+ sb.append(" <dispatchedTimeStdDevMs>").append(_statsHandler.getDispatchedTimeStdDev()).append("</dispatchedTimeStdDevMs>\n");
+
+ sb.append(" <asyncRequests>").append(_statsHandler.getAsyncRequests()).append("</asyncRequests>\n");
+ sb.append(" <requestsSuspended>").append(_statsHandler.getAsyncRequestsWaiting()).append("</requestsSuspended>\n");
+ sb.append(" <requestsSuspendedMax>").append(_statsHandler.getAsyncRequestsWaitingMax()).append("</requestsSuspendedMax>\n");
+ sb.append(" <requestsResumed>").append(_statsHandler.getAsyncDispatches()).append("</requestsResumed>\n");
+ sb.append(" <requestsExpired>").append(_statsHandler.getExpires()).append("</requestsExpired>\n");
+ sb.append(" </requests>\n");
+
+ sb.append(" <responses>\n");
+ sb.append(" <responses1xx>").append(_statsHandler.getResponses1xx()).append("</responses1xx>\n");
+ sb.append(" <responses2xx>").append(_statsHandler.getResponses2xx()).append("</responses2xx>\n");
+ sb.append(" <responses3xx>").append(_statsHandler.getResponses3xx()).append("</responses3xx>\n");
+ sb.append(" <responses4xx>").append(_statsHandler.getResponses4xx()).append("</responses4xx>\n");
+ sb.append(" <responses5xx>").append(_statsHandler.getResponses5xx()).append("</responses5xx>\n");
+ sb.append(" <responsesBytesTotal>").append(_statsHandler.getResponsesBytesTotal()).append("</responsesBytesTotal>\n");
+ sb.append(" </responses>\n");
+
+ sb.append(" <connections>\n");
+ for (Connector connector : _connectors)
+ {
+ sb.append(" <connector>\n");
+ sb.append(" <name>").append(connector.getClass().getName()).append("@").append(connector.hashCode()).append("</name>\n");
+ sb.append(" <protocols>\n");
+ for (String protocol:connector.getProtocols())
+ sb.append(" <protocol>").append(protocol).append("</protocol>\n");
+ sb.append(" </protocols>\n");
+
+ ConnectorStatistics connectorStats = null;
+
+ if (connector instanceof AbstractConnector)
+ connectorStats = ((AbstractConnector)connector).getBean(ConnectorStatistics.class);
+ if (connectorStats == null)
+ sb.append(" <statsOn>false</statsOn>\n");
+ else
+ {
+ sb.append(" <statsOn>true</statsOn>\n");
+ sb.append(" <connections>").append(connectorStats.getConnections()).append("</connections>\n");
+ sb.append(" <connectionsOpen>").append(connectorStats.getConnectionsOpen()).append("</connectionsOpen>\n");
+ sb.append(" <connectionsOpenMax>").append(connectorStats.getConnectionsOpenMax()).append("</connectionsOpenMax>\n");
+ sb.append(" <connectionsDurationTotal>").append(connectorStats.getConnectionsDurationTotal()).append("</connectionsDurationTotal>\n");
+ sb.append(" <connectionsDurationMean>").append(connectorStats.getConnectionsDurationMean()).append("</connectionsDurationMean>\n");
+ sb.append(" <connectionsDurationMax>").append(connectorStats.getConnectionsDurationMax()).append("</connectionsDurationMax>\n");
+ sb.append(" <connectionsDurationStdDev>").append(connectorStats.getConnectionsDurationStdDev()).append("</connectionsDurationStdDev>\n");
+ sb.append(" <messagesIn>").append(connectorStats.getMessagesIn()).append("</messagesIn>\n");
+ sb.append(" <messagesOut>").append(connectorStats.getMessagesIn()).append("</messagesOut>\n");
+ sb.append(" <elapsedMs>").append(connectorStats.getStartedMillis()).append("</elapsedMs>\n");
+ }
+ sb.append(" </connector>\n");
+ }
+ sb.append(" </connections>\n");
+
+ sb.append(" <memory>\n");
+ sb.append(" <heapMemoryUsage>").append(_memoryBean.getHeapMemoryUsage().getUsed()).append("</heapMemoryUsage>\n");
+ sb.append(" <nonHeapMemoryUsage>").append(_memoryBean.getNonHeapMemoryUsage().getUsed()).append("</nonHeapMemoryUsage>\n");
+ sb.append(" </memory>\n");
+
+ sb.append("</statistics>\n");
+
+ response.setContentType("text/xml");
+ PrintWriter pout = response.getWriter();
+ pout.write(sb.toString());
+ }
+
+
+
+ /**
+ * @param response
+ * @throws IOException
+ */
+ private void sendTextResponse(HttpServletResponse response) throws IOException
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.append(_statsHandler.toStatsHTML());
+
+ sb.append("<h2>Connections:</h2>\n");
+ for (Connector connector : _connectors)
+ {
+ sb.append("<h3>").append(connector.getClass().getName()).append("@").append(connector.hashCode()).append("</h3>");
+ sb.append("Protocols:");
+ for (String protocol:connector.getProtocols())
+ sb.append(protocol).append("&nbsp;");
+ sb.append(" <br />\n");
+
+ ConnectorStatistics connectorStats = null;
+
+ if (connector instanceof AbstractConnector)
+ connectorStats = ((AbstractConnector)connector).getBean(ConnectorStatistics.class);
+
+ if (connectorStats != null)
+ {
+ sb.append("Statistics gathering started ").append(connectorStats.getStartedMillis()).append("ms ago").append("<br />\n");
+ sb.append("Total connections: ").append(connectorStats.getConnections()).append("<br />\n");
+ sb.append("Current connections open: ").append(connectorStats.getConnectionsOpen()).append("<br />\n");;
+ sb.append("Max concurrent connections open: ").append(connectorStats.getConnectionsOpenMax()).append("<br />\n");
+ sb.append("Total connections duration: ").append(connectorStats.getConnectionsDurationTotal()).append("<br />\n");
+ sb.append("Mean connection duration: ").append(connectorStats.getConnectionsDurationMean()).append("<br />\n");
+ sb.append("Max connection duration: ").append(connectorStats.getConnectionsDurationMax()).append("<br />\n");
+ sb.append("Connection duration standard deviation: ").append(connectorStats.getConnectionsDurationStdDev()).append("<br />\n");
+ sb.append("Total messages in: ").append(connectorStats.getMessagesIn()).append("<br />\n");
+ sb.append("Total messages out: ").append(connectorStats.getMessagesOut()).append("<br />\n");
+ }
+ else
+ {
+ sb.append("Statistics gathering off.\n");
+ }
+
+ }
+
+ sb.append("<h2>Memory:</h2>\n");
+ sb.append("Heap memory usage: ").append(_memoryBean.getHeapMemoryUsage().getUsed()).append(" bytes").append("<br />\n");
+ sb.append("Non-heap memory usage: ").append(_memoryBean.getNonHeapMemoryUsage().getUsed()).append(" bytes").append("<br />\n");
+
+ response.setContentType("text/html");
+ PrintWriter pout = response.getWriter();
+ pout.write(sb.toString());
+
+ }
+}
diff --git a/pom.xml b/pom.xml
index badcf139cb..8ba74c34b6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -414,11 +414,11 @@
<module>tests</module>
<module>aggregates/jetty-all</module>
<module>jetty-distribution</module>
+ <module>jetty-runner</module>
<!-- modules that need fixed and added back, or simply dropped and not maintained
<module>tests</module>
- <module>jetty-runner</module>
<module>jetty-rhttp</module>
<module>jetty-http-spi</module>
-->

Back to the top