if (handler != null) { handler.sendStompErrorFrameToClient("Broker not available."); handler.clearConnection(); stompAccessor.setHost(getVirtualHost()); StompConnectionHandler handler = new StompConnectionHandler(sessionId, stompAccessor); this.connectionHandlers.put(sessionId, handler); this.stats.incrementConnectCount(); handler.forward(message, stompAccessor); handler.forward(message, stompAccessor);
@Override public void handleMessage(Message<byte[]> message) { StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); Assert.state(accessor != null, "No StompHeaderAccessor"); accessor.setSessionId(this.sessionId); Principal user = this.connectHeaders.getUser(); if (user != null) { accessor.setUser(user); } StompCommand command = accessor.getCommand(); if (StompCommand.CONNECTED.equals(command)) { if (logger.isDebugEnabled()) { logger.debug("Received " + accessor.getShortLogMessage(EMPTY_PAYLOAD)); } afterStompConnected(accessor); } else if (logger.isErrorEnabled() && StompCommand.ERROR.equals(command)) { logger.error("Received " + accessor.getShortLogMessage(message.getPayload())); } else if (logger.isTraceEnabled()) { logger.trace("Received " + accessor.getDetailedLogMessage(message.getPayload())); } handleInboundMessage(message); }
@Override public void afterConnected(TcpConnection<byte[]> connection) { if (logger.isDebugEnabled()) { logger.debug("TCP connection opened in session=" + getSessionId()); } this.tcpConnection = connection; connection.onReadInactivity(() -> { if (this.tcpConnection != null && !this.isStompConnected) { handleTcpConnectionFailure("No CONNECTED frame received in " + MAX_TIME_TO_CONNECTED_FRAME + " ms.", null); } }, MAX_TIME_TO_CONNECTED_FRAME); connection.send(MessageBuilder.createMessage(EMPTY_PAYLOAD, this.connectHeaders.getMessageHeaders())); }
if (handler != null) { handler.sendStompErrorFrameToClient("Broker not available."); handler.clearConnection(); stompAccessor.setHost(getVirtualHost()); StompConnectionHandler handler = new StompConnectionHandler(sessionId, stompAccessor); this.connectionHandlers.put(sessionId, handler); this.stats.incrementConnectCount(); handler.forward(message, stompAccessor); handler.forward(message, stompAccessor);
if (handler != null) { handler.sendStompErrorFrameToClient("Broker not available."); handler.clearConnection(); stompAccessor.setHost(getVirtualHost()); StompConnectionHandler handler = new StompConnectionHandler(sessionId, stompAccessor); this.connectionHandlers.put(sessionId, handler); this.stats.incrementConnectCount(); handler.forward(message, stompAccessor); handler.forward(message, stompAccessor);
private void initHeartbeats(StompHeaderAccessor connectedHeaders) { if (this.isRemoteClientSession) { return; } TcpConnection<byte[]> con = this.tcpConnection; Assert.state(con != null, "No TcpConnection available"); long clientSendInterval = this.connectHeaders.getHeartbeat()[0]; long clientReceiveInterval = this.connectHeaders.getHeartbeat()[1]; long serverSendInterval = connectedHeaders.getHeartbeat()[0]; long serverReceiveInterval = connectedHeaders.getHeartbeat()[1]; if (clientSendInterval > 0 && serverReceiveInterval > 0) { long interval = Math.max(clientSendInterval, serverReceiveInterval); con.onWriteInactivity(() -> con.send(HEARTBEAT_MESSAGE).addCallback( result -> {}, ex -> handleTcpConnectionFailure( "Failed to forward heartbeat: " + ex.getMessage(), ex)), interval); } if (clientReceiveInterval > 0 && serverSendInterval > 0) { final long interval = Math.max(clientReceiveInterval, serverSendInterval) * HEARTBEAT_MULTIPLIER; con.onReadInactivity( () -> handleTcpConnectionFailure("No messages received in " + interval + " ms.", null), interval); } }
private void initHeartbeats(StompHeaderAccessor connectedHeaders) { if (this.isRemoteClientSession) { return; } TcpConnection<byte[]> con = this.tcpConnection; Assert.state(con != null, "No TcpConnection available"); long clientSendInterval = this.connectHeaders.getHeartbeat()[0]; long clientReceiveInterval = this.connectHeaders.getHeartbeat()[1]; long serverSendInterval = connectedHeaders.getHeartbeat()[0]; long serverReceiveInterval = connectedHeaders.getHeartbeat()[1]; if (clientSendInterval > 0 && serverReceiveInterval > 0) { long interval = Math.max(clientSendInterval, serverReceiveInterval); con.onWriteInactivity(() -> con.send(HEARTBEAT_MESSAGE).addCallback( result -> {}, ex -> handleTcpConnectionFailure( "Failed to forward heartbeat: " + ex.getMessage(), ex)), interval); } if (clientReceiveInterval > 0 && serverSendInterval > 0) { final long interval = Math.max(clientReceiveInterval, serverSendInterval) * HEARTBEAT_MULTIPLIER; con.onReadInactivity( () -> handleTcpConnectionFailure("No messages received in " + interval + " ms.", null), interval); } }
@Override public void handleMessage(Message<byte[]> message) { StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); Assert.state(accessor != null, "No StompHeaderAccessor"); accessor.setSessionId(this.sessionId); Principal user = this.connectHeaders.getUser(); if (user != null) { accessor.setUser(user); } StompCommand command = accessor.getCommand(); if (StompCommand.CONNECTED.equals(command)) { if (logger.isDebugEnabled()) { logger.debug("Received " + accessor.getShortLogMessage(EMPTY_PAYLOAD)); } afterStompConnected(accessor); } else if (logger.isErrorEnabled() && StompCommand.ERROR.equals(command)) { logger.error("Received " + accessor.getShortLogMessage(message.getPayload())); } else if (logger.isTraceEnabled()) { logger.trace("Received " + accessor.getDetailedLogMessage(message.getPayload())); } handleInboundMessage(message); }
@Override public void handleMessage(Message<byte[]> message) { StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class); Assert.state(accessor != null, "No StompHeaderAccessor"); accessor.setSessionId(this.sessionId); Principal user = this.connectHeaders.getUser(); if (user != null) { accessor.setUser(user); } StompCommand command = accessor.getCommand(); if (StompCommand.CONNECTED.equals(command)) { if (logger.isDebugEnabled()) { logger.debug("Received " + accessor.getShortLogMessage(EMPTY_PAYLOAD)); } afterStompConnected(accessor); } else if (logger.isErrorEnabled() && StompCommand.ERROR.equals(command)) { logger.error("Received " + accessor.getShortLogMessage(message.getPayload())); } else if (logger.isTraceEnabled()) { logger.trace("Received " + accessor.getDetailedLogMessage(message.getPayload())); } handleInboundMessage(message); }
@Override public void afterConnectionClosed() { if (this.tcpConnection == null) { return; } try { if (logger.isDebugEnabled()) { logger.debug("TCP connection to broker closed in session " + this.sessionId); } sendStompErrorFrameToClient("Connection to broker closed."); } finally { try { // Prevent clearConnection() from trying to close this.tcpConnection = null; clearConnection(); } catch (Throwable ex) { // Shouldn't happen with connection reset beforehand } } }
/** * Invoked when any TCP connectivity issue is detected, i.e. failure to establish * the TCP connection, failure to send a message, missed heartbeat, etc. */ protected void handleTcpConnectionFailure(String error, @Nullable Throwable ex) { if (logger.isInfoEnabled()) { logger.info("TCP connection failure in session " + this.sessionId + ": " + error, ex); } try { sendStompErrorFrameToClient(error); } finally { try { clearConnection(); } catch (Throwable ex2) { if (logger.isDebugEnabled()) { logger.debug("Failure while clearing TCP connection state in session " + this.sessionId, ex2); } } } }
/** * After a DISCONNECT there should be no more client frames so we can * close the connection pro-actively. However, if the DISCONNECT has a * receipt header we leave the connection open and expect the server will * respond with a RECEIPT and then close the connection. * @see <a href="http://stomp.github.io/stomp-specification-1.2.html#DISCONNECT"> * STOMP Specification 1.2 DISCONNECT</a> */ private void afterDisconnectSent(StompHeaderAccessor accessor) { if (accessor.getReceipt() == null) { try { clearConnection(); } catch (Throwable ex) { if (logger.isDebugEnabled()) { logger.debug("Failure while clearing TCP connection state in session " + this.sessionId, ex); } } } }
/** * Invoked when any TCP connectivity issue is detected, i.e. failure to establish * the TCP connection, failure to send a message, missed heartbeat, etc. */ protected void handleTcpConnectionFailure(String error, @Nullable Throwable ex) { if (logger.isInfoEnabled()) { logger.info("TCP connection failure in session " + this.sessionId + ": " + error, ex); } try { sendStompErrorFrameToClient(error); } finally { try { clearConnection(); } catch (Throwable ex2) { if (logger.isDebugEnabled()) { logger.debug("Failure while clearing TCP connection state in session " + this.sessionId, ex2); } } } }
@Override public void afterConnectionClosed() { if (this.tcpConnection == null) { return; } try { if (logger.isDebugEnabled()) { logger.debug("TCP connection to broker closed in session " + this.sessionId); } sendStompErrorFrameToClient("Connection to broker closed."); } finally { try { // Prevent clearConnection() from trying to close this.tcpConnection = null; clearConnection(); } catch (Throwable ex) { // Shouldn't happen with connection reset beforehand } } }
/** * After a DISCONNECT there should be no more client frames so we can * close the connection pro-actively. However, if the DISCONNECT has a * receipt header we leave the connection open and expect the server will * respond with a RECEIPT and then close the connection. * @see <a href="http://stomp.github.io/stomp-specification-1.2.html#DISCONNECT"> * STOMP Specification 1.2 DISCONNECT</a> */ private void afterDisconnectSent(StompHeaderAccessor accessor) { if (accessor.getReceipt() == null) { try { clearConnection(); } catch (Throwable ex) { if (logger.isDebugEnabled()) { logger.debug("Failure while clearing TCP connection state in session " + this.sessionId, ex); } } } }
private void sendStompErrorFrameToClient(String errorText) { if (this.isRemoteClientSession) { StompHeaderAccessor accessor = StompHeaderAccessor.create(StompCommand.ERROR); if (getHeaderInitializer() != null) { getHeaderInitializer().initHeaders(accessor); } accessor.setSessionId(this.sessionId); Principal user = this.connectHeaders.getUser(); if (user != null) { accessor.setUser(user); } accessor.setMessage(errorText); accessor.setLeaveMutable(true); Message<?> errorMessage = MessageBuilder.createMessage(EMPTY_PAYLOAD, accessor.getMessageHeaders()); handleInboundMessage(errorMessage); } }
private void sendStompErrorFrameToClient(String errorText) { if (this.isRemoteClientSession) { StompHeaderAccessor accessor = StompHeaderAccessor.create(StompCommand.ERROR); if (getHeaderInitializer() != null) { getHeaderInitializer().initHeaders(accessor); } accessor.setSessionId(this.sessionId); Principal user = this.connectHeaders.getUser(); if (user != null) { accessor.setUser(user); } accessor.setMessage(errorText); accessor.setLeaveMutable(true); Message<?> errorMessage = MessageBuilder.createMessage(EMPTY_PAYLOAD, accessor.getMessageHeaders()); handleInboundMessage(errorMessage); } }
@Override public ListenableFuture<Void> forward(Message<?> message, StompHeaderAccessor accessor) { try { ListenableFuture<Void> future = super.forward(message, accessor); if (message.getHeaders().get(SimpMessageHeaderAccessor.IGNORE_ERROR) == null) { future.get(); } return future; } catch (Throwable ex) { throw new MessageDeliveryException(message, ex); } } }
@Override public void afterConnected(TcpConnection<byte[]> connection) { if (logger.isDebugEnabled()) { logger.debug("TCP connection opened in session=" + getSessionId()); } this.tcpConnection = connection; connection.onReadInactivity(() -> { if (this.tcpConnection != null && !this.isStompConnected) { handleTcpConnectionFailure("No CONNECTED frame received in " + MAX_TIME_TO_CONNECTED_FRAME + " ms.", null); } }, MAX_TIME_TO_CONNECTED_FRAME); connection.send(MessageBuilder.createMessage(EMPTY_PAYLOAD, this.connectHeaders.getMessageHeaders())); }
@Override public ListenableFuture<Void> forward(Message<?> message, StompHeaderAccessor accessor) { try { ListenableFuture<Void> future = super.forward(message, accessor); if (message.getHeaders().get(SimpMessageHeaderAccessor.IGNORE_ERROR) == null) { future.get(); } return future; } catch (Throwable ex) { throw new MessageDeliveryException(message, ex); } } }