Tomcat clientendpoint websocket keeps closing - java

I have the following clientendpoint class for a websocket in tomcat 7.0.53. It is based off of this example on a website https://blog.openshift.com/how-to-build-java-websocket-applications-using-the-jsr-356-api/
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
#ClientEndpoint
public class connect {
private static ArrayList<Session> sessionList = new ArrayList<Session>();
public connect(URI endpointURI) throws DeploymentException, IOException
{
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(this, endpointURI);
}
#OnOpen
public void onOpen(Session session) throws IOException
{
sessionList.add(session);
System.out.println(session.getId());
session.getBasicRemote().sendText("hello");
}
public void sendMessage(String message) throws IOException
{
for(Session session : sessionList){
//asynchronous communication
session.getBasicRemote().sendText(message);
}
}
#OnClose
public void onClose(Session session){
sessionList.remove(session);
System.out.println("here");
}
#OnError
public void onError(Throwable t, Session session){
System.out.println("tedt");
}
}
I then have the following code to start the client endpoint
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import javax.websocket.DeploymentException;
public class test {
public static void main(String[] args) throws DeploymentException, IOException, URISyntaxException {
// TODO Auto-generated method stub
connect connect = new connect(new URI("ws://localhost:8080/example/talk"));
connect.sendMessage("now");
}
}
The client does successfully connect to the websocket server, however then it gets disconnected right away when I try to send a message or do anything, I know this since the onError function is being called when I try to send a message from the onOpen function. Why is the websocket getting closed immediately after it is connected to the server?

You are being disconnected because your main thread in your client application is ending. After you send "now", your program simply exits. If you want to do anything else (like wait for a response from the server, for instance), then you'll have to prevent the main thread from exiting. Try something like this at the end of your main method:
System.in.read();
This will cause your process to sit and wait for input from standard input. Simply wait for your test to complete and then press ENTER on the command-line to terminate the client.
You will, of course, want to register a handler for receiving messages back from the server to the client. Right now, you can only send messages from the client to the server.

Related

Cannot read email body with Spring: javax.mail.FolderClosedException

I'm trying to listen my Gmail inbox for incoming mails. Every time new mail arrives, I want to see it's subject and content.
So far, I have this:
import java.io.IOException;
import javax.mail.BodyPart;
import javax.mail.Folder;
import javax.mail.internet.ContentType;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.mail.util.MimeMessageParser;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.channel.DirectChannel;
import org.springframework.integration.mail.transformer.MailToStringTransformer;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHandler;
import org.springframework.messaging.MessagingException;
public class GmailInboundImapIdleAdapterTestApp {
private static Log logger = LogFactory.getLog(GmailInboundImapIdleAdapterTestApp.class);
public static void main (String[] args) throws Exception {
#SuppressWarnings("resource")
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("/META-INF/spring/integration/gmail-imap-idle-config.xml");
DirectChannel inputChannel = ac.getBean("receiveChannel", DirectChannel.class);
inputChannel.subscribe(new MessageHandler() {
public void handleMessage(Message<?> message){
MimeMessage mm = (MimeMessage) message.getPayload();
try {
System.out.println("Subject: "+mm.getSubject());
System.out.println("Body: "+readPlainContent(mm));
}
catch (javax.mail.MessagingException e) {
System.out.println("MessagingException: "+e.getMessage());
e.printStackTrace();
}
catch (Exception e) {
System.out.println("Exception: "+e.getMessage());
e.printStackTrace();
}
}
});
}
private static String readHtmlContent(MimeMessage message) throws Exception {
return new MimeMessageParser(message).parse().getHtmlContent();
}
private static String readPlainContent(MimeMessage message) throws Exception {
return new MimeMessageParser(message).parse().getPlainContent();
}
}
It can read the mail subject correctly. But no luck with mail body.javax.mail.FolderClosedException hit me. How to fix this?
As Gary said: simple-content="true" or since recently autoCloseFolder = false: https://docs.spring.io/spring-integration/docs/5.2.0.RELEASE/reference/html/mail.html#mail-inbound
Starting with version 5.2, the autoCloseFolder option is provided on the mail receiver. Setting it to false doesn’t close the folder automatically after a fetch, but instead an IntegrationMessageHeaderAccessor.CLOSEABLE_RESOURCE header (see MessageHeaderAccessor API for more information) is populated into every message to producer from the channel adapter. It is the target application’s responsibility to call the close() on this header whenever it is necessary in the downstream flow:

Java WebSocket session resulting to null after onOpen

I am using websockets for the first time on a javafx project, when I start the program the session is set to the local variable session, but after when I call the sendMessage function the session is back to null. Below please find my client class
package myclient;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javax.websocket.ClientEndpoint;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
#ClientEndpoint
public class Client extends Application {
private static final Logger LOGGER = Logger.getLogger(Client.class.getName());
private Session session;
#OnOpen
public void onOpen(Session session){
this.session = session;
System.out.println("Opened Session " + this.session);
}
#OnClose
public void onClose(){
System.out.println("Closed Session " + this.session);
}
#OnMessage
public void onMessage(String msg){
System.out.println("Websocket message received! " + msg);
}
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLClient.fxml"));
Scene scene = new Scene(root);
connectToWebSocket();
stage.setScene(scene);
stage.show();
}
private void connectToWebSocket() {
System.out.println("Client WebSocket initialized>> " + this.session);
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
try {
URI uri = URI.create("ws://localhost:8080/Server/endpoint");
container.connectToServer(this, uri);
}
catch (DeploymentException | IOException ex) {
LOGGER.log(Level.SEVERE, null, ex);
System.exit(-1);
}
}
public void sendMessage(String message) throws IOException{
if(this.session != null){
System.out.println(message + ", " + this.session);
this.session.getBasicRemote().sendText(message);
}
else {
System.out.println("Session is null");
}
}
public static void main(String[] args) {
launch(args);
}
}
Any suggestions?
Thanks in advance
I think I now do know the answer to this.
You are probably using tomcat or some other server for this. When you see "tomcat" in this answer, please insert the name of your actually used server.
When a connection to your websocket is opened, tomcat will create an instance of the websocket (your Client) class by itself. This means, the onOpen-Method will be called and it will look as if it was you who created the instance, who opened the connection, when really you did not. Tomcat did.
This in turn means, that when you call sendMessage on your Client instance, the session will be null, because this object never connected anywhere.
Oh, and you don't have access to the connected instance that was created by tomcat.
One way of fixing this would be to do all the work inside the onOpen-Method, however that is not practical. You may want to put the work in another method and call it from onOpen. That way, the instance created by tomcat will do the necessary work.
In my project I needed to poll on an MQTT-Topic and render the data on a website (university assignment). I did the polling in a separate class, resulting in hard to debug errors whenever trying to send received data with my sendMessage-method.
I hope this answer does clear this up a little, if not for you, maybe at least for future generations having the same university assignment...

How to listen and generate respones for client in server in java?

This is my server side code in java listening on port 1880 and making http client request from browser/client.java code in localhost which gives connection refused error.I copied that server code from a webpage.I am not sure what exactly this code is doing.
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerHandlingHttpRequest {
public void start() throws IOException
{
InetSocketAddress addr=new InetSocketAddress(1880);
System.out.println(addr.getPort());
System.out.println(addr.getAddress());
System.out.println(addr.getHostName());
System.out.println(addr.toString());
HttpServer server=HttpServer.create(addr,0);
server.createContext("/", new MyHandler());
server.setExecutor(null);
server.start();
System.out.println("Server Listening");
System.out.println(server.getAddress());
server.stop(60);
}
class MyHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
System.out.println("Request Arrived");
String response = "This is the response";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
public static void main(String[] args) throws IOException
{
ServerHandlingHttpRequest w=new ServerHandlingHttpRequest();
w.start();
}
}
That code simply starts listening to the port that you have specified, as an HTTP listener. Which means, any HTTP Request that might come into that port will be intercepted by your program. And when it intercepts, it looks for the context path that you have configured to handle the response to the request.
So, when you run this program, it starts listening at port 1880. When a URL http://localhost:1880/ is hit, it will be intercepted by the handler, MyHandler. The response will be written to the OutputStream which will send back the request back to the client.
One of the problems that I see is that you are stopping the server after printing some statements, while the example that you have refered is not doing so. May be, remove server.stop(60) statement and check whether the issue still persists.

Using a Session interface in another class

I have a web application I am making using a websocket API to handle the websockets, here is the code for that part
package comm2.hello;
import java.io.IOException;
import java.util.ArrayList;
import javax.websocket.OnClose;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import org.apache.catalina.session.*;
#ServerEndpoint(value = "/echo")
public class wschat {
private static ArrayList<Session> sessionList = new ArrayList<Session>();
#OnOpen
public void onOpen(Session session) {
try {
sessionList.add(session);
// asynchronous communication
session.getBasicRemote().sendText("hello");
} catch (IOException e) {
}
}
public void send(String text, Session session) throws IOException {
session.getBasicRemote().sendText(text);
}
}
I am trying to have another java class then call into the send method to send messages, using the following code.
package comms;
import java.io.IOException;
import java.util.ArrayList;
import javax.websocket.Session;
import javax.websocket.Session;
import comm2.hello.*;
public class main {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
wschat h = new wschat();
String text = "hello";
//session shouldn't be null but not sure what to make it
Session session = null;
h.send(text,session);
}
}
As you can see, I have the session variable in the main.java class set to null which will thus always produce a null pointer error. This is because I am not sure what to make session equal to, does anyone have any idea what to initialize the session variable to in main.java?

Jboss Netty - Fails to send data continuously?

Using JBOSS Netty, I'm trying to send data continuously to the connected client. In the example below,
I try to send the time every 5 secs to the client, as soon as the client gets connected (channelConnected).
But this is not working. It works only if I comment the while loop.
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.bootstrap.ServerBootstrap;
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.ExceptionEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringEncoder;
public class SRNGServer {
public static void main(String[] args) throws Exception {
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
Executors.newCachedThreadPool()));
// Configure the pipeline factory.
bootstrap.setPipelineFactory(new SRNGServerPipelineFactoryP());
// Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(8080));
}
private static class SRNGServerHandlerP extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(SRNGServerHandlerP.class.getName());
#Override
public void channelConnected(
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
// Send greeting for a new connection.
e.getChannel().write("Welcome to " + InetAddress.getLocalHost().getHostName() + "!\r\n");
while(true){
e.getChannel().write("It is " + new Date() + " now.\r\n");
Thread.sleep(1000*5);
}
}
#Override
public void exceptionCaught(
ChannelHandlerContext ctx, ExceptionEvent e) {
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
e.getChannel().close();
}
}
private static class SRNGServerPipelineFactoryP implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SRNGServerHandlerP());
return pipeline;
}
}
}
The Netty documentation actually states that you should never make a Handler wait because it might eventually deadlock. The reason is that handler methods are called directly by I/O threads. One I/O thread in Netty performs multiple I/O operations in a sequence, so it's not one thread per operation.
In the channelConnected method you should start a new thread with a reference to the channel and make that thread send the time every 5 seconds. This would spawn one thread per connection.
Alternatively, you can have one single thread looping over a list of clients every 5 seconds and sending the time to each of them in a sequence.
Anyway, it's important to use a different thread for sending than the one that calls the Handler.
For what its worth, I figured the solution and here's the working code. After the "write" of time, I register the future with my ChannelFuturelistener. And then from operationComplete I keep registering the new future for every write. This works for what I want to accomplish, without using any extra threads.
import java.net.InetSocketAddress;
import java.nio.channels.ClosedChannelException;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
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.ExceptionEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.string.StringEncoder;
public class SRNGServer {
public static void main(String[] args) throws Exception {
// Configure the server.
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory(
Executors.newCachedThreadPool(),
//Executors.newCachedThreadPool()
Executors.newFixedThreadPool(2),2
));
// Configure the pipeline factory.
bootstrap.setPipelineFactory(new SRNGServerPipelineFactoryP());
// Bind and start to accept incoming connections.
bootstrap.bind(new InetSocketAddress(8080));
}
private static class SRNGServerHandlerP extends SimpleChannelUpstreamHandler {
private static final Logger logger = Logger.getLogger(SRNGServerHandlerP.class.getName());
#Override
public void channelConnected(
ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
// Send greeting for a new connection.
Channel ch=e.getChannel();
ChannelFuture writeFuture=e.getChannel().write("It is " + new Date() + " now.\r\n");
SRNGChannelFutureListener srngcfl=new SRNGChannelFutureListener();
writeFuture.addListener(srngcfl);
}
#Override
public void exceptionCaught(
ChannelHandlerContext ctx, ExceptionEvent e) {
logger.log(
Level.WARNING,
"Unexpected exception from downstream.",
e.getCause());
if(e.getCause() instanceof ClosedChannelException){
logger.log(Level.INFO, "****** Connection closed by client - Closing Channel");
}
e.getChannel().close();
}
}
private static class SRNGServerPipelineFactoryP implements ChannelPipelineFactory {
public ChannelPipeline getPipeline() throws Exception {
// Create a default pipeline implementation.
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new SRNGServerHandlerP());
return pipeline;
}
}
private static class SRNGChannelFutureListener implements ChannelFutureListener{
public void operationComplete(ChannelFuture future) throws InterruptedException{
Thread.sleep(1000*5);
Channel ch=future.getChannel();
if(ch!=null && ch.isConnected()){
ChannelFuture writeFuture=ch.write("It is " + new Date() + " now.\r\n");
//-- Add this instance as listener itself.
writeFuture.addListener(this);
}
}
}
}
Seems that the I/O thread is getting blocked as a result of sleep, so try using 2 worker threads instead:
ServerBootstrap bootstrap = new ServerBootstrap(
new NioServerSocketChannelFactory( Executors.newCachedThreadPool(),
Executors.newCachedThreadPool(), 2 ) );

Categories