Merging from master

This commit is contained in:
Joakim Erdfelt 2011-08-25 12:09:36 -07:00
commit 4ace183764
65 changed files with 5673 additions and 224 deletions

3
.gitignore vendored
View File

@ -3,7 +3,10 @@ target/
.project
.settings
*/src/main/java/META-INF/
.pmd
*.log
*.swp
*.diff
*.patch
*.iml
.idea

View File

@ -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

View File

@ -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();
}
}
}

View File

@ -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);

View File

@ -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
}
}

View File

@ -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>

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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));
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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);
}

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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);
}
}
});
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}

View File

@ -12,7 +12,7 @@
// ========================================================================
package org.eclipse.jetty.monitor;
package org.eclipse.jetty.monitor.thread;
/* ------------------------------------------------------------ */

View File

@ -12,7 +12,7 @@
// ========================================================================
package org.eclipse.jetty.monitor;
package org.eclipse.jetty.monitor.thread;
/* ------------------------------------------------------------ */

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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));
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}
}

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -0,0 +1,3 @@
RequestCounter: Request counter
counter: current value of the counter
increment(): increment the counter

View File

@ -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;
}
}
}

View File

@ -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;
}

View File

@ -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");
}
}
}

View File

@ -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());
}
}

View File

@ -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);

View File

@ -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
}
}
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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)
{

View File

@ -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());
}
}

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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++)

View File

@ -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);

View File

@ -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:

View File

@ -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

View File

@ -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");

View File

@ -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");