diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml
index f0da6e9f5b0..17cc6993e2d 100644
--- a/jetty-monitor/pom.xml
+++ b/jetty-monitor/pom.xml
@@ -1,3 +1,20 @@
+
org.eclipse.jetty
@@ -10,6 +27,9 @@
Performance monitoring artifact for jetty.
${project.groupId}.jmx
+ ${project.build.directory}/test-wars
+ ${project.build.directory}/test-libs
+ ${project.build.directory}/test-dist
@@ -59,6 +79,41 @@
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ always
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+
+
+ unpack-jetty-distro
+ process-test-resources
+
+ unpack
+
+
+
+
+ org.eclipse.jetty
+ jetty-distribution
+ ${project.version}
+ zip
+ true
+
+
+ true
+ ${test-dist-dir}
+ true
+ true
+
+
+
+
org.codehaus.mojo
findbugs-maven-plugin
@@ -69,15 +124,52 @@
-
- junit
- junit
- test
-
org.eclipse.jetty
jetty-util
${project.version}
+
+ org.eclipse.jetty
+ jetty-io
+ ${project.version}
+
+
+ org.eclipse.jetty
+ jetty-http
+ ${project.version}
+
+
+ org.eclipse.jetty
+ jetty-xml
+ ${project.version}
+
+
+ org.eclipse.jetty
+ jetty-client
+ ${project.version}
+
+
+ org.eclipse.jetty
+ jetty-jmx
+ ${project.version}
+ test
+
+
+ org.eclipse.jetty
+ jetty-server
+ ${project.version}
+ test
+
+
+ org.eclipse.jetty.toolchain
+ jetty-test-helper
+ test
+
+
+ junit
+ junit
+ test
+
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java
new file mode 100644
index 00000000000..3fdc2220812
--- /dev/null
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/JMXMonitor.java
@@ -0,0 +1,189 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// 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.monitor;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.management.MBeanServerConnection;
+
+import org.eclipse.jetty.monitor.jmx.MonitorAction;
+import org.eclipse.jetty.monitor.jmx.MonitorTask;
+import org.eclipse.jetty.monitor.jmx.ServiceConnection;
+import org.eclipse.jetty.xml.XmlConfiguration;
+
+/* ------------------------------------------------------------ */
+/**
+ * JMXMonitor
+ *
+ * Performs monitoring of the values of the attributes of MBeans
+ * and executes specified actions as well as sends notifications
+ * of the specified events that have occurred.
+ */
+public class JMXMonitor
+{
+ private static JMXMonitor __monitor = new JMXMonitor();
+
+ private String _serverUrl;
+ private ServiceConnection _serviceConnection;
+
+ private Set _actions = new HashSet();
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Constructs a JMXMonitor instance. Used for XML Configuration.
+ *
+ * !! DO NOT INSTANTIATE EXPLICITLY !!
+ */
+ public JMXMonitor() {}
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Adds monitor actions to the monitor
+ *
+ * @param actions monitor actions to add
+ * @return true if successful
+ */
+ public boolean addActions(MonitorAction... actions)
+ {
+ return getInstance().add(actions);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Removes monitor actions from the monitor
+ *
+ * @param actions monitor actions to remove
+ * @return true if successful
+ */
+ public boolean removeActions(MonitorAction... actions)
+ {
+ return getInstance().remove(actions);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Sets the JMX server URL
+ *
+ * @param url URL of the JMX server
+ */
+ public void setUrl(String url)
+ {
+ getInstance().set(url);
+ }
+
+ public MBeanServerConnection getConnection()
+ throws IOException
+ {
+ return getInstance().get();
+ }
+
+ public static JMXMonitor getInstance()
+ {
+ return __monitor;
+ }
+
+ public static boolean addMonitorActions(MonitorAction... actions)
+ {
+ return getInstance().add(actions);
+ }
+
+ public static boolean removeMonitorActions(MonitorAction... actions)
+ {
+ return getInstance().remove(actions);
+ }
+
+ public static void setServiceUrl(String url)
+ {
+ getInstance().set(url);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * Retrieves a connection to JMX service
+ *
+ * @return server connection
+ * @throws IOException
+ */
+ public static MBeanServerConnection getServiceConnection()
+ throws IOException
+ {
+ return getInstance().getConnection();
+ }
+
+ public static void main(final String args[]) throws Exception
+ {
+ XmlConfiguration.main(args);
+ }
+
+ private synchronized boolean add(MonitorAction... actions)
+ {
+ boolean result = true;
+
+ for (MonitorAction action : actions)
+ {
+ if (!_actions.add(action))
+ {
+ result = false;
+ }
+ else
+ {
+ MonitorTask.schedule(action);
+ }
+ }
+
+ return result;
+ }
+
+ private synchronized boolean remove(MonitorAction... actions)
+ {
+ boolean result = true;
+
+ for (MonitorAction action : actions)
+ {
+ if (!_actions.remove(action))
+ {
+ result = false;
+ }
+
+ MonitorTask.cancel(action);
+ }
+
+ return result;
+ }
+
+ private synchronized void set(String url)
+ {
+ _serverUrl = url;
+
+ if (_serviceConnection != null)
+ {
+ _serviceConnection.disconnect();
+ _serviceConnection = null;
+ }
+ }
+
+ private synchronized MBeanServerConnection get()
+ throws IOException
+ {
+ if (_serviceConnection == null)
+ {
+ _serviceConnection = new ServiceConnection(_serverUrl);
+ _serviceConnection.connect();
+ }
+
+ return _serviceConnection.getConnection();
+ }
+}
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java
index 6a63b88b13f..9badd226528 100644
--- a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/ThreadMonitor.java
@@ -23,6 +23,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import org.eclipse.jetty.monitor.thread.ThreadMonitorException;
+import org.eclipse.jetty.monitor.thread.ThreadMonitorInfo;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.log.Log;
diff --git a/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java
new file mode 100644
index 00000000000..65fe1d3f0c2
--- /dev/null
+++ b/jetty-monitor/src/main/java/org/eclipse/jetty/monitor/integration/JavaMonitorAction.java
@@ -0,0 +1,415 @@
+// ========================================================================
+// Copyright (c) Webtide LLC
+// ------------------------------------------------------------------------
+// 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.monitor.integration;
+
+import static java.lang.Integer.parseInt;
+import static java.lang.System.getProperty;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.Socket;
+import java.net.URL;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+
+import javax.management.MBeanServerConnection;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.eclipse.jetty.client.ContentExchange;
+import org.eclipse.jetty.client.HttpClient;
+import org.eclipse.jetty.http.HttpMethods;
+import org.eclipse.jetty.http.HttpStatus;
+import org.eclipse.jetty.io.ByteArrayBuffer;
+import org.eclipse.jetty.monitor.JMXMonitor;
+import org.eclipse.jetty.monitor.jmx.EventNotifier;
+import org.eclipse.jetty.monitor.jmx.EventState;
+import org.eclipse.jetty.monitor.jmx.EventState.TriggerState;
+import org.eclipse.jetty.monitor.jmx.EventTrigger;
+import org.eclipse.jetty.monitor.jmx.MonitorAction;
+import org.eclipse.jetty.monitor.triggers.AggregateEventTrigger;
+import org.eclipse.jetty.util.log.Log;
+
+
+/* ------------------------------------------------------------ */
+/**
+ */
+public class JavaMonitorAction extends MonitorAction
+{
+ private final HttpClient _client;
+
+ private final String _url;
+ private final String _uuid;
+ private final String _appid;
+
+ private String _srvip;
+ private String _session;
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param notifier
+ * @param pollInterval
+ * @throws Exception
+ * @throws MalformedObjectNameException
+ */
+ public JavaMonitorAction(EventNotifier notifier, String url, String uuid, String appid, long pollInterval)
+ throws Exception
+ {
+ super(new AggregateEventTrigger(),notifier,pollInterval);
+
+ _url = url;
+ _uuid = uuid;
+ _appid = appid;
+
+ _client = new HttpClient();
+ _client.setTimeout(60000);
+ _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
+
+ try
+ {
+ _client.start();
+ _srvip = getServerIP();
+ }
+ catch (Exception ex)
+ {
+ Log.debug(ex);
+ }
+
+ sendData(new Properties());
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see org.eclipse.jetty.monitor.jmx.MonitorAction#execute(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long)
+ */
+ @Override
+ public void execute(EventTrigger trigger, EventState> state, long timestamp)
+ {
+ exec(trigger, state, timestamp);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param trigger
+ * @param state
+ * @param timestamp
+ */
+ private void exec(EventTrigger trigger, EventState state, long timestamp)
+ {
+ Collection> trs = state.values();
+
+ Properties data = new Properties();
+ for (TriggerState ts : trs)
+ {
+ Object value = ts.getValue();
+
+ StringBuffer buffer = new StringBuffer();
+ buffer.append(value == null ? "" : value.toString());
+ buffer.append("|");
+ buffer.append(getClassID(value));
+ buffer.append("||");
+ buffer.append(ts.getDescription());
+
+ data.setProperty(ts.getID(), buffer.toString());
+
+ try
+ {
+ sendData(data);
+ }
+ catch (Exception ex)
+ {
+ Log.debug(ex);
+ }
+ }
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param data
+ * @throws Exception
+ */
+ private void sendData(Properties data)
+ throws Exception
+ {
+ data.put("account", _uuid);
+ data.put("appserver", "Jetty");
+ data.put("localIp", _srvip);
+ if (_appid == null)
+ data.put("lowestPort", getHttpPort());
+ else
+ data.put("lowestPort", _appid);
+ if (_session != null)
+ data.put("session", _session);
+
+ Properties response = sendRequest(data);
+
+ parseResponse(response);
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param request
+ * @return
+ * @throws Exception
+ */
+ private Properties sendRequest(Properties request)
+ throws Exception
+ {
+ ByteArrayOutputStream reqStream = null;
+ ByteArrayInputStream resStream = null;
+ Properties response = null;
+
+ try {
+ ContentExchange reqEx = new ContentExchange();
+ reqEx.setURL(_url);
+ reqEx.setMethod(HttpMethods.POST);
+ reqEx.addRequestHeader("Connection","close");
+
+ reqStream = new ByteArrayOutputStream();
+ request.storeToXML(reqStream,null);
+ ByteArrayBuffer reqBuff = new ByteArrayBuffer(reqStream.toByteArray());
+
+ reqEx.setRequestContent(reqBuff);
+ _client.send(reqEx);
+
+ reqEx.waitForDone();
+
+ if (reqEx.getResponseStatus() == HttpStatus.OK_200)
+ {
+ response = new Properties();
+ resStream = new ByteArrayInputStream(reqEx.getResponseContentBytes());
+ response.loadFromXML(resStream);
+ }
+ }
+ finally
+ {
+ try
+ {
+ if (reqStream != null)
+ reqStream.close();
+ }
+ catch (IOException ex)
+ {
+ Log.ignore(ex);
+ }
+
+ try
+ {
+ if (resStream != null)
+ resStream.close();
+ }
+ catch (IOException ex)
+ {
+ Log.ignore(ex);
+ }
+ }
+
+ return response;
+ }
+
+ /* ------------------------------------------------------------ */
+ private void parseResponse(Properties response)
+ {
+ if (response.get("onhold") != null)
+ throw new Error("Suspended");
+
+
+ if (response.get("session") != null)
+ {
+ _session = (String) response.remove("session");
+
+ AggregateEventTrigger trigger = (AggregateEventTrigger)getTrigger();
+
+ String queryString;
+ ObjectName[] queryResults;
+ for (Map.Entry