Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
ich habe eine kleine rmi-application programmiert und möchte, wenn irgendwie möglich, die gemeinsamen klassen im paket model nicht auf beiden seiten (server- und clientseite) extra ablegen bzw. verwalten. ich hätte sowohl einen ftp- als auch einen web-server zum ablegen von gemeinsamen klassen. meine frage ist: ist das überhaupt möglich? und wenn ja, könnte ich auch mit file-protokol soche dateien downloaden (achtung: server und client laufen auf unterschiedlichen systemen).
ich benuzte tomcat , port 8080 und habe im verzeichnis webapps/root/ das verzeichnis export/classes angelegt, in dem das paket model mit den zugehörigen klassen abgelegt wurde. tomcat läuft und es kann wohl nicht schief gehen ...
auf der serverseite habe ich folgende policy.txt angelegt:
und server wird wie folgt gestartet (datei run_server.bat):
Code:
@echo off
REM CLASSPATH setzen
set CLASSPATH=.;lib\log4j.jar;lib\postgresql-8.0-313.jdbc3.jar
REM Server starten
java -Djava.rmi.server.codebase=http://localhost:8080/export/classes/ -Djava.security.policy=policy.txt server.Server
pause
auf der clientseite habe ich das paket model entfernt (ansonsten funktioniert es einwandfrei).
- ich starte rmiregistry: start rmiregistry
- ich starte server: run_server.bat
alles im butter. server läuft auf der ip-adresse 137.181.183.110
ich starte client:
Code:
java client.Client 137.181.183.110
nun bekomme ich meldung, dass die klasse aus dem paket model nicht gefunden wird.
ja, auch diesen abschnitt habe ich gelesen. aber wenn du schon so fragst, denke ich, dass in diesem abschnitt etwas steht, was ich übersehen habe. stimmt das?
ich habe mittlerweile weiter probiert und habe noch logging von rmiregistry eingeschaltet. nun, habe ich immer am ende eine kommische meldung:
Code:
FEINER: RMI RenewClean-[137.181.183.110:1135]: class "java.rmi.server.UID" found
via codebase, defined by null
ich gebe hier noch die logg-messages an. vielleicht sieht man da etwas, was ich nicht gesehen habe.
Code:
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEIN: RMI RenewClean-[137.181.183.110:1135]: name = "java.rmi.dgc.Lease", codebas
e = "http://localhost:8080/export/classes/"
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEINER: RMI RenewClean-[137.181.183.110:1135]: (thread context class loader: sun.
misc.Launcher$AppClassLoader@133056f)
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEINER: RMI RenewClean-[137.181.183.110:1135]: class "java.rmi.dgc.Lease" found v
ia codebase, defined by null
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEIN: RMI RenewClean-[137.181.183.110:1135]: name = "java.rmi.dgc.VMID", codebase
= "http://localhost:8080/export/classes/"
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEINER: RMI RenewClean-[137.181.183.110:1135]: (thread context class loader: sun.
misc.Launcher$AppClassLoader@133056f)
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEINER: RMI RenewClean-[137.181.183.110:1135]: class "java.rmi.dgc.VMID" found vi
a codebase, defined by null
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEIN: RMI RenewClean-[137.181.183.110:1135]: name = "[B", codebase = ""
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEINER: RMI RenewClean-[137.181.183.110:1135]: (thread context class loader: sun.
misc.Launcher$AppClassLoader@133056f)
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEINER: RMI RenewClean-[137.181.183.110:1135]: class "[B" found via codebase, def
ined by null
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEIN: RMI RenewClean-[137.181.183.110:1135]: name = "java.rmi.server.UID", codeba
se = "http://localhost:8080/export/classes/"
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEINER: RMI RenewClean-[137.181.183.110:1135]: (thread context class loader: sun.
misc.Launcher$AppClassLoader@133056f)
02.02.2006 12:23:32 sun.rmi.server.LoaderHandler loadClass
FEINER: RMI RenewClean-[137.181.183.110:1135]: class "java.rmi.server.UID" found
was bedeutet das: found via codebase, defined by null
nun, jetzt habe ich es probiert, funktioniert aber nicht.
ich habe jetzt aber eine einfache, grundsätzlihce frage: wie funktioniert dynamisches downloaden von klassen in java?
dazu habe ich folgendes beispiel erstellt: klasse demo.Punkt und klasse Main.
klasse demo.Punkt:
Code:
package demo;
public class Punkt
{
private int x;
private int y;
public Punkt(int x, int y)
{
this.x = x;
this.y = y;
}
// set und get methoden ...
public String toString()
{
return "x = " + x + ", y = " + y;
}
}
klasse Main:
Code:
import java.rmi.RMISecurityManager;
import demo.Punkt;
public class Main
{
public static void main(String[] args)
{
if (System.getSecurityManager() == null)
{
System.setSecurityManager(new RMISecurityManager());
}
Punkt p = new Punkt(10, 20);
System.out.println(p);
}
}
habe die klasse demo.Punkt (bzw. das verzeichnis demo) auf dem webserver <ROOT>/export/classes/ abgelegt, policy-datei auf der clientseite definiert und probiert, die klasse Main auszuführen:
Code:
java -Djava.rmi.codebase=http://server:8080/export/classes/ -Djava.security.policy=policy.txt Main
meldung:
Code:
Exception in thread "main" java.lang.NoClassDefFoundError: demo/Punkt
der nächste versuch: paket bzw. verzeichnis demo local im verzeichnis c:\temp abgelegt und den aufruf wie folgt gemacht:
Code:
java -Djava.rmi.codebase=file:/C:\Temp\ -Djava.security.policy=policy.txt Main
und die gleiche fehlermeldung.
nun, wie macht man das? wenn ich mit diesem einfachen beispiel das nicht fertig bringe, dann habe ich wohl ein verständnisproblem, oder was? muss ich da noch mit klassenloader spielen bzw. etwas überschreiben? denn, ich habe gelesen, dass codebase eigentlich nichts anderes als ein "globaler" CLASSPATH ist? wie bringe ich den klassenloader so weit, dass er im codebase sucht?
das artikel ist zwar relativ alt, sollte aber immer noch grösstenteils "giltig" sein. leider, ist meine hoffunung, schlauer zu werden, nicht in erfüllung gegangen. meine frage bleibt weiter: wozu dient codebase???
ich habe mit einem einfachen beispiel (unabhängig von RMI) herausfinden probiert, wie das dynamische laden von klassen funktioniert. dazu habe ich folgende klassen definiert:
Code:
package hsw.fhw.calc;
public abstract class Calculator
{
public abstract double add(double a, double b);
public abstract double sub(double a, double b);
public abstract double mul(double a, double b);
public abstract double div(double a, double b);
public abstract double getMax(double ... array);
public abstract double getMin(double ... array);
}
Code:
package hsw.fhw.calc.model;
import java.util.Arrays;
import hsw.fhw.calc.Calculator;
public class CalculatorImpl extends Calculator
{
@Override
public double add(double a, double b)
{
Printer.print("Addition von " + a + " und " + b + ":");
return a + b;
}
@Override
public double sub(double a, double b)
{
Printer.print("Subtrachtion von " + a + " und " + b + ":");
return a-b;
}
@Override
public double mul(double a, double b)
{
Printer.print("Multiplikation von " + a + " und " + b + ":");
return a*b;
}
@Override
public double div(double a, double b)
{
Printer.print("Division von " + a + " und " + b + ":");
return a/b;
}
@Override
public double getMax(double... array)
{
Printer.print("Maximum:");
Arrays.sort(array);
return array[array.length-1];
}
@Override
public double getMin(double... array)
{
Printer.print("Minimum:");
Arrays.sort(array);
return array[0];
}
}
Code:
package hsw.fhw.calc.model;
public class Printer
{
public static void print(String msg)
{
System.out.println(msg);
}
}
auf der client-seite befindet sich nur die klasse Main und das interface Calculator. das paket model (mit CalculatorImpl und Printer) befindet sich auf dem web-server im verzeichnis <root>/export/classes. das ganze programm wird wei folgt gestartet:
Code:
java hsw.fhw.calc.test.Main
und, die ausführung funktioniert. dadurch, dass ich das interface Calculator auf der client-seite habe, kann ich das casten von Object in Calculator realisieren und damit alle methoden direkt (ohne reflection-gebrauch) einsetzten.
so weit, so gut. aber, zurück zu codebase. ich gehe davon aus, dass man codebase auch gebrauchen kann. nun wie?
ich habe jetzt die klasse Printer in das verzeichnis <root>/public auf dem web-server verschoben, mit dem ziel, diese lokation mit codebase anzugeben. der aufruf sah wie folgt aus:
ergebnis: klasse Printer kann nicht gefunden werden.
schlussfolgerung: mein versuch ist gescheitert!!!
im nächsten schritt habe ich die lokation der klasse Printer im code direkt angegeben:
Code:
URL[] urls = { new URL("http://192.168.1.33:8080/export/classes/"), new URL("http://192.168.1.33:8080/public/") };
URLClassLoader loader = new URLClassLoader(urls);
das programm wird wie folgt aufgerufen:
Code:
java hsw.fhw.calc.test.Main
ergebnis: es funktioniert.
obwohl ich klasse Printer nicht explizit lade, wird das laden dynamisch realisiert, sobald die klasse benötigt wird.
auf meine frage, wozu codebase dient, habe ich keine antwort gefunden. kann mir jemand aus meinem albtraum helfen?
Müsste eigentlich funktionieren. Mit codebase sollte, nach meinem bescheidenen Wissen, der URLClassLoader automatisch erzeugt und zum Laden von Klassen von der angegebenen URL eingesetzt werden. So etwa wie mit SecurityManger, der von der Commandozeile erzeugt wird, wobei ihm die Policy-Datei mitgegeben wird.