Bonjour,

J'ai un EJB qui sert en remote, local, localBean dans une application. Il a ses objets métiers depuis assez longtemps.

Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package services.auditeurs;
 
import java.io.*;
import java.util.*;
import javax.annotation.*;
import javax.ejb.*;
import javax.jws.*;
 
import surf.*;
import utils.fichier.*;
import utils.localisation.*;
 
import domaine.auditeurs.*;
import domaine.auditeurs.exception.*;
import domaine.sujets.*;
import domaine.uvs.*;
import domaine.uvs.exception.*;
 
import static dao.factory.auditeur.AuditeurDAOFactory.*;
import static dao.factory.uv.UVDAOFactory.*;
 
import services.*;
 
 
/**
 * Services aux auditeurs.
 */
@WebService @LocalBean @Stateless public class AuditeurBean extends ServiceStandard implements AuditeurRemoteService, AuditeurLocalService
{
   /**
    * Déclarer le niveau de moral d'un auditeur sur un sujet d'UV.
    * @param locales Locales à utiliser pour l'invocation.
    * @param c Casier de l'auditeur évalué.
    * @param idTheme Identifiant du thème sur lequel le moral est déclaré, peut valoir <em>null</em>.
    * @param niveauMoral Niveau de moral attribué.
    * @throws AuditeurInexistantException si l'auditeur n'existe pas.
    * @throws PersistanceException si un incident survient sur le support.
    */
   public void declarerMoral(Locales locales, Casier c, ThemeId idTheme, NiveauMoral niveauMoral) throws AuditeurInexistantException, PersistanceException
   {
        ...
   }
 
   /**
    * Ajouter un auditeur.
    * @param locales Locales à utiliser pour l'invocation.
    * @param auditeur Auditeur à ajouter.
    * @throws AuditeurDejaExistantException si l'ajout de l'auditeur provoquerait un doublon.
    * @throws PersistanceException si un incident est survenu sur le support.
    */
   public void ajouterAuditeur(Locales locales, Auditeur auditeur) throws AuditeurDejaExistantException, PersistanceException
   {
        ...
   }
 
   /**
    * Déterminer si un identifiant d'auditeur est valide.
    * @param locales Locales à utiliser pour l'invocation.
    * @param id Identifiant à contrôler.
    * @return <em>true</em> si l'identifiant est valide. <br>
    *         <em>false</em> s'il ne l'est pas.
    */
   public boolean isIdentifiantValide(Locales locales, String id)
   {
        ...
   }
 
   /**
    * Mettre à jour un auditeur.
    * @param locales Locales à utiliser pour l'invocation.
    * @param auditeur Auditeur à mettre à jour.
    * @throws AuditeurInexistantException si l'auditeur recherché n'a pas été trouvé sur le support.
    * @throws PersistanceException si un incident est survenu sur le support.
    */
   public void modifierAuditeur(Locales locales, Auditeur auditeur) throws AuditeurInexistantException, PersistanceException
   {
        ...
   }
 
   /**
    * Charger un auditeur d'indentifiant donné.
    * @param locales Locales à utiliser pour l'invocation.
    * @param id Identifiant de l'auditeur à charger.
    * @return Auditeur recherché.
    * @throws AuditeurInexistantException si l'auditeur n'a pas été trouvé.
    * @throws PersistanceException si un incident survient sur le support.
    */
   public Auditeur obtenirAuditeur(Locales locales, AuditeurId id) throws AuditeurInexistantException, PersistanceException
   {
        ...
   }
 
   /**
    * Charger l'ensemble des auditeurs.
    * @return Ensemble des auditeurs.
    * @throws DonneesNonTrouveesException si aucun auditeur n'a pu être trouvé.
    * @throws PersistanceException si un incident survient sur le support.
    * @deprecated Coûteuse en termes de performances.
    */
   // @RolesAllowed("enseignant") 
   @Deprecated public Auditeurs obtenirTousLesAuditeurs(Locales locales) throws PersistanceException
   {
        ...
   }
 
   /**
    * Obtenir la liste des auditeurs qui sont inscrits à une UV.
    * @param locales Locales à utiliser pour l'invocation.
    * @param idUV Identifiant de l'unité de valeur recherchée.
    * @return Liste des auditeurs qui se sont inscrits à cette UV.
    * @throws UVInexistanteException si l'unité de valeur n'existe pas.
    * @throws PersistanceException si un incident survient sur le support.
    */
   // @RolesAllowed("enseignant")
   public Auditeurs obtenirAuditeurs(Locales locales, UVId idUV) throws UVInexistanteException, PersistanceException
   {
        ...
   }
 
   /**
    * Supprimer une série d'auditeurs.
    * @param locales Locales à utiliser pour l'invocation.
    * @param ids Identifiant de l'UV.
    * @throws AuditeurInexistantException si l'auditeur à supprimer n'a pas été trouvé.
    * @throws PersistanceException si un incident survient sur le support.
    */
   public void supprimerAuditeurs(Locales locales, AuditeursIds ids) throws AuditeurInexistantException, PersistanceException
   {
        ...
   }
 
   /**
    * Supprimer un auditeur.
    * @param locales Locales à utiliser pour l'invocation.
    * @param id Identifiant de l'auditeur à supprimer.
    * @throws AuditeurInexistantException si l'auditeur à supprimer n'a pas été trouvé.
    * @throws PersistanceException si un incident survient sur le support.
    */
   // @RolesAllowed("enseignant")
   public void supprimerAuditeur(Locales locales, AuditeurId id) throws AuditeurInexistantException, PersistanceException
   {
        ...
   }
}
Les objets métiers utilisés en paramètres (import domaine.*) sont assez élaborés en terme de contrôles de cohérence. Ce sont de simples POJO, certes, mais qui vérifient beaucoup de choses avant d'accepter de retourner une valeur via leurs getters. Ce sont des éléments déterminants de la stabilité de mon application par leur auto-contrôle de la cohérence de leur état. J'y tiens particulièrement.

J'ai souhaité récemment que mon serveur d'application admettre d'être joint via des web services. J'ai mis en place les annotations @WebService et autres associées.

Cependant, je me suis rendu compte que les commandes wsgen (ou peut être wsimport) souhaitaient générer d'autres objets que ceux que j'utilisais en paramètre. Et cela me pose deux problèmes.

1) Toutes les liaisons vers des objets métiers dans l'équivalent stub produit par wsgen ou wsimport sont faites non pas vers:
domaine.auditeurs.Auditeur ou domaine.uvs.UVId
mais vers services.auditeurs.Auditeur et services.auditeurs.UVId.
Pourtant, ma commande wsgen mentionnait bien le classpath où se trouvaient les classes à utiliser.

2) Les objets proposés sont des POJO prosaïques, bien sûr. Le wsimport ne peut faire autre chose. Mais ce qu'il me propose ne me sert à rien.

D'abord parce que toutes mes applications attendent mes objets métiers dans les packages où ils sont, et pas là où le web service voudrait me les proposer à la place.
Ensuite, parce que ce sont mes objets qu'il faut instancier en fin de compte à l'appel et employer en arguments.

Je suis intrigué. Car de mon expérience de l'informatique, tout ce qui était mécanisme de sérialisation, RMI, Corba était peu intrusif, mais là, le mécanisme de web services semble souhaiter me forcer à changer tous mes objets, tous mes emplacements. J'ai rarement vu quelque-chose de plus destructeur, et donc je suis convaincu de faire fausse route parce que cela ne peut pas être aussi brutal que cela.

Pourtant, je n'ai rien trouvé dans la commande wsgen pour lui demander de respecter mes packages d'objets métiers.


J'ai l'impression qu'il me manque pas mal de billes pour comprendre l'ensemble du fonctionnement de ce mécanisme d'invocation. Mais:

Mes services actuels ont une interface qui ne doit pas changer. Ils peuvent prendre des annotations supplémentaires dans l'implémentation de l'EJB mais c'est tout.
Mes objets métiers sont ceux qu'ils sont, et ne doivent pas bouger non plus.

Le mécanisme de web services doit créer des équivalents "stubs - skeletons", je le comprends, pour sa cuisine interne. Mais là, il bousille mon code à la place. Comment dois-je employer les commandes wsgen/wsimport ou annoter mes web services pour que la génération des classes "techniques de transport" reste à sa place auxiliaire, et ne vienne pas se mêler à ce point au code métier existant? C'est à dire reste absolument transparente comme rmi, corba, et tous les autres mécanismes ont réussi à le faire depuis des dizaines d'années?

En vous remerciant,

Grunt.