I'm trying to make a custom "http" sever embedding a Jetty (verion 9) into my application.
The problem I'm facing right now is that Websocket Events are not being called.
This is what I have to so far (relevant parts):
SocketServer:
public class SocketServer
{
public static void main(String[] args) throws Exception
{
Server server = new Server(9091);
HandlerCollection handlerCollection = new HandlerCollection();
ServletContextHandler sch = new ServletContextHandler();
sch.addServlet(new ServletHolder(new RandomWebSocketServlet()), "");
handlerCollection.addHandler(sch);
server.setHandler(handlerCollection);
server.start();
server.join();
}
}
RandomWebSocketServlet:
public class RandomWebSocketServlet extends WebSocketServlet {
private static final long serialVersionUID = -1134228059326523215L;
public RandomWebSocketServlet() {
}
#Override
public void configure(WebSocketServletFactory factory) {
factory.setCreator(new AdvancedSocketCreator());
}
}
AdvancedSocketCreator:
public class AdvancedSocketCreator implements WebSocketCreator {
public AdvancedSocketCreator() {
}
#Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp) {
return new Handler();
}
}
Handler:
#WebSocket
public class Handler {
protected Session session = null;
public Handler() {
}
#OnWebSocketConnect
public void onConnect(Session session) {
Log.log("WebSocket connected to client: "+session.getRemoteAddress().getHostName()+":"+session.getRemoteAddress().getPort());
this.session = session;
}
#OnWebSocketError
public void onError(Throwable t) {
Log.log("WebSocket error");
}
#OnWebSocketMessage
public void onMessage(String message) {
Log.log("Message: "+message);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
Log.log("WebSocket closed: "+statusCode+" - "+reason);
}
}
When I try to open a connection (using telnet, for instance), the #OnWebSocketConnect onConnect method is not being called.
I tried many ways, following many internet tutorials... but with no success.
Any help?
Related
I am using org.glassfish.tyrus.server.Server and javax.websocket. After starting the server I want to call the broadcast method. Is there any way to interact with the ServerEndpoint class from the other classes in the program while the server is running?
The Server class:
public class WebsocketServer{
private int port;
private Server server;
public WebsocketServer(int port) {
this.port = port;
server = new Server("localhost", this.port, "/websockets", ExampleServerEndpoint.class);
}
public void startServer() throws Exception{
server.start();
}
public void stopServer() throws Exception{
server.stop();
}
}
The Server Endpoint class:
#ServerEndpoint( value = "/exmple")
public class ExampleServerEndpoint {
#OnOpen
public void onOpen(Session session) {}
#OnMessage
public void onMessage(String message, Session session) {}
#OnClose
public void onClose(Session session, CloseReason closeReason) {}
#OnError
public void onError(Session session) {}
public void broadcast() {
//Broadcast a message
}
}
I'm new to Jerry, and trying to implement WebSocket Client on Jetty9.
I saw an example on Jetty8.
org.eclipse.jetty.websocket Class WebSocketClient
http://archive.eclipse.org/jetty/8.0.0.v20110901/apidocs/org/eclipse/jetty/websocket/WebSocketClient.html
to create a new instance of WebSocketClient is :
WebSocketClientFactory factory = new WebSocketClientFactory();
factory.start();
WebSocketClient client = factory.newWebSocketClient();
// Configure the client
WebSocket.Connection connection = client.open(new
URI("ws://127.0.0.1:8080/"), new WebSocket.OnTextMessage()
{
public void onOpen(Connection connection)
{
// open notification
}
public void onClose(int closeCode, String message)
{
// close notification
}
public void onMessage(String data)
{
// handle incoming message
}
}).get(5, TimeUnit.SECONDS);
connection.sendMessage("Hello World");
However, I've never seen a document for Jetty9 for this.
So far, referring to
org.eclipse.jetty.websocket.common
Interface SessionFactory
//----------------------------------------------
WebSocketSession createSession(URI requestURI,
EventDriver websocket,
LogicalConnection connection)
//----------------------------------------------
I've tried
private WebSocketSessionFactory factory = new WebSocketSessionFactory();
try
{
WebSocketSession session = factory.createSession(uri,
eventDriver, connection);
RemoteEndpoint ep = session.getRemote();
}
catch (Exception ex)
{
System.out.println("=ERROR= " + ex);
//=ERROR= java.lang.NullPointerException
}
private EventDriver eventDriver = new EventDriver()
{
#Override
public WebSocketPolicy getPolicy()
{
return null;
}
//......................................
#Override
public void incomingFrame(Frame frame)
{
}
};
private LogicalConnection connection = new LogicalConnection()
{
#Override
public void close()
{
}
//...............................
#Override
public void resume()
{
}
};
but I've encounter java.lang.NullPointerException
How do we implement Jetty9 WebSocket Client ??
Thanks for your advise.
Hope this helpful: EventClient.java
I am writing a simple routing application. The idea is that I have servers or source nodes that receive transient clients connections that last for a period of x time. The messages received are decoded and then sent to a corresponding sink node or client that is/are already open depending on the details of the message. The Router class registers all channels and attemps to save them in maps so that it can filter and worj out the destination of the message. Once I get the destination, I should then be able to pick the actual sink node (could be of transient of persistent nature depending on the configurations) and send data to that channel wait for a response and then send it back to the originator. I'd like to know first if my implementation using netty is in the right direction ? and how can I pass a message received from any of the servers and send it to any of the clients and respond back to the originating source node ?
Below is my source code : It will / should give you an idea of what I am up to :Kindly use code examples in your explanation .
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelFactory;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.ChannelStateEvent;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.ChildChannelStateEvent;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
/*
* #author Kimathi
*/
public class Service {
private Nodes nodes;
public void start(){
nodes = new Nodes();
nodes.addSourceNodes(new SourceNodes()).
addSinkNodes(new SinkNodes()).
addConfigurations(new Configurations()).
boot();
}
public void stop(){
nodes.stop();
}
public static void main(String [] args){
new Service().start();
}
}
class Nodes {
private SourceNodes sourcenodes;
private SinkNodes sinknodes ;
private Configurations configurations;
public Nodes addConfigurations(Configurations configurations){
this.configurations = configurations;
return this;
}
public Nodes addSourceNodes(SourceNodes sourcenodes){
this.sourcenodes = sourcenodes;
return this;
}
public Nodes addSinkNodes(SinkNodes sinknodes){
this.sinknodes = sinknodes;
return this;
}
public void boot(){
Router router = new Router(configurations);
sourcenodes.addPort(8000).
addPort(8001).
addPort(8002);
sourcenodes.addRouter(router);
sourcenodes.boot() ;
sinknodes.addRemoteAddress("127.0.0.1", 6000).
addRemoteAddress("127.0.0.1", 6001).
addRemoteAddress("127.0.0.1", 6002);
sinknodes.addRouter(router);
sinknodes.boot();
}
public void stop(){
sourcenodes.stop();
sinknodes.stop();
}
}
final class SourceNodes implements Bootable , Routable {
private List <Integer> ports = new ArrayList();
private ServerBootstrap serverbootstrap;
private Router router;
#Override
public void addRouter(final Router router){
this.router = router;
}
public SourceNodes addPort(int port){
this.ports.add(port);
return this;
}
#Override
public void boot(){
this.initBootStrap();
this.serverbootstrap.setOption("child.tcpNoDelay", true);
this.serverbootstrap.setOption("child.keepAlive", true);
this.serverbootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new SourceHandler(router));
}
});
for(int port:this.ports){
this.serverbootstrap.bind(new InetSocketAddress(port));
}
}
#Override
public void stop(){
this.serverbootstrap.releaseExternalResources();
}
private void initBootStrap(){
ChannelFactory factory = new NioServerSocketChannelFactory( Executors.newCachedThreadPool(),Executors.newCachedThreadPool());
this.serverbootstrap = new ServerBootstrap(factory);
}
}
final class SinkNodes implements Bootable , Routable {
private List<SinkAddress> addresses= new ArrayList();
private ClientBootstrap clientbootstrap;
private Router router;
#Override
public void addRouter(final Router router){
this.router = router;
}
public SinkNodes addRemoteAddress(String hostAddress,int port){
this.addresses.add(new SinkAddress(hostAddress,port));
return this;
}
#Override
public void boot(){
this.initBootStrap();
this.clientbootstrap.setOption("tcpNoDelay", true);
this.clientbootstrap.setOption("keepAlive", true);
this.clientbootstrap.setPipelineFactory(new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
return Channels.pipeline(new SinkHandler(router));
}
});
for(SinkAddress address:this.addresses){
this.clientbootstrap.connect(new InetSocketAddress(address.hostAddress(),address.port()));
}
}
#Override
public void stop(){
this.clientbootstrap.releaseExternalResources();
}
private void initBootStrap(){
ChannelFactory factory = new NioClientSocketChannelFactory( Executors.newCachedThreadPool(),Executors.newCachedThreadPool());
this.clientbootstrap = new ClientBootstrap(factory);
}
private class SinkAddress {
private final String hostAddress;
private final int port;
public SinkAddress(String hostAddress, int port) {
this.hostAddress = hostAddress;
this.port = port;
}
public String hostAddress() { return this.hostAddress; }
public int port() { return this.port; }
}
}
class SourceHandler extends SimpleChannelHandler {
private Router router;
public SourceHandler(Router router){
this.router = router;
}
#Override
public void childChannelOpen(ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception {
System.out.println("child is opened");
}
#Override
public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("child is closed");
}
#Override
public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("Server is opened");
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println(e.getCause());
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println("channel received message");
}
}
class SinkHandler extends SimpleChannelHandler {
private Router router;
public SinkHandler(Router router){
this.router = router;
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
System.out.println("Channel is connected");
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println(e.getCause());
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
System.out.println("channel received message");
}
}
final class Router {
private Configurations configurations;
private Map sourcenodes = new HashMap();
private Map Sinknodes = new HashMap();
public Router(){}
public Router(Configurations configurations){
this.configurations = configurations;
}
public synchronized boolean submitSource(ChannelHandlerContext ctx , MessageEvent e){
boolean responded = false;
return responded;
}
public synchronized boolean submitSink(ChannelHandlerContext ctx , MessageEvent e){
boolean responded = false;
return responded;
}
}
final class Configurations {
public Configurations(){}
}
interface Bootable {
public abstract void boot();
public abstract void stop();
}
interface Routable {
public abstract void addRouter(Router router);
}
The idea seems reasonable.
The source channel handler can just write to the corresponding sink channel, using Channel#write(...), and vice versa on the reply.
Of course, you also need a way to correlate the source channel with the reply, and how that is best done depends an the nature of the protocol. The best alternative, if possible, is to somehow encode the source channel id in the message to the sink channel (and also in the reply, of course).
If that is not possible, you will somehow have to maintain the correlation. A FIFO queue per sink channel may be appropriate if the replies are guaranteed to pair up with the sent requests.
Applet freezes when I use Netty 4.0. If I use the Netty 3, the Applet starts correctly. My code is very simple, and I can not understand where the mistake.
public class Applet extends JApplet
{
#Override
public void init()
{
try {
new DiscardServer(1020).run();
} catch (Exception ex) {
Logger.getLogger(Applet.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class DiscardServer {
private final int port;
public DiscardServer(int port) {
this.port = port;
}
public void run() throws Exception {
ServerBootstrap b = new ServerBootstrap();
try {
b.group(new NioEventLoopGroup(), new NioEventLoopGroup()).channel(NioServerSocketChannel.class).localAddress(port)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new DiscardServerHandler());
}
});
ChannelFuture f = b.bind().sync();
f.channel().closeFuture().sync();
} finally {
b.shutdown();
}
}
}
public class DiscardServerHandler extends ChannelInboundByteHandlerAdapter {
private static final Logger logger = Logger.getLogger(DiscardServerHandler.class.getName());
#Override
public void inboundBufferUpdated(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
System.out.println("Message " + new String(in.array()));
in.clear();
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.log(Level.WARNING,"Unexpected exception from downstream.",cause);
ctx.close();
}
}
Last post in the console:
network: Cache entry not found [url: file:/D:/java/Applet/dist/lib/netty-4.0.0.Alpha6-20121021.180934-2.jar, version: null]
basic: Plugin2ClassLoader.getPermissions CeilingPolicy allPerms
If I remove the line:
ChannelFuture f = b.bind().sync();
, the applet starts, but the DiscardServer is not working.
I have some trouble getting application-to-application communication via web sockets (that is without a browser to work). Since this does not seem to be the most usual application of web sockets, I wonder if anybody has any experience doing this.
Why do I want to use web sockets?
Because of firewall issues I need to go through port 80/8080 (and I need to continue to handle some other HTTP communication, so I can't just use plain TCP/IP socket communication).
How did I try to make this work?
I'm using Jetty 8.0 both for the server and for the client. My server code:
public class WebSocketTestServlet extends WebSocketServlet {
public WebSocket doWebSocketConnect(HttpServletRequest arg0, String arg1) {
return new TestWebSocket();
}
class TestWebSocket implements WebSocket, WebSocket.OnTextMessage
{
public void onClose(int arg0, String arg1) {
}
public void onOpen(Connection arg0) {
}
public void onMessage(String messageText) {
}
}
}
My client code:
public class MyWebSocketClient{
MyWebSocketClient() throws IOException
{
WebSocketClientFactory factory = new WebSocketClientFactory();
try {
factory.start();
} catch (Exception e1) {
e1.printStackTrace();
}
WebSocketClient client = factory.newWebSocketClient();
WebSocket.Connection connection = client.open(new URI("ws://myserver:8080/testws"), new WebSocket.OnTextMessage()
{
public void onOpen(Connection connection)
{
}
public void onClose(int closeCode, String message)
{
}
public void onMessage(String data)
{
}
}).get(50, TimeUnit.SECONDS)
}
What problem do I see?
A ProtocolException
Caused by: java.net.ProtocolException: Bad response status 302 Found
at org.eclipse.jetty.websocket.WebSocketClientFactory$HandshakeConnection.closed(WebSocketClientFactory.java:423)
at org.eclipse.jetty.websocket.WebSocketClientFactory$WebSocketClientSelector.endPointClosed(WebSocketClientFactory.java:235)
at org.eclipse.jetty.io.nio.SelectorManager$SelectSet.destroyEndPoint(SelectorManager.java:948)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.doUpdateKey(SelectChannelEndPoint.java:523)
at org.eclipse.jetty.io.nio.SelectorManager$SelectSet.doSelect(SelectorManager.java:469)
at org.eclipse.jetty.io.nio.SelectorManager$1.run(SelectorManager.java:283)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:598)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:533)
at java.lang.Thread.run(Thread.java:619)
Any idea why this is not working?
Try to add "/" at the end of your address in the client's code:
"ws://myserver:8080/testws/"
It just fixed the issue for me.
Trying to do something similar to allow WS calls to an embedded Jetty REST API...here's my echo test code (Jetty 7), HTH
public class myApiSocketServlet extends WebSocketServlet
{
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException ,IOException
{
OutputStream responseBody = response.getOutputStream();
responseBody.write("Socket API".getBytes());
responseBody.close();
}
public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol)
{
return new APIWebSocket();
}
class APIWebSocket implements WebSocket, WebSocket.OnTextMessage
{
Connection connection;
#Override
public void onClose(int arg0, String arg1)
{
}
#Override
public void onOpen(Connection c)
{
connection = c;
}
#Override
public void onMessage(String msg)
{
try
{
this.connection.sendMessage("I received: " + msg);
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
}