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

com.github.czyzby.websocket.WebSocketHandler Maven / Gradle / Ivy

package com.github.czyzby.websocket;

import com.badlogic.gdx.utils.ObjectMap;
import com.github.czyzby.websocket.data.WebSocketException;

/** This is the proposed implementation of a {@link WebSocketListener} when using communicating with the server using
 * serialized objects rather than raw strings or bytes. Instead of forcing the user to determine packet type manually
 * (with {@code instanceof} or class comparing), this listener allows to register {@link Handler handlers} to each
 * packet type - when the selected type of packet is received, registered handler will be invoked. This allows to build
 * applications using event-driven approach. Errors during packet handling are delegated to
 * {@link #onError(WebSocket, Throwable)} method rather than rethrown.
 *
 * @author MJ
 * @see #registerHandler(Class, Handler)
 * @see Handler */
public class WebSocketHandler extends AbstractWebSocketListener {
    /** Maps class of expected packets to their handlers. */
    private final ObjectMap, Handler> handlers = new ObjectMap, Handler>();
    /** Used as default value when invoking {@link ObjectMap#get(Object, Object)} on {@link #handlers} to prevent
     * NPE. */
    private final Handler unknown = new Handler() {
        @Override
        public boolean handle(final WebSocket webSocket, final Object packet) {
            if (failIfNoHandler) {
                onError(webSocket, new WebSocketException("Unknown packet type: " + packet.getClass()));
            }
            return NOT_HANDLED;
        }
    };
    private boolean failIfNoHandler = true;

    /** @param packetClass class of the packet that should be passed to the selected handler.
     * @param handler will be notified when the chosen type of packet is received. Should be prepared to handle the
     *            specific packet class, otherwise {@link ClassCastException} might be thrown. */
    @SuppressWarnings("unchecked")
    public void registerHandler(final Class packetClass, final Handler handler) {
        handlers.put(packetClass, (Handler) handler);
    }

    /** @param failIfNoHandler if true and a web socket receives packet that has no handler registered to its class, an
     *            exception will passed to {@link #onError(WebSocket, Throwable)} method. Defaults to true. */
    public void setFailIfNoHandler(final boolean failIfNoHandler) {
        this.failIfNoHandler = failIfNoHandler;
    }

    @Override
    protected boolean onMessage(final WebSocket webSocket, final Object packet) throws WebSocketException {
        try {
            return handlers.get(packet.getClass(), unknown).handle(webSocket, packet);
        } catch (final Exception exception) {
            return onError(webSocket,
                    new WebSocketException("Unable to handle the received packet: " + packet, exception));
        }
    }

    /** Common interface for handlers that consume a specific type of packets.
     *
     * @author MJ
     *
     * @param  type of handled packets.
     * @see EmptyHandler */
    public static interface Handler {
        /** Should perform the logic using the received packet.
         *
         * @param webSocket this socket received the packet.
         * @param packet the deserialized packet instance.
         * @return true if message was fully handled and other web socket listeners should not be notified.
         * @see WebSocketListener#FULLY_HANDLED
         * @see WebSocketListener#NOT_HANDLED */
        boolean handle(WebSocket webSocket, Packet packet);
    }

    /** A simple {@link Handler} implementation that does nothing.
     *
     * @author MJ */
    public static class EmptyHandler implements Handler {
        @Override
        public boolean handle(final WebSocket webSocket, final Object packet) {
            return NOT_HANDLED;
        }
    }
}