bug 346605 commit the demo of jetty's continuation and webscoket to 'chat with the equinox console
git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@3221 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
parent
538038a7f2
commit
850170ba5f
|
@ -25,12 +25,12 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse</groupId>
|
||||
<artifactId>osgi</artifactId>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>services</artifactId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.mortbay.jetty</groupId>
|
||||
|
|
|
@ -21,8 +21,8 @@
|
|||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse</groupId>
|
||||
<artifactId>osgi</artifactId>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
|
@ -30,7 +30,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>services</artifactId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
<artifactId>jetty-util</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse</groupId>
|
||||
<artifactId>osgi</artifactId>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -31,12 +31,12 @@
|
|||
<artifactId>jetty-nested</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse</groupId>
|
||||
<artifactId>osgi</artifactId>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>services</artifactId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
Manifest-Version: 1.0
|
||||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: Console
|
||||
Bundle-SymbolicName: org.eclipse.jetty.osgi.equinoxtools
|
||||
Bundle-Description: Example application: equinox console accesssible on the web
|
||||
Bundle-Version: 7.4.2.qualifier
|
||||
Bundle-Activator: org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator
|
||||
Import-Package: javax.servlet;version="2.5.0",
|
||||
javax.servlet.http;version="2.5.0",
|
||||
org.eclipse.jetty.continuation;version="7.4.0",
|
||||
org.eclipse.jetty.io;version="7.4.0",
|
||||
org.eclipse.jetty.util;version="7.4.0",
|
||||
org.eclipse.jetty.util.log;version="7.4.0",
|
||||
org.eclipse.jetty.websocket;version="7.4.0",
|
||||
org.eclipse.osgi.framework.console;version="1.1.0",
|
||||
org.osgi.framework;version="1.3.0",
|
||||
org.osgi.service.http;version="1.2.0",
|
||||
org.osgi.util.tracker;version="1.3.0"
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
source.. = src/
|
||||
output.. = bin/
|
||||
bin.includes = META-INF/,\
|
||||
.
|
|
@ -0,0 +1,85 @@
|
|||
<html><head>
|
||||
<title>Async Equinox Console</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'>
|
||||
OSGi: <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>
|
|
@ -0,0 +1,109 @@
|
|||
<html><head>
|
||||
<title>Equinox Console (WebSocket)</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://').replace('/index.html','');
|
||||
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).replace('<','<').replace('>','>');
|
||||
var text=m.data.substring(c+1).replace('<','<').replace('>','>');
|
||||
|
||||
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>
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,96 @@
|
|||
<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.osgi</groupId>
|
||||
<artifactId>jetty-osgi-project</artifactId>
|
||||
<version>7.4.2-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>jetty-osgi-equinoxtools</artifactId>
|
||||
<name>Jetty :: OSGi :: Example Equinox Tools</name>
|
||||
<description>Jetty OSGi Example Equinox Tools</description>
|
||||
<properties>
|
||||
<bundle-symbolic-name>${project.groupId}.equinoxtools</bundle-symbolic-name>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-resources</phase>
|
||||
<configuration>
|
||||
<tasks>
|
||||
<replace file="target/classes/META-INF/MANIFEST.MF" token="Bundle-Version: 7.4.2.qualifier" value="Bundle-Version: ${parsedVersion.osgiVersion}" />
|
||||
<copy todir="target/classes/equinoxconsole">
|
||||
<fileset dir="equinoxconsole" />
|
||||
</copy>
|
||||
</tasks>
|
||||
</configuration>
|
||||
<goals>
|
||||
<goal>run</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>artifact-jar</id>
|
||||
<goals>
|
||||
<goal>jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-jar</id>
|
||||
<goals>
|
||||
<goal>test-jar</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<archive>
|
||||
<manifestFile>target/classes/META-INF/MANIFEST.MF</manifestFile>
|
||||
</archive>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>findbugs-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<onlyAnalyze>org.eclipse.jetty.osgi.equinoxtools.*</onlyAnalyze>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,127 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.osgi.equinoxtools;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
import org.eclipse.jetty.osgi.equinoxtools.console.EquinoxChattingSupport;
|
||||
import org.eclipse.jetty.osgi.equinoxtools.console.EquinoxConsoleContinuationServlet;
|
||||
import org.eclipse.jetty.osgi.equinoxtools.console.EquinoxConsoleSyncServlet;
|
||||
import org.eclipse.jetty.osgi.equinoxtools.console.EquinoxConsoleWebSocketServlet;
|
||||
import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleSession;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.osgi.framework.console.ConsoleSession;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.service.http.HttpService;
|
||||
import org.osgi.service.http.NamespaceException;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
import org.osgi.util.tracker.ServiceTrackerCustomizer;
|
||||
|
||||
/**
|
||||
* When started will register on the HttpService 3 servlets for 3 different styles of equinox consoles.
|
||||
*/
|
||||
public class WebEquinoxToolsActivator implements BundleActivator
|
||||
{
|
||||
|
||||
private static BundleContext context;
|
||||
public static BundleContext getContext()
|
||||
{
|
||||
return context;
|
||||
}
|
||||
|
||||
private HttpService _httpService;
|
||||
private ServiceTracker _tracker;
|
||||
private EquinoxChattingSupport _equinoxChattingSupport;
|
||||
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
public void start(BundleContext bundleContext) throws Exception
|
||||
{
|
||||
WebEquinoxToolsActivator.context = bundleContext;
|
||||
|
||||
ServiceTrackerCustomizer httpServiceTrackerCustomizer = new ServiceTrackerCustomizer()
|
||||
{
|
||||
@Override
|
||||
public void removedService(ServiceReference reference, Object service)
|
||||
{
|
||||
_httpService = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifiedService(ServiceReference reference, Object service)
|
||||
{
|
||||
_httpService = (HttpService)context.getService(reference);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object addingService(ServiceReference reference)
|
||||
{
|
||||
_httpService = (HttpService)context.getService(reference);
|
||||
try
|
||||
{
|
||||
//TODO; some effort to use the same console session on the 2 async console servlets?
|
||||
|
||||
//websocket:
|
||||
// WebConsoleSession wsSession = new WebConsoleSession();
|
||||
// WebEquinoxConsoleActivator.context.registerService(ConsoleSession.class.getName(), wsSession, null);
|
||||
// EquinoxChattingSupport wsEquinoxChattingSupport = new EquinoxChattingSupport(wsSession);
|
||||
_httpService.registerResources("/equinoxconsole/ws/index.html","/equinoxconsole/ws/index.html",null);
|
||||
_httpService.registerServlet("/equinoxconsole/ws",new EquinoxConsoleWebSocketServlet(/*wsSession, wsEquinoxChattingSupport*/),null,null);
|
||||
|
||||
//continuations:
|
||||
// WebConsoleSession contSession = new WebConsoleSession();
|
||||
// WebEquinoxConsoleActivator.context.registerService(ConsoleSession.class.getName(), contSession, null);
|
||||
// EquinoxChattingSupport contEquinoxChattingSupport = new EquinoxChattingSupport(contSession);
|
||||
_httpService.registerResources("/equinoxconsole/index.html","/equinoxconsole/index.html",null);
|
||||
_httpService.registerServlet("/equinoxconsole",new EquinoxConsoleContinuationServlet(/*contSession, contEquinoxChattingSupport*/),null,null);
|
||||
|
||||
//legacy synchroneous; keep it in a separate console session.
|
||||
WebConsoleSession syncSession = new WebConsoleSession();
|
||||
WebEquinoxToolsActivator.context.registerService(ConsoleSession.class.getName(), syncSession, null);
|
||||
_httpService.registerServlet("/equinoxconsole/sync",new EquinoxConsoleSyncServlet(syncSession),null,null);
|
||||
}
|
||||
catch (ServletException e)
|
||||
{
|
||||
Log.warn(e);
|
||||
}
|
||||
catch (NamespaceException e)
|
||||
{
|
||||
Log.warn(e);
|
||||
}
|
||||
return _httpService;
|
||||
}
|
||||
};
|
||||
|
||||
_tracker = new ServiceTracker(context,HttpService.class.getName(),httpServiceTrackerCustomizer);
|
||||
_tracker.open();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
|
||||
*/
|
||||
public void stop(BundleContext bundleContext) throws Exception
|
||||
{
|
||||
_tracker.close();
|
||||
WebEquinoxToolsActivator.context = null;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.osgi.equinoxtools.console;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
|
||||
import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleWriterOutputStream.OnFlushListener;
|
||||
|
||||
/**
|
||||
* Processing of the messages to be received and sent to the chat servlets.
|
||||
* Made to be extended for filtering of the messages and commands.
|
||||
*/
|
||||
public class EquinoxChattingSupport
|
||||
{
|
||||
|
||||
private WebConsoleSession _consoleSession;
|
||||
|
||||
public EquinoxChattingSupport(WebConsoleSession consoleSession)
|
||||
{
|
||||
_consoleSession = consoleSession;
|
||||
}
|
||||
|
||||
/**
|
||||
* Split the output into multiple lines.
|
||||
* Format them for the json messages sent to the chat.
|
||||
* Empties the console output from what is already displayed in the chat.
|
||||
* @return The lines to add to the message queue of each client.
|
||||
*/
|
||||
protected Queue<String> processConsoleOutput(boolean escape, OnFlushListener onflush)
|
||||
{
|
||||
Queue<String> result = new LinkedList<String>();
|
||||
String toDisplay = _consoleSession.getOutputAsWriter().getBuffer().toString();
|
||||
//the last listener to be called is in charge of clearing the console.
|
||||
boolean clearConsole = _consoleSession.getOnFlushListeners().indexOf(onflush) == _consoleSession.getOnFlushListeners().size();
|
||||
if (clearConsole)
|
||||
{
|
||||
_consoleSession.clearOutput();
|
||||
}
|
||||
boolean lastLineIsComplete = toDisplay.endsWith("\n") || toDisplay.endsWith("\r");
|
||||
String[] lines = toDisplay.split("\n");
|
||||
String lastLine = lastLineIsComplete ? null : lines[lines.length-1];
|
||||
if (clearConsole)
|
||||
{
|
||||
_consoleSession.getOutputAsWriter().append(lastLine);
|
||||
}
|
||||
for (int lnNb = 0; lnNb < (lastLineIsComplete ? lines.length : lines.length-1); lnNb++)
|
||||
{
|
||||
String line = lines[lnNb];
|
||||
while (line.trim().startsWith("null"))
|
||||
{//hum..
|
||||
line = line.trim().substring("null".length()).trim();
|
||||
}
|
||||
if (line.startsWith("osgi>"))
|
||||
{
|
||||
result.add("osgi>");
|
||||
result.add(escape ? jsonEscapeString(line.substring("osgi>".length())) : line.substring("osgi>".length()));
|
||||
}
|
||||
else
|
||||
{
|
||||
result.add(" ");
|
||||
result.add(escape ? jsonEscapeString(line) : line);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* http://www.ietf.org/rfc/rfc4627.txt
|
||||
* @param str
|
||||
* @return The same string escaped according to the JSON RFC.
|
||||
*/
|
||||
public static String jsonEscapeString(String str)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char[] asChars = str.toCharArray();
|
||||
for (char ch : asChars)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
//the reserved characters
|
||||
case '"':
|
||||
sb.append("\\\"");
|
||||
break;
|
||||
case '\\':
|
||||
sb.append("\\\\");
|
||||
break;
|
||||
case '\b':
|
||||
sb.append("\\b");
|
||||
break;
|
||||
case '\f':
|
||||
sb.append("\\f");
|
||||
break;
|
||||
case '\n':
|
||||
sb.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
sb.append("\\r");
|
||||
break;
|
||||
case '\t':
|
||||
sb.append("\\t");
|
||||
break;
|
||||
case '/':
|
||||
sb.append("\\/");
|
||||
break;
|
||||
default:
|
||||
//The non reserved characters
|
||||
if (ch >= '\u0000' && ch <= '\u001F')
|
||||
{
|
||||
//escape as a unicode number when out of range.
|
||||
String ss = Integer.toHexString(ch);
|
||||
sb.append("\\u");
|
||||
for (int i = 0; i < 4 - ss.length(); i++)
|
||||
{
|
||||
//padding
|
||||
sb.append('0');
|
||||
}
|
||||
sb.append(ss.toUpperCase());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void broadcast(OnFlushListener source)
|
||||
{
|
||||
for (OnFlushListener onflush : _consoleSession.getOnFlushListeners())
|
||||
{
|
||||
if (onflush != source)
|
||||
{
|
||||
onflush.onFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,248 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.osgi.equinoxtools.console;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.Queue;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.continuation.Continuation;
|
||||
import org.eclipse.jetty.continuation.ContinuationSupport;
|
||||
import org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator;
|
||||
import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleWriterOutputStream.OnFlushListener;
|
||||
import org.eclipse.osgi.framework.console.ConsoleSession;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
|
||||
/**
|
||||
* Async servlet with jetty continuations to interact with the equinox console.
|
||||
* Ported from jetty's example 'ChatServlet'
|
||||
*/
|
||||
public class EquinoxConsoleContinuationServlet extends HttpServlet implements OnFlushListener
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private Map<String,ConsoleUser> _consoleUsers = new HashMap<String, ConsoleUser>();
|
||||
private WebConsoleSession _consoleSession;
|
||||
private EquinoxChattingSupport _support;
|
||||
|
||||
/**
|
||||
* @param consoleSession
|
||||
*/
|
||||
public EquinoxConsoleContinuationServlet()
|
||||
{
|
||||
|
||||
}
|
||||
/**
|
||||
* @param consoleSession
|
||||
*/
|
||||
public EquinoxConsoleContinuationServlet(WebConsoleSession consoleSession, EquinoxChattingSupport support)
|
||||
{
|
||||
_consoleSession = consoleSession;
|
||||
_support = support;
|
||||
}
|
||||
@Override
|
||||
public void init() throws ServletException
|
||||
{
|
||||
if (_consoleSession == null)
|
||||
{
|
||||
_consoleSession = new WebConsoleSession();
|
||||
WebEquinoxToolsActivator.getContext().registerService(ConsoleSession.class.getName(), _consoleSession, null);
|
||||
}
|
||||
if (_support == null)
|
||||
{
|
||||
_support = new EquinoxChattingSupport(_consoleSession);
|
||||
}
|
||||
_consoleSession.addOnFlushListener(this);
|
||||
}
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
_consoleSession.removeOnFlushListener(this);
|
||||
}
|
||||
|
||||
// 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.getParameter("action")!=null)
|
||||
doPost(request,response);
|
||||
else
|
||||
response.sendRedirect("index.html");
|
||||
}
|
||||
|
||||
// Handle Ajax calls from browser
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
// Ajax calls are form encoded
|
||||
String action = request.getParameter("action");
|
||||
String message = request.getParameter("message");
|
||||
String username = request.getParameter("user");
|
||||
|
||||
if (action.equals("join"))
|
||||
join(request,response,username);
|
||||
else if (action.equals("poll"))
|
||||
poll(request,response,username);
|
||||
else if (action.equals("chat"))
|
||||
chat(request,response,username,message);
|
||||
}
|
||||
|
||||
private synchronized void join(HttpServletRequest request,HttpServletResponse response,String username)
|
||||
throws IOException
|
||||
{
|
||||
ConsoleUser member = new ConsoleUser(username);
|
||||
_consoleUsers.put(username,member);
|
||||
response.setContentType("text/json;charset=utf-8");
|
||||
PrintWriter out=response.getWriter();
|
||||
out.print("{action:\"join\"}");
|
||||
}
|
||||
|
||||
private synchronized void poll(HttpServletRequest request,HttpServletResponse response,String username)
|
||||
throws IOException
|
||||
{
|
||||
ConsoleUser member = _consoleUsers.get(username);
|
||||
if (member==null)
|
||||
{
|
||||
response.sendError(503);
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized(member)
|
||||
{
|
||||
if (member.getMessageQueue().size()>0)
|
||||
{
|
||||
// Send one chat message
|
||||
response.setContentType("text/json;charset=utf-8");
|
||||
StringBuilder buf=new StringBuilder();
|
||||
|
||||
buf.append("{\"action\":\"poll\",");
|
||||
buf.append("\"from\":\"");
|
||||
buf.append(member.getMessageQueue().poll());
|
||||
buf.append("\",");
|
||||
|
||||
String message = member.getMessageQueue().poll();
|
||||
int quote=message.indexOf('"');
|
||||
while (quote>=0)
|
||||
{
|
||||
message=message.substring(0,quote)+'\\'+message.substring(quote);
|
||||
quote=message.indexOf('"',quote+2);
|
||||
}
|
||||
buf.append("\"chat\":\"");
|
||||
buf.append(message);
|
||||
buf.append("\"}");
|
||||
byte[] bytes = buf.toString().getBytes("utf-8");
|
||||
response.setContentLength(bytes.length);
|
||||
response.getOutputStream().write(bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
Continuation continuation = ContinuationSupport.getContinuation(request);
|
||||
if (continuation.isInitial())
|
||||
{
|
||||
// No chat in queue, so suspend and wait for timeout or chat
|
||||
continuation.setTimeout(20000);
|
||||
continuation.suspend();
|
||||
member.setContinuation(continuation);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Timeout so send empty response
|
||||
response.setContentType("text/json;charset=utf-8");
|
||||
PrintWriter out=response.getWriter();
|
||||
out.print("{action:\"poll\"}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void chat(HttpServletRequest request,HttpServletResponse response,String username,String message)
|
||||
throws IOException
|
||||
{
|
||||
if (!message.endsWith("has joined!"))
|
||||
{
|
||||
_consoleSession.processCommand(message, false);
|
||||
}
|
||||
// Post chat to all members
|
||||
onFlush();
|
||||
|
||||
response.setContentType("text/json;charset=utf-8");
|
||||
PrintWriter out=response.getWriter();
|
||||
out.print("{action:\"chat\"}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Called right after the flush method on the output stream has been executed.
|
||||
*/
|
||||
public void onFlush()
|
||||
{
|
||||
Queue<String> pendingConsoleOutputMessages = _support.processConsoleOutput(true, this);
|
||||
for (ConsoleUser m:_consoleUsers.values())
|
||||
{
|
||||
synchronized (m)
|
||||
{
|
||||
// m.getMessageQueue().add("osgi>"); // from
|
||||
// m.getMessageQueue().add("something was printed"); // chat
|
||||
m.getMessageQueue().addAll(pendingConsoleOutputMessages);
|
||||
|
||||
// wakeup member if polling
|
||||
if (m.getContinuation()!=null)
|
||||
{
|
||||
m.getContinuation().resume();
|
||||
m.setContinuation(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ConsoleUser
|
||||
{
|
||||
private String _name;
|
||||
private Continuation _continuation;
|
||||
private Queue<String> _queue = new LinkedList<String>();
|
||||
|
||||
public ConsoleUser(String name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
|
||||
public void setContinuation(Continuation continuation)
|
||||
{
|
||||
_continuation = continuation;
|
||||
}
|
||||
|
||||
public Continuation getContinuation()
|
||||
{
|
||||
return _continuation;
|
||||
}
|
||||
public Queue<String> getMessageQueue()
|
||||
{
|
||||
return _queue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.osgi.equinoxtools.console;
|
||||
|
||||
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;
|
||||
|
||||
|
||||
/**
|
||||
* Take the example ChatServlet and use it to make an Equinox Console on the web.
|
||||
*/
|
||||
public class EquinoxConsoleSyncServlet extends HttpServlet
|
||||
{
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private WebConsoleSession _consoleSession;
|
||||
|
||||
public EquinoxConsoleSyncServlet(WebConsoleSession consoleSession)
|
||||
{
|
||||
_consoleSession = consoleSession;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
|
||||
{
|
||||
String cmd = request.getParameter("cmd");
|
||||
String Action = request.getParameter("Action");
|
||||
if (Action != null && Action.toLowerCase().indexOf("clear") != -1)
|
||||
{
|
||||
_consoleSession.clearOutput();
|
||||
}
|
||||
if (cmd != null)
|
||||
{
|
||||
_consoleSession.processCommand(cmd, true);
|
||||
}
|
||||
|
||||
response.setContentType("text/html;charset=utf-8");
|
||||
PrintWriter p = response.getWriter();
|
||||
p.println("<html><head><title>Equinox Console (Synchroneous)</title></head><body>");
|
||||
p.println("<textarea rows=\"30\" cols=\"110\">");
|
||||
p.println(_consoleSession.getOutputAsWriter().toString());
|
||||
p.println("</textarea>");
|
||||
p.println("<form method=\"GET\" action=\""+response.encodeURL(getURI(request))+"\">");
|
||||
p.println("osgi> <input type=\"text\" name=\"cmd\" value=\"\"/><br/>\n");
|
||||
p.println("<input type=\"submit\" name=\"Action\" value=\"Submit or Refresh\"><br/>");
|
||||
p.println("<input type=\"submit\" name=\"Action\" value=\"Clear and Submit\"><br/>");
|
||||
p.println("</form>");
|
||||
p.println("<br/>");
|
||||
}
|
||||
|
||||
|
||||
private String getURI(HttpServletRequest request)
|
||||
{
|
||||
String uri= (String)request.getAttribute("javax.servlet.forward.request_uri");
|
||||
if (uri == null)
|
||||
uri= request.getRequestURI();
|
||||
return uri;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.osgi.equinoxtools.console;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator;
|
||||
import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleWriterOutputStream.OnFlushListener;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.websocket.WebSocket;
|
||||
import org.eclipse.jetty.websocket.WebSocketServlet;
|
||||
import org.eclipse.osgi.framework.console.ConsoleSession;
|
||||
import org.osgi.framework.Bundle;
|
||||
import org.osgi.framework.FrameworkUtil;
|
||||
|
||||
/**
|
||||
* Websocket version of the Chat with equinox.
|
||||
* Ported from jetty's example 'WebSocketChatServlet'
|
||||
*/
|
||||
public class EquinoxConsoleWebSocketServlet extends WebSocketServlet implements OnFlushListener
|
||||
{
|
||||
private final Set<ChatWebSocket> _members = new CopyOnWriteArraySet<ChatWebSocket>();
|
||||
private static final long serialVersionUID = 1L;
|
||||
private WebConsoleSession _consoleSession;
|
||||
private EquinoxChattingSupport _support;
|
||||
|
||||
public EquinoxConsoleWebSocketServlet()
|
||||
{
|
||||
|
||||
}
|
||||
public EquinoxConsoleWebSocketServlet(WebConsoleSession consoleSession, EquinoxChattingSupport support)
|
||||
{
|
||||
_consoleSession = consoleSession;
|
||||
_support = support;
|
||||
}
|
||||
@Override
|
||||
public void init() throws ServletException
|
||||
{
|
||||
if (_consoleSession == null)
|
||||
{
|
||||
_consoleSession = new WebConsoleSession();
|
||||
WebEquinoxToolsActivator.getContext().registerService(ConsoleSession.class.getName(), _consoleSession, null);
|
||||
}
|
||||
if (_support == null)
|
||||
{
|
||||
_support = new EquinoxChattingSupport(_consoleSession);
|
||||
}
|
||||
super.init();
|
||||
_consoleSession.addOnFlushListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
_consoleSession.removeOnFlushListener(this);
|
||||
}
|
||||
|
||||
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||
throws javax.servlet.ServletException ,IOException
|
||||
{
|
||||
//getServletContext().getNamedDispatcher("default").forward(request,response);
|
||||
response.sendRedirect(request.getContextPath() + request.getServletPath()
|
||||
+ (request.getPathInfo() != null ? request.getPathInfo() : "") + "/index.html");
|
||||
};
|
||||
|
||||
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
|
||||
{
|
||||
return new ChatWebSocket();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
class ChatWebSocket implements WebSocket.OnTextMessage
|
||||
{
|
||||
Connection _connection;
|
||||
String _username;
|
||||
|
||||
public void onOpen(Connection connection)
|
||||
{
|
||||
// Log.info(this+" onConnect");
|
||||
_connection=connection;
|
||||
_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(String data)
|
||||
{
|
||||
Log.info("onMessage: {}",data);
|
||||
if (data.indexOf("disconnect")>=0)
|
||||
_connection.disconnect();
|
||||
else
|
||||
{
|
||||
if (!data.endsWith(":has joined!"))
|
||||
{
|
||||
if (_username != null)
|
||||
{
|
||||
if (data.startsWith(_username + ":"))
|
||||
{
|
||||
data = data.substring(_username.length()+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
//we should not be here?
|
||||
}
|
||||
}
|
||||
_consoleSession.processCommand(data, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
_username = data.substring(0, data.length()-":has joined!".length());
|
||||
}
|
||||
// Log.info(this+" onMessage: "+data);
|
||||
onFlush();
|
||||
}
|
||||
}
|
||||
|
||||
public void onClose(int code, String message)
|
||||
{
|
||||
// Log.info(this+" onDisconnect");
|
||||
_members.remove(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called right after the flush method on the output stream has been executed.
|
||||
*/
|
||||
public void onFlush()
|
||||
{
|
||||
Queue<String> pendingConsoleOutputMessages = _support.processConsoleOutput(false, this);
|
||||
for (ChatWebSocket member : _members)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (String line : pendingConsoleOutputMessages)
|
||||
{
|
||||
member._connection.sendMessage(line);
|
||||
}
|
||||
}
|
||||
catch(IOException e)
|
||||
{
|
||||
Log.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.osgi.equinoxtools.console;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleWriterOutputStream.OnFlushListener;
|
||||
import org.eclipse.osgi.framework.console.ConsoleSession;
|
||||
|
||||
/**
|
||||
* A simple console session for equinox.
|
||||
*
|
||||
* @author hmalphettes
|
||||
*/
|
||||
public class WebConsoleSession extends ConsoleSession
|
||||
{
|
||||
|
||||
private OutputStream _out;
|
||||
private StringWriter _outWriter;
|
||||
private PrintStream _source;
|
||||
private InputStream _in;
|
||||
|
||||
public WebConsoleSession()
|
||||
{
|
||||
_outWriter = new StringWriter();
|
||||
_out = new WebConsoleWriterOutputStream(_outWriter,"UTF-8");
|
||||
try
|
||||
{
|
||||
PipedOutputStream source = new PipedOutputStream();
|
||||
PipedInputStream sink = new PipedInputStream(source);
|
||||
_in = sink;
|
||||
_source = new PrintStream(source);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
//this never happens?
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doClose()
|
||||
{
|
||||
if (_out != null) try { _out.close(); } catch (IOException e) {}
|
||||
if (_in != null) try { _in.close(); } catch (IOException ioe) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInput()
|
||||
{
|
||||
return _in;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutput()
|
||||
{
|
||||
return _out;
|
||||
}
|
||||
|
||||
/**
|
||||
* For the output we are using a string writer in fact.
|
||||
* @return
|
||||
*/
|
||||
public StringWriter getOutputAsWriter()
|
||||
{
|
||||
return _outWriter;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The print stream where commands can be written.
|
||||
*/
|
||||
public PrintStream getSource()
|
||||
{
|
||||
return _source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Issue a command on the console.
|
||||
* @param cmd
|
||||
*/
|
||||
public void issueCommand(String cmd)
|
||||
{
|
||||
if (cmd != null)
|
||||
{
|
||||
getSource().println(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param flushListener Object that is called back when the outputstream is flushed.
|
||||
*/
|
||||
public void addOnFlushListener(OnFlushListener flushListener)
|
||||
{
|
||||
((WebConsoleWriterOutputStream)_out).addOnFlushListener(flushListener);
|
||||
}
|
||||
/**
|
||||
* @param flushListener Object that is called back when the outputstream is flushed.
|
||||
*/
|
||||
public boolean removeOnFlushListener(OnFlushListener flushListener)
|
||||
{
|
||||
return ((WebConsoleWriterOutputStream)_out).removeOnFlushListener(flushListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process command comming from a web UI
|
||||
* @param cmd
|
||||
*/
|
||||
public void processCommand(String cmd, boolean wait)
|
||||
{
|
||||
cmd = cmd.trim();
|
||||
while (cmd.startsWith("osgi>"))
|
||||
{
|
||||
cmd = cmd.substring("osgi>".length()).trim();
|
||||
}
|
||||
if (cmd.equals("clear"))
|
||||
{
|
||||
clearOutput();
|
||||
}
|
||||
else
|
||||
{
|
||||
getOutputAsWriter().append(cmd + "\n");
|
||||
int originalOutputLength = getOutputAsWriter().getBuffer().length();
|
||||
issueCommand(cmd);
|
||||
|
||||
if (wait)
|
||||
{
|
||||
//it does not get uglier than this:
|
||||
//give a little time to equinox to interpret the command so we see the response
|
||||
//we could do a lot better, but we might as well use the async servlets anyways.
|
||||
int waitLoopNumber = 0;
|
||||
int lastWaitOutputLength = -1;
|
||||
while (waitLoopNumber < 10)
|
||||
{
|
||||
waitLoopNumber++;
|
||||
try
|
||||
{
|
||||
Thread.sleep(100);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
break;
|
||||
}
|
||||
int newOutputLength = getOutputAsWriter().getBuffer().length();
|
||||
if (newOutputLength > originalOutputLength && newOutputLength == lastWaitOutputLength)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lastWaitOutputLength = newOutputLength;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void clearOutput()
|
||||
{
|
||||
StringBuffer buf = getOutputAsWriter().getBuffer();
|
||||
if (buf.length() > 0) buf.delete(0,buf.length()-1);
|
||||
}
|
||||
|
||||
public List<OnFlushListener> getOnFlushListeners()
|
||||
{
|
||||
return ((WebConsoleWriterOutputStream)_out).getOnFlushListeners();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
// ========================================================================
|
||||
// Copyright (c) 2006-2011 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.osgi.equinoxtools.console;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Can be set with a listener that is called back right after the flush method is called.
|
||||
*/
|
||||
public class WebConsoleWriterOutputStream extends org.eclipse.jetty.io.WriterOutputStream
|
||||
{
|
||||
|
||||
/**
|
||||
* Interface called back after the outputstream is flushed.
|
||||
*/
|
||||
public interface OnFlushListener
|
||||
{
|
||||
/**
|
||||
* Called right after the flush method on the output stream has been executed.
|
||||
*/
|
||||
public void onFlush();
|
||||
|
||||
}
|
||||
|
||||
public interface MessageBroadcaster
|
||||
{
|
||||
public void broadcast();
|
||||
}
|
||||
|
||||
private List<OnFlushListener> _callBacks;
|
||||
|
||||
public WebConsoleWriterOutputStream(Writer writer, String encoding)
|
||||
{
|
||||
super(writer, encoding);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void flush() throws IOException
|
||||
{
|
||||
super.flush();
|
||||
if (_callBacks != null)
|
||||
{
|
||||
for (OnFlushListener listener : _callBacks)
|
||||
{
|
||||
listener.onFlush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void addOnFlushListener(OnFlushListener callback)
|
||||
{
|
||||
if (_callBacks == null)
|
||||
{
|
||||
_callBacks = new ArrayList<WebConsoleWriterOutputStream.OnFlushListener>();
|
||||
}
|
||||
if (!_callBacks.contains(callback))
|
||||
{
|
||||
_callBacks.add(callback);
|
||||
}
|
||||
}
|
||||
public synchronized boolean removeOnFlushListener(OnFlushListener callback)
|
||||
{
|
||||
if (_callBacks != null)
|
||||
{
|
||||
return _callBacks.remove(callback);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public synchronized List<OnFlushListener> getOnFlushListeners()
|
||||
{
|
||||
return _callBacks;
|
||||
}
|
||||
|
||||
}
|
|
@ -27,8 +27,8 @@
|
|||
<artifactId>servlet</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse</groupId>
|
||||
<artifactId>osgi</artifactId>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
<name>Jetty :: OSGi</name>
|
||||
<packaging>pom</packaging>
|
||||
<properties>
|
||||
<osgi-version>3.5.0.v20090520</osgi-version>
|
||||
<osgi-services-version>3.1.200-v20070605</osgi-services-version>
|
||||
<osgi-version>3.6.0.v20100517</osgi-version>
|
||||
<osgi-services-version>3.2.100.v20100503</osgi-services-version>
|
||||
<equinox-http-servlet-version>1.0.0-v20070606</equinox-http-servlet-version>
|
||||
<!--equinox-servletbridge-version>1.0.0-v20070523</equinox-servletbridge-version-->
|
||||
<jsp-2.1-glassfish-version>2.1.v20100127</jsp-2.1-glassfish-version>
|
||||
|
@ -25,6 +25,7 @@
|
|||
<module>jetty-osgi-boot-logback</module>
|
||||
<module>jetty-osgi-boot-warurl</module>
|
||||
<module>jetty-osgi-httpservice</module>
|
||||
<module>jetty-osgi-equinoxtools</module>
|
||||
<module>test-jetty-osgi</module>
|
||||
</modules>
|
||||
<build>
|
||||
|
@ -72,6 +73,16 @@
|
|||
</build>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-continuation</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-websocket</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
|
@ -108,14 +119,14 @@
|
|||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse</groupId>
|
||||
<artifactId>osgi</artifactId>
|
||||
<version>${osgi-version}</version>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<version>${osgi-services-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>services</artifactId>
|
||||
<version>${osgi-services-version}</version>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<version>${osgi-version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.equinox.http</groupId>
|
||||
|
|
|
@ -110,14 +110,14 @@
|
|||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.eclipse</groupId>
|
||||
<artifactId>osgi</artifactId>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>org.eclipse.osgi</artifactId>
|
||||
<version>${osgi-version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.osgi</groupId>
|
||||
<artifactId>services</artifactId>
|
||||
<artifactId>org.eclipse.osgi.services</artifactId>
|
||||
<version>${osgi-services-version}</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
|
|
@ -72,8 +72,8 @@ public class TestJettyOSGiBootCore
|
|||
// CoreOptions.equinox(),
|
||||
|
||||
mavenBundle().groupId( "org.mortbay.jetty" ).artifactId( "servlet-api" ).versionAsInProject().noStart(),
|
||||
mavenBundle().groupId( "org.eclipse" ).artifactId( "osgi" ).versionAsInProject().noStart(),
|
||||
mavenBundle().groupId( "org.eclipse.osgi" ).artifactId( "services" ).versionAsInProject().noStart(),
|
||||
mavenBundle().groupId( "org.eclipse.osgi" ).artifactId( "org.eclipse.osgi" ).versionAsInProject().noStart(),
|
||||
mavenBundle().groupId( "org.eclipse.osgi" ).artifactId( "org.eclipse.osgi.services" ).versionAsInProject().noStart(),
|
||||
|
||||
mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-deploy" ).versionAsInProject().noStart(),
|
||||
mavenBundle().groupId( "org.eclipse.jetty" ).artifactId( "jetty-server" ).versionAsInProject().noStart(),
|
||||
|
|
Loading…
Reference in New Issue