First steps with GWT and Errai messaging

First steps with GWT and Errai messaging

When I was new at my current job, I got a task to realize server push messages from server to client. The application used GWT and my supervisor recommended to me to use Errai framework. At that time I had no experience with either GWT or Errai.

More details about server push in GWT is described in more depth in this article. You can find some articles about messaging in GWT like GWT consumer + Server push tutorial and use GWTEventService or GWT Comet Adapter for StreamHub. Maybe these solutions don’t fit to your requirements, some of these projects may not be in active development and probably wouldn’t work with new versions of GWT. At the end of this article, I will demonstrate a server push in Errai (the code is viewable on GitHub with a working example).

At first I created a basic GWT project. Lars Vogel wrote great tutorial on how to develop a basic web application with GWT. In this simple application you have a button with click action handler and when you click on this button, “user data” are created on server-side and rendered in table on client side. I used this project to demonstrate Errai messaging in GWT. For building whole project I used Maven and gwt-maven-plugin.

Now we can integrate a basic Errai Messaging. In the reference you can see snippets of how to implement sending/receiving messages between client and server.

GWT projects typically differentiate client and server code in form of sub-packages.

Source: http://developerlife.com/tutorials/?p=124

In server sub-package we create a MessageController class which ensures receiving message from client and sending them back a reply.

package gwt.user.server;
import org.jboss.errai.bus.client.api.base.MessageBuilder;
import org.jboss.errai.bus.client.api.messaging.Message;
import org.jboss.errai.bus.client.api.messaging.MessageCallback;
import org.jboss.errai.bus.client.api.messaging.RequestDispatcher;
import org.jboss.errai.bus.server.annotations.Service;
import com.google.inject.Inject;
@Service
public class MessageController implements MessageCallback {
// https://docs.jboss.org/author/display/ERRAI/Dependency+Injection
@Inject
private RequestDispatcher dispatcher;
public MessageController() {}
public void sendMessage() {
MessageBuilder.createMessage()
.toSubject("ClientService")
.signalling()
.with("text", "Hi There")
.noErrorHandling()
.sendNowWith(this.dispatcher);
}
public void callback(Message message) {
System.out.println("MessageController received message");
this.sendMessage();
}
}

Now in client service, which is EntryPoint we initialize RequestDispatcher and MessageBus.

private RequestDispatcher dispatcher = ErraiBus.getDispatcher();
private MessageBus bus = ErraiBus.get();

In addClickHandler method we send a message to our MessageController.

MessageBuilder.createMessage()
.toSubject("MessageController")
.signalling()
.noErrorHandling()
.sendNowWith(getDispatcher());

In onModuleLoad method we subscribe message from server with MessageBus.

bus.subscribe("ClientService", new MessageCallback() {
public void callback(Message message) {
Window.alert("ClientService message is received. " + message.get(String.class, "text"));
}
});

We also have to import ErraiBus to our GWT module xml configuration file as another module.

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

and add ErraiServlet to our web.xml

<servlet>
<servlet-name>ErraiServlet</servlet-name>
<servlet-class>org.jboss.errai.bus.server.servlet.DefaultBlockingServlet</servlet-class>
<init-param>
<param-name>auto-discover-services</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>ErraiServlet</servlet-name>
<url-pattern>*.erraiBus</url-pattern>
</servlet-mapping>
view raw web.xml hosted with ❤ by GitHub

Now when we click on the button, the client should send the message to the server, which generates a new message which the client shows in the alert window.

If you get an org.jboss.errai.bus.client.api.base.NoSubscribersToDeliverTo exception, you probably forgot the ErraiApp.properties file. This property file is a marker for classpath scanning and can be usually empty. We can define here Dispatcher implementation, which is not necessary, because by default it uses SimpleDispatcher. In reference you can find more options for ErraiBus configuration.

#
# Request dispatcher implementation (default is SimpleDispatcher)
#
errai.dispatcher_implementation=org.jboss.errai.bus.server.SimpleDispatcher

and add this property file as a context-param in web.xml

<context-param>
<param-name>ErraiApp.properties</param-name>
<param-value>WEB_INF/ErraiApp.properties</param-value>
</context-param>
view raw web.xml hosted with ❤ by GitHub

Server Push in Errai

In our previous example the client can send the message to the server and the server can send message back to the client, but we are in situation where we want the server to send messages to the client without the client’s initiation.

At first I tried to remove the RequestDispatcher and MessageBuilder in ClientService class, and send the message on server side, when “user data” are created. With this approach, I got the following error:

com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract java.util.List gwt.user.client.UserService.getUserList()' threw an unexpected exception: org.jboss.errai.bus.client.api.base.MessageDeliveryFailure: could not deliver message: null
and tried to figure out why it doesn’t work. I spent some time studying source code of errai-bus. The point was to send message with MessageBus on server-side. You can create MessageBus on server-side using:

ErraiService<?> service = ErraiServiceSingleton.getService();
this.bus = service.getBus();

Now MessageController class looks like this:

package gwt.user.server;
import org.jboss.errai.bus.client.api.base.MessageBuilder;
import org.jboss.errai.bus.client.api.messaging.Message;
import org.jboss.errai.bus.client.api.messaging.MessageBus;
import org.jboss.errai.bus.client.api.messaging.MessageCallback;
import org.jboss.errai.bus.server.annotations.Service;
import org.jboss.errai.bus.server.service.ErraiService;
import org.jboss.errai.bus.server.service.ErraiServiceSingleton;
@Service
public class MessageController implements MessageCallback {
private MessageBus bus;
public MessageController() {
ErraiService<?> service = ErraiServiceSingleton.getService();
this.bus = service.getBus();
}
public void sendMessage() {
MessageBuilder.createMessage()
.toSubject("ClientService")
.signalling()
.with("text", "Hi There")
.noErrorHandling()
.sendNowWith(this.bus);
}
public void callback(Message message) {
System.out.println("MessageController received message");
this.sendMessage();
}
}

and the server can send messages to the client without the client’s initiation.

NEED A FULL STACK WEB DEVELOPER? LET'S BUILD SOMETHING.

GET IN TOUCH
10 COMMENTS
  • Ugur
    Reply

    I used your solution for this exception “org.jboss.errai.bus.client.api.base.MessageDeliveryFailure: could not deliver message: null”. But I am getting the same error again and again. I can not find what I am doing wrong.
    Please give me a hand…

    Here is my simple classes:

    Client side:
    public class ClientService implements EntryPoint
    {
    private MyTable table;

    /*********************************************************************/
    private MessageBus bus = ErraiBus.get();

    /*********************************************************************/

    public void onModuleLoad()
    {
    table = new MyTable( null );

    Button button = new Button( “Click me” );
    button.addStyleName( “pc-template-btn” );

    VerticalPanel vPanel = new VerticalPanel();
    vPanel.setWidth( “100%” );
    vPanel.setHorizontalAlignment( VerticalPanel.ALIGN_CENTER );
    vPanel.add( button );
    vPanel.add( table );

    // add table and button to the RootPanel
    RootPanel.get().add( vPanel );

    button.addClickHandler( new ClickHandler() {
    @Override
    public void onClick( ClickEvent event)
    {
    UserServiceAsync service = (UserServiceAsync) GWT.create( UserService.class );
    ServiceDefTarget serviceDef = (ServiceDefTarget) service;
    serviceDef.setServiceEntryPoint( GWT.getModuleBaseURL() + “userService” );

    service.getUserList( new UserCallback( table ) );
    }
    } );

    /*********************************************************************/
    bus.subscribe( “ClientService”, new MessageCallback() {
    @Override
    public void callback( Message message)
    {
    Window.alert( “ClientService message is received. ” + message.get( String.class, “text” ) );
    }
    } );
    /*********************************************************************/
    }

    Server Side:
    @Service
    public class MessageController implements MessageCallback
    {
    private MessageBus bus;

    public MessageController()
    {
    ErraiService service = ErraiServiceSingleton.getService();
    this.bus = service.getBus();
    }

    public void sendMessage()
    {
    MessageBuilder.createMessage().toSubject( “ClientService” ).signalling().with( “text”, “Hi There” ).noErrorHandling().sendNowWith( this.bus );
    }

    public void callback( Message message)
    {
    System.out.println( “MessageController received message” );
    this.sendMessage();
    }
    }

    Server Side 2:

    public class UserServiceImpl extends RemoteServiceServlet implements UserService
    {
    private static final long serialVersionUID = 1L;
    private static final Logger logger = Logger.getLogger( UserServiceImpl.class );

    private List userList = new ArrayList();
    /*********************************************************************/
    private MessageController messageController = new MessageController();

    /*********************************************************************/

    public UserServiceImpl()
    {
    User user = new User();
    userList.add( user );
    user.setId( “1” );
    user.setUsername( “Peter” );
    user.setNumberOfHits( “15” );
    userList.add( user );

    user = new User();
    user.setId( “2” );
    user.setUsername( “Hanz” );
    user.setNumberOfHits( “25” );
    userList.add( user );
    }

    public List getUserList()
    {
    /*********************************************************************/
    messageController.sendMessage();
    /*********************************************************************/
    return userList;
    }
    }

    1. Andrej Gajdos
      Reply

      Hi Ugur,

      Check if you have ErraiApp.properties file in src directory and if this file is defined in web.xml. Also ErraiBus should be defined in gwtErraiMessaging.gwt.xml.

      You can try my simple project https://github.com/AndrejGajdos/gwt-errai-messaging

  • ERRAI with GWT (Server Push) – MessageDeliveryFailure could not deliver message: null | ASK Dev Archives
    Reply

    […] this site http://andrejgajdos.com/first-steps-with-gwt-and-errai-messaging/ I used all solutions for this exception org.jboss.errai.bus.client.api.base.MessageDeliveryFailure: […]

  • Amith Kumar
    Reply

    Hi,

    I have used errai for server push, it works well in Linux even with the heavy application, but it in windows machine it’s too slow, most of the time I’m not able see the popups, or it pops us once in a while.

    My application is hosted on CentOS and same application when accessed from Linux irrespective of browser works fine, but in windows I face the above issue.

    Do you have any idea about this?

    1. Andrej Gajdos
      Reply

      I haven’t used Windows for ages and Errai is developed by Red Hat so I am not sure how Windows is supported. You can try to check Errai discussion forum https://developer.jboss.org/en/errai

      1. Amith Kumar
        Reply

        Hey, thanks for the reply,
        My application is hosted on CentOS and I’m trying access it throw windows machine, push up notifications are not working. Tried all possible ways.. but no luck.

        1. Andrej Gajdos
          Reply

          If you try sample project on one system, does it work?

          1. Amith Kumar

            Same thing, I have debugged your sample application, registration is happening properly for both Linux and windows client, but push notifications are working for only Linux clients.

            When I trigger push notification debug points are not triggered on server side.

          2. Andrej Gajdos

            In this case I would contact Errai creators, ask in their discussion forum and open an issue on Github. There is nothing I can do for you, because it was a long time ago I worked with Errai.

          3. Amith Kumar

            Thank you so much

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: