Tyrus - Хранить сообщения, полученные клиентом

Я хочу иметь клиент, который будет получать сообщения WS и сохранять их для дальнейшего анализа.

Я создал клиент на основе https://dzone.com/articles/sample-java-web-socket-client

К сожалению, при каждом вызове метода onMessage поле, в котором будут храниться значения, имеет значение null, и сообщение не может быть добавлено.

Код

 package com.sample.ws;

import org.apache.log4j.Logger;

import javax.websocket.*;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;

import static java.lang.Thread.sleep;

@ClientEndpoint
public class WSClient {
    private static final Logger LOG = Logger.getLogger(WSClient.class);

    private List<String> testContext;

    public static void main(String[] args) {
        WSClient client = new WSClient();

        List testContext = new ArrayList<String>();
        client.setTestContext(testContext);

        client.run();

        LOG.info("Final state: " + testContext);
    }

    private void run() {
        LOG.info("Initial state: " + testContext);

        WebSocketContainer container = null;//
        Session session = null;
        try {
            container = ContainerProvider.getWebSocketContainer();
            session = container.connectToServer(com.sample.ws.WSClient.class, URI.create("ws://localhost:8080/wsserver-1.0/ratesrv"));
            LOG.info("Connected to server");
            sleep(10000L);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @OnMessage
    private void onMessage(String message) {
        //the new USD rate arrives from the websocket server side.
        LOG.info("Received msg: " + message);
        testContext.add(message);
    }

    private void setTestContext(List<String> testContext) {
        this.testContext = testContext;
    }
}

Журнал

INFO  WSClient - Initial state: []
INFO  WSClient - Connected to server
INFO  WSClient - Received msg: USD Rate: 2.998
Feb 03, 2017 5:52:22 PM org.glassfish.tyrus.core.AnnotatedEndpoint onError
INFO: Unhandled exception in endpoint com.sample.ws.WSClient.
java.lang.NullPointerException
    at com.sample.ws.WSClient.onMessage(WSClient.java:55)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.glassfish.tyrus.core.AnnotatedEndpoint.callMethod(AnnotatedEndpoint.java:520)
    at org.glassfish.tyrus.core.AnnotatedEndpoint.access$100(AnnotatedEndpoint.java:87)
    at org.glassfish.tyrus.core.AnnotatedEndpoint$WholeHandler$1.onMessage(AnnotatedEndpoint.java:619)
    at org.glassfish.tyrus.core.TyrusSession.notifyMessageHandlers(TyrusSession.java:576)
    at org.glassfish.tyrus.core.TyrusEndpointWrapper.onMessage(TyrusEndpointWrapper.java:879)
    at org.glassfish.tyrus.core.TyrusWebSocket.onMessage(TyrusWebSocket.java:216)
    at org.glassfish.tyrus.core.frame.TextFrame.respond(TextFrame.java:139)
    at org.glassfish.tyrus.core.ProtocolHandler.process(ProtocolHandler.java:807)
    at org.glassfish.tyrus.client.TyrusClientEngine$TyrusReadHandler.handle(TyrusClientEngine.java:747)
    at org.glassfish.tyrus.container.grizzly.client.GrizzlyClientFilter$ProcessTask.execute(GrizzlyClientFilter.java:476)
    at org.glassfish.tyrus.container.grizzly.client.TaskProcessor.processTask(TaskProcessor.java:114)
    at org.glassfish.tyrus.container.grizzly.client.TaskProcessor.processTask(TaskProcessor.java:91)
    at org.glassfish.tyrus.container.grizzly.client.GrizzlyClientFilter.handleRead(GrizzlyClientFilter.java:272)
    at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:526)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
    at java.lang.Thread.run(Thread.java:745)
INFO  WSClient - Final state: []

person Kuba    schedule 03.02.2017    source источник


Ответы (1)


Клиент WebSocket создает новый экземпляр, и поле «testContext» там не заполняется.

Сделайте его статичным, и он начнет работать. Кроме того, вам нужно сделать его потокобезопасным. (например: CopyOnWriteArrayList).

Другой вариант — вызвать #connectToServer(Object, URI), что заставит клиент WebSocket использовать предоставленный экземпляр (а не создавать новый). Опять же, вам нужно убедиться, что доступ к вашей коллекции (и любым другим полям, доступ к которым осуществляется во время обработки) осуществляется потокобезопасным способом.

person Pavel Bucek    schedule 04.02.2017