вторник, 31 марта 2015 г.

Java Client WebSockets


Java Client WebSockets

Собственно решил сделать небольшую заметку про websocketы,а точнее реализация их клиентов на Java,серверной части тут не будет(она особо нам и не нужна для наших целей),
зато будут 2 реализации,кому какая больше нравится.
Итак,коротко что такое WebSocket:
WebSocket — протокол полнодуплексной связи поверх TCP-соединения, предназначенный для обмена сообщениями между браузером и веб-сервером в режиме реального времени.
Можно даже не до конца понимать определение из википедии,чтобы понять насколько широкие горизонты в разработке и тестировании открывает эта технология.
Сейчас напишем пару клиентских программ использующих вебсокет для соединения с сервером.
1й варинт.
Добавляем в pom.xml

 
        
            javax.websocket
            javax.websocket-client-api
            1.0
        
        
            org.glassfish.tyrus
            tyrus-client
            1.1
        
        
            org.glassfish.tyrus
            tyrus-container-grizzly
            1.1
        

И код самого клиента

 
@ClientEndpoint(configurator = WebSocketClientEndpoint.Configurator.class)
public class WebSocketClientEndpoint {
    private Logger logger = Logger.getLogger(WebSocketClientEndpoint.class);
    Session userSession = null;
    private MessageHandler messageHandler;

    public static class Configurator extends javax.websocket.ClientEndpointConfig.Configurator {
        static String cookiesConf;

        public static void addCookie(String cookies) {
            cookiesConf = cookies;
        }

        @Override
        public void beforeRequest(Map> headers) {
            headers.put("Cookie", Collections.singletonList(cookiesConf));
            super.beforeRequest(headers);
        }
    }

    public WebSocketClientEndpoint(String host, String port) {
        try {
            WebSocketContainer container = ContainerProvider.getWebSocketContainer();
            container.connectToServer(this, URI.create("ws://" + host + ":" + port));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @OnError
    public void onError(Throwable t) {
        t.printStackTrace();
    }

    /**
     * Callback hook for Connection open events.
     *
     * @param userSession the userSession which is opened.
     */
    @OnOpen
    public void onOpen(Session userSession) {
        logger.info("Opening WS");
        this.userSession = userSession;

    }

    /**
     * Callback hook for Connection close events.
     *
     * @param userSession the userSession which is getting closed.
     * @param reason      the reason for connection close
     */
    @OnClose
    public void onClose(Session userSession, CloseReason reason) {
        logger.info("Closing WS");
        this.userSession = null;
    }

    /**
     * Callback hook for Message Events. This method will be invoked when a client send a message.
     *
     * @param message The text message
     */
    @OnMessage
    public void onMessage(String message) {
        if (this.messageHandler != null) this.messageHandler.handleMessage(message);
    }

    /**
     * register message handler
     */
    public WebSocketClientEndpoint addMessageHandler(MessageHandler msgHandler) {
        this.messageHandler = msgHandler;
        return this;
    }

    /**
     * Send a message.
     *
     * @param message
     */
    public WebSocketClientEndpoint sendMessage(String message) {
        this.userSession.getAsyncRemote().sendText(message);
        if (this.messageHandler != null) this.messageHandler.handleMessage(message);
        return this;
    }


    public interface MessageHandler {
        void handleMessage(String message);
    }
}

И пользуемся им как то так:

 
     WebsocketClientEndpoint clientEndPoint = new WebsocketClientEndpoint(new URI("ws://test.dev:8080"));
            // add listener
            clientEndPoint.addMessageHandler(message -> System.out.println(message));
            // send message to websocket
            clientEndPoint.sendMessage("{'event':'Hello world!'}");


Вроде удобно,просто и быстро.Но мне понадобилась поддержка cookie и  в данной реализации это создает определенные сложности(вроде статического класса конфигуратора),так что я использовал 2й вариант на jetty.
Добавляем в pom.xml


 

        
            org.eclipse.jetty.aggregate
            jetty-all-server
            8.1.16.v20140903
        
        
            org.eclipse.jetty.websocket
            websocket-client
            9.2.10.v20150310
        

И код самого клиента:

 
public class ClientWebSocket {
    private Logger logger = Logger.getLogger(ClientWebSocket.class);
    private WebSocket.Connection connection;
    private WebSocketClient client;
    private WebSocketClientFactory factory;

    ClientWebSocket() {
        factory = new WebSocketClientFactory();
        try {
            factory.start();
        } catch (Exception e) {
            logger.info("Factory start problem");
        }
        client = new WebSocketClient(factory);
    }

    public ClientWebSocket open(String uri) {
        try {
            Future connectionFuture = client.open(URI.create(uri), new WebSocket.OnTextMessage() {
                @Override
                public void onMessage(String s) {
                    logger.info(s);
                }

                @Override
                public void onOpen(Connection connection) {
                    logger.info("Opening WS");
                }

                @Override
                public void onClose(int i, String s) {
                    logger.info("Closing WS");
                }
            });
            try {
                this.connection = connectionFuture.get();
            } catch (InterruptedException | ExecutionException e) {
                logger.info("Cant get connection ws");
            }
        } catch (IOException e) {
            logger.info("IO exception with open ws");
        }
        return this;

    }

    public ClientWebSocket addCookies(String name, String value) {
        client.getCookies().put(name, value);
        return this;
    }

    public ClientWebSocket sendMessage(String mess) {
        try {
            connection.sendMessage(mess);
        } catch (Exception e) {
            logger.info("Plz open the connection");
        }
        return this;
    }

    public ClientWebSocket closeConnection() {
        try {
            connection.close();
            factory.stop();
        } catch (Exception e) {
            logger.info("Close connection error");
        }
        return this;
    }
}

И используем его как то так:

 
 String uri = "ws://test.dev:8080";
        ClientWebSocket client = new ClientWebSocket();
        client.addCookies("_user_id", "111111").open(uri).sendMessage("{'event':'Hello world!'}").closeConnection();

Вот так все просто.