java.lang.IllegalStateExceptionwhen the user reloads the page. The method is called onClose. I get an exception that the socket is already closed. Because of this, I cannot clear a few things in another thread that stops when the web socket session closes. Everything is in order if the user closes the session without reloading the page (basically this is the server terminal via websocket). I am on tomcat8.
Questions.
- How to properly close a websocket session on the server if the user reloads the page?
- Also, how can I do a few things when the webshocket session time ends?
Below is the code that serves the connection to the web server.
@ServerEndpoint(value = "/ws/{clientId}", configurator = HttpSessionConfigurator.class)
public class WSSession {
public static final long DEFAULT_TIMEOUT = 3600000;
public static final int DEFAULT_TIMEOUT_IN_SECONDS = 3600;
private Session wsSession;
private HttpSession httpSession;
private static final ConfigService configService;
static {
configService = ConfigServiceFactory.getConfigService(System
.getenv("ENVRIRONMENT"));
}
@OnOpen
public void onOpen(@PathParam("clientId") String clientId, Session session,
EndpointConfig config) throws IOException {
Logger logger = Logger.getLogger(clientId);
try {
FileHandler fh = new FileHandler(configService.logDirectory()
.toString() + "/" + clientId);
SimpleFormatter formatter = new SimpleFormatter();
fh.setFormatter(formatter);
logger.addHandler(fh);
logger.setLevel(Level.INFO);
} catch (SecurityException | IOException e1) {
e1.printStackTrace();
}
System.out.println("Got ID: " + clientId);
session.setMaxIdleTimeout(DEFAULT_TIMEOUT);
ConnectionDetails cd = configService.getConnectionDetails(clientId);
this.wsSession = session;
this.httpSession = (HttpSession) config.getUserProperties().get(
HttpSession.class.getName());
if (this.httpSession.getAttribute(SessionProperties.WS_SESSION.value()) != null
&& this.httpSession.getAttribute(SessionProperties.WS_SESSION
.value()) != session) {
Session wSession = (Session) this.httpSession
.getAttribute(SessionProperties.WS_SESSION.value());
if (wSession.isOpen()) {
wSession.close();
}
}
this.wsSession = session;
try {
Connection connection = new Connection(cd.getHost(), cd.getPort());
connection.connect();
boolean authenticated = connection.authenticateWithPublicKey(
cd.getUserName(), cd.getPrivateKey().toCharArray(), null);
if (authenticated) {
ch.ethz.ssh2.Session sshSession = connection.openSession();
sshSession.requestPTY("xterm", 120, 40, 14, 14, null);
OutputStream out = sshSession.getStdin();
InputStream in = new StreamGobbler(sshSession.getStdout());
sshSession.startShell();
Basic basicRemote = session.getBasicRemote();
Async asyncRemote = session.getAsyncRemote();
httpSession.setAttribute(SessionProperties.CLIENT_ID.value(),
clientId);
httpSession.setAttribute(SessionProperties.SSH_SESSION.value(),
sshSession);
httpSession.setAttribute(SessionProperties.IN_SSH.value(), out);
httpSession.setAttribute(SessionProperties.OUT_SSH.value(), in);
httpSession.setAttribute(
SessionProperties.BASIC_REMOTE.value(), basicRemote);
httpSession.setAttribute(SessionProperties.WS_SESSION.value(),
wsSession);
httpSession.setAttribute(
SessionProperties.ASYNC_REMOTE.value(), asyncRemote);
Thread worker = new Thread(new OutputTask(httpSession,
wsSession));
worker.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@OnMessage
public void onMessage(String message, Session session) throws IOException {
byte[] bytes = message.getBytes();
OutputStream out = (OutputStream) httpSession
.getAttribute(SessionProperties.IN_SSH.value());
out.write(bytes);
}
@OnClose
public void onClose(Session session) throws IOException {
if (session.isOpen()) {
try {
session.close();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
}
, , , , Exiting OutputTask , . .
@Override
public void run() {
InputStream stream = (StreamGobbler) session
.getAttribute(SessionProperties.OUT_SSH.value());
Basic basicRemote = (Basic) session
.getAttribute(SessionProperties.BASIC_REMOTE.value());
int read = 0;
byte[] bt = new byte[1024];
try {
while (wsSession.isOpen() && (read = stream.read(bt)) != -1) {
logger.info(new String(bt));
basicRemote.sendText(new String(Arrays.copyOf(bt, read)));
}
} catch (SecurityException | IOException e) {
e.printStackTrace();
} finally {
try {
Handler[] handlers = logger.getHandlers();
for (Handler h : handlers) {
h.close();
}
logger = null;
if (wsSession.isOpen()) {
wsSession.close();
}
if (stream != null) {
stream.close();
}
System.out.println("Exiting OutputTask");
session.invalidate();
} catch (IOException e) {
e.printStackTrace();
}
}
}
.
java.lang.IllegalStateException: Message will not be sent because the WebSocket session has been closed
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.writeMessagePart(WsRemoteEndpointImplBase.java:378)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessage(WsRemoteEndpointImplBase.java:335)
at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessageBlock(WsRemoteEndpointImplBase.java:264)
at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:536)
at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:464)
at org.apache.tomcat.websocket.WsSession.close(WsSession.java:441)
at org.apache.tomcat.websocket.WsSession.close(WsSession.java:435)
at com.example.websocket.wss.onClose(WSSession.java:130)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.apache.tomcat.websocket.pojo.PojoEndpointBase.onClose(PojoEndpointBase.java:107)
at org.apache.tomcat.websocket.WsSession.fireEndpointOnClose(WsSession.java:508)
at org.apache.tomcat.websocket.WsSession.onClose(WsSession.java:491)
at org.apache.tomcat.websocket.WsFrameBase.processDataControl(WsFrameBase.java:342)
at org.apache.tomcat.websocket.WsFrameBase.processData(WsFrameBase.java:284)
at org.apache.tomcat.websocket.WsFrameBase.processInputBuffer(WsFrameBase.java:130)
at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60)
at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:203)
at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:194)
at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:95)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:653)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:222)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1556)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1513)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)