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.
Package | Purpose |
com/example/app | Root project package. This package contains all the module files. No code can be placed in the root project package. |
com/example/app/client | Sub-package containing all the client-side source code. |
com/example/app/server | Sub-package containing all the server-side source code |
com/example/app/public | Static resources |
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> |
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> |
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: nulland 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.
10 COMMENTS
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;
}
}
Hi Ugur,
Check if you have
ErraiApp.properties
file insrc
directory and if this file is defined inweb.xml
. AlsoErraiBus
should be defined ingwtErraiMessaging.gwt.xml
.You can try my simple project https://github.com/AndrejGajdos/gwt-errai-messaging
[…] 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: […]
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?
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
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.
If you try sample project on one system, does it work?
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.
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.
Thank you so much