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 jetty-7.4.0.RC0
+ 324110 Added test harnesses for merging of QueryStrings. + 324110 Added test harnesses for merging of QueryStrings.
+ 337685 Update websocket API in preparation for draft -07 + 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; return _deploymentManager;
} }
/* ------------------------------------------------------------ */
@Deprecated
public Resource getMonitoredDir()
{
return _monitoredDir;
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
public Resource getMonitoredDirResource() public Resource getMonitoredDirResource()
@ -212,30 +206,18 @@ public abstract class ScanningAppProvider extends AbstractLifeCycle implements A
_deploymentManager = deploymentManager; _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) public void setMonitoredDirResource(Resource contextsDir)
{ {
_monitoredDir = contextsDir; _monitoredDir = contextsDir;
} }
/* ------------------------------------------------------------ */
public void addScannerListener(Scanner.Listener listener)
{
_scanner.addListener(listener);
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* @param dir * @param dir

View File

@ -16,9 +16,14 @@
package org.eclipse.jetty.deploy.providers; package org.eclipse.jetty.deploy.providers;
import java.io.IOException; 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.deploy.test.XmlConfiguredJetty;
import org.eclipse.jetty.toolchain.test.TestingDir; 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.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Rule; import org.junit.Rule;
@ -33,6 +38,8 @@ public class ScanningAppProviderRuntimeUpdatesTest
@Rule @Rule
public TestingDir testdir = new TestingDir(); public TestingDir testdir = new TestingDir();
private static XmlConfiguredJetty jetty; private static XmlConfiguredJetty jetty;
private final AtomicInteger _scans = new AtomicInteger();
private int _providers;
@Before @Before
public void setupEnvironment() throws Exception public void setupEnvironment() throws Exception
@ -46,6 +53,24 @@ public class ScanningAppProviderRuntimeUpdatesTest
// Start it // Start it
jetty.start(); 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 @After
@ -55,6 +80,23 @@ public class ScanningAppProviderRuntimeUpdatesTest
jetty.stop(); 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. * Simple webapp deployment after startup of server.
*/ */
@ -64,7 +106,7 @@ public class ScanningAppProviderRuntimeUpdatesTest
jetty.copyWebapp("foo-webapp-1.war","foo.war"); jetty.copyWebapp("foo-webapp-1.war","foo.war");
jetty.copyContext("foo.xml","foo.xml"); jetty.copyContext("foo.xml","foo.xml");
jetty.waitForDirectoryScan(); waitForDirectoryScan();
jetty.assertWebAppContextsExists("/foo"); jetty.assertWebAppContextsExists("/foo");
} }
@ -78,13 +120,13 @@ public class ScanningAppProviderRuntimeUpdatesTest
jetty.copyWebapp("foo-webapp-1.war","foo.war"); jetty.copyWebapp("foo-webapp-1.war","foo.war");
jetty.copyContext("foo.xml","foo.xml"); jetty.copyContext("foo.xml","foo.xml");
jetty.waitForDirectoryScan(); waitForDirectoryScan();
jetty.assertWebAppContextsExists("/foo"); jetty.assertWebAppContextsExists("/foo");
jetty.removeContext("foo.xml"); jetty.removeContext("foo.xml");
jetty.waitForDirectoryScan(); waitForDirectoryScan();
// FIXME: hot undeploy with removal not working! - jetty.assertNoWebAppContexts(); // 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.copyWebapp("foo-webapp-1.war","foo.war");
jetty.copyContext("foo.xml","foo.xml"); jetty.copyContext("foo.xml","foo.xml");
jetty.waitForDirectoryScan(); waitForDirectoryScan();
jetty.assertWebAppContextsExists("/foo"); jetty.assertWebAppContextsExists("/foo");
@ -111,8 +153,8 @@ public class ScanningAppProviderRuntimeUpdatesTest
jetty.copyWebapp("foo-webapp-2.war","foo.war"); jetty.copyWebapp("foo-webapp-2.war","foo.war");
// This should result in the existing foo.war being replaced with the new foo.war // This should result in the existing foo.war being replaced with the new foo.war
jetty.waitForDirectoryScan(); waitForDirectoryScan();
jetty.waitForDirectoryScan(); waitForDirectoryScan();
jetty.assertWebAppContextsExists("/foo"); jetty.assertWebAppContextsExists("/foo");
// Test that webapp response contains "-2" // Test that webapp response contains "-2"

View File

@ -431,18 +431,4 @@ public class XmlConfiguredJetty
_server.stop(); _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"> <Array type="org.eclipse.jetty.deploy.AppProvider">
<Item> <Item>
<New class="org.eclipse.jetty.deploy.providers.ContextProvider"> <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="scanInterval">1</Set>
<Set name="configurationManager"> <Set name="configurationManager">
<New class="org.eclipse.jetty.deploy.FileConfigurationManager"> <New class="org.eclipse.jetty.deploy.FileConfigurationManager">
@ -28,7 +28,7 @@
</Item> </Item>
<Item> <Item>
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider"> <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="scanInterval">1</Set>
<Set name="contextXmlDir"><SystemProperty name="jetty.home" />/contexts</Set> <Set name="contextXmlDir"><SystemProperty name="jetty.home" />/contexts</Set>
</New> </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 public interface DiscreteListener extends Listener
{ {
@ -391,6 +395,23 @@ public class Scanner extends AbstractLifeCycle
_prevScan.clear(); _prevScan.clear();
_prevScan.putAll(_currentScan); _prevScan.putAll(_currentScan);
reportScanEnd(_scanCount); 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 javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector; import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.TypeUtil;
@ -18,8 +19,9 @@ public class TestServer extends Server
WebSocket _websocket; WebSocket _websocket;
SelectChannelConnector _connector; SelectChannelConnector _connector;
WebSocketHandler _handler; WebSocketHandler _wsHandler;
ConcurrentLinkedQueue<TestWebSocket> _webSockets = new ConcurrentLinkedQueue<TestWebSocket>(); ResourceHandler _rHandler;
ConcurrentLinkedQueue<TestWebSocket> _broadcast = new ConcurrentLinkedQueue<TestWebSocket>();
public TestServer(int port) public TestServer(int port)
{ {
@ -27,7 +29,7 @@ public class TestServer extends Server
_connector.setPort(port); _connector.setPort(port);
addConnector(_connector); addConnector(_connector);
_handler = new WebSocketHandler() _wsHandler = new WebSocketHandler()
{ {
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
{ {
@ -56,20 +58,39 @@ public class TestServer extends Server
} }
}; };
setHandler(_handler); setHandler(_wsHandler);
_rHandler=new ResourceHandler();
_rHandler.setDirectoriesListed(true);
_rHandler.setResourceBase(".");
_wsHandler.setHandler(_rHandler);
} }
/* ------------------------------------------------------------ */
public boolean isVerbose() public boolean isVerbose()
{ {
return _verbose; return _verbose;
} }
/* ------------------------------------------------------------ */
public void setVerbose(boolean verbose) public void setVerbose(boolean verbose)
{ {
_verbose = verbose; _verbose = verbose;
} }
/* ------------------------------------------------------------ */
public void setResourceBase(String dir)
{
_rHandler.setResourceBase(dir);
}
/* ------------------------------------------------------------ */
public String getResourceBase()
{
return _rHandler.getResourceBase();
}
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
class TestWebSocket implements WebSocket, WebSocket.OnFrame, WebSocket.OnBinaryMessage, WebSocket.OnTextMessage, WebSocket.OnControl class TestWebSocket implements WebSocket, WebSocket.OnFrame, WebSocket.OnBinaryMessage, WebSocket.OnTextMessage, WebSocket.OnControl
@ -84,12 +105,14 @@ public class TestServer extends Server
public void onConnect(Connection connection) public void onConnect(Connection connection)
{ {
_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) 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) 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 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 @Override
public void onMessage(byte[] data, int offset, int length) public void onMessage(byte[] data, int offset, int length)
{ {
super.onMessage(data,offset,length); super.onMessage(data,offset,length);
for (TestWebSocket ws : _webSockets) for (TestWebSocket ws : _broadcast)
{ {
try try
{ {
@ -172,6 +209,7 @@ public class TestServer extends Server
} }
catch (IOException e) catch (IOException e)
{ {
_broadcast.remove(ws);
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -181,7 +219,7 @@ public class TestServer extends Server
public void onMessage(final String data) public void onMessage(final String data)
{ {
super.onMessage(data); super.onMessage(data);
for (TestWebSocket ws : _webSockets) for (TestWebSocket ws : _broadcast)
{ {
try try
{ {
@ -189,6 +227,7 @@ public class TestServer extends Server
} }
catch (IOException e) catch (IOException e)
{ {
_broadcast.remove(ws);
e.printStackTrace(); e.printStackTrace();
} }
} }
@ -286,17 +325,19 @@ public class TestServer extends Server
private static void usage() private static void usage()
{ {
System.err.println("java -cp CLASSPATH "+TestServer.class+" [ OPTIONS ]"); 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(" -v|--verbose ");
System.err.println(" -d|--docroot file (default '.')");
System.exit(1); System.exit(1);
} }
public static void main(String[] args) public static void main(String... args)
{ {
try try
{ {
int port=8080; int port=8080;
boolean verbose=false; boolean verbose=false;
String docroot=".";
for (int i=0;i<args.length;i++) for (int i=0;i<args.length;i++)
{ {
@ -305,6 +346,8 @@ public class TestServer extends Server
port=Integer.parseInt(args[++i]); port=Integer.parseInt(args[++i]);
else if ("-v".equals(a)||"--verbose".equals(a)) else if ("-v".equals(a)||"--verbose".equals(a))
verbose=true; verbose=true;
else if ("-d".equals(a)||"--docroot".equals(a))
docroot=args[++i];
else if (a.startsWith("-")) else if (a.startsWith("-"))
usage(); usage();
} }
@ -312,6 +355,7 @@ public class TestServer extends Server
TestServer server = new TestServer(port); TestServer server = new TestServer(port);
server.setVerbose(verbose); server.setVerbose(verbose);
server.setResourceBase(docroot);
server.start(); server.start();
server.join(); 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>