I'm trying Tomcat server with websocket. This is what I do:
I created 3 java files, copied from Tomcat examples. Please see the code below.
Then I build a war file and put it in webapps. But then I got this error message:
Info: WebSocket connection closed, Code: 1006
Do I miss any step to make a websocket on Tomcat?
Thanks.
1. ExamplesConfig.java
import java.util.HashSet;
import java.util.Set;
import javax.websocket.Endpoint;
import javax.websocket.server.ServerApplicationConfig;
import javax.websocket.server.ServerEndpointConfig;
public class ExamplesConfig implements ServerApplicationConfig
{
#Override
public Set<ServerEndpointConfig> getEndpointConfigs(Set<Class<? extends Endpoint>> scanned)
{
Set<ServerEndpointConfig> result = new HashSet<ServerEndpointConfig>();
System.out.println("ExamplesConfig ==========> getEndpointConfigs");
if (scanned.contains(EchoEndpoint.class))
{
result.add(ServerEndpointConfig.Builder.create(EchoEndpoint.class, "/websocket/echoProgrammatic").build());
}
return result;
}
#Override
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned)
{
// Deploy all WebSocket endpoints defined by annotations in the examples
// web application. Filter out all others to avoid issues when running
// tests on Gump
Set<Class<?>> results = new HashSet<Class<?>>();
for (Class<?> clazz : scanned)
{
if (clazz.getPackage().getName().startsWith("websocket."))
{
System.out.println("getAnnotatedEndpointClasses ===========>" + clazz);
results.add(clazz);
}
}
return results;
}
}
2. EchoEndpoint.java
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.RemoteEndpoint;
import javax.websocket.Session;
public class EchoEndpoint extends Endpoint
{
#Override
public void onOpen(Session session, EndpointConfig endpointConfig) {
RemoteEndpoint.Basic remoteEndpointBasic = session.getBasicRemote();
session.addMessageHandler(new EchoMessageHandlerText(remoteEndpointBasic));
session.addMessageHandler(new EchoMessageHandlerBinary(remoteEndpointBasic));
}
private static class EchoMessageHandlerText
implements MessageHandler.Partial<String> {
private final RemoteEndpoint.Basic remoteEndpointBasic;
private EchoMessageHandlerText(RemoteEndpoint.Basic remoteEndpointBasic) {
this.remoteEndpointBasic = remoteEndpointBasic;
}
#Override
public void onMessage(String message, boolean last) {
try {
if (remoteEndpointBasic != null) {
remoteEndpointBasic.sendText(message, last);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private static class EchoMessageHandlerBinary
implements MessageHandler.Partial<ByteBuffer> {
private final RemoteEndpoint.Basic remoteEndpointBasic;
private EchoMessageHandlerBinary(RemoteEndpoint.Basic remoteEndpointBasic) {
this.remoteEndpointBasic = remoteEndpointBasic;
}
#Override
public void onMessage(ByteBuffer message, boolean last) {
try {
if (remoteEndpointBasic != null) {
remoteEndpointBasic.sendBinary(message, last);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
3. EchoAnnotation.java
import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.OnMessage;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/websocket/echoAnnotation")
public class EchoAnnotation
{
#OnMessage
public void echoTextMessage(Session session, String msg, boolean last) {
try {
if (session.isOpen()) {
System.out.println("==========> this is my code");
session.getBasicRemote().sendText(msg, last);
}
} catch (IOException e) {
try {
session.close();
} catch (IOException e1) {
// Ignore
}
}
}
#OnMessage
public void echoBinaryMessage(Session session, ByteBuffer bb,
boolean last) {
try {
if (session.isOpen()) {
session.getBasicRemote().sendBinary(bb, last);
}
} catch (IOException e) {
try {
session.close();
} catch (IOException e1) {
// Ignore
}
}
}
/**
* Process a received pong. This is a NO-OP.
*
* #param pm Ignored.
*/
#OnMessage
public void echoPongMessage(PongMessage pm) {
// NO-OP
}
}
This example work's fine with Tomcat 7.0.x if you are running JVM version 1.7 and your web.xml use Servlet Specification version 3.0 according to Tomcat documentation.
You web.xml file should look like this :
<web-app version="3.0" ... >
Related
Here there is pseudocode about how to handle BLOB and CLOB in olingo jpa. I added the needed imports to the pseudocode:
package me;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.SQLException;
import javax.sql.rowset.serial.SerialException;
import org.apache.olingo.odata2.jpa.processor.api.OnJPAWriteContent;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
public class OnDBWriteContent implements OnJPAWriteContent {
#Override
public Blob getJPABlob(byte[] binaryData) throws ODataJPARuntimeException {
try {
return new JDBCBlob(binaryData);
} catch (SerialException e) {
ODataJPARuntimeException.throwException(ODataJPARuntimeException.INNER_EXCEPTION, e);
} catch (SQLException e) {
ODataJPARuntimeException.throwException(ODataJPARuntimeException.INNER_EXCEPTION, e);
}
return null;
}
#Override
public Clob getJPAClob(char[] characterData) throws ODataJPARuntimeException {
try {
return new JDBCClob(new String(characterData));
} catch (SQLException e) {
ODataJPARuntimeException.throwException(ODataJPARuntimeException.INNER_EXCEPTION, e);
}
return null;
}
}
the only problem is I couldn't find any implementation for JDBCBlob and JDBCClob. Any suggestion about how can I implement them or use some classes?
If You are using MySQL it requires an additional ExceptionInterceptor along with the Blob Implementation. You can have a custom implementation of ExceptionInterceptor and use it to initialise the Blob field.
The code to achieve it would be as follows
import java.sql.Blob;
import java.sql.Clob;
import java.util.Properties;
import org.apache.olingo.odata2.jpa.processor.api.OnJPAWriteContent;
import org.apache.olingo.odata2.jpa.processor.api.exception.ODataJPARuntimeException;
import com.mysql.cj.exceptions.ExceptionInterceptor;
import com.mysql.cj.log.Log;
public class CustomOnJPAWriteContent implements OnJPAWriteContent {
#Override
public Blob getJPABlob(byte[] binaryData) throws ODataJPARuntimeException {
return new com.mysql.cj.jdbc.Blob(binaryData, exceptionInterceptor);
}
#Override
public Clob getJPAClob(char[] characterData) throws ODataJPARuntimeException {
return new com.mysql.cj.jdbc.Clob(new String(characterData), exceptionInterceptor);
}
ExceptionInterceptor exceptionInterceptor = new ExceptionInterceptor() {
#Override
public Exception interceptException(Exception sqlEx) {
// TODO Auto-generated method stub
return null;
}
#Override
public ExceptionInterceptor init(Properties props, Log log) {
// TODO Auto-generated method stub
return null;
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
};
}
I'm trying to do a websocket communication with eclipse ide and when i run my code i get a NullPointerException. I've checked and the name in the getAttribute is the same as in the bean
package ws;
import java.io.IOException;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.server.ServerEndpoint;
import fundstarter.model.ConnectToRMIBean;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
#ServerEndpoint(value="/ws", configurator = HandShake.class)
public class WebSocketAnnotation {
private Session session;
private ConnectToRMIBean sessionUser;
private HttpSession httpSession;
private static final Set<WebSocketAnnotation> myConnections = new CopyOnWriteArraySet<WebSocketAnnotation>();
public WebSocketAnnotation() {
}
#OnOpen
public void start(Session session, EndpointConfig config) {
this.session = session;
this.httpSession = (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
myConnections.add(this);
this.sessionUser = (ConnectToRMIBean) httpSession.getAttribute("RMIBean");
//sendMessage("New message");
}
#OnClose
public void end() {
// clean up once the WebSocket connection is closed
myConnections.remove(this);
}
#OnMessage
public void receiveMessage(String message) {
sendMessage(message);
}
#OnError
public void handleError(Throwable t) {
t.printStackTrace();
}
private void sendMessage(String text) {
try {
System.out.println("[WebSocketAnnot]RMIBean User Id -> " + this.sessionUser.getUserID());
this.session.getBasicRemote().sendText(text);
} catch (IOException e) {
try {
this.session.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
Can anyone tell me what is my error?
I found the error. It was a typo on the modifyHandshake method on the HandShake
We are trying to create a system using Javas RMI. The problem is that a maintained list on the client cannot be accessed from the server using Java RMI. It seems that the RMI connection is handling a copy of the initialized list.
Below is a minimal example using an integer that the client increments every second until it equals 10. The server receives 0 all the time though.
Anyone have any idea what we are doing wrong?
Just run server and the client as a java application.
ServerDefaultImpl.java
package rmi;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class ServerDefaultImpl implements EIServerRemote, Runnable {
ClientRemote client;
private boolean running = true;
public ServerDefaultImpl() {
try {
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
ServerDefaultImpl server = this;
EIServerRemote stub = (EIServerRemote) UnicastRemoteObject.exportObject(server, 0);
Registry registry = LocateRegistry.getRegistry();
registry.rebind("test", stub);
} catch (RemoteException e) {
e.printStackTrace();
}
new Thread(this).start();
}
public static void main(String[] args) {
new ServerDefaultImpl();
}
#Override
public void run() {
while (true == running) {
try {
Thread.sleep(1000);
if (null != client) { //Client not connected yet.
int test = client.test();
System.out.println(test);
running = test <= 10;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public void attachClientListener(ClientRemote client) throws RemoteException {
this.client = client;
}
}
EIServerRemote.java
package rmi;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface EIServerRemote extends Remote {
void attachClientListener(ClientRemote client) throws RemoteException;
}
ClientRemote.java
package rmi;
import java.io.Serializable;
import java.rmi.Remote;
public interface ClientRemote extends Remote,Serializable {
int test();
}
ClientDefaultImpl.java
package rmi;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class ClientDefaultImpl implements Runnable,
ClientRemote {
private static final long serialVersionUID = 4846141863099303590L;
protected EIServerRemote server = null;
public int test;
public boolean running = true;
public ClientDefaultImpl(String serverName) {
test = 0;
try {
connect(serverName);
} catch (RemoteException | NotBoundException e) {
e.printStackTrace();
}
new Thread(this).start();
}
public static void main(String[] args) {
new ClientDefaultImpl("test");
}
public void connect(String serverName) throws RemoteException,
NotBoundException {
Registry registry = LocateRegistry.getRegistry();
EIServerRemote s = (EIServerRemote) registry.lookup(serverName);
server = s;
s.attachClientListener((ClientRemote) this);
}
#Override
public void run() {
while (true == running) {
try {
Thread.sleep(1000);
System.out.println(test++);
running = test <= 10;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
public int test() {
return test;
}
}
It seems that the RMI connection is handling a copy of the initialized list.
That's correct. The list isn't a remote object, so it is passed and returned via serialization.
I am trying to implement Java WebSocket api.
I am using this example for implementation.
My Client End Point Code is as below:
package com.java.webSocket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.DeploymentException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import org.glassfish.tyrus.client.ClientManager;
#ClientEndpoint
public class WordgameClientEndpoint {
private static CountDownLatch latch;
#OnOpen
public void onOpen(Session session) {
System.out.println("Connected ... " + session.getId());
}
#OnMessage
public String onMessage(String message, Session session) {
BufferedReader bufferRead = new BufferedReader(new InputStreamReader(System.in));
try {
System.out.println("session.getId():-- " + session.getId());
System.out.println("Received ...." + message);
String userInput = bufferRead.readLine();
return userInput;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
#OnClose
public void onClose(Session session, CloseReason closeReason) {
System.out.println(String.format("Session %s close because of %s", session.getId(), closeReason));
latch.countDown();
}
public static void main(String[] args) {
latch = new CountDownLatch(1);
ClientManager client = ClientManager.createClient();
try {
client.connectToServer(WordgameClientEndpoint.class, new URI("ws://localhost:8182/WbSocketDemoTest/game"));
latch.await();
} catch (DeploymentException | URISyntaxException | InterruptedException e) {
throw new RuntimeException(e);
}
}
}
WebSocketServer.java is as below:
package com.java.webSocket;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import org.glassfish.tyrus.server.Server;
public class WebSocketServer {
public static void main(String[] args) {
runServer();
}
public static void runServer() {
Server server = new Server("localhost", 8182, "/WbSocketDemoTest", WordgameServerEndpoint.class);
try {
server.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
System.out.print("Please press a key to stop the server.");
reader.readLine();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
server.stop();
}
}
}
My Server End points code is as below:
package com.java.webSocket;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.CloseReason;
import javax.websocket.CloseReason.CloseCodes;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint(value = "/game")
public class WordgameServerEndpoint {
private static final Set<WordgameServerEndpoint> connections = new CopyOnWriteArraySet<WordgameServerEndpoint>();
//private static final Set<Session> sessions = Collections.synchronizedSet(new HashSet<Session>());
private Session session;
#OnOpen
public void onOpen(Session session) {
System.out.println("Connected ... " + session.getId());
this.session = session;
connections.add(this);
try {
session.getBasicRemote().sendText("message form onOpen of server");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
#OnMessage
public void onMessage(String message, Session session) throws IOException {
switch (message) {
case "quit":
try {
session.close(new CloseReason(CloseCodes.NORMAL_CLOSURE,
"Game ended"));
} catch (IOException e) {
throw new RuntimeException(e);
}
break;
}
broadcast2(session,message);
}
private void broadcast2(Session currentSession, String message){
for(WordgameServerEndpoint current : connections){
try {
System.out.println("in broadcast current.session.getId():-- " + current.session.getId());
current.session.getBasicRemote().sendText(message);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
#OnClose
public void onClose(Session session, CloseReason closeReason) {
System.out.println(String.format("Session %s closed because of %s",
session.getId(), closeReason));
}
}
The problem is in broadcast2(Session currentSession, String message) method.
It shows all connected clients but sends message to only one client instead of all.
I want to implement this in spring, so any suggestion is highly appreciated.
I'm currently developing a system that loads classes via rmi. This system uses a classloader that communicates with the server in order to get the classes. The code is as follows.
Server:
import rocks.squareRock;
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class Server extends UnicastRemoteObject
implements RemInterface {
public Server() throws RemoteException {
super();
}
public static void main(String argv[]) {
try {
Server serv = new Server();
Naming.rebind("RockServer", serv);
} catch (Throwable t) {
t.printStackTrace();
}
}
public Class<?> getRockClass(String type) {
if (type.equals("squareRock"))
return squareRock.class;
else
return null;
}
}
Client:
import rocks.Rock;
import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
public class Client {
RemInterface reminterface = null;
RockLoader rl = null;
public Client() {
String strName = "rmi://127.0.0.1/RockServer";
try {
reminterface = (RemInterface) Naming.lookup(strName);
rl = new RockLoader(reminterface);
} catch (RemoteException e) {
e.printStackTrace();
} catch (NotBoundException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
}
loadRock("squareRock");
}
public Rock loadRock(String rock) {
try {
return (Rock) rl.loadClass(rock, false).newInstance();
} catch (Throwable t) {
return null;
}
}
}
Interface:
public interface RemInterface {
public Class<?> getRockClass(String type) throws RemoteException;
}
RockLoader:
import java.io.Serializable;
public class RockLoader extends ClassLoader implements Serializable {
private RemInterface reminterface = null;
public RockLoader(RemInterface reminterface) {
super();
this.reminterface = reminterface;
}
#Override
protected synchronized Class<?> loadClass(String className, boolean resolve)
throws ClassNotFoundException {
try {
return reminterface.getRockClass(className);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
The error I'm getting with this is (client-side):
java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
java.lang.ClassNotFoundException: SquareRock
This confuses me, as I'm not unmarshalling a SquareRock instance, but a Class. The only thought I have is that my classloader might be wrong.
It doesn't matter whether it's a Class or an object. The receiving JVM must have that class in its classpath, unless you are using the RMI codebase feature. What you are doing is basically trying to implement the codebase feature yourself. You can't do that.