/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package javax.websocket.server; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.ServiceLoader; import javax.websocket.Decoder; import javax.websocket.Encoder; import javax.websocket.EndpointConfig; import javax.websocket.Extension; import javax.websocket.HandshakeResponse; /** * Provides configuration information for WebSocket endpoints published to a * server. Applications may provide their own implementation or use * {@link Builder}. */ public interface ServerEndpointConfig extends EndpointConfig { Class getEndpointClass(); /** * Returns the path at which this WebSocket server endpoint has been * registered. It may be a path or a level 0 URI template. * @return The registered path */ String getPath(); List getSubprotocols(); List getExtensions(); Configurator getConfigurator(); public final class Builder { public static Builder create( Class endpointClass, String path) { return new Builder(endpointClass, path); } private final Class endpointClass; private final String path; private List> encoders = Collections.emptyList(); private List> decoders = Collections.emptyList(); private List subprotocols = Collections.emptyList(); private List extensions = Collections.emptyList(); private Configurator configurator = Configurator.fetchContainerDefaultConfigurator(); private Builder(Class endpointClass, String path) { this.endpointClass = endpointClass; this.path = path; } public ServerEndpointConfig build() { return new DefaultServerEndpointConfig(endpointClass, path, subprotocols, extensions, encoders, decoders, configurator); } public Builder encoders( List> encoders) { if (encoders == null || encoders.size() == 0) { this.encoders = Collections.emptyList(); } else { this.encoders = Collections.unmodifiableList(encoders); } return this; } public Builder decoders( List> decoders) { if (decoders == null || decoders.size() == 0) { this.decoders = Collections.emptyList(); } else { this.decoders = Collections.unmodifiableList(decoders); } return this; } public Builder subprotocols( List subprotocols) { if (subprotocols == null || subprotocols.size() == 0) { this.subprotocols = Collections.emptyList(); } else { this.subprotocols = Collections.unmodifiableList(subprotocols); } return this; } public Builder extensions( List extensions) { if (extensions == null || extensions.size() == 0) { this.extensions = Collections.emptyList(); } else { this.extensions = Collections.unmodifiableList(extensions); } return this; } public Builder configurator(Configurator serverEndpointConfigurator) { if (serverEndpointConfigurator == null) { this.configurator = Configurator.fetchContainerDefaultConfigurator(); } else { this.configurator = serverEndpointConfigurator; } return this; } } public class Configurator { private static volatile Configurator defaultImpl = null; private static final Object defaultImplLock = new Object(); private static final String DEFAULT_IMPL_CLASSNAME = "nginx.unit.websocket.server.DefaultServerEndpointConfigurator"; public static void setDefault(Configurator def) { synchronized (defaultImplLock) { defaultImpl = def; } } static Configurator fetchContainerDefaultConfigurator() { if (defaultImpl == null) { synchronized (defaultImplLock) { if (defaultImpl == null) { defaultImpl = loadDefault(); } } } return defaultImpl; } private static Configurator loadDefault() { Configurator result = null; ServiceLoader serviceLoader = ServiceLoader.load(Configurator.class); Iterator iter = serviceLoader.iterator(); while (result == null && iter.hasNext()) { result = iter.next(); } // Fall-back. Also used by unit tests if (result == null) { try { @SuppressWarnings("unchecked") Class clazz = (Class) Class.forName( DEFAULT_IMPL_CLASSNAME); result = clazz.getConstructor().newInstance(); } catch (ReflectiveOperationException | IllegalArgumentException | SecurityException e) { // No options left. Just return null. } } return result; } public String getNegotiatedSubprotocol(List supported, List requested) { return fetchContainerDefaultConfigurator().getNegotiatedSubprotocol(supported, requested); } public List getNegotiatedExtensions(List installed, List requested) { return fetchContainerDefaultConfigurator().getNegotiatedExtensions(installed, requested); } public boolean checkOrigin(String originHeaderValue) { return fetchContainerDefaultConfigurator().checkOrigin(originHeaderValue); } public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { fetchContainerDefaultConfigurator().modifyHandshake(sec, request, response); } public T getEndpointInstance(Class clazz) throws InstantiationException { return fetchContainerDefaultConfigurator().getEndpointInstance( clazz); } } }