001package systems.dmx.core.impl;
002
003import systems.dmx.core.service.CoreService;
004
005import org.eclipse.jetty.websocket.WebSocket;
006import org.eclipse.jetty.websocket.WebSocket.Connection;
007
008import java.util.logging.Level;
009import java.util.logging.Logger;
010
011
012
013/**
014 * A WebSocket connection that is bound to a DMX plugin.
015 * When a message arrives on the connection the plugin is notified via a WEBSOCKET_TEXT_MESSAGE event.
016 * <p>
017 * Once the actual WebSocket connection is opened or closed the WebSocketConnection is added/removed to a pool.
018 */
019class WebSocketConnection implements WebSocket, WebSocket.OnTextMessage, WebSocket.OnBinaryMessage {
020
021    // ---------------------------------------------------------------------------------------------- Instance Variables
022
023    String pluginUri;
024    String sessionId;
025
026    /**
027     * The underlying Jetty WebSocket connection.
028     */
029    private Connection connection;
030
031    private WebSocketConnectionPool pool;
032    private CoreService dmx;
033
034    private Logger logger = Logger.getLogger(getClass().getName());
035
036    // ----------------------------------------------------------------------------------------------------- Constructor
037
038    WebSocketConnection(String pluginUri, String sessionId, WebSocketConnectionPool pool, CoreService dmx) {
039        this.pluginUri = pluginUri;
040        this.sessionId = sessionId;
041        this.pool = pool;
042        this.dmx = dmx;
043    }
044
045    // -------------------------------------------------------------------------------------------------- Public Methods
046
047    // *** WebSocket ***
048
049    @Override
050    public void onOpen(Connection connection) {
051        logger.info("Opening a WebSocket connection for plugin \"" + pluginUri + "\" (session " + sessionId + ")");
052        this.connection = connection;
053        pool.add(this);
054    }
055
056    @Override
057    public void onClose(int code, String message) {
058        logger.info("Closing a WebSocket connection of plugin \"" + pluginUri + "\" (session " + sessionId + ")");
059        pool.remove(this);
060    }
061
062    // *** WebSocket.OnTextMessage ***
063
064    @Override
065    public void onMessage(String message) {
066        try {
067            dmx.dispatchEvent(pluginUri, CoreEvent.WEBSOCKET_TEXT_MESSAGE, message);
068        } catch (Exception e) {
069            // Note: we don't rethrow to Jetty here. It would not log the exception's cause. DM's exception
070            // mapper would not kick in either as the plugin is called from Jetty directly, not Jersey.
071            logger.log(Level.SEVERE, "An error occurred while dispatching a WebSocket message to plugin \"" +
072                pluginUri + "\":", e);
073        }
074    }
075
076    // *** WebSocket.OnBinaryMessage ***
077
078    @Override
079    public void onMessage(byte[] data, int offset, int length) {
080        // ### TODO
081    }
082
083    // ----------------------------------------------------------------------------------------- Package Private Methods
084
085    void sendMessage(String message) {
086        try {
087            connection.sendMessage(message);
088        } catch (Exception e) {
089            pool.remove(this);
090            logger.log(Level.SEVERE, "Sending message via " + this + " failed -- connection removed", e);
091        }
092    }
093}