001/* 002 * Copyright 2002-2018 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.server.standard; 018 019import java.util.ArrayList; 020import java.util.HashMap; 021import java.util.List; 022import java.util.Map; 023 024import javax.websocket.Decoder; 025import javax.websocket.Encoder; 026import javax.websocket.Endpoint; 027import javax.websocket.Extension; 028import javax.websocket.HandshakeResponse; 029import javax.websocket.server.HandshakeRequest; 030import javax.websocket.server.ServerEndpointConfig; 031 032import org.springframework.beans.factory.BeanFactory; 033import org.springframework.beans.factory.BeanFactoryAware; 034import org.springframework.lang.Nullable; 035import org.springframework.util.Assert; 036import org.springframework.web.socket.handler.BeanCreatingHandlerProvider; 037 038/** 039 * An implementation of {@link javax.websocket.server.ServerEndpointConfig} for use in 040 * Spring-based applications. A {@link ServerEndpointRegistration} bean is detected by 041 * {@link ServerEndpointExporter} and registered with a Java WebSocket runtime at startup. 042 * 043 * <p>Class constructors accept a singleton {@link javax.websocket.Endpoint} instance 044 * or an Endpoint specified by type {@link Class}. When specified by type, the endpoint 045 * will be instantiated and initialized through the Spring ApplicationContext before 046 * each client WebSocket connection. 047 * 048 * <p>This class also extends 049 * {@link javax.websocket.server.ServerEndpointConfig.Configurator} to make it easier 050 * to override methods for customizing the handshake process. 051 * 052 * @author Rossen Stoyanchev 053 * @author Juergen Hoeller 054 * @since 4.0 055 * @see ServerEndpointExporter 056 */ 057public class ServerEndpointRegistration extends ServerEndpointConfig.Configurator 058 implements ServerEndpointConfig, BeanFactoryAware { 059 060 private final String path; 061 062 @Nullable 063 private final Endpoint endpoint; 064 065 @Nullable 066 private final BeanCreatingHandlerProvider<Endpoint> endpointProvider; 067 068 private List<String> subprotocols = new ArrayList<>(0); 069 070 private List<Extension> extensions = new ArrayList<>(0); 071 072 private List<Class<? extends Encoder>> encoders = new ArrayList<>(0); 073 074 private List<Class<? extends Decoder>> decoders = new ArrayList<>(0); 075 076 private final Map<String, Object> userProperties = new HashMap<>(4); 077 078 079 /** 080 * Create a new {@link ServerEndpointRegistration} instance from an 081 * {@code javax.websocket.Endpoint} instance. 082 * @param path the endpoint path 083 * @param endpoint the endpoint instance 084 */ 085 public ServerEndpointRegistration(String path, Endpoint endpoint) { 086 Assert.hasText(path, "Path must not be empty"); 087 Assert.notNull(endpoint, "Endpoint must not be null"); 088 this.path = path; 089 this.endpoint = endpoint; 090 this.endpointProvider = null; 091 } 092 093 /** 094 * Create a new {@link ServerEndpointRegistration} instance from an 095 * {@code javax.websocket.Endpoint} class. 096 * @param path the endpoint path 097 * @param endpointClass the endpoint class 098 */ 099 public ServerEndpointRegistration(String path, Class<? extends Endpoint> endpointClass) { 100 Assert.hasText(path, "Path must not be empty"); 101 Assert.notNull(endpointClass, "Endpoint Class must not be null"); 102 this.path = path; 103 this.endpoint = null; 104 this.endpointProvider = new BeanCreatingHandlerProvider<>(endpointClass); 105 } 106 107 108 // ServerEndpointConfig implementation 109 110 @Override 111 public String getPath() { 112 return this.path; 113 } 114 115 @Override 116 public Class<? extends Endpoint> getEndpointClass() { 117 if (this.endpoint != null) { 118 return this.endpoint.getClass(); 119 } 120 else { 121 Assert.state(this.endpointProvider != null, "No endpoint set"); 122 return this.endpointProvider.getHandlerType(); 123 } 124 } 125 126 public Endpoint getEndpoint() { 127 if (this.endpoint != null) { 128 return this.endpoint; 129 } 130 else { 131 Assert.state(this.endpointProvider != null, "No endpoint set"); 132 return this.endpointProvider.getHandler(); 133 } 134 } 135 136 public void setSubprotocols(List<String> subprotocols) { 137 this.subprotocols = subprotocols; 138 } 139 140 @Override 141 public List<String> getSubprotocols() { 142 return this.subprotocols; 143 } 144 145 public void setExtensions(List<Extension> extensions) { 146 this.extensions = extensions; 147 } 148 149 @Override 150 public List<Extension> getExtensions() { 151 return this.extensions; 152 } 153 154 public void setEncoders(List<Class<? extends Encoder>> encoders) { 155 this.encoders = encoders; 156 } 157 158 @Override 159 public List<Class<? extends Encoder>> getEncoders() { 160 return this.encoders; 161 } 162 163 public void setDecoders(List<Class<? extends Decoder>> decoders) { 164 this.decoders = decoders; 165 } 166 167 @Override 168 public List<Class<? extends Decoder>> getDecoders() { 169 return this.decoders; 170 } 171 172 public void setUserProperties(Map<String, Object> userProperties) { 173 this.userProperties.clear(); 174 this.userProperties.putAll(userProperties); 175 } 176 177 @Override 178 public Map<String, Object> getUserProperties() { 179 return this.userProperties; 180 } 181 182 @Override 183 public Configurator getConfigurator() { 184 return this; 185 } 186 187 188 // ServerEndpointConfig.Configurator implementation 189 190 @SuppressWarnings("unchecked") 191 @Override 192 public final <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException { 193 return (T) getEndpoint(); 194 } 195 196 @Override 197 public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { 198 super.modifyHandshake(this, request, response); 199 } 200 201 202 // Remaining methods 203 204 @Override 205 public void setBeanFactory(BeanFactory beanFactory) { 206 if (this.endpointProvider != null) { 207 this.endpointProvider.setBeanFactory(beanFactory); 208 } 209 } 210 211 @Override 212 public String toString() { 213 return "ServerEndpointRegistration for path '" + getPath() + "': " + getEndpointClass(); 214 } 215 216}