1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 package javax.websocket.server; 18 19 import java.util.Collections; 20 import java.util.Iterator; 21 import java.util.List; 22 import java.util.ServiceLoader; 23 24 import javax.websocket.Decoder; 25 import javax.websocket.Encoder; 26 import javax.websocket.EndpointConfig; 27 import javax.websocket.Extension; 28 import javax.websocket.HandshakeResponse; 29 30 /** 31 * Provides configuration information for WebSocket endpoints published to a 32 * server. Applications may provide their own implementation or use 33 * {@link Builder}. 34 */ 35 public interface ServerEndpointConfig extends EndpointConfig { 36 getEndpointClass()37 Class<?> getEndpointClass(); 38 39 /** 40 * Returns the path at which this WebSocket server endpoint has been 41 * registered. It may be a path or a level 0 URI template. 42 * @return The registered path 43 */ getPath()44 String getPath(); 45 getSubprotocols()46 List<String> getSubprotocols(); 47 getExtensions()48 List<Extension> getExtensions(); 49 getConfigurator()50 Configurator getConfigurator(); 51 52 53 public final class Builder { 54 create( Class<?> endpointClass, String path)55 public static Builder create( 56 Class<?> endpointClass, String path) { 57 return new Builder(endpointClass, path); 58 } 59 60 61 private final Class<?> endpointClass; 62 private final String path; 63 private List<Class<? extends Encoder>> encoders = 64 Collections.emptyList(); 65 private List<Class<? extends Decoder>> decoders = 66 Collections.emptyList(); 67 private List<String> subprotocols = Collections.emptyList(); 68 private List<Extension> extensions = Collections.emptyList(); 69 private Configurator configurator = 70 Configurator.fetchContainerDefaultConfigurator(); 71 72 Builder(Class<?> endpointClass, String path)73 private Builder(Class<?> endpointClass, 74 String path) { 75 this.endpointClass = endpointClass; 76 this.path = path; 77 } 78 build()79 public ServerEndpointConfig build() { 80 return new DefaultServerEndpointConfig(endpointClass, path, 81 subprotocols, extensions, encoders, decoders, configurator); 82 } 83 84 encoders( List<Class<? extends Encoder>> encoders)85 public Builder encoders( 86 List<Class<? extends Encoder>> encoders) { 87 if (encoders == null || encoders.size() == 0) { 88 this.encoders = Collections.emptyList(); 89 } else { 90 this.encoders = Collections.unmodifiableList(encoders); 91 } 92 return this; 93 } 94 95 decoders( List<Class<? extends Decoder>> decoders)96 public Builder decoders( 97 List<Class<? extends Decoder>> decoders) { 98 if (decoders == null || decoders.size() == 0) { 99 this.decoders = Collections.emptyList(); 100 } else { 101 this.decoders = Collections.unmodifiableList(decoders); 102 } 103 return this; 104 } 105 106 subprotocols( List<String> subprotocols)107 public Builder subprotocols( 108 List<String> subprotocols) { 109 if (subprotocols == null || subprotocols.size() == 0) { 110 this.subprotocols = Collections.emptyList(); 111 } else { 112 this.subprotocols = Collections.unmodifiableList(subprotocols); 113 } 114 return this; 115 } 116 117 extensions( List<Extension> extensions)118 public Builder extensions( 119 List<Extension> extensions) { 120 if (extensions == null || extensions.size() == 0) { 121 this.extensions = Collections.emptyList(); 122 } else { 123 this.extensions = Collections.unmodifiableList(extensions); 124 } 125 return this; 126 } 127 128 configurator(Configurator serverEndpointConfigurator)129 public Builder configurator(Configurator serverEndpointConfigurator) { 130 if (serverEndpointConfigurator == null) { 131 this.configurator = Configurator.fetchContainerDefaultConfigurator(); 132 } else { 133 this.configurator = serverEndpointConfigurator; 134 } 135 return this; 136 } 137 } 138 139 140 public class Configurator { 141 142 private static volatile Configurator defaultImpl = null; 143 private static final Object defaultImplLock = new Object(); 144 145 private static final String DEFAULT_IMPL_CLASSNAME = 146 "nginx.unit.websocket.server.DefaultServerEndpointConfigurator"; 147 setDefault(Configurator def)148 public static void setDefault(Configurator def) { 149 synchronized (defaultImplLock) { 150 defaultImpl = def; 151 } 152 } 153 fetchContainerDefaultConfigurator()154 static Configurator fetchContainerDefaultConfigurator() { 155 if (defaultImpl == null) { 156 synchronized (defaultImplLock) { 157 if (defaultImpl == null) { 158 defaultImpl = loadDefault(); 159 } 160 } 161 } 162 return defaultImpl; 163 } 164 165 loadDefault()166 private static Configurator loadDefault() { 167 Configurator result = null; 168 169 ServiceLoader<Configurator> serviceLoader = 170 ServiceLoader.load(Configurator.class); 171 172 Iterator<Configurator> iter = serviceLoader.iterator(); 173 while (result == null && iter.hasNext()) { 174 result = iter.next(); 175 } 176 177 // Fall-back. Also used by unit tests 178 if (result == null) { 179 try { 180 @SuppressWarnings("unchecked") 181 Class<Configurator> clazz = 182 (Class<Configurator>) Class.forName( 183 DEFAULT_IMPL_CLASSNAME); 184 result = clazz.getConstructor().newInstance(); 185 } catch (ReflectiveOperationException | IllegalArgumentException | 186 SecurityException e) { 187 // No options left. Just return null. 188 } 189 } 190 return result; 191 } 192 getNegotiatedSubprotocol(List<String> supported, List<String> requested)193 public String getNegotiatedSubprotocol(List<String> supported, 194 List<String> requested) { 195 return fetchContainerDefaultConfigurator().getNegotiatedSubprotocol(supported, requested); 196 } 197 getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)198 public List<Extension> getNegotiatedExtensions(List<Extension> installed, 199 List<Extension> requested) { 200 return fetchContainerDefaultConfigurator().getNegotiatedExtensions(installed, requested); 201 } 202 checkOrigin(String originHeaderValue)203 public boolean checkOrigin(String originHeaderValue) { 204 return fetchContainerDefaultConfigurator().checkOrigin(originHeaderValue); 205 } 206 modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response)207 public void modifyHandshake(ServerEndpointConfig sec, 208 HandshakeRequest request, HandshakeResponse response) { 209 fetchContainerDefaultConfigurator().modifyHandshake(sec, request, response); 210 } 211 getEndpointInstance(Class<T> clazz)212 public <T extends Object> T getEndpointInstance(Class<T> clazz) 213 throws InstantiationException { 214 return fetchContainerDefaultConfigurator().getEndpointInstance( 215 clazz); 216 } 217 } 218 } 219