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.net.URI;
 import  java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
 
 
 public class WsSession implements Session {
 
     // An ellipsis is a single character that looks like three periods in a row
     // and is used to indicate a continuation.
     private static final byte[] ELLIPSIS_BYTES =
             "\u2026".getBytes(StandardCharsets.UTF_8);
     // An ellipsis is three bytes in UTF-8
     private static final int ELLIPSIS_BYTES_LEN = .;
 
     private static AtomicLong ids = new AtomicLong(0);
 
     private final Endpoint localEndpoint;
     private final WsRemoteEndpointImplBase wsRemoteEndpoint;
     private final RemoteEndpoint.Async remoteEndpointAsync;
     private final RemoteEndpoint.Basic remoteEndpointBasic;
     private final ClassLoader applicationClassLoader;
     private final WsWebSocketContainer webSocketContainer;
     private final URI requestUri;
     private final Map<String,List<String>> requestParameterMap;
     private final String queryString;
     private final Principal userPrincipal;
     private final EndpointConfig endpointConfig;
 
     private final List<ExtensionnegotiatedExtensions;
     private final String subProtocol;
     private final Map<String,StringpathParameters;
     private final boolean secure;
     private final String httpSessionId;
     private final String id;
 
     // Expected to handle message types of <String> only
     private MessageHandler textMessageHandler = null;
     // Expected to handle message types of <ByteBuffer> only
     private MessageHandler binaryMessageHandler = null;
     private MessageHandler.Whole<PongMessagepongMessageHandler = null;
     private volatile State state = .;
     private final Object stateLock = new Object();
     private final Map<String,ObjectuserProperties = new ConcurrentHashMap<StringObject>();
     private volatile int maxBinaryMessageBufferSize =
             .;
     private volatile int maxTextMessageBufferSize =
             .;
     private volatile long maxIdleTimeout = 0;
     private volatile long lastActive = System.currentTimeMillis();
             new ConcurrentHashMap<FutureToSendHandler,FutureToSendHandler>();

    
Creates a new WebSocket session for communication between the two provided end points. The result of Thread.getContextClassLoader() at the time this constructor is called will be used when calling Endpoint.onClose(Session, CloseReason).

Parameters:
localEndpoint
wsRemoteEndpoint
negotiatedExtensions
Throws:
DeploymentException
    public WsSession(Endpoint localEndpoint,
            WsRemoteEndpointImplBase wsRemoteEndpoint,
            WsWebSocketContainer wsWebSocketContainer,
            URI requestUriMap<String,List<String>> requestParameterMap,
            String queryStringPrincipal userPrincipalString httpSessionId,
            List<ExtensionnegotiatedExtensionsString subProtocolMap<String,StringpathParameters,
            boolean secureEndpointConfig endpointConfigthrows DeploymentException {
        this. = localEndpoint;
        this. = wsRemoteEndpoint;
        this..setSession(this);
        this. = new WsRemoteEndpointAsync(wsRemoteEndpoint);
        this. = new WsRemoteEndpointBasic(wsRemoteEndpoint);
        this. = wsWebSocketContainer;
        wsRemoteEndpoint.setSendTimeout(
                wsWebSocketContainer.getDefaultAsyncSendTimeout());
        this. =
        this. =
        this. =
                .getDefaultMaxSessionIdleTimeout();
        this. = requestUri;
        if (requestParameterMap == null) {
            this. = Collections.emptyMap();
        } else {
            this. = requestParameterMap;
        }
        this. = queryString;
        this. = userPrincipal;
        this. = httpSessionId;
        this. = negotiatedExtensions;
        if (subProtocol == null) {
            this. = "";
        } else {
            this. = subProtocol;
        }
        this. = pathParameters;
        this. = secure;
        this..setEncoders(endpointConfig);
        this. = endpointConfig;
        this..putAll(endpointConfig.getUserProperties());
        this. = Long.toHexString(.getAndIncrement());
    }
    @Override
    public WebSocketContainer getContainer() {
        checkState();
        return ;
    }
    @Override
    public void addMessageHandler(MessageHandler listener) {
        Class<?> target = Util.getMessageType(listener);
        doAddMessageHandler(targetlistener);
    }
    public <T> void addMessageHandler(Class<T> clazzPartial<T> handler)
            throws IllegalStateException {
        doAddMessageHandler(clazzhandler);
    }
    public <T> void addMessageHandler(Class<T> clazzWhole<T> handler)
            throws IllegalStateException {
        doAddMessageHandler(clazzhandler);
    }
    @SuppressWarnings("unchecked")
    private void doAddMessageHandler(Class<?> targetMessageHandler listener) {
        checkState();
        // Message handlers that require decoders may map to text messages,
        // binary messages, both or neither.
        // The frame processing code expects binary message handlers to
        // accept ByteBuffer
        // Use the POJO message handler wrappers as they are designed to wrap
        // arbitrary objects with MessageHandlers and can wrap MessageHandlers
        // just as easily.
        Set<MessageHandlerResultmhResults =
                Util.getMessageHandlers(targetlistenerthis);
        for (MessageHandlerResult mhResult : mhResults) {
            switch (mhResult.getType()) {
                case : {
                    if ( != null) {
                        throw .duplicateHandlerText();
                    }
                     = mhResult.getHandler();
                    break;
                }
                case : {
                    if ( != null) {
                        throw .duplicateHandlerBinary();
                    }
                     = mhResult.getHandler();
                    break;
                }
                case : {
                    if ( != null) {
                        throw .duplicateHandlerPong();
                    }
                    MessageHandler handler = mhResult.getHandler();
                    if (handler instanceof MessageHandler.Whole<?>) {
                         =
                                (MessageHandler.Whole<PongMessage>) handler;
                    } else {
                        throw .invalidHandlerPong();
                    }
                    break;
                }
                default: {
                    throw .invalidMessageHandler(listener,
                            mhResult.getType());
                }
            }
        }
    }
    @Override
        checkState();
        Set<MessageHandlerresult = new HashSet<MessageHandler>();
        if ( != null) {
            result.add();
        }
        if ( != null) {
            result.add();
        }
        if ( != null) {
            result.add();
        }
        return result;
    }
    @Override
    public void removeMessageHandler(MessageHandler listener) {
        checkState();
        if (listener == null) {
            return;
        }
        MessageHandler wrapped = null;
        if (listener instanceof WrappedMessageHandler) {
            wrapped = ((WrappedMessageHandlerlistener).getWrappedHandler();
        }
        if (wrapped == null) {
            wrapped = listener;
        }
        boolean removed = false;
        if (wrapped.equals() ||
                listener.equals()) {
             = null;
            removed = true;
        }
        if (listener.equals() ||
                listener.equals()) {
             = null;
            removed = true;
        }
        if (listener.equals() ||
                listener.equals()) {
             = null;
            removed = true;
        }
        if (!removed) {
            // ISE for now. Could swallow this silently / log this if the ISE
            // becomes a problem
            throw .cannotRemoveHandler(listener);
        }
    }
    @Override
    public String getProtocolVersion() {
        checkState();
        return .;
    }
    @Override
    public String getNegotiatedSubprotocol() {
        checkState();
        return ;
    }
    @Override
        checkState();
        return ;
    }
    @Override
    public boolean isSecure() {
        checkState();
        return ;
    }
    @Override
    public boolean isOpen() {
        return  == .;
    }
    @Override
    public long getMaxIdleTimeout() {
        checkState();
        return ;
    }
    @Override
    public void setMaxIdleTimeout(long timeout) {
        checkState();
        this. = timeout;
    }
    @Override
    public void setMaxBinaryMessageBufferSize(int max) {
        checkState();
        this. = max;
    }
    @Override
    public int getMaxBinaryMessageBufferSize() {
        checkState();
        return ;
    }
    @Override
    public void setMaxTextMessageBufferSize(int max) {
        checkState();
        this. = max;
    }
    @Override
    public int getMaxTextMessageBufferSize() {
        checkState();
        return ;
    }
    @Override
    public Set<SessiongetOpenSessions() {
        checkState();
    }
    @Override
    public RemoteEndpoint.Async getAsyncRemote() {
        checkState();
        return ;
    }
    @Override
    public RemoteEndpoint.Basic getBasicRemote() {
        checkState();
        return ;
    }
    @Override
    public void close() throws IOException {
        close(new CloseReason(.""));
    }
    @Override
    public void close(CloseReason closeReasonthrows IOException {
        doClose(closeReasoncloseReason);
    }


    
WebSocket 1.0. Section 2.1.5. Need internal close method as spec requires that the local endpoint receives a 1006 on timeout.
    private void doClose(CloseReason closeReasonMessage,
            CloseReason closeReasonLocal) {
        // Double-checked locking. OK because state is volatile
        if ( != .) {
            return;
        }
        synchronized () {
            if ( != .) {
                return;
            }
            try {
                .setBatchingAllowed(false);
            } catch (IOException e) {
                ..flushOnCloseFailed(e);
                fireEndpointOnError(e);
            }
             = .;
            if (!.) {
                sendCloseMessage(closeReasonMessage);
                fireEndpointOnClose(closeReasonLocal);
            } else {
                fireEndpointOnClose(closeReasonLocal);
                sendCloseMessage(closeReasonMessage);
            }
             = .;
        }
        IOException ioe = new IOException(.messageFailed());
        SendResult sr = new SendResult(ioe);
        for (FutureToSendHandler f2sh : .keySet()) {
            f2sh.onResult(sr);
        }
    }


    
Called when a close message is received. Should only ever happen once. Also called after a protocol error when the ProtocolHandler needs to force the closing of the connection.
    public void onClose(CloseReason closeReason) {
        synchronized () {
            if ( == .) {
                try {
                    .setBatchingAllowed(false);
                } catch (IOException e) {
                    ..flushOnCloseFailed(e);
                    fireEndpointOnError(e);
                }
                if (!.) {
                    sendCloseMessage(closeReason);
                    fireEndpointOnClose(closeReason);
                } else {
                    fireEndpointOnClose(closeReason);
                    sendCloseMessage(closeReason);
                }
                 = .;
            }
            // Close the socket
            .close();
        }
    }
    private void fireEndpointOnClose(CloseReason closeReason) {
        // Fire the onClose event
        Thread t = Thread.currentThread();
        ClassLoader cl = t.getContextClassLoader();
        try {
            .onClose(thiscloseReason);
        } catch (Throwable throwable) {
            ExceptionUtils.handleThrowable(throwable);
            .onError(thisthrowable);
        } finally {
            t.setContextClassLoader(cl);
        }
    }
    private void fireEndpointOnError(Throwable throwable) {
        // Fire the onError event
        Thread t = Thread.currentThread();
        ClassLoader cl = t.getContextClassLoader();
        try {
            .onError(thisthrowable);
        } finally {
            t.setContextClassLoader(cl);
        }
    }
    private void sendCloseMessage(CloseReason closeReason) {
        // 125 is maximum size for the payload of a control message
        ByteBuffer msg = ByteBuffer.allocate(125);
        CloseCode closeCode = closeReason.getCloseCode();
        // CLOSED_ABNORMALLY should not be put on the wire
        if (closeCode == .) {
            // PROTOCOL_ERROR is probably better than GOING_AWAY here
            msg.putShort((short..getCode());
        } else {
            msg.putShort((shortcloseCode.getCode());
        }
        String reason = closeReason.getReasonPhrase();
        if (reason != null && reason.length() > 0) {
            appendCloseReasonWithTruncation(msgreason);
        }
        msg.flip();
        try {
            .startMessageBlock(
                    .msgtrue);
        } catch (IOException ioe) {
            // Failed to send close message. Close the socket and let the caller
            // deal with the Exception
            ..closeMessageFail(ioe);
            .close();
            // Failure to send a close message is not unexpected in the case of
            // an abnormal closure (usually triggered by a failure to read/write
            // from/to the client. In this case do not trigger the endpoint's
            // error handling
            if (closeCode != .) {
                .onError(thisioe);
            }
        } finally {
            .unregisterSession(this);
        }
    }


    
Use protected so unit tests can access this method directly.
    protected static void appendCloseReasonWithTruncation(ByteBuffer msg,
            String reason) {
        // Once the close code has been added there are a maximum of 123 bytes
        // left for the reason phrase. If it is truncated then care needs to be
        // taken to ensure the bytes are not truncated in the middle of a
        // multi-byte UTF-8 character.
        byte[] reasonBytes = reason.getBytes(StandardCharsets.UTF_8);
        if (reasonBytes.length  <= 123) {
            // No need to truncate
            msg.put(reasonBytes);
        } else {
            // Need to truncate
            int remaining = 123 - ;
            int pos = 0;
            byte[] bytesNext = reason.substring(pospos + 1).getBytes(
                    StandardCharsets.UTF_8);
            while (remaining >= bytesNext.length) {
                msg.put(bytesNext);
                remaining -= bytesNext.length;
                pos++;
                bytesNext = reason.substring(pospos + 1).getBytes(
                        StandardCharsets.UTF_8);
            }
            msg.put();
        }
    }


    
Make the session aware of a FutureToSendHandler that will need to be forcibly closed if the session closes before the FutureToSendHandler completes.
    protected void registerFuture(FutureToSendHandler f2sh) {
        .put(f2shf2sh);
    }


    
Remove a FutureToSendHandler from the set of tracked instances.
    protected void unregisterFuture(FutureToSendHandler f2sh) {
        .remove(f2sh);
    }
    @Override
    public URI getRequestURI() {
        checkState();
        return ;
    }
    @Override
        checkState();
        return ;
    }
    @Override
    public String getQueryString() {
        checkState();
        return ;
    }
    @Override
    public Principal getUserPrincipal() {
        checkState();
        return ;
    }
    @Override
    public Map<String,StringgetPathParameters() {
        checkState();
        return ;
    }
    @Override
    public String getId() {
        return ;
    }
    @Override
    public Map<String,ObjectgetUserProperties() {
        checkState();
        return ;
    }
    public Endpoint getLocal() {
        return ;
    }
    public String getHttpSessionId() {
        return ;
    }
    protected MessageHandler getTextMessageHandler() {
        return ;
    }
        return ;
    }
        return ;
    }
    protected void updateLastActive() {
         = System.currentTimeMillis();
    }
    protected void checkExpiration() {
        long timeout = ;
        if (timeout < 1) {
            return;
        }
        if (System.currentTimeMillis() -  > timeout) {
            String msg = .sessionTimeout();
            doClose(new CloseReason(.msg),
                    new CloseReason(.msg));
        }
    }
    private void checkState() {
        if ( == .) {
            throw .sessionAlreadyClosed();
        }
    }
    }
    public ClassLoader getClassLoader() {
        return .getClassLoader();
    }
    private static enum State {
        OPEN,
        CLOSING,
        CLOSED
    }
New to GrepCode? Check out our FAQ X