[débutant] RMI et réutilisation de code

RMI et réutilisation de code [débutant] - Java - Programmation

Marsh Posté le 27-03-2004 à 13:01:04    

j'ai un TP sur RMI à faire avec l'exemple pompé et repompé du dictionnaire distribué (une collection de mot côté serveur).
 
Je me dis : je vais y aller doucement, faire un truc qui marche sans client serveur. je fais un classe classique Dictionary, et une petite interface en ligne de commande Cmd (d'ailleurs regarder moi cette verbosité, on est loin de python Cmd, enfin bon, c'est ça ni delegate, ni pointeur de fonction, hum hum)
Voilà, ça marche comme je veux en local : il me reste plus qu'à enrober tout ça pour l'exporter.
 
et là je bloque. déjà, je vois qu'il faut que je fasse une interface à mon Dictionary pour déclarer que tout est succeptible de lancer RemoteException. ok.
 
maintenant mon RDictionaryServer : là je bloque un peu. pas d'héritage multiple, donc comme ça doit "extends UnicastRemoteObject implements RDictionary" je me retrouve à faire de la composition : c'est un peu pénible, mais simple à faire. ok
 
mon RegisterIt : ras
 
mon RDictionaryClient ... ça commence facile, jusqu'au moment ou je veux utiliser mon code existent, à savoir mon Interface Cmd ... ben évidemment ça marche plus, j'ai pas pu hériter de Dictionary... là je bloque, je suis pas allé plus loin.
 
http://dejean.benoit.free.fr/code/rmi_rdict.tar.bz2 (rdict_old)
 
comment je peux faire pour réutiliser mon code, et en général, comment faire ?


Message édité par Taz le 27-03-2004 à 21:41:35
Reply

Marsh Posté le 27-03-2004 à 13:01:04   

Reply

Marsh Posté le 27-03-2004 à 14:28:14    

Salut,
pour ta qst, je n'ai pas bien compris ton problème ...
 
Par contre, pour ton RDictionaryServer, je te conseillerais plutot de faire comme ça :
 
créer une classe de type :
1. RDictionaryImpl extends java.rmi.server.UnicastRemoteObject implements RDictionary qui fasse les traitemets.
 
2. une classe RDictionaryServer du genre :
import java.rmi.Naming;
 
public class RDictionaryServer
{
  public RDictionaryServer()
  {
    try
    {
      RDictionary = new RDictionaryImpl();
      Naming.rebind("rmi://localhost:1099/RDictionaryService", c);
    } catch (Exception e) {
      System.out.println(e);
    }
  }
 
  public static void main (String args[]) {
    new RDictionaryServer();
  }
}

Reply

Marsh Posté le 27-03-2004 à 14:46:25    

ma question est simple : entre toutes ces interfaces et super-classes, je peux pas réutiliser mon code.
 
quant à ton conseil, il ne change rien au problème.
 
j'ai un client et du code qui jusqu'à présent manipule des Dictionary, je n'arrive pas par RMI à lui faire utiliser des  Dictionary distants.

Reply

Marsh Posté le 27-03-2004 à 15:23:16    

citation=685600,1][nom]Taz a écrit[/nom]ma question est simple : entre toutes ces interfaces et super-classes, je peux pas réutiliser mon code.
 
quant à ton conseil, il ne change rien au problème.
 
j'ai un client et du code qui jusqu'à présent manipule des Dictionary, je n'arrive pas par RMI à lui faire utiliser des  Dictionary distants.
[/citation]
 
t'es pas obligé de faire hériter ta classe d'objet remote d'UnicastRemoteObject (URO).. il faut juste que tu fasses le boulot à la main...
 
1) Tu crées une interface décrivant l'objet remote avec juste les méthodes que tu veux voir disponibles à distance...  
2) Tu crée ta classe d'objet remote sans hériter d'URO... mais tu peux alors utiliser l'héritage unique pour ta propre arborescence.
3) Dans le code qui va créer réellement l'objet remote (càd souvent le code du serveur) tu  dois simplement faire  

Code :
  1. <interface type> var = new <remote object class>(...);
  2. <interface type> stub = (<interface type> )UnicastRemoteObject.exportObject(var);
  3. Naming.rebind(<service name>, stub);


ou <interface type> est le nom de ton interface, <remote object class> est le nom de la classe réalisant l'interface et <service name> est le nom que tu as choisit pour ton service
et normalement ça devrait marcher comme tu l'espère


Message édité par leonhard le 27-03-2004 à 15:23:59
Reply

Marsh Posté le 27-03-2004 à 15:25:59    

Taz a écrit :

ma question est simple : entre toutes ces interfaces et super-classes, je peux pas réutiliser mon code.
 
quant à ton conseil, il ne change rien au problème.
 
j'ai un client et du code qui jusqu'à présent manipule des Dictionary, je n'arrive pas par RMI à lui faire utiliser des  Dictionary distants.


 
Je n'ai pas dit cela allait résoudre ton pb, c t juste un conseil de conception au niveau de tes classes. D'ailleurs, je t'avais dit que n'avais pas bien compris ton problème ... tu parles d'Interface Cmd alors que c une classe, tu veux hériter de Dictionary, alors que tu n'en as absolument pas besoin ...

Reply

Marsh Posté le 27-03-2004 à 15:35:10    

kotw a écrit :

tu parles d'Interface Cmd alors que c une classe, tu veux hériter de Dictionary, alors que tu n'en as absolument pas besoin ...  

je parlais d'IHM :o
je veux juste que mon appli client puisse récupérer un sous type de Dictionary pour pouvoir utiliser du code existant.
 
donc si je te suis, je garde mon <interface> RDictionary. donc à part faire une sous-interface Remote et une classe implémentant cette sous-interface composé d'un Dictionary, ça devrait passer.  
 
question : si tu veux exporter une classe complète, tu fais comment ? parce que faire une interface pour juste rajouter les déclarations d'exception et une classe d'implémentation qui ne fait strictement rien si ce n'est enrober pour que ça colle au niveau des prototypes ...

Reply

Marsh Posté le 27-03-2004 à 15:40:26    

genre

Code :
  1. import java.rmi.*;
  2. import java.rmi.server.*;
  3. public class RemoteDictionaryImpl implements RemoteDictionary
  4. {
  5.     // et voilà, boom, pas d'héritage multiple
  6.     private Dictionary rdict;
  7.     public RemoteDictionaryServer() throws RemoteException
  8.     {
  9. super();
  10. this.rdict = new Dictionary();
  11.     }
  12.     public boolean hasWord(String w) throws RemoteException
  13.     {
  14. return this.rdict.hasWord(w);
  15.     }
  16.     public void addWord(String w) throws RemoteException
  17.     {
  18. this.rdict.addWord(w);
  19.     }
  20.     public void delWord(String w) throws RemoteException
  21.     {
  22. this.rdict.delWord(w);
  23.     }
  24.     public int count() throws RemoteException
  25.     {
  26. return this.rdict.count();
  27.     }
  28.     public String[] allWords() throws RemoteException
  29.     {
  30. return this.rdict.allWords();
  31.     }
  32. }

c'est pas ce que ça m'amuse mais bon ;)

Reply

Marsh Posté le 27-03-2004 à 15:56:04    

1. Tu gardes ta classe RDictionary
2. tu jettes ta classe Dictionary : tu créés à la place une classe RDictionaryImplementation qui hérite de UnicastRemoteObject et qui implemente RDictionary.
3. Dans ton RDictionaryServer, tu créés un objet de type :
RDictionary dict = new RDictionaryImplementation();
Naming.rebind("rmi://localhost:1099/RDictionaryService", dict); (tu enregistres cet objet de serveur au niveau du service)
4. Coté client, pour accéder à ce service de manière distante, tu fais :
RDictionary dico = (RDictionary )
          Naming.lookup(
              "rmi://localhost/RDictionaryService" );
 
après, "dico" pourra etre utilisé dans ta classe Cmd !

Reply

Marsh Posté le 27-03-2004 à 16:00:47    

kotw a écrit :

1. Tu gardes ta classe RDictionary
2. tu jettes ta classe Dictionary : tu créés à la place une classe RDictionaryImplementation qui hérite de UnicastRemoteObject et qui implemente RDictionary.
3. Dans ton RDictionaryServer, tu créés un objet de type :
RDictionary dict = new RDictionaryImplementation();
Naming.rebind("rmi://localhost:1099/RDictionaryService", dict); (tu enregistres cet objet de serveur au niveau du service)
4. Coté client, pour accéder à ce service de manière distante, tu fais :
RDictionary dico = (RDictionary )
          Naming.lookup(
              "rmi://localhost/RDictionaryService" );
 
après, "dico" pourra etre utilisé dans ta classe Cmd !

C'est trop facile ça. La base du cahier des charges c'est de réutiliser Dictionnary et Cmd...
Ceci dit j'ai jamais fais de RMI donc je peux pas aider...


---------------
Au royaume des sourds, les borgnes sont sourds.
Reply

Marsh Posté le 27-03-2004 à 16:06:00    

R3g a écrit :

C'est trop facile ça. La base du cahier des charges c'est de réutiliser Dictionnary et Cmd...
Ceci dit j'ai jamais fais de RMI donc je peux pas aider...


 
Dis moi, à quoi elle sert cette classe Dictionary ? Je n'arrive pas à voir son utilité ...
 
Edit : qd on fait des invocations de méthodes distantes, les variables d'objets sont des interfaces et non des objets !!


Message édité par kotw le 27-03-2004 à 16:07:42
Reply

Marsh Posté le 27-03-2004 à 16:06:00   

Reply

Marsh Posté le 27-03-2004 à 16:11:03    

Si le but est de "réutiliser" Dictionary, c'est dans la classe RDictionaryImplementation qu'il faudra utiliser les méthodes de Dictionary. Mais il faut avoir à l'esprit que ce sont des objets de type interface auxquels on accède aux méthodes ...

Reply

Marsh Posté le 27-03-2004 à 19:01:32    

kotw a écrit :

Si le but est de "réutiliser" Dictionary, c'est dans la classe RDictionaryImplementation qu'il faudra utiliser les méthodes de Dictionary. Mais il faut avoir à l'esprit que ce sont des objets de type interface auxquels on accède aux méthodes ...

mais c'est exactement ce que j'ai posté. et le problème c'est justement ça : avec 2/3 méthodes ça passe, maintenant, si tu veux exporter un truc complet genre java.util.List, pas la peine d'y penser. ton edit confirme le problème. les interfaces, c'est bien, mais quand tu as tu code existant... Donc déjà, ça répond à une de mes questions, à savoir que c'est fastidieux à mettre en place.
 
par contre ça me dit pas comment récupérer un Dictionary sur le client. le problème c'est que ma classe Cmd bosse avec des Dictionary ...
 
je te remercie de ton aide. maintenant que le problème est posé, à savoir réutiliser du code, est-ce que tu vois un moyen de récupérer un Dictionary et pas un RDictionary coté client ?

Reply

Marsh Posté le 27-03-2004 à 19:23:51    

Le problème, c'est qu'en RMI, ton client ne peut récupérer que des objets de type interface et non des objets instances d'une classe (comme c'est le cas dans ta classe Cmd). Il y a une énorme différence entre programmer en RMI et programmer "classiquement" : "classiquement" tu peux utiliser ou pas des interfaces, en RMI c'est obligatoire ! Dans ta classe Cmd, si tu veux absolument trouver un moyen de faire :
Dictionary dit = new Dictionary(); // en utilisant RMI bon courage !
 
Maintenant, dans ta classe Cmd, il faut que tu fasses comme dans ta classe RDictionaryClient :
RDictionary dict = (RDictionary) Naming.lookup (..);
 
PS : je te rappelle que RMI = invocation distante de Méthodes et non pas d'objets ...

Reply

Marsh Posté le 27-03-2004 à 19:30:21    

oui mais bon, on a quand même plus la notion d'objets qu'en RPC.
 
je sais bien que je peux résoudre mon problème en créant faisant un Dictionary qui a implémente Remote et non pas dans l'autre sens. à çe moment là, pour sur, ça fonctionne très bien.
 
est-ce que je peux conclure que RMI c'est bien, sauf que la réutilisabilité stricte (c'est à dire la possibilité de réutiliser du code déjà écrit et fonctionnel sans le modifier), elle tend vers zéro ?

Reply

Marsh Posté le 27-03-2004 à 19:39:35    

Ben, tout dépend quand même du code existant !
AMHA, si tu prends l'habitude de programmer en utilisant au maximum les interfaces, les possibilités de réutilisabilité ne tendent pas vers zéro.

Reply

Marsh Posté le 27-03-2004 à 19:45:14    

euh comment ça ? comment je peux faire sans foutre une seule ligne de RMI dans mon code Cmd et Dictionary ?

Reply

Marsh Posté le 27-03-2004 à 19:56:00    

Lol je n'ai pas dit que tu pouvais le faire directement dans ton cas particulier, mais en règle générale ...
 
Maintenant, dans ton cas, honnetement, c'est si pénalisant d'écire dans Cmd : RDictionary dict = (RDictionary) ...
et d'écrire une classe du genre :  
RDictionaryImplementation extends UnicastRemoteObject implements RDictionary qui fasse exactement la meme chose que ta classe Dictionary ?

Reply

Marsh Posté le 27-03-2004 à 19:59:21    

donc, je dois bien comprendre que pour travailler avec RMI:
- soit créer une interface basée sur Remote et dériver tôt ou tard de UnicastRemoteObject
- soit créer une interface basée sur Remote et utiliser UnicastRemoteObject.exportObject
 
bref au moment ou tu codes, il faut penser à faire cette sous-interface de Remote et tout travailler avec. correct ?

Reply

Marsh Posté le 27-03-2004 à 20:17:58    

AMHA, le plus simple est :
- créer une interface qui hérite de java.rmi.Remote qui contient les signatures des méthodes
- créer une classe d'implémentation qui hérite d'UnicastRemoteObject et qui implémente ton interface. Cette classe peut effectivement hériter d'une autre classe et utiliser UnicastRemoteObject.exportObject.
 
Edit :
- soit créer une interface basée sur Remote et dériver tôt ou tard de UnicastRemoteObject  --> créer simplement une interface qui hérite de Remote.
- soit créer une interface basée sur Remote et utiliser UnicastRemoteObject.exportObject -- > créer une classe(et non pas une interface !) qui hérite d'UnicastRemoteObject et qui implémente ton interface.
 
J'espère que c'est un peu plus clair pour toi, parce-que j'ai l'impression que tu confonds parfois interface et classe ...


Message édité par kotw le 27-03-2004 à 20:24:24
Reply

Marsh Posté le 27-03-2004 à 20:25:55    

c'est un peu exactement ce que j'ai dit :D
 
non, je ne fais pas de confusion, seulement tu interprètes mal à chaque fois que je fais de l'implicite.
 
merci

Reply

Marsh Posté le 27-03-2004 à 20:42:11    

En fait, je fais autre chose à côté ...
et c'est vrai qu'il m'arrive dans ces cas là de pas bien comprendre :-)

Reply

Marsh Posté le 27-03-2004 à 21:33:08    

voilà j'ai donc fait mon TP comme ça.
http://dejean.benoit.free.fr/code/rmi_rdict.tar.bz2


Message édité par Taz le 27-03-2004 à 21:41:03
Reply

Marsh Posté le 27-03-2004 à 21:53:57    

Si ça marche chez toi, c'est le principal ... :-)  
Après, y a tjrs des remarques sur la façon de faire... que je ne dirais pas parce-que j'ai pas envie de me prendre pour un expert alors que je n'en suis pas ...

Reply

Marsh Posté le 27-03-2004 à 22:00:15    

ben là j'ai fait une sous-interface RemoteDictionary de java.rmi.Remote. j'ai gardé ma classe Dictionary. J'ai créé une classe RemoteDictionaryImplementation qui concrétise RemoteDictionary en utilisant Dictionary. Et puis comme ça me paraissait trop simple, j'ai mélangé, c'est à dire que RemoteDictionaryImplementation ne dérive pas de java.rmi.server.UnicastRemoteObject, par contre je crée moi même le stub avec  java.rmi.server.UnicastRemoteObject.exportObject :D

Reply

Marsh Posté le 27-03-2004 à 22:18:20    

AMHA,
1. ta classe RegisterIt devrait s'appeler RemoteDictionaryServer avec une méthode  
main (String[] args]
{
  new RemoteDictionaryServer();
}
et, dans le constructeur de RemoteDictionaryServer, tu mets le code actuel de ta mtd main de RegisterIt.
 
2. ton client devrait pas appeler run directement mais pourrait être appelé en ligne de commande.
Imagines que ton service se trouve sur une autre machine, tu pourras appeler ton client en passant en paramètre l'adresse exacte de la machine --> dans ton client, tu ferais un Naming.lookup(args[0]) par ex plutot que d'écrire en dur le nom du service ...
 
etc... :-)

Reply

Marsh Posté le 27-03-2004 à 22:46:27    

1) mouef, c'est une autre technique
 
2) ouaip

Reply

Marsh Posté le 28-03-2004 à 01:06:18    

Taz > j'ai la flemme de ragarder en détail (j'ai juste cru capter que tu veux réutiliser du code sans te taper 15 délégations à la mano), mais je te file ça : http://java.sun.com/j2se/1.4.2/doc [...] Proxy.html
 
Qui est probablement en rapport avec la choucroute.
 
J'ai un exemple d'utilisation là (classe "CollectionProxy" ) de délégation sur la classe Collection:
http://rien.a.dire.free.fr/concour [...] nning.html


---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 28-03-2004 à 01:13:32    

oui et non. c'est vrai que c'est pas mal, pour résoudre le problème de la fastidieuse délégation. je vais apprendre à jouer avec. edit: mais d'ailleurs, je ne suis pas sur de pouvoir m'en sortir, puisque ce qui m'obligeait à la délagation était le changement de prototype, à savoir le type d'exception suceptible d'être lancé ( <rien> -> RemoteException ). et j'ai pas encore découvert si je pouvais le régler facilement.
 
mais le principal problème n'était pas là et la solution s'est éloignée de ce que j'avais prévu (en fait j'ai tout réécrit sauf une classe et là effectivement, j'ai délégué)


Message édité par Taz le 28-03-2004 à 01:19:16
Reply

Marsh Posté le 30-03-2004 à 12:19:50    

nraynaud a écrit :

Taz > j'ai la flemme de ragarder en détail (j'ai juste cru capter que tu veux réutiliser du code sans te taper 15 délégations à la mano), mais je te file ça : http://java.sun.com/j2se/1.4.2/doc [...] Proxy.html
 
Qui est probablement en rapport avec la choucroute.
 
J'ai un exemple d'utilisation là (classe "CollectionProxy" ) de délégation sur la classe Collection:
http://rien.a.dire.free.fr/concour [...] nning.html


 
Dans quel cas, la génération dynamique d'un objet Proxy peut-être utile ? Est-ce-que tu as un exemple d'utilisation de cette classe ?

Reply

Marsh Posté le 30-03-2004 à 13:08:29    

ben l'exemple de nraynaud est superbe je trouve

Reply

Marsh Posté le 30-03-2004 à 13:29:06    

ben son code doit être trop pointu pour moi car je panne que dalle à ce que c'est censé faire  :sweat:


Message édité par machinbidule1974 le 30-03-2004 à 13:29:36
Reply

Marsh Posté le 30-03-2004 à 16:30:14    

machinbidule1974 a écrit :

ben son code doit être trop pointu pour moi car je panne que dalle à ce que c'est censé faire  :sweat:  

je fais un proxy de collection.
Les méthodes qui m'intéressent je les prends ; les autre je les file à l'objet réel (collection dans ce cas).
 
Tout appel de méthode sur le proxy fini dans le invoke() avec les paramètres qui vont bien.

Code :
  1. public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  2.   try {
  3. /* la méthode contains() m'intéresse, je la traite moi-même */
  4.    if (method.equals(containsMethod))
  5.     if (args[0] == null)
  6.      return Boolean.FALSE;
  7.     else
  8.      return unwrappingInvoke(collection, method, args);
  9. /* la méthode containsAll() m'aintéresse, je traite moi-même */
  10.    if (method.equals(containsAllMethod))
  11.     return containsAll((Collection)args[0]);
  12.   } catch (OverlapsException e) {
  13.    return Boolean.FALSE;
  14.   }
  15. /* les autres méthodes, c'est le vrai objet (collection) qui se démerdera avec */
  16.   return unwrappingInvoke(collection, method, args);
  17.  }
  18. /* une petite feinte au niveau des exceptions expliquée ici : http://forum.hardware.fr/forum2.ph [...] 0&subcat=0
  19. */
  20.  private Object unwrappingInvoke(Object object, Method method, Object[] args)
  21.   throws Throwable {
  22.   try {
  23.    return method.invoke(object, args);
  24.   } catch (InvocationTargetException e) {
  25.    throw e.getCause();
  26.   }
  27.  }


 
 
 
Taz > attention cependant que ce code est buggé dans sa partie comportementale (et j'ai la flemme de le corriger). Il y a des cas dans lequels prendre un sous-arbre ne renvoie pas le bon réultat.


Message édité par nraynaud le 30-03-2004 à 16:31:09

---------------
trainoo.com, c'est fini
Reply

Marsh Posté le 30-03-2004 à 16:32:13    

ok. toutes façons, a priori, je ne peux pas l'utiliser, j'ai résolu mon programme en réécrivant tout

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed