# ClientFacade mit RMI



## Bradan (7. Jun 2010)

Hallo,

Gibt es irgendeinen Weg ohne RMIProxy eine asynchrone ClientFacade zu realisieren über RMI, ohne dass der Client andauernd Nachfragen muss ob der Server nun eine Nachricht übermitteln will? Mit anderen Worten: Ich will die Naming.rebind Geschichte auch den Clients erlauben, die nicht auf dem Serverrechner laufen ohne gleich die AccessException zu bekommen.

Mit freundlichen Grüßen,
Daniel


----------



## L-ectron-X (7. Jun 2010)

Gegen die AccessControlException hilft signieren...


----------



## Bradan (9. Jun 2010)

Hallo,

Danke für die Antwort. Wenn du das mit der policy Datei meinst, dann habe ich das hier bereits versucht:

Main-Methode, ganz am Anfang:

```
System.setSecurityManager(new RMISecurityManager()); // mit und ohne dem
		
		System.setProperty("java.security.policy", "java.policy");
		System.setProperty("java.rmi.server.ignoreStubClasses", "true");
		System.setProperty("java.rmi.server.hostname", "192.168.2.101");
```

java.policy:

```
grant {
    permission java.security.AllPermission;
};
```

Doch es funktioniert nicht. Es verhält sich wie zuvor. Auch das mit "ignoreStubClasses" zeigt garkeine Wirkung. Muss ich vielleicht erst eine JAR Datei erstellen und diese dann mit einem Zertifikat signieren? Das wäre echt blöd, denn dann müsste ich zum Debuggen dauernd Exportieren, Signieren, ... .


----------



## tuxedo (9. Jun 2010)

Bradan hat gesagt.:


> Gibt es irgendeinen Weg ohne RMIProxy eine asynchrone ClientFacade zu realisieren über RMI, ohne dass der Client andauernd Nachfragen muss ob der Server nun eine Nachricht übermitteln will?



Öhm, ich denke das was du suchst sind Callbacks, oder? Einfach auf Clientseite ein RemoteObjekt basteln (über die export-Funktion oder eben klassich...) und den Server per RMI rüberschieben. Der Server kann dann das Objekt nutzen um Methoden beim CLient aufzurufen.

Allerdings ist das (wie deine angedachte Lösung wohl auch), mehr als unschön wenn über's Internet kommuniziert werden soll. Ne erklärung gibts hier: SIMON - Start - root1.de - Software Engineering

- Alex


----------



## Bradan (9. Jun 2010)

tuxedo hat gesagt.:


> Öhm, ich denke das was du suchst sind Callbacks, oder? Einfach auf Clientseite ein RemoteObjekt basteln (über die export-Funktion oder eben klassich...) und den Server per RMI rüberschieben. Der Server kann dann das Objekt nutzen um Methoden beim CLient aufzurufen.
> 
> Allerdings ist das (wie deine angedachte Lösung wohl auch), mehr als unschön wenn über's Internet kommuniziert werden soll. Ne erklärung gibts hier: SIMON - Start - root1.de - Software Engineering
> 
> - Alex



Die RemoteObjects sind bereits im Klassendiagramm und im Code (ClientFacade) ;-) , nur wirft es eben beim Registry.bind/rebind/unbind auf einer Registry, die nicht auf demselben Rechner läuft AccessExceptions die ich einfach nicht losbekomme. Das Internet ist egal, denn das Programm ist für das lokale Netzwerk gedacht.


----------



## tuxedo (9. Jun 2010)

Du brauchst um vom Server aus Methoden am Client aufuzrufen keine Registry auf Client-Seite.

Wenn der Client ein Remote-Objekt einem Methodenaufruf auf dem Server als Argument mitgibt, kann der Server dieses Remoteobjekt nutzen um Methoden in diesem Remoteobjekt am Client aufzurufen.
RMI (wie SIMON auch) erledigen das ganze binden an die Registry und Co. intern. 

Gibt es denn eine Anforderung dass am Client eine Registry laufen MUSS?
Wenn nicht: Weglassen ... Verkompliziert die Sache nur...

- Alex


----------



## Bradan (9. Jun 2010)

Hallo,

Danke für die Antwort.



tuxedo hat gesagt.:


> Du brauchst um vom Server aus Methoden am Client aufuzrufen keine Registry auf Client-Seite.



Hab ich auch garnicht behauptet. Das ist ja mein Ziel das zu vermeiden ohne eine AccessException zu bekommen von Registry.rebind/bind/unbind.



tuxedo hat gesagt.:


> Wenn der Client ein Remote-Objekt einem Methodenaufruf auf dem Server als Argument mitgibt, kann der Server dieses Remoteobjekt nutzen um Methoden in diesem Remoteobjekt am Client aufzurufen.
> RMI (wie SIMON auch) erledigen das ganze binden an die Registry und Co. intern.



Hmm also geschieht das intern? Und es wird keine Kopie erstellt wie mit Serializable? Das ist nämlich jetzt blöd, da ich die Methoden nichtmehr anpassen kann.



tuxedo hat gesagt.:


> Gibt es denn eine Anforderung dass am Client eine Registry laufen MUSS?
> Wenn nicht: Weglassen ... Verkompliziert die Sache nur...
> 
> - Alex



Nein, eben nicht. Aber ich wollte das RemoteObjekt vom Client direkt an der Server-Registry binden. Also sowas hier:


```
Registry registry = LocateRegistry.getRegistry("192.168.2.101", 6000);

ServerActionInterface server = (ServerActionInterface) registry.lookup("ServerFacade");
String name = server.registerClient(); // gib einen eindeutigen Namen zurück, der nicht mehrmals vergeben wird.

// registriere die Clientfacade in der Server-Registry
TestClient client = new TestClient();
ClientActionInterface clientStub = (ClientActionInterface) UnicastRemoteObject.exportObject(client);
registry.rebind(name, clientStub);
```

Mit freundlichen Grüßen,
Daniel Brall


----------



## tuxedo (9. Jun 2010)

> Hmm also geschieht das intern? Und es wird keine Kopie erstellt wie mit Serializable? Das ist nämlich jetzt blöd, da ich die Methoden nichtmehr anpassen kann.



Fast ... Beim übergeben des Client-Remoteobjekts an den Server via Methodenaufruf, wird dieses Objekt beim Client quasi in einer eigenen Registry gebunden und beim Server wird ein Proxy-Objekt angelegt das die Aufrufe übers Netzwerk zum Client leitet. Das Objekt ist und bleibt das gleiche. Keine Kopie.



> Nein, eben nicht. Aber ich wollte das RemoteObjekt vom Client direkt an der Server-Registry binden.



Das kannst du dir sparen wenn du das Objekt einfach als Argument dem Server bei einem Remote-Methodenaufruf mitgibst.

Google einfach mal nach "RMI Callback" ...
Du kannst auch in dieses Beispiel reinschauen. Das ist von der Art her sehr verwand zu RMI und macht genau das. --> SIMON - Sample helloworld - root1.de - Software Engineering

- Alex


----------



## Bradan (9. Jun 2010)

Danke, das sind aber schlechte Nachrichten für mich :-( .


----------



## tuxedo (9. Jun 2010)

Was ist daran schlecht? Das ganze ist weniger komplex, Fehleranfällig und eigentlich fix zu machen...
Oder hab ich was übersehen?

- Alex


----------



## Bradan (9. Jun 2010)

tuxedo hat gesagt.:


> Was ist daran schlecht? Das ganze ist weniger komplex, Fehleranfällig und eigentlich fix zu machen...
> Oder hab ich was übersehen?
> 
> - Alex



Ja, dass ich die Methoden nichtmehr ändern darf. Das würde zu weit reichende Konsequenzen mit sich ziehen. Alles nochmal von vorne. Alle Dokumente und jegliche Pseudocodes umändern. Nichtmehr den Facadename auf der Serverseite speichern, sondern gleich die Referenz auf das Objekt. Ich hätte nie gedacht, dass das automatisch geht. Steht ja auch fast nirgends. Sucht man nach RMI und ClientFacade findet man Mojibake Seiten und irgendwelche Zusatzbibliotheken. In allen Beispielen steht nur eine Serverfacade. Und mit RMI Callback findet man Lösungen über "Polling", d.h. der Client fragt dauernd nach neuen Daten.


----------



## tuxedo (9. Jun 2010)

?? Let me google that for you --> 4. Suchergebnis "RMI Client Callback  Example" ... oder auch 8. Suchergebnis: "Threads and Callbacks  in RMI" :autsch:

Und die Sache mit dem "Code nicht mehr ändern".

Versteh ich nicht. Der Server hat zwar mit deinem Ansatz erstmal nur den Namen der Client-facade. Aber spätestens wenn er eine Methode aufrufen will braucht er a) das passende Interface und b) muss er wissen welche Methode er aufrufen will.

Änderst du nun das Interface, hat doch der Server keine Chance mehr die Methode aufzurufen. Gut, wenn du das Interface nur immer erweiterst und das Interface zur Laufzeit von Client runterlädst, dann geht das. Aber dann hast du immer noch a) ein sehr komplexes Szenario und b) hat der Server nix von deiner Erweiterung deiner Facade. Was du erreicht hast ist, dass ein alter Server auch mit einer neuen Client-facade zurecht kommt. Bleibt aber immer noch die Frage offen ob ein neuer Client mit einem alten Server zurecht kommt?

- Alex


----------



## Bradan (10. Jun 2010)

tuxedo hat gesagt.:


> ?? Let me google that for you --> 4. Suchergebnis "RMI Client Callback  Example" ... oder auch 8. Suchergebnis: "Threads and Callbacks  in RMI" :autsch:
> 
> Und die Sache mit dem "Code nicht mehr ändern".



Danke, dennoch bin ich irgendwie nach langer Suche auf eine Seite gekommen die mir da ernsthaft Polling als Callback andrehen wollte.



tuxedo hat gesagt.:


> Versteh ich nicht. Der Server hat zwar mit deinem Ansatz erstmal nur den Namen der Client-facade. Aber spätestens wenn er eine Methode aufrufen will braucht er a) das passende Interface und b) muss er wissen welche Methode er aufrufen will.



Ja dann solltest du dir mal das Naming oder Registry ansehen. Da hats die Methode lookup() womit ich über den Facadename zur Facade käme. Aber dazu müsste ich zuerst Registry.bind oder rebind aufrufen von dem Client aus auf dem Server. Wenn das irgendwie machbar wäre ohne dass ich an der Serverseite was ändern müsste wäre ich glücklich. Ich mein das wär ja ganz einfach es so zu machen auf der ClientSeite:

Registry reg = LocateRegistry.getRegistry(ServerIP, ServerPort);
reg.bind("ClientStub", clientStub);

Das funktioniert auch auf der Clientseite, aber nur solange der Client auf demselben PC wie der Server läuft.



tuxedo hat gesagt.:


> Änderst du nun das Interface, hat doch der Server keine Chance mehr die Methode aufzurufen. Gut, wenn du das Interface nur immer erweiterst und das Interface zur Laufzeit von Client runterlädst, dann geht das. Aber dann hast du immer noch a) ein sehr komplexes Szenario und b) hat der Server nix von deiner Erweiterung deiner Facade. Was du erreicht hast ist, dass ein alter Server auch mit einer neuen Client-facade zurecht kommt. Bleibt aber immer noch die Frage offen ob ein neuer Client mit einem alten Server zurecht kommt?
> 
> - Alex



Nein das Interface will ich ja garnicht ändern, Mensch. Ich will garnichts ändern an den Methoden, ich will ne Lösung für das AccessException Problem ;-) .
Am Code bin ich ja noch garnicht. Ich bin an den Klassendiagrammen, aber die darf ich wie gesagt nichtmehr ändern, da der "Kunde" das bereits so abgesegnet hat.

Ich weiß nicht was an meinem Problem so schwer zu verstehen ist. Die erste Antwort lief wohl auf das richtige hinaus, da andere es so auch gelöst bekommen haben. Aber bei mir scheint es nicht richtig zu funktionieren.

Stell dir das Problem vielleicht ganz anders vor: Der Server hat garkeine Facade und darf auch nie eine haben (Kundenanforderung z.B.) und die Clients registrieren sich manuell auf der entfernten Java Registry.


----------



## tuxedo (10. Jun 2010)

> Da hats die Methode lookup() womit ich über den Facadename zur Facade käme.



Das ist klar. Aber wie ich ja geschrieben hatte bringt das keinen wirklichen Vorteil mit sich.

Die Sache mit dem "Code nicht mehr ändern" hab ich falschrum verstanden. Dachte du meintest den Code bzgl. Facade bzw. deren Implementierung.

Was du ändern müsstest ist eine Methode am Server. Evtl. müsste man sogar eine hinzufügen. Nämlich so, dass man den Clientcallback dem Server mitteilen kann. Abet gut, wenn der Kunde auf so niedriger Ebene alles absegnet, dann ist das natürlich nicht mehr möglich. 

In diesem Fall kann ich dir leider nicht weiterhelfen :-(

- Alex


----------

