Hi,

I follow what you are trying to do, it would solve some complexity on
the server side.

But one of the main benefits of using the command pattern is that you
only need one client API call. In case of GWT it means that you write
onesync and async interface with one method... and from there on you
can add commands without having to update these interfaces. On the
server side you have one servlet that can use Guice to inject the
handlers so you can implement handlers as POJOs. That is easier for
testing and you don't need to extend the RPC servlet class everywhere.

You should maybe look at something like gwt-dispatcher that implements
the command pattern. I don't like the fact that I need to define that
many classes (request,result, handler and registere the handler), but
I guess there can be solutions to improve upon that design as well
(introspection to find the handler automatically for example).


David

On Thu, Nov 19, 2009 at 6:52 AM, Jamie Gennis <jgen...@gmail.com> wrote:
> Hi all,
> I've been writing a GWT library to implement the command pattern for GWT RPC
> calls using the same interfaces that traditional GWT RPC uses.  Basically,
> when an app calls a method of the FooAsync action service interface, an
> action object is created from the method arguments, processed by some action
> filters on the client, then passed to the server.  The server then pulls the
> method arguments out of the action object and passes them as arguments to
> the appropriate method of the Foo interface implementation class.  The
> return value (or thrown Throwable) from that method then gets put into an
> action result object on the server and sent back to the client, where it
> gets processed by filters and eventually has the return value or throwable
> pulled out and passed to the onSuccess or onFailure methods of the async
> callback.
> I have a working (albeit not extensively tested)
> google-web-toolkit-contribut...@googlegroups.comimplementation
> at http://code.google.com/p/gwt-remote-action/, but the implementation
> relies on some GWT internals, so it's rather brittle at the moment. I'd like
> to get some feedback on how I can change my implementation to be more
> future-proof (or correct if it isn't), and which (if any) of the GWT
> internals that I'm using might be candidates for becoming a part of GWT's
> public interface.
> The tricky part of the implementation is the action result.  The purpose of
> an action result object is to encapsulate the result of executing an action
> in such a way that action filters can manipulate it without having any
> knowledge of what the action was.  It needs to contain an arbitrary return
> value object or an arbitrary Throwable object (as well as an indication that
> the Throwable was thrown rather than returned).  These objects are exposed
> via the ActionResult interface.  Simply having a general action result class
> that contains a return value field of type Object and an exception field of
> type Throwable is not desirable because it would cause deserialization code
> for every class that GWT knows about to be included in the compiled
> javascript.
> The current implementation works by generating one action result class for
> each RPC method.  Identical action result classes are generated by a GWT
> Generator at gwtc-time (for the client) and via Java byte code generation at
> run-time (for the server).  My original idea was that this method-specific
> action result class could have a result field of the specific return type of
> the method along with a field for each type in the method's throws list.
>  This turned out not to be necessary (at least for the cases I've tested),
> because when GWT calls the Generator for the ActionExecutionService (the
> traditional GWT RPC that sends the action objects to the server) it doesn't
> find any of the generated method-specific action result classes.  Because of
> this I simplified the action result classes to just have one field of type
> Throwable, and I verified that not all the Throwable classes get included in
> the deserializable classes list in the *.rpc.log files.  I'm not sure that
> this behavior doesn't depend on GWT.create being called in a specific order
> or something else I'm not aware of, but that should be solvable by splitting
> the throwables into multiple fields if needed.
> Generating the action result classes after the ActionExecutionService gets
> generated means that none of the deserializers for the return values and
> throwables of the action methods get generated or rescued.  To get around
> this I:
>
> Make the ActionExecutionService use the new deRPC implementation rather than
> the previous RPC implementation
> Use the RpcProxyCreator class to generate a dummy implementation of a deRPC
> proxy for the action service (this proxy doesn't get used)
> Add an @ArtificialRescue to the generated action service proxy to rescue the
> _TypeOverridesFactory class that the RpcProxyCreator generated.  This
> _TypeOverridesFactory class has all of the @ArtificalRescue's necessary to
> deserialize the fields of the generated action result class.
>
> Step 1 is mostly acceptable to me, though it would be nice if my
> implementation didn't depend upon an experimental feature that may not make
> it into GWT 2.0.  Step 2 is somewhat wasteful since it takes gwtc time
> generating a proxy class that it will ultimately throw away via dead code
> elimination.  Step 3 is pretty gross since the action proxy generator
> basically just divines the name of the _TypeOverridesFactory via string
> manipulation (see the getArtificialRescue method).  It may make sense to
> factor the _TypeOverridesFactory generation into its own public *Creator
> class that could return the generated class name (or maybe there's a better
> way for me to leverage that functionality).  Also, the comments for the
> ArtificialRescue class make me feel like a bad person for using it, so  if
> there's a better way to achieve what I'm trying to do (or could be in the
> future with some GWT changes) let me know.
> The one last bit of black magic required to make this work has to do with
> GWT's aggressive dead code elimination.  The action service proxy class that
> gets generated has code that essentially does:
> Throwable thrown = actionResult.getException();
> if (thrown != null)
>   callback.onFailure(thrown);
> else
>   callback.onSuccess(actionResult.getResult())
> However, because the field returned from the getException method never gets
> written (except by the eval'd code returned from the deRPC call), the GWT
> compiler thinks it can eliminate the whole if-block, resulting in an
> unconditional call to callback.onSuccess.  I'm not sure whether this is
> specific to how I'm doing things or if this is a bug with the deRPC code in
> general.  I currently work around it by creating a dummy action result
> object (of the generated action result class type) and I set the field
> returned to 'new Exception()'.  This currently tricks the compiler into
> thinking that the field gets written to a non-null value, but I don't have
> too much faith that it will continue to trick it in the future.  Who knows
> how smart that compiler will get?
> If you've gotten this far then... Wow, I'm impressed!  If you actually
> followed what I was trying to explain then I'm even more impressed.  I'd
> love to hear what more GWT-knowledgeable folk than me think about this
> implementation.  I think being able to add command pattern capabilities to
> existing GWT RPC services is pretty cool, but if it can't be implemented in
> a robust and maintainable way then it probably won't fly.
> Thanks,
> Jamie
>
> --
> http://groups.google.com/group/Google-Web-Toolkit-Contributors

-- 
http://groups.google.com/group/Google-Web-Toolkit-Contributors

Reply via email to