0

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.

1 Answer 1

1

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>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.