demo websocket implementation
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@1087 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
parent
153bd88fc6
commit
f9455c7712
|
@ -38,5 +38,10 @@
|
|||
<artifactId>jetty-jmx</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -377,6 +377,15 @@
|
|||
<outputDirectory>${assembly.directory}</outputDirectory>
|
||||
<destFileName>start.jar</destFileName>
|
||||
</artifactItem>
|
||||
<artifactItem>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<type>jar</type>
|
||||
<overWrite>true</overWrite>
|
||||
<includes>**</includes>
|
||||
<outputDirectory>${assembly.directory}/lib</outputDirectory>
|
||||
</artifactItem>
|
||||
</artifactItems>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
@ -500,5 +509,10 @@
|
|||
<artifactId>jetty-policy</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#
|
||||
#===========================================================
|
||||
|
||||
OPTIONS=Server,jmx,resources,websocket
|
||||
|
||||
#===========================================================
|
||||
# The following is an example of the ini args to run the
|
||||
# server with a heap size, JMX remote enabled, JMX mbeans
|
||||
|
|
|
@ -485,6 +485,7 @@ public class HttpGenerator extends AbstractGenerator
|
|||
HttpFields.Field field = fields.getField(f);
|
||||
if (field==null)
|
||||
continue;
|
||||
|
||||
switch (field.getNameOrdinal())
|
||||
{
|
||||
case HttpHeaders.CONTENT_LENGTH_ORDINAL:
|
||||
|
@ -506,7 +507,8 @@ public class HttpGenerator extends AbstractGenerator
|
|||
break;
|
||||
|
||||
case HttpHeaders.TRANSFER_ENCODING_ORDINAL:
|
||||
if (_version == HttpVersions.HTTP_1_1_ORDINAL) transfer_encoding = field;
|
||||
if (_version == HttpVersions.HTTP_1_1_ORDINAL)
|
||||
transfer_encoding = field;
|
||||
// Do NOT add yet!
|
||||
break;
|
||||
|
||||
|
@ -566,6 +568,15 @@ public class HttpGenerator extends AbstractGenerator
|
|||
|
||||
break;
|
||||
}
|
||||
case HttpHeaderValues.UPGRADE_ORDINAL:
|
||||
{
|
||||
// special case for websocket connection ordering
|
||||
if (_method==null)
|
||||
{
|
||||
field.put(_header);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
case HttpHeaderValues.CLOSE_ORDINAL:
|
||||
{
|
||||
close=true;
|
||||
|
|
|
@ -42,7 +42,8 @@ public class HttpHeaderValues extends BufferCache
|
|||
PROCESSING="102-processing",
|
||||
TE="TE",
|
||||
BYTES="bytes",
|
||||
NO_CACHE="no-cache";
|
||||
NO_CACHE="no-cache",
|
||||
UPGRADE="Upgrade";
|
||||
|
||||
public final static int
|
||||
CLOSE_ORDINAL=1,
|
||||
|
@ -54,7 +55,8 @@ public class HttpHeaderValues extends BufferCache
|
|||
PROCESSING_ORDINAL=7,
|
||||
TE_ORDINAL=8,
|
||||
BYTES_ORDINAL=9,
|
||||
NO_CACHE_ORDINAL=10;
|
||||
NO_CACHE_ORDINAL=10,
|
||||
UPGRADE_ORDINAL=11;
|
||||
|
||||
public final static HttpHeaderValues CACHE= new HttpHeaderValues();
|
||||
|
||||
|
@ -68,7 +70,8 @@ public class HttpHeaderValues extends BufferCache
|
|||
PROCESSING_BUFFER=CACHE.add(PROCESSING, PROCESSING_ORDINAL),
|
||||
TE_BUFFER=CACHE.add(TE,TE_ORDINAL),
|
||||
BYTES_BUFFER=CACHE.add(BYTES,BYTES_ORDINAL),
|
||||
NO_CACHE_BUFFER=CACHE.add(NO_CACHE,NO_CACHE_ORDINAL);
|
||||
NO_CACHE_BUFFER=CACHE.add(NO_CACHE,NO_CACHE_ORDINAL),
|
||||
UPGRADE_BUFFER=CACHE.add(UPGRADE,UPGRADE_ORDINAL);
|
||||
|
||||
static
|
||||
{
|
||||
|
|
|
@ -32,9 +32,6 @@ import org.eclipse.jetty.util.thread.Timeout;
|
|||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* An Endpoint that can be scheduled by {@link SelectorManager}.
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class SelectChannelEndPoint extends ChannelEndPoint implements Runnable, AsyncEndPoint, ConnectedEndPoint
|
||||
{
|
||||
|
|
|
@ -648,7 +648,7 @@ public class ObjectMBean implements DynamicMBean
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.warn(Log.EXCEPTION, e);
|
||||
Log.warn(name+": "+metaData, e);
|
||||
throw new IllegalArgumentException(e.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ public class Server extends HandlerWrapper implements Attributes
|
|||
if (Server.class.getPackage()!=null && Server.class.getPackage().getImplementationVersion()!=null)
|
||||
_version=Server.class.getPackage().getImplementationVersion();
|
||||
else
|
||||
_version=System.getProperty("jetty.version","7.0.y.z-SNAPSHOT");
|
||||
_version=System.getProperty("jetty.version","7.0.2-SNAPSHOT");
|
||||
}
|
||||
private final Container _container=new Container();
|
||||
private final AttributesMap _attributes = new AttributesMap();
|
||||
|
|
|
@ -63,8 +63,8 @@ import org.eclipse.jetty.util.thread.Timeout.Task;
|
|||
public class SelectChannelConnector extends AbstractNIOConnector
|
||||
{
|
||||
protected ServerSocketChannel _acceptChannel;
|
||||
private long _lowResourcesConnections;
|
||||
private long _lowResourcesMaxIdleTime;
|
||||
private int _lowResourcesConnections;
|
||||
private int _lowResourcesMaxIdleTime;
|
||||
|
||||
private final SelectorManager _manager = new SelectorManager()
|
||||
{
|
||||
|
@ -226,7 +226,7 @@ public class SelectChannelConnector extends AbstractNIOConnector
|
|||
/**
|
||||
* @return the lowResourcesConnections
|
||||
*/
|
||||
public long getLowResourcesConnections()
|
||||
public int getLowResourcesConnections()
|
||||
{
|
||||
return _lowResourcesConnections;
|
||||
}
|
||||
|
@ -236,9 +236,9 @@ public class SelectChannelConnector extends AbstractNIOConnector
|
|||
* Set the number of connections, which if exceeded places this manager in low resources state.
|
||||
* This is not an exact measure as the connection count is averaged over the select sets.
|
||||
* @param lowResourcesConnections the number of connections
|
||||
* @see {@link #setLowResourcesMaxIdleTime(long)}
|
||||
* @see {@link #setLowResourcesMaxIdleTime(int)}
|
||||
*/
|
||||
public void setLowResourcesConnections(long lowResourcesConnections)
|
||||
public void setLowResourcesConnections(int lowResourcesConnections)
|
||||
{
|
||||
_lowResourcesConnections=lowResourcesConnections;
|
||||
}
|
||||
|
@ -247,27 +247,11 @@ public class SelectChannelConnector extends AbstractNIOConnector
|
|||
/**
|
||||
* @return the lowResourcesMaxIdleTime
|
||||
*/
|
||||
public long getLowResourcesMaxIdleTime()
|
||||
public int getLowResourcesMaxIdleTime()
|
||||
{
|
||||
return _lowResourcesMaxIdleTime;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set the period in ms that a connection is allowed to be idle when this there are more
|
||||
* than {@link #getLowResourcesConnections()} connections. This allows the server to rapidly close idle connections
|
||||
* in order to gracefully handle high load situations.
|
||||
* @param lowResourcesMaxIdleTime the period in ms that a connection is allowed to be idle when resources are low.
|
||||
* @see {@link #setMaxIdleTime(long)}
|
||||
* @deprecated use {@link #setLowResourceMaxIdleTime(int)}
|
||||
*/
|
||||
@Deprecated
|
||||
public void setLowResourcesMaxIdleTime(long lowResourcesMaxIdleTime)
|
||||
{
|
||||
_lowResourcesMaxIdleTime=lowResourcesMaxIdleTime;
|
||||
super.setLowResourceMaxIdleTime((int)lowResourcesMaxIdleTime); // TODO fix the name duplications
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Set the period in ms that a connection is allowed to be idle when this there are more
|
||||
|
|
|
@ -143,6 +143,9 @@ $(jetty.home)/lib/policy/jetty.policy
|
|||
$(jetty.home)/lib/jetty-http-$(version).jar ! available org.eclipse.jetty.http.HttpParser
|
||||
$(jetty.home)/lib/jetty-client-$(version).jar ! available org.eclipse.jetty.client.HttpClient
|
||||
|
||||
[All,websocket]
|
||||
$(jetty.home)/lib/jetty-websocket-$(version).jar ! available org.eclipse.jetty.websocket.WebSocket
|
||||
|
||||
# Add ext if it exists
|
||||
[All,default,=$(jetty.home)/lib/ext]
|
||||
|
||||
|
|
|
@ -46,8 +46,8 @@ public class StringMap extends AbstractMap implements Externalizable
|
|||
protected boolean _ignoreCase=false;
|
||||
protected NullEntry _nullEntry=null;
|
||||
protected Object _nullValue=null;
|
||||
protected HashSet _entrySet=new HashSet(3);
|
||||
protected Set _umEntrySet=Collections.unmodifiableSet(_entrySet);
|
||||
protected HashSet _entrySet=new HashSet(3);
|
||||
protected Set _umEntrySet=Collections.unmodifiableSet(_entrySet);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
|
@ -135,6 +135,9 @@ public class StringMap extends AbstractMap implements Externalizable
|
|||
return oldValue;
|
||||
}
|
||||
|
||||
if (_ignoreCase)
|
||||
key=key.toUpperCase();
|
||||
|
||||
Node node = _root;
|
||||
int ni=-1;
|
||||
Node prev = null;
|
||||
|
|
|
@ -16,7 +16,7 @@ public interface WebSocket
|
|||
void sendMessage(byte frame,String data) throws IOException;
|
||||
void sendMessage(byte frame,byte[] data) throws IOException;
|
||||
void sendMessage(byte frame,byte[] data, int offset, int length) throws IOException;
|
||||
void disconnect() throws IOException;
|
||||
void disconnect();
|
||||
boolean isOpen();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import org.eclipse.jetty.io.Buffer;
|
|||
import org.eclipse.jetty.io.ByteArrayBuffer;
|
||||
import org.eclipse.jetty.io.ThreadLocalBuffers;
|
||||
import org.eclipse.jetty.io.nio.DirectNIOBuffer;
|
||||
import org.eclipse.jetty.io.nio.IndirectNIOBuffer;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
@ -31,7 +32,7 @@ public class WebSocketBuffers
|
|||
@Override
|
||||
protected Buffer newBuffer(int size)
|
||||
{
|
||||
return new ByteArrayBuffer(bufferSize);
|
||||
return new IndirectNIOBuffer(bufferSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,10 +5,12 @@ import java.io.IOException;
|
|||
import org.eclipse.jetty.io.Buffer;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
||||
public class WebSocketConnection implements Connection, WebSocket.Outbound
|
||||
{
|
||||
final Connector _connector;
|
||||
final EndPoint _endp;
|
||||
final WebSocketParser _parser;
|
||||
final WebSocketGenerator _generator;
|
||||
|
@ -16,8 +18,9 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound
|
|||
final WebSocket _websocket;
|
||||
final int _maxIdleTimeMs=30000;
|
||||
|
||||
public WebSocketConnection(WebSocketBuffers buffers, EndPoint endpoint, long timestamp, WebSocket websocket)
|
||||
public WebSocketConnection(Connector connector, WebSocketBuffers buffers, EndPoint endpoint, long timestamp, WebSocket websocket)
|
||||
{
|
||||
_connector=connector;
|
||||
_endp = endpoint;
|
||||
_timestamp = timestamp;
|
||||
_websocket = websocket;
|
||||
|
@ -72,21 +75,28 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound
|
|||
int filled=_parser.parseNext();
|
||||
|
||||
more = flushed>0 || filled>0 || !_parser.isBufferEmpty() || !_generator.isBufferEmpty();
|
||||
if (filled<0 || flushed<0)
|
||||
_endp.close();
|
||||
|
||||
// System.err.println("flushed="+flushed+" filled="+filled+" more="+more+" endp="+_endp.isOpen());
|
||||
// System.err.println("flushed="+flushed+" filled="+filled+" more="+more+" p.e="+_parser.isBufferEmpty()+" g.e="+_generator.isBufferEmpty());
|
||||
|
||||
if (filled<0 || flushed<0)
|
||||
{
|
||||
_endp.close();
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
System.err.println(e);
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// TODO - not really the best way
|
||||
if (!_endp.isOpen())
|
||||
if (_endp.isOpen())
|
||||
_connector.persist(_endp);
|
||||
else
|
||||
// TODO - not really the best way
|
||||
_websocket.onDisconnect();
|
||||
}
|
||||
}
|
||||
|
@ -115,24 +125,34 @@ public class WebSocketConnection implements Connection, WebSocket.Outbound
|
|||
{
|
||||
_generator.addFrame(frame,content,_maxIdleTimeMs);
|
||||
_generator.flush();
|
||||
_connector.persist(_endp);
|
||||
}
|
||||
|
||||
public void sendMessage(byte frame, byte[] content) throws IOException
|
||||
{
|
||||
_generator.addFrame(frame,content,_maxIdleTimeMs);
|
||||
_generator.flush();
|
||||
_connector.persist(_endp);
|
||||
}
|
||||
|
||||
public void sendMessage(byte frame, byte[] content, int offset, int length) throws IOException
|
||||
{
|
||||
_generator.addFrame(frame,content,offset,length,_maxIdleTimeMs);
|
||||
_generator.flush();
|
||||
_connector.persist(_endp);
|
||||
}
|
||||
|
||||
public void disconnect() throws IOException
|
||||
public void disconnect()
|
||||
{
|
||||
_generator.flush(_maxIdleTimeMs);
|
||||
_endp.close();
|
||||
try
|
||||
{
|
||||
_generator.flush(_maxIdleTimeMs);
|
||||
_endp.close();
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
Log.ignore(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void fill(Buffer buffer)
|
||||
|
|
|
@ -73,12 +73,17 @@ public abstract class WebSocketHandler extends HandlerWrapper
|
|||
{
|
||||
HttpConnection http = HttpConnection.getCurrentConnection();
|
||||
ConnectedEndPoint endp = (ConnectedEndPoint)http.getEndPoint();
|
||||
WebSocketConnection connection = new WebSocketConnection(_buffers,endp,http.getTimeStamp(),websocket);
|
||||
WebSocketConnection connection = new WebSocketConnection(http.getConnector(),_buffers,endp,http.getTimeStamp(),websocket);
|
||||
|
||||
String uri=request.getRequestURI();
|
||||
String host=request.getHeader("Host");
|
||||
String origin=request.getHeader("Origin");
|
||||
origin=checkOrigin(request,host,origin);
|
||||
|
||||
response.setHeader("Upgrade","WebSocket");
|
||||
response.addHeader("Connection","Upgrade");
|
||||
response.addHeader("WebSocket-Origin",request.getScheme()+"://"+request.getServerName());
|
||||
response.addHeader("WebSocket-Location","ws://"+request.getHeader("Host")+request.getRequestURI());
|
||||
response.addHeader("WebSocket-Origin",origin);
|
||||
response.addHeader("WebSocket-Location","ws://"+host+uri);
|
||||
if (protocol!=null)
|
||||
response.addHeader("WebSocket-Protocol",protocol);
|
||||
response.sendError(101,"Web Socket Protocol Handshake");
|
||||
|
@ -101,6 +106,13 @@ public abstract class WebSocketHandler extends HandlerWrapper
|
|||
}
|
||||
}
|
||||
|
||||
protected String checkOrigin(HttpServletRequest request, String host, String origin)
|
||||
{
|
||||
if (origin==null)
|
||||
origin=host;
|
||||
return origin;
|
||||
}
|
||||
|
||||
abstract protected WebSocket doWebSocketConnect(HttpServletRequest request,String protocol);
|
||||
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ public class WebSocketParser
|
|||
int total_filled=0;
|
||||
|
||||
// Loop until an datagram call back or can't fill anymore
|
||||
boolean progress=true;
|
||||
while(true)
|
||||
{
|
||||
int length=_buffer.length();
|
||||
|
@ -92,7 +93,7 @@ public class WebSocketParser
|
|||
{
|
||||
int filled=_endp.isOpen()?_endp.fill(_buffer):-1;
|
||||
if (filled<=0)
|
||||
return total_filled>0?total_filled:-1;
|
||||
return total_filled;
|
||||
total_filled+=filled;
|
||||
length=_buffer.length();
|
||||
}
|
||||
|
|
|
@ -15,19 +15,19 @@ import org.eclipse.jetty.server.HttpConnection;
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Servlet to ugrade connections to WebSocket
|
||||
* Servlet to upgrade connections to WebSocket
|
||||
* <p>
|
||||
* The request must have the correct upgrade headers, else it is
|
||||
* handled as a normal servlet request.
|
||||
* <p>
|
||||
* The initParameter "bufferSize" can be used to set the buffer size,
|
||||
* which is also the max frame byte size (default 8192).
|
||||
*
|
||||
*/
|
||||
public abstract class WebSocketServlet extends HttpServlet
|
||||
{
|
||||
WebSocketBuffers _buffers;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see javax.servlet.GenericServlet#init()
|
||||
|
@ -56,12 +56,17 @@ public abstract class WebSocketServlet extends HttpServlet
|
|||
{
|
||||
HttpConnection http = HttpConnection.getCurrentConnection();
|
||||
ConnectedEndPoint endp = (ConnectedEndPoint)http.getEndPoint();
|
||||
WebSocketConnection connection = new WebSocketConnection(_buffers,endp,http.getTimeStamp(),websocket);
|
||||
WebSocketConnection connection = new WebSocketConnection(http.getConnector(),_buffers,endp,http.getTimeStamp(),websocket);
|
||||
|
||||
String uri=request.getRequestURI();
|
||||
String host=request.getHeader("Host");
|
||||
String origin=request.getHeader("Origin");
|
||||
origin=checkOrigin(request,host,origin);
|
||||
|
||||
response.setHeader("Upgrade","WebSocket");
|
||||
response.addHeader("Connection","Upgrade");
|
||||
response.addHeader("WebSocket-Origin",request.getScheme()+"://"+request.getServerName());
|
||||
response.addHeader("WebSocket-Location","ws://"+request.getHeader("Host")+request.getRequestURI());
|
||||
response.addHeader("WebSocket-Origin",origin);
|
||||
response.addHeader("WebSocket-Location","ws://"+host+uri);
|
||||
if (protocol!=null)
|
||||
response.addHeader("WebSocket-Protocol",protocol);
|
||||
response.sendError(101,"Web Socket Protocol Handshake");
|
||||
|
@ -81,6 +86,13 @@ public abstract class WebSocketServlet extends HttpServlet
|
|||
else
|
||||
super.service(request,response);
|
||||
}
|
||||
|
||||
protected String checkOrigin(HttpServletRequest request, String host, String origin)
|
||||
{
|
||||
if (origin==null)
|
||||
origin=host;
|
||||
return origin;
|
||||
}
|
||||
|
||||
abstract protected WebSocket doWebSocketConnect(HttpServletRequest request,String protocol);
|
||||
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
package org.eclipse.jetty.websocket;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.eclipse.jetty.server.LocalConnector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.ResourceHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.websocket.WebSocketTest.TestWebSocket;
|
||||
|
||||
public class SimpleWebSocketServer extends Server
|
||||
{
|
||||
TestWebSocket _websocket;
|
||||
SelectChannelConnector _connector;
|
||||
WebSocketHandler _handler;
|
||||
|
||||
public SimpleWebSocketServer()
|
||||
{
|
||||
_connector = new SelectChannelConnector();
|
||||
_connector.setPort(8080);
|
||||
|
||||
addConnector(_connector);
|
||||
_handler= new WebSocketHandler()
|
||||
{
|
||||
@Override
|
||||
protected WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
{
|
||||
_websocket = new TestWebSocket();
|
||||
return _websocket;
|
||||
}
|
||||
};
|
||||
ResourceHandler rh=new ResourceHandler();
|
||||
_handler.setHandler(rh);
|
||||
rh.setDirectoriesListed(true);
|
||||
rh.setResourceBase("./src/test/resources");
|
||||
|
||||
setHandler(_handler);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class TestWebSocket implements WebSocket
|
||||
{
|
||||
Outbound _outbound;
|
||||
|
||||
public void onConnect(Outbound outbound)
|
||||
{
|
||||
System.err.println("onConnect");
|
||||
_outbound=outbound;
|
||||
|
||||
new Thread()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
for (int i=0;_outbound.isOpen()&& i<10;i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(1000);
|
||||
System.err.println("send "+i);
|
||||
_outbound.sendMessage(SENTINEL_FRAME,"Roger That "+i);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
public void onMessage(byte frame, byte[] data,int offset, int length)
|
||||
{
|
||||
System.err.println("onMessage: "+TypeUtil.toHexString(data,offset,length));
|
||||
}
|
||||
|
||||
public void onMessage(byte frame, String data)
|
||||
{
|
||||
System.err.println("onMessage: "+data);
|
||||
}
|
||||
|
||||
public void onDisconnect()
|
||||
{
|
||||
System.err.println("onDisconnect");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
SimpleWebSocketServer server = new SimpleWebSocketServer();
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
Log.warn(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
<h1>WebSocket Test</h1>
|
||||
|
||||
<script lang="javascript">
|
||||
alert("testing");
|
||||
|
||||
var ws = new WebSocket("ws://localhost:8080/");
|
||||
|
||||
ws.onopen = function(evt)
|
||||
{
|
||||
alert("Conn opened");
|
||||
ws.send("Hello World");
|
||||
}
|
||||
|
||||
ws.onmessage = function(evt) { alert("onmessage: " + evt.data); }
|
||||
ws.onclose = function(evt) { alert("Conn closed"); }
|
||||
|
||||
</script>
|
|
@ -117,6 +117,12 @@
|
|||
<artifactId>servlet-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.eclipse.jetty.continuation.Continuation;
|
|||
import org.eclipse.jetty.continuation.ContinuationSupport;
|
||||
|
||||
|
||||
|
||||
// Simple asynchronous Chat room.
|
||||
// This does not handle duplicate usernames or multiple frames/tabs from the same browser
|
||||
// Some code is duplicated for clarity.
|
||||
|
@ -90,7 +89,7 @@ public class ChatServlet extends HttpServlet
|
|||
return;
|
||||
}
|
||||
Member member = room.get(username);
|
||||
if (room==null)
|
||||
if (member==null)
|
||||
{
|
||||
response.sendError(503);
|
||||
return;
|
||||
|
@ -147,19 +146,22 @@ public class ChatServlet extends HttpServlet
|
|||
throws IOException
|
||||
{
|
||||
Map<String,Member> room=_rooms.get(request.getPathInfo());
|
||||
// Post chat to all members
|
||||
for (Member m:room.values())
|
||||
if (room!=null)
|
||||
{
|
||||
synchronized (m)
|
||||
// Post chat to all members
|
||||
for (Member m:room.values())
|
||||
{
|
||||
m._queue.add(username); // from
|
||||
m._queue.add(message); // chat
|
||||
|
||||
// wakeup member if polling
|
||||
if (m._continuation!=null)
|
||||
synchronized (m)
|
||||
{
|
||||
m._continuation.resume();
|
||||
m._continuation=null;
|
||||
m._queue.add(username); // from
|
||||
m._queue.add(message); // chat
|
||||
|
||||
// wakeup member if polling
|
||||
if (m._continuation!=null)
|
||||
{
|
||||
m._continuation.resume();
|
||||
m._continuation=null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,111 +170,16 @@ public class ChatServlet extends HttpServlet
|
|||
PrintWriter out=response.getWriter();
|
||||
out.print("{action:\"chat\"}");
|
||||
}
|
||||
|
||||
|
||||
// Serve the HTML with embedded CSS and Javascript.
|
||||
// This should be static content and should use real JS libraries.
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
if (!request.getRequestURI().endsWith("/"))
|
||||
{
|
||||
response.sendRedirect(request.getRequestURI()+"/");
|
||||
return;
|
||||
}
|
||||
if (request.getParameter("action")!=null)
|
||||
{
|
||||
doPost(request,response);
|
||||
return;
|
||||
}
|
||||
|
||||
response.setContentType("text/html");
|
||||
PrintWriter out=response.getWriter();
|
||||
out.println("<html><head>");
|
||||
out.println(" <title>async chat</title>");
|
||||
out.println(" <script type='text/javascript'>");
|
||||
out.println(" function $() { return document.getElementById(arguments[0]); }");
|
||||
out.println(" function $F() { return document.getElementById(arguments[0]).value; }");
|
||||
out.println(" function getKeyCode(ev) { if (window.event) return window.event.keyCode; return ev.keyCode; } ");
|
||||
out.println(" function xhr(method,uri,body,handler) {");
|
||||
out.println(" var req=(window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');");
|
||||
out.println(" req.onreadystatechange=function() { if (req.readyState==4 && handler) { eval('var o='+req.responseText);handler(o);} }");
|
||||
out.println(" req.open(method,uri,true);");
|
||||
out.println(" req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');");
|
||||
out.println(" req.send(body);");
|
||||
out.println(" };");
|
||||
out.println(" function send(action,user,message,handler){");
|
||||
out.println(" if (message) message=message.replace('%','%25').replace('&','%26').replace('=','%3D');");
|
||||
out.println(" if (user) user=user.replace('%','%25').replace('&','%26').replace('=','%3D');");
|
||||
out.println(" xhr('POST','chat','action='+action+'&user='+user+'&message='+message,handler);");
|
||||
out.println(" };");
|
||||
out.println(" ");
|
||||
out.println(" var room = {");
|
||||
out.println(" join: function(name) {");
|
||||
out.println(" this._username=name;");
|
||||
out.println(" $('join').className='hidden';");
|
||||
out.println(" $('joined').className='';");
|
||||
out.println(" $('phrase').focus();");
|
||||
out.println(" send('join', room._username,null);");
|
||||
out.println(" send('chat', room._username,'has joined!');");
|
||||
out.println(" send('poll', room._username,null, room._poll);");
|
||||
out.println(" },");
|
||||
out.println(" chat: function(text) {");
|
||||
out.println(" if (text != null && text.length>0 )");
|
||||
out.println(" send('chat',room._username,text);");
|
||||
out.println(" },");
|
||||
out.println(" _poll: function(m) {");
|
||||
out.println(" //console.debug(m);");
|
||||
out.println(" if (m.chat){");
|
||||
out.println(" var chat=document.getElementById('chat');");
|
||||
out.println(" var spanFrom = document.createElement('span');");
|
||||
out.println(" spanFrom.className='from';");
|
||||
out.println(" spanFrom.innerHTML=m.from+': ';");
|
||||
out.println(" var spanText = document.createElement('span');");
|
||||
out.println(" spanText.className='text';");
|
||||
out.println(" spanText.innerHTML=m.chat;");
|
||||
out.println(" var lineBreak = document.createElement('br');");
|
||||
out.println(" chat.appendChild(spanFrom);");
|
||||
out.println(" chat.appendChild(spanText);");
|
||||
out.println(" chat.appendChild(lineBreak);");
|
||||
out.println(" chat.scrollTop = chat.scrollHeight - chat.clientHeight; ");
|
||||
out.println(" }");
|
||||
out.println(" if (m.action=='poll')");
|
||||
out.println(" send('poll', room._username,null, room._poll);");
|
||||
out.println(" },");
|
||||
out.println(" _end:''");
|
||||
out.println(" };");
|
||||
out.println(" </script>");
|
||||
out.println(" <style type='text/css'>");
|
||||
out.println(" div { border: 0px solid black; }");
|
||||
out.println(" div#chat { clear: both; width: 40em; height: 20ex; overflow: auto; background-color: #f0f0f0; padding: 4px; border: 1px solid black; }");
|
||||
out.println(" div#input { clear: both; width: 40em; padding: 4px; background-color: #e0e0e0; border: 1px solid black; border-top: 0px }");
|
||||
out.println(" input#phrase { width:30em; background-color: #e0f0f0; }");
|
||||
out.println(" input#username { width:14em; background-color: #e0f0f0; }");
|
||||
out.println(" div.hidden { display: none; }");
|
||||
out.println(" span.from { font-weight: bold; }");
|
||||
out.println(" span.alert { font-style: italic; }");
|
||||
out.println(" </style>");
|
||||
out.println("</head><body>");
|
||||
out.println("<div id='chat'></div>");
|
||||
out.println("<div id='input'>");
|
||||
out.println(" <div id='join' >");
|
||||
out.println(" Username: <input id='username' type='text'/><input id='joinB' class='button' type='submit' name='join' value='Join'/>");
|
||||
out.println(" </div>");
|
||||
out.println(" <div id='joined' class='hidden'>");
|
||||
out.println(" Chat: <input id='phrase' type='text'></input>");
|
||||
out.println(" <input id='sendB' class='button' type='submit' name='join' value='Send'/>");
|
||||
out.println(" </div>");
|
||||
out.println("</div>");
|
||||
out.println("<script type='text/javascript'>");
|
||||
out.println("$('username').setAttribute('autocomplete','OFF');");
|
||||
out.println("$('username').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.join($F('username')); return false; } return true; } ; ");
|
||||
out.println("$('joinB').onclick = function(event) { room.join($F('username')); return false; };");
|
||||
out.println("$('phrase').setAttribute('autocomplete','OFF');");
|
||||
out.println("$('phrase').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.chat($F('phrase')); $('phrase').value=''; return false; } return true; };");
|
||||
out.println("$('sendB').onclick = function(event) { room.chat($F('phrase')); $('phrase').value=''; return false; };");
|
||||
out.println("</script>");
|
||||
out.println("</body></html>");
|
||||
else
|
||||
getServletContext().getNamedDispatcher("default").forward(request,response);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package com.acme;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import javax.servlet.RequestDispatcher;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.WebSocketServlet;
|
||||
|
||||
public class WebSocketChatServlet extends WebSocketServlet
|
||||
{
|
||||
private final Set<ChatWebSocket> _members = new CopyOnWriteArraySet<ChatWebSocket>();
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws javax.servlet.ServletException ,IOException
|
||||
{
|
||||
getServletContext().getNamedDispatcher("default").forward(request,response);
|
||||
};
|
||||
|
||||
@Override
|
||||
protected WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
{
|
||||
return new ChatWebSocket();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class ChatWebSocket implements WebSocket
|
||||
{
|
||||
Outbound _outbound;
|
||||
|
||||
public void onConnect(Outbound outbound)
|
||||
{
|
||||
// Log.info(this+" onConnect");
|
||||
_outbound=outbound;
|
||||
_members.add(this);
|
||||
}
|
||||
|
||||
public void onMessage(byte frame, byte[] data,int offset, int length)
|
||||
{
|
||||
// Log.info(this+" onMessage: "+TypeUtil.toHexString(data,offset,length));
|
||||
}
|
||||
|
||||
public void onMessage(byte frame, String data)
|
||||
{
|
||||
// Log.info(this+" onMessage: "+data);
|
||||
for (ChatWebSocket member : _members)
|
||||
{
|
||||
try
|
||||
{
|
||||
member._outbound.sendMessage(frame,data);
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
Log.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onDisconnect()
|
||||
{
|
||||
// Log.info(this+" onDisconnect");
|
||||
_members.remove(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -176,6 +176,17 @@
|
|||
<url-pattern>/chat/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>WSChat</servlet-name>
|
||||
<servlet-class>com.acme.WebSocketChatServlet</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>WSChat</servlet-name>
|
||||
<url-pattern>/ws/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
|
||||
<servlet>
|
||||
<servlet-name>Rewrite</servlet-name>
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
<html><head>
|
||||
<title>Async Chat</title>
|
||||
<script type='text/javascript'>
|
||||
function $() { return document.getElementById(arguments[0]); }
|
||||
function $F() { return document.getElementById(arguments[0]).value; }
|
||||
function getKeyCode(ev) { if (window.event) return window.event.keyCode; return ev.keyCode; }
|
||||
function xhr(method,uri,body,handler) {
|
||||
var req=(window.XMLHttpRequest)?new XMLHttpRequest():new ActiveXObject('Microsoft.XMLHTTP');
|
||||
req.onreadystatechange=function() { if (req.readyState==4 && handler) { eval('var o='+req.responseText);handler(o);} }
|
||||
req.open(method,uri,true);
|
||||
req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
|
||||
req.send(body);
|
||||
};
|
||||
function send(action,user,message,handler){
|
||||
if (message) message=message.replace('%','%25').replace('&','%26').replace('=','%3D');
|
||||
if (user) user=user.replace('%','%25').replace('&','%26').replace('=','%3D');
|
||||
xhr('POST','chat','action='+action+'&user='+user+'&message='+message,handler);
|
||||
};
|
||||
|
||||
var room = {
|
||||
join: function(name) {
|
||||
this._username=name;
|
||||
$('join').className='hidden';
|
||||
$('joined').className='';
|
||||
$('phrase').focus();
|
||||
send('join', room._username,null);
|
||||
send('chat', room._username,'has joined!');
|
||||
send('poll', room._username,null, room._poll);
|
||||
},
|
||||
chat: function(text) {
|
||||
if (text != null && text.length>0 )
|
||||
send('chat',room._username,text);
|
||||
},
|
||||
_poll: function(m) {
|
||||
//console.debug(m);
|
||||
if (m.chat){
|
||||
var chat=document.getElementById('chat');
|
||||
var spanFrom = document.createElement('span');
|
||||
spanFrom.className='from';
|
||||
spanFrom.innerHTML=m.from+': ';
|
||||
var spanText = document.createElement('span');
|
||||
spanText.className='text';
|
||||
spanText.innerHTML=m.chat;
|
||||
var lineBreak = document.createElement('br');
|
||||
chat.appendChild(spanFrom);
|
||||
chat.appendChild(spanText);
|
||||
chat.appendChild(lineBreak);
|
||||
chat.scrollTop = chat.scrollHeight - chat.clientHeight;
|
||||
}
|
||||
if (m.action=='poll')
|
||||
send('poll', room._username,null, room._poll);
|
||||
},
|
||||
_end:''
|
||||
};
|
||||
</script>
|
||||
<style type='text/css'>
|
||||
div { border: 0px solid black; }
|
||||
div#chat { clear: both; width: 40em; height: 20ex; overflow: auto; background-color: #f0f0f0; padding: 4px; border: 1px solid black; }
|
||||
div#input { clear: both; width: 40em; padding: 4px; background-color: #e0e0e0; border: 1px solid black; border-top: 0px }
|
||||
input#phrase { width:30em; background-color: #e0f0f0; }
|
||||
input#username { width:14em; background-color: #e0f0f0; }
|
||||
div.hidden { display: none; }
|
||||
span.from { font-weight: bold; }
|
||||
span.alert { font-style: italic; }
|
||||
</style>
|
||||
</head><body>
|
||||
<div id='chat'></div>
|
||||
<div id='input'>
|
||||
<div id='join' >
|
||||
Username: <input id='username' type='text'/><input id='joinB' class='button' type='submit' name='join' value='Join'/>
|
||||
</div>
|
||||
<div id='joined' class='hidden'>
|
||||
Chat: <input id='phrase' type='text'/>
|
||||
<input id='sendB' class='button' type='submit' name='join' value='Send'/>
|
||||
</div>
|
||||
</div>
|
||||
<script type='text/javascript'>
|
||||
$('username').setAttribute('autocomplete','OFF');
|
||||
$('username').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.join($F('username')); return false; } return true; } ;
|
||||
$('joinB').onclick = function(event) { room.join($F('username')); return false; };
|
||||
$('phrase').setAttribute('autocomplete','OFF');
|
||||
$('phrase').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.chat($F('phrase')); $('phrase').value=''; return false; } return true; };
|
||||
$('sendB').onclick = function(event) { room.chat($F('phrase')); $('phrase').value=''; return false; };
|
||||
</script>
|
||||
</body></html>
|
|
@ -18,21 +18,19 @@ Commercial support for Jetty is available via <a href="http://www.webtide.com">w
|
|||
This is a test context that serves:
|
||||
</p>
|
||||
<ul>
|
||||
<li>static content (
|
||||
<li>static content:
|
||||
<a href="d.txt">tiny</a>,
|
||||
<a href="da.txt">small</a>,
|
||||
<a href="dat.txt">medium</a>,
|
||||
<a href="data.txt">large</a>,
|
||||
<a href="data.txt.gz">large gziped</a>)</li>
|
||||
<li>a <a href="hello/">Hello World Servlet</a></li>
|
||||
<li>a <a href="dump/info">Request Dump Servlet</a></li>
|
||||
<li>a <a href="session/">Session Dump Servlet</a></li>
|
||||
<li>a <a href="cookie/">Cookie Dump Servlet</a></li>
|
||||
<li>a <a href="dispatch">Dispatcher Servlet</a></li>
|
||||
<li>a <a href="rewrite/">Request Rewrite Servlet</a></li>
|
||||
<li>a <a href="google/">Transparent Proxy</a> (to www.google.com)</li>
|
||||
<li>a <a href="chat/">Comet Chat</a></li>
|
||||
<li>a <a href="auth.html">Authentication</a></li>
|
||||
<a href="data.txt.gz">large gziped</a></li>
|
||||
<li><a href="hello/">Hello World Servlet</a></li>
|
||||
<li>Dump: <a href="dump/info">Request</a>, <a href="session/">Session</a>, <a href="cookie/">Cookie</a></li>
|
||||
<li><a href="dispatch">Dispatcher Servlet</a></li>
|
||||
<li><a href="rewrite/">Request Rewrite Servlet</a></li>
|
||||
<li><a href="google/">Transparent Proxy</a> (to www.google.com)</li>
|
||||
<li>Comet Chat: <a href="chat/">Long Polling</a>, <a href="ws">WebSocket</a></li>
|
||||
<li><a href="auth.html">Authentication</a></li>
|
||||
</ul>
|
||||
<p/>
|
||||
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
|
||||
<html><head>
|
||||
<title>WebSocket Chat</title>
|
||||
<script type='text/javascript'>
|
||||
|
||||
if (!window.WebSocket)
|
||||
alert("WebSocket not supported by this browser");
|
||||
|
||||
function $() { return document.getElementById(arguments[0]); }
|
||||
function $F() { return document.getElementById(arguments[0]).value; }
|
||||
|
||||
function getKeyCode(ev) { if (window.event) return window.event.keyCode; return ev.keyCode; }
|
||||
|
||||
var room = {
|
||||
join: function(name) {
|
||||
this._username=name;
|
||||
var location = document.location.toString().replace('http:','ws:');
|
||||
this._ws=new WebSocket(location);
|
||||
this._ws.onopen=this._onopen;
|
||||
this._ws.onmessage=this._onmessage;
|
||||
this._ws.onclose=this._onclose;
|
||||
},
|
||||
|
||||
_onopen: function(){
|
||||
$('join').className='hidden';
|
||||
$('joined').className='';
|
||||
$('phrase').focus();
|
||||
room._send(room._username,'has joined!');
|
||||
},
|
||||
|
||||
_send: function(user,message){
|
||||
user=user.replace(':','_');
|
||||
if (this._ws)
|
||||
this._ws.send(user+':'+message);
|
||||
},
|
||||
|
||||
chat: function(text) {
|
||||
if (text != null && text.length>0 )
|
||||
room._send(room._username,text);
|
||||
},
|
||||
|
||||
_onmessage: function(m) {
|
||||
if (m.data){
|
||||
var c=m.data.indexOf(':');
|
||||
var from=m.data.substring(0,c);
|
||||
var text=m.data.substring(c+1);
|
||||
|
||||
var chat=$('chat');
|
||||
var spanFrom = document.createElement('span');
|
||||
spanFrom.className='from';
|
||||
spanFrom.innerHTML=from+': ';
|
||||
var spanText = document.createElement('span');
|
||||
spanText.className='text';
|
||||
spanText.innerHTML=text;
|
||||
var lineBreak = document.createElement('br');
|
||||
chat.appendChild(spanFrom);
|
||||
chat.appendChild(spanText);
|
||||
chat.appendChild(lineBreak);
|
||||
chat.scrollTop = chat.scrollHeight - chat.clientHeight;
|
||||
}
|
||||
},
|
||||
|
||||
_onclose: function(m) {
|
||||
this._ws=null;
|
||||
$('join').className='';
|
||||
$('joined').className='hidden';
|
||||
$('username').focus();
|
||||
$('chat').innerHTML='';
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
</script>
|
||||
<style type='text/css'>
|
||||
div { border: 0px solid black; }
|
||||
div#chat { clear: both; width: 40em; height: 20ex; overflow: auto; background-color: #f0f0f0; padding: 4px; border: 1px solid black; }
|
||||
div#input { clear: both; width: 40em; padding: 4px; background-color: #e0e0e0; border: 1px solid black; border-top: 0px }
|
||||
input#phrase { width:30em; background-color: #e0f0f0; }
|
||||
input#username { width:14em; background-color: #e0f0f0; }
|
||||
div.hidden { display: none; }
|
||||
span.from { font-weight: bold; }
|
||||
span.alert { font-style: italic; }
|
||||
</style>
|
||||
</head><body>
|
||||
<div id='chat'></div>
|
||||
<div id='input'>
|
||||
<div id='join' >
|
||||
Username: <input id='username' type='text'/><input id='joinB' class='button' type='submit' name='join' value='Join'/>
|
||||
</div>
|
||||
<div id='joined' class='hidden'>
|
||||
Chat: <input id='phrase' type='text'/>
|
||||
<input id='sendB' class='button' type='submit' name='join' value='Send'/>
|
||||
</div>
|
||||
</div>
|
||||
<script type='text/javascript'>
|
||||
$('username').setAttribute('autocomplete','OFF');
|
||||
$('username').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.join($F('username')); return false; } return true; } ;
|
||||
$('joinB').onclick = function(event) { room.join($F('username')); return false; };
|
||||
$('phrase').setAttribute('autocomplete','OFF');
|
||||
$('phrase').onkeyup = function(ev) { var keyc=getKeyCode(ev); if (keyc==13 || keyc==10) { room.chat($F('phrase')); $('phrase').value=''; return false; } return true; };
|
||||
$('sendB').onclick = function(event) { room.chat($F('phrase')); $('phrase').value=''; return false; };
|
||||
</script>
|
||||
|
||||
<p>
|
||||
This is a demonstration of the Jetty websocket server.
|
||||
</p>
|
||||
</body></html>
|
||||
|
||||
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
package org.eclipse.jetty;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
import javax.management.MBeanServer;
|
||||
|
||||
import org.eclipse.jetty.http.security.Password;
|
||||
import org.eclipse.jetty.jmx.MBeanContainer;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
public class DemoServer
|
||||
{
|
||||
public static void main(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
if (args.length!=1)
|
||||
{
|
||||
System.err.println("Usage - java "+DemoServer.class+" webappdir|war");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
Server server = new Server();
|
||||
|
||||
// setup JMX
|
||||
MBeanServer mbeanS = ManagementFactory.getPlatformMBeanServer();
|
||||
MBeanContainer mbeanC = new MBeanContainer(mbeanS);
|
||||
server.getContainer().addEventListener(mbeanC);
|
||||
server.addBean(mbeanC);
|
||||
|
||||
// setup connector
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
connector.setPort(8080);
|
||||
server.addConnector(connector);
|
||||
|
||||
// setup Login service
|
||||
HashLoginService login = new HashLoginService();
|
||||
login.putUser("jetty",new Password("password"),new String[]{"user"});
|
||||
login.putUser("admin",new Password("password"),new String[]{"user","admin"});
|
||||
server.addBean(login);
|
||||
|
||||
// ContextHandlerCollection
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
server.setHandler(contexts);
|
||||
|
||||
// setup webapp
|
||||
WebAppContext context = new WebAppContext();
|
||||
context.setWar(args[0]);
|
||||
context.setDefaultsDescriptor("../jetty-webapp/src/main/config/etc/webdefault.xml");
|
||||
contexts.addHandler(context);
|
||||
|
||||
|
||||
// start the server
|
||||
server.start();
|
||||
System.err.println(server.dump());
|
||||
server.join();
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
// ========================================================================
|
||||
package com.acme;
|
||||
package org.eclipse.jetty;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
|
@ -19,6 +19,8 @@ import org.eclipse.jetty.servlet.DefaultServlet;
|
|||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.testing.ServletTester;
|
||||
|
||||
import com.acme.DispatchServlet;
|
||||
|
||||
/**
|
||||
* Simple tests against DispatchServlet.
|
||||
*/
|
|
@ -1,32 +0,0 @@
|
|||
package org.eclipse.jetty;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.DebugHandler;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.servlets.IncludableGzipFilter;
|
||||
|
||||
import com.acme.Dump;
|
||||
|
||||
|
||||
public class DumpServer
|
||||
{
|
||||
public static void main(String[] args)
|
||||
throws Exception
|
||||
{
|
||||
Server server = new Server(8080);
|
||||
DebugHandler debug = new DebugHandler();
|
||||
debug.setOutputStream(System.err);
|
||||
server.setHandler(debug);
|
||||
|
||||
ServletContextHandler context = new ServletContextHandler(debug,"/",ServletContextHandler.SESSIONS);
|
||||
FilterHolder gzip=context.addFilter(IncludableGzipFilter.class,"/*",0);
|
||||
gzip.setInitParameter("uncheckedPrintWriter","true");
|
||||
context.addServlet(new ServletHolder(new Dump()), "/*");
|
||||
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,106 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
|
||||
package org.eclipse.jetty;
|
||||
|
||||
import java.lang.management.ManagementFactory;
|
||||
|
||||
import org.eclipse.jetty.jmx.MBeanContainer;
|
||||
import org.eclipse.jetty.security.HashLoginService;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.NCSARequestLog;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerCollection;
|
||||
import org.eclipse.jetty.server.handler.RequestLogHandler;
|
||||
import org.eclipse.jetty.server.nio.SelectChannelConnector;
|
||||
import org.eclipse.jetty.server.ssl.SslSelectChannelConnector;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
||||
public class TestServer
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
String jetty_home = System.getProperty("jetty.home","../jetty-distribution/target/distribution");
|
||||
System.setProperty("jetty.home",jetty_home);
|
||||
|
||||
Server server = new Server();
|
||||
|
||||
// Setup JMX
|
||||
MBeanContainer mbContainer=new MBeanContainer(ManagementFactory.getPlatformMBeanServer());
|
||||
server.getContainer().addEventListener(mbContainer);
|
||||
server.addBean(mbContainer);
|
||||
mbContainer.addBean(Log.getLog());
|
||||
|
||||
|
||||
// Setup Threadpool
|
||||
QueuedThreadPool threadPool = new QueuedThreadPool();
|
||||
threadPool.setMaxThreads(100);
|
||||
server.setThreadPool(threadPool);
|
||||
|
||||
// Setup Connectors
|
||||
SelectChannelConnector connector = new SelectChannelConnector();
|
||||
connector.setPort(8080);
|
||||
connector.setMaxIdleTime(30000);
|
||||
connector.setConfidentialPort(8443);
|
||||
server.setConnectors(new Connector[]
|
||||
{ connector });
|
||||
|
||||
SslSelectChannelConnector ssl_connector = new SslSelectChannelConnector();
|
||||
ssl_connector.setPort(8443);
|
||||
ssl_connector.setKeystore(jetty_home + "/etc/keystore");
|
||||
ssl_connector.setPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
ssl_connector.setKeyPassword("OBF:1u2u1wml1z7s1z7a1wnl1u2g");
|
||||
ssl_connector.setTruststore(jetty_home + "/etc/keystore");
|
||||
ssl_connector.setTrustPassword("OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4");
|
||||
server.addConnector(ssl_connector);
|
||||
|
||||
HandlerCollection handlers = new HandlerCollection();
|
||||
ContextHandlerCollection contexts = new ContextHandlerCollection();
|
||||
RequestLogHandler requestLogHandler = new RequestLogHandler();
|
||||
handlers.setHandlers(new Handler[]
|
||||
{ contexts, new DefaultHandler(), requestLogHandler });
|
||||
server.setHandler(handlers);
|
||||
|
||||
|
||||
// Setup deployers
|
||||
|
||||
HashLoginService login = new HashLoginService();
|
||||
login.setName("Test Realm");
|
||||
login.setConfig(jetty_home + "/etc/realm.properties");
|
||||
server.addBean(login);
|
||||
|
||||
NCSARequestLog requestLog = new NCSARequestLog(jetty_home + "/logs/jetty-yyyy_mm_dd.log");
|
||||
requestLog.setExtended(false);
|
||||
requestLogHandler.setRequestLog(requestLog);
|
||||
|
||||
server.setStopAtShutdown(true);
|
||||
server.setSendServerVersion(true);
|
||||
|
||||
|
||||
WebAppContext webapp = new WebAppContext();
|
||||
webapp.setParentLoaderPriority(true);
|
||||
webapp.setResourceBase("./src/main/webapp");
|
||||
|
||||
contexts.addHandler(webapp);
|
||||
|
||||
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue