Merging from master
This commit is contained in:
commit
4ace183764
|
@ -3,7 +3,10 @@ target/
|
|||
.project
|
||||
.settings
|
||||
*/src/main/java/META-INF/
|
||||
.pmd
|
||||
*.log
|
||||
*.swp
|
||||
*.diff
|
||||
*.patch
|
||||
*.iml
|
||||
.idea
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
jetty-7.5.0-SNAPSHOT
|
||||
+ 354080 ServletContextHandler allows to replace any subordinate handler when restarted
|
||||
|
||||
jetty-7.5.0.RC1 - 19 August 2011
|
||||
+ 276670 SLF4J loggers show correct location information
|
||||
+ 335001 Eliminate expected exceptions from log when running in JBoss
|
||||
+ 355103 Make allowCredentials default to true in CrossOriginFilter
|
||||
+ 355162 Allow creating an empty resource collection
|
||||
+ JETTY-1410 HTTP client handles CONTINUE 100 response correctly
|
||||
+ JETTY-1414 HashLoginService doesn't refresh realm if specified config filename is not an absolute platform specific value
|
||||
|
||||
jetty-7.5.0.RC0 - 15 August 2011
|
||||
|
|
|
@ -73,7 +73,7 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
HttpConnection(Buffers requestBuffers, Buffers responseBuffers, EndPoint endp)
|
||||
{
|
||||
super(endp);
|
||||
|
||||
|
||||
_generator = new HttpGenerator(requestBuffers,endp);
|
||||
_parser = new HttpParser(responseBuffers,endp,new Handler());
|
||||
}
|
||||
|
@ -574,14 +574,24 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
@Override
|
||||
public void startResponse(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
|
||||
HttpExchange exchange = _exchange;
|
||||
if (exchange!=null)
|
||||
{
|
||||
// handle special case for CONNECT 200 responses
|
||||
if (status==HttpStatus.OK_200 && HttpMethods.CONNECT.equalsIgnoreCase(exchange.getMethod()))
|
||||
_parser.setHeadResponse(true);
|
||||
|
||||
switch(status)
|
||||
{
|
||||
case HttpStatus.CONTINUE_100:
|
||||
case HttpStatus.PROCESSING_102:
|
||||
// TODO check if appropriate expect was sent in the request.
|
||||
exchange.setEventListener(new NonFinalResponseListener(exchange));
|
||||
break;
|
||||
|
||||
case HttpStatus.OK_200:
|
||||
// handle special case for CONNECT 200 responses
|
||||
if (HttpMethods.CONNECT.equalsIgnoreCase(exchange.getMethod()))
|
||||
_parser.setHeadResponse(true);
|
||||
break;
|
||||
}
|
||||
|
||||
_http11 = HttpVersions.HTTP_1_1_BUFFER.equals(version);
|
||||
_status=status;
|
||||
exchange.getEventListener().onResponseStatus(version,status,reason);
|
||||
|
@ -737,8 +747,10 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class ConnectionIdleTask extends Timeout.Task
|
||||
{
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void expired()
|
||||
{
|
||||
|
@ -749,4 +761,87 @@ public class HttpConnection extends AbstractConnection implements Dumpable
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private class NonFinalResponseListener implements HttpEventListener
|
||||
{
|
||||
final HttpExchange _exchange;
|
||||
final HttpEventListener _next;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public NonFinalResponseListener(HttpExchange exchange)
|
||||
{
|
||||
_exchange=exchange;
|
||||
_next=exchange.getEventListener();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onRequestCommitted() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onRequestComplete() throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseStatus(Buffer version, int status, Buffer reason) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
_next.onResponseHeader(name,value);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseHeaderComplete() throws IOException
|
||||
{
|
||||
_next.onResponseHeaderComplete();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseContent(Buffer content) throws IOException
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onResponseComplete() throws IOException
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_exchange.setStatus(HttpExchange.STATUS_WAITING_FOR_RESPONSE);
|
||||
_parser.reset();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onConnectionFailed(Throwable ex)
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_next.onConnectionFailed(ex);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onException(Throwable ex)
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_next.onException(ex);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onExpire()
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_next.onExpire();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void onRetry()
|
||||
{
|
||||
_exchange.setEventListener(_next);
|
||||
_next.onRetry();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -305,6 +305,7 @@ public class HttpExchange
|
|||
{
|
||||
case STATUS_START:
|
||||
case STATUS_EXCEPTED:
|
||||
case STATUS_WAITING_FOR_RESPONSE:
|
||||
set=_status.compareAndSet(oldStatus,newStatus);
|
||||
break;
|
||||
case STATUS_CANCELLING:
|
||||
|
@ -347,7 +348,7 @@ public class HttpExchange
|
|||
}
|
||||
|
||||
if (!set)
|
||||
throw new IllegalStateException(oldStatus + " => " + newStatus);
|
||||
throw new IllegalStateException(toState(oldStatus) + " => " + toState(newStatus));
|
||||
}
|
||||
catch (IOException x)
|
||||
{
|
||||
|
@ -729,11 +730,10 @@ public class HttpExchange
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
public static String toState(int s)
|
||||
{
|
||||
String state;
|
||||
switch(getStatus())
|
||||
switch(s)
|
||||
{
|
||||
case STATUS_START: state="START"; break;
|
||||
case STATUS_WAITING_FOR_CONNECTION: state="CONNECTING"; break;
|
||||
|
@ -749,6 +749,13 @@ public class HttpExchange
|
|||
case STATUS_CANCELLED: state="CANCELLED"; break;
|
||||
default: state="UNKNOWN";
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
String state=toState(getStatus());
|
||||
long now=System.currentTimeMillis();
|
||||
long forMs = now -_lastStateChange;
|
||||
String s= String.format("%s@%x=%s//%s%s#%s(%dms)",getClass().getSimpleName(),hashCode(),_method,_address,_uri,state,forMs);
|
||||
|
|
|
@ -0,0 +1,240 @@
|
|||
// ========================================================================
|
||||
// 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.client;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public class Http100ContinueTest
|
||||
{
|
||||
private static final int TIMEOUT = 500;
|
||||
|
||||
private static final String CONTENT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "
|
||||
+ "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "
|
||||
+ "habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. "
|
||||
+ "Vestibulum sit amet felis augue, vel convallis dolor. Cras accumsan vehicula diam "
|
||||
+ "at faucibus. Etiam in urna turpis, sed congue mi. Morbi et lorem eros. Donec vulputate "
|
||||
+ "velit in risus suscipit lobortis. Aliquam id urna orci, nec sollicitudin ipsum. "
|
||||
+ "Cras a orci turpis. Donec suscipit vulputate cursus. Mauris nunc tellus, fermentum "
|
||||
+ "eu auctor ut, mollis at diam. Quisque porttitor ultrices metus, vitae tincidunt massa "
|
||||
+ "sollicitudin a. Vivamus porttitor libero eget purus hendrerit cursus. Integer aliquam "
|
||||
+ "consequat mauris quis luctus. Cras enim nibh, dignissim eu faucibus ac, mollis nec neque. "
|
||||
+ "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "
|
||||
+ "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque.";
|
||||
|
||||
private static TestFeature _feature;
|
||||
|
||||
private static Server _server;
|
||||
private static TestHandler _handler;
|
||||
private static HttpClient _client;
|
||||
private static String _requestUrl;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() throws Exception
|
||||
{
|
||||
File docRoot = new File("target/test-output/docroot/");
|
||||
if (!docRoot.exists())
|
||||
assertTrue(docRoot.mkdirs());
|
||||
docRoot.deleteOnExit();
|
||||
|
||||
_server = new Server();
|
||||
Connector connector = new SelectChannelConnector();
|
||||
_server.addConnector(connector);
|
||||
|
||||
_handler = new TestHandler();
|
||||
_server.setHandler(_handler);
|
||||
|
||||
_server.start();
|
||||
|
||||
_client = new HttpClient();
|
||||
_client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
_client.setTimeout(TIMEOUT);
|
||||
_client.setMaxRetries(0);
|
||||
_client.start();
|
||||
|
||||
_requestUrl = "http://localhost:" + connector.getLocalPort() + "/";
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void destroy() throws Exception
|
||||
{
|
||||
_client.stop();
|
||||
|
||||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess() throws Exception
|
||||
{
|
||||
// Handler to send CONTINUE 100
|
||||
_feature = TestFeature.CONTINUE;
|
||||
|
||||
ContentExchange exchange = sendExchange();
|
||||
|
||||
int state = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||
|
||||
int responseStatus = exchange.getResponseStatus();
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
|
||||
String content = exchange.getResponseContent();
|
||||
assertEquals(Http100ContinueTest.CONTENT,content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingContinue() throws Exception
|
||||
{
|
||||
// Handler does not send CONTINUE 100
|
||||
_feature = TestFeature.NORMAL;
|
||||
|
||||
ContentExchange exchange = sendExchange();
|
||||
|
||||
int state = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||
|
||||
int responseStatus = exchange.getResponseStatus();
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
|
||||
String content = exchange.getResponseContent();
|
||||
assertEquals(Http100ContinueTest.CONTENT,content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testError() throws Exception
|
||||
{
|
||||
// Handler sends NOT FOUND 404 response
|
||||
_feature = TestFeature.NOTFOUND;
|
||||
|
||||
ContentExchange exchange = sendExchange();
|
||||
|
||||
int state = exchange.waitForDone();
|
||||
assertEquals(HttpExchange.STATUS_COMPLETED, state);
|
||||
|
||||
int responseStatus = exchange.getResponseStatus();
|
||||
assertEquals(HttpStatus.NOT_FOUND_404,responseStatus);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTimeout() throws Exception
|
||||
{
|
||||
// Handler delays response till client times out
|
||||
_feature = TestFeature.TIMEOUT;
|
||||
|
||||
final CountDownLatch expires = new CountDownLatch(1);
|
||||
ContentExchange exchange = new ContentExchange()
|
||||
{
|
||||
@Override
|
||||
protected void onExpire()
|
||||
{
|
||||
expires.countDown();
|
||||
}
|
||||
};
|
||||
|
||||
configureExchange(exchange);
|
||||
_client.send(exchange);
|
||||
|
||||
assertTrue(expires.await(TIMEOUT*10,TimeUnit.MILLISECONDS));
|
||||
}
|
||||
|
||||
public ContentExchange sendExchange() throws Exception
|
||||
{
|
||||
ContentExchange exchange = new ContentExchange();
|
||||
|
||||
configureExchange(exchange);
|
||||
_client.send(exchange);
|
||||
|
||||
return exchange;
|
||||
}
|
||||
|
||||
public void configureExchange(ContentExchange exchange)
|
||||
{
|
||||
exchange.setURL(_requestUrl);
|
||||
exchange.setMethod(HttpMethods.GET);
|
||||
exchange.addRequestHeader("User-Agent","Jetty-Client/7.0");
|
||||
exchange.addRequestHeader("Expect","100-continue"); //server to send CONTINUE 100
|
||||
}
|
||||
|
||||
private static class TestHandler extends AbstractHandler
|
||||
{
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
if (baseRequest.isHandled())
|
||||
return;
|
||||
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
switch (_feature)
|
||||
{
|
||||
case CONTINUE:
|
||||
// force 100 Continue response to be sent
|
||||
request.getInputStream();
|
||||
// next send data
|
||||
|
||||
case NORMAL:
|
||||
response.setContentType("text/plain");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
response.getWriter().print(CONTENT);
|
||||
break;
|
||||
|
||||
case NOTFOUND:
|
||||
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
break;
|
||||
|
||||
case TIMEOUT:
|
||||
try
|
||||
{
|
||||
Thread.sleep(TIMEOUT*4);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
Log.ignore(ex);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum TestFeature {
|
||||
CONTINUE,
|
||||
NORMAL,
|
||||
NOTFOUND,
|
||||
TIMEOUT
|
||||
}
|
||||
}
|
|
@ -1,3 +1,20 @@
|
|||
<!--
|
||||
// ========================================================================
|
||||
// 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.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
-->
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
@ -10,6 +27,9 @@
|
|||
<description>Performance monitoring artifact for jetty.</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.jmx</bundle-symbolic-name>
|
||||
<test-wars-dir>${project.build.directory}/test-wars</test-wars-dir>
|
||||
<test-libs-dir>${project.build.directory}/test-libs</test-libs-dir>
|
||||
<test-dist-dir>${project.build.directory}/test-dist</test-dist-dir>
|
||||
</properties>
|
||||
<build>
|
||||
<plugins>
|
||||
|
@ -59,6 +79,41 @@
|
|||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<forkMode>always</forkMode>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-dependency-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>unpack-jetty-distro</id>
|
||||
<phase>process-test-resources</phase>
|
||||
<goals>
|
||||
<goal>unpack</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifactItems>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-distribution</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>zip</type>
|
||||
<overWrite>true</overWrite>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
<outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename>
|
||||
<outputDirectory>${test-dist-dir}</outputDirectory>
|
||||
<overWriteSnapshots>true</overWriteSnapshots>
|
||||
<overWriteIfNewer>true</overWriteIfNewer>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
|
@ -69,15 +124,52 @@
|
|||
</plugins>
|
||||
</build>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-io</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-xml</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -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<MonitorAction> _actions = new HashSet<MonitorAction>();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,418 @@
|
|||
// ========================================================================
|
||||
// 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;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class JavaMonitorAction extends MonitorAction
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JavaMonitorAction.class);
|
||||
|
||||
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 <T> void exec(EventTrigger trigger, EventState<T> state, long timestamp)
|
||||
{
|
||||
Collection<TriggerState<T>> trs = state.values();
|
||||
|
||||
Properties data = new Properties();
|
||||
for (TriggerState<T> 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<Object, Object> entry : response.entrySet())
|
||||
{
|
||||
String[] values = ((String) entry.getValue()).split("\\|");
|
||||
|
||||
queryString = values[0];
|
||||
if (queryString.startsWith("com.javamonitor.openfire"))
|
||||
continue;
|
||||
|
||||
if (queryString.startsWith("com.javamonitor"))
|
||||
{
|
||||
queryString = "org.eclipse.jetty.monitor.integration:type=javamonitortools,id=0";
|
||||
}
|
||||
|
||||
queryResults = null;
|
||||
try
|
||||
{
|
||||
queryResults = queryNames(queryString);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
catch (MalformedObjectNameException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
|
||||
if (queryResults != null)
|
||||
{
|
||||
int idx = 0;
|
||||
for(ObjectName objName : queryResults)
|
||||
{
|
||||
String id = entry.getKey().toString()+(idx == 0 ? "" : ":"+idx);
|
||||
String name = queryString.equals(objName.toString()) ? "" : objName.toString();
|
||||
boolean repeat = Boolean.parseBoolean(values[2]);
|
||||
trigger.add(new JavaMonitorTrigger(objName, values[1], id, name, repeat));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
private int getClassID(final Object value)
|
||||
{
|
||||
if (value == null)
|
||||
return 0;
|
||||
|
||||
if (value instanceof Byte ||
|
||||
value instanceof Short ||
|
||||
value instanceof Integer ||
|
||||
value instanceof Long)
|
||||
return 1;
|
||||
|
||||
if (value instanceof Float ||
|
||||
value instanceof Double)
|
||||
return 2;
|
||||
|
||||
if (value instanceof Boolean)
|
||||
return 3;
|
||||
|
||||
return 4; // String
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
private String getServerIP()
|
||||
throws Exception
|
||||
{
|
||||
Socket s = null;
|
||||
try {
|
||||
if (getProperty("http.proxyHost") != null)
|
||||
{
|
||||
s = new Socket(getProperty("http.proxyHost"),
|
||||
parseInt(getProperty("http.proxyPort", "80")));
|
||||
}
|
||||
else
|
||||
{
|
||||
int port = 80;
|
||||
|
||||
URL url = new URL(_url);
|
||||
if (url.getPort() != -1) {
|
||||
port = url.getPort();
|
||||
}
|
||||
s = new Socket(url.getHost(), port);
|
||||
}
|
||||
return s.getLocalAddress().getHostAddress();
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
if (s != null)
|
||||
s.close();
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
LOG.ignore(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Integer getHttpPort()
|
||||
{
|
||||
Collection<ObjectName> connectors = null;
|
||||
MBeanServerConnection service;
|
||||
try
|
||||
{
|
||||
service = JMXMonitor.getServiceConnection();
|
||||
|
||||
connectors = service.queryNames(new ObjectName("org.eclipse.jetty.nio:type=selectchannelconnector,*"), null);
|
||||
if (connectors != null && connectors.size() > 0)
|
||||
{
|
||||
Integer lowest = Integer.MAX_VALUE;
|
||||
for (final ObjectName connector : connectors) {
|
||||
lowest = (Integer)service.getAttribute(connector, "port");
|
||||
}
|
||||
|
||||
if (lowest < Integer.MAX_VALUE)
|
||||
return lowest;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param param
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws NullPointerException
|
||||
* @throws MalformedObjectNameException
|
||||
*/
|
||||
private ObjectName[] queryNames(ObjectName param)
|
||||
throws IOException, MalformedObjectNameException
|
||||
{
|
||||
ObjectName[] result = null;
|
||||
|
||||
MBeanServerConnection connection = JMXMonitor.getServiceConnection();
|
||||
Set names = connection.queryNames(param, null);
|
||||
if (names != null && names.size() > 0)
|
||||
{
|
||||
result = new ObjectName[names.size()];
|
||||
|
||||
int idx = 0;
|
||||
for(Object name : names)
|
||||
{
|
||||
if (name instanceof ObjectName)
|
||||
result[idx++] = (ObjectName)name;
|
||||
else
|
||||
result[idx++] = new ObjectName(name.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private ObjectName[] queryNames(String param)
|
||||
throws IOException, MalformedObjectNameException
|
||||
{
|
||||
return queryNames(new ObjectName(param));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
// ========================================================================
|
||||
// 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 java.lang.management.ManagementFactory;
|
||||
import java.lang.management.ThreadInfo;
|
||||
import java.lang.management.ThreadMXBean;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.Security;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Derived from the JMX bean classes created by Kees Jan Koster for the java-monitor
|
||||
* J2EE probe http://code.google.com/p/java-monitor-probes/source/browse/.
|
||||
*
|
||||
* @author kjkoster <kjkoster@gmail.com>
|
||||
*/
|
||||
public class JavaMonitorTools
|
||||
{
|
||||
private static final ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
|
||||
|
||||
private static Method findDeadlockMethod = null;
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
findDeadlockMethod = ThreadMXBean.class.getMethod("findDeadlockedThreads");
|
||||
}
|
||||
catch (Exception ignored)
|
||||
{
|
||||
// this is a 1.5 JVM
|
||||
try
|
||||
{
|
||||
findDeadlockMethod = ThreadMXBean.class.getMethod("findMonitorDeadlockedThreads");
|
||||
}
|
||||
catch (SecurityException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
catch (NoSuchMethodException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ThreadInfo[] findDeadlock()
|
||||
throws IllegalAccessException, InvocationTargetException
|
||||
{
|
||||
final long[] threadIds = (long[])findDeadlockMethod.invoke(threadMXBean,(Object[])null);
|
||||
|
||||
if (threadIds == null || threadIds.length < 1)
|
||||
{
|
||||
// no deadlock, we're done
|
||||
return null;
|
||||
}
|
||||
|
||||
final ThreadInfo[] threads = threadMXBean.getThreadInfo(threadIds,Integer.MAX_VALUE);
|
||||
return threads;
|
||||
}
|
||||
|
||||
public String getDeadlockStacktraces()
|
||||
{
|
||||
try
|
||||
{
|
||||
final ThreadInfo[] threads = findDeadlock();
|
||||
if (threads == null)
|
||||
{
|
||||
// no deadlock, we're done
|
||||
return null;
|
||||
}
|
||||
|
||||
return stacktraces(threads,0);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
private static final int MAX_STACK = 10;
|
||||
|
||||
private String stacktraces(final ThreadInfo[] threads, final int i)
|
||||
{
|
||||
if (i >= threads.length)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
final ThreadInfo thread = threads[i];
|
||||
|
||||
final StringBuilder trace = new StringBuilder();
|
||||
for (int stack_i = 0; stack_i < Math.min(thread.getStackTrace().length,MAX_STACK); stack_i++)
|
||||
{
|
||||
if (stack_i == (MAX_STACK - 1))
|
||||
{
|
||||
trace.append(" ...");
|
||||
}
|
||||
else
|
||||
{
|
||||
trace.append(" at ").append(thread.getStackTrace()[stack_i]).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
return "\"" + thread.getThreadName() + "\", id " + thread.getThreadId() + " is " + thread.getThreadState() + " on " + thread.getLockName()
|
||||
+ ", owned by " + thread.getLockOwnerName() + ", id " + thread.getLockOwnerId() + "\n" + trace + "\n\n" + stacktraces(threads,i + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* We keep track of the last time we sampled the thread states.
|
||||
* It is a crude optimization to avoid having to query for the
|
||||
* threads states very often.
|
||||
*/
|
||||
private long lastSampled = 0L;
|
||||
|
||||
private final Map<Thread.State, Integer> states = new HashMap<Thread.State, Integer>();
|
||||
|
||||
public int getThreadsBlocked()
|
||||
{
|
||||
sampleThreads();
|
||||
|
||||
return states.get(Thread.State.BLOCKED);
|
||||
}
|
||||
|
||||
public int getThreadsNew()
|
||||
{
|
||||
sampleThreads();
|
||||
|
||||
return states.get(Thread.State.NEW);
|
||||
}
|
||||
|
||||
public int getThreadsTerminated()
|
||||
{
|
||||
sampleThreads();
|
||||
|
||||
return states.get(Thread.State.TERMINATED);
|
||||
}
|
||||
|
||||
public int getThreadsTimedWaiting()
|
||||
{
|
||||
sampleThreads();
|
||||
|
||||
return states.get(Thread.State.TIMED_WAITING);
|
||||
}
|
||||
|
||||
public int getThreadsWaiting()
|
||||
{
|
||||
sampleThreads();
|
||||
|
||||
return states.get(Thread.State.WAITING);
|
||||
}
|
||||
|
||||
public int getThreadsRunnable()
|
||||
{
|
||||
sampleThreads();
|
||||
|
||||
return states.get(Thread.State.RUNNABLE);
|
||||
}
|
||||
|
||||
private synchronized void sampleThreads()
|
||||
{
|
||||
if ((lastSampled + 50L) < System.currentTimeMillis())
|
||||
{
|
||||
lastSampled = System.currentTimeMillis();
|
||||
for (final Thread.State state : Thread.State.values())
|
||||
{
|
||||
states.put(state,0);
|
||||
}
|
||||
|
||||
for (final ThreadInfo thread : threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds()))
|
||||
{
|
||||
if (thread != null)
|
||||
{
|
||||
final Thread.State state = thread.getThreadState();
|
||||
states.put(state,states.get(state) + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
states.put(Thread.State.TERMINATED,states.get(Thread.State.TERMINATED) + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final String POLICY = "sun.net.InetAddressCachePolicy";
|
||||
|
||||
public int getCacheSeconds() throws ClassNotFoundException,
|
||||
IllegalAccessException, InvocationTargetException,
|
||||
NoSuchMethodException {
|
||||
final Class policy = Class.forName(POLICY);
|
||||
final Object returnValue = policy.getMethod("get", (Class[]) null)
|
||||
.invoke(null, (Object[]) null);
|
||||
Integer seconds = (Integer) returnValue;
|
||||
|
||||
return seconds.intValue();
|
||||
}
|
||||
|
||||
public int getCacheNegativeSeconds() throws ClassNotFoundException,
|
||||
IllegalAccessException, InvocationTargetException,
|
||||
NoSuchMethodException {
|
||||
final Class policy = Class.forName(POLICY);
|
||||
final Object returnValue = policy.getMethod("getNegative",
|
||||
(Class[]) null).invoke(null, (Object[]) null);
|
||||
Integer seconds = (Integer) returnValue;
|
||||
|
||||
return seconds.intValue();
|
||||
}
|
||||
|
||||
private static final String DEFAULT = "default";
|
||||
|
||||
private static final String SECURITY = "security";
|
||||
|
||||
private static final String SYSTEM = "system";
|
||||
|
||||
private static final String BOTH = "both";
|
||||
|
||||
private static final String SECURITY_TTL = "networkaddress.cache.ttl";
|
||||
|
||||
private static final String SYSTEM_TTL = "sun.net.inetaddr.ttl";
|
||||
|
||||
private static final String SECURITY_NEGATIVE_TTL = "networkaddress.cache.negative.ttl";
|
||||
|
||||
private static final String SYSTEM_NEGATIVE_TTL = "sun.net.inetaddr.negative.ttl";
|
||||
|
||||
public String getCacheTweakedFrom() {
|
||||
if (Security.getProperty(SECURITY_TTL) != null) {
|
||||
if (System.getProperty(SYSTEM_TTL) != null) {
|
||||
return BOTH;
|
||||
}
|
||||
|
||||
return SECURITY;
|
||||
}
|
||||
|
||||
if (System.getProperty(SYSTEM_TTL) != null) {
|
||||
return SYSTEM;
|
||||
}
|
||||
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
public String getCacheNegativeTweakedFrom() {
|
||||
if (Security.getProperty(SECURITY_NEGATIVE_TTL) != null) {
|
||||
if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) {
|
||||
return BOTH;
|
||||
}
|
||||
|
||||
return SECURITY;
|
||||
}
|
||||
|
||||
if (System.getProperty(SYSTEM_NEGATIVE_TTL) != null) {
|
||||
return SYSTEM;
|
||||
}
|
||||
|
||||
return DEFAULT;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
// ========================================================================
|
||||
// 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 javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.eclipse.jetty.monitor.triggers.AttrEventTrigger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class JavaMonitorTrigger <TYPE extends Comparable<TYPE>>
|
||||
extends AttrEventTrigger<TYPE>
|
||||
{
|
||||
private final String _id;
|
||||
private final String _name;
|
||||
private final boolean _dynamic;
|
||||
private int _count;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param nameObject
|
||||
* @param attributeName
|
||||
* @param id
|
||||
* @param dynamic
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public JavaMonitorTrigger(ObjectName nameObject, String attributeName, String id, String name, boolean dynamic)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
super(nameObject, attributeName);
|
||||
|
||||
_id = id;
|
||||
_name = name;
|
||||
_dynamic = dynamic;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable)
|
||||
*/
|
||||
@Override
|
||||
public boolean match(Comparable<TYPE> value)
|
||||
{
|
||||
return _dynamic ? true : (_count++ < 1);
|
||||
}
|
||||
|
||||
protected boolean getSaveAll()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getID()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNameString()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* ConsoleNotifier
|
||||
*
|
||||
* Provides a way to output notification messages to the server console
|
||||
*/
|
||||
public class ConsoleNotifier implements EventNotifier
|
||||
{
|
||||
String _messageFormat;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Constructs a new notifier with specified format string
|
||||
*
|
||||
* @param format the {@link java.util.Formatter format string}
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public ConsoleNotifier(String format)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if (format == null)
|
||||
throw new IllegalArgumentException("Message format cannot be null");
|
||||
|
||||
_messageFormat = format;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventNotifier#notify(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long)
|
||||
*/
|
||||
public void notify(EventTrigger trigger, EventState<?> state, long timestamp)
|
||||
{
|
||||
String output = String.format("%1$tF %1$tT.%1$tL:NOTIFY::", timestamp);
|
||||
|
||||
output += String.format(_messageFormat, state);
|
||||
|
||||
System.out.println(output);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* EventNotifier
|
||||
*
|
||||
* Interface for classes used to send event notifications
|
||||
*/
|
||||
public interface EventNotifier
|
||||
{
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* This method is called when a notification event is received by the containing object
|
||||
*
|
||||
* @param state an {@link org.eclipse.jetty.monitor.jmx.EventState event state}
|
||||
* @param timestamp time stamp of the event
|
||||
*/
|
||||
public void notify(EventTrigger trigger, EventState<?> state, long timestamp);
|
||||
}
|
|
@ -0,0 +1,202 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* EventState
|
||||
*
|
||||
* Holds the state of one or more {@link org.eclipse.jetty.monitor.jmx.EventTrigger event trigger}
|
||||
* instances to be used when sending notifications as well as executing the actions
|
||||
*/
|
||||
public class EventState<TYPE>
|
||||
{
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* State
|
||||
*
|
||||
* Holds the state of a single {@link org.eclipse.jetty.monitor.jmx.EventTrigger event trigger}
|
||||
*/
|
||||
public static class TriggerState<TYPE>
|
||||
{
|
||||
private final String _id;
|
||||
private final String _desc;
|
||||
private final TYPE _value;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct a trigger state
|
||||
*
|
||||
* @param id unique identification string of the associated event trigger
|
||||
* @param desc description of the associated event trigger
|
||||
* @param value effective value of the MXBean attribute (if applicable)
|
||||
*/
|
||||
public TriggerState(String id, String desc, TYPE value)
|
||||
{
|
||||
_id = id;
|
||||
_desc = desc;
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the identification string of associated event trigger
|
||||
*
|
||||
* @return unique identification string
|
||||
*/
|
||||
public String getID()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the description string set by event trigger
|
||||
*
|
||||
* @return description string
|
||||
*/
|
||||
public String getDescription()
|
||||
{
|
||||
return _desc;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the effective value of the MXBean attribute (if applicable)
|
||||
*
|
||||
* @return attribute value
|
||||
*/
|
||||
public TYPE getValue()
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return string representation of the state
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append(_desc);
|
||||
result.append('=');
|
||||
result.append(_value);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
|
||||
protected Map<String, TriggerState<TYPE>> _states;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Constructs an empty event state
|
||||
*/
|
||||
public EventState()
|
||||
{
|
||||
_states = new ConcurrentHashMap<String, TriggerState<TYPE>>();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Constructs an event state and adds a specified trigger state to it
|
||||
*
|
||||
* @param id unique identification string of the associated event trigger
|
||||
* @param desc description of the associated event trigger
|
||||
* @param value effective value of the MXBean attribute (if applicable)
|
||||
*/
|
||||
public EventState(String id, String desc, TYPE value)
|
||||
{
|
||||
this();
|
||||
|
||||
add(new TriggerState<TYPE>(id, desc, value));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Adds a trigger state to the event state
|
||||
*
|
||||
* @param state trigger state to add
|
||||
*/
|
||||
public void add(TriggerState<TYPE> state)
|
||||
{
|
||||
_states.put(state.getID(), state);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Adds a collection of trigger states to the event state
|
||||
*
|
||||
* @param entries collection of trigger states to add
|
||||
*/
|
||||
public void addAll(Collection<TriggerState<TYPE>> entries)
|
||||
{
|
||||
for (TriggerState<TYPE> entry : entries)
|
||||
{
|
||||
add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieves a single trigger state
|
||||
*
|
||||
* @param id unique identification string of the event trigger
|
||||
* @return requested trigger state or null if not found
|
||||
*/
|
||||
public TriggerState<TYPE> get(String id)
|
||||
{
|
||||
return _states.get(id);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieves a collection of all trigger states of the event state
|
||||
*
|
||||
* @return collection of the trigger states
|
||||
*/
|
||||
public Collection<TriggerState<TYPE>> values()
|
||||
{
|
||||
return Collections.unmodifiableCollection(_states.values());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns a string representation of the event state
|
||||
*
|
||||
* @return string representation of the event state
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
int cnt = 0;
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
for (TriggerState<TYPE> value : _states.values())
|
||||
{
|
||||
result.append(cnt++>0?"#":"");
|
||||
result.append(value.toString());
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
import static java.util.UUID.randomUUID;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* EventTrigger
|
||||
*
|
||||
* Abstract base class for all EventTrigger implementations.
|
||||
* Used to determine whether the necessary conditions for
|
||||
* triggering an event are present.
|
||||
*/
|
||||
public abstract class EventTrigger
|
||||
{
|
||||
private final String _id;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an event trigger
|
||||
*/
|
||||
public EventTrigger()
|
||||
{
|
||||
_id = randomUUID().toString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the identification string of the event trigger
|
||||
*
|
||||
* @return unique identification string
|
||||
*/
|
||||
public String getID()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Abstract method to verify if the event trigger conditions
|
||||
* are in the appropriate state for an event to be triggered
|
||||
*
|
||||
* @return true to trigger an event
|
||||
*/
|
||||
public abstract boolean match(long timestamp) throws Exception;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the event state associated with specified invocation
|
||||
* of the event trigger match method
|
||||
*
|
||||
* @param timestamp time stamp associated with invocation
|
||||
* @return event state or null if not found
|
||||
*/
|
||||
public abstract EventState<?> getState(long timestamp);
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* ConsoleNotifier
|
||||
*
|
||||
* Provides a way to output notification messages to a log file
|
||||
*/
|
||||
public class LoggingNotifier implements EventNotifier
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(LoggingNotifier.class);
|
||||
|
||||
String _messageFormat;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Constructs a new notifier with specified format string
|
||||
*
|
||||
* @param format the {@link java.util.Formatter format string}
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public LoggingNotifier(String format)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if (format == null)
|
||||
throw new IllegalArgumentException("Message format cannot be null");
|
||||
|
||||
_messageFormat = format;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventNotifier#notify(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long)
|
||||
*/
|
||||
public void notify(EventTrigger trigger, EventState<?> state, long timestamp)
|
||||
{
|
||||
String output = String.format(_messageFormat, state);
|
||||
|
||||
LOG.info(output);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
import static java.util.UUID.randomUUID;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* MonitorAction
|
||||
*
|
||||
* Abstract base class for all MonitorAction implementations.
|
||||
* Receives notification when an associated EventTrigger is matched.
|
||||
*/
|
||||
public abstract class MonitorAction
|
||||
extends NotifierGroup
|
||||
{
|
||||
public static final int DEFAULT_POLL_INTERVAL = 5000;
|
||||
|
||||
private final String _id;
|
||||
private final EventTrigger _trigger;
|
||||
private final EventNotifier _notifier;
|
||||
private final long _pollInterval;
|
||||
private final long _pollDelay;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Creates a new monitor action
|
||||
*
|
||||
* @param trigger event trigger to be associated with this action
|
||||
* @throws InvalidParameterException
|
||||
*/
|
||||
public MonitorAction(EventTrigger trigger)
|
||||
throws InvalidParameterException
|
||||
{
|
||||
this(trigger, null, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Creates a new monitor action
|
||||
*
|
||||
* @param trigger event trigger to be associated with this action
|
||||
* @param notifier event notifier to be associated with this action
|
||||
* @throws InvalidParameterException
|
||||
*/
|
||||
public MonitorAction(EventTrigger trigger, EventNotifier notifier)
|
||||
throws InvalidParameterException
|
||||
{
|
||||
this(trigger, notifier, 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Creates a new monitor action
|
||||
*
|
||||
* @param trigger event trigger to be associated with this action
|
||||
* @param notifier event notifier to be associated with this action
|
||||
* @param pollInterval interval for polling of the JMX server
|
||||
* @throws InvalidParameterException
|
||||
*/
|
||||
public MonitorAction(EventTrigger trigger, EventNotifier notifier, long pollInterval)
|
||||
throws InvalidParameterException
|
||||
{
|
||||
this(trigger, notifier, pollInterval, 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Creates a new monitor action
|
||||
*
|
||||
* @param trigger event trigger to be associated with this action
|
||||
* @param notifier event notifier to be associated with this action
|
||||
* @param pollInterval interval for polling of the JMX server
|
||||
* @param pollDelay delay before starting to poll the JMX server
|
||||
* @throws InvalidParameterException
|
||||
*/
|
||||
public MonitorAction(EventTrigger trigger, EventNotifier notifier, long pollInterval, long pollDelay)
|
||||
throws InvalidParameterException
|
||||
{
|
||||
if (trigger == null)
|
||||
throw new InvalidParameterException("Trigger cannot be null");
|
||||
|
||||
_id = randomUUID().toString();
|
||||
_trigger = trigger;
|
||||
_notifier = notifier;
|
||||
_pollInterval = pollInterval > 0 ? pollInterval : DEFAULT_POLL_INTERVAL;
|
||||
_pollDelay = pollDelay > 0 ? pollDelay : _pollInterval;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the identification string of the monitor action
|
||||
*
|
||||
* @return unique identification string
|
||||
*/
|
||||
|
||||
public final String getID()
|
||||
{
|
||||
return _id;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the event trigger of the monitor action
|
||||
*
|
||||
* @return associated event trigger
|
||||
*/
|
||||
public EventTrigger getTrigger()
|
||||
{
|
||||
return _trigger;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the poll interval
|
||||
*
|
||||
* @return interval value (in milliseconds)
|
||||
*/
|
||||
public long getPollInterval()
|
||||
{
|
||||
return _pollInterval;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Retrieve the poll delay
|
||||
* @return delay value (in milliseconds)
|
||||
*/
|
||||
public long getPollDelay()
|
||||
{
|
||||
return _pollDelay;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* This method will be called when event trigger associated
|
||||
* with this monitor action matches its conditions.
|
||||
*
|
||||
* @param timestamp time stamp of the event
|
||||
*/
|
||||
public final void doExecute(long timestamp)
|
||||
{
|
||||
EventState<?> state =_trigger.getState(timestamp);
|
||||
if (_notifier != null)
|
||||
_notifier.notify(_trigger, state, timestamp);
|
||||
execute(_trigger, state, timestamp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* This method will be called to allow subclass to execute
|
||||
* the desired action in response to the event.
|
||||
*
|
||||
* @param trigger event trigger associated with this monitor action
|
||||
* @param state event state associated with current invocation of event trigger
|
||||
* @param timestamp time stamp of the current invocation of event trigger
|
||||
*/
|
||||
public abstract void execute(EventTrigger trigger, EventState<?> state, long timestamp);
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* MonitorTask
|
||||
*
|
||||
* Invokes polling of the JMX server for the MBean attribute values
|
||||
* through executing timer task scheduled using java.util.Timer
|
||||
* at specified poll interval following a specified delay.
|
||||
*/
|
||||
public class MonitorTask extends TimerTask
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(MonitorTask.class);
|
||||
|
||||
private static Timer __timer = new Timer(true);
|
||||
private static ThreadPool _callback = new ExecutorThreadPool(4,64,60,TimeUnit.SECONDS);;
|
||||
private static Map<String,TimerTask> __tasks = new HashMap<String,TimerTask>();
|
||||
|
||||
private final MonitorAction _action;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Creates new instance of MonitorTask
|
||||
*
|
||||
* @param action instance of MonitorAction to use
|
||||
*/
|
||||
private MonitorTask(MonitorAction action)
|
||||
{
|
||||
_action = action;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Schedule new timer task for specified monitor action
|
||||
*
|
||||
* @param action monitor action
|
||||
*/
|
||||
public static void schedule(MonitorAction action)
|
||||
{
|
||||
TimerTask task = new MonitorTask(action);
|
||||
__timer.scheduleAtFixedRate(task,
|
||||
action.getPollDelay(),
|
||||
action.getPollInterval());
|
||||
|
||||
__tasks.put(action.getID(), task);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Cancel timer task for specified monitor action
|
||||
*
|
||||
* @param action monitor action
|
||||
*/
|
||||
public static void cancel(MonitorAction action)
|
||||
{
|
||||
TimerTask task = __tasks.remove(action.getID());
|
||||
if (task != null)
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* This method is invoked when poll interval has elapsed
|
||||
* to check if the event trigger conditions are satisfied
|
||||
* in order to fire event.
|
||||
*
|
||||
* @see java.util.TimerTask#run()
|
||||
*/
|
||||
@Override
|
||||
public final void run()
|
||||
{
|
||||
final long timestamp = System.currentTimeMillis();
|
||||
final EventTrigger trigger = _action.getTrigger();
|
||||
|
||||
_callback.dispatch(new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
if(trigger.match(timestamp))
|
||||
_action.doExecute(timestamp);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* NotifierGroup
|
||||
*
|
||||
* This class allows for grouping of the event notifiers
|
||||
*/
|
||||
public class NotifierGroup implements EventNotifier
|
||||
{
|
||||
private Set<EventNotifier> _group;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Create a notifier group
|
||||
*/
|
||||
public NotifierGroup()
|
||||
{
|
||||
_group = new HashSet<EventNotifier>();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve all event notifier associated with this group
|
||||
*
|
||||
* @return collection of event notifiers
|
||||
*/
|
||||
public Collection<EventNotifier> getNotifiers()
|
||||
{
|
||||
return Collections.unmodifiableSet(_group);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Add specified event notifier to event notifier group
|
||||
*
|
||||
* @param notifier event notifier to be added
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean addNotifier(EventNotifier notifier)
|
||||
{
|
||||
return _group.add(notifier);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Add a collection of event notifiers to event notifier group
|
||||
*
|
||||
* @param notifiers collection of event notifiers to be added
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean addNotifiers(Collection<EventNotifier> notifiers)
|
||||
{
|
||||
return _group.addAll(notifiers);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Remove event notifier from event notifier group
|
||||
*
|
||||
* @param notifier event notifier to be removed
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean removeNotifier(EventNotifier notifier)
|
||||
{
|
||||
return _group.remove(notifier);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Remove a collection of event notifiers from event notifier group
|
||||
*
|
||||
* @param notifiers collection of event notifiers to be removed
|
||||
* @return true if successful
|
||||
*/
|
||||
public boolean removeNotifiers(Collection<EventNotifier> notifiers)
|
||||
{
|
||||
return _group.removeAll(notifiers);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Invoke the notify() method of each of the notifiers in group
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventNotifier#notify(org.eclipse.jetty.monitor.jmx.EventTrigger, org.eclipse.jetty.monitor.jmx.EventState, long)
|
||||
*/
|
||||
public void notify(EventTrigger trigger, EventState<?> state, long timestamp)
|
||||
{
|
||||
for (EventNotifier notifier: _group)
|
||||
{
|
||||
notifier.notify(trigger, state, timestamp);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.remote.JMXConnector;
|
||||
import javax.management.remote.JMXConnectorFactory;
|
||||
import javax.management.remote.JMXConnectorServer;
|
||||
import javax.management.remote.JMXConnectorServerFactory;
|
||||
import javax.management.remote.JMXServiceURL;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* ServerConnection
|
||||
*
|
||||
* Provides ability to create a connection to either an external
|
||||
* JMX server, or a loopback connection to the internal one.
|
||||
*/
|
||||
public class ServiceConnection
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ServiceConnection.class);
|
||||
|
||||
private String _serviceUrl;
|
||||
private MBeanServer _server;
|
||||
private JMXConnectorServer _connectorServer;
|
||||
private JMXConnector _serverConnector;
|
||||
private MBeanServerConnection _serviceConnection;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct a loopback connection to an internal server
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public ServiceConnection()
|
||||
throws IOException
|
||||
{
|
||||
this(null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct a connection to specified server
|
||||
*
|
||||
* @param url URL of JMX server
|
||||
* @throws IOException
|
||||
*/
|
||||
public ServiceConnection(String url)
|
||||
throws IOException
|
||||
{
|
||||
_serviceUrl = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an external URL for the JMX server
|
||||
*
|
||||
* @return service URL
|
||||
*/
|
||||
public String getServiceUrl()
|
||||
{
|
||||
return _serviceUrl;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve a connection to MBean server
|
||||
*
|
||||
* @return connection to MBean server
|
||||
*/
|
||||
public MBeanServerConnection getConnection()
|
||||
{
|
||||
return _serviceConnection;
|
||||
}
|
||||
|
||||
public void connect()
|
||||
throws IOException
|
||||
{
|
||||
if (_serviceConnection == null)
|
||||
{
|
||||
if (_serviceUrl == null)
|
||||
openLoopbackConnection();
|
||||
else
|
||||
openServerConnection(_serviceUrl);
|
||||
}
|
||||
}
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Open a loopback connection to local JMX server
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
private void openLoopbackConnection()
|
||||
throws IOException
|
||||
{
|
||||
_server = ManagementFactory.getPlatformMBeanServer();
|
||||
|
||||
JMXServiceURL serviceUrl = new JMXServiceURL("service:jmx:rmi://");
|
||||
_connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serviceUrl, null, _server);
|
||||
_connectorServer.start();
|
||||
|
||||
_serviceUrl = _connectorServer.getAddress().toString();
|
||||
|
||||
_serverConnector = JMXConnectorFactory.connect(_connectorServer.getAddress());
|
||||
_serviceConnection = _serverConnector.getMBeanServerConnection();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Open a connection to remote JMX server
|
||||
*
|
||||
* @param url
|
||||
* @throws IOException
|
||||
*/
|
||||
private void openServerConnection(String url)
|
||||
throws IOException
|
||||
{
|
||||
_serviceUrl = url;
|
||||
|
||||
JMXServiceURL serviceUrl = new JMXServiceURL(_serviceUrl);
|
||||
_serverConnector = JMXConnectorFactory.connect(serviceUrl);
|
||||
_serviceConnection = _serverConnector.getMBeanServerConnection();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Close the connections
|
||||
*/
|
||||
public void disconnect()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_serverConnector != null)
|
||||
{
|
||||
_serverConnector.close();
|
||||
_serviceConnection = null;
|
||||
}
|
||||
if (_connectorServer != null)
|
||||
{
|
||||
_connectorServer.stop();
|
||||
_connectorServer = null;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
// ========================================================================
|
||||
// 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.jmx;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class SimpleAction extends MonitorAction
|
||||
{
|
||||
public SimpleAction(EventTrigger trigger, EventNotifier notifier, long pollInterval)
|
||||
throws InvalidParameterException
|
||||
{
|
||||
super(trigger,notifier,pollInterval);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
System.out.printf("Action time: %tc%n", timestamp);
|
||||
}
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
// ========================================================================
|
||||
|
||||
|
||||
package org.eclipse.jetty.monitor;
|
||||
package org.eclipse.jetty.monitor.thread;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
|
@ -12,7 +12,7 @@
|
|||
// ========================================================================
|
||||
|
||||
|
||||
package org.eclipse.jetty.monitor;
|
||||
package org.eclipse.jetty.monitor.thread;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
|
@ -0,0 +1,164 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.monitor.jmx.EventState;
|
||||
import org.eclipse.jetty.monitor.jmx.EventTrigger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* AggregateEventTrigger
|
||||
*
|
||||
* EventTrigger aggregation that executes every aggregated event
|
||||
* triggers in left to right order, and returns match if any one
|
||||
* of them have returned match.
|
||||
*/
|
||||
public class AggregateEventTrigger extends EventTrigger
|
||||
{
|
||||
protected final List<EventTrigger> _triggers;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an event trigger
|
||||
*/
|
||||
public AggregateEventTrigger()
|
||||
{
|
||||
_triggers = new ArrayList<EventTrigger>();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an event trigger and associate the list
|
||||
* of event triggers to be aggregated by this trigger
|
||||
*
|
||||
* @param triggers list of event triggers to add
|
||||
*/
|
||||
public AggregateEventTrigger(List<EventTrigger> triggers)
|
||||
{
|
||||
_triggers = new ArrayList<EventTrigger>(triggers);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an event trigger and associate the array
|
||||
* of event triggers to be aggregated by this trigger
|
||||
*
|
||||
* @param triggers list of event triggers to add
|
||||
*/
|
||||
public AggregateEventTrigger(EventTrigger... triggers)
|
||||
{
|
||||
_triggers = Arrays.asList(triggers);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param trigger
|
||||
*/
|
||||
public void add(EventTrigger trigger)
|
||||
{
|
||||
_triggers.add(trigger);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param triggers
|
||||
*/
|
||||
public void addAll(List<EventTrigger> triggers)
|
||||
{
|
||||
_triggers.addAll(triggers);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param triggers
|
||||
*/
|
||||
public void addAll(EventTrigger... triggers)
|
||||
{
|
||||
_triggers.addAll(Arrays.asList(triggers));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the event state associated with specified invocation
|
||||
* of the event trigger match method. This event trigger retrieves
|
||||
* the combined event state of all aggregated event triggers.
|
||||
*
|
||||
* @param timestamp time stamp associated with invocation
|
||||
* @return event state or null if not found
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventTrigger#getState(long)
|
||||
*/
|
||||
@Override
|
||||
public EventState getState(long timestamp)
|
||||
{
|
||||
EventState state = new EventState();
|
||||
|
||||
for (EventTrigger trigger : _triggers)
|
||||
{
|
||||
EventState subState = trigger.getState(timestamp);
|
||||
if (subState != null)
|
||||
{
|
||||
state.addAll(subState.values());
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventTrigger#match(long)
|
||||
*/
|
||||
@Override
|
||||
public boolean match(long timestamp) throws Exception
|
||||
{
|
||||
boolean result = false;
|
||||
for(EventTrigger trigger : _triggers)
|
||||
{
|
||||
result = trigger.match(timestamp) ? true : result;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "AND(triger1,trigger2,...)".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
int cnt = 0;
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append("ANY(");
|
||||
for (EventTrigger trigger : _triggers)
|
||||
{
|
||||
result.append(cnt++ > 0 ? "," : "");
|
||||
result.append(trigger);
|
||||
}
|
||||
result.append(')');
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.monitor.jmx.EventState;
|
||||
import org.eclipse.jetty.monitor.jmx.EventTrigger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* AndEventTrigger
|
||||
*
|
||||
* EventTrigger aggregation using logical AND operation
|
||||
* that executes matching of the aggregated event triggers
|
||||
* in left to right order
|
||||
*/
|
||||
public class AndEventTrigger extends EventTrigger
|
||||
{
|
||||
protected final List<EventTrigger> _triggers;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an event trigger and associate the list
|
||||
* of event triggers to be aggregated by this trigger
|
||||
*
|
||||
* @param triggers list of event triggers to add
|
||||
*/
|
||||
public AndEventTrigger(List<EventTrigger> triggers)
|
||||
{
|
||||
_triggers = triggers;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an event trigger and associate the array
|
||||
* of event triggers to be aggregated by this trigger
|
||||
*
|
||||
* @param triggers array of event triggers to add
|
||||
*/
|
||||
public AndEventTrigger(EventTrigger... triggers)
|
||||
{
|
||||
_triggers = Arrays.asList(triggers);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Verify if the event trigger conditions are in the
|
||||
* appropriate state for an event to be triggered.
|
||||
* This event trigger will match if all aggregated
|
||||
* event triggers would return a match.
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventTrigger#match(long)
|
||||
*/
|
||||
public boolean match(long timestamp)
|
||||
throws Exception
|
||||
{
|
||||
for(EventTrigger trigger : _triggers)
|
||||
{
|
||||
if (!trigger.match(timestamp))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the event state associated with specified invocation
|
||||
* of the event trigger match method. This event trigger retrieves
|
||||
* the combined event state of all aggregated event triggers.
|
||||
*
|
||||
* @param timestamp time stamp associated with invocation
|
||||
* @return event state or null if not found
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventTrigger#getState(long)
|
||||
*/
|
||||
@Override
|
||||
public EventState getState(long timestamp)
|
||||
{
|
||||
EventState state = new EventState();
|
||||
|
||||
for (EventTrigger trigger : _triggers)
|
||||
{
|
||||
EventState subState = trigger.getState(timestamp);
|
||||
state.addAll(subState.values());
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "AND(triger1,trigger2,...)".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
int cnt = 0;
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append("AND(");
|
||||
for (EventTrigger trigger : _triggers)
|
||||
{
|
||||
result.append(cnt++ > 0 ? "," : "");
|
||||
result.append(trigger);
|
||||
}
|
||||
result.append(')');
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
import javax.management.openmbean.CompositeData;
|
||||
|
||||
import org.eclipse.jetty.monitor.JMXMonitor;
|
||||
import org.eclipse.jetty.monitor.jmx.EventState;
|
||||
import org.eclipse.jetty.monitor.jmx.EventTrigger;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* AttrEventTrigger
|
||||
*
|
||||
* Event trigger that polls a value of an MXBean attribute
|
||||
* and matches every invocation of this trigger. It can be
|
||||
* used to send notifications of the value of an attribute
|
||||
* of the MXBean being polled at a certain interval, or as
|
||||
* a base class for the event triggers that match the
|
||||
* value of an attribute of the MXBean being polled against
|
||||
* some specified criteria.
|
||||
*/
|
||||
public class AttrEventTrigger<TYPE extends Comparable<TYPE>>
|
||||
extends EventTrigger
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(AttrEventTrigger.class);
|
||||
|
||||
private final ObjectName _nameObject;
|
||||
|
||||
protected final String _objectName;
|
||||
protected final String _attributeName;
|
||||
protected Map<Long, EventState<TYPE>> _states;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct event trigger and specify the MXBean attribute
|
||||
* that will be polled by this event trigger.
|
||||
*
|
||||
* @param objectName object name of an MBean to be polled
|
||||
* @param attributeName name of an MBean attribute to be polled
|
||||
*
|
||||
* @throws MalformedObjectNameException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public AttrEventTrigger(String objectName, String attributeName)
|
||||
throws MalformedObjectNameException, IllegalArgumentException
|
||||
{
|
||||
if (objectName == null)
|
||||
throw new IllegalArgumentException("Object name cannot be null");
|
||||
if (attributeName == null)
|
||||
throw new IllegalArgumentException("Attribute name cannot be null");
|
||||
|
||||
_states = new ConcurrentHashMap<Long,EventState<TYPE>>();
|
||||
|
||||
_objectName = objectName;
|
||||
_attributeName = attributeName;
|
||||
|
||||
_nameObject = new ObjectName(_objectName);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct event trigger and specify the MXBean attribute
|
||||
* that will be polled by this event trigger.
|
||||
*
|
||||
* @param nameObject object name of an MBean to be polled
|
||||
* @param attributeName name of an MBean attribute to be polled
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public AttrEventTrigger(ObjectName nameObject, String attributeName)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if (nameObject == null)
|
||||
throw new IllegalArgumentException("Object name cannot be null");
|
||||
if (attributeName == null)
|
||||
throw new IllegalArgumentException("Attribute name cannot be null");
|
||||
|
||||
_states = new ConcurrentHashMap<Long,EventState<TYPE>>();
|
||||
|
||||
_objectName = nameObject.toString();
|
||||
_attributeName = attributeName;
|
||||
|
||||
_nameObject = nameObject;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Verify if the event trigger conditions are in the
|
||||
* appropriate state for an event to be triggered.
|
||||
* This event trigger uses the match(Comparable<TYPE>)
|
||||
* method to compare the value of the MXBean attribute
|
||||
* to the conditions specified by the subclasses.
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventTrigger#match(long)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public final boolean match(long timestamp)
|
||||
throws Exception
|
||||
{
|
||||
MBeanServerConnection serverConnection = JMXMonitor.getServiceConnection();
|
||||
|
||||
TYPE value = null;
|
||||
try
|
||||
{
|
||||
int pos = _attributeName.indexOf('.');
|
||||
if (pos < 0)
|
||||
value = (TYPE)serverConnection.getAttribute(_nameObject,_attributeName);
|
||||
else
|
||||
value = getValue((CompositeData)serverConnection.getAttribute(_nameObject, _attributeName.substring(0, pos)),
|
||||
_attributeName.substring(pos+1));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
|
||||
boolean result = false;
|
||||
if (value != null)
|
||||
{
|
||||
result = match(value);
|
||||
|
||||
if (result || getSaveAll())
|
||||
{
|
||||
_states.put(timestamp,
|
||||
new EventState<TYPE>(this.getID(), this.getNameString(), value));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Verify if the event trigger conditions are in the
|
||||
* appropriate state for an event to be triggered.
|
||||
* Allows subclasses to override the default behavior
|
||||
* that matches every invocation of this trigger
|
||||
*/
|
||||
public boolean match(Comparable<TYPE> value)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the event state associated with specified invocation
|
||||
* of the event trigger match method.
|
||||
*
|
||||
* @param timestamp time stamp associated with invocation
|
||||
* @return event state or null if not found
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventTrigger#getState(long)
|
||||
*/
|
||||
@Override
|
||||
public final EventState<TYPE> getState(long timestamp)
|
||||
{
|
||||
return _states.get(timestamp);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "[object_name:attribute_name]".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
return getNameString();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "[object_name:attribute_name]". Allows
|
||||
* subclasses to override the name string used to identify
|
||||
* this event trigger in the event state object as well as
|
||||
* string representation of the subclasses.
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*/
|
||||
protected String getNameString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append('[');
|
||||
result.append(_objectName);
|
||||
result.append(":");
|
||||
result.append(_attributeName);
|
||||
result.append("]");
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
protected boolean getSaveAll()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
protected TYPE getValue(CompositeData compValue, String fieldName)
|
||||
{
|
||||
int pos = fieldName.indexOf('.');
|
||||
if (pos < 0)
|
||||
return (TYPE)compValue.get(fieldName);
|
||||
else
|
||||
return getValue((CompositeData)compValue.get(fieldName.substring(0, pos)),
|
||||
fieldName.substring(pos+1));
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import javax.management.MalformedObjectNameException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* EqualToAttrEventTrigger
|
||||
*
|
||||
* Event trigger that polls a value of an MXBean attribute and
|
||||
* checks if it is equal to specified value.
|
||||
*/
|
||||
public class EqualToAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
|
||||
{
|
||||
protected final TYPE _value;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct event trigger and specify the MXBean attribute
|
||||
* that will be polled by this event trigger as well as the
|
||||
* target value of the attribute.
|
||||
*
|
||||
* @param objectName object name of an MBean to be polled
|
||||
* @param attributeName name of an MBean attribute to be polled
|
||||
* @param value target value of the attribute
|
||||
*
|
||||
* @throws MalformedObjectNameException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public EqualToAttrEventTrigger(String objectName, String attributeName, TYPE value)
|
||||
throws MalformedObjectNameException, IllegalArgumentException
|
||||
{
|
||||
super(objectName,attributeName);
|
||||
|
||||
if (value == null)
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
|
||||
_value = value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Compare the value of the MXBean attribute being polling
|
||||
* to check if it is equal to the specified value.
|
||||
*/
|
||||
@Override
|
||||
public boolean match(Comparable<TYPE> value)
|
||||
{
|
||||
return (value.compareTo(_value) == 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "name=value".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append(getNameString());
|
||||
result.append("==");
|
||||
result.append(_value);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import javax.management.MalformedObjectNameException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* GreaterThanAttrEventTrigger
|
||||
*
|
||||
* Event trigger that polls a value of an MXBean attribute and
|
||||
* checks if it is greater than specified min value.
|
||||
*/
|
||||
public class GreaterThanAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
|
||||
{
|
||||
protected final TYPE _min;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct event trigger and specify the MXBean attribute
|
||||
* that will be polled by this event trigger as well as min
|
||||
* value of the attribute.
|
||||
*
|
||||
* @param objectName object name of an MBean to be polled
|
||||
* @param attributeName name of an MBean attribute to be polled
|
||||
* @param min minimum value of the attribute
|
||||
*
|
||||
* @throws MalformedObjectNameException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public GreaterThanAttrEventTrigger(String objectName, String attributeName, TYPE min)
|
||||
throws MalformedObjectNameException, IllegalArgumentException
|
||||
{
|
||||
super(objectName,attributeName);
|
||||
|
||||
if (min == null)
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
|
||||
_min = min;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Compare the value of the MXBean attribute being polling
|
||||
* to check if it is greater than the min value.
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable)
|
||||
*/
|
||||
@Override
|
||||
public boolean match(Comparable<TYPE> value)
|
||||
{
|
||||
return (value.compareTo(_min) > 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "min<name".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append(_min);
|
||||
result.append("<");
|
||||
result.append(getNameString());
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import javax.management.MalformedObjectNameException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* GreaterThanOrEqualToAttrEventTrigger
|
||||
*
|
||||
* Event trigger that polls a value of an MXBean attribute and
|
||||
* checks if it is greater than or equal to specified min value.
|
||||
*/
|
||||
public class GreaterThanOrEqualToAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
|
||||
{
|
||||
protected final TYPE _min;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct event trigger and specify the MXBean attribute
|
||||
* that will be polled by this event trigger as well as min
|
||||
* value of the attribute.
|
||||
*
|
||||
* @param objectName object name of an MBean to be polled
|
||||
* @param attributeName name of an MBean attribute to be polled
|
||||
* @param min minimum value of the attribute
|
||||
*
|
||||
* @throws MalformedObjectNameException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public GreaterThanOrEqualToAttrEventTrigger(String objectName, String attributeName, TYPE min)
|
||||
throws MalformedObjectNameException, IllegalArgumentException
|
||||
{
|
||||
super(objectName,attributeName);
|
||||
|
||||
if (min == null)
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
|
||||
_min = min;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Compare the value of the MXBean attribute being polling
|
||||
* to check if it is greater than or equal to the min value.
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable)
|
||||
*/
|
||||
@Override
|
||||
public boolean match(Comparable<TYPE> value)
|
||||
{
|
||||
return (value.compareTo(_min) >= 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "min<=name".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append(_min);
|
||||
result.append("<=");
|
||||
result.append(getNameString());
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import javax.management.MalformedObjectNameException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* LessThanAttrEventTrigger
|
||||
*
|
||||
* Event trigger that polls a value of an MXBean attribute and
|
||||
* checks if it is greater than specified max value.
|
||||
*/
|
||||
public class LessThanAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
|
||||
{
|
||||
protected final TYPE _max;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct event trigger and specify the MXBean attribute
|
||||
* that will be polled by this event trigger as well as max
|
||||
* value of the attribute.
|
||||
*
|
||||
* @param objectName object name of an MBean to be polled
|
||||
* @param attributeName name of an MBean attribute to be polled
|
||||
* @param max maximum value of the attribute
|
||||
*
|
||||
* @throws MalformedObjectNameException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public LessThanAttrEventTrigger(String objectName, String attributeName, TYPE max)
|
||||
throws MalformedObjectNameException, IllegalArgumentException
|
||||
{
|
||||
super(objectName,attributeName);
|
||||
|
||||
if (max == null)
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
|
||||
_max = max;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Compare the value of the MXBean attribute being polling
|
||||
* to check if it is less than the min value.
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable)
|
||||
*/
|
||||
@Override
|
||||
public boolean match(Comparable<TYPE> value)
|
||||
{
|
||||
return (value.compareTo(_max) < 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "name<max".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append(getNameString());
|
||||
result.append("<");
|
||||
result.append(_max);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import javax.management.MalformedObjectNameException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* LessThanOrEqualToAttrEventTrigger
|
||||
*
|
||||
* Event trigger that polls a value of an MXBean attribute and
|
||||
* checks if it is less than or equal to specified max value.
|
||||
*/
|
||||
public class LessThanOrEqualToAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
|
||||
{
|
||||
protected final TYPE _max;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct event trigger and specify the MXBean attribute
|
||||
* that will be polled by this event trigger as well as max
|
||||
* value of the attribute.
|
||||
*
|
||||
* @param objectName object name of an MBean to be polled
|
||||
* @param attributeName name of an MBean attribute to be polled
|
||||
* @param max maximum value of the attribute
|
||||
*
|
||||
* @throws MalformedObjectNameException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public LessThanOrEqualToAttrEventTrigger(String objectName, String attributeName, TYPE max)
|
||||
throws MalformedObjectNameException, IllegalArgumentException
|
||||
{
|
||||
super(objectName,attributeName);
|
||||
|
||||
if (max == null)
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
|
||||
_max = max;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Compare the value of the MXBean attribute being polling
|
||||
* to check if it is less than or equal to the max value.
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable)
|
||||
*/
|
||||
@Override
|
||||
public boolean match(Comparable<TYPE> value)
|
||||
{
|
||||
return (value.compareTo(_max) <= 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "name<=max".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append(getNameString());
|
||||
result.append("<=");
|
||||
result.append(_max);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.monitor.jmx.EventState;
|
||||
import org.eclipse.jetty.monitor.jmx.EventTrigger;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* AndEventTrigger
|
||||
*
|
||||
* EventTrigger aggregation using logical OR operation
|
||||
* that executes matching of the aggregated event triggers
|
||||
* in left to right order
|
||||
*/
|
||||
public class OrEventTrigger
|
||||
extends EventTrigger
|
||||
{
|
||||
private final List<EventTrigger> _triggers;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an event trigger and associate the list
|
||||
* of event triggers to be aggregated by this trigger
|
||||
*
|
||||
* @param triggers list of event triggers to add
|
||||
*/
|
||||
public OrEventTrigger(List<EventTrigger> triggers)
|
||||
{
|
||||
_triggers = triggers;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct an event trigger and associate the array
|
||||
* of event triggers to be aggregated by this trigger
|
||||
*
|
||||
* @param triggers array of event triggers to add
|
||||
*/
|
||||
public OrEventTrigger(EventTrigger... triggers)
|
||||
{
|
||||
_triggers = Arrays.asList(triggers);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Verify if the event trigger conditions are in the
|
||||
* appropriate state for an event to be triggered.
|
||||
* This event trigger will match if any of aggregated
|
||||
* event triggers would return a match.
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventTrigger#match(long)
|
||||
*/
|
||||
public boolean match(long timestamp)
|
||||
throws Exception
|
||||
{
|
||||
for(EventTrigger trigger : _triggers)
|
||||
{
|
||||
if (trigger.match(timestamp))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Retrieve the event state associated with specified invocation
|
||||
* of the event trigger match method. This event trigger retrieves
|
||||
* the combined event state of all aggregated event triggers.
|
||||
*
|
||||
* @param timestamp time stamp associated with invocation
|
||||
* @return event state or null if not found
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.jmx.EventTrigger#getState(long)
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public EventState getState(long timestamp)
|
||||
{
|
||||
EventState state = new EventState();
|
||||
|
||||
for (EventTrigger trigger : _triggers)
|
||||
{
|
||||
EventState subState = trigger.getState(timestamp);
|
||||
if (subState!=null)
|
||||
{
|
||||
state.addAll(subState.values());
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "OR(triger1,trigger2,...)".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
int cnt = 0;
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append("OR(");
|
||||
for (EventTrigger trigger : _triggers)
|
||||
{
|
||||
result.append(cnt++ > 0 ? "," : "");
|
||||
result.append(trigger);
|
||||
}
|
||||
result.append(')');
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import javax.management.MalformedObjectNameException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* RangeAttrEventTrigger
|
||||
*
|
||||
* Event trigger that polls a value of an MXBean attribute and
|
||||
* checks if it is in a range from specified min value to
|
||||
* specified max value.
|
||||
*/
|
||||
public class RangeAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
|
||||
{
|
||||
protected final TYPE _min;
|
||||
protected final TYPE _max;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct event trigger and specify the MXBean attribute
|
||||
* that will be polled by this event trigger as well as min
|
||||
* and max value of the attribute.
|
||||
*
|
||||
* @param objectName object name of an MBean to be polled
|
||||
* @param attributeName name of an MBean attribute to be polled
|
||||
* @param min minimum value of the attribute
|
||||
* @param max maximum value of the attribute
|
||||
*
|
||||
* @throws MalformedObjectNameException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public RangeAttrEventTrigger(String objectName, String attributeName,TYPE min, TYPE max)
|
||||
throws MalformedObjectNameException, IllegalArgumentException
|
||||
{
|
||||
super(objectName,attributeName);
|
||||
|
||||
if (min == null)
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
if (max == null)
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
|
||||
_min = min;
|
||||
_max = max;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Compare the value of the MXBean attribute being polling
|
||||
* to check if it is in a range from specified min value to
|
||||
* specified max value.
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable)
|
||||
*/
|
||||
@Override
|
||||
public boolean match(Comparable<TYPE> value)
|
||||
{
|
||||
return (value.compareTo(_min) > 0) &&(value.compareTo(_max) < 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "min<name<max".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append(_min);
|
||||
result.append("<");
|
||||
result.append(getNameString());
|
||||
result.append("<");
|
||||
result.append(_max);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
// ========================================================================
|
||||
// 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.triggers;
|
||||
|
||||
import javax.management.MalformedObjectNameException;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* RangeInclAttrEventTrigger
|
||||
*
|
||||
* Event trigger that polls a value of an MXBean attribute and
|
||||
* checks if it is in a range from specified min value to
|
||||
* specified max value including the range bounds.
|
||||
*/
|
||||
public class RangeInclAttrEventTrigger<TYPE extends Comparable<TYPE>> extends AttrEventTrigger<TYPE>
|
||||
{
|
||||
protected final TYPE _min;
|
||||
protected final TYPE _max;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Construct event trigger and specify the MXBean attribute
|
||||
* that will be polled by this event trigger as well as min
|
||||
* and max value of the attribute.
|
||||
*
|
||||
* @param objectName object name of an MBean to be polled
|
||||
* @param attributeName name of an MBean attribute to be polled
|
||||
* @param min minimum value of the attribute
|
||||
* @param max maximum value of the attribute
|
||||
*
|
||||
* @throws MalformedObjectNameException
|
||||
* @throws IllegalArgumentException
|
||||
*/
|
||||
public RangeInclAttrEventTrigger(String objectName, String attributeName,TYPE min, TYPE max)
|
||||
throws MalformedObjectNameException, IllegalArgumentException
|
||||
{
|
||||
super(objectName,attributeName);
|
||||
|
||||
if (min == null)
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
if (max == null)
|
||||
throw new IllegalArgumentException("Value cannot be null");
|
||||
|
||||
_min = min;
|
||||
_max = max;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Compare the value of the MXBean attribute being polling
|
||||
* to check if it is in a range from specified min value to
|
||||
* specified max value including the range bounds.
|
||||
*
|
||||
* @see org.eclipse.jetty.monitor.triggers.AttrEventTrigger#match(java.lang.Comparable)
|
||||
*/
|
||||
@Override
|
||||
public boolean match(Comparable<TYPE> value)
|
||||
{
|
||||
return (value.compareTo(_min) >= 0) &&(value.compareTo(_max) <= 0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Returns the string representation of this event trigger
|
||||
* in the format "min<=name<=max".
|
||||
*
|
||||
* @return string representation of the event trigger
|
||||
*
|
||||
* @see java.lang.Object#toString()
|
||||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
result.append(_min);
|
||||
result.append("<=");
|
||||
result.append(getNameString());
|
||||
result.append("<=");
|
||||
result.append(_max);
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
JavaMonitorTools: Retrieves additional information required by java-monitor
|
||||
DeadlockStacktraces: RO:Detailed report on the deadlocked threads.
|
||||
ThreadsNew: RO:Number of new threads
|
||||
ThreadsRunnable: RO:Number of runnable threads
|
||||
ThreadsBlocked: RO:Number of blocked threads
|
||||
ThreadsWaiting: RO:Number of waiting threads
|
||||
ThreadsTimedWaiting: RO:Number of sleeping and waiting threads
|
||||
ThreadsTerminated: RO:Number of terminated threads
|
||||
CacheSeconds: RO:Amount of time successful DNS queries are cached for
|
||||
CacheTweakedFrom: RO:Cache policy for successful DNS lookups was changed from the hard-coded default
|
||||
CacheNegativeSeconds: RO:Amount of time failed DNS queries are cached for
|
||||
CacheNegativeTweakedFrom: RO:Cache policy for failed DNS lookups was changed from the hard-coded default
|
|
@ -0,0 +1,509 @@
|
|||
// ========================================================================
|
||||
// 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 static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.ContentExchange;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.client.security.Realm;
|
||||
import org.eclipse.jetty.client.security.SimpleRealmResolver;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.jmx.MBeanContainer;
|
||||
import org.eclipse.jetty.monitor.JMXMonitor;
|
||||
import org.eclipse.jetty.monitor.jmx.ConsoleNotifier;
|
||||
import org.eclipse.jetty.monitor.jmx.EventNotifier;
|
||||
import org.eclipse.jetty.monitor.jmx.EventState;
|
||||
import org.eclipse.jetty.monitor.jmx.EventTrigger;
|
||||
import org.eclipse.jetty.monitor.jmx.MonitorAction;
|
||||
import org.eclipse.jetty.monitor.jmx.EventState.TriggerState;
|
||||
import org.eclipse.jetty.monitor.triggers.AndEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.AttrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.EqualToAttrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.GreaterThanAttrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.GreaterThanOrEqualToAttrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.LessThanAttrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.LessThanOrEqualToAttrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.OrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.RangeAttrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.RangeInclAttrEventTrigger;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class AttrEventTriggerTest
|
||||
{
|
||||
private Server _server;
|
||||
private TestHandler _handler;
|
||||
private RequestCounter _counter;
|
||||
private JMXMonitor _monitor;
|
||||
private HttpClient _client;
|
||||
private String _requestUrl;
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
File docRoot = new File("target/test-output/docroot/");
|
||||
docRoot.mkdirs();
|
||||
docRoot.deleteOnExit();
|
||||
|
||||
System.setProperty("org.eclipse.jetty.util.log.DEBUG","");
|
||||
_server = new Server();
|
||||
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
_server.addConnector(connector);
|
||||
|
||||
_handler = new TestHandler();
|
||||
_server.setHandler(_handler);
|
||||
|
||||
MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer();
|
||||
MBeanContainer mBeanContainer = new MBeanContainer(mBeanServer);
|
||||
mBeanContainer.addBean(Log.getLog());
|
||||
|
||||
_counter = _handler.getRequestCounter();
|
||||
mBeanContainer.addBean(_counter);
|
||||
|
||||
_server.addBean(mBeanContainer);
|
||||
_server.getContainer().addEventListener(mBeanContainer);
|
||||
_server.start();
|
||||
|
||||
startClient(null);
|
||||
|
||||
_monitor = new JMXMonitor();
|
||||
|
||||
int port = _server.getConnectors()[0].getLocalPort();
|
||||
_requestUrl = "http://localhost:"+port+ "/";
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown()
|
||||
throws Exception
|
||||
{
|
||||
stopClient();
|
||||
|
||||
if (_server != null)
|
||||
{
|
||||
_server.stop();
|
||||
_server = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoCondition()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
|
||||
AttrEventTrigger<Long> trigger =
|
||||
new AttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter");
|
||||
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(1,requestCount);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqual_TRUE()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testValue = 5;
|
||||
|
||||
EqualToAttrEventTrigger<Long> trigger =
|
||||
new EqualToAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",testValue);
|
||||
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(testValue);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEqual_FALSE()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testValue = 11;
|
||||
|
||||
EqualToAttrEventTrigger<Long> trigger =
|
||||
new EqualToAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testValue);
|
||||
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet();
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLowerLimit()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testRangeLow = 5;
|
||||
|
||||
GreaterThanAttrEventTrigger<Long> trigger =
|
||||
new GreaterThanAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeLow);
|
||||
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(6,10);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLowerLimitIncl()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testRangeLow = 5;
|
||||
|
||||
GreaterThanOrEqualToAttrEventTrigger<Long> trigger =
|
||||
new GreaterThanOrEqualToAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeLow);
|
||||
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(5,10);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpperLimit()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testRangeHigh = 5;
|
||||
|
||||
LessThanAttrEventTrigger<Long> trigger =
|
||||
new LessThanAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeHigh);
|
||||
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(1,4);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUpperLimitIncl()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testRangeHigh = 5;
|
||||
|
||||
LessThanOrEqualToAttrEventTrigger<Long> trigger =
|
||||
new LessThanOrEqualToAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeHigh);
|
||||
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(1,5);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeInclusive()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testRangeLow = 3;
|
||||
long testRangeHigh = 8;
|
||||
|
||||
RangeInclAttrEventTrigger<Long> trigger =
|
||||
new RangeInclAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeLow, testRangeHigh);
|
||||
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(testRangeLow,testRangeHigh);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInsideRangeExclusive()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testRangeLow = 3;
|
||||
long testRangeHigh = 8;
|
||||
|
||||
RangeAttrEventTrigger<Long> trigger =
|
||||
new RangeAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeLow, testRangeHigh);
|
||||
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(testRangeLow+1,testRangeHigh-1);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeComposite()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testRangeLow = 4;
|
||||
long testRangeHigh = 7;
|
||||
|
||||
GreaterThanAttrEventTrigger<Long> trigger1 =
|
||||
new GreaterThanAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeLow);
|
||||
LessThanOrEqualToAttrEventTrigger<Long> trigger2 =
|
||||
new LessThanOrEqualToAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeHigh);
|
||||
AndEventTrigger trigger = new AndEventTrigger(trigger1, trigger2);
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(testRangeLow+1,testRangeHigh);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRangeOuter()
|
||||
throws Exception
|
||||
{
|
||||
long requestCount = 10;
|
||||
long testRangeLow = 4;
|
||||
long testRangeHigh = 7;
|
||||
|
||||
LessThanOrEqualToAttrEventTrigger<Long> trigger1 =
|
||||
new LessThanOrEqualToAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeLow);
|
||||
GreaterThanAttrEventTrigger<Long> trigger2 =
|
||||
new GreaterThanAttrEventTrigger<Long>("org.eclipse.jetty.monitor:type=requestcounter,id=0", "counter",
|
||||
testRangeHigh);
|
||||
OrEventTrigger trigger = new OrEventTrigger(trigger1, trigger2);
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
CounterAction action = new CounterAction(trigger, notifier, 500, 100);
|
||||
|
||||
performTest(action, requestCount, 1000);
|
||||
|
||||
ResultSet result = new ResultSet(1,testRangeLow,testRangeHigh+1, requestCount);
|
||||
assertEquals(result, action.getHits());
|
||||
}
|
||||
|
||||
protected void performTest(MonitorAction action, long count, long interval)
|
||||
throws Exception
|
||||
{
|
||||
_monitor.addActions(action);
|
||||
|
||||
for (long cnt=0; cnt < count; cnt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
ContentExchange getExchange = new ContentExchange();
|
||||
getExchange.setURL(_requestUrl);
|
||||
getExchange.setMethod(HttpMethods.GET);
|
||||
|
||||
_client.send(getExchange);
|
||||
int state = getExchange.waitForDone();
|
||||
|
||||
String content = "";
|
||||
int responseStatus = getExchange.getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200)
|
||||
{
|
||||
content = getExchange.getResponseContent();
|
||||
}
|
||||
|
||||
assertEquals(HttpStatus.OK_200,responseStatus);
|
||||
Thread.sleep(interval);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Thread.sleep(interval);
|
||||
|
||||
_monitor.removeActions(action);
|
||||
}
|
||||
|
||||
protected void startClient(Realm realm)
|
||||
throws Exception
|
||||
{
|
||||
_client = new HttpClient();
|
||||
_client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
if (realm != null)
|
||||
_client.setRealmResolver(new SimpleRealmResolver(realm));
|
||||
_client.start();
|
||||
}
|
||||
|
||||
protected void stopClient()
|
||||
throws Exception
|
||||
{
|
||||
if (_client != null)
|
||||
{
|
||||
_client.stop();
|
||||
_client = null;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class TestHandler
|
||||
extends AbstractHandler
|
||||
{
|
||||
private RequestCounter _counter = new RequestCounter();
|
||||
|
||||
public void handle(String target, Request baseRequest,
|
||||
HttpServletRequest request, HttpServletResponse response)
|
||||
throws IOException, ServletException
|
||||
{
|
||||
if (baseRequest.isHandled()) {
|
||||
return;
|
||||
}
|
||||
_counter.increment();
|
||||
|
||||
response.setContentType("text/plain");
|
||||
response.setStatus(HttpServletResponse.SC_OK);
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.println("===TEST RESPONSE===");
|
||||
baseRequest.setHandled(true);
|
||||
}
|
||||
|
||||
public RequestCounter getRequestCounter()
|
||||
{
|
||||
return _counter;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class ResultSet extends TreeSet<Long>
|
||||
{
|
||||
public ResultSet() {}
|
||||
|
||||
public ResultSet(long value)
|
||||
{
|
||||
add(value);
|
||||
}
|
||||
|
||||
public ResultSet(long start, long end)
|
||||
{
|
||||
addEntries(start, end);
|
||||
}
|
||||
|
||||
public ResultSet(long start, long pause, long resume, long end)
|
||||
{
|
||||
addEntries(start, pause);
|
||||
addEntries(resume, end);
|
||||
}
|
||||
|
||||
public void addEntries(long start, long stop)
|
||||
{
|
||||
if (start > 0 && stop > 0)
|
||||
{
|
||||
for(long idx=start; idx <= stop; idx++)
|
||||
{
|
||||
add(idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean equals(ResultSet set)
|
||||
{
|
||||
return (this.size() == set.size()) && containsAll(set);
|
||||
}
|
||||
}
|
||||
|
||||
protected static class CounterAction
|
||||
extends MonitorAction
|
||||
{
|
||||
private ResultSet _hits = new ResultSet();
|
||||
|
||||
public CounterAction(EventTrigger trigger, EventNotifier notifier, long interval, long delay)
|
||||
{
|
||||
super(trigger, notifier, interval, delay);
|
||||
}
|
||||
|
||||
public void execute(EventTrigger trigger, EventState<?> state, long timestamp)
|
||||
{
|
||||
if (trigger != null && state != null)
|
||||
{
|
||||
Collection<?> values = state.values();
|
||||
|
||||
Iterator<?> it = values.iterator();
|
||||
while(it.hasNext())
|
||||
{
|
||||
TriggerState<?> entry = (TriggerState<?>)it.next();
|
||||
Object value = entry.getValue();
|
||||
if (value != null)
|
||||
{
|
||||
_hits.add((Long)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ResultSet getHits()
|
||||
{
|
||||
return _hits;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
// ========================================================================
|
||||
// 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 static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.monitor.JMXMonitor;
|
||||
import org.eclipse.jetty.toolchain.test.JettyDistro;
|
||||
import org.eclipse.jetty.toolchain.test.PropertyFlag;
|
||||
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.thread.ExecutorThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class JavaMonitorIntegrationTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JavaMonitorIntegrationTest.class);
|
||||
|
||||
private static JettyDistro jetty;
|
||||
|
||||
@BeforeClass
|
||||
public static void initJetty() throws Exception
|
||||
{
|
||||
PropertyFlag.assume("JAVAMONITOR");
|
||||
|
||||
jetty = new JettyDistro(JavaMonitorIntegrationTest.class);
|
||||
|
||||
jetty.delete("contexts/javadoc.xml");
|
||||
|
||||
jetty.overlayConfig("monitor");
|
||||
|
||||
jetty.start();
|
||||
|
||||
JMXMonitor.setServiceUrl(jetty.getJmxUrl());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void shutdownJetty() throws Exception
|
||||
{
|
||||
if (jetty != null)
|
||||
{
|
||||
jetty.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
Resource configRes = Resource.newClassPathResource("/org/eclipse/jetty/monitor/java-monitor-integration.xml");
|
||||
XmlConfiguration xmlConfig = new XmlConfiguration(configRes.getURL());
|
||||
xmlConfig.configure();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIntegration()
|
||||
throws Exception
|
||||
{
|
||||
final int threadCount = 100;
|
||||
final long requestCount = 500;
|
||||
final String requestUrl = jetty.getBaseUri().resolve("d.txt").toASCIIString();
|
||||
final CountDownLatch gate = new CountDownLatch(threadCount);
|
||||
|
||||
ThreadPool worker = new ExecutorThreadPool(threadCount,threadCount,60,TimeUnit.SECONDS);
|
||||
for (int idx=0; idx < threadCount; idx++)
|
||||
{
|
||||
worker.dispatch(new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
runTest(requestUrl, requestCount);
|
||||
gate.countDown();
|
||||
}
|
||||
});
|
||||
Thread.sleep(500);
|
||||
}
|
||||
gate.await();
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
protected static void runTest(String requestUrl, long count)
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
try
|
||||
{
|
||||
client.start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
Random rnd = new Random();
|
||||
for (long cnt=0; cnt < count; cnt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
ContentExchange getExchange = new ContentExchange();
|
||||
getExchange.setURL(requestUrl);
|
||||
getExchange.setMethod(HttpMethods.GET);
|
||||
|
||||
client.send(getExchange);
|
||||
int state = getExchange.waitForDone();
|
||||
|
||||
String content = "";
|
||||
int responseStatus = getExchange.getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200)
|
||||
{
|
||||
content = getExchange.getResponseContent();
|
||||
}
|
||||
|
||||
Thread.sleep(200);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
// ========================================================================
|
||||
// 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 static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
|
||||
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.monitor.JMXMonitor;
|
||||
import org.eclipse.jetty.toolchain.jmx.JmxServiceConnection;
|
||||
import org.eclipse.jetty.toolchain.test.JettyDistro;
|
||||
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.thread.ExecutorThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class JmxServiceTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JmxServiceTest.class);
|
||||
|
||||
private static JettyDistro jetty;
|
||||
|
||||
@BeforeClass
|
||||
public static void initJetty() throws Exception
|
||||
{
|
||||
jetty = new JettyDistro(JmxServiceTest.class);
|
||||
|
||||
jetty.delete("contexts/javadoc.xml");
|
||||
|
||||
jetty.overlayConfig("monitor");
|
||||
|
||||
jetty.start();
|
||||
|
||||
JMXMonitor.setServiceUrl(jetty.getJmxUrl());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void shutdownJetty() throws Exception
|
||||
{
|
||||
if (jetty != null)
|
||||
{
|
||||
jetty.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
Resource configRes = Resource.newClassPathResource("/org/eclipse/jetty/monitor/jetty-monitor-service.xml");
|
||||
XmlConfiguration xmlConfig = new XmlConfiguration(configRes.getURL());
|
||||
xmlConfig.configure();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreadPoolMXBean()
|
||||
throws Exception
|
||||
{
|
||||
final int threadCount = 100;
|
||||
final long requestCount = 100;
|
||||
final String requestUrl = jetty.getBaseUri().resolve("d.txt").toASCIIString();
|
||||
final CountDownLatch gate = new CountDownLatch(threadCount);
|
||||
ThreadPool worker = new ExecutorThreadPool(threadCount,threadCount,60,TimeUnit.SECONDS);
|
||||
for (int idx=0; idx < threadCount; idx++)
|
||||
{
|
||||
worker.dispatch(new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
runTest(requestUrl, requestCount);
|
||||
gate.countDown();
|
||||
}
|
||||
});
|
||||
Thread.sleep(100);
|
||||
}
|
||||
gate.await();
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
protected static void runTest(String requestUrl, long count)
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
try
|
||||
{
|
||||
client.start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
for (long cnt=0; cnt < count; cnt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
ContentExchange getExchange = new ContentExchange();
|
||||
getExchange.setURL(requestUrl);
|
||||
getExchange.setMethod(HttpMethods.GET);
|
||||
|
||||
client.send(getExchange);
|
||||
int state = getExchange.waitForDone();
|
||||
|
||||
String content = "";
|
||||
int responseStatus = getExchange.getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200)
|
||||
{
|
||||
content = getExchange.getResponseContent();
|
||||
}
|
||||
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,182 @@
|
|||
// ========================================================================
|
||||
// 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 static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.management.MBeanServerConnection;
|
||||
|
||||
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.monitor.JMXMonitor;
|
||||
import org.eclipse.jetty.monitor.jmx.ConsoleNotifier;
|
||||
import org.eclipse.jetty.monitor.jmx.EventNotifier;
|
||||
import org.eclipse.jetty.monitor.jmx.EventState;
|
||||
import org.eclipse.jetty.monitor.jmx.EventTrigger;
|
||||
import org.eclipse.jetty.monitor.jmx.MonitorAction;
|
||||
import org.eclipse.jetty.monitor.triggers.GreaterThanAttrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.LessThanOrEqualToAttrEventTrigger;
|
||||
import org.eclipse.jetty.monitor.triggers.OrEventTrigger;
|
||||
import org.eclipse.jetty.toolchain.jmx.JmxServiceConnection;
|
||||
import org.eclipse.jetty.toolchain.test.JettyDistro;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.ExecutorThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class ProgramConfigTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ProgramConfigTest.class);
|
||||
|
||||
private static JettyDistro jetty;
|
||||
|
||||
@BeforeClass
|
||||
public static void initJetty() throws Exception
|
||||
{
|
||||
jetty = new JettyDistro(ProgramConfigTest.class);
|
||||
|
||||
jetty.delete("contexts/javadoc.xml");
|
||||
|
||||
jetty.overlayConfig("monitor");
|
||||
|
||||
jetty.start();
|
||||
|
||||
JMXMonitor.setServiceUrl(jetty.getJmxUrl());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void shutdownJetty() throws Exception
|
||||
{
|
||||
if (jetty != null)
|
||||
{
|
||||
jetty.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreadPoolMXBean()
|
||||
throws Exception
|
||||
{
|
||||
int testRangeLow = 4;
|
||||
int testRangeHigh = 7;
|
||||
|
||||
LessThanOrEqualToAttrEventTrigger<Integer> trigger1 =
|
||||
new LessThanOrEqualToAttrEventTrigger<Integer>("org.eclipse.jetty.util.thread:type=queuedthreadpool,id=0", "idleThreads",
|
||||
testRangeLow);
|
||||
GreaterThanAttrEventTrigger<Integer> trigger2 =
|
||||
new GreaterThanAttrEventTrigger<Integer>("org.eclipse.jetty.util.thread:type=queuedthreadpool,id=0", "idleThreads",
|
||||
testRangeHigh);
|
||||
OrEventTrigger trigger = new OrEventTrigger(trigger1, trigger2);
|
||||
EventNotifier notifier = new ConsoleNotifier("%s");
|
||||
final AtomicLong counter = new AtomicLong();
|
||||
MonitorAction action = new MonitorAction(trigger, notifier, 500) {
|
||||
@Override
|
||||
public void execute(EventTrigger trigger, EventState<?> state, long timestamp)
|
||||
{
|
||||
System.out.println(counter.incrementAndGet());
|
||||
}
|
||||
};
|
||||
JMXMonitor.addMonitorActions(action);
|
||||
|
||||
final int threadCount = 100;
|
||||
final long requestCount = 100;
|
||||
final String requestUrl = jetty.getBaseUri().resolve("d.txt").toASCIIString();
|
||||
final CountDownLatch gate = new CountDownLatch(threadCount);
|
||||
ThreadPool worker = new ExecutorThreadPool(threadCount,threadCount,60,TimeUnit.SECONDS);
|
||||
for (int idx=0; idx < threadCount; idx++)
|
||||
{
|
||||
worker.dispatch(new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
runTest(requestUrl, requestCount);
|
||||
gate.countDown();
|
||||
}
|
||||
});
|
||||
Thread.sleep(100);
|
||||
}
|
||||
gate.await();
|
||||
JMXMonitor.removeMonitorActions(action);
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
protected static void runTest(String requestUrl, long count)
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
try
|
||||
{
|
||||
client.start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
for (long cnt=0; cnt < count; cnt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
ContentExchange getExchange = new ContentExchange();
|
||||
getExchange.setURL(requestUrl);
|
||||
getExchange.setMethod(HttpMethods.GET);
|
||||
|
||||
client.send(getExchange);
|
||||
getExchange.waitForDone();
|
||||
|
||||
String content = "";
|
||||
int responseStatus = getExchange.getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200)
|
||||
{
|
||||
content = getExchange.getResponseContent();
|
||||
}
|
||||
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
|
||||
public class RequestCounter
|
||||
{
|
||||
public long _counter;
|
||||
|
||||
public synchronized long getCounter()
|
||||
{
|
||||
return _counter;
|
||||
}
|
||||
|
||||
public synchronized void increment()
|
||||
{
|
||||
_counter++;
|
||||
}
|
||||
|
||||
public synchronized void reset()
|
||||
{
|
||||
_counter = 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
// ========================================================================
|
||||
// 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 static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
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.monitor.JMXMonitor;
|
||||
import org.eclipse.jetty.toolchain.test.JettyDistro;
|
||||
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.thread.ExecutorThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
*/
|
||||
public class XmlConfigTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(XmlConfigTest.class);
|
||||
|
||||
private static JettyDistro jetty;
|
||||
|
||||
@BeforeClass
|
||||
public static void initJetty() throws Exception
|
||||
{
|
||||
jetty = new JettyDistro(XmlConfigTest.class);
|
||||
|
||||
jetty.delete("contexts/javadoc.xml");
|
||||
|
||||
jetty.overlayConfig("monitor");
|
||||
|
||||
jetty.start();
|
||||
|
||||
JMXMonitor.setServiceUrl(jetty.getJmxUrl());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void shutdownJetty() throws Exception
|
||||
{
|
||||
if (jetty != null)
|
||||
{
|
||||
jetty.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp()
|
||||
throws Exception
|
||||
{
|
||||
Resource configRes = Resource.newClassPathResource("/org/eclipse/jetty/monitor/jetty-monitor-test.xml");
|
||||
XmlConfiguration xmlConfig = new XmlConfiguration(configRes.getURL());
|
||||
xmlConfig.configure();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testThreadPoolMXBean()
|
||||
throws Exception
|
||||
{
|
||||
final int threadCount = 100;
|
||||
final long requestCount = 100;
|
||||
final String requestUrl = jetty.getBaseUri().resolve("d.txt").toASCIIString();
|
||||
final CountDownLatch gate = new CountDownLatch(threadCount);
|
||||
ThreadPool worker = new ExecutorThreadPool(threadCount,threadCount,60,TimeUnit.SECONDS);
|
||||
for (int idx=0; idx < threadCount; idx++)
|
||||
{
|
||||
worker.dispatch(new Runnable() {
|
||||
public void run()
|
||||
{
|
||||
runTest(requestUrl, requestCount);
|
||||
gate.countDown();
|
||||
}
|
||||
});
|
||||
Thread.sleep(100);
|
||||
}
|
||||
gate.await();
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
protected static void runTest(String requestUrl, long count)
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL);
|
||||
try
|
||||
{
|
||||
client.start();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
Random rnd = new Random();
|
||||
for (long cnt=0; cnt < count; cnt++)
|
||||
{
|
||||
try
|
||||
{
|
||||
ContentExchange getExchange = new ContentExchange();
|
||||
getExchange.setURL(requestUrl);
|
||||
getExchange.setMethod(HttpMethods.GET);
|
||||
|
||||
client.send(getExchange);
|
||||
int state = getExchange.waitForDone();
|
||||
|
||||
String content = "";
|
||||
int responseStatus = getExchange.getResponseStatus();
|
||||
if (responseStatus == HttpStatus.OK_200)
|
||||
{
|
||||
content = getExchange.getResponseContent();
|
||||
}
|
||||
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException ex)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LOG.debug(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<!-- ============================================================================ -->
|
||||
<!-- To correctly start Jetty with JMX module enabled, this configuration -->
|
||||
<!-- file must appear first in the list of the configuration files. -->
|
||||
<!-- The simplest way to achieve this is to add etc/jetty-jmx.xml as the -->
|
||||
<!-- first file in configuration file list at the end of start.ini file. -->
|
||||
<!-- ============================================================================ -->
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Initialize an mbean server -->
|
||||
<!-- =========================================================== -->
|
||||
<Call id="MBeanServer" class="java.lang.management.ManagementFactory"
|
||||
name="getPlatformMBeanServer" />
|
||||
|
||||
<!-- =========================================================== -->
|
||||
<!-- Initialize the Jetty MBean container -->
|
||||
<!-- =========================================================== -->
|
||||
<New id="MBeanContainer" class="org.eclipse.jetty.jmx.MBeanContainer">
|
||||
<Arg>
|
||||
<Ref id="MBeanServer" />
|
||||
</Arg>
|
||||
</New>
|
||||
|
||||
<!-- Add to the Server to listen for object events -->
|
||||
<Get id="Container" name="container">
|
||||
<Call name="addEventListener">
|
||||
<Arg>
|
||||
<Ref id="MBeanContainer" />
|
||||
</Arg>
|
||||
</Call>
|
||||
</Get>
|
||||
|
||||
<!-- Add to the Server as a lifecycle -->
|
||||
<!-- Only do this if you know you will only have a single jetty server -->
|
||||
<Call name="addBean">
|
||||
<Arg>
|
||||
<Ref id="MBeanContainer" />
|
||||
</Arg>
|
||||
</Call>
|
||||
|
||||
<!-- Add the static log -->
|
||||
<Get id="Logger" class="org.eclipse.jetty.util.log.Log" name="log" />
|
||||
<Ref id="MBeanContainer">
|
||||
<Call name="addBean">
|
||||
<Arg>
|
||||
<Ref id="Logger" />
|
||||
</Arg>
|
||||
</Call>
|
||||
</Ref>
|
||||
|
||||
<!-- In order to connect to the JMX server remotely from a different
|
||||
process, possibly running on a different host, Jetty JMX module
|
||||
can create a remote JMX connector.
|
||||
-->
|
||||
|
||||
|
||||
<!-- Optionally add a remote JMX connector. The parameters of the constructor
|
||||
below specify the JMX service URL, and the object name string for the
|
||||
connector server bean. The parameters of the JMXServiceURL constructor
|
||||
specify the protocol that clients will use to connect to the remote JMX
|
||||
connector (RMI), the hostname of the server (local hostname), port number
|
||||
(automatically assigned), and the URL path. Note that URL path contains
|
||||
the RMI registry hostname and port number, that may need to be modified
|
||||
in order to comply with the firewall requirements.
|
||||
-->
|
||||
<New id="ConnectorServer" class="org.eclipse.jetty.jmx.ConnectorServer">
|
||||
<Arg>
|
||||
<New class="javax.management.remote.JMXServiceURL">
|
||||
<Arg type="java.lang.String">rmi</Arg>
|
||||
<Arg type="java.lang.String" />
|
||||
<Arg type="java.lang.Integer">0</Arg>
|
||||
<Arg type="java.lang.String">/jndi/rmi://localhost:0/jettyjmx</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Arg>org.eclipse.jetty:name=rmiconnectorserver</Arg>
|
||||
<Call name="start" />
|
||||
</New>
|
||||
</Configure>
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
OPTIONS=Server,jsp,jmx,resources,websocket,ext
|
||||
etc/jetty-jmx.xml
|
||||
etc/jetty.xml
|
||||
etc/jetty-deploy.xml
|
||||
etc/jetty-webapps.xml
|
||||
etc/jetty-contexts.xml
|
||||
etc/jetty-testrealm.xml
|
|
@ -0,0 +1,62 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<!--
|
||||
// ========================================================================
|
||||
// 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.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
-->
|
||||
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
|
||||
<!--
|
||||
<Call id="MBeanServer" class="java.lang.management.ManagementFactory" name="getPlatformMBeanServer">
|
||||
<Call name="registerMBean">
|
||||
<Arg><New class="com.javamonitor.mbeans.DNSCachePolicy" /></Arg>
|
||||
<Arg>
|
||||
<New class="javax.management.ObjectName">
|
||||
<Arg>com.javamonitor:type=DNSCachePolicy</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
<Call name="registerMBean">
|
||||
<Arg><New class="com.javamonitor.mbeans.Threading" /></Arg>
|
||||
<Arg>
|
||||
<New class="javax.management.ObjectName">
|
||||
<Arg>com.javamonitor:type=Threading</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Call>
|
||||
-->
|
||||
|
||||
<Call id="JMXMonitor" class="org.eclipse.jetty.monitor.JMXMonitor" name="getInstance">
|
||||
<Call name="addActions">
|
||||
<Arg>
|
||||
<Array type="org.eclipse.jetty.monitor.jmx.MonitorAction">
|
||||
<Item>
|
||||
<New id="MonitorAction" class="org.eclipse.jetty.monitor.integration.JavaMonitorAction">
|
||||
<Arg />
|
||||
<Arg>http://194.109.206.51/lemongrass/1.1/push</Arg>
|
||||
<Arg>57e48e79-f0e6-4909-a6da-e8c1267cbf49</Arg>
|
||||
<Arg>8080</Arg>
|
||||
<Arg type="java.lang.Integer">15000</Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Call>
|
||||
</Configure>
|
|
@ -0,0 +1,68 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<!--
|
||||
// ========================================================================
|
||||
// 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.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
-->
|
||||
|
||||
<Configure id="Monitor" class="org.eclipse.jetty.monitor.JMXMonitor">
|
||||
<Call name="setUrl">
|
||||
<Arg>service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jettyjmx</Arg>
|
||||
</Call>
|
||||
<Call name="addActions">
|
||||
<Arg>
|
||||
<Array type="org.eclipse.jetty.monitor.jmx.MonitorAction">
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.monitor.jmx.SimpleAction">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.monitor.triggers.OrEventTrigger">
|
||||
<Arg>
|
||||
<Array type="org.eclipse.jetty.monitor.jmx.EventTrigger">
|
||||
<Item>
|
||||
<New
|
||||
class="org.eclipse.jetty.monitor.triggers.LessThanOrEqualToAttrEventTrigger">
|
||||
<Arg>org.eclipse.jetty.util.thread:type=queuedthreadpool,id=0
|
||||
</Arg>
|
||||
<Arg>idleThreads</Arg>
|
||||
<Arg type="java.lang.Integer">4</Arg>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New
|
||||
class="org.eclipse.jetty.monitor.triggers.GreaterThanAttrEventTrigger">
|
||||
<Arg>org.eclipse.jetty.util.thread:type=queuedthreadpool,id=0
|
||||
</Arg>
|
||||
<Arg>idleThreads</Arg>
|
||||
<Arg type="java.lang.Integer">7</Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.monitor.jmx.ConsoleNotifier">
|
||||
<Arg>%s</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Arg type="java.lang.Long">500</Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Configure>
|
|
@ -0,0 +1,65 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">
|
||||
|
||||
<!--
|
||||
// ========================================================================
|
||||
// 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.apache.org/licenses/LICENSE-2.0.txt
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
-->
|
||||
|
||||
<Configure id="Monitor" class="org.eclipse.jetty.monitor.JMXMonitor">
|
||||
<Call name="addActions">
|
||||
<Arg>
|
||||
<Array type="org.eclipse.jetty.monitor.jmx.MonitorAction">
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.monitor.jmx.SimpleAction">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.monitor.triggers.OrEventTrigger">
|
||||
<Arg>
|
||||
<Array type="org.eclipse.jetty.monitor.jmx.EventTrigger">
|
||||
<Item>
|
||||
<New
|
||||
class="org.eclipse.jetty.monitor.triggers.LessThanOrEqualToAttrEventTrigger">
|
||||
<Arg>org.eclipse.jetty.util.thread:type=queuedthreadpool,id=0
|
||||
</Arg>
|
||||
<Arg>idleThreads</Arg>
|
||||
<Arg type="java.lang.Integer">4</Arg>
|
||||
</New>
|
||||
</Item>
|
||||
<Item>
|
||||
<New
|
||||
class="org.eclipse.jetty.monitor.triggers.GreaterThanAttrEventTrigger">
|
||||
<Arg>org.eclipse.jetty.util.thread:type=queuedthreadpool,id=0
|
||||
</Arg>
|
||||
<Arg>idleThreads</Arg>
|
||||
<Arg type="java.lang.Integer">7</Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.monitor.jmx.ConsoleNotifier">
|
||||
<Arg>%s</Arg>
|
||||
</New>
|
||||
</Arg>
|
||||
<Arg type="java.lang.Long">500</Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Configure>
|
|
@ -0,0 +1,3 @@
|
|||
RequestCounter: Request counter
|
||||
counter: current value of the counter
|
||||
increment(): increment the counter
|
|
@ -16,7 +16,7 @@ import org.eclipse.jetty.util.IO;
|
|||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
class HashedSession extends AbstractSession
|
||||
public class HashedSession extends AbstractSession
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HashedSession.class);
|
||||
|
||||
|
@ -226,4 +226,4 @@ class HashedSession extends AbstractSession
|
|||
_saveFailed = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ public class ServletContextHandler extends ContextHandler
|
|||
protected SessionHandler _sessionHandler;
|
||||
protected SecurityHandler _securityHandler;
|
||||
protected ServletHandler _servletHandler;
|
||||
protected HandlerWrapper _wrapper;
|
||||
protected int _options;
|
||||
protected Object _restrictedContextListeners;
|
||||
|
||||
|
@ -142,6 +143,7 @@ public class ServletContextHandler extends ContextHandler
|
|||
{
|
||||
super.doStop();
|
||||
_decorators.clear();
|
||||
_wrapper.setHandler(null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -214,16 +216,16 @@ public class ServletContextHandler extends ContextHandler
|
|||
}
|
||||
|
||||
// skip any wrapped handlers
|
||||
HandlerWrapper wrapper=this;
|
||||
while (wrapper!=handler && wrapper.getHandler() instanceof HandlerWrapper)
|
||||
wrapper=(HandlerWrapper)wrapper.getHandler();
|
||||
_wrapper=this;
|
||||
while (_wrapper!=handler && _wrapper.getHandler() instanceof HandlerWrapper)
|
||||
_wrapper=(HandlerWrapper)_wrapper.getHandler();
|
||||
|
||||
// if we are not already linked
|
||||
if (wrapper!=handler)
|
||||
if (_wrapper!=handler)
|
||||
{
|
||||
if (wrapper.getHandler()!=null )
|
||||
if (_wrapper.getHandler()!=null )
|
||||
throw new IllegalStateException("!ScopedHandler");
|
||||
wrapper.setHandler(handler);
|
||||
_wrapper.setHandler(handler);
|
||||
}
|
||||
|
||||
super.startContext();
|
||||
|
@ -376,7 +378,7 @@ public class ServletContextHandler extends ContextHandler
|
|||
{
|
||||
if (isStarted())
|
||||
throw new IllegalStateException("STARTED");
|
||||
|
||||
|
||||
_sessionHandler = sessionHandler;
|
||||
}
|
||||
|
||||
|
@ -388,7 +390,7 @@ public class ServletContextHandler extends ContextHandler
|
|||
{
|
||||
if (isStarted())
|
||||
throw new IllegalStateException("STARTED");
|
||||
|
||||
|
||||
_securityHandler = securityHandler;
|
||||
}
|
||||
|
||||
|
@ -400,7 +402,7 @@ public class ServletContextHandler extends ContextHandler
|
|||
{
|
||||
if (isStarted())
|
||||
throw new IllegalStateException("STARTED");
|
||||
|
||||
|
||||
_servletHandler = servletHandler;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,25 +2,54 @@ package org.eclipse.jetty.servlet;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.eclipse.jetty.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.security.SecurityHandler;
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandlerContainer;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.session.SessionHandler;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ServletContextHandlerTest
|
||||
{
|
||||
private Server _server;
|
||||
private LocalConnector _connector;
|
||||
|
||||
@Before
|
||||
public void createServer()
|
||||
{
|
||||
_server = new Server();
|
||||
|
||||
_connector = new LocalConnector();
|
||||
_server.addConnector(_connector);
|
||||
}
|
||||
|
||||
@After
|
||||
public void destroyServer() throws Exception
|
||||
{
|
||||
_server.stop();
|
||||
_server.join();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFindContainer() throws Exception
|
||||
{
|
||||
Server server = new Server();
|
||||
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
server.setHandler(contexts);
|
||||
_server.setHandler(contexts);
|
||||
|
||||
ServletContextHandler root = new ServletContextHandler(contexts,"/",ServletContextHandler.SESSIONS);
|
||||
|
||||
|
@ -28,10 +57,148 @@ public class ServletContextHandlerTest
|
|||
ServletHandler servlet = root.getServletHandler();
|
||||
SecurityHandler security = new ConstraintSecurityHandler();
|
||||
root.setSecurityHandler(security);
|
||||
server.start();
|
||||
|
||||
assertEquals(root, AbstractHandlerContainer.findContainerOf(server, ContextHandler.class, session));
|
||||
assertEquals(root, AbstractHandlerContainer.findContainerOf(server, ContextHandler.class, security));
|
||||
assertEquals(root, AbstractHandlerContainer.findContainerOf(server, ContextHandler.class, servlet));
|
||||
_server.start();
|
||||
|
||||
assertEquals(root, AbstractHandlerContainer.findContainerOf(_server, ContextHandler.class, session));
|
||||
assertEquals(root, AbstractHandlerContainer.findContainerOf(_server, ContextHandler.class, security));
|
||||
assertEquals(root, AbstractHandlerContainer.findContainerOf(_server, ContextHandler.class, servlet));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddServletAfterStart() throws Exception
|
||||
{
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.addServlet(TestServlet.class,"/test");
|
||||
context.setContextPath("/");
|
||||
_server.setHandler(context);
|
||||
_server.start();
|
||||
|
||||
StringBuffer request = new StringBuffer();
|
||||
request.append("GET /test HTTP/1.1\n");
|
||||
request.append("Host: localhost\n");
|
||||
request.append("\n");
|
||||
|
||||
String response = _connector.getResponses(request.toString());
|
||||
assertResponseContains("Test", response);
|
||||
|
||||
context.addServlet(HelloServlet.class, "/hello");
|
||||
|
||||
request = new StringBuffer();
|
||||
request.append("GET /hello HTTP/1.1\n");
|
||||
request.append("Host: localhost\n");
|
||||
request.append("\n");
|
||||
|
||||
response = _connector.getResponses(request.toString());
|
||||
assertResponseContains("Hello World", response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceServletHandlerWithServlet() throws Exception
|
||||
{
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.addServlet(TestServlet.class,"/test");
|
||||
context.setContextPath("/");
|
||||
_server.setHandler(context);
|
||||
_server.start();
|
||||
|
||||
StringBuffer request = new StringBuffer();
|
||||
request.append("GET /test HTTP/1.1\n");
|
||||
request.append("Host: localhost\n");
|
||||
request.append("\n");
|
||||
|
||||
String response = _connector.getResponses(request.toString());
|
||||
assertResponseContains("Test", response);
|
||||
|
||||
context.stop();
|
||||
ServletHandler srvHnd = new ServletHandler();
|
||||
srvHnd.addServletWithMapping(HelloServlet.class,"/hello");
|
||||
context.setServletHandler(srvHnd);
|
||||
context.start();
|
||||
|
||||
request = new StringBuffer();
|
||||
request.append("GET /hello HTTP/1.1\n");
|
||||
request.append("Host: localhost\n");
|
||||
request.append("\n");
|
||||
|
||||
response = _connector.getResponses(request.toString());
|
||||
assertResponseContains("Hello World", response);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceServletHandlerWithoutServlet() throws Exception
|
||||
{
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.addServlet(TestServlet.class,"/test");
|
||||
context.setContextPath("/");
|
||||
_server.setHandler(context);
|
||||
_server.start();
|
||||
|
||||
StringBuffer request = new StringBuffer();
|
||||
request.append("GET /test HTTP/1.1\n");
|
||||
request.append("Host: localhost\n");
|
||||
request.append("\n");
|
||||
|
||||
String response = _connector.getResponses(request.toString());
|
||||
assertResponseContains("Test", response);
|
||||
|
||||
context.stop();
|
||||
ServletHandler srvHnd = new ServletHandler();
|
||||
context.setServletHandler(srvHnd);
|
||||
context.start();
|
||||
|
||||
context.addServlet(HelloServlet.class,"/hello");
|
||||
|
||||
request = new StringBuffer();
|
||||
request.append("GET /hello HTTP/1.1\n");
|
||||
request.append("Host: localhost\n");
|
||||
request.append("\n");
|
||||
|
||||
response = _connector.getResponses(request.toString());
|
||||
assertResponseContains("Hello World", response);
|
||||
}
|
||||
|
||||
private int assertResponseContains(String expected, String response)
|
||||
{
|
||||
int idx = response.indexOf(expected);
|
||||
if (idx == (-1))
|
||||
{
|
||||
// Not found
|
||||
StringBuffer err = new StringBuffer();
|
||||
err.append("Response does not contain expected string \"").append(expected).append("\"");
|
||||
err.append("\n").append(response);
|
||||
|
||||
System.err.println(err);
|
||||
throw new AssertionFailedError(err.toString());
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
public static class HelloServlet extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
resp.setStatus(HttpServletResponse.SC_OK);
|
||||
PrintWriter writer = resp.getWriter();
|
||||
writer.write("Hello World");
|
||||
}
|
||||
}
|
||||
|
||||
public static class TestServlet extends HttpServlet
|
||||
{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
|
||||
throws ServletException, IOException
|
||||
{
|
||||
resp.setStatus(HttpServletResponse.SC_OK);
|
||||
PrintWriter writer = resp.getWriter();
|
||||
writer.write("Test");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public class DeflateFrameExtension extends AbstractExtension
|
|||
catch(DataFormatException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
getConnection().close(WebSocketConnectionD10.CLOSE_PROTOCOL,e.toString());
|
||||
getConnection().close(WebSocketConnectionD12.CLOSE_PROTOCOL,e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ public class TestClient implements WebSocket.OnFrame
|
|||
{
|
||||
__framesSent++;
|
||||
byte flags= (byte)(off+len==data.length?0x8:0);
|
||||
byte op=(byte)(off==0?opcode:WebSocketConnectionD10.OP_CONTINUATION);
|
||||
byte op=(byte)(off==0?opcode:WebSocketConnectionD12.OP_CONTINUATION);
|
||||
|
||||
if (_verbose)
|
||||
System.err.printf("%s#addFrame %s|%s %s\n",this.getClass().getSimpleName(),TypeUtil.toHexString(flags),TypeUtil.toHexString(op),TypeUtil.toHexString(data,off,len));
|
||||
|
@ -240,11 +240,11 @@ public class TestClient implements WebSocket.OnFrame
|
|||
{
|
||||
long next = System.currentTimeMillis()+delay;
|
||||
|
||||
byte opcode=binary?WebSocketConnectionD10.OP_BINARY:WebSocketConnectionD10.OP_TEXT;
|
||||
byte opcode=binary?WebSocketConnectionD12.OP_BINARY:WebSocketConnectionD12.OP_TEXT;
|
||||
|
||||
byte data[]=null;
|
||||
|
||||
if (opcode==WebSocketConnectionD10.OP_TEXT)
|
||||
if (opcode==WebSocketConnectionD12.OP_TEXT)
|
||||
{
|
||||
StringBuilder b = new StringBuilder();
|
||||
while (b.length()<size)
|
||||
|
@ -258,7 +258,7 @@ public class TestClient implements WebSocket.OnFrame
|
|||
}
|
||||
|
||||
for (int i=0;i<clients;i++)
|
||||
client[i].ping(opcode,data,opcode==WebSocketConnectionD10.OP_PING?-1:fragment);
|
||||
client[i].ping(opcode,data,opcode==WebSocketConnectionD12.OP_PING?-1:fragment);
|
||||
|
||||
while(System.currentTimeMillis()<next)
|
||||
Thread.sleep(10);
|
||||
|
|
|
@ -36,12 +36,13 @@ import org.eclipse.jetty.util.component.AggregateLifeCycle;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.util.thread.ThreadPool;
|
||||
import org.eclipse.jetty.websocket.WebSocketGeneratorD12.MaskGen;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** WebSocket Client
|
||||
* <p>This WebSocket Client class can create multiple websocket connections to multiple destinations.
|
||||
* It uses the same {@link WebSocket} endpoint API as the server.
|
||||
* <p>This WebSocket Client class can create multiple websocket connections to multiple destinations.
|
||||
* It uses the same {@link WebSocket} endpoint API as the server.
|
||||
* Simple usage is as follows: <pre>
|
||||
* WebSocketClient client = new WebSocketClient();
|
||||
* client.setMaxIdleTime(500);
|
||||
|
@ -58,19 +59,19 @@ import org.eclipse.jetty.util.thread.ThreadPool;
|
|||
* {
|
||||
* // close notification
|
||||
* }
|
||||
*
|
||||
*
|
||||
* public void onMessage(String data)
|
||||
* {
|
||||
* // handle incoming message
|
||||
* }
|
||||
* }).get(5,TimeUnit.SECONDS);
|
||||
*
|
||||
*
|
||||
* connection.sendMessage("Hello World");
|
||||
* </pre>
|
||||
* </pre>
|
||||
*/
|
||||
public class WebSocketClient extends AggregateLifeCycle
|
||||
{
|
||||
private final static Logger __log = org.eclipse.jetty.util.log.Log.getLogger(WebSocketClient.class.getCanonicalName());
|
||||
{
|
||||
private final static Logger __log = org.eclipse.jetty.util.log.Log.getLogger(WebSocketClient.class.getName());
|
||||
private final static Random __random = new Random();
|
||||
private final static ByteArrayBuffer __ACCEPT = new ByteArrayBuffer.CaseInsensitive("Sec-WebSocket-Accept");
|
||||
|
||||
|
@ -81,14 +82,15 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
|
||||
private final Map<String,String> _cookies=new ConcurrentHashMap<String, String>();
|
||||
private final List<String> _extensions=new CopyOnWriteArrayList<String>();
|
||||
|
||||
|
||||
private int _bufferSize=64*1024;
|
||||
private String _origin;
|
||||
private String _protocol;
|
||||
private int _maxIdleTime=-1;
|
||||
|
||||
|
||||
private WebSocketBuffers _buffers;
|
||||
|
||||
private boolean _maskingEnabled = true;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Create a WebSocket Client with default configuration.
|
||||
|
@ -97,7 +99,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
{
|
||||
this(new QueuedThreadPool());
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Create a WebSocket Client with shared threadpool.
|
||||
* @param threadpool
|
||||
|
@ -111,11 +113,11 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
addBean(_selector);
|
||||
addBean(_threadPool);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Create a WebSocket Client from another.
|
||||
* <p>If multiple clients are required so that connections created may have different
|
||||
* configurations, then it is more efficient to create a client based on another, so
|
||||
* <p>If multiple clients are required so that connections created may have different
|
||||
* configurations, then it is more efficient to create a client based on another, so
|
||||
* that the thread pool and IO infrastructure may be shared.
|
||||
*/
|
||||
public WebSocketClient(WebSocketClient parent)
|
||||
|
@ -126,7 +128,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
_selector=parent._selector;
|
||||
_parent.addBean(this);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Get the selectorManager. Used to configure the manager.
|
||||
|
@ -136,7 +138,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
{
|
||||
return _selector;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the ThreadPool.
|
||||
* <p>Used to set/query the thread pool configuration.
|
||||
|
@ -146,7 +148,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
{
|
||||
return _threadPool;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the maxIdleTime for connections opened by this client.
|
||||
* @return The maxIdleTime in ms, or -1 if the default from {@link #getSelectorManager()} is used.
|
||||
|
@ -184,7 +186,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
throw new IllegalStateException(getState());
|
||||
_bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the subprotocol string for connections opened by this client.
|
||||
* @return The subprotocol
|
||||
|
@ -202,7 +204,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
{
|
||||
_protocol = protocol;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the origin of the client
|
||||
* @return The clients Origin
|
||||
|
@ -226,14 +228,32 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
{
|
||||
return _cookies;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public List<String> getExtensions()
|
||||
{
|
||||
return _extensions;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return whether masking is enabled.
|
||||
*/
|
||||
public boolean isMaskingEnabled()
|
||||
{
|
||||
return _maskingEnabled;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param maskingEnabled whether to enable masking
|
||||
*/
|
||||
public void setMaskingEnabled(boolean maskingEnabled)
|
||||
{
|
||||
_maskingEnabled=maskingEnabled;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Open a WebSocket connection.
|
||||
* Open a websocket connection to the URI and block until the connection is accepted or there is an error.
|
||||
|
@ -264,12 +284,12 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
throw new RuntimeException(cause);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Asynchronously open a websocket connection.
|
||||
* Open a websocket connection and return a {@link Future} to obtain the connection.
|
||||
* Open a websocket connection and return a {@link Future} to obtain the connection.
|
||||
* The caller must call {@link Future#get(long, TimeUnit)} if they wish to impose a connect timeout on the open.
|
||||
*
|
||||
*
|
||||
* @param uri The URI to connect to.
|
||||
* @param websocket The {@link WebSocket} instance to handle incoming events.
|
||||
* @return A {@link Future} to the {@link WebSocket.Connection}
|
||||
|
@ -284,7 +304,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
throw new IllegalArgumentException("Bad WebSocket scheme '"+scheme+"'");
|
||||
if ("wss".equalsIgnoreCase(scheme))
|
||||
throw new IOException("wss not supported");
|
||||
|
||||
|
||||
SocketChannel channel = SocketChannel.open();
|
||||
channel.socket().setTcpNoDelay(true);
|
||||
int maxIdleTime = getMaxIdleTime();
|
||||
|
@ -303,18 +323,18 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
|
||||
return holder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (_parent!=null && !_parent.isRunning())
|
||||
throw new IllegalStateException("parent:"+getState());
|
||||
|
||||
_buffers = new WebSocketBuffers(_bufferSize);
|
||||
|
||||
_buffers = new WebSocketBuffers(_bufferSize);
|
||||
|
||||
super.doStart();
|
||||
|
||||
|
||||
// Start a selector and timer if this is the root client
|
||||
if (_parent==null)
|
||||
{
|
||||
|
@ -342,7 +362,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** WebSocket Client Selector Manager
|
||||
*/
|
||||
|
@ -366,7 +386,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
WebSocketFuture holder = (WebSocketFuture) endpoint.getSelectionKey().attachment();
|
||||
return new HandshakeConnection(endpoint,holder);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void endPointOpened(SelectChannelEndPoint endpoint)
|
||||
{
|
||||
|
@ -394,13 +414,13 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
{
|
||||
__log.debug(ex);
|
||||
WebSocketFuture holder = (WebSocketFuture)attachment;
|
||||
|
||||
|
||||
holder.handshakeFailed(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Handshake Connection.
|
||||
* Handles the connection until the handshake succeeds or fails.
|
||||
|
@ -413,21 +433,21 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
private final HttpParser _parser;
|
||||
private String _accept;
|
||||
private String _error;
|
||||
|
||||
|
||||
|
||||
|
||||
public HandshakeConnection(SelectChannelEndPoint endpoint, WebSocketFuture holder)
|
||||
{
|
||||
super(endpoint,System.currentTimeMillis());
|
||||
_endp=endpoint;
|
||||
_holder=holder;
|
||||
|
||||
|
||||
byte[] bytes=new byte[16];
|
||||
__random.nextBytes(bytes);
|
||||
_key=new String(B64Code.encode(bytes));
|
||||
|
||||
|
||||
Buffers buffers = new SimpleBuffers(_buffers.getBuffer(),null);
|
||||
_parser=new HttpParser(buffers,_endp,
|
||||
|
||||
|
||||
new HttpParser.EventHandler()
|
||||
{
|
||||
@Override
|
||||
|
@ -439,7 +459,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
_endp.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void parsedHeader(Buffer name, Buffer value) throws IOException
|
||||
{
|
||||
|
@ -454,7 +474,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
_error="Bad response: "+method+" "+url+" "+version;
|
||||
_endp.close();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void content(Buffer ref) throws IOException
|
||||
{
|
||||
|
@ -463,23 +483,23 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
_endp.close();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
String path=_holder.getURI().getPath();
|
||||
if (path==null || path.length()==0)
|
||||
path="/";
|
||||
|
||||
|
||||
String request=
|
||||
"GET "+path+" HTTP/1.1\r\n"+
|
||||
"Host: "+holder.getURI().getHost()+":"+_holder.getURI().getPort()+"\r\n"+
|
||||
"Upgrade: websocket\r\n"+
|
||||
"Connection: Upgrade\r\n"+
|
||||
"Sec-WebSocket-Key: "+_key+"\r\n"+
|
||||
(_origin==null?"":"Sec-WebSocket-Origin: "+_origin+"\r\n")+
|
||||
"Sec-WebSocket-Version: "+WebSocketConnectionD10.VERSION+"\r\n";
|
||||
|
||||
(_origin==null?"":"Origin: "+_origin+"\r\n")+
|
||||
"Sec-WebSocket-Version: "+WebSocketConnectionD12.VERSION+"\r\n";
|
||||
|
||||
if (holder.getProtocol()!=null)
|
||||
request+="Sec-WebSocket-Protocol: "+holder.getProtocol()+"\r\n";
|
||||
|
||||
|
||||
if (holder.getCookies()!=null && holder.getCookies().size()>0)
|
||||
{
|
||||
for (String cookie : holder.getCookies().keySet())
|
||||
|
@ -490,9 +510,9 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
}
|
||||
|
||||
request+="\r\n";
|
||||
|
||||
|
||||
// TODO extensions
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
Buffer handshake = new ByteArrayBuffer(request,false);
|
||||
|
@ -504,7 +524,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
{
|
||||
holder.handshakeFailed(e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public Connection handle() throws IOException
|
||||
|
@ -519,26 +539,27 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
case 0:
|
||||
return this;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (_error==null)
|
||||
{
|
||||
if (_accept==null)
|
||||
_error="No Sec-WebSocket-Accept";
|
||||
else if (!WebSocketConnectionD10.hashKey(_key).equals(_accept))
|
||||
else if (!WebSocketConnectionD12.hashKey(_key).equals(_accept))
|
||||
_error="Bad Sec-WebSocket-Accept";
|
||||
else
|
||||
else
|
||||
{
|
||||
Buffer header=_parser.getHeaderBuffer();
|
||||
WebSocketConnectionD10 connection = new WebSocketConnectionD10(_holder.getWebSocket(),_endp,_buffers,System.currentTimeMillis(),_holder.getMaxIdleTime(),_holder.getProtocol(),null,10, new WebSocketGeneratorD10.RandomMaskGen());
|
||||
MaskGen maskGen=_maskingEnabled?new WebSocketGeneratorD12.RandomMaskGen():new WebSocketGeneratorD12.NullMaskGen();
|
||||
WebSocketConnectionD12 connection = new WebSocketConnectionD12(_holder.getWebSocket(),_endp,_buffers,System.currentTimeMillis(),_holder.getMaxIdleTime(),_holder.getProtocol(),null,10,maskGen);
|
||||
|
||||
if (header.hasContent())
|
||||
connection.fillBuffersFrom(header);
|
||||
_buffers.returnBuffer(header);
|
||||
|
||||
_holder.onConnection(connection);
|
||||
|
||||
|
||||
return connection;
|
||||
}
|
||||
}
|
||||
|
@ -566,7 +587,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** The Future Websocket Connection.
|
||||
*/
|
||||
|
@ -583,7 +604,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
ByteChannel _channel;
|
||||
WebSocketConnection _connection;
|
||||
Throwable _exception;
|
||||
|
||||
|
||||
public WebSocketFuture(WebSocket websocket, URI uri, String protocol, int maxIdleTime, Map<String,String> cookies,List<String> extensions, ByteChannel channel)
|
||||
{
|
||||
_websocket=websocket;
|
||||
|
@ -594,9 +615,9 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
_extensions=extensions;
|
||||
_channel=channel;
|
||||
}
|
||||
|
||||
|
||||
public void onConnection(WebSocketConnection connection)
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
synchronized (this)
|
||||
|
@ -612,7 +633,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
|
||||
_websocket.onOpen(connection.getConnection());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -621,7 +642,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
}
|
||||
|
||||
public void handshakeFailed(Throwable ex)
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
ByteChannel channel=null;
|
||||
|
@ -638,9 +659,9 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
if (channel!=null)
|
||||
{
|
||||
if (ex instanceof ProtocolException)
|
||||
closeChannel(channel,WebSocketConnectionD10.CLOSE_PROTOCOL,ex.getMessage());
|
||||
closeChannel(channel,WebSocketConnectionD12.CLOSE_PROTOCOL,ex.getMessage());
|
||||
else
|
||||
closeChannel(channel,WebSocketConnectionD10.CLOSE_NOCLOSE,ex.getMessage());
|
||||
closeChannel(channel,WebSocketConnectionD12.CLOSE_NOCLOSE,ex.getMessage());
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
@ -663,17 +684,17 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
{
|
||||
return _websocket;
|
||||
}
|
||||
|
||||
|
||||
public URI getURI()
|
||||
{
|
||||
return _uri;
|
||||
}
|
||||
|
||||
|
||||
public int getMaxIdleTime()
|
||||
{
|
||||
return _maxIdleTime;
|
||||
}
|
||||
|
||||
|
||||
public String toString()
|
||||
{
|
||||
return "[" + _uri + ","+_websocket+"]@"+hashCode();
|
||||
|
@ -695,7 +716,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
|
||||
if (channel!=null)
|
||||
{
|
||||
closeChannel(channel,WebSocketConnectionD10.CLOSE_NOCLOSE,"cancelled");
|
||||
closeChannel(channel,WebSocketConnectionD12.CLOSE_NOCLOSE,"cancelled");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -753,9 +774,9 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
else
|
||||
connection=_connection.getConnection();
|
||||
}
|
||||
|
||||
|
||||
if (channel!=null)
|
||||
closeChannel(channel,WebSocketConnectionD10.CLOSE_NOCLOSE,"timeout");
|
||||
closeChannel(channel,WebSocketConnectionD12.CLOSE_NOCLOSE,"timeout");
|
||||
if (exception!=null)
|
||||
throw new ExecutionException(exception);
|
||||
if (connection!=null)
|
||||
|
@ -773,7 +794,7 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
{
|
||||
__log.warn(e);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
channel.close();
|
||||
|
@ -784,5 +805,5 @@ public class WebSocketClient extends AggregateLifeCycle
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -38,11 +38,11 @@ import org.eclipse.jetty.websocket.WebSocket.OnBinaryMessage;
|
|||
import org.eclipse.jetty.websocket.WebSocket.OnControl;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnFrame;
|
||||
import org.eclipse.jetty.websocket.WebSocket.OnTextMessage;
|
||||
import org.eclipse.jetty.websocket.WebSocketGeneratorD10.MaskGen;
|
||||
import org.eclipse.jetty.websocket.WebSocketGeneratorD12.MaskGen;
|
||||
|
||||
public class WebSocketConnectionD10 extends AbstractConnection implements WebSocketConnection
|
||||
public class WebSocketConnectionD12 extends AbstractConnection implements WebSocketConnection
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketConnectionD10.class);
|
||||
private static final Logger LOG = Log.getLogger(WebSocketConnectionD12.class);
|
||||
|
||||
final static byte OP_CONTINUATION = 0x00;
|
||||
final static byte OP_TEXT = 0x01;
|
||||
|
@ -81,9 +81,9 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
private final static byte[] MAGIC;
|
||||
private final IdleCheck _idle;
|
||||
private final List<Extension> _extensions;
|
||||
private final WebSocketParserD10 _parser;
|
||||
private final WebSocketParserD12 _parser;
|
||||
private final WebSocketParser.FrameHandler _inbound;
|
||||
private final WebSocketGeneratorD10 _generator;
|
||||
private final WebSocketGeneratorD12 _generator;
|
||||
private final WebSocketGenerator _outbound;
|
||||
private final WebSocket _webSocket;
|
||||
private final OnFrame _onFrame;
|
||||
|
@ -122,14 +122,14 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public WebSocketConnectionD10(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol, List<Extension> extensions,int draft)
|
||||
public WebSocketConnectionD12(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol, List<Extension> extensions,int draft)
|
||||
throws IOException
|
||||
{
|
||||
this(websocket,endpoint,buffers,timestamp,maxIdleTime,protocol,extensions,draft,null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public WebSocketConnectionD10(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol, List<Extension> extensions,int draft, MaskGen maskgen)
|
||||
public WebSocketConnectionD12(WebSocket websocket, EndPoint endpoint, WebSocketBuffers buffers, long timestamp, int maxIdleTime, String protocol, List<Extension> extensions,int draft, MaskGen maskgen)
|
||||
throws IOException
|
||||
{
|
||||
super(endpoint,timestamp);
|
||||
|
@ -148,7 +148,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
_onTextMessage=_webSocket instanceof OnTextMessage ? (OnTextMessage)_webSocket : null;
|
||||
_onBinaryMessage=_webSocket instanceof OnBinaryMessage ? (OnBinaryMessage)_webSocket : null;
|
||||
_onControl=_webSocket instanceof OnControl ? (OnControl)_webSocket : null;
|
||||
_generator = new WebSocketGeneratorD10(buffers, _endp,maskgen);
|
||||
_generator = new WebSocketGeneratorD12(buffers, _endp,maskgen);
|
||||
|
||||
_extensions=extensions;
|
||||
if (_extensions!=null)
|
||||
|
@ -167,7 +167,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
_outbound=(_extensions==null||_extensions.size()==0)?_generator:extensions.get(extensions.size()-1);
|
||||
_inbound=(_extensions==null||_extensions.size()==0)?_frameHandler:extensions.get(0);
|
||||
|
||||
_parser = new WebSocketParserD10(buffers, endpoint,_inbound,maskgen==null);
|
||||
_parser = new WebSocketParserD12(buffers, endpoint,_inbound,maskgen==null);
|
||||
|
||||
_protocol=protocol;
|
||||
|
||||
|
@ -253,9 +253,10 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
finally
|
||||
{
|
||||
current.setContextClassLoader(oldcontext);
|
||||
_parser.returnBuffer();
|
||||
_generator.returnBuffer();
|
||||
if (_endp.isOpen())
|
||||
{
|
||||
_generator.idle();
|
||||
_idle.access(_endp);
|
||||
if (_closedIn && _closedOut && _outbound.isBufferEmpty())
|
||||
_endp.close();
|
||||
|
@ -264,7 +265,6 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
else
|
||||
checkWriteable();
|
||||
}
|
||||
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
public void idleExpired()
|
||||
{
|
||||
long idle = System.currentTimeMillis()-((SelectChannelEndPoint)_endp).getIdleTimestamp();
|
||||
closeOut(WebSocketConnectionD10.CLOSE_NORMAL,"Idle for "+idle+"ms");
|
||||
closeOut(WebSocketConnectionD12.CLOSE_NORMAL,"Idle for "+idle+"ms");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -297,10 +297,10 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
{
|
||||
closed=_closeCode==0;
|
||||
if (closed)
|
||||
_closeCode=WebSocketConnectionD10.CLOSE_NOCLOSE;
|
||||
_closeCode=WebSocketConnectionD12.CLOSE_NOCLOSE;
|
||||
}
|
||||
if (closed)
|
||||
_webSocket.onClose(WebSocketConnectionD10.CLOSE_NOCLOSE,"closed");
|
||||
_webSocket.onClose(WebSocketConnectionD12.CLOSE_NOCLOSE,"closed");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -376,11 +376,11 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
else
|
||||
{
|
||||
if (code<=0)
|
||||
code=WebSocketConnectionD10.CLOSE_NORMAL;
|
||||
code=WebSocketConnectionD12.CLOSE_NORMAL;
|
||||
byte[] bytes = ("xx"+(message==null?"":message)).getBytes(StringUtil.__ISO_8859_1);
|
||||
bytes[0]=(byte)(code/0x100);
|
||||
bytes[1]=(byte)(code%0x100);
|
||||
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD10.OP_CLOSE,bytes,0,bytes.length);
|
||||
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD12.OP_CLOSE,bytes,0,bytes.length);
|
||||
}
|
||||
_outbound.flush();
|
||||
|
||||
|
@ -413,8 +413,8 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
private class WSFrameConnection implements WebSocket.FrameConnection
|
||||
{
|
||||
volatile boolean _disconnecting;
|
||||
int _maxTextMessage=WebSocketConnectionD10.this._maxTextMessageSize;
|
||||
int _maxBinaryMessage=WebSocketConnectionD10.this._maxBinaryMessageSize;
|
||||
int _maxTextMessage=WebSocketConnectionD12.this._maxTextMessageSize;
|
||||
int _maxBinaryMessage=WebSocketConnectionD12.this._maxBinaryMessageSize;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void sendMessage(String content) throws IOException
|
||||
|
@ -422,7 +422,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
if (_closedOut)
|
||||
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
|
||||
byte[] data = content.getBytes(StringUtil.__UTF8);
|
||||
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD10.OP_TEXT,data,0,data.length);
|
||||
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD12.OP_TEXT,data,0,data.length);
|
||||
checkWriteable();
|
||||
_idle.access(_endp);
|
||||
}
|
||||
|
@ -432,7 +432,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
{
|
||||
if (_closedOut)
|
||||
throw new IOException("closedOut "+_closeCode+":"+_closeMessage);
|
||||
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD10.OP_BINARY,content,offset,length);
|
||||
_outbound.addFrame((byte)FLAG_FIN,WebSocketConnectionD12.OP_BINARY,content,offset,length);
|
||||
checkWriteable();
|
||||
_idle.access(_endp);
|
||||
}
|
||||
|
@ -475,7 +475,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
if (_disconnecting)
|
||||
return;
|
||||
_disconnecting=true;
|
||||
WebSocketConnectionD10.this.closeOut(code,message);
|
||||
WebSocketConnectionD12.this.closeOut(code,message);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -593,6 +593,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return this.getClass().getSimpleName()+"@"+_endp.getLocalAddr()+":"+_endp.getLocalPort()+"<->"+_endp.getRemoteAddr()+":"+_endp.getRemotePort();
|
||||
|
@ -612,7 +613,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
{
|
||||
boolean lastFrame = isLastFrame(flags);
|
||||
|
||||
synchronized(WebSocketConnectionD10.this)
|
||||
synchronized(WebSocketConnectionD12.this)
|
||||
{
|
||||
// Ignore incoming after a close
|
||||
if (_closedIn)
|
||||
|
@ -637,10 +638,10 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
|
||||
switch(opcode)
|
||||
{
|
||||
case WebSocketConnectionD10.OP_CONTINUATION:
|
||||
case WebSocketConnectionD12.OP_CONTINUATION:
|
||||
{
|
||||
// If text, append to the message buffer
|
||||
if (_onTextMessage!=null && _opcode==WebSocketConnectionD10.OP_TEXT)
|
||||
if (_onTextMessage!=null && _opcode==WebSocketConnectionD12.OP_TEXT)
|
||||
{
|
||||
if (_utf8.append(buffer.array(),buffer.getIndex(),buffer.length(),_connection.getMaxTextMessageSize()))
|
||||
{
|
||||
|
@ -680,23 +681,23 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
}
|
||||
break;
|
||||
}
|
||||
case WebSocketConnectionD10.OP_PING:
|
||||
case WebSocketConnectionD12.OP_PING:
|
||||
{
|
||||
LOG.debug("PING {}",this);
|
||||
if (!_closedOut)
|
||||
_connection.sendControl(WebSocketConnectionD10.OP_PONG,buffer.array(),buffer.getIndex(),buffer.length());
|
||||
_connection.sendControl(WebSocketConnectionD12.OP_PONG,buffer.array(),buffer.getIndex(),buffer.length());
|
||||
break;
|
||||
}
|
||||
|
||||
case WebSocketConnectionD10.OP_PONG:
|
||||
case WebSocketConnectionD12.OP_PONG:
|
||||
{
|
||||
LOG.debug("PONG {}",this);
|
||||
break;
|
||||
}
|
||||
|
||||
case WebSocketConnectionD10.OP_CLOSE:
|
||||
case WebSocketConnectionD12.OP_CLOSE:
|
||||
{
|
||||
int code=WebSocketConnectionD10.CLOSE_NOCODE;
|
||||
int code=WebSocketConnectionD12.CLOSE_NOCODE;
|
||||
String message=null;
|
||||
if (buffer.length()>=2)
|
||||
{
|
||||
|
@ -708,7 +709,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
break;
|
||||
}
|
||||
|
||||
case WebSocketConnectionD10.OP_TEXT:
|
||||
case WebSocketConnectionD12.OP_TEXT:
|
||||
{
|
||||
if(_onTextMessage!=null)
|
||||
{
|
||||
|
@ -728,7 +729,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
}
|
||||
else
|
||||
{
|
||||
_opcode=WebSocketConnectionD10.OP_TEXT;
|
||||
_opcode=WebSocketConnectionD12.OP_TEXT;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -772,7 +773,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
int max = _connection.getMaxBinaryMessageSize();
|
||||
if (max>0 && (bufferLen+length)>max)
|
||||
{
|
||||
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Message size > "+_connection.getMaxBinaryMessageSize());
|
||||
_connection.close(WebSocketConnectionD12.CLOSE_LARGE,"Message size > "+_connection.getMaxBinaryMessageSize());
|
||||
_opcode=-1;
|
||||
if (_aggregate!=null)
|
||||
_aggregate.clear();
|
||||
|
@ -783,7 +784,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
|
||||
private void textMessageTooLarge()
|
||||
{
|
||||
_connection.close(WebSocketConnectionD10.CLOSE_LARGE,"Text message size > "+_connection.getMaxTextMessageSize()+" chars");
|
||||
_connection.close(WebSocketConnectionD12.CLOSE_LARGE,"Text message size > "+_connection.getMaxTextMessageSize()+" chars");
|
||||
|
||||
_opcode=-1;
|
||||
_utf8.reset();
|
||||
|
@ -796,9 +797,10 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
_connection.close(code,message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return WebSocketConnectionD10.this.toString()+"FH";
|
||||
return WebSocketConnectionD12.this.toString()+"FH";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -850,6 +852,7 @@ public class WebSocketConnectionD10 extends AbstractConnection implements WebSoc
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "WS/D"+_draft+"-"+_endp;
|
|
@ -181,8 +181,10 @@ public class WebSocketFactory
|
|||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
extensions= initExtensions(extensions_requested,8-WebSocketConnectionD10.OP_EXT_DATA, 16-WebSocketConnectionD10.OP_EXT_CTRL,3);
|
||||
connection = new WebSocketConnectionD10(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol,extensions,draft);
|
||||
case 11:
|
||||
case 12:
|
||||
extensions= initExtensions(extensions_requested,8-WebSocketConnectionD12.OP_EXT_DATA, 16-WebSocketConnectionD12.OP_EXT_CTRL,3);
|
||||
connection = new WebSocketConnectionD12(websocket, endp, _buffers, http.getTimeStamp(), _maxIdleTime, protocol,extensions,draft);
|
||||
break;
|
||||
default:
|
||||
LOG.warn("Unsupported Websocket version: "+draft);
|
||||
|
@ -219,9 +221,9 @@ public class WebSocketFactory
|
|||
{
|
||||
if ("websocket".equalsIgnoreCase(request.getHeader("Upgrade")))
|
||||
{
|
||||
String origin = request.getHeader("Sec-WebSocket-Origin");
|
||||
String origin = request.getHeader("Origin");
|
||||
if (origin==null)
|
||||
origin = request.getHeader("Origin");
|
||||
origin = request.getHeader("Sec-WebSocket-Origin");
|
||||
if (!_acceptor.checkOrigin(request,origin))
|
||||
{
|
||||
response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.eclipse.jetty.io.EofException;
|
|||
* threads will call the addMessage methods while other
|
||||
* threads are flushing the generator.
|
||||
*/
|
||||
public class WebSocketGeneratorD10 implements WebSocketGenerator
|
||||
public class WebSocketGeneratorD12 implements WebSocketGenerator
|
||||
{
|
||||
final private WebSocketBuffers _buffers;
|
||||
final private EndPoint _endp;
|
||||
|
@ -93,20 +93,25 @@ public class WebSocketGeneratorD10 implements WebSocketGenerator
|
|||
}
|
||||
|
||||
|
||||
public WebSocketGeneratorD10(WebSocketBuffers buffers, EndPoint endp)
|
||||
public WebSocketGeneratorD12(WebSocketBuffers buffers, EndPoint endp)
|
||||
{
|
||||
_buffers=buffers;
|
||||
_endp=endp;
|
||||
_maskGen=null;
|
||||
}
|
||||
|
||||
public WebSocketGeneratorD10(WebSocketBuffers buffers, EndPoint endp, MaskGen maskGen)
|
||||
public WebSocketGeneratorD12(WebSocketBuffers buffers, EndPoint endp, MaskGen maskGen)
|
||||
{
|
||||
_buffers=buffers;
|
||||
_endp=endp;
|
||||
_maskGen=maskGen;
|
||||
}
|
||||
|
||||
public synchronized Buffer getBuffer()
|
||||
{
|
||||
return _buffer;
|
||||
}
|
||||
|
||||
public synchronized void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException
|
||||
{
|
||||
// System.err.printf("<< %s %s %s\n",TypeUtil.toHexString(flags),TypeUtil.toHexString(opcode),length);
|
||||
|
@ -116,14 +121,14 @@ public class WebSocketGeneratorD10 implements WebSocketGenerator
|
|||
if (_buffer==null)
|
||||
_buffer=mask?_buffers.getBuffer():_buffers.getDirectBuffer();
|
||||
|
||||
boolean last=WebSocketConnectionD10.isLastFrame(flags);
|
||||
boolean last=WebSocketConnectionD12.isLastFrame(flags);
|
||||
byte orig=opcode;
|
||||
|
||||
int space=mask?14:10;
|
||||
|
||||
do
|
||||
{
|
||||
opcode = _opsent?WebSocketConnectionD10.OP_CONTINUATION:opcode;
|
||||
opcode = _opsent?WebSocketConnectionD12.OP_CONTINUATION:opcode;
|
||||
opcode=(byte)(((0xf&flags)<<4)+(0xf&opcode));
|
||||
_opsent=true;
|
||||
|
||||
|
@ -273,7 +278,7 @@ public class WebSocketGeneratorD10 implements WebSocketGenerator
|
|||
return _buffer==null || _buffer.length()==0;
|
||||
}
|
||||
|
||||
public synchronized void idle()
|
||||
public synchronized void returnBuffer()
|
||||
{
|
||||
if (_buffer!=null && _buffer.length()==0)
|
||||
{
|
|
@ -28,9 +28,9 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
* Parser the WebSocket protocol.
|
||||
*
|
||||
*/
|
||||
public class WebSocketParserD10 implements WebSocketParser
|
||||
public class WebSocketParserD12 implements WebSocketParser
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketParserD10.class);
|
||||
private static final Logger LOG = Log.getLogger(WebSocketParserD12.class);
|
||||
|
||||
public enum State {
|
||||
|
||||
|
@ -73,7 +73,7 @@ public class WebSocketParserD10 implements WebSocketParser
|
|||
* @param endp
|
||||
* @param handler
|
||||
*/
|
||||
public WebSocketParserD10(WebSocketBuffers buffers, EndPoint endp, FrameHandler handler, boolean shouldBeMasked)
|
||||
public WebSocketParserD12(WebSocketBuffers buffers, EndPoint endp, FrameHandler handler, boolean shouldBeMasked)
|
||||
{
|
||||
_buffers=buffers;
|
||||
_endp=endp;
|
||||
|
@ -124,7 +124,6 @@ public class WebSocketParserD10 implements WebSocketParser
|
|||
{
|
||||
if (_buffer==null)
|
||||
_buffer=_buffers.getBuffer();
|
||||
|
||||
int total_filled=0;
|
||||
int events=0;
|
||||
|
||||
|
@ -160,9 +159,9 @@ public class WebSocketParserD10 implements WebSocketParser
|
|||
// System.err.printf("%s %s %s >>\n",TypeUtil.toHexString(_flags),TypeUtil.toHexString(_opcode),data.length());
|
||||
events++;
|
||||
_bytesNeeded-=data.length();
|
||||
_handler.onFrame((byte)(_flags&(0xff^WebSocketConnectionD10.FLAG_FIN)), _opcode, data);
|
||||
_handler.onFrame((byte)(_flags&(0xff^WebSocketConnectionD12.FLAG_FIN)), _opcode, data);
|
||||
|
||||
_opcode=WebSocketConnectionD10.OP_CONTINUATION;
|
||||
_opcode=WebSocketConnectionD12.OP_CONTINUATION;
|
||||
}
|
||||
|
||||
if (_buffer.space() == 0)
|
||||
|
@ -205,11 +204,11 @@ public class WebSocketParserD10 implements WebSocketParser
|
|||
_opcode=(byte)(b&0xf);
|
||||
_flags=(byte)(0xf&(b>>4));
|
||||
|
||||
if (WebSocketConnectionD10.isControlFrame(_opcode)&&!WebSocketConnectionD10.isLastFrame(_flags))
|
||||
if (WebSocketConnectionD12.isControlFrame(_opcode)&&!WebSocketConnectionD12.isLastFrame(_flags))
|
||||
{
|
||||
events++;
|
||||
LOG.warn("Fragmented Control from "+_endp);
|
||||
_handler.close(WebSocketConnectionD10.CLOSE_PROTOCOL,"Fragmented control");
|
||||
_handler.close(WebSocketConnectionD12.CLOSE_PROTOCOL,"Fragmented control");
|
||||
_skip=true;
|
||||
}
|
||||
|
||||
|
@ -250,7 +249,7 @@ public class WebSocketParserD10 implements WebSocketParser
|
|||
if (_length>_buffer.capacity() && !_fakeFragments)
|
||||
{
|
||||
events++;
|
||||
_handler.close(WebSocketConnectionD10.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
|
||||
_handler.close(WebSocketConnectionD12.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
|
||||
_skip=true;
|
||||
}
|
||||
|
||||
|
@ -269,7 +268,7 @@ public class WebSocketParserD10 implements WebSocketParser
|
|||
if (_length>=_buffer.capacity())
|
||||
{
|
||||
events++;
|
||||
_handler.close(WebSocketConnectionD10.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
|
||||
_handler.close(WebSocketConnectionD12.CLOSE_LARGE,"frame size "+_length+">"+_buffer.capacity());
|
||||
_skip=true;
|
||||
}
|
||||
|
||||
|
@ -312,7 +311,7 @@ public class WebSocketParserD10 implements WebSocketParser
|
|||
_buffer.skip(_bytesNeeded);
|
||||
_state=State.START;
|
||||
events++;
|
||||
_handler.close(WebSocketConnectionD10.CLOSE_PROTOCOL,"bad mask");
|
||||
_handler.close(WebSocketConnectionD12.CLOSE_PROTOCOL,"bad mask");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -334,12 +333,6 @@ public class WebSocketParserD10 implements WebSocketParser
|
|||
_state=State.START;
|
||||
}
|
||||
|
||||
if (_buffer.length()==0)
|
||||
{
|
||||
_buffers.returnBuffer(_buffer);
|
||||
_buffer=null;
|
||||
}
|
||||
|
||||
return total_filled+events;
|
||||
}
|
||||
}
|
||||
|
@ -352,9 +345,28 @@ public class WebSocketParserD10 implements WebSocketParser
|
|||
{
|
||||
if (_buffer==null)
|
||||
_buffer=_buffers.getBuffer();
|
||||
|
||||
_buffer.put(buffer);
|
||||
buffer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void returnBuffer()
|
||||
{
|
||||
if (_buffer!=null && _buffer.length()==0)
|
||||
{
|
||||
_buffers.returnBuffer(_buffer);
|
||||
_buffer=null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
Buffer buffer=_buffer;
|
||||
return WebSocketParserD12.class.getSimpleName()+"@"+ Integer.toHexString(hashCode())+"|"+_state+"|"+(buffer==null?"<>":buffer.toDetailString());
|
||||
}
|
||||
|
||||
}
|
|
@ -14,8 +14,6 @@
|
|||
package org.eclipse.jetty.websocket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
|
|
|
@ -110,7 +110,7 @@ public class WebSocketClientTest
|
|||
}
|
||||
|
||||
Assert.assertFalse(open.get());
|
||||
Assert.assertEquals(WebSocketConnectionD10.CLOSE_NOCLOSE,close.get());
|
||||
Assert.assertEquals(WebSocketConnectionD12.CLOSE_NOCLOSE,close.get());
|
||||
Assert.assertTrue(error instanceof ConnectException);
|
||||
|
||||
}
|
||||
|
@ -151,7 +151,7 @@ public class WebSocketClientTest
|
|||
}
|
||||
|
||||
Assert.assertFalse(open.get());
|
||||
Assert.assertEquals(WebSocketConnectionD10.CLOSE_NOCLOSE,close.get());
|
||||
Assert.assertEquals(WebSocketConnectionD12.CLOSE_NOCLOSE,close.get());
|
||||
Assert.assertTrue(error instanceof TimeoutException);
|
||||
|
||||
}
|
||||
|
@ -191,7 +191,7 @@ public class WebSocketClientTest
|
|||
}
|
||||
|
||||
Assert.assertFalse(open.get());
|
||||
Assert.assertEquals(WebSocketConnectionD10.CLOSE_NOCLOSE,close.get());
|
||||
Assert.assertEquals(WebSocketConnectionD12.CLOSE_NOCLOSE,close.get());
|
||||
Assert.assertTrue(error instanceof TimeoutException);
|
||||
|
||||
}
|
||||
|
@ -233,7 +233,7 @@ public class WebSocketClientTest
|
|||
}
|
||||
|
||||
Assert.assertFalse(open.get());
|
||||
Assert.assertEquals(WebSocketConnectionD10.CLOSE_PROTOCOL,close.get());
|
||||
Assert.assertEquals(WebSocketConnectionD12.CLOSE_PROTOCOL,close.get());
|
||||
Assert.assertTrue(error instanceof IOException);
|
||||
Assert.assertTrue(error.getMessage().indexOf("404 NOT FOUND")>0);
|
||||
|
||||
|
@ -277,7 +277,7 @@ public class WebSocketClientTest
|
|||
error=e.getCause();
|
||||
}
|
||||
Assert.assertFalse(open.get());
|
||||
Assert.assertEquals(WebSocketConnectionD10.CLOSE_PROTOCOL,close.get());
|
||||
Assert.assertEquals(WebSocketConnectionD12.CLOSE_PROTOCOL,close.get());
|
||||
Assert.assertTrue(error instanceof IOException);
|
||||
Assert.assertTrue(error.getMessage().indexOf("Bad Sec-WebSocket-Accept")>=0);
|
||||
}
|
||||
|
@ -316,7 +316,7 @@ public class WebSocketClientTest
|
|||
socket.close();
|
||||
_latch.await(10,TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertEquals(WebSocketConnectionD10.CLOSE_NOCLOSE,close.get());
|
||||
Assert.assertEquals(WebSocketConnectionD12.CLOSE_NOCLOSE,close.get());
|
||||
|
||||
}
|
||||
|
||||
|
@ -355,7 +355,7 @@ public class WebSocketClientTest
|
|||
long start=System.currentTimeMillis();
|
||||
_latch.await(10,TimeUnit.SECONDS);
|
||||
Assert.assertTrue(System.currentTimeMillis()-start<5000);
|
||||
Assert.assertEquals(WebSocketConnectionD10.CLOSE_NORMAL,close.get());
|
||||
Assert.assertEquals(WebSocketConnectionD12.CLOSE_NORMAL,close.get());
|
||||
}
|
||||
|
||||
|
||||
|
@ -482,7 +482,7 @@ public class WebSocketClientTest
|
|||
}
|
||||
connection.getOutputStream().write((
|
||||
"HTTP/1.1 101 Upgrade\r\n" +
|
||||
"Sec-WebSocket-Accept: "+ WebSocketConnectionD10.hashKey(key) +"\r\n" +
|
||||
"Sec-WebSocket-Accept: "+ WebSocketConnectionD12.hashKey(key) +"\r\n" +
|
||||
"\r\n").getBytes());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ import org.junit.Test;
|
|||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public class WebSocketGeneratorD10Test
|
||||
public class WebSocketGeneratorD12Test
|
||||
{
|
||||
private ByteArrayBuffer _out;
|
||||
private WebSocketGenerator _generator;
|
||||
|
@ -20,7 +20,7 @@ public class WebSocketGeneratorD10Test
|
|||
byte[] _mask = new byte[4];
|
||||
int _m;
|
||||
|
||||
public WebSocketGeneratorD10.MaskGen _maskGen = new WebSocketGeneratorD10.FixedMaskGen(
|
||||
public WebSocketGeneratorD12.MaskGen _maskGen = new WebSocketGeneratorD12.FixedMaskGen(
|
||||
new byte[]{(byte)0x00,(byte)0x00,(byte)0x0f,(byte)0xff});
|
||||
|
||||
@Before
|
||||
|
@ -42,7 +42,7 @@ public class WebSocketGeneratorD10Test
|
|||
@Test
|
||||
public void testOneString() throws Exception
|
||||
{
|
||||
_generator = new WebSocketGeneratorD10(_buffers, _endPoint,null);
|
||||
_generator = new WebSocketGeneratorD12(_buffers, _endPoint,null);
|
||||
|
||||
byte[] data = "Hell\uFF4F W\uFF4Frld".getBytes(StringUtil.__UTF8);
|
||||
_generator.addFrame((byte)0x8,(byte)0x04,data,0,data.length);
|
||||
|
@ -69,7 +69,7 @@ public class WebSocketGeneratorD10Test
|
|||
@Test
|
||||
public void testOneBuffer() throws Exception
|
||||
{
|
||||
_generator = new WebSocketGeneratorD10(_buffers, _endPoint,null);
|
||||
_generator = new WebSocketGeneratorD12(_buffers, _endPoint,null);
|
||||
|
||||
String string = "Hell\uFF4F W\uFF4Frld";
|
||||
byte[] bytes=string.getBytes(StringUtil.__UTF8);
|
||||
|
@ -97,7 +97,7 @@ public class WebSocketGeneratorD10Test
|
|||
@Test
|
||||
public void testOneLongBuffer() throws Exception
|
||||
{
|
||||
_generator = new WebSocketGeneratorD10(_buffers, _endPoint,null);
|
||||
_generator = new WebSocketGeneratorD12(_buffers, _endPoint,null);
|
||||
|
||||
byte[] b=new byte[150];
|
||||
for (int i=0;i<b.length;i++)
|
||||
|
@ -118,7 +118,7 @@ public class WebSocketGeneratorD10Test
|
|||
@Test
|
||||
public void testOneStringMasked() throws Exception
|
||||
{
|
||||
_generator = new WebSocketGeneratorD10(_buffers, _endPoint,_maskGen);
|
||||
_generator = new WebSocketGeneratorD12(_buffers, _endPoint,_maskGen);
|
||||
|
||||
byte[] data = "Hell\uFF4F W\uFF4Frld".getBytes(StringUtil.__UTF8);
|
||||
_generator.addFrame((byte)0x8,(byte)0x04,data,0,data.length);
|
||||
|
@ -147,7 +147,7 @@ public class WebSocketGeneratorD10Test
|
|||
@Test
|
||||
public void testOneBufferMasked() throws Exception
|
||||
{
|
||||
_generator = new WebSocketGeneratorD10(_buffers, _endPoint,_maskGen);
|
||||
_generator = new WebSocketGeneratorD12(_buffers, _endPoint,_maskGen);
|
||||
|
||||
String string = "Hell\uFF4F W\uFF4Frld";
|
||||
byte[] bytes=string.getBytes(StringUtil.__UTF8);
|
||||
|
@ -177,7 +177,7 @@ public class WebSocketGeneratorD10Test
|
|||
@Test
|
||||
public void testOneLongBufferMasked() throws Exception
|
||||
{
|
||||
_generator = new WebSocketGeneratorD10(_buffers, _endPoint,_maskGen);
|
||||
_generator = new WebSocketGeneratorD12(_buffers, _endPoint,_maskGen);
|
||||
|
||||
byte[] b=new byte[150];
|
||||
for (int i=0;i<b.length;i++)
|
|
@ -33,7 +33,7 @@ import org.junit.Test;
|
|||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public class WebSocketLoadD10Test
|
||||
public class WebSocketLoadD12Test
|
||||
{
|
||||
private static Server _server;
|
||||
private static Connector _connector;
|
||||
|
@ -142,8 +142,8 @@ public class WebSocketLoadD10Test
|
|||
private final int iterations;
|
||||
private final CountDownLatch latch;
|
||||
private final SocketEndPoint _endp;
|
||||
private final WebSocketGeneratorD10 _generator;
|
||||
private final WebSocketParserD10 _parser;
|
||||
private final WebSocketGeneratorD12 _generator;
|
||||
private final WebSocketParserD12 _parser;
|
||||
private final WebSocketParser.FrameHandler _handler = new WebSocketParser.FrameHandler()
|
||||
{
|
||||
public void onFrame(byte flags, byte opcode, Buffer buffer)
|
||||
|
@ -167,8 +167,8 @@ public class WebSocketLoadD10Test
|
|||
this.iterations = iterations;
|
||||
|
||||
_endp=new SocketEndPoint(socket);
|
||||
_generator = new WebSocketGeneratorD10(new WebSocketBuffers(32*1024),_endp,new WebSocketGeneratorD10.FixedMaskGen());
|
||||
_parser = new WebSocketParserD10(new WebSocketBuffers(32*1024),_endp,_handler,false);
|
||||
_generator = new WebSocketGeneratorD12(new WebSocketBuffers(32*1024),_endp,new WebSocketGeneratorD12.FixedMaskGen());
|
||||
_parser = new WebSocketParserD12(new WebSocketBuffers(32*1024),_endp,_handler,false);
|
||||
|
||||
}
|
||||
|
||||
|
@ -202,7 +202,7 @@ public class WebSocketLoadD10Test
|
|||
for (int i = 0; i < iterations; ++i)
|
||||
{
|
||||
byte[] data = message.getBytes(StringUtil.__UTF8);
|
||||
_generator.addFrame((byte)0x8,WebSocketConnectionD10.OP_TEXT,data,0,data.length);
|
||||
_generator.addFrame((byte)0x8,WebSocketConnectionD12.OP_TEXT,data,0,data.length);
|
||||
_generator.flush();
|
||||
|
||||
//System.err.println("-> "+message);
|
|
@ -33,7 +33,7 @@ import org.junit.Test;
|
|||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public class WebSocketMessageD10Test
|
||||
public class WebSocketMessageD12Test
|
||||
{
|
||||
private static Server _server;
|
||||
private static Connector _connector;
|
||||
|
@ -74,7 +74,7 @@ public class WebSocketMessageD10Test
|
|||
@Test
|
||||
public void testHash()
|
||||
{
|
||||
assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",WebSocketConnectionD10.hashKey("dGhlIHNhbXBsZSBub25jZQ=="));
|
||||
assertEquals("s3pPLMBiTxaQ9kYGzzhZRbK+xOo=",WebSocketConnectionD12.hashKey("dGhlIHNhbXBsZSBub25jZQ=="));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -115,7 +115,7 @@ public class WebSocketMessageD10Test
|
|||
String data=message.toString();
|
||||
_serverWebSocket.connection.sendMessage(data);
|
||||
|
||||
assertEquals(WebSocketConnectionD10.OP_TEXT,input.read());
|
||||
assertEquals(WebSocketConnectionD12.OP_TEXT,input.read());
|
||||
assertEquals(0x7e,input.read());
|
||||
assertEquals(0x1f,input.read());
|
||||
assertEquals(0xf6,input.read());
|
||||
|
@ -321,7 +321,7 @@ public class WebSocketMessageD10Test
|
|||
output.write(buf,0,l+3);
|
||||
output.flush();
|
||||
|
||||
assertEquals(0x40+WebSocketConnectionD10.OP_TEXT,input.read());
|
||||
assertEquals(0x40+WebSocketConnectionD12.OP_TEXT,input.read());
|
||||
assertEquals(0x20+3,input.read());
|
||||
assertEquals(0x7e,input.read());
|
||||
assertEquals(0x02,input.read());
|
||||
|
@ -489,7 +489,7 @@ public class WebSocketMessageD10Test
|
|||
output.write(bytes[i]^0xff);
|
||||
output.flush();
|
||||
|
||||
assertEquals(0x80|WebSocketConnectionD10.OP_CLOSE,input.read());
|
||||
assertEquals(0x80|WebSocketConnectionD12.OP_CLOSE,input.read());
|
||||
assertEquals(30,input.read());
|
||||
int code=(0xff&input.read())*0x100+(0xff&input.read());
|
||||
assertEquals(1004,code);
|
||||
|
@ -540,7 +540,7 @@ public class WebSocketMessageD10Test
|
|||
|
||||
|
||||
|
||||
assertEquals(0x80|WebSocketConnectionD10.OP_CLOSE,input.read());
|
||||
assertEquals(0x80|WebSocketConnectionD12.OP_CLOSE,input.read());
|
||||
assertEquals(30,input.read());
|
||||
int code=(0xff&input.read())*0x100+(0xff&input.read());
|
||||
assertEquals(1004,code);
|
||||
|
@ -576,7 +576,7 @@ public class WebSocketMessageD10Test
|
|||
assertNotNull(_serverWebSocket.connection);
|
||||
_serverWebSocket.getConnection().setMaxBinaryMessageSize(1024);
|
||||
|
||||
output.write(WebSocketConnectionD10.OP_BINARY);
|
||||
output.write(WebSocketConnectionD12.OP_BINARY);
|
||||
output.write(0x8a);
|
||||
output.write(0xff);
|
||||
output.write(0xff);
|
||||
|
@ -597,7 +597,7 @@ public class WebSocketMessageD10Test
|
|||
output.write(bytes[i]^0xff);
|
||||
output.flush();
|
||||
|
||||
assertEquals(0x80+WebSocketConnectionD10.OP_BINARY,input.read());
|
||||
assertEquals(0x80+WebSocketConnectionD12.OP_BINARY,input.read());
|
||||
assertEquals(20,input.read());
|
||||
lookFor("01234567890123456789",input);
|
||||
}
|
||||
|
@ -654,7 +654,7 @@ public class WebSocketMessageD10Test
|
|||
output.flush();
|
||||
|
||||
|
||||
assertEquals(0x80|WebSocketConnectionD10.OP_CLOSE,input.read());
|
||||
assertEquals(0x80|WebSocketConnectionD12.OP_CLOSE,input.read());
|
||||
assertEquals(19,input.read());
|
||||
int code=(0xff&input.read())*0x100+(0xff&input.read());
|
||||
assertEquals(1004,code);
|
||||
|
@ -703,7 +703,7 @@ public class WebSocketMessageD10Test
|
|||
output.write(bytes[i]^0xff);
|
||||
output.flush();
|
||||
|
||||
assertEquals(0x80|WebSocketConnectionD10.OP_CLOSE,input.read());
|
||||
assertEquals(0x80|WebSocketConnectionD12.OP_CLOSE,input.read());
|
||||
assertEquals(19,input.read());
|
||||
int code=(0xff&input.read())*0x100+(0xff&input.read());
|
||||
assertEquals(1004,code);
|
||||
|
@ -829,14 +829,14 @@ public class WebSocketMessageD10Test
|
|||
final AtomicReference<String> received = new AtomicReference<String>();
|
||||
ByteArrayEndPoint endp = new ByteArrayEndPoint(new byte[0],4096);
|
||||
|
||||
WebSocketGeneratorD10 gen = new WebSocketGeneratorD10(new WebSocketBuffers(8096),endp,null);
|
||||
WebSocketGeneratorD12 gen = new WebSocketGeneratorD12(new WebSocketBuffers(8096),endp,null);
|
||||
|
||||
byte[] data = message.getBytes(StringUtil.__UTF8);
|
||||
gen.addFrame((byte)0x8,(byte)0x4,data,0,data.length);
|
||||
|
||||
endp = new ByteArrayEndPoint(endp.getOut().asArray(),4096);
|
||||
|
||||
WebSocketParserD10 parser = new WebSocketParserD10(new WebSocketBuffers(8096),endp,new WebSocketParser.FrameHandler()
|
||||
WebSocketParserD12 parser = new WebSocketParserD12(new WebSocketBuffers(8096),endp,new WebSocketParser.FrameHandler()
|
||||
{
|
||||
public void onFrame(byte flags, byte opcode, Buffer buffer)
|
||||
{
|
||||
|
@ -861,15 +861,15 @@ public class WebSocketMessageD10Test
|
|||
final AtomicReference<String> received = new AtomicReference<String>();
|
||||
ByteArrayEndPoint endp = new ByteArrayEndPoint(new byte[0],4096);
|
||||
|
||||
WebSocketGeneratorD10.MaskGen maskGen = new WebSocketGeneratorD10.RandomMaskGen();
|
||||
WebSocketGeneratorD12.MaskGen maskGen = new WebSocketGeneratorD12.RandomMaskGen();
|
||||
|
||||
WebSocketGeneratorD10 gen = new WebSocketGeneratorD10(new WebSocketBuffers(8096),endp,maskGen);
|
||||
WebSocketGeneratorD12 gen = new WebSocketGeneratorD12(new WebSocketBuffers(8096),endp,maskGen);
|
||||
byte[] data = message.getBytes(StringUtil.__UTF8);
|
||||
gen.addFrame((byte)0x8,(byte)0x1,data,0,data.length);
|
||||
|
||||
endp = new ByteArrayEndPoint(endp.getOut().asArray(),4096);
|
||||
|
||||
WebSocketParserD10 parser = new WebSocketParserD10(new WebSocketBuffers(8096),endp,new WebSocketParser.FrameHandler()
|
||||
WebSocketParserD12 parser = new WebSocketParserD12(new WebSocketBuffers(8096),endp,new WebSocketParser.FrameHandler()
|
||||
{
|
||||
public void onFrame(byte flags, byte opcode, Buffer buffer)
|
||||
{
|
||||
|
@ -992,9 +992,9 @@ public class WebSocketMessageD10Test
|
|||
{
|
||||
switch(opcode)
|
||||
{
|
||||
case WebSocketConnectionD10.OP_CLOSE:
|
||||
case WebSocketConnectionD10.OP_PING:
|
||||
case WebSocketConnectionD10.OP_PONG:
|
||||
case WebSocketConnectionD12.OP_CLOSE:
|
||||
case WebSocketConnectionD12.OP_PING:
|
||||
case WebSocketConnectionD12.OP_PONG:
|
||||
break;
|
||||
|
||||
default:
|
|
@ -20,11 +20,11 @@ import org.junit.Test;
|
|||
/**
|
||||
* @version $Revision$ $Date$
|
||||
*/
|
||||
public class WebSocketParserD10Test
|
||||
public class WebSocketParserD12Test
|
||||
{
|
||||
private MaskedByteArrayBuffer _in;
|
||||
private Handler _handler;
|
||||
private WebSocketParserD10 _parser;
|
||||
private WebSocketParserD12 _parser;
|
||||
private byte[] _mask = new byte[] {(byte)0x00,(byte)0xF0,(byte)0x0F,(byte)0xFF};
|
||||
private int _m;
|
||||
|
||||
|
@ -87,7 +87,7 @@ public class WebSocketParserD10Test
|
|||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
endPoint.setNonBlocking(true);
|
||||
_handler = new Handler();
|
||||
_parser=new WebSocketParserD10(buffers, endPoint,_handler,true);
|
||||
_parser=new WebSocketParserD12(buffers, endPoint,_handler,true);
|
||||
_parser.setFakeFragments(false);
|
||||
_in = new MaskedByteArrayBuffer();
|
||||
|
||||
|
@ -113,6 +113,7 @@ public class WebSocketParserD10Test
|
|||
assertEquals(0xf,_handler._flags);
|
||||
assertEquals(0xf,_handler._opcode);
|
||||
assertTrue(_parser.isBufferEmpty());
|
||||
_parser.returnBuffer();
|
||||
assertTrue(_parser.getBuffer()==null);
|
||||
}
|
||||
|
||||
|
@ -132,6 +133,7 @@ public class WebSocketParserD10Test
|
|||
assertEquals(0x8,_handler._flags);
|
||||
assertEquals(0x1,_handler._opcode);
|
||||
assertTrue(_parser.isBufferEmpty());
|
||||
_parser.returnBuffer();
|
||||
assertTrue(_parser.getBuffer()==null);
|
||||
}
|
||||
|
||||
|
@ -152,6 +154,7 @@ public class WebSocketParserD10Test
|
|||
assertEquals(string,_handler._data.get(0));
|
||||
assertEquals(0x8,_handler._flags);
|
||||
assertEquals(0x1,_handler._opcode);
|
||||
_parser.returnBuffer();
|
||||
assertTrue(_parser.isBufferEmpty());
|
||||
assertTrue(_parser.getBuffer()==null);
|
||||
}
|
||||
|
@ -179,6 +182,7 @@ public class WebSocketParserD10Test
|
|||
assertEquals(string,_handler._data.get(0));
|
||||
assertEquals(0x8,_handler._flags);
|
||||
assertEquals(0x1,_handler._opcode);
|
||||
_parser.returnBuffer();
|
||||
assertTrue(_parser.isBufferEmpty());
|
||||
assertTrue(_parser.getBuffer()==null);
|
||||
}
|
||||
|
@ -188,7 +192,7 @@ public class WebSocketParserD10Test
|
|||
{
|
||||
WebSocketBuffers buffers = new WebSocketBuffers(0x20000);
|
||||
ByteArrayEndPoint endPoint = new ByteArrayEndPoint();
|
||||
WebSocketParser parser=new WebSocketParserD10(buffers, endPoint,_handler,false);
|
||||
WebSocketParserD12 parser=new WebSocketParserD12(buffers, endPoint,_handler,false);
|
||||
ByteArrayBuffer in = new ByteArrayBuffer(0x20000);
|
||||
endPoint.setIn(in);
|
||||
|
||||
|
@ -213,6 +217,7 @@ public class WebSocketParserD10Test
|
|||
in.put(bytes);
|
||||
|
||||
int progress =parser.parseNext();
|
||||
parser.returnBuffer();
|
||||
|
||||
assertEquals(bytes.length+11,progress);
|
||||
assertEquals(string,_handler._data.get(0));
|
||||
|
@ -240,6 +245,7 @@ public class WebSocketParserD10Test
|
|||
assertFalse(_parser.getBuffer()==null);
|
||||
|
||||
progress =_parser.parseNext();
|
||||
_parser.returnBuffer();
|
||||
|
||||
assertEquals(1,progress);
|
||||
assertEquals("Hello World",_handler._data.get(0));
|
||||
|
@ -263,7 +269,7 @@ public class WebSocketParserD10Test
|
|||
|
||||
assertTrue(progress>0);
|
||||
|
||||
assertEquals(WebSocketConnectionD10.CLOSE_LARGE,_handler._code);
|
||||
assertEquals(WebSocketConnectionD12.CLOSE_LARGE,_handler._code);
|
||||
for (int i=0;i<2048;i++)
|
||||
_in.put((byte)'a');
|
||||
progress =_parser.parseNext();
|
||||
|
@ -307,7 +313,7 @@ public class WebSocketParserD10Test
|
|||
assertTrue(progress>0);
|
||||
|
||||
assertEquals(2,_handler._frames);
|
||||
assertEquals(WebSocketConnectionD10.OP_CONTINUATION,_handler._opcode);
|
||||
assertEquals(WebSocketConnectionD12.OP_CONTINUATION,_handler._opcode);
|
||||
}
|
||||
|
||||
private class Handler implements WebSocketParser.FrameHandler
|
|
@ -2,7 +2,9 @@
|
|||
<html><head>
|
||||
<title>WebSocket Chat</title>
|
||||
<script type='text/javascript'>
|
||||
|
||||
|
||||
if (!window.WebSocket && window.MozWebSocket)
|
||||
window.WebSocket=window.MozWebSocket;
|
||||
if (!window.WebSocket)
|
||||
alert("WebSocket not supported by this browser");
|
||||
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
<html><head>
|
||||
<title>WebSocket Chat</title>
|
||||
<script type='text/javascript'>
|
||||
|
||||
|
||||
if (!window.WebSocket && window.MozWebSocket)
|
||||
window.WebSocket=window.MozWebSocket;
|
||||
if (!window.WebSocket)
|
||||
alert("WebSocket not supported by this browser");
|
||||
|
||||
|
|
Loading…
Reference in New Issue