[Java] RMI probleem

Pagina: 1
Acties:

  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
Ik moet binnenkort een presentatie doen over Java RMI.
Om RMI wat beter te proberen begrijpen probeer ik het voorbeeld uit de
RMI Trail van de Java Tutorial te laten werken.
Dit lukt echter niet naar wens:

Ik zal even kort de situatie uitleggen (je kunt ook de pagina's over dit voorbeeld
raadplegen op http://java.sun.com/docs/books/tutorial/rmi/ ):
Het voorbeeld bestaat dus uit een server en een client gedeelte.
- Op de server wordt een remote object ComputeEngine aangemaakt dat de interface Compute implementeert. Deze interface vereist dat het object een methode executeTask(Task t) bezit. De client kan dan deze methode oproepen en een Task meegeven die uitgevoerd moet worden.
- De client contacteert het remote ComputeEngine object dmv de registry,
maakt een instantie van de klasse ComputePi aan die de interface Task implementeert, en roept executeTask() van het remote ComputeEngine object aan met als parameter het ComputeEngine object.

De situatie is als volgt:
- De class files van de interfaces Task en Compute staan zowel aan client als aan serverkant lokaal in het classpath.
- De class files van ComputeEngine staan natuurlijk in het classpath aan serverkant. De class files van de bijhorende stub en skeleton van ComputeEngine staan op de webserver aan de serverkant, zodat ze via het netwerk beschikbaar zijn aan de client.
- De class files van ComputePi en Pi staan natuurlijk in het classpath aan de clientzijde + de class file van Pi staat ook op de webserver aan clientzijde zodat de server de klasse Pi kan ophalen als die de klasse nodig heeft.

Dit is de configuratie die met de stappen in de tutorial wordt bekomen,
en het is ook de configuratie die strookt met mijn idee van de werking van RMI.

Volgens mij zou het volgende moeten gebeuren als de client uitgevoerd wordt:
- De client contacteert de registry en verkrijgt zo 'link' naar het remote ComputeEngine object. Die 'link' bevat het adres van de webserver waar de client de klassen die 'm nodig heeft kan downloaden.
- De client download vervolgens de stub file van de ComputeEngine klasse van de webserver van de remote server.
- Via deze stub roept de client de methode executeTask() van ComputeEngine op,
met als parameter een ComputePi object.
- RMI transporteert het ComputePi object naar de server.
- Bij het verwerken van de execute() methode ComputePi komt de server de Pi klasse tegen, dus downloadt de server deze klasse van de webserver van de client.
- Het resultaat wordt van de server naar de client getransporteert en daar weergegeven.

Ik krijg het voorbeeld echter niet werkend met de configuratie zoals hierboven.
Bij het uitvoeren van de client wordt de volgende exceptie gegenereerd:

code:
1
java.lang.ClassNotFoundException: engine.ComputeEngine_Stub


Na wat research blijkt dat de client ComputeEngine_Stub.class aanvraagt bij zijn EIGEN
webserver ipv de webserver van de remote server.
Concreet: de client vraagt om ComputeEngine_Stub.class bij de URL die opgegeven werd bij java.rmi.server.codebase bij het starten van de client.
Maar waarom zoekt de client deze stub file in zijn eigen publieke klassen?

Ik kan het voorbeeld WEL laten werken als ik ComputeEngine_Stub.class in het classpath van de client zet. Dan werkt het voorbeeld perfect.
Dit druist echter volledig in tegen mijn begrip van RMI:
het is toch de bedoeling dat de client alleen weet heeft van de Compute interface,
en dat RMI zorgt voor het transport van de stub die communicatie met de implementatie van Compute mogelijk maakt?
Maw: RMI zou er toch moeten voor zorgen dat ComputeEngine_Stub.class bij de client terecht komt?

Begrijp ik de werking van RMI niet goed en moet ik die stub file toch zelf aan de client kant zetten? Maar hoe past dit dan in het concept van RMI, waar zit de fout in mijn redenering?

Nog wat aanvullende informatie:
- Het gebruikte commando om de server op te starten (rmiregistry draait dan al):
code:
1
2
3
java -classpath .;classes\compute.jar
    -Djava.rmi.server.codebase=http://localhost/server_classes/
    -Djava.security.policy=java.policy engine.ComputeEngine //localhost/Compute

(hierbij is http://localhost/server_classes de URL naar de publieke klassen van de server.)

- Het gebruikte commando om de client op te starten:
code:
1
2
3
java -classpath .;classes\compute.jar
    -Djava.rmi.server.codebase=http://localhost/client_classes/ 
    -Djava.security.policy=java.policy client.ComputePi localhost 20

(hierbij is http://localhost/client_classes de URL naar de publieke klassen van de client.)

- De beide policy files zijn zeker in orde.

De kernvraag van mijn probleem is dus:
Waarom zoekt de client de stub file van het remote object in zijn eigen publieke klassen en niet in de publieke klassen van de remote server, wat een stuk logischer zou zijn imo...

Ik hoop dat er hier iemand is die ervaring heeft met RMI, want ik ben hier nu al een dag of 2 mee bezig en het ziet er nier naar uit dat ik ooit zelf de oplossing zal vinden... (en eerlijk gezegd wordt ik er lichtjes 8)7 van.)

  • Robtimus
  • Registratie: November 2002
  • Laatst online: 26-05 15:28

Robtimus

me Robtimus no like you

DieterVDW schreef op 07 april 2004 @ 06:34:
De kernvraag van mijn probleem is dus:
Waarom zoekt de client de stub file van het remote object in zijn eigen publieke klassen en niet in de publieke klassen van de remote server, wat een stuk logischer zou zijn imo...
Omdat je dus opgeeft dat de codebase van de RMI server op http://localhost/client_classes zit, en daar gaat hij dus ook zoeken. De codebase van de client moet volgens mij ook die van de server zijn, daar moet hij immers de class files ophalen.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


Verwijderd

hihihi, hier heb ik ook een tijd mee zitten klooien. Probeer je client eens op te starten zonder de codebase parameter. Good luck ;) Zou moeten werken

  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
IceManX schreef op 07 april 2004 @ 10:05:
[...]
Omdat je dus opgeeft dat de codebase van de RMI server op http://localhost/client_classes zit, en daar gaat hij dus ook zoeken. De codebase van de client moet volgens mij ook die van de server zijn, daar moet hij immers de class files ophalen.
De codebase van de RMI server is http://localhost/server_classes hé!
Maar ik begrijp wat je bedoelt denk ik.
Je bedoelt waarschijnlijk dat de codebase van de client naar http://localhost/server_classes moet wijzen.
Ik heb dit al geprobeerd, maar dan krijg ik deze exception:

code:
1
2
3
4
ComputePi exception: RemoteException occurred in server thread; nested exception
 is:
        java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
        java.lang.ClassNotFoundException: client.Pi


Waaruit ik denk af te leiden dat de RMI server nu de klasse Pi niet vindt.
Volgens mij download de RMI server deze klasse normaal uit de client codebase.
Daarom denk ik dat de codebase van de client zeker naar http://localhost/client_classes zou moeten wijzen.
Zo staat het trouwens ook in de RMI tutorial: de codebase is de plaats waar de klassen staan die de andere kant nodig kan hebben...
Verwijderd schreef op 07 april 2004 @ 15:28:
hihihi, hier heb ik ook een tijd mee zitten klooien. Probeer je client eens op te starten zonder de codebase parameter. Good luck ;) Zou moeten werken
Nee werkt niet :s .

Ik merk trouwens wel dat veel mensen een RMI voorbeeld draaiende krijgen,
maar er niet bij stilstaan dat de gebruikte klassen gewoon langs beide kanten in de classpath aanwezig zijn... Tja dan heeft RMI ook niet veel nut hé...
(gaat niet over jou hoor nochoice :))

[ Voor 18% gewijzigd door DieterVDW op 07-04-2004 18:38 ]


  • Robtimus
  • Registratie: November 2002
  • Laatst online: 26-05 15:28

Robtimus

me Robtimus no like you

http://java.sun.com/docs/books/tutorial/rmi/index.html al doorgelezen?

Ik weet het anders ook niet meer.

More than meets the eye
There is no I in TEAM... but there is ME
system specs


Verwijderd

Laat ik het zo zeggen, dat Compute en Engine gedoe heb ik idd ook aan de praat gekregen maar dan door de classes overal te verspreiden. Als ik jou was zou ik niet al te veel tijd besteden aan het voorbeeldje maar gewoon zelf iets (simpels) bouwen. Ik weet nog van mezelf dat heb bij mij niet geheel klopte :9

En dat van de codebase property. De client hoeft naar mijn weten nooit een codebase property te krijgen! De client haalt uit een RMIRegistry een RemoteStub object waar (door de server) de codebase-property in staat gesteld. De client gaat vervolgens zelf de code downloaden (als t nodig is) en uitvoeren.

Maar goed zoals ik al zei: Probeer eerst eens iets simpels (Hello world >:) ) aan de praat te krijgen, geloof me als je RMI gaat gebruiken ga je nogwel vaker tegen deze steen aanstoten (en andere...)

  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
Zie startpost.
Verwijderd schreef op 07 april 2004 @ 20:22:
Laat ik het zo zeggen, dat Compute en Engine gedoe heb ik idd ook aan de praat gekregen maar dan door de classes overal te verspreiden. Als ik jou was zou ik niet al te veel tijd besteden aan het voorbeeldje maar gewoon zelf iets (simpels) bouwen. Ik weet nog van mezelf dat heb bij mij niet geheel klopte :9

En dat van de codebase property. De client hoeft naar mijn weten nooit een codebase property te krijgen! De client haalt uit een RMIRegistry een RemoteStub object waar (door de server) de codebase-property in staat gesteld. De client gaat vervolgens zelf de code downloaden (als t nodig is) en uitvoeren.

Maar goed zoals ik al zei: Probeer eerst eens iets simpels (Hello world >:) ) aan de praat te krijgen, geloof me als je RMI gaat gebruiken ga je nogwel vaker tegen deze steen aanstoten (en andere...)
Ja 'k ga in ieder geval es proberen zo'n Hello world dingetje te doen :)

Bij het voorbeeld uit de Java RMI Tutorial moet de client de stub van het server object afhalen zodat de client kan communiceren met het remote object (via de stub dus), maar bij het uitvoeren van die Task heeft de server de Pi klasse nodig
(en die heeft hij niet), dus moet de server die downloaden van bij de client.
Vandaar dat de client bij dit voorbeeld wel een codebase nodig heeft hoor.
Bij Hello World daarentegen zou dat niet nodig mogen zijn...

Ik zal laten weten wat ik ontdek!

[ Voor 77% gewijzigd door DieterVDW op 07-04-2004 23:47 ]


  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
Ok ik heb het gevonden!

Het probleem was dat ik om de RMI server te starten de volgende commando's uitvoerde:

code:
1
2
3
4
5
6
set CLASSPATH=
start rmiregistry
java -classpath .;classes\compute.jar
      -Djava.rmi.server.codebase=http://localhost/server_classes/
      -Djava.security.policy=java.policy engine.ComputeEngine
            //localhost/Compute


Ik deed "set CLASSPATH=" omdat de stub files niet in het classpath van rmiregistry
aanwezig mogen zijn (expliciete voorwaarde, staat ook in java tutorial).
Waar ik echter niet op gerekend had is dat bij het starten van rmiregistry de lokale directory automatisch bij het classpath wordt toegevoegd...
Daarom vond rmiregistry de stub files toch in z'n classpath, en dat zorgt er
(om de een of andere duistere reden) voor dat die stub files dan niet meer aan de client doorgegeven worden... :s

Deze komt in m'n top 10 van lastigste problemen ooit hoor...

  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
Ik probeer het voorbeeld uit de RMI Trail van de Java Tutorial te laten werken.
(Zie ook dit topic)
Dit lukt nu als client en server op dezelfde computer draaien, maar dit
is natuurlijk nogal nutteloos...
En dus wil ik het voorbeeld nu ook laten werken in het geval waarbij client en server op verschillende machines draaien.
Ik wil de RMI server laten draaien op een linux machine.
Op een windows machine werkt dit perfect, maar als ik exact hetzelfde doe
op de linux computer dan krijg ik de volgende output:

code:
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
Exception in thread "Thread-8" java.lang.ClassFormatError: engine.ComputeEngine_Stub (bad magic number)
   at 0x40268e17: java.lang.Throwable.Throwable(java.lang.String) (/usr/lib/./libgcj.so.3)
   at 0x4025bc8e: java.lang.Error.Error(java.lang.String) (/usr/lib/./libgcj.so.3)
   at 0x4025d6b6: java.lang.LinkageError.LinkageError(java.lang.String) (/usr/lib/./libgcj.so.3)
   at 0x4025a742: java.lang.ClassFormatError.ClassFormatError(java.lang.String) (/usr/lib/./libgcj.so.3)
   at 0x4022d605: ?? (??:0)
   at 0x4022d506: ?? (??:0)
   at 0x4022aa3b: _Jv_ClassReader.parse() (/usr/lib/./libgcj.so.3)
   at 0x4022a97f: _Jv_DefineClass(java.lang.Class, byte[], int, int) (/usr/lib/./libgcj.so.3)
   at 0x40247e6f: java.lang.ClassLoader.defineClass0(java.lang.String, byte[], int, int, java.security.ProtectionDomain) (/usr/lib/./libgcj.so.3)
   at 0x4025aaa3: java.lang.ClassLoader.defineClass(java.lang.String, byte[], int, int, java.security.ProtectionDomain) (/usr/lib/./libgcj.so.3)
   at 0x4025aa13: java.lang.ClassLoader.defineClass(java.lang.String, byte[], int, int) (/usr/lib/./libgcj.so.3)
   at 0x40316d73: java.rmi.server.RMIClassLoader$MyClassLoader.defineClass(java.lang.String, byte[]) (/usr/lib/./libgcj.so.3)
   at 0x40316ec6: java.rmi.server.RMIClassLoader.loadClass(java.net.URL, java.lang.String) (/usr/lib/./libgcj.so.3)
   at 0x40320d0d: gnu.java.rmi.server.RMIObjectInputStream.resolveClass(java.io.ObjectStreamClass) (/usr/lib/./libgcj.so.3)
   at 0x402721c2: java.io.ObjectInputStream.readObject() (/usr/lib/./libgcj.so.3)
   at 0x40272278: java.io.ObjectInputStream.readObject() (/usr/lib/./libgcj.so.3)
   at 0x40319b1b: gnu.java.rmi.registry.RegistryImpl_Skel.dispatch(java.rmi.Remote, java.rmi.server.RemoteCall, int, long) (/usr/lib/./libgcj.so.3)
   at 0x4032372e: gnu.java.rmi.server.UnicastServerRef.incomingMessageCall(gnu.java.rmi.server.UnicastConnection, int, long) (/usr/lib/./libgcj.so.3)
   at 0x403230ed: gnu.java.rmi.server.UnicastServer.incomingMessageCall(gnu.java.rmi.server.UnicastConnection) (/usr/lib/./libgcj.so.3)
   at 0x4032302b: gnu.java.rmi.server.UnicastServer.dispatch(gnu.java.rmi.server.UnicastConnection) (/usr/lib/./libgcj.so.3)
   at 0x4032122d: gnu.java.rmi.server.UnicastConnection.run() (/usr/lib/./libgcj.so.3)
   at 0x40266e8a: java.lang.Thread.run() (/usr/lib/./libgcj.so.3)
   at 0x4024fc4c: _Jv_ThreadRun(java.lang.Thread) (/usr/lib/./libgcj.so.3)
   at 0x40371fa0: ?? (??:0)
   at 0x40379b35: GC_start_routine (/usr/lib/./libgcj.so.3)
   at 0x406139b1: ?? (??:0)
   at 0x40758ed7: __clone (/lib/i686/libc.so.6)


Java klaagt dus dat de 'magic numbers' van de stub bestanden niet ok zijn,
maar deze bestanden zijn exact hetzelfde als op de windows computer,
en daar werkt het wel!
Ik heb ook al geprobeerd om alles es opnieuw te compileren op de linux machine
en de stubs ook opnieuw aan te maken, maar dit helpt niet.
Ik heb mijn Java runtime ook al geupgraded -> no joy.

Iemand enig idee waar ik het probleem moet zoeken?

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

DieterVDW schreef op 08 april 2004 @ 23:27:
Ik probeer het voorbeeld uit de RMI Trail van de Java Tutorial te laten werken.
(Zie ook dit topic)
Ga daar dan verder.... :z

Professionele website nodig?


Verwijderd

/edit nr2.

Ik heb ff gegoogled enzo en ik kom overal tegen dat het te maken heeft met class-files die niet overeen komen. Misschien is er iets fout gegaan bij het kopieren naar de Linux machine (of andersom)?

[ Voor 188% gewijzigd door Verwijderd op 09-04-2004 00:02 ]


  • DieterVDW
  • Registratie: Juli 2002
  • Laatst online: 12-02-2017
Verwijderd schreef op 08 april 2004 @ 23:47:
Ik heb ff gegoogled enzo en ik kom overal tegen dat het te maken heeft met class-files die niet overeen komen. Misschien is er iets fout gegaan bij het kopieren naar de Linux machine (of andersom)?
Ik heb alles al es opnieuw gecompileerd, dus daaraan zou het niet mogen liggen...
Tijd om de java fora es wat verder te doorspitten, I'll keep ya informed...
Pagina: 1