cito.server.AbstractEndpoint.java Source code

Java tutorial

Introduction

Here is the source code for cito.server.AbstractEndpoint.java

Source

/*
 * Copyright 2016-2017 Daniel Siviter
 *
 * Licensed 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 cito.server;

import static cito.server.Extension.webSocketContext;
import static java.lang.String.format;

import java.io.IOException;

import javax.enterprise.event.Event;
import javax.enterprise.inject.spi.BeanManager;
import javax.inject.Inject;
import javax.websocket.CloseReason;
import javax.websocket.CloseReason.CloseCodes;
import javax.websocket.EncodeException;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.PongMessage;
import javax.websocket.Session;
import javax.ws.rs.core.MediaType;

import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;

import cito.QuietClosable;
import cito.annotation.FromClient;
import cito.event.ClientMessageProducer;
import cito.event.Message;
import cito.scope.WebSocketContext;
import cito.server.ws.WebSocketConfigurator;
import cito.stomp.Frame;
import cito.stomp.jms.Relay;

/**
 * 
 * @author Daniel Siviter
 * @since v1.0 [15 Jul 2016]
 */
public abstract class AbstractEndpoint extends Endpoint {
    @Inject
    protected Logger log;
    @Inject
    private BeanManager beanManager;
    @Inject
    private SessionRegistry registry;
    @Inject
    private Relay relay;
    @Inject
    @FromClient
    private Event<Message> messageEvent;
    @Inject
    private Event<Session> sessionEvent;
    @Inject
    private Event<Throwable> errorEvent;
    @Inject
    private RttService rttService;

    @OnOpen
    @Override
    public void onOpen(Session session, EndpointConfig config) {
        final String httpSessionId = session.getRequestParameterMap().get("httpSessionId").get(0);
        this.log.info("WebSocket connection opened. [id={},httpSessionId={},principle={}]", session.getId(),
                httpSessionId, session.getUserPrincipal());
        final SecurityContext securityCtx = WebSocketConfigurator.removeSecurityContext(config.getUserProperties(),
                httpSessionId);
        SecurityContextProducer.set(session, securityCtx);
        try (QuietClosable c = webSocketContext(this.beanManager).activate(session)) {
            this.registry.register(session);
            this.sessionEvent.select(cito.annotation.OnOpen.Literal.onOpen()).fire(session);
        }

        this.rttService.start(session);
    }

    /**
     * 
     * @param session
     * @param msg
     */
    @OnMessage
    public void pong(Session session, PongMessage msg) {
        try (QuietClosable c = webSocketContext(this.beanManager).activate(session)) {
            this.rttService.pong(session, msg);
        }
    }

    /**
     * 
     * @param session
     * @param frame
     */
    @OnMessage
    public void message(Session session, Frame frame) {
        final String sessionId = session.getId();
        this.log.debug("Received message from client. [id={},principle={},command={}]", sessionId,
                session.getUserPrincipal(), frame.command());
        try (QuietClosable c = webSocketContext(this.beanManager).activate(session)) {
            final Message event = new Message(sessionId, frame);
            try (QuietClosable closable = ClientMessageProducer.set(event)) {
                this.relay.fromClient(event); // due to no @Observe @Priority we need to ensure the relay gets this first
                this.messageEvent.fire(event);
            }
        }
    }

    @OnError
    @Override
    public void onError(Session session, Throwable cause) {
        final String errorId = RandomStringUtils.randomAlphanumeric(8).toUpperCase();
        this.log.warn("WebSocket error. [id={},principle={},errorId={}]", session.getId(),
                session.getUserPrincipal(), errorId, cause);
        try (QuietClosable c = webSocketContext(this.beanManager).activate(session)) {
            this.errorEvent.select(cito.annotation.OnError.Literal.onError()).fire(cause);
            final Frame errorFrame = Frame.error()
                    .body(MediaType.TEXT_PLAIN_TYPE, format("%s [errorId=%s]", cause.getMessage(), errorId))
                    .build();
            session.getBasicRemote().sendObject(errorFrame);
            session.close(
                    new CloseReason(CloseCodes.PROTOCOL_ERROR, format("See server log. [errorId=%s]", errorId)));
        } catch (IOException | EncodeException e) {
            this.log.error("Unable to send error frame! [id={},principle={}]", session.getId(),
                    session.getUserPrincipal(), e);
        }
    }

    @OnClose
    @Override
    public void onClose(Session session, CloseReason reason) {
        this.log.info("WebSocket connection closed. [id={},principle={},code={},reason={}]", session.getId(),
                session.getUserPrincipal(), reason.getCloseCode(), reason.getReasonPhrase());
        final WebSocketContext ctx = webSocketContext(this.beanManager);
        try (QuietClosable c = ctx.activate(session)) {
            this.registry.unregister(session);
            this.sessionEvent.select(cito.annotation.OnClose.Literal.onClose()).fire(session);
        }
        ctx.dispose(session);
    }
}