Andy725
Andy725

Reputation: 11

javax.websocket Client

I am trying to set up a websocket client in Java. I've followed the exact steps to this accepted answer, but when it runs I get a

java.lang.RuntimeException: Could not find an implementation class.
    at javax.websocket.ContainerProvider.getWebSocketContainer(ContainerProvider.java:73)
    at multiplayer.matchmaking.WebsocketClient$1.run(WebsocketClient.java:31)
    at java.lang.Thread.run(Thread.java:748)
Exception in thread "Websocket Connection" java.lang.NullPointerException
    at multiplayer.matchmaking.WebsocketClient$1.run(WebsocketClient.java:35)
    at java.lang.Thread.run(Thread.java:748)

This is my WebsocketClient class:

package multiplayer.matchmaking;

import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Base64;

import javax.websocket.*;

import org.json.JSONException;
import org.json.JSONObject;

@ClientEndpoint
public abstract class WebsocketClient {

    private Thread connectionThread;
    private Session userSession;

    public WebsocketClient(String addr) throws URISyntaxException {
        this(new URI(addr));
    }

    public WebsocketClient(URI endpointURI) {
        connectionThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    WebSocketContainer container = ContainerProvider.getWebSocketContainer();
                    container.connectToServer(this, endpointURI);
                } catch (Exception e) {
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }

            }
        }, "Websocket Connection");
        connectionThread.setDaemon(true);
        connectionThread.start();
    }

    @OnMessage
    public void onMessage(String message) {
        JSONObject json = null;
        try {
            json = new JSONObject(message);
        } catch (JSONException e) {
            System.err.println("Uknown text recieved: " + message);
        }

        if (json != null)
            recieveJSON(json);
    }

    protected abstract void recieveJSON(JSONObject json);

    protected abstract void connected();

    public void sendAction(WebsocketCommand c) {
        JSONObject msg = new JSONObject();
        msg.put("command", "message");
        msg.put("identifier", new JSONObject().put("channel", "GameChannel").toString());
        msg.put("data", new JSONObject().put("action", "send_action").put("data", b64encode(c)).toString());

        sendMessage(msg.toString());
    }

    public void sendMessage(String message) {
        if (!isConnected())
            throw new RuntimeException("sendMessage called before connected");

        this.userSession.getAsyncRemote().sendText(message);
    }

    @OnOpen
    public synchronized void onOpen(Session userSession) {
        this.userSession = userSession;
        connected();
    }

    @OnClose
    public synchronized void onClose(Session userSession, CloseReason reason) {
        this.userSession = null;
    }

    public synchronized boolean isConnected() {
        return userSession != null;
    }

    public void join() throws InterruptedException {
        connectionThread.join();
    }

    private static String b64encode(WebsocketCommand cmd) {
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
            try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
                oos.writeObject(cmd);
                oos.flush();
                return new String(Base64.getEncoder().encode(baos.toByteArray()));
            }
        } catch (IOException e) {
            e.printStackTrace();
            return "err";
        }
    }

    public static WebsocketCommand b64decode(String enc) {
        if (enc.equals("err"))
            return null;
        try (ByteArrayInputStream bais = new ByteArrayInputStream(Base64.getDecoder().decode(enc))) {
            try (ObjectInputStream ois = new ObjectInputStream(bais)) {
                return (WebsocketCommand) ois.readObject();
            }
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }
}

It looks like the line container.connectToServer(this, endpointURI) is looking for a ServerEndpoint instead of a ClientEndpoint from the documentation, but I can't find anything describing how to use a ClientEndpoint. Has anyone actually used the javax.websocket package as a functional client? I find it strange that the accepted solution to the other question doesn't actually work out of the box.

Upvotes: 0

Views: 1573

Answers (1)

Andy725
Andy725

Reputation: 11

I solved it. I was missing a maven dependency. If anyone else runs into the same error, make sure you include the full javax dependencies-

<dependency>
   <groupId>javax.websocket</groupId>
   <artifactId>javax.websocket-client-api</artifactId>
   <version>1.0</version>
</dependency>
<dependency>
   <groupId>org.glassfish.tyrus</groupId>
   <artifactId>tyrus-client</artifactId>
   <version>1.1</version>
</dependency>
<dependency>
   <groupId>org.glassfish.tyrus</groupId>
   <artifactId>tyrus-container-grizzly</artifactId>
   <version>1.1</version>
</dependency>
<dependency>
   <groupId>javax.json</groupId>
   <artifactId>javax.json-api</artifactId>
   <version>1.0</version>
</dependency>
<dependency>
   <groupId>org.glassfish</groupId>
   <artifactId>javax.json</artifactId>
   <version>1.0.1</version>
</dependency>

Upvotes: 1

Related Questions