8. Version 4 – client/server in a web service architecture
In this new version, the [Pam] application will run in client/server mode within a web service architecture. Let’s revisit the architecture of the previous application:
![]() |
Above, a [C, RMI, S] communication layer enabled transparent communication between the [ui] client and the [metier] remote layer. We will use a similar architecture, where the [C, RMI, S] communication layer will be replaced by a [C, HTTP / SOAP, S] layer:
![]() |
The HTTP / SOAP protocol has the advantage over the previous RMI / EJB protocol of being cross-platform. Thus, the web service can be written in Java and deployed on the Glassfish server, while the client could be a .NET or PHP client.
We will develop this architecture in three different modes:
- the web service will be provided by EJB [Metier]
- the web service will be provided by a web application using EJB and [Metier]
- the web service will be provided by a web application using Spring
A web service can be implemented in various ways within a Java server EE:
- by a class annotated with @WebService that runs in a web container
![]() |
- by a EJB annotated with @WebService that runs in a EJB container
![]() |
We’ll start with this latter architecture.
8.1. Web service implemented by a EJB
8.1.1. The server side
8.1.1.1. The Netbeans project
Let's start by creating a new Maven project that is a copy of the EJB and [mv-pam-ejb-metier-dao-jpa-eclipselink] projects:
![]() |
With the following architecture:
![]() |
The [metier] layer will be the web service contacted by the [ui] layer. This class does not need to implement an interface. It is annotations that transform a POJO (Plain Ordinary Java Object) into a web service. The [Metier] class, which implements the [metier] layer above, is transformed as follows:
package metier;
...
@WebService
@Stateless()
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class Metier implements IMetierLocal,IMetierRemote {
// references on layers [DAO]
@EJB
private ICotisationDaoLocal cotisationDao = null;
@EJB
private IEmployeDaoLocal employeDao=null;
@EJB
private IIndemniteDaoLocal indemniteDao=null;
// get your payslip
@WebMethod
public FeuilleSalaire calculerFeuilleSalaire(String SS,
...
}
// list of employees
@WebMethod
public List<Employe> findAllEmployes() {
...
}
// important - no getters and setters for EJB
}
- line 4, the @WebService annotation makes the [Metier] class a web service. A web service exposes methods to its clients. These must be annotated with the @WebMethod attribute.
- Lines 19 and 25: The two methods of the [Metier] class become methods of the web service.
- Line 29: It is important that the getters and setters be removed; otherwise, they will be exposed in the web service, causing security errors.
The addition of these annotations is detected by Netbeans, which then changes the nature of the project:
![]() |
In [1], a [Web Services] tree structure has appeared in the project. It contains the Metier web service and its two methods. The server application can be deployed as [2]. The MySQL server must be launched, and its database [dbpam_eclipselink] must exist and be populated. It may be necessary to first delete [3] and EJB from the client/server project EJB discussed previously to avoid name conflicts. In fact, our new project includes the same EJB as the previous project.
![]() |
In [1], we see our server application deployed on the Glassfish server. Once the web service is deployed, it can be tested:
![]() |
- in [1], in the current project, we test the [Metier] web service
- The web service is accessible via various URL. The URL and [2] allow us to test the web service
- in [3], a link to the XML file defining the web service. The clients files for the web service need to know the URL of this file. The client layer (stubs) of the web service is generated from it.
- In [4,5], a form for testing the methods exposed by the web service. These are presented along with their parameters, which the user can define.
For example, let’s test the [findAllEmployes] method, which requires no parameters:
![]() |
Above, we are testing the method. We then receive the response below (partial view). We can see the two employees with their allowances. The reader is invited to test the [4] method in the same way by passing it the three parameters it expects.

8.1.2. The client side
![]() |
8.1.2.1. The client project Netbeans for the console
We are now creating a Java project of type [Java Application] for the client side of the application. As of June 2012, it was not possible to create a Maven project for this client. An error occurs, which appears to be known on net but remains unresolved.
![]() | ![]() |
Once the project is created, we specify that it will be a client of the web service we just deployed on the Glassfish server:
![]() |
- In [2], we select the new project and click the button [New File]
- In [3], we specify that we want to create a web service client
![]() |
- In [4], we will designate the Netbeans web service project
- In the [5] window, all projects with a [Web Services] branch are listed; here, only the [mv-pam-ws-metier-dao-eclipselink] project is shown.
- A project can deploy multiple web services. In [6], we select the web service we want to connect to.
![]() |
- In [7], the URL web service definition is displayed. This URL is used by the software tools that generate the client layer that will interface with the web service.
![]() |
- The [C] [1] client layer that will be generated consists of a set of Java classes that will be placed in the same package. The name of this package is set to [8].
- Once the web service client creation wizard is completed by clicking the [Finish] button, the [C] layer described above is created.
This is reflected by a number of changes in the project:
- In [10] above, a [Generated Sources] tree structure appears that contains the classes of the [C] layer, which allow the [3] client to communicate with the web service. This layer allows the [3] client to communicate with the [metier] and [4] layers as if they were local rather than remote.
- In [11], a [Web Service References] tree structure appears, listing the web services for which a client layer has been generated.
Note that in the generated [C] [10] layer, we find classes that have been deployed on the server side: Indemnite, Cotisation, Employe, FeuilleSalaire, ElementsSalaire, Metier. Metier is the web service, and the other classes are classes required by this service. One might be curious to examine their code. We will see that the definition of the classes—which, when instantiated, represent objects manipulated by the service—consists of defining the class fields and their accessors, as well as adding annotations that enable the serialization of the class into a XML stream. The Metier class has become an interface containing the two methods that have been annotated with @WebMethod. Each of these gives rise to two classes, for example [CalculerFeuilleSalaire.java] and [CalculerFeuilleSalaireResponse.java], where one encapsulates the method call and the other its result. Finally, the MetierService class is the class that allows the client to have a reference to the remote Metier web service:
The getMetierPort method on line 2 allows you to obtain a reference to the remote Metier web service.
8.1.2.2. The Metier web service console client
All that remains is to write the Metier web service client. We copy the [MainRemote] class from the [mv-pam-client-metier-dao-jpa-eclipselink] project—which was a client of the EJB server—into the new project.
![]() |
- In [1], the web service client class. The [MainRemote] class contains errors. To fix them, we will start by removing all existing [import] instructions in the class and regenerate them using option and [Fix Imports]. This is because some of the classes used by the [MainRemote] class are now part of the generated [client] package.
- In [3], the code snippet where the [metier] layer is instantiated is [3]. It is instantiated with JNDI code to obtain a reference to a remote EJB.
We are updating the code as follows:
- the JNDI code is removed
- since the [PamException] class does not exist on the client side, we remove the associated catch block to keep only the catch block on the parent class [Exception].
![]() |
- In [4], we still need to obtain a reference to the remote web service [Metier] in order to call its method [calculerFeuilleSalaire].
- In [5], using the mouse, we drag the method [calculerFeuilleSalaire] from the web service [Metier] and drop it into [4]. Code is generated: [6]. This generic code can then be adapted by the developer.
![]() |
- On line 112, we see that [calculerFeuilleSalaire] is a method of the [client.Metier] class (line 111). Now that we know how to obtain the [metier] layer, the previous code can be rewritten as follows:
Line 7 retrieves a reference to the Metier web service. Once this is done, the class code remains unchanged, except that on line 10, it is not the [Exception] exception type that is handled, but the more general Throwable type, the parent class of the Exception class. If an exception occurs, we display all its nested causes down to the root cause.
We are ready for testing:
- ensure that SGBD MySQL5 is launched, and that the dbpam_eclipselink database is created and initialized
- Ensure that the web service is deployed on the Glassfish server
- Build the client (Clean and Build)
- Configure the client execution
![]() |
- Run the client
The results in the console are as follows:
With the following configuration:

we get the following results:
Note that while the [Metier] web service sends a [PamException] exception, the exception received by the client is of type [SOAPFaultException]. Even in the exception chain, the type [PamException] does not appear.
8.1.3. The Swing client for the Metier web service
Task: Port the Swing client from the [mv-pam-client-ejb-metier-dao-jpa-eclipselink] project to the new project so that it too becomes a client of the web service deployed on the Glassfish server.
8.2. Web service implemented by a web application
We are now working within the following architecture:
![]() |
The web service is provided by a web application running within the web container of the Glassfish server. This web service will rely on EJB and [Metier], which are deployed in the EJB3 container.
8.2.1. The server side
We create a web application:
![]() |
- in [1], we create a new project
- in [2], this project is of type [Web Application]
- in [3], we name it [mv-pam-ws-ejb-metier-dao-eclipselink]
![]() |
- in [4], we select version Java EE 6
- to [6], the created project
In the diagram below, the created web application will run in the web container. It will use the EJB [Metier], which will be deployed in the server’s EJB container.
![]() |
To ensure that the created web application has access to the classes associated with EJB and [Metier], we add the [mv-pam-ws-ejb-metier-dao-eclipselink] dependency to the web application’s libraries, the dependency on the EJB and [mv-pam-ejb-metier-dao-eclipselink] servers we previously examined.
![]() |
- In [1], we add a project to the web project's dependencies,
- In [2], select the project [mv-pam-ejb-metier-dao-eclipselink],
- in [3], the dependency type is ejb,
- In [4], the scope of the dependency is provided, meaning it will be supplied by the runtime environment,
- in [5], the dependency has been added.
To create the same web service as before, we need to:
- create a class annotated with @Webservice
- with two methods calculerFeuilleSalaire and findAllEmployes annotated with @WebMethod
We create a class named [PamWsEjbMetier] in a package named [pam.ws]:
![]() |
![]() |
The [PamWsEjbMetier] class is as follows:
- lines 7–10: The class imports classes from the EJB and [pam-serveurws-metier-dao-jpa-eclipselink] modules, whose Maven project has been added to the project’s dependencies.
- line 12: the class is a web service
- line 13: it implements the IMetier interface defined in the EJB module
- lines 18-19: the calculerFeuilleSalaire method is exposed as a web service method
- lines 23-24: the findAllEmployes method is exposed as a web service method
- lines 15-16: the local interface of EJB [Metier] is injected into the field on line 16. We use the local interface because the web application and the EJB module run in the same JVM.
- Lines 20 and 25: The methods calculerFeuilleSalaire and findAllEmployes delegate their processing to the methods of the same name in EJB [Metier]. The class therefore serves only to expose the methods of EJB and [Metier] to remote clients instances as web service methods.
In Netbeans, the web application is recognized as exposing a web service:
![]() |
To deploy the web service on the Glassfish server, we must deploy both:
- the web module in the server’s web container
- the EJB module in the server’s EJB container
To do this, we need to create a [Enterprise Application]-type application that will deploy both modules at the same time. To do this, both projects must be loaded into Netbeans and [2].
Once this is done, we create a new project named [3].
![]() |
- In [4], we select a project of type [Enterprise Application].
- In [5], we name the project
![]() |
- In [6], we configure the project. The version of Java EE will be Java EE 6. An enterprise project can be created with two modules: a EJB module and a Web module. Here, the enterprise project will encapsulate the Web module and the EJB module that have already been created and loaded into Netbeans. Therefore, we do not request the creation of new modules.
- In [7], the enterprise project [mv-pam-webapp-ear] is created as described. Another Maven project, [mv-pam-webapp], was created at the same time. We will not be concerned with it.
- In [8], we add dependencies to the enterprise project
![]() |
- In [9], we add the WAR-type web project,
- In [10], we add the EJB-type project EJB,
![]() |
- in [11], the enterprise project with its two dependencies.
We build the enterprise project using Clean and Build. We are almost ready to deploy it to the Glassfish server. Before doing so, it may be necessary to unload applications already loaded on the server to avoid potential name conflicts between EJB and [11]:
![]() |
The MySQL server must be running, and the [dbpam_eclipselink] database must be available and populated. Once this is done, the [12] enterprise application can be deployed. In [13], we can see that it has been successfully deployed to the Glassfish server.
We can test the web service that has just been deployed:
![]() |
- In [1], we request to test the web service [PamWsEjbMetier]
- in [2], the test page. We leave it to the reader to conduct the tests.
8.2.2. The client side
Task: Following the procedure described in Section 8.1.2.1, build a console client for the previous web service.
8.3. Web service implemented with Spring and Tomcat
We now consider the following architecture:
![]() |
The web service is provided by a web application running within the Tomcat server’s web container. The application architecture will be as follows:
![]() |
We will build upon the [mv-pam-spring-hibernate] project created in Section 5.11:
![]() |
8.3.1. The server side
We create a web-type Maven application named [mv-pam-ws-spring-tomcat] [1]:
![]() |
We modify the [pom.xml] file to include the following [2] dependencies:
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>mv-pam-spring-hibernate</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Apache CXF dependencies -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>2.2.12</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>2.2.12</version>
</dependency>
</dependencies>
- lines 3–7: the dependency on the [spring-pam-jpa-hibernate] project,
- lines 8–17: dependencies on the Apache framework CXF and [http://cxf.apache.org/]. This framework facilitates the creation of web services.
This [pom.xml] file introduces numerous [2] dependencies.
Let’s return to the application architecture:
![]() |
Calls to the web service we are going to build are handled by a servlet from the CXF framework. This is reflected in the [WEB-INF / web.xml] file as follows:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>mv-pam-ws-spring-tomcat</display-name>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- CXF configuration -->
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/ws/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
- The CXF framework depends on Spring. Lines 4–6: A listener is declared. The corresponding class will be loaded along with the web application. It will use the Spring configuration file [WEB-INF / applicationContext.xml]:
![]() |
- lines 8–12: the CXF servlet, which will handle calls to the web service we are about to create,
- lines 13–16: the URL requests handled by the CXF servlet will be of the type /ws/*. The others will not be handled by CXF.
To define the web service, we define an interface and its implementation:
![]() |
The [IWsMetier] interface will be as follows:
package pam.ws;
import javax.jws.WebService;
import metier.IMetier;
@WebService
public interface IWsMetier extends IMetier{
}
- line 7: the [IWsMetier] interface derives from the [IMetier] interface in the [métier] layer of the [mv-pam-spring-hibernate] project,
- line 6: the [IWsMetier] interface is that of a web service.
The implementation class for this interface is as follows:
package pam.ws;
import java.util.List;
import javax.jws.WebMethod;
import javax.jws.WebService;
import jpa.Employe;
import metier.FeuilleSalaire;
import metier.IMetier;
@WebService
public class PamWsMetier implements IWsMetier {
// business layer
private IMetier metier;
// manufacturer
public PamWsMetier(){
}
@WebMethod
public FeuilleSalaire calculerFeuilleSalaire(String SS, double nbHeuresTravaillees, int nbJoursTravailles) {
return metier.calculerFeuilleSalaire(SS, nbHeuresTravaillees, nbJoursTravailles);
}
@WebMethod
public List<Employe> findAllEmployes() {
return metier.findAllEmployes();
}
// getters and setters
public void setMetier(IMetier metier) {
this.metier = metier;
}
}
- line 11: the [PamWsMetier] class implements the interface defined previously,
- line 10: defines the class as a web service,
- line 14: the [métier] layer will be injected by Spring,
- lines 21, 26: the @WebMethod annotation makes a method a method exposed by the web service,
- lines 23, 28: the methods are implemented using the [métier] layer.
We still need to define the contents of the Spring configuration file [applicationContext.xml]:
![]() |
Its content is as follows:
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
<!-- Apache CXF -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- lower layers -->
<import resource="classpath:spring-config-metier-dao.xml" />
<!-- web service -->
<bean id="wsMetier" class="pam.ws.PamWsMetier">
<property name="metier" ref="metier"/>
</bean>
<jaxws:endpoint id="wsmetier"
implementor="#wsMetier"
address="/metier">
</jaxws:endpoint>
</beans>
- lines 13–15: Apache configuration files CXF are imported. These are searched for in the project’s classpath (classpath attribute),
- lines 4, 9, 10: Apache-specific namespaces CXF are declared,
- line 18: the Spring configuration file for the [mv-pam-spring-hibernate] project is imported,
- lines 21–23: define the web service bean with its dependency on the [métier] layer (line 22),
- lines 24–27: define the web service itself,
- line 25: the Spring bean implementing the web service is the one defined on line 21;
- line 26: defines the URL path where the web service will be available, here /metier. Combined with the format required for URLs processed by Apache (see the web.xml file), this URL becomes /ws/metier.
Our project is ready to run. We run it and request the URL [http://localhost:8080/mv-pam-ws-spring-tomcat/ws] in a browser:

The page lists all deployed web services. Here, there is only one. We follow the link WSDL:
![]() |
The text displayed is from a file that defines the web service’s functionality, how to call it, and what responses it sends. Note the URL [2] of this file WSDL. All clients of the web service need to know it.
8.3.2. The client side
Task: Following the procedure described in Section 8.1.2.1, build a console client for the previous web service.
Note: To specify the URL of the WSDL file from the web service, proceed as follows:
![]() |
Set [3] to the URL previously noted as [2].












































