Monday, August 29, 2011

How to deploy my application in an external directory in JBoss-5

If you want to deploy an application outside the "deploy" folder of JBoss in JBossAS-5, you can add your user directory to the ProfileService bootstrap process. This will automatically pick up the specified directory and treat it as if you would put the content to the deploy/ folder. Note that all specified folders need to be fully qualified url.

JBoss AS 5.0.0 EAP
Same as the instructions for JBoss AS 5.1.x below, edit the server/${jboss.server.name}/conf/bootstrap/profile.xml.
JBoss AS 5.1.x
Starting with 5.1.0.Beta1 there have been some changes to the ProfileService. To add your custom folder you would need to edit the server/${jboss.server.name}/conf/bootstrap/profile.xml.


Note - the folder names must be specified using URL syntax. For example, to specify that /home/jpai/test/deploy be used for deployment, the example below uses the value file:///home/jpai/test/deploy.

<bean name="BootstrapProfileFactory"
     class="org.jboss.system.server.profileservice.repository.StaticProfileFactory">
     <property name="bootstrapURI">${jboss.server.home.url}conf/jboss-service.xml</property>
     <property name="deployersURI">${jboss.server.home.url}deployers</property>
     <property name="applicationURIs">
          <list elementClass="java.net.URI">
               <value>${jboss.server.home.url}deploy</value>

               <!-- Add your own deploy folder -->
               <value>file:///home/jpai/test/deploy</value>
          </list>
     </property>
     ...
</bean>


JBoss AS 5.0.x
In JBoss AS 5.0.0.GA you need to edit the %JBOSS_HOME%/server/< serverName>/conf/bootstrap/profile-repository.xml and add your directory to the URIs property of SerializableDeploymentRepositoryFactory bean. Here's an example, where i am adding my /home/jpai/test/deploy folder to the URIs property. Doing so, i will be able to place any deployable application in /home/jpai/test/deploy folder, so that it will be picked up for deployment:

<bean name="SerializableDeploymentRepositoryFactory" 
     class="org.jboss.system.server.profileservice.repository.SerializableDeploymentRepositoryFactory">
      <property name="storeRoot">${jboss.server.base.dir}</property>
      <property name="attachmentsRoot">${jboss.server.data.dir}/attachments</property>
      <property name="applicationURIs">
         <array elementClass="java.net.URI">
            <value>${jboss.server.home.url}deploy</value>
           
              <!-- Add my own folder -->
            <value>file:/home/jpai/test/deploy</value>
     ...
</bean>

JBoss AS 5.x Architecture

2.4. What is new in JBoss AS 5?

  • New kernel ⇒ JBoss Microcontainer
    • is a refactoring of old JMX Microkernel (JBoss AS 3.x and 4.x)
    • the core of JBoss AS 5
  • New messaging provider ⇒ JBoss Messaging
    • Replaces old JBossMQ (shipped with JBoss AS 4.x series)
  • One of the first application servers to implement EJB 3.0 specification (dating back to 4.x series)
  • Reliable transaction manager ⇒ JBoss TS
    • more than 20 years of expertise in transaction management
  • JBoss Web based on Apache Tomcat 6.0
  • JBoss WS 3.0 (support for JAX-WS/JAX-RPC)
    • can be replaced by Sun Metro or Apache CXF for example
  • Two new configurations:
    • standard: Java EE compliant configuration.
    • web: provides support for JTA/JCA and JPA in addition to the Servlet/JSP container. The server can only be accessed through the http port.

2.5. JBoss AS Architecture

"JBoss AS is assembled from a set of independent, yet cooperating components and services that are neatly packaged and fully hot-deployable. It is architected to be seamlessly embeddable in applications, and the nature of its embedding is completely customizable to the requirements of the application itself. Only the critical and necessary application server components, therefore, need to be brought along as part of the application’s baseline footprint. Developers can also easily create and add their own services to the system, thus ensuring that custom services exhibit the same consistent behavior as the JBoss standard set of services."

2.6. JBoss Microcontainer Layer

JBoss Microcontainer is an inversion of control (IoC) framework. IoC frameworks let you create, configure and wire up simple Java objects (POJOs). Classes don’t need special coding to be usable. The objects created usualy represent the modules of your application.
  • Replaces JMX-based Microkernel, though still supports all JMX Microkernel features
  • IoC framework similar to Spring IoC
  • POJO based kernel (no need for Standard/XMBean or MBeanProxy)
  • Simplified and improved lifecycle management
  • Additional control over dependencies
  • Transparent AOP integration
  • Virtual File System (VFS)
  • Virtual Deployment Framework
  • OSGi class-loading

2.7. Services Layer

  • Service-oriented architecture - service is either defined as a POJO or a JMX Managed Bean (use the JMX kernel, still available in JBoss 5.x but is created by JBoss Microcontainer).
  • Services are hot-pluggable
  • Makes it possible to tune the system for just the required services to lower the overall footprint (easier to secure and tune)
  • Easy to define new services and package them as SARs (service archives) or JARs (Java ARchives)
  • Examples: Servlet/JSP container, EJB container, transaction management, messaging, connection pooling, security etc.

2.8. Aspect Layer

Increase the modularity of an application by allowing the separation of cross-cutting concerns (e.g logging is often required in many parts of your application).
  • Based on aspect-oriented programming model (AOP)
  • Defines cross-cutting simple-to-use services
  • Makes it possible to add object persistence, caching, replication, remoteness, security, etc. late in the development cycle by annotating existing plain-old-java-objects (a.k.a POJOs) 

2.9. Application Layer

  • This is where Java EE applications reside
  • This layer deals with the business logic while leaving the container services up to JBoss AS
  • Portable - Independent of JBoss AS

2.10. JBoss AS Services

  • JBoss Microcontainer - POJOs services container
  • JBoss Microkernel - JMX MBean server (One of the primary POJOs created by JBoss Microcontainer)
  • Aspect-oriented Framework
  • Web Application Services - based on Tomcat (Servlet, JSP, JSF)
  • Enterprise Services: EJB, ORB, JNDI, JTA
  • Web Services - based on SOAP, WSDL, UDDI, and XML
  • Messaging Services: JMS, JDBC, JCA
  • Persistence Services - Hibernate O/R mapping and transparent persistence
  • HA Services: clustering, fail-over, load-balancing, distributed deployments
  • Security Services - based on JAAS
  • Console Services - monitoring, configuration, deployment, management, lifecycle


Thursday, August 18, 2011

Configuring a datasource for Oracle DB

To make the JDBC driver classes available to JBoss Application Server, copy the archive ojdbc5.jar to the lib directory in the default server configuration (assuming that is the server configuration you’re running).
Then create a text file in the deploy directory called oracle-ds.xml with the following datasource descriptor :

Install JDBC Drivers


For the JBoss Application Server and our applications to use the external database, we also need to install the database's JDBC driver. The JDBC driver is a JAR file, which you'll need to copy into your JBoss AS's <JBoss_Home>/server/all/lib directory. Replace all with the server configuration you are using if needed. This file is loaded when JBoss starts up. So if you have the JBoss AS running, you'll need to shut down and restart. The availability of JDBC drivers for different databases are as follows.


Creating a DataSource for the External Database

JBoss AS connects to relational databases via datasources. These datasource definitions can be found in the <JBoss_Home>/server/all/deploy directory. The datasource definitions are deployable just like WAR and EAR files. The datasource files can be recognized by looking for the XML files that end in *-ds.xml.

Friday, June 17, 2011

GWT 2 Spring 3 JPA 2 Hibernate 3.5 Tutorial

This step by step guide will present how to develop a simple web application using Google's Web Toolkit (GWT) for the rich client and Spring as the back – end, server side framework. The sample web application will provide functionality to make CRUD (Create Retrieve Update Delete) operations to a database. For the data access layer we will use JPA over Hibernate and for a database we will use Hypersonic. Of course you can change the configuration and use whatever you like. We will deploy the web application to an Apache – Tomcat instance.

Our preferred development environment is Eclipse, so as a prerequisite you must have Eclipse with GWT support installed. The installation of the GWT plugin for Eclipse is out of the scope of this tutorial and will not be discussed. Nevertheless you will need the following components :

  1. Eclipse from here
  2. GWT Plugin for Eclipse from here
  3. Spring framework distribution from here
  4. Hibernate persistence framework distribution from here
  5. Hypersonic database from here
  6. Apache commons-logging library from here
  7. AOP Alliance (Java/J2EE AOP Standard) library from here
  8. SLF4J library from here
  9. Apache log4j library from here
  10. Last but not least, download the GWT – Spring “glue” library spring4gwt from here
We will be using Eclipse Galileo, GWT version 2.0.3, Spring version 3.0.1, Hibernate version 3.5.2, Hypersonic version 1.8.1.2, Apache commons-logging version 1.1.1, AOP Alliance (Java/J2EE AOP Standard) version 1.0, SLF4J version 1.5.8, Apache log4j version 1.2.16 and spring4gwt version 0.0.1 for this tutorial.

Enough talk, lets get our hands dirty!
  1. Create a new GWT project, go to File → New Web Application Project
  2. We will name our project GWTSpring. The base package will be com.javacodegeeks.gwtspring also use only Google Web Toolkit thus uncheck “Use Google App Engine” at the wizard window.
Let's recap a few things about the GWT project structure
  1. /src folder contains all source files of the application
    • {package_name}.client subpackage contains all source files only available to the client side of the application
    • {package_name}.server subpackage contains all source files only available to the server side part of the application
    • {package_name}.shared subpackage contains all source files available to both the client and server side of the application
  2. /test folder contains all source files for unit tests
  3. /war folder contains essential files for creating a valid web application
In order to properly integrate Spring with GWT at runtime, we must provide all necessary libraries to the web application. So copy the files listed below under /war/WEB-INF/lib (copy the relevant files if you are using different versions)

From Spring distribution
  • /dist/org.springframework.expression-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.beans-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.oxm-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.jms-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.jdbc-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.core-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.context-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.asm-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.aspects-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.transaction-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.context.support-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.aop-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.orm-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.instrument-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.instrument.tomcat-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.test-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.web-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.web.portlet-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.web.servlet-3.0.1.RELEASE-A.jar
  • /dist/org.springframework.web.struts-3.0.1.RELEASE-A.jar
From the Hibernate distribution
  • hibernate3.jar
  • /lib/required/antlr-2.7.6.jar
  • /lib/required/commons-collections-3.1.jar
  • /lib/required/dom4j-1.6.1.jar
  • /lib/required/javassist-3.9.0.GA.jar
  • /lib/required/jta-1.1.jar
  • /lib/required/slf4j-api-1.5.8.jar
  • /lib/jpa/hibernate-jpa-2.0-api-1.0.0.Final.jar
  • /lib/optional/c3p0/c3p0-0.9.1.jar
From the Hypersonic distribution
  • /lib/hsqldb.jar
From the Apache Commons Logging distribution
  • commons-logging-1.1.1.jar
From the AOP Alliance (Java/J2EE AOP Standard) distribution
  • aopalliance.jar
From the SLF4J distribution
  • slf4j-log4j12-1.5.8.jar
From the Apache log4j distribution
  • log4j-1.2.16.jar
The sping4gwt library
  • spring4gwt-0.0.1.jar
We now have to take care of dependences for our Eclipse project. The following jars should be included in the Java build path of the project :
  • hibernate-jpa-2.0-api-1.0.0.Final.jar
  • org.springframework.beans-3.0.1.RELEASE-A.jar
  • org.springframework.context-3.0.1.RELEASE-A.jar
  • org.springframework.core-3.0.1.RELEASE-A.jar
  • org.springframework.orm-3.0.1.RELEASE-A.jar
  • org.springframework.transaction-3.0.1.RELEASE-A.jar
The next step is to provide hooks for the web application so as to load the Spring context upon startup and to allow for spring4gwt to intercept RPC calls between the client and the server and transform them to Spring service invocations.

Locate the web.xml file under /war/WEB-INF and add the following :

For loading the Spring context upon startup,
1<listener>
2 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
3</listener>
At the servlets section include
1<servlet>
2 <servlet-name>springGwtRemoteServiceServlet</servlet-name>
3 <servlet-class>org.spring4gwt.server.SpringGwtRemoteServiceServlet</servlet-class>
4</servlet>
At the servlet-mapping section include, for spring4gwt to intercept RPC calls.
1<servlet-mapping>
2 <servlet-name>springGwtRemoteServiceServlet</servlet-name>
3 <url-pattern>/gwtspring/springGwtServices/*</url-pattern>
4</servlet-mapping>
Things to notice here :
  1. The url-pattern child element of the servlet-mapping element for the springGwtRemoteServiceServlet servlet, should be changed to whatever your GWT module name is e.g. {module_name}/springGwtServices/*, the module name is defined in {project_name}.gwt.xml file (here GWTSpring.gwt.xml) located at the root of the base package of the project under /src folder
  2. You can change the name of spring4gwt servlet (springGwtRemoteServiceServlet here) to whatever you like
To continue we have to create the persistence.xml file so as to describe the connection with the database using JPA. The pesistence.xml file must be located inside a META-INF directory which in turn has to be accessible by the web application at runtime (on the classpath). To fulfill the aforementioned requirements we have to create the META-INF folder under the project's /war/WEB-INF/classes folder. To do so we create a new source folder under the name e.g. “resources” and create the META-INF folder inside it. Finally create the persistence.xml file inside the /resources/META-INF folder. An example persistence.xml is presented below
04    version="2.0">
05 
06    <persistence-unit name="MyPersistenceUnit" transaction-type="RESOURCE_LOCAL">
07        <provider>org.hibernate.ejb.HibernatePersistence</provider>
08 
09        <properties>
10            <property name="hibernate.hbm2ddl.auto" value="update"/>
11            <property name="hibernate.show_sql" value="false"/>
12            <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect"/>
13            <property name="hibernate.connection.driver_class" value="org.hsqldb.jdbcDriver"/>
14            <property name="hibernate.connection.url" value="jdbc:hsqldb:mem:javacodegeeks"/>
15            <property name="hibernate.connection.username" value="sa"/>
16            <property name="hibernate.connection.password" value=""/>
17 
18            <property name="hibernate.c3p0.min_size" value="5"/>
19            <property name="hibernate.c3p0.max_size" value="20"/>
20            <property name="hibernate.c3p0.timeout" value="300"/>
21            <property name="hibernate.c3p0.max_statements" value="50"/>
22            <property name="hibernate.c3p0.idle_test_period" value="3000"/>
23        </properties>
24 
25    </persistence-unit>
26 
27</persistence>
Things to notice here :
  1. If you intent to deploy the web application to a J2EE application server that supports JTA transactions e.g. JBoss or use other databases e.g. Oracle, MySQL etc, please see our “JBoss Spring JPA Hibernate tutorial” here for alternative configurations
Now lets create the applicationContext.xml file that will drive Spring container. Create the file under /war/WEB-INF directory. An example applicationContext.xml is presented below
06    xsi:schemaLocation="
13 
14    <context:component-scan base-package="com.javacodegeeks.gwtspring"/>
15 
16    <task:annotation-driven executor="myExecutor" scheduler="myScheduler"/>
17 
18    <task:executor id="myExecutor" pool-size="5"/>
19 
20    <task:scheduler id="myScheduler" pool-size="10"/>
21 
22    <tx:annotation-driven/>
23 
24    <bean class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean" id="entityManagerFactory">
25        <property name="persistenceUnitName" value="MyPersistenceUnit"/>
26    </bean>
27 
28    <bean class="org.springframework.orm.jpa.JpaTransactionManager" id="transactionManager">
29        <property name="entityManagerFactory" ref="entityManagerFactory"/>
30    </bean>
31 
32</beans>
Things to notice here :
  1. Change the base-package attribute of the context:component-scan element to whatever is the base package of your project so as to be scanned for Spring components (services, DAOs etc).
  2. Change the value attribute of entityManagerFactory bean persistentUnitName property to the name of your persistent unit as dictated in the persistence.xml file
  3. If you intent to deploy the web application to a J2EE application server that supports JTA transactions e.g. JBoss please see our “JBoss Sping JPA Hibernate tutorial” here for alternative configurations
In the last part of this tutorial we are going to present the Data Transfer Object (DTO) for transferring data between the client and the server, the Data Access Object (DAO) that is used to access the database and the Spring service to expose functionality to the GWT Web client.

The DTO is an object that can be used by both the client and the server, thus you should create a “dto” subpackage under the “shared” package and place the DTO there. We are going to create an EmployeeDTO containing information for an employee like below
01package com.javacodegeeks.gwtspring.shared.dto;
02 
03import javax.persistence.Column;
04import javax.persistence.Entity;
05import javax.persistence.Id;
06import javax.persistence.Table;
07 
08@Entity
09@Table(name = "EMPLOYEE")
10public class EmployeeDTO implements java.io.Serializable {
11     
12    private static final long serialVersionUID = 7440297955003302414L;
13 
14    @Id
15    @Column(name="employee_id")
16    private long employeeId;
17     
18    @Column(name="employee_name", nullable = false, length=30)
19    private String employeeName;
20     
21    @Column(name="employee_surname", nullable = false, length=30)
22    private String employeeSurname;
23     
24    @Column(name="job", length=50)
25    private String job;
26         
27    public EmployeeDTO() {
28    }
29 
30    public EmployeeDTO(int employeeId) {
31        this.employeeId = employeeId;       
32    }
33 
34    public EmployeeDTO(long employeeId, String employeeName, String employeeSurname,
35            String job) {
36        this.employeeId = employeeId;
37        this.employeeName = employeeName;
38        this.employeeSurname = employeeSurname;
39        this.job = job;
40    }
41 
42    public long getEmployeeId() {
43        return employeeId;
44    }
45 
46    public void setEmployeeId(long employeeId) {
47        this.employeeId = employeeId;
48    }
49 
50    public String getEmployeeName() {
51        return employeeName;
52    }
53 
54    public void setEmployeeName(String employeeName) {
55        this.employeeName = employeeName;
56    }
57 
58    public String getEmployeeSurname() {
59        return employeeSurname;
60    }
61 
62    public void setEmployeeSurname(String employeeSurname) {
63        this.employeeSurname = employeeSurname;
64    }
65 
66    public String getJob() {
67        return job;
68    }
69 
70    public void setJob(String job) {
71        this.job = job;
72    }
73 
74}
The DAO object will be used to access the database and perform CRUD (Create Retrieve Update Delete) operations. It is a server side component so it should be placed under the “server” subpackage of our project. Create a “dao” subpackage and place the DAO there. An example DAO is presented below
01package com.javacodegeeks.gwtspring.server.dao;
02 
03import javax.annotation.PostConstruct;
04import javax.persistence.EntityManagerFactory;
05 
06import org.springframework.beans.factory.annotation.Autowired;
07import org.springframework.stereotype.Repository;
08 
09import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO;
10 
11@Repository("employeeDAO")
12public class EmployeeDAO extends JpaDAO<Long, EmployeeDTO> {
13     
14    @Autowired
15    EntityManagerFactory entityManagerFactory;
16     
17    @PostConstruct
18    public void init() {
19        super.setEntityManagerFactory(entityManagerFactory);
20    }
21     
22}
As you can see the EmployeeDAO class extends a basic DAO class (JpaDAO). The EmployeeDAO class can contain specific queries concerning the EmployeeDTO object, but all CRUD operations can be handled from the basic DAO class (JpaDAO). Place the JpaDAO class at the same level as the EmployeeDAO class, under the “dao” subpackage. Below we present the JpaDAO class
01package com.javacodegeeks.gwtspring.server.dao;
02 
03import java.lang.reflect.ParameterizedType;
04import java.util.List;
05 
06import javax.persistence.EntityManager;
07import javax.persistence.PersistenceException;
08import javax.persistence.Query;
09 
10import org.springframework.orm.jpa.JpaCallback;
11import org.springframework.orm.jpa.support.JpaDaoSupport;
12 
13public abstract class JpaDAO<K, E> extends JpaDaoSupport {
14    protected Class<E> entityClass;
15 
16    @SuppressWarnings("unchecked")
17    public JpaDAO() {
18        ParameterizedType genericSuperclass = (ParameterizedType) getClass()
19                .getGenericSuperclass();
20        this.entityClass = (Class<E>) genericSuperclass
21                .getActualTypeArguments()[1];
22    }
23 
24    public void persist(E entity) {
25        getJpaTemplate().persist(entity);
26    }
27 
28    public void remove(E entity) {
29        getJpaTemplate().remove(entity);
30    }
31     
32    public E merge(E entity) {
33        return getJpaTemplate().merge(entity);
34    }
35     
36    public void refresh(E entity) {
37        getJpaTemplate().refresh(entity);
38    }
39 
40    public E findById(K id) {
41        return getJpaTemplate().find(entityClass, id);
42    }
43     
44    public E flush(E entity) {
45        getJpaTemplate().flush();
46        return entity;
47    }
48     
49    @SuppressWarnings("unchecked")
50    public List<E> findAll() {
51        Object res = getJpaTemplate().execute(new JpaCallback() {
52 
53            public Object doInJpa(EntityManager em) throws PersistenceException {
54                Query q = em.createQuery("SELECT h FROM " +
55                        entityClass.getName() + " h");
56                return q.getResultList();
57            }
58             
59        });
60         
61        return (List<E>) res;
62    }
63 
64    @SuppressWarnings("unchecked")
65    public Integer removeAll() {
66        return (Integer) getJpaTemplate().execute(new JpaCallback() {
67 
68            public Object doInJpa(EntityManager em) throws PersistenceException {
69                Query q = em.createQuery("DELETE FROM " +
70                        entityClass.getName() + " h");
71                return q.executeUpdate();
72            }
73             
74        });
75    }
76     
77}
Finally we are going to create the service interface and implementation classes for the GWT client to access. The service interface should be accessible by both the client and the server, so it should be placed under the “shared” subpackage of our project. Create a “services” subpackage and place the service interface there. An example interface class follows
01package com.javacodegeeks.gwtspring.shared.services;
02 
03import com.google.gwt.user.client.rpc.RemoteService;
04import com.google.gwt.user.client.rpc.RemoteServiceRelativePath;
05 
06import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO;
07 
08@RemoteServiceRelativePath("springGwtServices/employeeService")
09public interface EmployeeService extends RemoteService {
10     
11    public EmployeeDTO findEmployee(long employeeId);
12    public void saveEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception;
13    public void updateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception;
14    public void saveOrUpdateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception;
15    public void deleteEmployee(long employeeId) throws Exception;
16     
17}
Things to notice here :
  1. GWT client has to be able to make asynchronous Remote Procedure Calls (RPCs) to the server side service. Thus the service interface must extend the RemoteService interface. An asynchronous counterpart of the specified interface must also be provided to enable asynchronous communication (see below)
  2. We annotate the interface so as to define the URL under which the service will be accessible. As the service is a Spring service we want spring4gwt to intercept the RPC calls and perform a Spring service invocation. To do that we define a relative path that will be handled by “springGwtRemoteServiceServlet” declared in our web.xml as shown above.
  3. The service name declared at “RemoteServiceRelativePath” annotation, here “employeeService”, must match the Spring service bean name. We will define the Spring service bean name in the service implementation class (see below)
The asynchronous counter part of the service interface follows
01package com.javacodegeeks.gwtspring.shared.services;
02 
03import com.google.gwt.user.client.rpc.AsyncCallback;
04import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO;
05 
06public interface EmployeeServiceAsync {
07 
08    void deleteEmployee(long employeeId, AsyncCallback<Void> callback);
09 
10    void findEmployee(long employeeId, AsyncCallback<EmployeeDTO> callback);
11 
12    void saveEmployee(long employeeId, String name, String surname,
13            String jobDescription, AsyncCallback<Void> callback);
14 
15    void saveOrUpdateEmployee(long employeeId, String name, String surname,
16            String jobDescription, AsyncCallback<Void> callback);
17 
18    void updateEmployee(long employeeId, String name, String surname,
19            String jobDescription, AsyncCallback<Void> callback);
20 
21}
The service implementation class is a server side component, so we must place it under “server” subpackage of our project. Create the “services” subpackage and place it there. An example service implementation class is presented below
01package com.javacodegeeks.gwtspring.server.services;
02 
03import javax.annotation.PostConstruct;
04import javax.annotation.PreDestroy;
05 
06import org.springframework.beans.factory.annotation.Autowired;
07import org.springframework.stereotype.Service;
08import org.springframework.transaction.annotation.Propagation;
09import org.springframework.transaction.annotation.Transactional;
10 
11import com.javacodegeeks.gwtspring.server.dao.EmployeeDAO;
12import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO;
13import com.javacodegeeks.gwtspring.shared.services.EmployeeService;
14 
15@Service("employeeService")
16public class EmployeeServiceImpl implements EmployeeService {
17     
18    @Autowired
19    private EmployeeDAO employeeDAO;
20 
21    @PostConstruct
22    public void init() throws Exception {
23    }
24     
25    @PreDestroy
26    public void destroy() {
27    }
28 
29    public EmployeeDTO findEmployee(long employeeId) {
30         
31        return employeeDAO.findById(employeeId);
32         
33    }
34     
35    @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
36    public void saveEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception {
37             
38        EmployeeDTO employeeDTO = employeeDAO.findById(employeeId);
39         
40        if(employeeDTO == null) {
41            employeeDTO = new EmployeeDTO(employeeId, name,surname, jobDescription);
42            employeeDAO.persist(employeeDTO);
43        }
44         
45    }
46     
47    @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
48    public void updateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception {
49         
50        EmployeeDTO employeeDTO = employeeDAO.findById(employeeId);
51         
52        if(employeeDTO != null) {
53            employeeDTO.setEmployeeName(name);
54            employeeDTO.setEmployeeSurname(surname);
55            employeeDTO.setJob(jobDescription);
56        }
57 
58    }
59     
60    @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
61    public void deleteEmployee(long employeeId) throws Exception {
62         
63        EmployeeDTO employeeDTO = employeeDAO.findById(employeeId);
64         
65        if(employeeDTO != null)
66            employeeDAO.remove(employeeDTO);
67 
68    }
69     
70    @Transactional(propagation=Propagation.REQUIRED, rollbackFor=Exception.class)
71    public void saveOrUpdateEmployee(long employeeId, String name, String surname, String jobDescription) throws Exception {
72         
73        EmployeeDTO employeeDTO = new EmployeeDTO(employeeId, name,surname, jobDescription);
74         
75        employeeDAO.merge(employeeDTO);
76         
77    }
78 
79}
Things to notice here :
  1. We use the @Service("employeeService") stereotype annotation so as to declare that this class represents a Spring service by the name "exampleService". The Spring container will instantiate all services at start up.
  2. We use the @Autowire annotation to inject the instance of the DAO class to the "employeeService". For proper instantiation of the service Spring container has to resolve first all potential references among services, so it instantiates the DAO class and injects the instance to the appropriate field of "employeeService" - the "employeeDAO" field. In case you wonder, the dependency injection is done according to type (Class) and if not satisfied according to name, meaning that if we have defined multiple services of the same type (Class) the one injected would be the one with the same name as the designated field.
  3. We use the Java annotations @PostConstruct and @PreDestroy to declare the methods that will be invoked by Spring container after initialization (all dependency injection is done) and prior destruction of the service.
  4. We use the @Transactional annotation for all methods that need to perform update operation on the database (INSERT, UPDATE, DELETE)
  5. We DO NOT use the @Transactional annotation on methods that perform retrieve (FIND) operations on the database (except for objects that contain lazily initialized references - see below), and/or perform no database operations. That is because every time you invoke a method annotated as transactional, Spring container involves in the invocation JPA's entity manager and as a consequence platform's transaction manager, so as to define the transactional behavior that will be applied, introducing a noticeable performance penalty especially for low latency / high throughput applications
  6. For methods that perform retrieve (FIND) operations for objects that contain lazily initialized references you should use the @Transactional annotation, designating "NESTED" propagation type in order for Spring to maintain Hibernate session open for the entire method call
  7. Transactional behavior is applied only on client calls to the service. Transactional behavior is not applied to intra operation calls. For example if a client invokes an operation that is not annotated as transactional and the implementation of the latter introduces a call to another operation of the same service that is annotated transactional then for the combined operations no transactional behavior will be applied
We are almost done!, we have to develop the GWT user interface to access our Spring service. Despite the fact that GWT user interface development is out of the scope of this tutorial we are going to provide a basic user interface just to show a couple of Spring service invocations.

Locate the entry point of your GWT application. The file should be named like {project_name}.java, in our case GWTSpring.java, and located under “client” subpackage or our main package. Alter the entry point class as shown below
001package com.javacodegeeks.gwtspring.client;
002 
003import com.google.gwt.core.client.EntryPoint;
004import com.google.gwt.core.client.GWT;
005import com.google.gwt.event.dom.client.ClickEvent;
006import com.google.gwt.event.dom.client.ClickHandler;
007import com.google.gwt.event.dom.client.KeyCodes;
008import com.google.gwt.event.dom.client.KeyUpEvent;
009import com.google.gwt.event.dom.client.KeyUpHandler;
010import com.google.gwt.user.client.rpc.AsyncCallback;
011import com.google.gwt.user.client.ui.Button;
012import com.google.gwt.user.client.ui.DialogBox;
013import com.google.gwt.user.client.ui.HTML;
014import com.google.gwt.user.client.ui.Label;
015import com.google.gwt.user.client.ui.RootPanel;
016import com.google.gwt.user.client.ui.TextBox;
017import com.google.gwt.user.client.ui.VerticalPanel;
018import com.javacodegeeks.gwtspring.shared.dto.EmployeeDTO;
019import com.javacodegeeks.gwtspring.shared.services.EmployeeService;
020import com.javacodegeeks.gwtspring.shared.services.EmployeeServiceAsync;
021 
022/**
023 * Entry point classes define <code>onModuleLoad()</code>.
024 */
025public class GWTSpring implements EntryPoint {
026    /**
027     * The message displayed to the user when the server cannot be reached or
028     * returns an error.
029     */
030    private static final String SERVER_ERROR = "An error occurred while "
031            + "attempting to contact the server. Please check your network "
032            + "connection and try again. The error is : ";
033     
034    /**
035     * Create a remote service proxy to talk to the server-side Employee service.
036     */
037    private final EmployeeServiceAsync employeeService = GWT
038            .create(EmployeeService.class);
039 
040    /**
041     * This is the entry point method.
042     */
043    public void onModuleLoad() {
044        final Button saveOrUpdateButton = new Button("SaveOrUpdate");
045        final Button retrieveButton = new Button("Retrieve");
046        final TextBox employeeInfoField = new TextBox();
047        employeeInfoField.setText("Employee Info");
048        final TextBox employeeIdField = new TextBox();
049        final Label errorLabel = new Label();
050 
051        // We can add style names to widgets
052        saveOrUpdateButton.addStyleName("sendButton");
053        retrieveButton.addStyleName("sendButton");
054 
055        // Add the nameField and sendButton to the RootPanel
056        // Use RootPanel.get() to get the entire body element
057        RootPanel.get("employeeInfoFieldContainer").add(employeeInfoField);
058        RootPanel.get("updateEmployeeButtonContainer").add(saveOrUpdateButton);
059        RootPanel.get("employeeIdFieldContainer").add(employeeIdField);
060        RootPanel.get("retrieveEmployeeButtonContainer").add(retrieveButton);
061        RootPanel.get("errorLabelContainer").add(errorLabel);
062 
063        // Focus the cursor on the name field when the app loads
064        employeeInfoField.setFocus(true);
065        employeeInfoField.selectAll();
066 
067        // Create the popup dialog box
068        final DialogBox dialogBox = new DialogBox();
069        dialogBox.setText("Remote Procedure Call");
070        dialogBox.setAnimationEnabled(true);
071        final Button closeButton = new Button("Close");
072        // We can set the id of a widget by accessing its Element
073        closeButton.getElement().setId("closeButton");
074        final Label textToServerLabel = new Label();
075        final HTML serverResponseLabel = new HTML();
076        VerticalPanel dialogVPanel = new VerticalPanel();
077        dialogVPanel.addStyleName("dialogVPanel");
078        dialogVPanel.add(new HTML("<b>Sending request to the server:</b>"));
079        dialogVPanel.add(textToServerLabel);
080        dialogVPanel.add(new HTML("
081<b>Server replies:</b>"));
082        dialogVPanel.add(serverResponseLabel);
083        dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
084        dialogVPanel.add(closeButton);
085        dialogBox.setWidget(dialogVPanel);
086 
087        // Add a handler to close the DialogBox
088        closeButton.addClickHandler(new ClickHandler() {
089            public void onClick(ClickEvent event) {
090                dialogBox.hide();
091                saveOrUpdateButton.setEnabled(true);
092                saveOrUpdateButton.setFocus(true);
093                retrieveButton.setEnabled(true);
094            }
095        });
096 
097        // Create a handler for the saveOrUpdateButton and employeeInfoField
098        class SaveOrUpdateEmployeeHandler implements ClickHandler, KeyUpHandler {
099            /**
100             * Fired when the user clicks on the saveOrUpdateButton.
101             */
102            public void onClick(ClickEvent event) {
103                sendEmployeeInfoToServer();
104            }
105 
106            /**
107             * Fired when the user types in the employeeInfoField.
108             */
109            public void onKeyUp(KeyUpEvent event) {
110                if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
111                    sendEmployeeInfoToServer();
112                }
113            }
114 
115            /**
116             * Send the employee info from the employeeInfoField to the server and wait for a response.
117             */
118            private void sendEmployeeInfoToServer() {
119                // First, we validate the input.
120                errorLabel.setText("");
121                String textToServer = employeeInfoField.getText();
122 
123                // Then, we send the input to the server.
124                saveOrUpdateButton.setEnabled(false);
125                textToServerLabel.setText(textToServer);
126                serverResponseLabel.setText("");
127 
128                String[] employeeInfo = textToServer.split(" ");
129                 
130                long employeeId = Long.parseLong(employeeInfo[0]);
131                String employeeName = employeeInfo[1];
132                String employeeSurname = employeeInfo[2];
133                String employeeJobTitle = employeeInfo[3];
134                 
135                employeeService.saveOrUpdateEmployee(employeeId, employeeName, employeeSurname, employeeJobTitle,
136                        new AsyncCallback<Void>() {
137                            public void onFailure(Throwable caught) {
138                                // Show the RPC error message to the user
139                                dialogBox
140                                        .setText("Remote Procedure Call - Failure");
141                                serverResponseLabel
142                                        .addStyleName("serverResponseLabelError");
143                                serverResponseLabel.setHTML(SERVER_ERROR + caught.toString());
144                                dialogBox.center();
145                                closeButton.setFocus(true);
146                            }
147 
148                            public void onSuccess(Void noAnswer) {
149                                dialogBox.setText("Remote Procedure Call");
150                                serverResponseLabel
151                                        .removeStyleName("serverResponseLabelError");
152                                serverResponseLabel.setHTML("OK");
153                                dialogBox.center();
154                                closeButton.setFocus(true);
155                            }
156                        });
157            }
158        }
159         
160        // Create a handler for the retrieveButton and employeeIdField
161        class RetrieveEmployeeHandler implements ClickHandler, KeyUpHandler {
162            /**
163             * Fired when the user clicks on the retrieveButton.
164             */
165            public void onClick(ClickEvent event) {
166                sendEmployeeIdToServer();
167            }
168 
169            /**
170             * Fired when the user types in the employeeIdField.
171             */
172            public void onKeyUp(KeyUpEvent event) {
173                if (event.getNativeKeyCode() == KeyCodes.KEY_ENTER) {
174                    sendEmployeeIdToServer();
175                }
176            }
177 
178            /**
179             * Send the id from the employeeIdField to the server and wait for a response.
180             */
181            private void sendEmployeeIdToServer() {
182                // First, we validate the input.
183                errorLabel.setText("");
184                String textToServer = employeeIdField.getText();
185 
186                // Then, we send the input to the server.
187                retrieveButton.setEnabled(false);
188                textToServerLabel.setText(textToServer);
189                serverResponseLabel.setText("");
190 
191                employeeService.findEmployee(Long.parseLong(textToServer), 
192                        new AsyncCallback<EmployeeDTO>() {
193                            public void onFailure(Throwable caught) {
194                                // Show the RPC error message to the user
195                                dialogBox
196                                        .setText("Remote Procedure Call - Failure");
197                                serverResponseLabel
198                                        .addStyleName("serverResponseLabelError");
199                                serverResponseLabel.setHTML(SERVER_ERROR + caught.toString());
200                                dialogBox.center();
201                                closeButton.setFocus(true);
202                            }
203 
204                            public void onSuccess(EmployeeDTO employeeDTO) {
205                                dialogBox.setText("Remote Procedure Call");
206                                serverResponseLabel
207                                        .removeStyleName("serverResponseLabelError");
208                                if(employeeDTO != null)
209                                    serverResponseLabel.setHTML("Employee Information Id : " + employeeDTO.getEmployeeId() + " Name : " + employeeDTO.getEmployeeName() + " Surname : " + employeeDTO.getEmployeeSurname() + " Job Title : " + employeeDTO.getJob());
210                                else
211                                    serverResponseLabel.setHTML("No employee with the specified id found");
212                                dialogBox.center();
213                                closeButton.setFocus(true);
214                            }
215                        });
216            }
217        }
218 
219        // Add a handler to send the employee info to the server
220        SaveOrUpdateEmployeeHandler saveOrUpdateEmployeehandler = new SaveOrUpdateEmployeeHandler();
221        saveOrUpdateButton.addClickHandler(saveOrUpdateEmployeehandler);
222        employeeInfoField.addKeyUpHandler(saveOrUpdateEmployeehandler);
223         
224        // Add a handler to send the employee id to the server
225        RetrieveEmployeeHandler retrieveEmployeehandler = new RetrieveEmployeeHandler();
226        retrieveButton.addClickHandler(retrieveEmployeehandler);
227        employeeIdField.addKeyUpHandler(retrieveEmployeehandler);
228    }
229}
As you can see, Spring service invocations are performed just like classic GWT service invocations, transparently to the client.

Finally locate the main web page for your project. The file should be named like {project_name}.html, in our case GWTSpring.html, and located under /war folder of our project. Alter the main web page as shown below
01<!doctype html>
02<!-- The DOCTYPE declaration above will set the    -->
03<!-- browser's rendering engine into               -->
04<!-- "Standards Mode". Replacing this declaration  -->
05<!-- with a "Quirks Mode" doctype may lead to some -->
06<!-- differences in layout.                        -->
07 
08<html>
09  <head>
10    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
11 
12    <!--                                                               -->
13    <!-- Consider inlining CSS to reduce the number of requested files -->
14    <!--                                                               -->
15    <link type="text/css" rel="stylesheet" href="GWTSpring.css">
16 
17    <!--                                           -->
18    <!-- Any title is fine                         -->
19    <!--                                           -->
20    <title>Spring GWT Web Application Starter Project</title>
21     
22    <!--                                           -->
23    <!-- This script loads your compiled module.   -->
24    <!-- If you add any GWT meta tags, they must   -->
25    <!-- be added before this line.                -->
26    <!--                                           -->
27    <script type="text/javascript" language="javascript" src="gwtspring/gwtspring.nocache.js"></script>
28  </head>
29 
30  <!--                                           -->
31  <!-- The body can have arbitrary html, or      -->
32  <!-- you can leave the body empty if you want  -->
33  <!-- to create a completely dynamic UI.        -->
34  <!--                                           -->
35  <body>
36 
37    <!-- OPTIONAL: include this if you want history support -->
38    <iframe src="javascript:''" id="__gwt_historyFrame" tabIndex='-1' style="position:absolute;width:0;height:0;border:0"></iframe>
39     
40    <!-- RECOMMENDED if your web app will not function without JavaScript enabled -->
41    <noscript>
42      <div style="width: 22em; position: absolute; left: 50%; margin-left: -11em; color: red; background-color: white; border: 1px solid red; padding: 4px; font-family: sans-serif">
43        Your web browser must have JavaScript enabled
44        in order for this application to display correctly.
45      </div>
46    </noscript>
47 
48    <h1>Spring GWT Web Application Starter Project</h1>
49 
50    <table align="center">
51      <tr>
52        <td colspan="2" style="font-weight:bold;">Please enter employee info (id name surname job):</td>       
53      </tr>
54      <tr>
55        <td id="employeeInfoFieldContainer"></td>
56        <td id="updateEmployeeButtonContainer"></td>
57      </tr>
58      <tr>
59      <tr>
60        <td colspan="2" style="font-weight:bold;">Please enter employee id:</td>       
61      </tr>
62      <tr>
63        <td id="employeeIdFieldContainer"></td>
64        <td id="retrieveEmployeeButtonContainer"></td>
65      </tr>
66      <tr>
67        <td colspan="2" style="color:red;" id="errorLabelContainer"></td>
68      </tr>
69    </table>
70  </body>
71</html>
To compile the application, right click on the project name and select Run As → Compile GWT Application

To deploy the web application just copy the /war folder in Apache – Tomcat “webapps” folder. You can change the name of the war folder to whatever you like, preferably rename it after the project name e.g. GWTSpring

To launch the application point your browser to the following address

http://localhost:8080/GWTSpring/

If all went well you should see your main web page. Two text boxes should be displayed each followed by a button. In the first text box you can save or update an employee to the database. Provide as input the id, the name, the surname, and a job description separated by a space character. Clicking on the “SaveOrUpdate” button the provided information will be stored to the database. For existing employee entries (same id) an update will be performed. The second text box is used to retrieve existing employee entries. Provide an employee id and click on the “Retrieve” button. If the employee exists you should see the employee id, name, surname and job description.

Few, that was a big tutorial!

You can download the project from here (required 3rd party libraries as described at the beginning are not included)