All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.everrest.websockets.WSConnectionImpl Maven / Gradle / Ivy

There is a newer version: 1.15.0
Show newest version
/*******************************************************************************
 * Copyright (c) 2012-2016 Codenvy, S.A.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Codenvy, S.A. - initial API and implementation
 *******************************************************************************/
package org.everrest.websockets;

import org.everrest.core.impl.EverrestProcessor;
import org.everrest.websockets.message.MessageSender;
import org.everrest.websockets.message.OutputMessage;
import org.everrest.websockets.message.RestInputMessage;

import javax.servlet.http.HttpSession;
import javax.websocket.CloseReason;
import javax.websocket.DecodeException;
import javax.websocket.EncodeException;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import javax.ws.rs.core.SecurityContext;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicLong;

import static javax.websocket.CloseReason.CloseCodes.getCloseCode;
import static org.everrest.websockets.ServerContainerInitializeListener.EVERREST_PROCESSOR_ATTRIBUTE;
import static org.everrest.websockets.ServerContainerInitializeListener.EXECUTOR_ATTRIBUTE;
import static org.everrest.websockets.ServerContainerInitializeListener.HTTP_SESSION_ATTRIBUTE;
import static org.everrest.websockets.ServerContainerInitializeListener.SECURITY_CONTEXT;

public class WSConnectionImpl extends Endpoint implements WSConnection {
    private static final AtomicLong counter = new AtomicLong(1);

    private final long id = counter.getAndIncrement();
    private final List messageReceivers;
    private final Set             channels;
    private final Map     attributes;

    private Session       wsSession;
    private HttpSession   httpSession;
    private CloseReason   closeReason;
    private MessageSender messageSender;

    public WSConnectionImpl() {
        this.messageReceivers = new CopyOnWriteArrayList<>();
        this.channels = new CopyOnWriteArraySet<>();
        this.attributes = new HashMap<>();
    }

    @Override
    public void onOpen(Session session, EndpointConfig config) {
        wsSession = session;
        messageSender = new MessageSender(session);
        final Map userProperties = config.getUserProperties();
        httpSession = (HttpSession)userProperties.get(HTTP_SESSION_ATTRIBUTE);
        final WS2RESTAdapter restAdapter =
                new WS2RESTAdapter(this,
                                   (SecurityContext)userProperties.get(SECURITY_CONTEXT),
                                   (EverrestProcessor)userProperties.get(EVERREST_PROCESSOR_ATTRIBUTE),
                                   (Executor)userProperties.get(EXECUTOR_ATTRIBUTE));
        messageReceivers.add(restAdapter);
        wsSession.addMessageHandler(RestInputMessage.class, new MessageHandler.Whole() {
            @Override
            public void onMessage(RestInputMessage message) {
                for (WSMessageReceiver receiver : messageReceivers) {
                    receiver.onMessage(message);
                }
            }
        });

        for (WSConnectionListener connectionListener : WSConnectionContext.connectionListeners) {
            connectionListener.onOpen(this);
        }

        WSConnectionContext.connections.put(getId(), this);
    }

    @Override
    public void onClose(Session session, CloseReason closeReason) {
        this.closeReason = closeReason;
        for (WSConnectionListener connectionListener : WSConnectionContext.connectionListeners) {
            connectionListener.onClose(this);
        }
        super.onClose(session, closeReason);
    }


    @Override
    public void onError(Session session, Throwable thr) {
        if (thr instanceof DecodeException) {
            for (WSMessageReceiver receiver : messageReceivers) {
                receiver.onError((DecodeException)thr);
            }
        }
        super.onError(session, thr);
    }

    @Override
    public Long getId() {
        return id;
    }

    @Override
    public HttpSession getHttpSession() {
        return httpSession;
    }

    @Override
    public Session getWsSession() {
        return wsSession;
    }

    @Override
    public boolean subscribeToChannel(String channel) {
        if (channel == null) {
            throw new IllegalArgumentException("Channel name may not be null. ");
        }
        return channels.add(channel);
    }

    @Override
    public boolean unsubscribeFromChannel(String channel) {
        if (channel == null) {
            throw new IllegalArgumentException("Channel name may not be null. ");
        }
        return channels.remove(channel);
    }

    @Override
    public Collection getChannels() {
        return channels;
    }

    @Override
    public boolean isConnected() {
        return wsSession != null && wsSession.isOpen();
    }

    @Override
    public void close() throws IOException {
        if (isConnected()) {
            wsSession.close();
        }
    }

    @Override
    public void close(int status, String message) throws IOException {
        if (isConnected()) {
            wsSession.close(new CloseReason(getCloseCode(status), message));
        }
    }

    @Override
    public int getCloseStatus() {
        return closeReason == null ? 0 : closeReason.getCloseCode().getCode();
    }

    @Override
    public void sendMessage(OutputMessage output) throws EncodeException, IOException {
        checkIsConnected();
        messageSender.send(output);
    }

    private void checkIsConnected() {
        if (!isConnected()) {
            throw new IllegalStateException("Unable send message because the WebSocket connection has been closed");
        }
    }

    @Override
    public void registerMessageReceiver(WSMessageReceiver messageReceiver) {
        messageReceivers.add(messageReceiver);
    }

    @Override
    public void removeMessageReceiver(WSMessageReceiver messageReceiver) {
        messageReceivers.remove(messageReceiver);
    }

    @Override
    public Object getAttribute(String name) {
        return attributes.get(name);
    }

    @Override
    public void setAttribute(String name, Object value) {
        attributes.put(name, value);
    }

    @Override
    public void removeAttribute(String name) {
        attributes.remove(name);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder().append("WSConnectionImpl{")
                                              .append("id=").append(id)
                                              .append(", wsSession=").append(wsSession.getId());
        if (httpSession != null) {
            sb.append(", httpSession=").append(httpSession.getId());
        }
        sb.append(", channels=").append(channels).append('}');
        return sb.toString();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy