The use of the Command pattern for the organization of RPC calls in GWT

In his statement Google I/O Rayan Ray told the audience about how to properly cost the architecture more or less large GWT projects. One of his recommendations — the use of a template (pattern) Command for organizatsii RPC services. In this article I will try to briefly highlight the approach on the example of a simple GWT application. For dispatching RPC calls will be used the library of gwt-dispatch GWT-Dispatch. Just want to warn you that this article is a symbiosis, interpretation and compilation of several sources (GWT-Dispatch Getting Started, GWT MVP Example). Think of it as a quick start guide on the correct way of building GWT applications. All material is designed so that server-side implementation of the RPC services also run on the Java language.


It is no secret that the development of less major applications to help us hasten the templates (patterns) of design. Patterns are a sort of recipes to solve specific cases of the model. A head start in the study and application of design patterns can be Patterns on Wiki continue to deepen already in relevant books, articles, papers, etc.
To be brief, the template Command (Command) allows to perform implementation-specific interface Command (Action etc.) through a uniform interface.



Regarding GWT RPC, this approach will allow you to have one interface call RPC services (Manager) and pass an object of the corresponding action (command).

the

Connect necessary libraries


So, to implement the RPC interop in the project with the commands we need to connect additional libraries:
the
    the
  • GWT-Dispatch — GWT implementation of call Manager. Also, this library provides the interfaces between Action and Result for commands and their execution results.
  • the
  • Google Guice — Dependency Injection framework from Google. Allows you to manage dependencies in server-side code using the Dependency Injection approach. It is much easier all known Spring Framework, and, consequently, is faster. With the implementation of the demo project Guice also served as service Manager servlet and initializes the link only the server side. But more on that later.
  • the
  • Google GIN — implementation of Guice for GWT. Allows you to apply DI-approach in the client-side (i.e. GWT) code. Obviously we can't use, it requires as a dependency.

To connect these libraries to the project enough to put the files gin-1.0.jar, guice-2.0.jar, guice-servlet-2.0.jar and gwt-dispatch-1.0.0.jar in WEB-INF/lib and add them to the Build Path of the project. The configuration of the GWT-module with plug-in modules I have looks like this:

    <?xml version="1.0" encoding="UTF-8"?>

    <module rename-to='rpc_command'>

    <inherits name='com.google.gwt.user.User' />

    <inherits name="com.google.gwt.inject.Inject" />

    <inherits name="net.customware.gwt.dispatch.Dispatch" />

    <entry-point class='net.pimgwt.client.RpcCommandEntryPoint' />

    <source path='client' />

    </module>

* This source code was highlighted with Source Code Highlighter.


the

Organization specific command on the GWT side


The team I will illustrate on the example of creating a single RPC call. Its essence is simple as a door: to send server method read from the input field parameter and get the answer. All. Oh, and for displaying the received response on the UI. The demo project contains another challenge from the server gets the array of the fake DTO objects. The code will not be considered in this note. If interested, I can provide further comment.
To create the RPC commands you need to create a class that implements the Action interface:
    the
  1. package net.pimgwt.client.rpc;
  2. the

  3. import net.customware.gwt.dispatch.shared.Action;
  4. the

  5. @SuppressWarnings("serial")
  6. public class SingleRequestAction implements Action<SingleRequestResult> {

    private String param;

    public SingleRequestAction() { the

  7. }
  8. public SingleRequestAction(String param) {

    this.param = param; the

  9. }
  10. public String getParam() {

    return this.param; the

  11. }
  12. the
  13. }
* This source code was highlighted with Source Code Highlighter.

As you can see, nothing complicated. This command encapsulates the parameter that will be passed to the server. The only interesting point is the indication that the execution result will be an object of class SingleRequestResult:
    the
  1. package net.pimgwt.client.rpc;
  2. the

  3. import net.customware.gwt.dispatch.shared.Result;
  4. the

  5. @SuppressWarnings("serial")
  6. public class SingleRequestResult implements Result {

    private String resultMessage;

    public SingleRequestResult() { }

    public SingleRequestResult(String resultMessage) {

    this.resultMessage = resultMessage; the

  7. }
  8. public String getResultMessage() {

    return this.resultMessage; the

  9. }
  10. the
  11. }
* This source code was highlighted with Source Code Highlighter.

which also encapsulates the data that is "coming" to the client code.
At the moment of preparation on the client side is finished. It's time to take the roasting coffee bean that will work on the server. By the way, the server we will work on Google App Engine.

the

server-side implementation of the RPC service


Library GWT-Dispatch provides the tools for organization managers in both client and server parts.
Let's start configuring the server-side with a dispatcher servlet that will handle the processing of RPC call:

    the
  1. package net.pimgwt.server;
  2. the

  3. import net.customware.gwt.dispatch.server.service.DispatchServiceServlet;
  4. the

  5. import com.google.inject.servlet.ServletModule;
  6. public class DispatcherServletModule extends ServletModule {

    @Override

    protected void configureServlets() { the

  7. serve("/rpc_command/dispatch").with(DispatchServiceServlet.class);
  8. the
  9. }
  10. the
  11. }
* This source code was highlighted with Source Code Highlighter.

The class DispatcherServletModule successor ServletModule. In this overwritten method of the parent configureServlets(), which sets the according RPC implementation-URL of the dispatcher servlet, which is GWT-Dispatch. The default URL that will be monitored by the dispatcher is based on the scheme appname/dispatch.
Now implement the handler (handler), which will be tied to the team that is declared on the client side (the command SingleRequestAction):
the
  • package net.pimgwt.server;
  • the

  • import net.customware.gwt.dispatch.server.ActionHandler;
  • the
  • import net.customware.gwt.dispatch.server.ExecutionContext;
  • the
  • import net.customware.gwt.dispatch.shared.ActionException;
  • the
  • import net.pimgwt.client.rpc.SingleRequestAction;
  • the
  • import net.pimgwt.client.rpc.SingleRequestResult;
  • public class SingleRequestHandler implements ActionHandler<SingleRequestAction, SingleRequestResult> {

    @Override

    public SingleRequestResult execute(SingleRequestAction action, ExecutionContext the

  • context) throws ActionException {
  • return new SingleRequestResult("You are entered: " + action.getParam()); the

  • }
  • @Override

    public Class<SingleRequestAction > getActionType() {

    return SingleRequestAction.class; the

  • }
  • @Override

    public void rollback(SingleRequestAction action, SingleRequestResult result the

  • ExecutionContext context) throws ActionException { }
  • the
  • }
  • * This source code was highlighted with Source Code Highlighter.
    The command handler implements the generic-interface, with parameterization which specifies the command and its result. In this case, SingleRequestAction and SingleRequestResult, respectively. Interface ActionHandler class also requires the implementation to provide the methods execute () getActionType() and rollback(), whose names speak for themselves. In the above code for such a simple command as SingleRequestAction action rollback in case of failure, just left blank. There is nothing to roll back.
    The result of executing the method execute() object is SingleRequestResult, we simply write the response text that will be passed to the caller (client) side.
    Well, the method getActionType() should return a reference to the command class, which is tied to the processor. This is to ensure that the Manager was able to correctly call the appropriate handler, and not some other.
    In addition to direct dispatch and delivery of interfaces, Action and Result, the library of GWT-Dispatch also provides integration with Google Guice. This integration allows you to register handlers for commands in Guice context:
      the
    1. package net.pimgwt.server;
    2. the

    3. import net.customware.gwt.dispatch.server.guice.ActionHandlerModule;
    4. public class RpcCommandHandlerModule extends ActionHandlerModule {

      @Override

      protected void configureHandlers() { the

    5. bindHandler(SingleRequestHandler.class);
    6. the
    7. // . . .
    8. the
    9. }
    10. the
    11. }
    * This source code was highlighted with Source Code Highlighter.

    Tie everything together with class GuiceServletContextListener, which will "listen" to what is happening outside and respond in the case, when the client will be requested /rpc_command/dispatch and run the appropriate command handler:
      the
    1. package net.pimgwt.server;
    2. the

    3. import com.google.inject.Guice;
    4. the
    5. import com.google.inject.Injector;
    6. the
    7. import com.google.inject.servlet.GuiceServletContextListener;
    8. public class RpcCommandGuiceConfig extends GuiceServletContextListener {

      @Override

      protected Injector getInjector() {

      return Guice.createInjector(new RpcCommandHandlerModule () new DispatcherServletModule()); the

    9. }
    10. the
    11. }
    * This source code was highlighted with Source Code Highlighter.

    The class GuiceServletContextListener is Guice framework as a means of its integration with Java Servlets. The above code will perform the required injection (injects) in the right places. Thus we have the chain of integration of GWT-Dispatch and Guice and Servlets will be closed.
    The last step that is needed in order to get it all played as a single ensemble – the statement web.xml file need of the student and the appropriate filter query:

      <?xml version="1.0" encoding="UTF-8"?>

      PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

      "http://java.sun.com/dtd/web-app_2_3.dtd">

      <web-app>

      <filter>

      <filter-name>guiceFilter</filter-name>

      <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>

      </filter>

      <filter-mapping>

      <filter-name>guiceFilter</filter-name>

      <url-pattern>/*</url-pattern>

      </filter-mapping>

      <listener>

      <listener-class>net.pimgwt.server.RpcCommandGuiceConfig</listener-class>

      </listener>

      <welcome-file-list>

      <welcome-file>index.html</welcome-file>

      </welcome-file-list>

      </web-app>

    * This source code was highlighted with Source Code Highlighter.
    GuiceFilter is configured to filter all requests that fall on the server side from the client. Esstestvenno, in the url param-the user can specify the URL pattern to listen to. How to do it I will not say this is obvious and irrelevant to the question at issue.
    The server part is ready. Left now to bind RPC calls from client code Manager.

    the

    Dispatching of the teams in the GWT code.


    For RPC commands in GWT code meets interface DispatchAsync. You can implement this interface as you wish, for example, as a Manager, which is able to cache previous results. For a demo project I chose "boxed" implementation of a DefaultDispatchAsync again from the delivery of GWT-Dispatch.
    Below I will give only the handler for clicking on the button that initiates the RPC call through the specified interface and displays obtained from server-side result:
      the
    1. // . . .
    2. private DispatchAsync rpcDispatcher = new DefaultDispatchAsync(); the

    3. // . . .
    4. @UiField Button singleValueTestButton; the

    5. // . . .
    6. the

    7. @UiHandler("singleValueTestButton")
    8. public void singleValueButtonClicked(ClickEvent event) { the

    9. responseLable.setText("");
    10. the

    11. rpcDispatcher.execute(new SingleRequestAction(paramTextbox.getText ()) new
    12. the
    13. AsyncCallback<SingleRequestResult>() {
    14. @Override

      public void onFailure(Throwable caught) { the

    15. responseLable.setText("Error occured: " +
    16. the
    17. caught.getMessage());
    18. the
    19. }
    20. @Override

      public void onSuccess(SingleRequestResult result) { the

    21. responseLable.setText(result.getResultMessage());
    22. the
    23. }
    24. the
    25. });
    26. the
    27. }
    * This source code was highlighted with Source Code Highlighter.

    The main point here is that we give the Manager initialized the command to send it to the server. In College from the resulting Olvera SingleRequestResponse just retrieves the result responseLable.setText(result.getResultMessage());
    All written, implemented, configured, and even works!

    the

    Demo project


    The screenshot below shows the structure demo project in the Project panel Packages

    image hosting

    If you look at it, we can see that the project implemented another RPC command, MultiRequestAction. The execution result is MultiRequestResult, which in turn contains a list of objects DummyDTO, which is filled in a loop in serverom the handler for this command.
    The project for live viewing is available RPC Command Demo Project

    the

    in conclusion


    The described approach RPC interaction does not diminish the role of a simple RPC calls that were discussed in the article Authorization service User Service in GWT applications. In some cases, when you have to project a maximum of two requests to the server side, it makes little sense to fuss from the Action s, Result s, some Guice and others like them does not make sense, because that only complicates the code. On the other hand, the use of "correct" practices in creating OOP-code increases its strukturelement, readability and dobavte your benefit.
    Moreover, I am aware of several projects on GWT, which are generally on the server side does not contain Java. So with such a server implementation of esstestvenno to use a common messaging format, for example JSON or XML. But that's another story.

    Waiting for constructive critics, suggestions and of course questions!
    Thank you.
    Article based on information from habrahabr.ru

    Комментарии

    Популярные сообщения из этого блога

    March Habrameeting in Kiev

    PostgreSQL load testing using JMeter, Yandex.Tank and Overload

    Monitoring PostgreSQL with Zabbix