The use of the Command pattern for the organization of RPC calls in GWT
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 - package net.pimgwt.client.rpc;
the
- import net.customware.gwt.dispatch.shared.Action;
the
- @SuppressWarnings("serial")
public class SingleRequestAction implements Action<SingleRequestResult> {
private String param;
public SingleRequestAction() {
the
- }
public SingleRequestAction(String param) {
this.param = param;
the
- }
public String getParam() {
return this.param;
the
- }
the - }
* 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 - package net.pimgwt.client.rpc;
the
- import net.customware.gwt.dispatch.shared.Result;
the
- @SuppressWarnings("serial")
public class SingleRequestResult implements Result {
private String resultMessage;
public SingleRequestResult() { }
public SingleRequestResult(String resultMessage) {
this.resultMessage = resultMessage;
the
- }
public String getResultMessage() {
return this.resultMessage;
the
- }
the - }
* 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 - package net.pimgwt.server;
the
- import net.customware.gwt.dispatch.server.service.DispatchServiceServlet;
the
- import com.google.inject.servlet.ServletModule;
public class DispatcherServletModule extends ServletModule {
@Override
protected void configureServlets() {
the
- serve("/rpc_command/dispatch").with(DispatchServiceServlet.class);
the - }
the - }
* 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
the
public class SingleRequestHandler implements ActionHandler<SingleRequestAction, SingleRequestResult> {
@Override
public SingleRequestResult execute(SingleRequestAction action, ExecutionContext the
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
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 - package net.pimgwt.server;
the
- import net.customware.gwt.dispatch.server.guice.ActionHandlerModule;
public class RpcCommandHandlerModule extends ActionHandlerModule {
@Override
protected void configureHandlers() {
the
- bindHandler(SingleRequestHandler.class);
the - // . . .
the - }
the - }
* 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 - package net.pimgwt.server;
the
- import com.google.inject.Guice;
the - import com.google.inject.Injector;
the - import com.google.inject.servlet.GuiceServletContextListener;
public class RpcCommandGuiceConfig extends GuiceServletContextListener {
@Override
protected Injector getInjector() {
return Guice.createInjector(new RpcCommandHandlerModule () new DispatcherServletModule());
the
- }
the - }
* 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 - // . . .
private DispatchAsync rpcDispatcher = new DefaultDispatchAsync();
the
- // . . .
@UiField Button singleValueTestButton;
the
- // . . .
the
- @UiHandler("singleValueTestButton")
public void singleValueButtonClicked(ClickEvent event) {
the
- responseLable.setText("");
the
- rpcDispatcher.execute(new SingleRequestAction(paramTextbox.getText ()) new
the - AsyncCallback<SingleRequestResult>() {
@Override
public void onFailure(Throwable caught) {
the
- responseLable.setText("Error occured: " +
the - caught.getMessage());
the - }
@Override
public void onSuccess(SingleRequestResult result) {
the
- responseLable.setText(result.getResultMessage());
the - }
the - });
the - }
* 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
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.
Комментарии
Отправить комментарий