All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.integration.websocket.IntegrationWebSocketContainer Maven / Gradle / Ivy

There is a newer version: 6.4.1
Show newest version
/*
 * Copyright 2014-2015 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.integration.websocket;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.util.Assert;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.SubProtocolCapable;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator;

/**
 * The high-level 'connection factory pattern' contract over low-level Web-Socket
 * configuration.
 * 

* Provides the composition for the internal {@link WebSocketHandler} * implementation, which is used with native Web-Socket containers. *

* Collects established {@link WebSocketSession}s, which can be accessed using * {@link #getSession(String)}. *

* Can accept the {@link WebSocketListener} to delegate {@link WebSocketSession} events * from the internal {@link IntegrationWebSocketContainer.IntegrationWebSocketHandler}. *

* Supported sub-protocols can be configured, but {@link WebSocketListener#getSubProtocols()} * have a precedent. * * @author Artem Bilan * @since 4.1 * @see org.springframework.integration.websocket.inbound.WebSocketInboundChannelAdapter * @see org.springframework.integration.websocket.outbound.WebSocketOutboundMessageHandler */ public abstract class IntegrationWebSocketContainer implements DisposableBean { protected final Log logger = LogFactory.getLog(this.getClass()); protected final WebSocketHandler webSocketHandler = new IntegrationWebSocketHandler(); protected final Map sessions = new ConcurrentHashMap(); private final List supportedProtocols = new ArrayList(); private volatile WebSocketListener messageListener; private volatile int sendTimeLimit = 10 * 1000; private volatile int sendBufferSizeLimit = 512 * 1024; public void setSendTimeLimit(int sendTimeLimit) { this.sendTimeLimit = sendTimeLimit; } public void setSendBufferSizeLimit(int sendBufferSizeLimit) { this.sendBufferSizeLimit = sendBufferSizeLimit; } public void setMessageListener(WebSocketListener messageListener) { Assert.state(this.messageListener == null || this.messageListener == messageListener, "'messageListener' is already configured"); this.messageListener = messageListener; } public void setSupportedProtocols(String... protocols) { this.supportedProtocols.clear(); addSupportedProtocols(protocols); } public void addSupportedProtocols(String... protocols) { for (String protocol : protocols) { this.supportedProtocols.add(protocol.toLowerCase()); } } public List getSubProtocols() { List protocols = new ArrayList(); if (this.messageListener != null) { protocols.addAll(this.messageListener.getSubProtocols()); } protocols.addAll(this.supportedProtocols); return Collections.unmodifiableList(protocols); } public Map getSessions() { return Collections.unmodifiableMap(this.sessions); } public WebSocketSession getSession(String sessionId) { WebSocketSession session = this.sessions.get(sessionId); Assert.notNull(session, "Session not found for id '" + sessionId + "'"); return session; } public void closeSession(WebSocketSession session, CloseStatus closeStatus) throws Exception { // Session may be unresponsive so clear first session.close(closeStatus); this.webSocketHandler.afterConnectionClosed(session, closeStatus); } @Override public void destroy() throws Exception { try { // Notify sessions to stop flushing messages for (WebSocketSession session : this.sessions.values()) { try { session.close(CloseStatus.GOING_AWAY); } catch (Exception e) { logger.error("Failed to close session id '" + session.getId() + "': " + e.getMessage()); } } } finally { this.sessions.clear(); } } /** * An internal {@link WebSocketHandler} implementation to be used with native * Web-Socket containers. *

* Delegates all operations to the wrapping {@link IntegrationWebSocketContainer} * and its {@link WebSocketListener}. */ private class IntegrationWebSocketHandler implements WebSocketHandler, SubProtocolCapable { @Override public List getSubProtocols() { return IntegrationWebSocketContainer.this.getSubProtocols(); } @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { session = new ConcurrentWebSocketSessionDecorator(session, IntegrationWebSocketContainer.this.sendTimeLimit, IntegrationWebSocketContainer.this.sendBufferSizeLimit); IntegrationWebSocketContainer.this.sessions.put(session.getId(), session); if (logger.isDebugEnabled()) { logger.debug("Started WebSocket session = " + session.getId() + ", number of sessions = " + IntegrationWebSocketContainer.this.sessions.size()); } if (IntegrationWebSocketContainer.this.messageListener != null) { IntegrationWebSocketContainer.this.messageListener.afterSessionStarted(session); } } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { WebSocketSession removed = IntegrationWebSocketContainer.this.sessions.remove(session.getId()); if (removed != null) { if (IntegrationWebSocketContainer.this.messageListener != null) { IntegrationWebSocketContainer.this.messageListener.afterSessionEnded(session, closeStatus); } } } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { IntegrationWebSocketContainer.this.sessions.remove(session.getId()); throw new Exception(exception); } @Override public void handleMessage(WebSocketSession session, WebSocketMessage message) throws Exception { if (IntegrationWebSocketContainer.this.messageListener != null) { IntegrationWebSocketContainer.this.messageListener.onMessage(session, message); } else if (logger.isInfoEnabled()) { logger.info("This 'WebSocketHandlerContainer' isn't configured with 'WebSocketMessageListener'." + " Received messages are ignored. Current message is: " + message); } } @Override public boolean supportsPartialMessages() { return false; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy