[Java ] - RMI et les MAJ d'objets

- RMI et les MAJ d'objets [Java ] - Programmation

Marsh Posté le 11-02-2002 à 23:43:46    

Bon, voilà le truc : je cherche à créer un Pong en réseau. J'ai choisi d'utiliser RMI pour mettre des objets en partage. Pour l'instant je cherche à écrire un module de connection pour les joueurs. Chaque joueur ouvre une appli PongClient clique sur Join et ajoute son nom à la liste puis "launch". On lance aussi un PongServer qui crée l'objet distant RemoteList. Tout ça j'y arrive. Maintenant ce que je voudrais faire et je n'y arrive pas, c'est gérer le fait que lorsqu'un joueur fait "launch" ça réactualise les listes dans les menus Join des autres PongClient.
 

Code :
  1. //AboutDialog.java
  2. import java.awt.*;
  3. import java.awt.event.*;
  4. import javax.swing.*;
  5. public class AboutDialog extends JDialog implements ActionListener {
  6.    
  7.     public AboutDialog(Frame parent, String title, String message) {
  8.         super(parent, title, true);
  9.        
  10.         if (parent != null) {
  11.             Dimension parentSize = parent.getSize();
  12.             Point p = parent.getLocation();
  13.             setLocation(p.x + parentSize.width / 4, p.y + parentSize.height / 4);
  14.         }
  15.        
  16.         JPanel messagePane = new JPanel();
  17.         messagePane.add(new JLabel(message));
  18.         getContentPane().add(messagePane, BorderLayout.CENTER);
  19.        
  20.         JPanel buttonPane = new JPanel();
  21.         JButton button = new JButton("OK" );
  22.         buttonPane.add(button);
  23.         button.addActionListener(this);
  24.         getContentPane().add(buttonPane, BorderLayout.SOUTH);
  25.        
  26.         setDefaultCloseOperation(DISPOSE_ON_CLOSE);
  27.         pack();
  28.         setVisible(true);
  29.     }
  30.    
  31.     public void actionPerformed(ActionEvent e) {
  32.         setVisible(false);
  33.         dispose();
  34.     }
  35. }
  36. //PongClient.java
  37. import java.awt.*;
  38. import java.awt.event.*;
  39. public class PongClient {
  40.     public PongClient() {
  41.     }
  42.    
  43.     public static void main(String args[]) {
  44.         theApp = new PongClient();
  45.         theApp.init();
  46.     }
  47.    
  48.     public void init() {
  49.         window = new PongClientFrame(this, "Pong" );
  50.         window.setBounds(0, 0, 640, 480);
  51.         window.setResizable(false);
  52.         window.setVisible(true);
  53.     }
  54.    
  55.     public String getUser() {
  56.         return user;
  57.     }
  58.    
  59.     public void setUser(String user) {
  60.         this.user = user;
  61.     }
  62.    
  63.     public void windowClosing(WindowEvent e) {
  64.         window.dispose();
  65.         System.exit(0);
  66.     }
  67.    
  68.     public void windowOpened(WindowEvent e) {}
  69.     public void windowClosed(WindowEvent e) {}
  70.     public void windowIconified(WindowEvent e) {}
  71.     public void windowDeiconified(WindowEvent e) {}
  72.     public void windowActivated(WindowEvent e) {}
  73.     public void windowDeactivated(WindowEvent e) {}
  74.    
  75.     private static PongClientFrame window;
  76.    
  77.     private static PongClient theApp;
  78.    
  79.     private String user = "user";
  80. }
  81. //PongClientFrame.java
  82. import java.awt.*;
  83. import java.awt.event.*;
  84. import javax.swing.*;
  85. import javax.swing.event.*;
  86. public class PongClientFrame extends JFrame implements ActionListener {
  87.    
  88.     public PongClientFrame(PongClient theApp, String title) {
  89.         setTitle(title);
  90.         this.theApp = theApp;
  91.         setJMenuBar(menuBar);
  92.         setDefaultCloseOperation(EXIT_ON_CLOSE);
  93.        
  94.         JMenu gameMenu = new JMenu("Game" );
  95.         JMenu helpMenu = new JMenu("Help" );
  96.        
  97.         gameMenu.setMnemonic('G');
  98.         helpMenu.setMnemonic('H');
  99.        
  100.         joinAction = new GameAction("Join", KeyStroke.getKeyStroke('J', Event.CTRL_MASK));
  101.         exitAction = new GameAction("Exit", KeyStroke.getKeyStroke('E', Event.CTRL_MASK));
  102.        
  103.         addMenuItem(gameMenu, joinAction);
  104.         addMenuItem(gameMenu, exitAction);
  105.        
  106.         aboutItem = createMenuItem("About" );
  107.         helpMenu.add(aboutItem);
  108.        
  109.         rulesItem = createMenuItem("Rules" );
  110.         helpMenu.add(rulesItem);
  111.        
  112.         aboutItem.setAccelerator(KeyStroke.getKeyStroke('A', Event.CTRL_MASK));
  113.         rulesItem.setAccelerator(KeyStroke.getKeyStroke('R', Event.CTRL_MASK));
  114.        
  115.         menuBar.add(gameMenu);
  116.         menuBar.add(helpMenu);
  117.         enableEvents(AWTEvent.WINDOW_EVENT_MASK);
  118.     }
  119.    
  120.     public void actionPerformed(ActionEvent e) {
  121.         if (e.getSource() == aboutItem) {
  122.             AboutDialog aboutDialog = new AboutDialog(this, "About", "Copyright 2002 Cherrytree" );
  123.         }
  124.         else if (e.getSource() == rulesItem) {
  125.         }
  126.     }
  127.    
  128.     private JMenuItem createMenuItem(String label) {
  129.         JMenuItem item = new JMenuItem(label);
  130.         item.addActionListener(this);
  131.         return item;
  132.     }
  133.    
  134.     private JMenuItem addMenuItem(JMenu menu, Action action) {
  135.         JMenuItem item = menu.add(action);
  136.        
  137.         KeyStroke keystroke = (KeyStroke)action.getValue(action.ACCELERATOR_KEY);
  138.         if(keystroke != null)
  139.             item.setAccelerator(keystroke);
  140.         return item;
  141.     }
  142.    
  143.     private void showConnectDialog() {
  144.         PongConnectDialog connectDialog = new PongConnectDialog(theApp, this, "Join", theApp.getUser());
  145.     }
  146.    
  147.     class GameAction extends AbstractAction {
  148.        
  149.         GameAction(String name) {
  150.             super(name);
  151.         }
  152.        
  153.         GameAction(String name, KeyStroke keystroke) {
  154.             this(name);
  155.             if(keystroke != null)
  156.                 putValue(ACCELERATOR_KEY, keystroke);
  157.         }
  158.        
  159.         public void actionPerformed(ActionEvent e) {
  160.             String name = (String)getValue(NAME);
  161.             if (name.equals(joinAction.getValue(NAME)))
  162.                 showConnectDialog();
  163.             else if (name.equals(exitAction.getValue(NAME)))
  164.                 System.exit(0);
  165.         }
  166.     }
  167.    
  168.     private PongClient theApp;
  169.    
  170.     private JMenuBar menuBar = new JMenuBar();
  171.     private GameAction joinAction, exitAction;
  172.     private JMenuItem aboutItem, rulesItem;
  173. }
  174. //PongConnectDialog
  175. import java.awt.*;
  176. import java.awt.event.*;
  177. import javax.swing.*;
  178. import java.rmi.*;
  179. import java.net.*;
  180. public class PongConnectDialog extends JDialog implements ActionListener {
  181.    
  182.     public PongConnectDialog(PongClient theApp, Frame parent, String title, String user) {
  183.         super(parent, title, true);
  184.         this.theApp = theApp;
  185.         this.user = user;
  186.         if (parent != null) {
  187.             Dimension parentSize = parent.getSize();
  188.             Point p = parent.getLocation();
  189.             setLocation(p.x + parentSize.width / 4, p.y + parentSize.height / 4);
  190.         }
  191.         setSize(new Dimension(180, 300));
  192.        
  193.         Box inputBox = Box.createHorizontalBox();
  194.         JLabel userLabel = new JLabel("User: " );
  195.         inputBox.add(userLabel);
  196.         inputBox.add(userInput);
  197.        
  198.         Box buttonBox = Box.createHorizontalBox();
  199.         addButton = new JButton("Add" );
  200.         addButton.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
  201.         addButton.addActionListener(new AddListener());
  202.         buttonBox.add(addButton);
  203.        
  204.         removeButton = new JButton("Remove" );
  205.         removeButton.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
  206.         removeButton.setEnabled(false);
  207.         removeButton.addActionListener(new RemoveListener());
  208.         buttonBox.add(removeButton);
  209.        
  210.         Box userBox = Box.createVerticalBox();
  211.         userBox.add(inputBox);
  212.         userBox.add(buttonBox);
  213.         getContentPane().add(userBox, BorderLayout.NORTH);
  214.        
  215.         try {
  216.             RemoteListModel remoteList = (RemoteListModel)Naming.lookup("rmi://localhost/remoteList" );
  217.             JList list = new JList(remoteList.getList());
  218.             JScrollPane scrollPane = new JScrollPane(list);
  219.             getContentPane().add(scrollPane, BorderLayout.CENTER);
  220.         }
  221.         catch (NotBoundException e) {
  222.             System.err.println(e.getMessage());
  223.             e.printStackTrace();
  224.         }
  225.         catch (MalformedURLException e) {
  226.             System.err.println(e.getMessage());
  227.             e.printStackTrace();
  228.         }
  229.         catch (RemoteException e) {
  230.             System.err.println(e.getMessage());
  231.             e.printStackTrace();
  232.         }
  233.        
  234.         Box launchBox = Box.createHorizontalBox();
  235.         launchButton = new JButton("Launch" );
  236.         launchButton.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
  237.         launchButton.setEnabled(false);
  238.         launchButton.addActionListener(new LaunchListener());
  239.         launchBox.add(launchButton);
  240.        
  241.         cancelButton = new JButton("Cancel" );
  242.         cancelButton.setMaximumSize(new Dimension(Integer.MAX_VALUE, 20));
  243.         cancelButton.addActionListener(this);
  244.         launchBox.add(cancelButton);
  245.        
  246.         getContentPane().add(launchBox, BorderLayout.SOUTH);
  247.        
  248.         setDefaultCloseOperation(DISPOSE_ON_CLOSE);
  249.         setVisible(true);
  250.     }
  251.    
  252.     public void actionPerformed(ActionEvent e) {
  253.         if(e.getSource() == cancelButton) {
  254.             setVisible(false);
  255.             dispose();
  256.         }
  257.     }
  258.    
  259.     class AddListener implements ActionListener {
  260.        
  261.         public void actionPerformed(ActionEvent e) {
  262.             user = new String(userInput.getText());
  263.             if (user.equals("" ) || user.equalsIgnoreCase("user" )) {
  264.                 Toolkit.getDefaultToolkit().beep();
  265.                 return;
  266.             }
  267.             else {
  268.                 addButton.setEnabled(false);
  269.                 removeButton.setEnabled(true);
  270.                 launchButton.setEnabled(true);
  271.             }
  272.         }
  273.     }
  274.    
  275.     class RemoveListener implements ActionListener {
  276.        
  277.         public void actionPerformed(ActionEvent e) {
  278.             addButton.setEnabled(true);
  279.             removeButton.setEnabled(false);
  280.             launchButton.setEnabled(false);
  281.         }
  282.     }
  283.    
  284.     class LaunchListener implements ActionListener {
  285.        
  286.         public void actionPerformed(ActionEvent event) {
  287.             try {
  288.                 theApp.setUser(user);
  289.                 RemoteListModel remoteList = (RemoteListModel)Naming.lookup("rmi://localhost/remoteList" );
  290.                 remoteList.addElement(user);
  291.                 setVisible(false);
  292.                 dispose();
  293.             }
  294.             catch (NotBoundException e) {
  295.                 System.err.println(e.getMessage());
  296.                 e.printStackTrace();
  297.             }
  298.             catch (MalformedURLException e) {
  299.                 System.err.println(e.getMessage());
  300.                 e.printStackTrace();
  301.             }
  302.             catch (RemoteException e) {
  303.                 System.err.println(e.getMessage());
  304.                 e.printStackTrace();
  305.             }
  306.         }
  307.     }
  308.    
  309.     private PongClient theApp;
  310.    
  311.     private String user;
  312.     private JTextField userInput = new JTextField(user);
  313.    
  314.     private JButton addButton, removeButton, launchButton, cancelButton;
  315.    
  316.     private DefaultListModel users;
  317. }
  318. //PongServer.java
  319. import java.rmi.*;
  320. public class PongServer {
  321.    
  322.     public static void main(String[] args) {
  323.         try {
  324.             RemoteList remoteList = new RemoteList();
  325.             Naming.rebind("rmi://localhost/remoteList", remoteList);
  326.         }
  327.         catch (Exception e) {
  328.             System.err.println("PongServer exception: " + e.getMessage());
  329.             e.printStackTrace();
  330.         }
  331.     }
  332. }
  333. //RemoteList.java
  334. import javax.swing.*;
  335. import java.rmi.*;
  336. import java.rmi.server.*;
  337. public class RemoteList extends UnicastRemoteObject implements RemoteListModel {
  338.    
  339.     public RemoteList() throws RemoteException {
  340.         super();
  341.     }
  342.    
  343.     public DefaultListModel getList() {
  344.         return remoteList;
  345.     }
  346.    
  347.     public void addElement(String name) {
  348.         remoteList.addElement(name);
  349.     }
  350.    
  351.     private DefaultListModel remoteList = new DefaultListModel();
  352. }
  353. //RemoteListModel.java
  354. import javax.swing.*;
  355. import java.rmi.Remote;
  356. import java.rmi.RemoteException;
  357. public interface RemoteListModel extends Remote {
  358.     DefaultListModel getList() throws RemoteException;
  359.     void addElement(String name) throws RemoteException;
  360. }

 

[jfdsdjhfuetppo]--Message édité par Cherrytree--[/jfdsdjhfuetppo]


---------------
Le site de ma maman
Reply

Marsh Posté le 11-02-2002 à 23:43:46   

Reply

Marsh Posté le 12-02-2002 à 00:37:33    

il suffit que tu utilises le pattern listeneur.
 
le principe c'est que tu as un objet qui gère une liste d'objet qu'il devra prenévenir dans le cas où il arrive un évenement.
 
lorsque ton client se connecte, il faut qu'il envoie la référence d'un objet que le serveur stockera dans une liste.  
 
Lorsque le serveur reçoit la connection d'un nouveau joueur, il préviendra les autres joueurs en appelant une méthode sur chaqu'un des objets de la liste en question (en passant en paramètre le nom de chaque joueur par exemple).
 
c'est ce que tu voulais savoir ?


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 12-02-2002 à 07:19:10    

Très exactement ! C'est encore un peu confus dans ma tête, mais je vais chercher dans la direction Pattern Listener et je vais voir ce que je trouve tout seul. Si j'échoue, et bien...
 
Encore merci benou.


---------------
Le site de ma maman
Reply

Marsh Posté le 12-02-2002 à 10:49:46    

Plus clairement tu peux définir une interface comme ca
 

Code :
  1. public interface ClientCallback {
  2.     public void updateClientList(Client[] clients);
  3.     // autres fonctions utiles
  4. }


ensuite tes clients implémente cette interface (par exemple l'objet MyCallback.  On peut ensuite imaginer que ta méthode connect sur ton serveur à l'allure suivante:
 

Code :
  1. public void connect (ClientCallback callback, //autres params) {
  2. // ici tu ajoutes l'interface de callback dans une List et tu appelles la méthode updateClientList sur toutes les interface de la liste
  3. // autres trucs ...
  4. }

 

[jfdsdjhfuetppo]--Message édité par darklord22--[/jfdsdjhfuetppo]


---------------
What is popular is not always right, what is right is not always popular :D
Reply

Marsh Posté le 12-02-2002 à 11:53:51    

darklord22 a écrit a écrit :

Plus clairement


ca veut dire quoi ca ??? ;)


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 12-02-2002 à 11:55:25    

benou a écrit a écrit :

ca veut dire quoi ca ??? ;)  




 
ro la la je donnais juste un exemple parce que le callback c'est pas toujours si évident à comprendre c'est tout :D


---------------
What is popular is not always right, what is right is not always popular :D
Reply

Marsh Posté le 12-02-2002 à 20:44:23    

darklord22 a écrit a écrit :

 
 
ro la la je donnais juste un exemple parce que le callback c'est pas toujours si évident à comprendre c'est tout :D  




 
Très juste, d'autant que j'avais pris l'info de benou au premier degré, du coup j'suis allé voir comme un dingue sur le net et dans mes bouquins ce que c'était que "pattern listener" :) . J'ai pensé que c'était une sorte de Listener en Java et j'ai bien galéré...
 
Donc là je rentre du boulot, je vois le squelette de code que tu me pond. Au début je me dit en voyant interface qu'il va falloir faire du client/serveur dans les deux sens ; puis en éxaminant mieux : public void updateClientList(Client[] clients);
 
En somme tu veux que le client agisse sur les autres clients directement. C'est ça ? Dans ce cas, ben... je sais pas trop comment récupérer les références à moins de les passer au serveur. Donc si je ne me trompe pas au final, tout nouveau client gagne une référence sur les clients connectés précedemment. Dis-moi si je me trompe !
 
Par contre et ça peut paraître idiot mais j'ai pas tout compris sur la méthode : public void connect(ClientCallback callback, //autres params). Celle-ci est bien une méthode destinée à être implémentée sur le client, pas sur le serveur, et je passerai this en tant que ClientCallback (du moins le client courant)...
 
A que c'est compliqué quand on débute !


---------------
Le site de ma maman
Reply

Marsh Posté le 12-02-2002 à 21:03:33    

non ce n'est pas ca et je n'ai plus le temps pour t'expliquer. Demain matin je posterai si ben est pas passé....


---------------
What is popular is not always right, what is right is not always popular :D
Reply

Marsh Posté le 12-02-2002 à 22:09:59    

darklord22 a écrit a écrit :

non ce n'est pas ca et je n'ai plus le temps pour t'expliquer. Demain matin je posterai si ben est pas passé....  




:jap: :sweat: :) Je suis désolé... J'ai honte. Enfin merci en tous cas.


---------------
Le site de ma maman
Reply

Marsh Posté le 12-02-2002 à 23:59:25    

bon, je vais essayé d'être plus clair ce coup-ci....
 
déjà le patern que j'appelait Listener, c'est aps son vrai nom. Le paterne s'appelle "Obervé-Observer". Tu pourras d'ailleur trouvé un semblant d'implémentation dans le package java.util.  Ce patern là est beaucoup utilisé dans Swing pour les evénements : un composant peux générer des évenement, et d'autres objets s'abonnent (grâce aux listeners) à ce composant pour resevoir les évenement générés.
 
mais bon. C'ets pas ton problème, donc je passe ...
 
Résumons. Tu veux que tes clients recçoivent la liste des autres joueurs connectés au serveur, et que celles-ci se mette à jour lorsqu'un nouveau joueur se connecte.
 
Dans ce problème, l'objet Observé est le serveur, qui contient la liste des clients. Les clients sont les observeurs : ils observent une modification du serveur (un nouveau joueur se connecte).
 
Pour être au courant des évenements du serveur, les clients vont devoir s'abonner au serveur. Il faut donc qu'il y ait une méthode d'abonnement sur ton objet serveur, et que le serveur gère une liste des clients abonnés. :
 

Code :
  1. import java.util.*;
  2. public class Serveur {
  3.   protected Collection clientsAbonnes = new ArrayList();
  4.   ... 
  5.   public abonner(Client client) {
  6.      clientsAbonnes.add(client);
  7.   }
  8.   ...
  9. }


remarque : pour faire propre il faudrait aussi gérer les désabonnement, mais bon ... :sarcastic:  
 
On va dire que ton Client possède une méthode qui lui permet de remettre  jour la liste des joueur connectés :

Code :
  1. public class Client {
  2.    ...
  3.    public void mettreAJourListeJoueurs(String[] joueurs) {
  4.        ...
  5.    }
  6.    ...
  7. }


 
ce qu'il suffit ensuite de faire c'est que lorsque le Serveur reçoit une nouvelle connection d'un de tes clients, il met à jour sa liste interne de joueurs puis la diffuse à tous les clients abonnés.
 

Code :
  1. ...
  2.    Iterator it = clientsAbonnes.iterator();
  3.    while (it.hasNext()) {
  4.       ((Client)it.next()).mettreAJourListeJoueurs(listeInterneDeJoueurs);
  5.    }
  6.    ...


 
voila c'est tout.
 
En pratique, ce n'est pas l'objet Client qu'on abonne au serveur, mais un sous-objet dont le rôle et de reservoir les évenement (Le listener : écouteur d'évenement). Ce listener à une interface bien définie dans laquelle chaque méthode correspond à un évenement particulier. Cette méthode sera appelée lorsque l'évenement en questiona ura étét déclenché. Pour des raisons pratique, on passe habituellement en paramètre de ces méthodes des informations sur l'évenement (ici la liste des joueurs). Ca évite d'avoir à redemander l'info au serveur.
 
Maintenant, si on parle RMI, il faut que l'objet Listener (celui qui tu envoies au serveur pour l'abonner) soit un PortableRemote Object (si je me souviens bien, c'est ca les objets intérrogeable à distance), ainsi que ton serveur. Les paramètres des méthodes de ton Listener devront être Serializable pour pouvoir être transférés  via le réseau.
 
 
voila. J'espère que je me suis mieux fait comprendre ce coup-ci. J'ai un gros effort pour être clair ! :)
 
PS : le vrai design-patern observé-observeur est (à peine) plus compliqué que ca ...


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 12-02-2002 à 23:59:25   

Reply

Marsh Posté le 13-02-2002 à 08:53:16    

Merci benou... :hello: Là c'est super clair. Juste un dernier avant d'implémenter : en RMI, il me semblait qu'on passait les objets par valeurs, autrement dit quand tu fais "clientsAbonnes.add(client)", tu copies l'objet dans la liste que maintient le serveur. Ce qui fait que le serveur ne retrouve pas le client ? Je sais que j'ai tort, mais je veux être sûr. Est-ce que cette possibilité par rapport à Remote est du fait que tu utilises PortableRemote ?

Reply

Marsh Posté le 13-02-2002 à 09:46:58    

Cherrytree a écrit a écrit :

Merci benou... :hello: Là c'est super clair. Juste un dernier avant d'implémenter : en RMI, il me semblait qu'on passait les objets par valeurs, autrement dit quand tu fais "clientsAbonnes.add(client)", tu copies l'objet dans la liste que maintient le serveur. Ce qui fait que le serveur ne retrouve pas le client ? Je sais que j'ai tort, mais je veux être sûr. Est-ce que cette possibilité par rapport à Remote est du fait que tu utilises PortableRemote ?  




 
il n'y a que les types primaires qui sont passés par valeur en RMI. Les interfaces et compagnie sont passées par référence.


---------------
What is popular is not always right, what is right is not always popular :D
Reply

Marsh Posté le 13-02-2002 à 09:56:11    

Alors ça devrait rouler. Merci encore :hello: !


---------------
Le site de ma maman
Reply

Marsh Posté le 13-02-2002 à 10:44:02    

si je me souviens bien, il faut que tes objets héritent de PortableRemoteObject pour ca, nan ? c'est pas automatique ...
 
(je me souviens plus bien, j'ai pas fais bcp de RMI)
 
petite précision : il n'y a que les types primaires ET les objets sérializables qui sont passés par valeur


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 13-02-2002 à 11:41:21    

benou a écrit a écrit :

si je me souviens bien, il faut que tes objets héritent de PortableRemoteObject pour ca, nan ? c'est pas automatique ...
 
(je me souviens plus bien, j'ai pas fais bcp de RMI)
 
petite précision : il n'y a que les types primaires ET les objets sérializables qui sont passés par valeur  




 
Y'm semblait aussi que les types primaires n'étaient pas les seuls. Pour les PortableRemote, j'ai aucun bouquin qui en parle (je crois, je suis pas à la maison).

Reply

Marsh Posté le 13-02-2002 à 14:11:47    

y a un reflexe à avoir : question en Java --> Thinking in Java
 
regarde la : http://penserenjava.free.fr/pens/i [...] htm#07.040
 
il faut que ton objet hérite de UnicastRemoteObject et implémente une interface qui étend Remote.
 
enfin, tu trouveras tous les détails avec le lien !


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 13-02-2002 à 14:21:05    

Je sens que je vais apprendre ce bouquin par coeur. Encore merci.

Reply

Marsh Posté le 13-02-2002 à 14:23:42    

Cherrytree a écrit a écrit :

Je sens que je vais apprendre ce bouquin par coeur. Encore merci.  




sincérement, si tu prends le temps (c'est long) ca vaut vraiment le coup !!!
tu apprendras le java, abordera tout ce qui se rapporte au Java (rmi, ejb, jni, servlet, jsp, corba, ...) et tu auras surtout une excellente vision d'une bonne programation objet.
 
un must !


---------------
ma vie, mon oeuvre - HomePlayer
Reply

Marsh Posté le 13-02-2002 à 14:36:32    

J'aime.

Reply

Sujets relatifs:

Leave a Replay

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