Mitch Pronschinske is a Senior Content Analyst at DZone. That means he writes and searches for the finest developer content in the land so that you don't have to. He often eats peanut butter and bananas, likes to make his own ringtones, enjoys card and board games, and is married to an underwear model. Mitch is a DZone Zone Leader and has posted 2576 posts at DZone. You can read more from them at their website. View Full User Profile

Errai Tips

05.07.2010
| 11554 views |
  • submit to reddit
Test-driving JBoss' GWT-based, Message-Oriented Errai framework can be a lot smoother with some best practices that were recently posted by Anil Saldhana, the JBoss lead security architect.  Errai combines the Message-Oriented Programming paradigm with RPC and Push Messaging.  The framework is based on the Google Web Toolkit and it is built on ErraiBus, which espouses a  programming model that permeates both the client and the server.  This is also the central idea behind the SOA design pattern.  Last month, DZone had an interview Mike Brock, the Errai project lead.  This month, Mike added new asynchronous task APIs to Errai, which is currently at version 1.0.  Here are some excerpts to get you started with Errai:

Don't build a GWT console from scratch
Basically, it's just not worth it sometimes, Saldhana says.  Errai Workspaces already gives you some reusable infrastructure for layouts, widgets, and more.  Here's how you add tools to a workspace:
@LoadTool(name = "Users", group = "Administration")                          (1)

public class UserManagement implements WidgetProvider
{
public void provideWidget(final ProvisioningCallback callback) { (2)
callback.onSuccess(new UserManagementWidget());
}

class UserManagementWidget extends LayoutPanel (3)
{
[...]
}

}

Get your UI Widgets from GWT Mosaic
The GWT Mosaic project offers plenty of widgets that provide a good user experience.  Just scan the bug list for the appropriate project because some of the widgets are not very stable.  You may have to use GWT core components if the Mosaic widgets are too buggy.

Server code before client code
Because building and debugging in GWT takes awhile, you should write your server code first and unit test it thoroughly.  Then you can develop client components as you need them.  Saldhana says this will make you much more productive.

Declare the subscriber in the client (widget) before sending a message to the server
In this example, a message is being sent to the server, taking a widget on the client side.  First, you subscribe to the bus with "TokenProviderList" as the subject:
bus.subscribe("TokenProviderList", new MessageCallback()
{
public void callback(Message message)
{
//We got response from server
}
});


//Send a message to the server
MessageBuilder.createMessage()
.toSubject("TokenProviderService")
.command( TokenProviderConfigurationCommands.TOKEN_LIST )
.noErrorHandling().sendNowWith(bus);
Second, you send a message to the server.  The service is called "TokenProviderService".  The order is significant because there are no subscribers for "TokenProviderList" from the errai bus.  Here are the snippets from the TokenProviderService on the server side:
@Service
@RequireRoles({"admin"})
public class TokenProviderService implements MessageCallback
{
private MessageBus bus;

@Inject
public TokenProviderService( MessageBus bus )
{
this.bus = bus;
}


public void callback(Message message)
{
String commandType = message.getCommandType();

if( commandType == null )
{
return;
}
String resultStr = "SUCCESS";

TokenProviderConfigurationHandler handler = new TokenProviderConfigurationHandler();

switch( TokenProviderConfigurationCommands.valueOf( commandType ) )
{
case TOKEN_ADD:
TokenProvider tokenProvider = message.get( TokenProvider.class , TokenProviderConfigurationParts.TokenProviderObj );
trace( tokenProvider );
try
{
handler.persist( tokenProvider );
message.set("RESULT", "SUCCESS" );
}
catch (Exception e)
{
log.error( "Unable to persist TokenProvider" );
resultStr = "FAILURE";
}
updateClient( message, resultStr );
break;

case TOKEN_DELETE:
String providerClass = message.get( String.class, TokenProviderConfigurationParts.ProviderClass );
Set<TokenProvider> tokenProviderSet;
try
{
tokenProviderSet = handler.getTokenProviders();
}
catch ( Exception e1)
{
log.error( "Unable to get list of token providers", e1 );
return;
}

Iterator<TokenProvider> iter = tokenProviderSet.iterator();

TokenProvider removeThisTokenProvider = null;

while( iter.hasNext() )
{
TokenProvider tp = iter.next();
if( tp.getProviderClassName().equals( providerClass ))
{
removeThisTokenProvider = tp;
break;
}
}

if( removeThisTokenProvider != null )
{
try
{
handler.remove(removeThisTokenProvider);
}
catch ( Exception e )
{
log.error( "Unable to remove TokenProvider", e);
}
}
break;

case TOKEN_UPDATE:
tokenProvider = message.get( TokenProvider.class , TokenProviderConfigurationParts.TokenProviderObj );
trace( tokenProvider );
try
{
handler.persist( tokenProvider );
}
catch (Exception e)
{
log.error( "Unable to persist TokenProvider", e);
resultStr = "FAILURE";
}
updateClient( message, resultStr );
break;

case TOKEN_LIST:
tokenProviderSet = new HashSet<TokenProvider>();
try
{
tokenProviderSet = handler.getTokenProviders();

System.out.println( "TOKEN PROVIDER LIST RECEIVED:" + tokenProviderSet.size());
}
catch ( Exception e)
{
log.error( "Unable to persist TokenProvider", e );
}
finally
{
MessageBuilder.createConversation(message)
.toSubject("TokenProviderList")
.signalling()
.with( TokenProviderConfigurationParts.TokenProviderList, tokenProviderSet )
.noErrorHandling().sendNowWith( bus );
}
break;
}
}

}
You can check out the Errai Documenation to better understand this example, or contact the Errai team and suggest docs changes.

Choosing messaging parameters
Here are the ways you can choose the appropriate messaging facility:
//SEND ONE PARAMETER  ("with" usage)
MessageBuilder.createMessage().toSubject("ClientBus")
.command(BusCommands.RemoteSubscribe)
.with(MessageParts.Subject, service)
.noErrorHandling().sendNowWith(bus);

// ZERO PARAMETERS
MessageBuilder.createMessage()
.toSubject("ClientBus")
.command(BusCommands.FinishStateSync)
.noErrorHandling().sendNowWith( bus);

//TWO PARAMETERS
MessageBuilder.createMessage()
.toSubject(remoteMonitorSubject)
.command(MonitorCommands.SubscribeEvent)
.with(MonitorParts.Time, System.currentTimeMillis())
.with(MonitorParts.MessageContent, subject)
.noErrorHandling().sendNowWith( bus );

Adding serialized objects
When you add serialized objects to Java Collections, be sure that there isn't any object duplication.  You can do this by making sure the methods are properly implemented with an IDE.

You should also choose your serialized objects carefully.  If you have a UserManagment feature sending User objects from client to server, you need your User object to be serializable.  The User has four operations: Create, Update, Delete, and Read.  For Create and Read, you'll need to transmit the entire User object.  For Update and Delete, you only need to send in the user identifier and the fields that have changed.

Make use of the Development Mode Window
You should use the Development Mode window to view the generated Marshaller/Unmarshaller code for serialized objects:



Track messages using the Errai ActivityMonitor
This tool will visualize message formats and contents going from the client to the server.  It's a great tool for debugging subtle issues.  
To get the ActivityMonitor:

1) Bring in org.jboss.errai/errai-tools as a dependency in your maven project.
2) Set the JVM parameter "-Derrai.tools.bus_monitor_attach=true"

Maven pom:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>gwt-maven-plugin</artifactId>
<version>1.2.0-11137</version>
<configuration>
<inplace>true</inplace>
<logLevel>DEBUG</logLevel>
<runTarget>PicketLinkService.html</runTarget>
<warSourceDirectory>war</warSourceDirectory>
<extraJvmArgs>-Xmx512m -Derrai.tools.bus_monitor_attach=true</extraJvmArgs>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>

You can find out more about the Activity Monitor on Mike Brock's blog.