leponceau.org

Programming And Stuff, You Know The Thing…

Jetty/GWT/Errai Message Bus/Maven Example

Posted at — Sep 12, 2017

Finally got it running. Here are a few remarks.

I was looking for a nice solution to sending Java data objects over a websocket wire, ie. server push. I was able to re-use GWT-RPC for that. However, that’s not as nice a solution as the usual GWT RPC service declaration and code generation from that as it is done by the GWT framework.

Now let’s come back to Errai.

First of all, there are restrictions on the Java data object’s constructor. Second, we are required to write boiler plate for each remote call/message send and this is not done in a type-safe way (link):

    MessageBuilder.createMessage()
                .toSubject("ErraiChatService")
                .signalling()
                .with("message", pojoMessage)
                .errorsHandledBy(new ErrorCallback() {
                    @Override
                    public boolean error(Object message, Throwable throwable) {
                        throwable.printStackTrace();
                        return true;
                    }
                })
                .sendNowWith(dispatcher);

Not even the remote service name is being checked by your IDE or compiler and is simply an arbitrary String.

The only (errai) dependency that was necessary to add to the maven project descriptor is (link)

    <dependency>
        <groupId>org.jboss.errai</groupId>
        <artifactId>errai-bus</artifactId>
        <version>${errai.version}</version>
    </dependency>        

Your GWT app’s module descriptor needs an additional line (link):

    <inherits name="org.jboss.errai.bus.ErraiBus" />

This is how a simple server-side consumer service looks like (link):

    @Service
    public class ErraiChatService implements MessageCallback {
        private final RequestDispatcher dispatcher;
    
        @Inject
        public ErraiChatService(RequestDispatcher dispatcher) {
            LOG.info("ErraiChatService new");
            this.dispatcher = dispatcher;
        }
    
        @Override
        public void callback(Message message) {
            LOG.log(Level.INFO, "ErraiChatService.callback1 {0}", message);
            MessageBuilder.createMessage()
                    .toSubject("BroadcastReceiver")
                    .with("message", message.get(PojoMessage.class, "message"))
                    .noErrorHandling()
                    .sendGlobalWith(dispatcher);
        }
    
        public void callback(CommandMessage message) {
            LOG.log(Level.INFO, "ErraiChatService.callback2 {0}", message);
        }

If you wonder what the callback with the CommandMessage parameter is about, well, that’s from the documentation that is seemingly not totally accurate.

The advanatages of the Errai framework are its modularity: you can basiucally use most modules without pulling in everything else. Unfortunately, there are no good stripped down examples available, especially not for Jetty. That’s why I had to do this on my own. The current Errai tutorial is based on a fully fledged Wild Fly EE server – hardly something that invities you to understand how stuff fits together and to adopt it.

Another point that is not really accurate in the documentation is the location of the ErraiApp.properties file which serves as a flag fpr the classpath scanner that is looking for the server-side @Service annotations to register your server-side consumer services. That file must be at the ROOT(!), not just anywhere above your Errai related stuff.

One final point: the Errai bus module itself is not providing websocket transport. For that, you need to include more errai modules. For development/debugging it’s probably better to not use websockets and go with the simpleest solution because you can inspect network traffic that way.

Considering how the original GWT service declaration mechanism works, I’m switching back to gwt-websockets and GWT RPC serialization and I probably gonna write an annotation processor for the boiler plate code. That way I’ll have proper type-safety and a proper interface declaration that I can use on client and server side.