Exercice 1 - Développer un service Web suivant une approche montante Bottom/Up▲
But▲
- Décrire un service Web à partir d'une interface Java.
- Implémenter le service Web.
- Déployer sous Glassfish ou Tomcat.
- Tester le service Web via SOAP-UI.
Description▲
Le service Web de ce premier exercice consiste à fournir des opérations pour la gestion d'un carnet d'adresses simplifié. Une opération pour ajouter une personne, une autre pour récupérer la liste complète et enfin une dernière opération pour récupérer une personne par un nom. Une personne est décrite par un nom (String) et une adresse (String).
Étapes à suivre▲
Démarrer l'environnement de développement NetBeans.
Créer un nouveau projet File -> New Project… puis Java Web et choisir Web Application, faire Next.
Dans le nom du projet, choisir le nom NotebookWebServiceExercice1.
Comme type de serveur d'application, choisir Tomcat ou GlassFish et comme version Java EE choisir Java EE 7 puis faire Next.
Ne rien choisir dans les Frameworks proposés, puis faire Finish. L'initialisation du projet est en cours.
Depuis le projet NotebookWebServiceExercice1 s'assurer que les opérations Clean and Build et Deploy fonctionnent correctement. L'URL pour accéder à l'application Web est donnée depuis la console de Netbeans (par défaut : http://localhost:8080/NotebookWebServiceExercice1).
Créer une classe qui représentera une personne (File -> New File… puis choisir Java et enfin Java Class), puis faire Next. Appeler la classe Person et la définir dans le package soa.jaxwslabs.notebookwebserviceexercice1, puis faire Finish.
Dans la nouvelle classe créée, ajouter un attribut name de type String et un attribut address de type String. Définir un constructeur par défaut (important pour JAXB) et un constructeur avec deux paramètres correspondant respectivement aux deux attributs. Générer les modifieurs et accesseurs. Pour la génération, exploiter les outils fournis par NetBeans (Insert Code… via le menu contextuel de la classe Java).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
public
class
Person {
protected
String name;
protected
String address;
public
Person
(
) {
}
public
Person
(
String pName, String pAddress) {
this
.name =
pName;
this
.address =
pAddress;
}
public
String getName
(
) {
return
name;
}
public
void
setName
(
String name) {
this
.name =
name;
}
public
String getAddress
(
) {
return
address;
}
public
void
setAddress
(
String address) {
this
.address =
address;
}
}
Définir une interface Java représentant la description du service Web (File -> New File… puis choisir Java et enfin Java Interface) puis faire Next. Définir comme nom de l'interface NotebookService et utiliser le précédent package. Faire Finish.
Ajouter les méthodes suivantes dans l'interface NotebookService :
- void addPerson(Person p) : ajouter une nouvelle personne ;
- List<Person> getPersons() : récupérer l'ensemble des personnes ;
- Person getPersonAt(String name) : récupérer une personne par son nom.
Ajouter une annotation @WebService au niveau de l'interface puis initialiser ces attributs name à NotebookService et targetNamespace à http://soa.jaxwslabs.notebookwebserviceexercice1.
@WebService
(
name =
"NotebookService"
, targetNamespace =
"http://soa.jaxwslabs.notebookwebserviceexercice1"
)
public
interface
NotebookService {
void
addPerson
(
Person p);
List<
Person>
getPersons
(
);
Person getPersonAt
(
String name);
}
Construire une nouvelle classe appelée NotebookServiceImpl qui implémente l'interface NotebookService.
Ajouter une annotation @WebService au niveau de la classe puis modifier les attributs de l'annotation comme décrit ci-dessous :
- endpointInterface = soa.jaxwslabs.notbookwebserviceexercice1.NotebookService;
- serviceName = NotebookService;
- portName = NoteBookPort.
Ci-dessous est donné un exemple d'implémentation. Saisir le code de la classe NotebookServiceImpl.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
@WebService
(
endpointInterface =
"soa.jaxwslabs.notebookwebserviceexercice1.NotebookService"
,
serviceName =
"NotebookService"
,
portName =
"NoteBookPort"
)
public
class
NotebookServiceImpl implements
NotebookService {
@Override
public
void
addPerson
(
Person p) {
if
(
p ==
null
) {
throw
new
NullPointerException
(
"Person is null"
);
}
try
{
Thread.sleep
(
5000
);
}
catch
(
InterruptedException e) {
e.printStackTrace
(
);
}
System.out.println
(
"addPerson method has been invoked : "
+
p.toString
(
));
}
@Override
public
List<
Person>
getPersons
(
) {
List<
Person>
myPerson =
new
ArrayList<
Person>(
);
myPerson.add
(
new
Person
(
"Mickael BARON"
, "Migné-Auxances"
));
myPerson.add
(
new
Person
(
"Sébastien LOEB"
, "France"
));
System.out.println
(
"getPersons method has been invoked"
);
return
myPerson;
}
@Override
public
Person getPersonAt
(
String name) {
if
(
name ==
null
||
name.equals
(
""
)) {
throw
new
NullPointerException
(
"Name is null"
);
}
System.out.println
(
"getPersonAt method has been invoked"
);
return
new
Person
(
"Mickael BARON"
, "Migné-Auxances"
);
}
}
Faire un Clean and Build à partir du projet NotebookWebServiceExercice1 et s'assurer que le projet se construit correctement.
Faire un Deploy et Run à partir du projet. Le serveur Tomcat ou Glassfish doit démarrer. Depuis la console de Glassfish, un service Web doit avoir été découvert, un message similaire doit être présent :
Afficher sa description WSDL et examiner le résultat par rapport à ce qui a été défini dans l'interface Java.
Pour tester le comportement du service Web vous pouvez soit utiliser l'outil SOAP-UI (voir leçon 1) soit utiliser l'outil fourni par JAX-WS (à partir du projet sous NetBeans, afficher le menu contextuel du sous-nœud de services Web qui est NotebookServiceImpl).
Exercice 2 - Développer un service Web suivant une approche descendante Up/Down▲
But▲
- Générer les artefacts d'un service Web à partir d'une description WSDL.
- Implémenter le service Web.
- Déployer sous Glassfish ou Tomcat.
- Tester le service Web.
- wsimport.
Description▲
Dans cet exercice nous développons un service Web à partir de sa description WSDL. Pour cela, nous nous basons sur la description WSDL du service Web obtenue à la fin de l'exercice 1. L'intérêt est de montrer que la génération des classes (artefacts) ne donne pas exactement les mêmes classes que celles construites et utilisées dans l'exercice 1.
Étapes à suivre▲
Créer un nouveau projet de type Web Application nommé NotebookWebServiceExercice2.
Ajouter un nouveau fichier File -> New File… puis choisir Web Services et enfin Web Service from WSDL. Faire Next.
Dans le champ Web Service Name saisir la valeur NotebookServiceImpl, dans le champ package soa.jaxwslabs.notebookwebserviceexercice2, dans le champ Select Local WSDL File or Enter WSDL URL saisir l'URL du WSDL de l'exercice 1. L'outil analyse le WSDL et propose de choisir le port, sélectionner celui par défaut. Faire Finish.
Un ensemble de classes est généré par l'outil wsimport. Ces classes ne doivent pas être modifiées puisqu'elles sont générées automatiquement. Seule la classe NotebookServiceImpl peut l'être. Elle correspond à la classe implémentant le comportement du service Web. Réutiliser le code de l'exercice 1 pour compléter cette classe en l'adaptant en fonction du code généré.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
@WebService
(
serviceName =
"NotebookService"
, portName =
"NoteBookPort"
, endpointInterface =
"soa.jaxwslabs.notebookwebserviceexercice1.NotebookService"
, targetNamespace =
"http://notebookwebserviceexercice1.jaxwslabs.soa/"
, wsdlLocation =
"WEB-INF/wsdl/NotebookServiceImpl/lias-baron_8080/NotebookWebServiceExercice1/NotebookService.wsdl"
)
public
class
NotebookServiceImpl {
public
void
addPerson
(
Person p) {
if
(
p ==
null
) {
throw
new
NullPointerException
(
"Person is null"
);
}
try
{
Thread.sleep
(
5000
);
}
catch
(
InterruptedException e) {
e.printStackTrace
(
);
}
System.out.println
(
"addPerson method has been invoked : "
+
p.toString
(
));
}
public
List<
Person>
getPersons
(
) {
List<
Person>
myPersons =
new
ArrayList<
Person>(
);
Person myPerson =
new
Person
(
);
myPerson.setName
(
"Mickael BARON"
);
myPerson.setAddress
(
"Migné-Auxances"
);
myPersons.add
(
myPerson);
myPerson =
new
Person
(
);
myPerson.setName
(
"Sébastien LOEB"
);
myPerson.setAddress
(
"France"
);
myPersons.add
(
myPerson);
System.out.println
(
"getPersons method has been invoked"
);
return
myPersons;
}
public
Person getPersonAt
(
String name) {
if
(
name ==
null
||
name.equals
(
""
)) {
throw
new
NullPointerException
(
"Name is null"
);
}
System.out.println
(
"getPersonAt method has been invoked"
);
Person myPerson =
new
Person
(
);
myPerson.setName
(
"Mickael BARON"
);
myPerson.setAddress
(
"Migné-Auxances"
);
return
myPerson;
}
}
Faire un Clean and Build (s'assurer qu'il n'y a aucune erreur) et faire un Deploy.
En comparant le WSDL obtenu par cet exercice avec celui de l'exercice 1 vous remarquerez que syntaxiquement, il existe des différences, mais que sémantiquement c'est la même chose.
Exercice 3 - Développer un client de service Web en mode synchrone▲
But▲
- Développer un client d'un service Web.
- Appel synchrone.
- Outil wsimport.
- Client Web via une JSP.
Description▲
Cet exercice consiste à appeler le service Web défini dans l'exercice 1. Un client léger via une JSP est utilisé pour appeler l'opération getPersons() définie par le service Web. Cette opération est invoquée en mode synchrone, c'est-à-dire que le client est en attente de la réponse pour continuer son traitement.
Étapes à suivre▲
Créer un nouveau projet de type Web Application nommé NotebookWebServiceClientExercice3.
Ajouter un nouveau fichier File -> New File… puis choisir Web Services et enfin Web Service Client. Faire Next.
Dans le champ WSDL URL, saisir l'URL http://localhost:8080/NotebookWebServiceExercice1/NotebookService?wsdl et vérifier que les options sont paramétrées comme montrées sur la figure ci-dessous.
Un ensemble de classe est généré par l'outil wsimport. Elles représentent les classes liées au mapping JAXB (voir répertoire NotebookWebServiceClientExercice3\build\generated-sources\).
Éditer la page index.jsp de manière à invoquer l'opération getPersons() en mode synchrone. Saisir le code comme décrit ci-dessous :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
<html>
<head>
<meta
http-equiv
=
"Content-Type"
content
=
"text/html; charset=UTF-8"
>
<title>
Web Service Client of NotebookWebService</title>
</head>
<body>
<h1>
Web Service Client : NotebookWebServiceExercice 1</h1>
<%
soa.jaxwslabs.notebookwebserviceexercice1.NotebookService_Service myService
=
new soa.jaxwslabs.notebookwebserviceexercice1.NotebookService_Service();
soa.jaxwslabs.notebookwebserviceexercice1.NotebookService notebookPort
=
myService.getNoteBookPort();
java.util.List<notebookwebserviceexercice1.jaxwslabs.soa.Person>
persons = notebookPort.getPersons();
for (notebookwebserviceexercice1.jaxwslabs.soa.Person current : persons) {
out.print(current.getName() + " - " + current.getAddress() + "<br>
");
}
%>
</body>
</html>
L'opération getPersons() est invoquée via l'utilisation de la classe NotebookService. Le retour de l'opération est traité dans une boucle qui affiche pour chaque personne les informations concernant le nom et l'adresse. Déployer et tester l'application.
Exercice 4 - Développer un client de service Web en mode asynchrone▲
But▲
- Développer un client d'un service Web.
- Appel asynchrone.
- Outil wsimport.
- Client lourd via une interface graphique SWING.
Description▲
Cet exercice consiste à appeler le service Web défini dans l'exercice 1. Un client lourd défini via une interface graphique SWING est utilisé pour invoquer l'opération addPerson(…) en mode asynchrone. L'intérêt de cet exercice est de montrer comment paramétrer la génération des artefacts via wsimport pour le mode asynchrone.
Étapes à suivre▲
Créer un nouveau projet File -> New Project… puis Java choisir Java Application, faire Next.
Choisir comme nom de projet NotebookWebServiceClientExercice4 et comme nom de la classe principale (Main) soa.jaxwslabs.notebookwebserviceclientexercice4.WebServiceClient puis faire Finish.
Ajouter un nouveau fichier File -> New File… puis choisir Web Services et enfin Web Service Client. Faire Next.
Dans le champ WSDL URL, saisir l'URL http://localhost:8080/NotebookWebServiceExercice1/NotebookService?wsdl et configurer de la même manière que dans l'exercice 3 (étape 3).
Au niveau de la gestion des services Web du projet (nœud Web Service References), accéder aux propriétés du service NotebookService (menu Edit Web Service Attributes). Ouvrir l'onglet WSDL Customization, déplier l'option Global Customization et cocher l'option Enable Asynchronous Client (voir figure ci-dessous pour plus de précisions).
Il vous sera demandé de régénérer les artefacts liés au client service Web. Choisir le service Web NotebookService et faire Refresh Client.
Dans la classe WebServiceClient, recopier le code présenté ci-dessous.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
public
class
WebServiceClient extends
JFrame {
public
WebServiceClient
(
) {
super
(
"WebService Client from SWING application"
);
this
.setLayout
(
new
BorderLayout
(
));
final
JButton startButton =
new
JButton
(
"Call addPerson operation"
);
this
.getContentPane
(
).add
(
BorderLayout.NORTH, startButton);
final
JTextArea textArea =
new
JTextArea
(
);
this
.getContentPane
(
).add
(
BorderLayout.CENTER, textArea);
startButton.addActionListener
(
new
ActionListener
(
) {
public
void
actionPerformed
(
ActionEvent e) {
startButton.setEnabled
(
false
);
Person newPerson =
new
Person
(
);
newPerson.setName
(
"Mickael BARON"
);
newPerson.setAddress
(
"Poitiers"
);
textArea.append
(
"addPerson operation has been invoked.
\n
"
);
NotebookService_Service service =
new
NotebookService_Service
(
);
NotebookService port =
service.getNoteBookPort
(
);
port.addPersonAsync
(
newPerson, new
AsyncHandler<
AddPersonResponse>(
) {
public
void
handleResponse
(
Response<
AddPersonResponse>
res) {
if
(!
res.isCancelled
(
) &&
res.isDone
(
)) {
textArea.append
(
"New Person added"
);
startButton.setEnabled
(
true
);
}
}
}
);
}
}
);
this
.pack
(
);
this
.setVisible
(
true
);
}
public
static
void
main
(
String[] args) {
new
WebServiceClient
(
);
}
}
Vous aurez peut être besoin d'ajouter la bibliothèque JAX-WS dans le classpath du projet. Dans la partie Libraries du projet, ajouter la dépendance vers la bibliothèque JAX-WS 2.1 (menu Add Library… et choisir JAX-WS 2.1).
Faire un Clean and Build à partir du projet puis exécuter le programme. Le résultat attendu est celui montré sur la figure ci-dessous.
Exercice 5 - Développer un service Web en utilisant l'outillage de JavaSE▲
But▲
- Développer un service Web avec JavaSE.
- EndPoint.
- Méthode publish.
- Serveur Web intégré.
Description▲
L'objectif de cet exercice est de développer et publier un service Web en utilisant les fonctionnalités offertes par JavaSE. L'exemple de l'exercice 1 (Notebook) est utilisé.
Étapes à suivre▲
Créer un nouveau projet File -> New Project… puis Java choisir Java Application, faire Next.
Choisir comme nom de projet NotebookWebServiceJavaSE6Exercice5 et comme nom de la classe principale (Main) soa.jaxwslabs.notebookwebservicejavase6exercice5.JavaSE6WebService puis faire Finish.
Recopier l'interface NotebookService et les classes NotebookServiceImpl et Person issues de l'exercice 1 dans le projet NotebookWebServiceJavaSE6Exercice5 (respecter le nouveau nom de package).
Dans la classe JavaSE6WebService recopier le code présenté ci-dessous.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
public
class
JavaSE6WebService extends
JFrame {
private
Endpoint publish;
public
JavaSE6WebService
(
) {
this
.getContentPane
(
).setLayout
(
new
GridLayout
(
2
, 1
));
final
JButton startPublish =
new
JButton
(
);
this
.getContentPane
(
).add
(
startPublish);
startPublish.setText
(
"Start Publish"
);
final
JButton stopPublish =
new
JButton
(
);
stopPublish.addActionListener
(
new
ActionListener
(
) {
@Override
public
void
actionPerformed
(
ActionEvent e) {
publish.stop
(
);
stopPublish.setEnabled
(
false
);
startPublish.setEnabled
(
true
);
}
}
);
stopPublish.setText
(
"Stop Publish"
);
startPublish.addActionListener
(
new
ActionListener
(
) {
@Override
public
void
actionPerformed
(
ActionEvent e) {
NotebookService current =
new
NotebookServiceImpl
(
);
publish =
Endpoint.publish
(
"http://localhost:8080/notebook"
, current);
startPublish.setEnabled
(
false
);
stopPublish.setEnabled
(
true
);
}
}
);
stopPublish.setEnabled
(
false
);
startPublish.setEnabled
(
true
);
this
.getContentPane
(
).add
(
stopPublish);
this
.setTitle
(
"Start / Stop Web Service Publication"
);
this
.pack
(
);
this
.setVisible
(
true
);
}
public
static
void
main
(
String[] args) {
new
JavaSE6WebService
(
);
}
}
Vous aurez peut être encore besoin d'ajouter la bibliothèque JAX-WS dans le classpath du projet. Dans la partie Libraries du projet, ajouter la dépendance vers la bibliothèque JAX-WS 2.1 (menu Add Library… et choisir JAX-WS 2.1).
Faire un Clean and Build à partir du projet puis exécuter le programme.
Ouvrir une page de votre navigateur préféré et vérifier que le WSDL s'affiche correctement (URL : http://localhost:8080/notebook).
Exercice 6 - Ajouter un intercepteur (handler) à un service Web▲
But▲
- Implémentation handler.
- Configuration du service Web.
- Filtrage par opération.
Description▲
Dans cet exercice un intercepteur est ajouté au service Web décrivant le carnet d'adresses. L'intercepteur a pour fonction de filtrer les messages SOAP de telle sorte que le traitement de l'opération getPersons() ne soit pas réalisé.
Étapes à suivre▲
Créer un nouveau projet de type Web Application nommé NotebookWebServiceExercice6.
Créer un package intitulé soa.jaxwslabs.notebookwebserviceexercice6.
Recopier l'interface NotebookService et les classes NotebookServiceImpl et Person issues de l'exercice 1 dans le projet NotebookWebServiceExercice6 (respecter le nouveau nom de package).
Dans la classe NotebookServiceImpl, ajouter l'annotation @HandlerChain(file = « handler.xml ») au niveau de la description de la classe.
Ajouter un fichier handler.xml, au niveau du répertoire WEB-INF de l'application Web.
2.
3.
4.
5.
6.
7.
8.
9.
<?xml version="1.0" encoding="UTF-8"?>
<handler-chains
xmlns
=
"http://java.sun.com/xml/ns/javaee"
>
<handler-chain>
<handler>
<handler-name>
soa.jaxwslabs.notebookwebserviceexercice6.SOAPLoggingHandler</handler-name>
<handler-class>
soa.jaxwslabs.notebookwebserviceexercice6.SOAPLoggingHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
Ajouter une nouvelle classe intitulée SOAPLoggingHandler dont le code est défini de la manière suivante :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
public
class
SOAPLoggingHandler implements
SOAPHandler<
SOAPMessageContext>
{
@Override
public
Set<
QName>
getHeaders
(
) {
return
null
; }
@Override
public
void
close
(
MessageContext context) {
}
public
boolean
handleMessage
(
SOAPMessageContext smc) {
Boolean outboundProperty =
(
Boolean) smc.get
(
MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if
(
outboundProperty.booleanValue
(
)) {
return
false
; }
else
{
return
(!
"getPersons"
.equals
(
getMethodName
(
smc, true
)));
}
}
public
boolean
handleFault
(
SOAPMessageContext smc) {
return
true
; }
private
String getMethodName
(
SOAPMessageContext context, boolean
isRequest) {
try
{
Field field =
context.getClass
(
).getSuperclass
(
).getDeclaredField
(
"packet"
);
field.setAccessible
(
true
);
Packet packet =
(
Packet) field.get
(
context);
if
(
isRequest) {
return
((
StreamMessage) packet.getMessage
(
)).getPayloadLocalPart
(
);
}
return
((
JAXBMessage) packet.getMessage
(
)).getPayloadLocalPart
(
);
}
catch
(
Exception e) {
e.printStackTrace
(
);
}
return
null
;
}
}
Noter que la méthode getMethodName(…) s'occupe d'extraire du contenu du message SOAP le nom de l'opération.
Faire un Clean and Build à partir du projet de déployer l'application.
Remerciements▲
Je tiens à remercier Claude Leloup pour sa relecture orthographique attentive de cet article.