I am migrating an enterprise-level application based on JBOSS EAP 7.3 using the WebSocket Servlets to IBM WebSphere Application Server 9.0.5.6 (WAS). The problem is that when I try to connecting to WebSocket endpoint it does nothing. In WebSphere, I have configured all virtual hosts and ports accordingly and my WebSocket endpoint class looks like below.
#ServerEndpoint("/WebSocketServices")
public class ClientConnectorWebSocketCore {
private static final OMSLogHandlerI logger = new Log4j2HndlAdaptor("ClientConnectorWebSocketCore");
private ClientConnectorFacadeWrapperRemote clientConnectorFacadeRemote;
private EJBServiceLocatorI ejbServiceLocatorI;
#OnOpen
public void onConnectionOpen(Session session) {
session.setMaxIdleTimeout(120000); //todo //milli seconds
getEjbServiceLocatorI();
logger.elkLog("29", LogEventsEnum.WSOCKET_SESSION_CONNECT, " Session Create:" + session.getId());
}
#OnMessage
public String onMessage(String message) {
return handleJSONRequest(message);
}
#OnClose
public void onConnectionClose(Session session) {
logger.elkLog("42", LogEventsEnum.WSOCKET_SESSION_CLOSE, " Session Close:" + session.getId());
}
#OnError
public void onConnectionError(Session session, Throwable t) {
// logger.info("LN:47", session.getId(), LogEventsEnum.WEB_SOCKET_ONERROR, "WebSocket OnException" + t.getMessage());
logger.elkLog("48", LogEventsEnum.WEB_SOCKET_ONERROR, " Session error:" + session.getId() + ", Msg:" + t.getMessage());
}
public void msgBroadCast(Session session, String msg) {
for (Session session1 : session.getOpenSessions()) {
if (session1.isOpen()) {
session1.getAsyncRemote().sendText(msg);
}
}
}
private EJBServiceLocatorI getEjbServiceLocatorI(){
if (ejbServiceLocatorI == null){
ejbServiceLocatorI =
(EJBServiceLocatorI) SpringBeanFactoryLoader.getInstance().getBeanLoader().getBean(EJBServiceLocatorI.class);
}
return ejbServiceLocatorI;
}
private ClientConnectorFacadeWrapperRemote getClientConnectFacade() {
if (clientConnectorFacadeRemote == null) {
try {
ejbServiceLocatorI = getEjbServiceLocatorI();
clientConnectorFacadeRemote =
(ClientConnectorFacadeWrapperRemote) ejbServiceLocatorI.contextLookupConnectorFacadeRemote(ClientConnectorFacadeWrapperRemote.class);
} catch (Exception e) {
logger.error("LN:66", "Error in Creating Client connector " + e.getMessage(), e);
}
}
return clientConnectorFacadeRemote;
}
private String handleJSONRequest(String jsonRequest) {
ClientConnectorFacadeWrapperRemote clientConnector = getClientConnectFacade();
String response = null;
if (clientConnector != null) {
response = clientConnector.processMessage(jsonRequest);
}
return response;
}
#OnMessage
public void pongMessage(Session session, PongMessage msg) {
msg.getApplicationData().toString();
}
public void setEjbServiceLocatorI(EJBServiceLocatorI ejbServiceLocatorI) {
this.ejbServiceLocatorI = ejbServiceLocatorI;
}
}
Any advice is highly appreciated.
If your requests flow through a web server with WebSphere plugin, you need to ensure plugin is at level 9.0.5.6 or higher due to bug (PH27966) which can block websocket traffic.
Related
I have a test which should connect and subscribe multiple users to a websocket endpoint. The test connects the user but doesn't subscribe the users.
This is how I try to connect the users:
List<ConsumerStompSessionHandler> consumers = new ArrayList<>();
for (int i = 0; i < NUMBER_OF_USERS; i++) {
consumers.add(new ConsumerStompSessionHandler(BROADCAST_MESSAGE_COUNT, connectLatch, subscribeLatch,
messageLatch, disconnectLatch, failure));
stompClient.connect(stompUrl, consumers.get(i), host, port);
}
if (failure.get() != null) {
throw new AssertionError("Test failed", failure.get());
}
if (!connectLatch.await(5000, TimeUnit.MILLISECONDS)) {
fail("Not all users connected, remaining: " + connectLatch.getCount());
}
if (!subscribeLatch.await(5000, TimeUnit.MILLISECONDS)) {
fail("Not all users subscribed, remaining: " +
subscribeLatch.getCount());
}
stopWatch.stop();
logger.debug("Finished: " + stopWatch.getLastTaskTimeMillis() + " millis");
The afterConnect method, which I think it is not executed:
#Override
public void afterConnected(final StompSession session, StompHeaders connectedHeaders) {
this.connectLatch.countDown();
session.setAutoReceipt(true);
session.subscribe("/topic/greetings", new StompFrameHandler() {
public Type getPayloadType(StompHeaders headers) {
return String.class;
}
public void handleFrame(StompHeaders headers, Object payload) {
if (messageCount.incrementAndGet() == expectedMessageCount) {
messageLatch.countDown();
disconnectLatch.countDown();
session.disconnect();
}
}
}).addReceiptTask(new Runnable() {
#Override
public void run() {
subscribeLatch.countDown();
}
});
}
I also tried to put a Thread.sleep(5000) in the for after the connection but it didn't work.
Can anyone tell me why it doesn't subscribe.
The subscribe url is the same from #Controller -> #SendTo("/topic/greetings").
I'm trying to make a two page website and need separate ServerEndpoint for each. My java code structure for two classes looks like,
#ServerEndpoint ("/action")
public class MonitorWebSocket {
#OnOpen
public void open (Session session) throws IOException {
System.out.println("Connection Opened");
session.getBasicRemote().sendText("MonitorWebSocket");
}
#OnClose
public void close () {
}
#OnError
public void err (Throwable error) {
System.out.println("Error: " + error);
}
}
and
#ServerEndpoint ("/configData")
public class ConfigDataWebSocket {
#OnOpen
public void open (Session session) throws IOException {
System.out.println("Config Connection Open");
session.getBasicRemote().sendText("ConfigDataWebSocket");
}
#OnError
public void err (Throwable er) {
System.out.println("Error: " + er);
}
#OnClose
public void close () {
}
}
And my javascripts looks as follows.
For page "index.html"
var ws = new WebSocket ("ws://localhost:8080/MultipleEndpoints/action");
ws.open = function (event) {
document.getElementById("read").innerText = event.data;
};
ws.onerror = function (event) {
console.log(event.data);
};
and for page "config.html"
var ws1 = new WebSocket ("ws://localhost:8080/MultipleEndpoints/configData");
ws1.onopen = function (event) {
document.getElementById("a").innerText = event.data;
};
ws1.onerror = function (event) {
console.log(event.data);
};
Now when I run this code, I receive following error in Browser log,
WebSocket connection to 'ws://localhost:8080/MultipleEndpoints/action' failed: Unexpected response code: 404
WebSocket connection to 'ws://localhost:8080/MultipleEndpoints/configData' failed: Unexpected response code: 404
But when I get rid of ConfigDataWebSocket class completely, my MonitorWebSocket works just fine and my div gets updated by the value sent from java class.
I have been over through my code a few times and cannot spot the mistake I'm making.
Thanks!
I am trying to connect with secure websocket connection wss:// in android using org.java_websocket.client.WebSocketClient API, but unable to connect with https. However it is working fine with ws://.. Here is my code.
private void connect(String websocketEndPointUrl) throws Exception {
URI uri;
try {
websocketEndPointUrl="wss://echo.websocket.org:443";
Log.i(TAG, " WSURL: " + websocketEndPointUrl);
uri = new URI(websocketEndPointUrl);
} catch (URISyntaxException e) {
Log.e(TAG, e.getMessage());
return;
}
mWebSocketClient = new WebSocketClient(uri,new Draft_17()) {
#Override
public void onOpen(ServerHandshake serverHandshake) {
Log.i("Websocket", "Opened");
}
#Override
public void onMessage(String s) {
//final String message =s;
}
#Override
public void onClose(int i, String s, boolean b) {
Log.i("Websocket", "Closed " + s);
}
#Override
public void onError(Exception e) {
Log.i("Websocket", "Error " + e.getMessage());
}
};
mWebSocketClient.connect();
}
i am using online test websocket url:
ws://echo.websocket.org (port 80) // working with that
wss://echo.websocket.org (port 443)
As per my observation there is no need of certificate required in my code. Can anyone suggest me what is a reason and how i can fix this.
Find a solution. I don't know why this is not a part of the documentation. You just need to set setWebSocketFactory after WebSocketClient initialization and before the .connect() method
mWebSocketClient = new WebSocketClient(uri,new Draft_17())
{
#Override
public void onOpen(ServerHandshake serverHandshake) {
Log.i("Websocket", "Opened");
}
#Override
public void onMessage(String s) {
//final String message =s;
}
#Override
public void onClose(int i, String s, boolean b) {
Log.i("Websocket", "Closed " + s);
}
#Override
public void onError(Exception e) {
Log.i("Websocket", "Error " + e.getMessage());
}
};
if (websocketEndPointUrl.indexOf("wss") == 0)
{
try {
SSLContext sslContext = SSLContext.getDefault();
mWebSocketClient.setWebSocketFactory(new DefaultSSLWebSocketClientFactory(sslContext));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
mWebSocketClient.connect();
In my case, I need two thing to fix "Trust anchor for certification path not found" error when websocket connect():
HttpsURLConnection requests that particular wss host (but in https:// form) successfully at least once.
Then dosetWebSocketFactory() as mentioned in accepted answer. Which this extra method (plus new Draft_17()) only appeared in library version org.java-websocket:Java-WebSocket:1.3.0, not 1.4.0.
Note that don't test with allowAllSSL() like this answer do, which affect the two thing above not working.
I currently have a problem while working with Mina. I am able to create a NIOAcceptor and Connector and connect the client to the server. Upon session being created in the Server, it sends the handshake packet which in turn validates and sends back validation to the server to see if files are up-to-date, etc. The server receives this validation and correctly deciphers the packet and sends the packet to the Client to display the game window. However, after this initial connection, I can no longer send packets to the server via the Client.
ServerHandler:
#Override
public void sessionOpened(IoSession session) {
log.info("[Login] to [" + GameConstants.GAME_NAME + ": IoSession with {} opened", session.getRemoteAddress());
Client c = new Client(session);
connectedClients.add(session.getRemoteAddress().toString());
session.setAttribute(Client.KEY, c);
c.write(PacketCreator.getHandshake());
// c.write(PacketCreator.getPing());
}
#Override
public void messageReceived(IoSession session, Object message) {
PacketReader reader = new PacketReader((byte[]) message);
Client c = (Client) session.getAttribute(Client.KEY);
short header = reader.readShort();
PacketHandler handler = PacketProcessor.getHandler(header);
System.out.println("Received opcode: 0x" + Integer.toHexString(header).toUpperCase());
if (handler != null) {
handler.handlePacket(reader, c);
} else {
log.info("Received opcode: 0x" + Integer.toHexString(header).toUpperCase() + " with no handler.");
}
}
#Override
public void exceptionCaught(IoSession session, Throwable cause) {
System.out.println("session error");
}
#Override
public void sessionClosed(IoSession session) throws Exception {
System.out.println("Session closing: " + session.getRemoteAddress().toString());
connectedClients.remove(session.getRemoteAddress().toString());
Client c = (Client) session.getAttribute(Client.KEY);
if (c != null) {
c.disconnect();
c.dispose();
} else {
log.warn("Client is null in sessionClosed for ip {} when it shouldn't be", session.getRemoteAddress());
}
super.sessionClosed(session);
}
ClientHandler:
#Override
public void sessionOpened(IoSession session) {
System.out.println("Session opened: " + session);
Server s = new Server(session);
session.setAttribute(Server.KEY, s);
s.write(PacketCreator.getPong());
}
#Override
public void messageReceived(IoSession session, Object message) {
PacketReader reader = new PacketReader((byte[]) message);
Server s = (Server) session.getAttribute(Server.KEY);
short header = reader.readShort();
PacketHandler handler = PacketProcessor.getHandler(header);
if (handler != null) {
handler.handlePacket(reader, s);
} else {
log.info("Received opcode: 0x" + Integer.toHexString(header).toUpperCase() + " with no handler.");
}
}
#Override
public void exceptionCaught(IoSession session, Throwable cause) {
System.out.println("session error");
log.error("Exception caught in Server Handler: ", cause);
}
#Override
public void sessionClosed(IoSession session) throws Exception {
// TODO
System.out.println("session closed");
super.sessionClosed(session);
}
Client (NIOConnection class):
public static void connectToServer() throws Throwable {
NioSocketConnector connector = new NioSocketConnector();
connector.setConnectTimeoutMillis(1000 * 30); // 30 seconds
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
connector.setHandler(new ClientHandler());
IoSession session;
long startTime = System.currentTimeMillis();
for (;;) {
try {
ConnectFuture future = connector.connect(new InetSocketAddress("127.0.0.1", 9494)); // 24.7.142.74
future.awaitUninterruptibly();
session = future.getSession();
break;
} catch (RuntimeIoException e) {
log.error("Failed to connect", e);
Thread.sleep(5000);
}
}
session.getCloseFuture().awaitUninterruptibly();
}
Server (NIOAcceptor class):
private static void initializeLoginServer() {
PacketProcessor.registerHandlers();
acceptor = new NioSocketAcceptor();
// acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new TextLineCodecFactory(Charset.forName("UTF-8"))));// TODO: encoding/decoding packets
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(new ObjectSerializationCodecFactory()));
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 10);
acceptor.getSessionConfig().setTcpNoDelay(true);
acceptor.setHandler(new ServerHandler(1));
try {
acceptor.bind(new InetSocketAddress(GameConstants.SERVER_PORT));
} catch (Exception e) {
log.error("Could not bind. ", e);
}
log.info("Login Server: Listening on port " + GameConstants.SERVER_PORT);
}
What I want?
I am trying to write an application where client sends a query and based on the query server gets twitter-stream and pushes to client.
What I have?
I have a simple structure in place where client can connect to server and server responds back
TweetStreamServer
package com.self.tweetstream;
import javax.websocket.OnMessage;
import javax.websocket.server.ServerEndpoint;
#ServerEndpoint("/tweets")
public class TweetStreamServer {
#OnMessage
public String tweets(final String message) {
return message;
}
}
TweetStreamClient
#ClientEndpoint
public class TweetStreamClient {
public static CountDownLatch latch;
public static String response;
#OnOpen
public void onOpen(Session session) {
try{
session.getBasicRemote().sendText("Hello World!");
} catch (IOException e) {
e.printStackTrace();
}
}
#OnMessage
public void printTweets(final String tweet) {
System.out.println("Tweet:" + tweet);
response = tweet;
latch.countDown();
}
}
TweetStreamTest
#Test
public void test() throws URISyntaxException, IOException, DeploymentException, InterruptedException {
System.out.println("URI: " + getEndpointUrl());
TweetStreamClient.latch = new CountDownLatch(1);
Session session = connectToServer(TweetStreamClient.class, "tweets");
assertNotNull(session);
assertTrue(TweetStreamClient.latch.await(10, TimeUnit.SECONDS));
assertEquals("Hello World!", TweetStreamClient.response);
}
Question
I am confused how can I now send continuous tweets that I receive from Twitter because my server method as per API is
#OnMessage
public String tweets(final String message) {
return message;
}
This means it expects a message in order return anything.
How can I send on-coming data from Twitter send to client?
This worked for me
#OnMessage
public void tweets(final String message, Session client) throws IOException, InterruptedException {
int i = 0;
for (Session peer : client.getOpenSessions()) {
while (i < 10) {
System.out.println("sending ...");
peer.getBasicRemote().sendText("Hello");
Thread.sleep(2000);
i++;
}
}
}
Thanks to Arun Gupta for helping through his tweets :)