Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   *  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 org.apache.tomcat.websocket;
 
 import static org.jboss.web.WebsocketsMessages.MESSAGES;
 
 import java.io.File;
 import java.net.URI;
 import  java.nio.channels.AsynchronousChannelGroup;
 import  java.nio.channels.AsynchronousSocketChannel;
 import  java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 
 
 public class WsWebSocketContainer
         implements WebSocketContainerBackgroundProcess {
 
     protected static final ThreadBindingListener DEFAULT_THREAD_BINDING_LISTENER = (new ThreadBindingListener() {
         public void bind() {}
         public void unbind() {}
     });
    
Property name to set to configure the value that is passed to SSLEngine.setEnabledProtocols(String[]). The value should be a comma separated string.
 
     public static final String SSL_PROTOCOLS_PROPERTY =
             "org.apache.tomcat.websocket.SSL_PROTOCOLS";
     public static final String SSL_TRUSTSTORE_PROPERTY =
             "org.apache.tomcat.websocket.SSL_TRUSTSTORE";
     public static final String SSL_TRUSTSTORE_PWD_PROPERTY =
             "org.apache.tomcat.websocket.SSL_TRUSTSTORE_PWD";
     public static final String SSL_TRUSTSTORE_PWD_DEFAULT = "changeit";
    
Property name to set to configure used SSLContext. The value should be an instance of SSLContext. If this property is present, the SSL_TRUSTSTORE* properties are ignored.
 
     public static final String SSL_CONTEXT_PROPERTY =
             "org.apache.tomcat.websocket.SSL_CONTEXT";

    
Property name to set to configure the timeout (in milliseconds) when establishing a WebSocket connection to server. The default is IO_TIMEOUT_MS_DEFAULT.
    public static final String IO_TIMEOUT_MS_PROPERTY =
            "org.apache.tomcat.websocket.IO_TIMEOUT_MS";
    public static final long IO_TIMEOUT_MS_DEFAULT = 5000;
    private static final Random random = new Random();
    private static final byte[] crlf = new byte[] {13, 10};
    private volatile AsynchronousChannelGroup asynchronousChannelGroup = null;
    private final Object asynchronousChannelGroupLock = new Object();
    private final Map<Class<?>, Set<WsSession>> endpointSessionMap =
            new HashMap<Class<?>, Set<WsSession>>();
    private final Map<WsSession,WsSessionsessions = new ConcurrentHashMap<WsSessionWsSession>();
    private final Object endPointSessionMapLock = new Object();
    private long defaultAsyncTimeout = -1;
    private volatile long defaultMaxSessionIdleTimeout = 0;
    private int backgroundProcessCount = 0;
    private int processPeriod = 10;
    @Override
    public Session connectToServer(Object pojoURI path)
            throws DeploymentException {
        ClientEndpoint annotation =
                pojo.getClass().getAnnotation(ClientEndpoint.class);
        if (annotation == null) {
            throw new DeploymentException(
                    .missingClientEndpointAnnotation(pojo.getClass().getName()));
        }
        Endpoint ep = new PojoEndpointClient(pojoannotation.decoders());
        Class<? extends ClientEndpointConfig.ConfiguratorconfiguratorClazz =
                pojo.getClass().getAnnotation(
                        ClientEndpoint.class).configurator();
        ClientEndpointConfig.Configurator configurator = null;
        if (!ClientEndpointConfig.Configurator.class.equals(
                configuratorClazz)) {
            try {
                configurator = configuratorClazz.newInstance();
            } catch (InstantiationException e) {
                throw new DeploymentException(.defaultConfiguratorFailed(), e);
            } catch (IllegalAccessException e) {
                throw new DeploymentException(.defaultConfiguratorFailed(), e);
            }
        }
        ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create();
        // Avoid NPE when using RI API JAR - see BZ 56343
        if (configurator != null) {
            builder.configurator(configurator);
        }
        ClientEndpointConfig config = builder.
                decoders(Arrays.asList(annotation.decoders())).
                encoders(Arrays.asList(annotation.encoders())).
                preferredSubprotocols(Arrays.asList(annotation.subprotocols())).
                build();
        return connectToServer(epconfigpath);
    }
    @Override
    public Session connectToServer(Class<?> annotatedEndpointClassURI path)
            throws DeploymentException {
        Object pojo;
        try {
            pojo = annotatedEndpointClass.newInstance();
        } catch (InstantiationException e) {
            throw new DeploymentException(.endpointCreateFailed(annotatedEndpointClass.getName()), e);
        } catch (IllegalAccessException e) {
            throw new DeploymentException(.endpointCreateFailed(annotatedEndpointClass.getName()), e);
        }
        return connectToServer(pojopath);
    }
    @Override
    public Session connectToServer(Class<? extends Endpointclazz,
            ClientEndpointConfig clientEndpointConfigurationURI path)
            throws DeploymentException {
        Endpoint endpoint;
        try {
            endpoint = clazz.newInstance();
        } catch (InstantiationException e) {
            throw new DeploymentException(.endpointCreateFailed(clazz.getName()), e);
        } catch (IllegalAccessException e) {
            throw new DeploymentException(.endpointCreateFailed(clazz.getName()), e);
        }
        return connectToServer(endpointclientEndpointConfigurationpath);
    }
    @Override
    public Session connectToServer(Endpoint endpoint,
            ClientEndpointConfig clientEndpointConfigurationURI path)
            throws DeploymentException {
        boolean secure = false;
        String scheme = path.getScheme();
        if (!("ws".equalsIgnoreCase(scheme) ||
                "wss".equalsIgnoreCase(scheme))) {
            throw new DeploymentException(.pathWrongScheme(scheme));
        }
        String host = path.getHost();
        if (host == null) {
            throw new DeploymentException(.pathNoHost());
        }
        int port = path.getPort();
        Map<String,List<String>> reqHeaders = createRequestHeaders(hostport,
                clientEndpointConfiguration.getPreferredSubprotocols(),
                clientEndpointConfiguration.getExtensions());
        clientEndpointConfiguration.getConfigurator().
                beforeRequest(reqHeaders);
        ByteBuffer request = createRequest(pathreqHeaders);
        SocketAddress sa;
        if (port == -1) {
            if ("ws".equalsIgnoreCase(scheme)) {
                sa = new InetSocketAddress(host, 80);
            } else if ("wss".equalsIgnoreCase(scheme)) {
                sa = new InetSocketAddress(host, 443);
                secure = true;
            } else {
                throw new DeploymentException(.invalidScheme(scheme));
            }
        } else {
            if ("wss".equalsIgnoreCase(scheme)) {
                secure = true;
            }
            sa = new InetSocketAddress(hostport);
        }
        AsynchronousSocketChannel socketChannel;
        try {
            socketChannel = AsynchronousSocketChannel.open(getAsynchronousChannelGroup());
        } catch (IOException ioe) {
            throw new DeploymentException(.connectionFailed(), ioe);
        }
        Future<VoidfConnect = socketChannel.connect(sa);
        AsyncChannelWrapper channel;
        if (secure) {
            SSLEngine sslEngine = createSSLEngine(
                    clientEndpointConfiguration.getUserProperties());
            channel = new AsyncChannelWrapperSecure(socketChannelsslEngine);
        } else {
            channel = new AsyncChannelWrapperNonSecure(socketChannel);
        }
        // Get the connection timeout
        long timeout = ;
        String timeoutValue = (StringclientEndpointConfiguration.getUserProperties().get(
                );
        if (timeoutValue != null) {
            timeout = Long.valueOf(timeoutValue).intValue();
        }
        ByteBuffer response;
        String subProtocol;
        boolean success = false;
        List<ExtensionextensionsAgreed = new ArrayList<Extension>();
        Transformation transformation = null;
        try {
            fConnect.get(timeout.);
            Future<VoidfHandshake = channel.handshake();
            fHandshake.get(timeout.);
            int toWrite = request.limit();
            Future<IntegerfWrite = channel.write(request);
            Integer thisWrite = fWrite.get(timeout.);
            toWrite -= thisWrite.intValue();
            while (toWrite > 0) {
                fWrite = channel.write(request);
                thisWrite = fWrite.get(timeout.);
                toWrite -= thisWrite.intValue();
            }
            // Same size as the WsFrame input buffer
            response = ByteBuffer.allocate();
            HandshakeResponse handshakeResponse =
                    processResponse(responsechanneltimeout);
            clientEndpointConfiguration.getConfigurator().
                    afterResponse(handshakeResponse);
            // Sub-protocol
            // Header names are always stored in lower case
            List<StringprotocolHeaders = handshakeResponse.getHeaders().get(
                    .);
            if (protocolHeaders == null || protocolHeaders.size() == 0) {
                subProtocol = null;
            } else if (protocolHeaders.size() == 1) {
                subProtocol = protocolHeaders.get(0);
            } else {
                throw new DeploymentException(.invalidProtocolHeader());
            }
            // Extensions
            // Should normally only be one header but handle the case of
            // multiple headers
            List<StringextHeaders = handshakeResponse.getHeaders().get(
                    .);
            if (extHeaders != null) {
                for (String extHeader : extHeaders) {
                    Util.parseExtensionHeader(extensionsAgreedextHeader);
                }
            }
            // Build the transformations
            TransformationFactory factory = TransformationFactory.getInstance();
            for (Extension extension : extensionsAgreed) {
                List<List<Extension.Parameter>> wrapper = new ArrayList<List<Extension.Parameter>>(1);
                wrapper.add(extension.getParameters());
                Transformation t = factory.create(extension.getName(), wrapperfalse);
                if (t == null) {
                    throw new DeploymentException(.unsupportedParameters());
                }
                if (transformation == null) {
                    transformation = t;
                } else {
                    transformation.setNext(t);
                }
            }
            success = true;
        } catch (ExecutionException e) {
            throw new DeploymentException(.httpRequestFailed(), e);
        } catch (InterruptedException e) {
            throw new DeploymentException(.httpRequestFailed(), e);
        } catch (SSLException e) {
            throw new DeploymentException(.httpRequestFailed(), e);
        } catch (EOFException e) {
            throw new DeploymentException(.httpRequestFailed(), e);
        } catch (TimeoutException e) {
            throw new DeploymentException(.httpRequestFailed(), e);
        } finally {
            if (!success) {
                channel.close();
            }
        }
        // Switch to WebSocket
        WsRemoteEndpointImplClient wsRemoteEndpointClient = new WsRemoteEndpointImplClient(channel);
        WsSession wsSession = new WsSession(endpointwsRemoteEndpointClient,
                thisnullnullnullnullnullextensionsAgreed,
                subProtocol, Collections.<String,String>emptyMap(), secure,
                clientEndpointConfiguration);
        WsFrameClient wsFrameClient = new WsFrameClient(responsechannel,
                wsSessiontransformation);
        // WsFrame adds the necessary final transformations. Copy the
        // completed transformation chain to the remote end point.
        wsRemoteEndpointClient.setTransformation(wsFrameClient.getTransformation());
        endpoint.onOpen(wsSessionclientEndpointConfiguration);
        registerSession(endpointwsSession);
        wsFrameClient.startInputProcessing();
        return wsSession;
    }
    protected void registerSession(Endpoint endpointWsSession wsSession) {
        Class<?> endpointClazz = endpoint.getClass();
        if (!wsSession.isOpen()) {
            // The session was closed during onOpen. No need to register it.
            return;
        }
        synchronized () {
            if (.size() == 0) {
                BackgroundProcessManager.getInstance().register(this);
            }
            Set<WsSessionwsSessions = .get(endpointClazz);
            if (wsSessions == null) {
                wsSessions = new HashSet<WsSession>();
                .put(endpointClazzwsSessions);
            }
            wsSessions.add(wsSession);
        }
        .put(wsSessionwsSession);
    }
    protected void unregisterSession(Endpoint endpointWsSession wsSession) {
        Class<?> endpointClazz = endpoint.getClass();
        synchronized () {
            Set<WsSessionwsSessions = .get(endpointClazz);
            if (wsSessions != null) {
                wsSessions.remove(wsSession);
                if (wsSessions.size() == 0) {
                    .remove(endpointClazz);
                }
            }
            if (.size() == 0) {
                BackgroundProcessManager.getInstance().unregister(this);
            }
        }
        .remove(wsSession);
    }
    Set<SessiongetOpenSessions(Class<?> endpoint) {
        HashSet<Sessionresult = new HashSet<Session>();
        synchronized () {
            Set<WsSessionsessions = .get(endpoint);
            if (sessions != null) {
                result.addAll(sessions);
            }
        }
        return result;
    }
    private Map<String,List<String>> createRequestHeaders(String host,
            int portList<StringsubProtocolsList<Extensionextensions) {
        Map<String,List<String>> headers = new HashMap<StringList<String>>();
        // Host header
        List<StringhostValues = new ArrayList<String>(1);
        if (port == -1) {
            hostValues.add(host);
        } else {
            hostValues.add(host + ':' + port);
        }
        headers.put(.hostValues);
        // Upgrade header
        List<StringupgradeValues = new ArrayList<String>(1);
        upgradeValues.add(.);
        headers.put(.upgradeValues);
        // Connection header
        List<StringconnectionValues = new ArrayList<String>(1);
        connectionValues.add(.);
        headers.put(.connectionValues);
        // WebSocket version header
        List<StringwsVersionValues = new ArrayList<String>(1);
        wsVersionValues.add(.);
        headers.put(.wsVersionValues);
        // WebSocket key
        List<StringwsKeyValues = new ArrayList<String>(1);
        wsKeyValues.add(generateWsKeyValue());
        headers.put(.wsKeyValues);
        // WebSocket sub-protocols
        if (subProtocols != null && subProtocols.size() > 0) {
            headers.put(.subProtocols);
        }
        // WebSocket extensions
        if (extensions != null && extensions.size() > 0) {
            headers.put(.,
                    generateExtensionHeaders(extensions));
        }
        return headers;
    }
    private List<StringgenerateExtensionHeaders(List<Extensionextensions) {
        List<Stringresult = new ArrayList<String>(extensions.size());
        for (Extension extension : extensions) {
            StringBuilder header = new StringBuilder();
            header.append(extension.getName());
            for (Extension.Parameter param : extension.getParameters()) {
                header.append(';');
                header.append(param.getName());
                String value = param.getValue();
                if (value != null && value.length() > 0) {
                    header.append('=');
                    header.append(value);
                }
            }
            result.add(header.toString());
        }
        return result;
    }
    private String generateWsKeyValue() {
        byte[] keyBytes = new byte[16];
        .nextBytes(keyBytes);
        return Base64.encodeBase64String(keyBytes);
    }
    private ByteBuffer createRequest(URI uri,
            Map<String,List<String>> reqHeaders) {
        ByteBuffer result = ByteBuffer.allocate(4 * 1024);
        // Request line
        result.put("GET ".getBytes(StandardCharsets.ISO_8859_1));
        result.put(uri.getRawPath().getBytes(StandardCharsets.ISO_8859_1));
        String query = uri.getRawQuery();
        if (query != null) {
            result.put((byte'?');
            result.put(query.getBytes(StandardCharsets.ISO_8859_1));
        }
        result.put(" HTTP/1.1\r\n".getBytes(StandardCharsets.ISO_8859_1));
        // Headers
        Iterator<Entry<String,List<String>>> iter =
                reqHeaders.entrySet().iterator();
        while (iter.hasNext()) {
            Entry<String,List<String>> entry = iter.next();
            addHeader(resultentry.getKey(), entry.getValue());
        }
        // Terminating CRLF
        result.put();
        result.flip();
        return result;
    }
    private void addHeader(ByteBuffer resultString keyList<Stringvalues) {
        StringBuilder sb = new StringBuilder();
        Iterator<Stringiter = values.iterator();
        if (!iter.hasNext()) {
            return;
        }
        sb.append(iter.next());
        while (iter.hasNext()) {
            sb.append(',');
            sb.append(iter.next());
        }
        result.put(key.getBytes(StandardCharsets.ISO_8859_1));
        result.put(": ".getBytes(StandardCharsets.ISO_8859_1));
        result.put(sb.toString().getBytes(StandardCharsets.ISO_8859_1));
        result.put();
    }


    
Process response, blocking until HTTP response has been fully received.

Throws:
ExecutionException
InterruptedException
DeploymentException
TimeoutException
    @SuppressWarnings("null"// line is not null in line.endsWith() call
    private HandshakeResponse processResponse(ByteBuffer response,
            AsyncChannelWrapper channellong timeoutthrows InterruptedException,
            TimeoutException {
        Map<String,List<String>> headers = new HashMap<StringList<String>>();
        boolean readStatus = false;
        boolean readHeaders = false;
        String line = null;
        while (!readHeaders) {
            // On entering loop buffer will be empty and at the start of a new
            // loop the buffer will have been fully read.
            response.clear();
            // Blocking read
            Future<Integerread = channel.read(response);
            Integer bytesRead = read.get(timeout.);
            if (bytesRead.intValue() == -1) {
                throw new EOFException();
            }
            response.flip();
            while (response.hasRemaining() && !readHeaders) {
                if (line == null) {
                    line = readLine(response);
                } else {
                    line += readLine(response);
                }
                if ("\r\n".equals(line)) {
                    readHeaders = true;
                } else if (line.endsWith("\r\n")) {
                    if (readStatus) {
                        parseHeaders(lineheaders);
                    } else {
                        parseStatus(line);
                        readStatus = true;
                    }
                    line = null;
                }
            }
        }
        return new WsHandshakeResponse(headers);
    }
    private void parseStatus(String linethrows DeploymentException {
        // This client only understands HTTP 1.1
        // RFC2616 is case specific
        if (!line.startsWith("HTTP/1.1 101")) {
            throw new DeploymentException(.invalidHttpStatus(line));
        }
    }
    private void parseHeaders(String lineMap<String,List<String>> headers) {
        // Treat headers as single values by default.
        int index = line.indexOf(':');
        if (index == -1) {
            ..invalidHttpHeader(line);
            return;
        }
        // Header names are case insensitive so always use lower case
        String headerName = line.substring(0, index).trim().toLowerCase();
        // TODO handle known multi-value headers
        String headerValue = line.substring(index + 1).trim();
        List<Stringvalues = headers.get(headerName);
        if (values == null) {
            values = new ArrayList<String>(1);
            headers.put(headerNamevalues);
        }
        values.add(headerValue);
    }
    private String readLine(ByteBuffer response) {
        // All ISO-8859-1
        StringBuilder sb = new StringBuilder();
        char c = 0;
        while (response.hasRemaining()) {
            c = (charresponse.get();
            sb.append(c);
            if (c == 10) {
                break;
            }
        }
        return sb.toString();
    }
    private SSLEngine createSSLEngine(Map<String,ObjectuserProperties)
            throws DeploymentException {
        try {
            // See if a custom SSLContext has been provided
            SSLContext sslContext =
                    (SSLContextuserProperties.get();
            if (sslContext == null) {
                // Create the SSL Context
                sslContext = SSLContext.getInstance("TLS");
                // Trust store
                String sslTrustStoreValue =
                        (StringuserProperties.get();
                if (sslTrustStoreValue != null) {
                    String sslTrustStorePwdValue = (StringuserProperties.get(
                            );
                    if (sslTrustStorePwdValue == null) {
                        sslTrustStorePwdValue = ;
                    }
                    
                    File keyStoreFile = new File(sslTrustStoreValue);
                    KeyStore ks = KeyStore.getInstance("JKS");
                    InputStream is = null;
                    try {
                        is = new FileInputStream(keyStoreFile);
                        ks.load(issslTrustStorePwdValue.toCharArray());
                    } finally {
                        if (is != null) {
                            try {
                                is.close();
                            } catch (IOException ioe) {
                               // Ignore
                            }
                        }
                    }
                    TrustManagerFactory tmf = TrustManagerFactory.getInstance(
                            TrustManagerFactory.getDefaultAlgorithm());
                    tmf.init(ks);
                    sslContext.init(nulltmf.getTrustManagers(), null);
                } else {
                    sslContext.init(nullnullnull);
                }
            }
            SSLEngine engine = sslContext.createSSLEngine();
            String sslProtocolsValue =
                    (StringuserProperties.get();
            if (sslProtocolsValue != null) {
                engine.setEnabledProtocols(sslProtocolsValue.split(","));
            }
            engine.setUseClientMode(true);
            return engine;
        } catch (Exception e) {
            throw new DeploymentException(.sslEngineFail(), e);
        }
    }
    @Override
    public long getDefaultMaxSessionIdleTimeout() {
        return ;
    }
    @Override
    public void setDefaultMaxSessionIdleTimeout(long timeout) {
        this. = timeout;
    }
    @Override
    public int getDefaultMaxBinaryMessageBufferSize() {
        return ;
    }
    @Override
    public void setDefaultMaxBinaryMessageBufferSize(int max) {
         = max;
    }
    @Override
    public int getDefaultMaxTextMessageBufferSize() {
        return ;
    }
    @Override
    public void setDefaultMaxTextMessageBufferSize(int max) {
         = max;
    }


    
Currently, this implementation does not support any extensions.
    @Override
    public Set<ExtensiongetInstalledExtensions() {
        return Collections.emptySet();
    }


    
The default value for this implementation is -1.
    @Override
    public long getDefaultAsyncSendTimeout() {
        return ;
    }


    
The default value for this implementation is -1.
    @Override
    public void setAsyncSendTimeout(long timeout) {
        this. = timeout;
    }


    
Cleans up the resources still in use by WebSocket sessions created from this container. This includes closing sessions and cancelling Futures associated with blocking read/writes.
    public void destroy() {
        CloseReason cr = new CloseReason(
                ..webappStopping());
        for (WsSession session : .keySet()) {
            try {
                session.close(cr);
            } catch (IOException ioe) {
                ..sessionCloseFailed(session.getId(), ioe);
            }
        }
        // Only unregister with AsyncChannelGroupUtil if this instance
        // registered with it
        if ( != null) {
            synchronized () {
                if ( != null) {
                    AsyncChannelGroupUtil.unregister();
                     = null;
                }
            }
        }
    }
    private AsynchronousChannelGroup getAsynchronousChannelGroup() {
        // Use AsyncChannelGroupUtil to share a common group amongst all
        // WebSocket clients
        AsynchronousChannelGroup result = ;
        if (result == null) {
            synchronized () {
                if ( == null) {
                     = AsyncChannelGroupUtil.register();
                }
                result = ;
            }
        }
        return result;
    }
    // ----------------------------------------------- BackgroundProcess methods
    @Override
    public void backgroundProcess() {
        // This method gets called once a second.
         ++;
        if ( >= ) {
             = 0;
            for (WsSession wsSession : .keySet()) {
                wsSession.checkExpiration();
            }
        }
    }
    @Override
    public void setProcessPeriod(int period) {
        this. = period;
    }


    
The default value is 10 which means session expirations are processed every 10 seconds.
    @Override
    public int getProcessPeriod() {
        return ;
    }
        return ;
    }
    public ClassLoader getClassLoader() {
        return WsWebSocketContainer.class.getClassLoader();
    }
New to GrepCode? Check out our FAQ X