package xdi2.transport.impl.websocket.endpoint; import java.util.Arrays; import java.util.List; import javax.servlet.ServletContext; import javax.websocket.CloseReason; import javax.websocket.Decoder; import javax.websocket.DeploymentException; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; import javax.websocket.Extension; import javax.websocket.Session; import javax.websocket.server.ServerContainer; import javax.websocket.server.ServerEndpointConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import xdi2.transport.impl.websocket.WebSocketTransport; import xdi2.transport.registry.impl.uri.UriMessagingContainerFactoryMount; public class WebSocketServerEndpoint extends javax.websocket.Endpoint { private static final Logger log = LoggerFactory.getLogger(WebSocketServerEndpoint.class); public static void install(WebSocketTransport webSocketTransport, ServletContext servletContext) throws DeploymentException { String contextPath = servletContext.getContextPath(); if (contextPath == null) contextPath = ""; if (! contextPath.startsWith("/")) contextPath = "/" + contextPath; if (contextPath.endsWith("/")) contextPath = contextPath.substring(0, contextPath.length() - 1); if (log.isDebugEnabled()) log.debug("Context Path: " + contextPath); String endpointPath = webSocketTransport.getEndpointPath(); if (endpointPath == null) endpointPath = ""; if (! endpointPath.startsWith("/")) endpointPath = "/" + endpointPath; if (endpointPath.endsWith("/")) endpointPath = endpointPath.substring(0, endpointPath.length() - 1); if (log.isDebugEnabled()) log.debug("Endpoint Path: " + endpointPath); // find server container ServerContainer serverContainer = (ServerContainer) servletContext.getAttribute("javax.websocket.server.ServerContainer"); if (serverContainer == null) throw new DeploymentException("Cannot find ServerContainer"); // set default timeout long oldDefaultMaxSessionIdleTimeout = serverContainer.getDefaultMaxSessionIdleTimeout(); long newDefaultMaxSessionIdleTimeout = 0; serverContainer.setDefaultMaxSessionIdleTimeout(newDefaultMaxSessionIdleTimeout); if (log.isDebugEnabled()) log.debug("Changed default max session idle timeout from " + oldDefaultMaxSessionIdleTimeout + " to " + newDefaultMaxSessionIdleTimeout); // install install(serverContainer, webSocketTransport, contextPath, endpointPath, "/{path}"); for (UriMessagingContainerFactoryMount messagingContainerFactoryMount : webSocketTransport.getUriMessagingContainerRegistry().getMessagingContainerFactoryMounts()) { install(serverContainer, webSocketTransport, contextPath, endpointPath, messagingContainerFactoryMount.getMessagingContainerFactoryPath() + "/{path}"); } } private static void install(ServerContainer serverContainer, WebSocketTransport webSocketTransport, String contextPath, String endpointPath, String requestPath) throws DeploymentException { String path = endpointPath + requestPath; // init websocket endpoint List<String> subprotocols = Arrays.asList(new String[] { "xdi" }); List<Extension> extensions = null; List<Class<? extends Encoder>> encoders = null; List<Class<? extends Decoder>> decoders = null; ServerEndpointConfig.Configurator serverEndpointConfigConfigurator = new ServerEndpointConfig.Configurator() { }; ServerEndpointConfig.Builder serverEndpointConfigBuilder = ServerEndpointConfig.Builder.create( WebSocketServerEndpoint.class, path); serverEndpointConfigBuilder.subprotocols(subprotocols); serverEndpointConfigBuilder.extensions(extensions); serverEndpointConfigBuilder.encoders(encoders); serverEndpointConfigBuilder.decoders(decoders); serverEndpointConfigBuilder.configurator(serverEndpointConfigConfigurator); ServerEndpointConfig serverEndpointConfig = serverEndpointConfigBuilder.build(); serverEndpointConfig.getUserProperties().put("webSocketTransport", webSocketTransport); serverEndpointConfig.getUserProperties().put("contextPath", contextPath); serverEndpointConfig.getUserProperties().put("endpointPath", endpointPath); // install websocket endpoint serverContainer.addEndpoint(serverEndpointConfig); // done log.info("Installed WebSocket endpoint at " + path + " with subprotocols " + subprotocols); } @Override public void onOpen(Session session, EndpointConfig endpointConfig) { // set timeout long oldMaxIdleTimeout = session.getMaxIdleTimeout(); long newMaxIdleTimeout = 0; session.setMaxIdleTimeout(newMaxIdleTimeout); if (log.isDebugEnabled()) log.debug("Changed max idle timeout of session " + session.getId() + " from " + oldMaxIdleTimeout + " to " + newMaxIdleTimeout); // read properties ServerEndpointConfig serverEndpointConfig = (ServerEndpointConfig) endpointConfig; WebSocketTransport webSocketTransport = (WebSocketTransport) serverEndpointConfig.getUserProperties().get("webSocketTransport"); // init message handler WebSocketServerMessageHandler webSocketMessageHandler = new WebSocketServerMessageHandler(session); // init session log.info("WebSocket session " + session.getId() + " opened (" + serverEndpointConfig.getPath() + ")."); session.addMessageHandler(webSocketMessageHandler); session.getUserProperties().putAll(serverEndpointConfig.getUserProperties()); // register session webSocketTransport.registerSession(session, null); } @Override public void onClose(Session session, CloseReason closeReason) { log.info("WebSocket session " + session.getId() + " closed."); // read properties WebSocketTransport webSocketTransport = (WebSocketTransport) session.getUserProperties().get("webSocketTransport"); // unregister session webSocketTransport.unregisterSession(session); } @Override public void onError(Session session, Throwable throwable) { log.error("WebSocket session " + session.getId() + " problem: " + throwable.getMessage(), throwable); } }