001/* 002 * Copyright 2002-2016 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.socket.client.standard; 018 019import javax.websocket.ContainerProvider; 020import javax.websocket.Session; 021import javax.websocket.WebSocketContainer; 022 023import org.springframework.beans.BeansException; 024import org.springframework.beans.factory.BeanFactory; 025import org.springframework.beans.factory.BeanFactoryAware; 026import org.springframework.core.task.SimpleAsyncTaskExecutor; 027import org.springframework.core.task.TaskExecutor; 028import org.springframework.util.Assert; 029import org.springframework.web.socket.client.ConnectionManagerSupport; 030import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; 031 032/** 033 * A WebSocket connection manager that is given a URI, a 034 * {@link javax.websocket.ClientEndpoint}-annotated endpoint, connects to a 035 * WebSocket server through the {@link #start()} and {@link #stop()} methods. 036 * If {@link #setAutoStartup(boolean)} is set to {@code true} this will be 037 * done automatically when the Spring ApplicationContext is refreshed. 038 * 039 * @author Rossen Stoyanchev 040 * @since 4.0 041 */ 042public class AnnotatedEndpointConnectionManager extends ConnectionManagerSupport implements BeanFactoryAware { 043 044 private final Object endpoint; 045 046 private final BeanCreatingHandlerProvider<Object> endpointProvider; 047 048 private WebSocketContainer webSocketContainer = ContainerProvider.getWebSocketContainer(); 049 050 private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor("AnnotatedEndpointConnectionManager-"); 051 052 private volatile Session session; 053 054 055 public AnnotatedEndpointConnectionManager(Object endpoint, String uriTemplate, Object... uriVariables) { 056 super(uriTemplate, uriVariables); 057 this.endpointProvider = null; 058 this.endpoint = endpoint; 059 } 060 061 public AnnotatedEndpointConnectionManager(Class<?> endpointClass, String uriTemplate, Object... uriVariables) { 062 super(uriTemplate, uriVariables); 063 this.endpointProvider = new BeanCreatingHandlerProvider<Object>(endpointClass); 064 this.endpoint = null; 065 } 066 067 068 public void setWebSocketContainer(WebSocketContainer webSocketContainer) { 069 this.webSocketContainer = webSocketContainer; 070 } 071 072 public WebSocketContainer getWebSocketContainer() { 073 return this.webSocketContainer; 074 } 075 076 @Override 077 public void setBeanFactory(BeanFactory beanFactory) throws BeansException { 078 if (this.endpointProvider != null) { 079 this.endpointProvider.setBeanFactory(beanFactory); 080 } 081 } 082 083 /** 084 * Set a {@link TaskExecutor} to use to open the connection. 085 * By default {@link SimpleAsyncTaskExecutor} is used. 086 */ 087 public void setTaskExecutor(TaskExecutor taskExecutor) { 088 Assert.notNull(taskExecutor, "TaskExecutor must not be null"); 089 this.taskExecutor = taskExecutor; 090 } 091 092 /** 093 * Return the configured {@link TaskExecutor}. 094 */ 095 public TaskExecutor getTaskExecutor() { 096 return this.taskExecutor; 097 } 098 099 100 @Override 101 protected void openConnection() { 102 this.taskExecutor.execute(new Runnable() { 103 @Override 104 public void run() { 105 try { 106 if (logger.isInfoEnabled()) { 107 logger.info("Connecting to WebSocket at " + getUri()); 108 } 109 Object endpointToUse = (endpoint != null) ? endpoint : endpointProvider.getHandler(); 110 session = webSocketContainer.connectToServer(endpointToUse, getUri()); 111 logger.info("Successfully connected to WebSocket"); 112 } 113 catch (Throwable ex) { 114 logger.error("Failed to connect to WebSocket", ex); 115 } 116 } 117 }); 118 } 119 120 @Override 121 protected void closeConnection() throws Exception { 122 try { 123 if (isConnected()) { 124 this.session.close(); 125 } 126 } 127 finally { 128 this.session = null; 129 } 130 } 131 132 @Override 133 protected boolean isConnected() { 134 return (this.session != null && this.session.isOpen()); 135 } 136 137}