Introduction
LinkSet as described in the previous article is a tiny library created in order to relieve programmers from declaring listener interfaces. It utilizes Java 5 features, and was designed to be a drop-in replacement for a conventional “listener interface + anonymous class” solution. Previously, it had an event bus support, and now it supports a remote dynamic Command pattern.
Introduction
Command pattern is a very useful solution, but it causes some problems when used in a distributed environment. When implemented in a classical way and performed over the wire, it causes almost all server code to reside on client side as well. It is unfavorable and often even impossible to implement when the client side uses a different technology than the server side (like JavaScript or Adobe Flex).
A solution
The most obvious way is to split the commands code from the execution code so that commands carry only a command name and data which can be easily transported over the wire. This solution raises, however, a different problem of easily dispatching commands on the server side. There is a solution to that, but type safety causes makes it too complicated. I found that dropping type safety makes it easier and simpler.
Using LinkSet as a dynamic command dispatcher with a GWT application
There are only two classes that make the magic happen. First is a CommandExecutor
class that takes care of the binding commands to methods, and second is an Eexecutor
annotation that is used for marking methods.
The class CommandExecutor
has only one public constructor that takes a reference to an object containing methods that perform commands, and only one public method execute
that causes real command execution to happen.
The code below is an axample of a GWT RPC service that uses the LinkSet Command pattern support.
A command interface
This interface is needed if you want your client side to be type safe.
public interface Command<ReturnType extends Serializable> extends Serializable{
}
A service interface
@RemoteServiceRelativePath("rpcservice")
public interface RPCService extends RemoteService {
public <R extends Serializable> R execute(
final Command<R> command) throws Throwable;
}
An asynchronous service interface
public interface RPCServiceAsync {
public <ReturnType extends Serializable> void execute(
Command<ReturnType> command, AsyncCallback<ReturnType> callback);
}
A servlet class
This is the only place where LinkSet is actually used.
public class RPCServiceServlet extends RemoteServiceServlet
implements RPCService {
private final CommandExecutor executor = new CommandExecutor(this);
@SuppressWarnings("unchecked")
public <ReturnType extends Serializable> ReturnType execute(
final Command<ReturnType> command) throws Throwable {
return (ReturnType) this.executor.execute(command);
}
@Executor(cmdClass = InvalidateSession.class)
public Null invalidateSession(final InvalidateSession cmd) {
getThreadLocalRequest().getSession().invalidate();
return null;
}
@Executor(cmdClass = ListUsers.class)
public ArrayList<User> listDomains(final ListUsers cmd) {
final ArrayList<User> result = new ArrayList<User>();
…
return result;
}
}
When a CommandExecutor
object is created:
CommandExecutor executor = new CommandExecutor(this);
it scans its parameter's class, looking for annotated methods:
@Executor(cmdClass = ListUsers.class)
public ArrayList listDomains(final ListUsers cmd) {
and creates a mapping between a command's class and a method.
When the execute
method is called:
this.executor.execute(command);
it calls the appropriate method assigned to its parameter's type (via Reflection).
It is worth noting that LinkSet does not depend on any external library, and it does not enforce commands to subclass any particular class or implement any particular interface, so it is totally invisible to the client side of an application. It can be used not only with GWT, but also with Adobe Flex, EJB, RMI, and other frameworks.
Summary
LinkSet is a little experiment with a light, dynamic approach to Java. If you like it .. enjoy using it .. and report bugs at github.com/lbownik/linkset.