/* * Copyright 2002-2016 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.web.socket.client.standard; import javax.websocket.ContainerProvider; import javax.websocket.Session; import javax.websocket.WebSocketContainer; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; import org.springframework.util.Assert; import org.springframework.web.socket.client.ConnectionManagerSupport; import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; /** * A WebSocket connection manager that is given a URI, a * {@link javax.websocket.ClientEndpoint}-annotated endpoint, connects to a * WebSocket server through the {@link #start()} and {@link #stop()} methods. * If {@link #setAutoStartup(boolean)} is set to {@code true} this will be * done automatically when the Spring ApplicationContext is refreshed. * * @author Rossen Stoyanchev * @since 4.0 */ public class AnnotatedEndpointConnectionManager extends ConnectionManagerSupport implements BeanFactoryAware { private final Object endpoint; private final BeanCreatingHandlerProvider<Object> endpointProvider; private WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer(); private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("AnnotatedEndpointConnectionManager-"); private volatile Session session; public AnnotatedEndpointConnectionManager(Object endpoint, String uriTemplate, Object... uriVariables) { super(uriTemplate, uriVariables); this.endpointProvider = null; this.endpoint = endpoint; } public AnnotatedEndpointConnectionManager(Class<?> endpointClass, String uriTemplate, Object... uriVariables) { super(uriTemplate, uriVariables); this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass); this.endpoint = null; } public void setWebSocketContainer(WebSocketContainer webSocketContainer) { this.webSocketContainer = webSocketContainer; } public WebSocketContainer getWebSocketContainer() { return this.webSocketContainer; } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { if (this.endpointProvider != null) { this.endpointProvider.setBeanFactory(beanFactory); } } /** * Set a {@link TaskExecutor} to use to open the connection. * By default {@link SimpleAsyncTaskExecutor} is used. */ public void setTaskExecutor(TaskExecutor taskExecutor) { Assert.notNull(taskExecutor, "TaskExecutor must not be null"); this.taskExecutor = taskExecutor; } /** * Return the configured {@link TaskExecutor}. */ public TaskExecutor getTaskExecutor() { return this.taskExecutor; } @Override protected void openConnection() { this.taskExecutor.execute(new Runnable() { @Override public void run() { try { if (logger.isInfoEnabled()) { logger.info("Connecting to WebSocket at " + getUri()); } Object endpointToUse = (endpoint != null) ? endpoint : endpointProvider.getHandler(); session = webSocketContainer.connectToServer(endpointToUse, getUri()); logger.info("Successfully connected to WebSocket"); } catch (Throwable ex) { logger.error("Failed to connect to WebSocket", ex); } } }); } @Override protected void closeConnection() throws Exception { try { if (isConnected()) { this.session.close(); } } finally { this.session = null; } } @Override protected boolean isConnected() { return (this.session != null && this.session.isOpen()); } }