342504 Scanner Listener

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@2999 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Greg Wilkins 2011-04-12 02:12:52 +00:00
parent e5bad59c14
commit d3c5eddd79
8 changed files with 247 additions and 59 deletions

View File

@ -1,3 +1,6 @@
jetty-7.4.0-SNAPSHOT
+ 342504 Scanner Listener
jetty-7.4.0.RC0
+ 324110 Added test harnesses for merging of QueryStrings.
+ 337685 Update websocket API in preparation for draft -07

View File

@ -175,12 +175,6 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
return _deploymentManager;
}
/* ------------------------------------------------------------ */
@Deprecated
public Resource getMonitoredDir()
{
return _monitoredDir;
}
/* ------------------------------------------------------------ */
public Resource getMonitoredDirResource()
@ -211,30 +205,18 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
{
_deploymentManager = deploymentManager;
}
/* ------------------------------------------------------------ */
/**
* @deprecated use {@link #setMonitoredDirResource(Resource)}
*/
public void setMonitoredDir(Resource dir)
{
setMonitoredDirResource(dir);
}
/* ------------------------------------------------------------ */
/**
* @deprecated use {@link #setMonitoredDirName(String)}
*/
public void setMonitoredDir(String dir)
{
setMonitoredDirName(dir);
}
/* ------------------------------------------------------------ */
public void setMonitoredDirResource(Resource contextsDir)
{
_monitoredDir = contextsDir;
}
/* ------------------------------------------------------------ */
public void addScannerListener(Scanner.Listener listener)
{
_scanner.addListener(listener);
}
/* ------------------------------------------------------------ */
/**

View File

@ -16,9 +16,14 @@
package org.eclipse.jetty.deploy.providers;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.deploy.AppProvider;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.deploy.test.XmlConfiguredJetty;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.util.log.Log;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@ -30,9 +35,11 @@ import org.junit.Test;
*/
public class ScanningAppProviderRuntimeUpdatesTest
{
@Rule
public TestingDir testdir = new TestingDir();
@Rule
public TestingDir testdir = new TestingDir();
private static XmlConfiguredJetty jetty;
private final AtomicInteger _scans = new AtomicInteger();
private int _providers;
@Before
public void setupEnvironment() throws Exception
@ -46,6 +53,24 @@ public class ScanningAppProviderRuntimeUpdatesTest
// Start it
jetty.start();
// monitor tick
DeploymentManager dm = jetty.getServer().getBeans(DeploymentManager.class).get(0);
for (AppProvider provider : dm.getAppProviders())
{
if (provider instanceof ScanningAppProvider)
{
_providers++;
((ScanningAppProvider)provider).addScannerListener(new Scanner.ScanListener()
{
public void scan()
{
_scans.incrementAndGet();
}
});
}
}
}
@After
@ -55,6 +80,23 @@ public class ScanningAppProviderRuntimeUpdatesTest
jetty.stop();
}
public void waitForDirectoryScan()
{
int scan=_scans.get()+2*_providers;
do
{
try
{
Thread.sleep(200);
}
catch(InterruptedException e)
{
Log.warn(e);
}
}
while(_scans.get()<scan);
}
/**
* Simple webapp deployment after startup of server.
*/
@ -64,7 +106,7 @@ public class ScanningAppProviderRuntimeUpdatesTest
jetty.copyWebapp("foo-webapp-1.war","foo.war");
jetty.copyContext("foo.xml","foo.xml");
jetty.waitForDirectoryScan();
waitForDirectoryScan();
jetty.assertWebAppContextsExists("/foo");
}
@ -78,13 +120,13 @@ public class ScanningAppProviderRuntimeUpdatesTest
jetty.copyWebapp("foo-webapp-1.war","foo.war");
jetty.copyContext("foo.xml","foo.xml");
jetty.waitForDirectoryScan();
waitForDirectoryScan();
jetty.assertWebAppContextsExists("/foo");
jetty.removeContext("foo.xml");
jetty.waitForDirectoryScan();
waitForDirectoryScan();
// FIXME: hot undeploy with removal not working! - jetty.assertNoWebAppContexts();
}
@ -98,7 +140,7 @@ public class ScanningAppProviderRuntimeUpdatesTest
jetty.copyWebapp("foo-webapp-1.war","foo.war");
jetty.copyContext("foo.xml","foo.xml");
jetty.waitForDirectoryScan();
waitForDirectoryScan();
jetty.assertWebAppContextsExists("/foo");
@ -111,8 +153,8 @@ public class ScanningAppProviderRuntimeUpdatesTest
jetty.copyWebapp("foo-webapp-2.war","foo.war");
// This should result in the existing foo.war being replaced with the new foo.war
jetty.waitForDirectoryScan();
jetty.waitForDirectoryScan();
waitForDirectoryScan();
waitForDirectoryScan();
jetty.assertWebAppContextsExists("/foo");
// Test that webapp response contains "-2"

View File

@ -431,18 +431,4 @@ public class XmlConfiguredJetty
_server.stop();
}
public void waitForDirectoryScan()
{
int ms = 2000;
System.out.printf("Waiting %d milliseconds for AppProvider to process directory scan ...%n",ms);
try
{
Thread.sleep(ms);
}
catch (InterruptedException ignore)
{
/* ignore */
}
}
}

View File

@ -15,7 +15,7 @@
<Array type="org.eclipse.jetty.deploy.AppProvider">
<Item>
<New class="org.eclipse.jetty.deploy.providers.ContextProvider">
<Set name="monitoredDir"><SystemProperty name="jetty.home" />/contexts</Set>
<Set name="monitoredDirName"><SystemProperty name="jetty.home" />/contexts</Set>
<Set name="scanInterval">1</Set>
<Set name="configurationManager">
<New class="org.eclipse.jetty.deploy.FileConfigurationManager">
@ -28,7 +28,7 @@
</Item>
<Item>
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
<Set name="monitoredDir"><SystemProperty name="jetty.home" />/webapps</Set>
<Set name="monitoredDirName"><SystemProperty name="jetty.home" />/webapps</Set>
<Set name="scanInterval">1</Set>
<Set name="contextXmlDir"><SystemProperty name="jetty.home" />/contexts</Set>
</New>

View File

@ -104,6 +104,10 @@ public class Scanner extends AbstractLifeCycle
{
}
public interface ScanListener extends Listener
{
public void scan();
}
public interface DiscreteListener extends Listener
{
@ -391,6 +395,23 @@ public class Scanner extends AbstractLifeCycle
_prevScan.clear();
_prevScan.putAll(_currentScan);
reportScanEnd(_scanCount);
for (Listener l : _listeners)
{
try
{
if (l instanceof ScanListener)
((ScanListener)l).scan();
}
catch (Exception e)
{
Log.warn(e);
}
catch (Error e)
{
Log.warn(e);
}
}
}
/**

View File

@ -6,6 +6,7 @@ import java.util.concurrent.ConcurrentLinkedQueue;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil;
@ -18,8 +19,9 @@ public class TestServer extends Server
WebSocket _websocket;
SelectChannelConnector _connector;
WebSocketHandler _handler;
ConcurrentLinkedQueue<TestWebSocket> _webSockets = new ConcurrentLinkedQueue<TestWebSocket>();
WebSocketHandler _wsHandler;
ResourceHandler _rHandler;
ConcurrentLinkedQueue<TestWebSocket> _broadcast = new ConcurrentLinkedQueue<TestWebSocket>();
public TestServer(int port)
{
@ -27,7 +29,7 @@ public class TestServer extends Server
_connector.setPort(port);
addConnector(_connector);
_handler = new WebSocketHandler()
_wsHandler = new WebSocketHandler()
{
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
{
@ -56,19 +58,38 @@ public class TestServer extends Server
}
};
setHandler(_handler);
setHandler(_wsHandler);
_rHandler=new ResourceHandler();
_rHandler.setDirectoriesListed(true);
_rHandler.setResourceBase(".");
_wsHandler.setHandler(_rHandler);
}
/* ------------------------------------------------------------ */
public boolean isVerbose()
{
return _verbose;
}
/* ------------------------------------------------------------ */
public void setVerbose(boolean verbose)
{
_verbose = verbose;
}
/* ------------------------------------------------------------ */
public void setResourceBase(String dir)
{
_rHandler.setResourceBase(dir);
}
/* ------------------------------------------------------------ */
public String getResourceBase()
{
return _rHandler.getResourceBase();
}
/* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */
@ -84,12 +105,14 @@ public class TestServer extends Server
public void onConnect(Connection connection)
{
_connection = connection;
_webSockets.add(this);
if (_verbose)
System.err.printf("%s#onConnect %s\n",this.getClass().getSimpleName(),connection);
}
public void onDisconnect(int code,String message)
{
_webSockets.remove(this);
if (_verbose)
System.err.printf("%s#onDisonnect %d %s\n",this.getClass().getSimpleName(),code,message);
}
public boolean onFrame(byte flags, byte opcode, byte[] data, int offset, int length)
@ -160,11 +183,25 @@ public class TestServer extends Server
/* ------------------------------------------------------------ */
class TestEchoBroadcastWebSocket extends TestWebSocket
{
@Override
public void onConnect(Connection connection)
{
super.onConnect(connection);
_broadcast.add(this);
}
@Override
public void onDisconnect(int code,String message)
{
super.onDisconnect(code,message);
_broadcast.remove(this);
}
@Override
public void onMessage(byte[] data, int offset, int length)
{
super.onMessage(data,offset,length);
for (TestWebSocket ws : _webSockets)
for (TestWebSocket ws : _broadcast)
{
try
{
@ -172,6 +209,7 @@ public class TestServer extends Server
}
catch (IOException e)
{
_broadcast.remove(ws);
e.printStackTrace();
}
}
@ -181,7 +219,7 @@ public class TestServer extends Server
public void onMessage(final String data)
{
super.onMessage(data);
for (TestWebSocket ws : _webSockets)
for (TestWebSocket ws : _broadcast)
{
try
{
@ -189,6 +227,7 @@ public class TestServer extends Server
}
catch (IOException e)
{
_broadcast.remove(ws);
e.printStackTrace();
}
}
@ -286,17 +325,19 @@ public class TestServer extends Server
private static void usage()
{
System.err.println("java -cp CLASSPATH "+TestServer.class+" [ OPTIONS ]");
System.err.println(" -p|--port PORT ");
System.err.println(" -p|--port PORT (default 8080)");
System.err.println(" -v|--verbose ");
System.err.println(" -d|--docroot file (default '.')");
System.exit(1);
}
public static void main(String[] args)
public static void main(String... args)
{
try
{
int port=8080;
boolean verbose=false;
String docroot=".";
for (int i=0;i<args.length;i++)
{
@ -305,6 +346,8 @@ public class TestServer extends Server
port=Integer.parseInt(args[++i]);
else if ("-v".equals(a)||"--verbose".equals(a))
verbose=true;
else if ("-d".equals(a)||"--docroot".equals(a))
docroot=args[++i];
else if (a.startsWith("-"))
usage();
}
@ -312,6 +355,7 @@ public class TestServer extends Server
TestServer server = new TestServer(port);
server.setVerbose(verbose);
server.setResourceBase(docroot);
server.start();
server.join();
}

View File

@ -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://').replace('https://','wss://');
this._ws=new WebSocket(location,"org.ietf.websocket.test-echo-broadcast");
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).replace('<','&lt;').replace('>','&gt;');
var text=m.data.substring(c+1).replace('<','&lt;').replace('>','&gt;');
var chat=$('chat');
var spanFrom = document.createElement('span');
spanFrom.className='from';
spanFrom.innerHTML=from+':&nbsp;';
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:&nbsp;<input id='username' type='text'/><input id='joinB' class='button' type='submit' name='join' value='Join'/>
</div>
<div id='joined' class='hidden'>
Chat:&nbsp;<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>