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