Simple GWT Client integrated with Spring built with Maven

Introduction

In this article we will integrate the SOAP client generated in the article:  Simple Spring-WS Application [with JPA and Jersey REST] into a GWT-Spring web application.  Again we are using Maven2 to build the application.  The web application is broken into to two GWT projects: Server and Web which can be built through a Parent project.  The Server project implments a GWT remote services with the Springframework working in the background to provide the SOAP connectivity.  GWT provides servlets that the GWT persentation layer communicates.

Implementation

The structure for this article is based upon the build environment created by Sam Brodking.  There are tools available which will allow for the building of the front and backend of Spring-GWT in a single project but I feel that there is value in this division from the perspective of unit testing and independent development.

The Server Project

The server side deals with the SOAP connection, extracts the entity objects from the SOAP messages, maps the entity objects into their DTO counter parts and makes operations available through a GWT servlet.

The SOAP connection is simple since it was solved in the last article: Simple SOAP Client Using XMLBeans.  To utilize its’ services we need only to add it as a dependency.  All the jar files related to enabling this dependency to perform are automatically installed through the definition of the dependency: this one of the great benifits to developing with Maven.

<dependency>
	<groupId>com.persistent</groupId>
	<artifactId>gclient</artifactId>
	<version>1.0-SNAPSHOT</version>
</dependency>

To create are service we need to provide the following:

  1. Create the remote interface to the service we are providing extending: com.google.gwt.user.client.rpc.RemoteService
  2. The implementation of that remote interface while also extending:import com.google.gwt.user.server.rpc.RemoteServiceServlet
  3. Additionally we create the Async Interface that is registered in our ServiceRegistry through which our client screens will execute commands against the service this occurs in the Web project and we will discuss it in more detail in that section.

This application defines one service which is the CompanyDirectory service.

The remote interface CompanyDirectoryDTO:

import com.google.gwt.user.client.rpc.RemoteService;
import com.persistent.client.domain.CompanyDTO;
import com.persistent.client.domain.PersonDTO;

public interface CompanyDirectoryDTO extends RemoteService {
	public PersonDTO addPersonDTO(PersonDTO person);
	public Integer countCompanies();
	public Integer countPersonDTOs();
	public String deletePersonDTO(String sid);
	public ArrayList<PersonDTO> findByCompanyDTOId(Long id);
	public ArrayList<PersonDTO> findByCompanyDTOIds(ArrayList<Long> ids);
	public ArrayList<CompanyDTO> getCompanies();
	public PersonDTO getPersonDTO(Long id);
	public ArrayList<PersonDTO> getPersonDTOs();
	public PersonDTO updatePersonDTO(PersonDTO person);
}

The implementation of the remote inter face CompanyDirectoryDTOImpl:

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.persistent.client.CompanyDirectoryDTO;
import com.persistent.client.domain.CompanyDTO;
import com.persistent.client.domain.PersonDTO;
import com.persistent.ws.client.SoapClient;

public class CompanyDirectoryDTOImpl extends RemoteServiceServlet implements
		CompanyDirectoryDTO {
	public PersonDTO addPersonDTO(PersonDTO person) {
		return SoapClient.addPersonDTO(person);
	}

	public String deletePersonDTO(String sid){
		return deletePersonDTO(Long.parseLong(sid));
	}

	public String deletePersonDTO(Long id) {
		if (id != null) {
			if (SoapClient.getCompanyDirectory() != null) {
				SoapClient.getCompanyDirectory().deletePerson(id);
			}
		}
		return "Success";
	}

	public ArrayList<PersonDTO> findByCompanyDTOId(Long id) {
		ArrayList<PersonDTO> result;
		if(id==null) {
			result = new ArrayList<PersonDTO>();
		} else {
			result = SoapClient.findByCompanyDTOId(id);
		}
		return result;
	}

	public ArrayList<CompanyDTO> getCompanies() {
			return SoapClient.getCompanies();
	}

	public ArrayList<PersonDTO> getPersonDTOs() {
		return (ArrayList<PersonDTO>) SoapClient.getPersonDTOs();
	}

	public PersonDTO updatePersonDTO(PersonDTO person) {
		return SoapClient.updatePerson(person);
	}

	public ArrayList<PersonDTO> findByCompanyDTOIds(ArrayList<Long> ids) {
		ArrayList<PersonDTO> result = new ArrayList<PersonDTO>();
		for (Long id : ids) {
			result.addAll(findByCompanyDTOId(id));
		}
		return result;
	}
   :
   :
}

The CompanyDirectoryDTOAsync:

import com.google.gwt.http.client.Request;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.persistent.client.domain.CompanyDTO;
import com.persistent.client.domain.PersonDTO;

public interface CompanyDirectoryDTOAsync {
	public Request addPersonDTO(PersonDTO person,AsyncCallback<PersonDTO> callback);
	public Request countCompanies(AsyncCallback<Integer> callback);
	public Request countPersonDTOs(AsyncCallback<Integer> callback);
	public Request deletePersonDTO(String sd,AsyncCallback<String> callback);
	public Request findByCompanyDTOId(Long id,AsyncCallback<ArrayList<PersonDTO>> asyncCallback);
	public Request findByCompanyDTOIds(ArrayList<Long> ids ,AsyncCallback<ArrayList<PersonDTO>> asyncCallback);
	public Request getCompanies(AsyncCallback<ArrayList<CompanyDTO>> asyncCallback);
	public Request getPersonDTO(Long id,AsyncCallback<PersonDTO> callback);
	public Request getPersonDTOs(AsyncCallback<ArrayList<PersonDTO>> asyncCallback);
	public Request updatePersonDTO(PersonDTO person, AsyncCallback<PersonDTO> callback);
}

These server function work in conjunction to the SOAP client.  We utilize the soap client through a simple api as generated in the: Simple SOAP Client using XMLBeans. To communicate through the GWT Servlet we need to make a data transfer object. Again we utilize the servces Dozer as described in a previous article here.

 Here is a general picture of the classes in the Server project ( external classes are not included).

 

The Web Project

We will focus on the communication services of this layer and update and leave the GWT presentation code to the reader.

The web application has a ClientMain class setups the application entry loading the GWT module and constructing the main pane with the ServiceRegistry.   The ServiceRegistry is were all communications with the server side are registered.  In this application we have one service registered:

Service Registry:

public class ServiceRegistry {
	private CompanyDirectoryDTOAsync companyDirectoryDTO;
	public CompanyDirectoryDTOAsync getCompanyDirectoryDTO() {
		if(companyDirectoryDTO == null) {
			companyDirectoryDTO = GWT.create(CompanyDirectoryDTO.class);
			((ServiceDefTarget)companyDirectoryDTO).setServiceEntryPoint(GWT.getModuleBaseURL() + "companyDirectoryDTO");
		}
		return companyDirectoryDTO;
	}
}

The communciation with the server side is done asynchronously.  The widgets are populated through AJAX callbacks as part of the GWT toolkit.  Below is an example of such a call when we populate all the persons in a company.

private void retrievePersonsInCompanies(ArrayList<Long> selectedCompanies) {
	getServiceRegistry().getCompanyDirectoryDTO().findByCompanyDTOIds(
			selectedCompanies, new AsyncCallback<ArrayList<PersonDTO>>() {
				public void onFailure(Throwable caught) {
					Window.alert("RPC failed.");
				}
				public void onSuccess(ArrayList<PersonDTO> pPersons) {
					persons.addAll(pPersons);
					refreshPersonsTable();
				}
			});
}

An overview of the Web Project classes

Web Project Class View

PersonChangeEvent: keeping screen information current

We have two screens that alow us to interact with the CompanyDirectories.  If we alter the information on one screen we want to insure that when we switch to the other screen that the information has been refreshed otherwise we will run into cached stale data.  To accomplish this we have implemented a simple PersonChangeEvent.  This is accomplished in the following way:

Each screen that maintains person information:

  1. implements the PersonChangeListener interface adding the personChange method to handle the change to the Person information
  2. registers themselves with the PersonChangePublisher
  3. when a screen alters Person data they publish a change through the pubilsh with a notifyPersonChange

The Screens look as follows

The Checkbox Screen


The Tree Screen


Compiling and Running the Application

There are a number of steps required to get this application working.  There are now two applications that need to run for both the JUnit test cases and the running application.

Prerequisite Tasks

Prior to building the GWT application we need to get the SOAP Service started.  It is prerequisite to have this SOAP service installed in the system  along with its client jar entered into the repository and the SOAP Client built .  Below are the links to the instructions to perform these  tasks:

  1. Installing the SOAP Service
  2. Deploy the client jar into the repository
  3. Building the SOAP client

Building the GWT Server and Web Project

Without running the test cases you can build the projects through parent directory with the following command:

mvn clean install -Dmaven.skip.test=true

This should build both projects.  Unfortuantely I find that there are problems at times with this approach and would highly recommend build with the test cases.

To build with the test cases one will have to start the SOAP service for the test cases to complete successfully.  We are going to have two web applications running the SOAP server and the GWT application.  For the SOAP server we can alter the port that Jetty runs the application on with the following command run from the SOAP server’s root directory:

mvn jetty:run -Djetty.port=9444

We are now free to run the GWT build along with it’s test cases.  The GWT application is coded to utilize the SOAP service on port 9444 of the localhost.  Again the command to build the GWT application is from the Parent project root directory:

mvn clean install

I have found that sometimes there are problems in the building of the Web project.  In this case I go into the Web project root directory and issue that same command.  Hopefully this will resolve the problem.  If not send me an e-mail and we’ll get it straightened out.

At this point we should have a war file in the Web project’s target directory which is ready for deployment in a tomcat6.x /Java 1.5 environment.  I have not tested others so you’ll be on your own if you need to use an alternate.

Here is a trick part (part of the build process I didn’t get ironed out (feel free to send me the answer)).  I copy the web-1.–SNAPSHOT.war into the webapp directory of tomcat and when it has deployed I copy the following two files from Server project:

  1. server/src/main/resources/applicationContext.xml
  2. server/src/main/resources/dozer-bean-mappings.xml

The application should not be available for use at:

http://localhost:8080/web-1.0-SNAPSHOT/com.persistent.Application/Application.html

Additionally the REST server should also be available, since it is included in the SOAP Server, at:

http://localhost:9444/general/crud.html

 

Source Code

Here is the source code.

Conclusion

That concludes the simple GWT user interface into the Company Directory SOAP Service.  It is a complex setup.  If you are interested in installing this on your local machine please don’t hesitate to contact me if you should have any difficulties setting it up.

 

About The Author

David Sells is a computer consultant in Toronto, Ontario who specializes in Java Enterprise Development. He has  provided innovative solutions for clients including: IBM, Goldman Sachs, Merrill Lynch and Deutsche Bank.

He also holds the following certifications:

  • Sun Certified Enterprise Architect for the Java Platform, Enterprise Edition 5 (2009)
  • Sun Certified Web Component Developer
  • Sun Certified Java Programmer.

Contact: david@persistentdesigns.com

 

 

 

 

 

 

 

1 comment to Simple GWT Client integrated with Spring built with Maven

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>