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