1

I am looking for more information that I cannot find in my searches of the web. I am most likely searching for the wrong thing and I hope someone can correct me.

I have implemented a client(javascript)-server(java) websocket application. I have the connections working for several clients and now I want to start with some initial data created from a main method. However, the main method I have in my java application is not linked to the websocket endpoint. So if I create object instances when I run the application I want that information to be sent to the connected clients outside of the closed loop of session actions.

What I am describing sounds impossible to but I am certain I am just not explaining it properly.

Conclusion:

When dealing with websockets, how can I have an OnServerStartup so to speak so that I can either load saved data or create initial data?

Background:

I have implemented an annotated server endpoint using javax.websocket.server. The history which due to going out of order may have caused my quandry is that I started with the java application first and then I wanted to have a client UI to add, edit, delete data. So I went with a javascript frontend communicating with my java app via websockets. Now my app cannot communicate with the websocket connections or at least I do not know how yet.

Ideally what I am trying to do is have the useractions come in over the websocket and then I want to put the actions into a queue that my application then processes. When complete it sends the resulting changes to the dataset to all active sessions. There is a big issue here because I want to initialize saved data before allowing the websocket connections. Also if I have a timed event I want to be able to send all the updates to the connected sessions.

Mark
  • 911
  • 13
  • 30
  • [this here](https://github.com/TooTallNate/Java-WebSocket/blob/master/src/main/java/org/java_websocket/server/WebSocketServer.java) is your server implementation? You could actually write a websocket server application and do things from the actual main method right after you call the `start()` method (it's non-blocking and creates a thread) of the websocket part. Or you make a thread. Or maybe I'm not understanding where your problem lies. Please explain :) – zapl Nov 28 '15 at 19:43
  • I have implemented an annotated endpoint via the javax.websocket.server.ServerEndpoint along with a glassfish server. Maybe I have just implemented it wrong for the use case. I did take a look already at the example you linked to. It seemed too complex so I went with a simpler implementation. specifically [this](https://tyrus.java.net/documentation/1.12/user-guide.html#d0e440) – Mark Nov 28 '15 at 20:31
  • Ok, completely different framework / environment. You can ignore what I said. For that you're primarily in Glassfish application lifecycle, dependency management & event processing area I guess. – zapl Nov 28 '15 at 21:07
  • I think you just confirmed what I was thinking. I need to implement websocket endpoints from my application. Currently they must be implemented by glassfish because I am not doing anything in my code. I was worried that using glassfish was going to give me issues. – Mark Nov 28 '15 at 21:18
  • Now I'm even more confused. By "java application" and "glass fish" you mean you have an application on a JavaEE Glassfish application server (https://glassfish.java.net/) that also uses the `org.glassfish.tyrus` implementation of websockets and those two parts are not connected yet? – zapl Nov 28 '15 at 21:40
  • 1
    Well Tyrus is just a reference implementation. I use implemented annotated server endpoints based on that implementation. However, glassfish owns the ServerContainer ( just found out that this is what I need to access the session data ). What I need to do is launch my own websocket server [here](http://stackoverflow.com/questions/33415121/using-java-websocket-api-implementation-without-a-web-server). It's a little more complicated but I can keep it all inside my java application that way. – Mark Nov 28 '15 at 21:59

1 Answers1

1

Here are three solutions. They might not help the original poster using Glassfish; I do not know. But they are answers to the posted question and might be of some use.

I use embedded Jetty for my server. (Meaning the server is created in my Java code, so I have access to everything.)

Answer 1: Have your websocket server endpoint listen to CDI events sent from your main thread. I have not done this, but I think it is a very clean concept.

Answer 2: Have your endpoint "register" itself with the main thread.

Create a static collection member in a core class:

public class Core()
...
    public static List<MyEndpoint> webSockets = new ArrayList<MyEndpoint>();

Endpoint adds self to collection:

@ServerEndpoint(value="/path/")
public class MyEndpoint
{
    @OnOpen
    public void onWebSocketConnect(javax.websocket.Session session)
    {
        synchronized(Core.webSockets)
        {
            Core.webSockets.add(this);
        }
        ...
    }

Back in Core you will iterate through webSockets to send messages. Synchronize the iteration, or better, copy webSockets and iterate throught the copy (standard synched collection practices). You will also need to handle removal from the List in @OnClose, and watch for closed sockets during the iteration.

Note the synchronizations might be done in other ways as you need: Collections.synchronizedList() or CopyOnWriteArrayList are useful in different situations.

Answer 3: Take control of constructing the endpoint instance. This is the most powerful of my choices, as you can construct it with data and external references.

My implementation is JSR-356 (and Jetty) based, but there are hooks in other frameworks, too. Always slightly complicated.

During server creation:

context = new ServletContextHandler(ServletContextHandler.SESSIONS);
// ... more server creation

ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(context);

wscontainer.addEndpoint(ServerEndpointConfig.Builder.create(MyEndpoint.class, "/path/")
    .configurator(new MyConfigurator(aSocketManagerObject))
    .build());

Where:

public class MyConfigurator extends javax.websocket.server.ServerEndpointConfig.Configurator
{
    private final ManagerObject aSocketManagerObject;

    public EventsConfigurator(ManagerObject aSocketManagerObject)
    {
        this.aSocketManagerObject = aSocketManagerObject;
    }

    @Override
    public <T> T getEndpointInstance(Class<T> endpointClass) throws InstantiationException
    {
        return (T) new MyEndpoint(aSocketManagerObject); // This constructor to be added to your MyEndpoint class
    }
}

The endpoint now has a reference to aSocketManagerObject and can communicate with it freely to acquire data, register as listener, whatever.

Bhaskar S. provides a robust implementation of Answer 3 at Introduction to WebSockets

Edit:

More info on the CDI approach is in question, How to get an existing websocket instance.

And Accessing HttpSession from HttpServletRequest in a Web Socket @ServerEndpoint includes a long discussion about instances of endpoints.

Saturn5
  • 108
  • 1
  • 7
  • This is great stuff! I am still interested in a solution here so this is helpful. As time passes more and more documentation and solutions become available. Thanks for taking the time to put explicit examples as answers! – Mark Sep 04 '17 at 14:33