Tuesday, October 25, 2011

Spring and GWT tutorial. Part 3 - GWT RPC Services


Recently I've started working in a GWT project. It is a new technology for me, so I've decided to create a simple web application based on Spring and GWT.

This post has a Russian version.

We have already integrated Spring and GWT in our application. At this time we will make client and server sides of our application effectively communicate with each other using a GWT RPC service.

We will use Spring annotations instead of XML to configure application beans. To make it possible we should add <context:component-scan/> into applicationContext.xml and set the package where beans are located:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.hellogwt"/>

</beans>

According to GWT RPC rules, let's create service GreetingService annotated with @RemoteServiceRelativePath in com.hellogwt.client package. It will contain only one method greet() that takes and returns a String:
package com.hellogwt.client;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;

@RemoteServiceRelativePath("springGwtServices/greetingService")
public interface GreetingService extends RemoteService {

    String greet(String name);
}

Service GreetingService should have a pair - asynchronous service GreetingServiceAsync. Create it in the same package:
package com.hellogwt.client;

import com.google.gwt.user.client.rpc.AsyncCallback;

public interface GreetingServiceAsync {

    void greet(String name, AsyncCallback<String> callback);
}

Now let's create a server part of our application. Create a class that implements GreetingService interface in com.hellogwt.server package. Don't forget to annotate it with @Service. Class GreetingServiceImpl implements method greet(). In our case the method takes one String as an argument, builds another String and returns it:
package com.hellogwt.server;

import com.hellogwt.client.GreetingService;
import org.springframework.stereotype.Service;

@Service("greetingService")
public class GreetingServiceImpl implements GreetingService {

    @Override
    public String greet(String name) {
        return "Hello, " + name + "!";
    }
}

All that left is to use our service in application. We will invoke greet() method every time any symbol is entered into the text field. If greet() completes successfully then label text will change to String that method returns. Otherwise label text will tell us about error:
package com.hellogwt.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.*;

public class HelloGWT implements EntryPoint {
    private GreetingServiceAsync greetingService = GWT.create(GreetingService.class);
    private TextBox nameTextBox = new TextBox();
    private Label greetingLabel = new Label("Hello, GWT!");

    @Override
    public void onModuleLoad() {
        RootPanel.get().add(nameTextBox);
        RootPanel.get().add(greetingLabel);

        final AsyncCallback<String> callback = new AsyncCallback<String>() {
            @Override
            public void onFailure(Throwable caught) {
                greetingLabel.setText("ERROR!");
            }

            @Override
            public void onSuccess(String result) {
                greetingLabel.setText(result);
            }
        };

        nameTextBox.addKeyUpHandler(new KeyUpHandler() {
            @Override
            public void onKeyUp(KeyUpEvent keyUpEvent) {
                greetingService.greet(nameTextBox.getText(), callback);
            }
        });
    }
}

Build the project by executing  "mvn clean install" command:
[INFO] Scanning for projects...
[WARNING] 
[WARNING] Some problems were encountered while building the effective model for hellogwt:hellogwt:war:1.0
[WARNING] 'build.plugins.plugin.version' for org.codehaus.mojo:tomcat-maven-plugin is missing. @ line 76, column 21
[WARNING] 
[WARNING] It is highly recommended to fix these problems because they threaten the stability of your build.
[WARNING] 
[WARNING] For this reason, future Maven versions might no longer support building such malformed projects.
[WARNING] 
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building hellogwt 1.0
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-clean-plugin:2.4.1:clean (default-clean) @ hellogwt ---
[INFO] Deleting D:\Work\hellogwt\target
[INFO] 
[INFO] >>> tomcat-maven-plugin:1.1:deploy (default-cli) @ hellogwt >>>
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:resources (default-resources) @ hellogwt ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ hellogwt ---
[WARNING] File encoding has not been set, using platform encoding Cp1252, i.e. build is platform dependent!
[INFO] Compiling 6 source files to D:\Work\hellogwt\target\classes
[INFO] 
[INFO] --- maven-resources-plugin:2.4.3:testResources (default-testResources) @ hellogwt ---
[WARNING] Using platform encoding (Cp1252 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory D:\Work\hellogwt\src\test\resources
[INFO] 
[INFO] --- maven-compiler-plugin:2.3.2:testCompile (default-testCompile) @ hellogwt ---
[INFO] Nothing to compile - all classes are up to date
[INFO] 
[INFO] --- maven-surefire-plugin:2.7.2:test (default-test) @ hellogwt ---
[INFO] No tests to run.
[INFO] Surefire report directory: D:\Work\hellogwt\target\surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
There are no tests to run.

Results :

Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

[INFO] 
[INFO] --- gwt-maven-plugin:2.4.0:compile (default) @ hellogwt ---
[INFO] auto discovered modules [com.hellogwt.HelloGWT]
[INFO] Compiling module com.hellogwt.HelloGWT
[INFO]    Compiling 6 permutations
[INFO]       Compiling permutation 1...
[INFO]       Process output
[INFO]          Compiling
[INFO]             Compiling permutation 0...
[INFO]       Compiling permutation 2...
[INFO]       Compiling permutation 3...
[INFO]          Compiling
[INFO]             Compiling permutation 4...
[INFO]       Compiling permutation 5...
[INFO]    Compile of permutations succeeded
[INFO] Linking into D:\Work\hellogwt\target\hellogwt-1.0\hellogwt
[INFO]    Link succeeded
[INFO]    Compilation succeeded -- 30.131s
[INFO] 
[INFO] --- maven-war-plugin:2.1.1:war (default-war) @ hellogwt ---
[INFO] Packaging webapp
[INFO] Assembling webapp [hellogwt] in [D:\Work\hellogwt\target\hellogwt-1.0]
[INFO] Processing war project
[INFO] Copying webapp resources [D:\Work\hellogwt\src\main\webapp]
[INFO] Webapp assembled in [308 msecs]
[INFO] Building war: D:\Work\hellogwt\target\hellogwt-1.0.war
[WARNING] Warning: selected war files include a WEB-INF/web.xml which will be ignored 
(webxml attribute is missing from war task, or ignoreWebxml attribute is specified as 'true')
[INFO] 
[INFO] <<< tomcat-maven-plugin:1.1:deploy (default-cli) @ hellogwt <<<
[INFO] 
[INFO] --- tomcat-maven-plugin:1.1:deploy (default-cli) @ hellogwt ---
[INFO] Deploying war to http://localhost:8080/hellogwt  
[INFO] OK - Deployed application at context path /hellogwt
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 37.890s
[INFO] Finished at: Fri Nov 18 00:00:40 EET 2011
[INFO] Final Memory: 16M/309M
[INFO] ------------------------------------------------------------------------

Now we have application war-file. Copy it into Tomcat's webapps folder, start the server and go to http://localhost:8080/hellogwt/. Label text should change according to text field value:











Folder structure:



































Application source code is available at https://subversion.assembla.com/svn/hellogwt-3/trunk/.

We have added GWT RPC services to our application. Well done! Next we will add a MySQL database support to our application using MyBatis framework.

11 comments:

  1. Hi, interesting topic, but when i replaced my gwt part within ur demo, the css was not working, i placed it in the same place of GWT PROJECT,

    Suggestions would be helpful,

    Thanks anyway :D

    ReplyDelete
    Replies
    1. Mustafa, I didn't make accent on stylesheets and UI design. You can read about best practices there.

      Delete
  2. I am getting this

    com.google.appengine.tools.development.LocalResourceFileServlet doGet
    WARNING: No file found for: /connect2telos/gwtSpringServices/greetingService

    ReplyDelete
    Replies
    1. Hi, vickey! Please, look at working application source code to find possible errors in yours

      Delete
  3. I get this error after run:
    Etat HTTP 404 - Servlet springGwtRemoteServiceServlet n'est pas disponible.

    type Rapport d'état

    message Servlet springGwtRemoteServiceServlet n'est pas disponible.

    description La ressource demandée n'est pas disponible.
    Apache Tomcat/6.0.36

    ReplyDelete
    Replies
    1. Sorry, I don't speak French.
      But it seems there are problems with usage of spring4gwt library. Please, check that it is visible in project and check annotations.

      Delete
  4. I don't see the hellogwt.css and hellogwt/hellogwt.nocache.js file in the link http://hellogwt-5.googlecode.com/svn/trunk/src/main/webapp/. After successfull run empty content in the http://localhost:8080/hellogwt/

    ReplyDelete
    Replies
    1. These files should be created during project compilation. Please, try to do it

      Delete
  5. Also, I got something like this :annotations are not supported in -source 1.3
    (use -source 5 or higher to enable annotations)

    Maven default is using JDK1.3 for the project compilation, building or packaging (mvn compile, install). Since JDK1.3 is not support annotation, if your project has annotation, you need to configure your Maven to use the latest JDK version. The solution is very simple, just include the Maven compiler plugin and specify the JDK version.

    The solution I have obtained from this source: http://www.mkyong.com/maven/annotations-are-not-supported-in-source-1-3-maven/

    ReplyDelete
    Replies
    1. German, thank you for problem description and solution!

      Delete
  6. Hello, please help me, how to debug en client, HelloGWT, PLEASE.

    ReplyDelete