Sie sind auf Seite 1von 12

124639,122514,121068,124680,120703 ----------------------------------01. 02.

2006, 17:56 rmi und download von klassen ----------------------------------hallo ich habe eine kleine rmi-application programmiert und mchte, wenn irgendwie mglich , die gemeinsamen klassen im paket model nicht auf beiden seiten (server- und cl ientseite) extra ablegen bzw. verwalten. ich htte sowohl einen ftp- als auch eine n web-server zum ablegen von gemeinsamen klassen. meine frage ist: ist das berhau pt mglich? und wenn ja, knnte ich auch mit file-protokol soche dateien downloaden (achtung: server und client laufen auf unterschiedlichen systemen). danke ----------------------------------Bleiglanz 01. 02. 2006, 18:07 ----------------------------------ftp wohl nicht, http funktioniert aber => Codebase http://java.sun.com/j2se/1.4.2/docs/guide/rmi/codebase.html ----------------------------------01. 02. 2006, 18:40 ----------------------------------ftp wohl nicht, http funktioniert aber => Codebase http://java.sun.com/j2se/1.4.2/docs/guide/rmi/codebase.html vielen dank. ich habe diesen artikel schon gelesen, bin aber nicht schlauer gewo rden. ausserdem habe ich auch dies hier gelesen: http://labs.cs.utt.ro/doc/java_tutor/rmi/running.html ich benuzte tomcat , port 8080 und habe im verzeichnis webapps/root/ das verzei chnis export/classes angelegt, in dem das paket model mit den zugehrigen klassen abgelegt wurde. tomcat luft und es kann wohl nicht schief gehen ... auf der serverseite habe ich folgende policy.txt angelegt: grant { permission java.net.SocketPermission "*:1024-65535", "connect,accept";

permission java.net.SocketPermission "*:8080", "connect"; }; und server wird wie folgt gestartet (datei run_server.bat): @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.sec urity.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 luft auf der ip-adresse 137.181.183.110 ich starte client: java client.Client 137.181.183.110 nun bekomme ich meldung, dass die klasse aus dem paket model nicht gefunden wird . was mach ich falsch? ----------------------------------Bleiglanz 02. 02. 2006, 11:34 ----------------------------------vielen dank. ich habe diesen artikel schon gelesen, bin aber nicht schlauer gewo rden. ausserdem habe ich auch dies hier gelesen: http://labs.cs.utt.ro/doc/java_tutor/rmi/running.html Wirklich auch den Abschnitt "Starting the Client"? ----------------------------------02. 02. 2006, 12:37 ----------------------------------Wirklich auch den Abschnitt "Starting the Client"? 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 eing eschaltet. nun, habe ich immer am ende eine kommische meldung: FEINER: RMI RenewClean-[137.181.183.110:1135]: class "java.rmi.server.UI D" found via codebase, defined by null ich gebe hier noch die logg-messages an. vielleicht sieht man da etwas, was ich nicht gesehen habe. 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 loa der: 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 loa der: 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 loa der: 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 loa der: 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.UI D" found was bedeutet das: found via codebase, defined by null ----------------------------------Bleiglanz 02. 02. 2006, 12:48 ----------------------------------hast du schon mal versucht, auch dem Client die codebase mitzuteilen (-D) ----------------------------------02. 02. 2006, 20:26 ----------------------------------nein, habe ich nicht. und, was soll ich im sagen? das gleiche (bzw. fast das gle iche) wie dem server: -Djava.rmi.server.codebase=http://137.181.183.110:8080/export/classes/ du meinst, der klassenlader sollte dann selbst nach den klassen suchen gehen? vilen dank fr den tipp. ich werde es morgen probieren. ----------------------------------03. 02. 2006, 14:18 ----------------------------------nun, jetzt habe ich es probiert, funktioniert aber nicht. ich habe jetzt aber eine einfache, grundstzlihce frage: wie funktioniert dynamisc hes downloaden von klassen in java? dazu habe ich folgendes beispiel erstellt: klasse demo.Punkt und klasse Main. klasse demo.Punkt: package demo;

public class Punkt &#123; private int x; private int y; public Punkt(int x, int y) &#123; this.x = x; this.y = y; &#125; // set und get methoden ... public String toString() &#123; return "x = " + x + ", y = " + y; &#125; &#125; klasse Main: import java.rmi.RMISecurityManager; import demo.Punkt; public class Main &#123; public static void main(String&#91;&#93; args) &#123; if (System.getSecurityManager() == null) &#123; System.setSecurityManager(new RMISecurityManager()); &#125; Punkt p = new Punkt(10, 20); System.out.println(p); &#125; &#125; habe die klasse demo.Punkt (bzw. das verzeichnis demo) auf dem webserver <ROOT>/ export/classes/ abgelegt, policy-datei auf der clientseite definiert und probier t, die klasse Main auszufhren:

java -Djava.rmi.codebase=http://server:8080/export/classes/ -Djava.security.poli cy=policy.txt Main meldung: Exception in thread "main" java.lang.NoClassDefFoundError: demo/Punkt der nchste versuch: paket bzw. verzeichnis demo local im verzeichnis c:\temp abge legt und den aufruf wie folgt gemacht: 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 verstndnisproblem, oder was? muss ich da noch mit klassenloader spielen bzw. etwas berschreiben? denn, ich habe gelesen, dass codeb ase eigentlich nichts anderes als ein "globaler" CLASSPATH ist? wie bringe ich d en klassenloader so weit, dass er im codebase sucht? danke fr jeden tipp. ----------------------------------03. 02. 2006, 14:30 ergnzung ----------------------------------:D meine natrlich -Djava.rmi.server.codebase ... ----------------------------------halber 05. 02. 2006, 21:25 ----------------------------------Schau mal hier: [url=http://www.bs.informatik.uni-siegen.de/www/lehre/ws0506/csp/index_html]Clie nt/Server-Programmierung vielleicht hilft dir davon was. ----------------------------------07. 02. 2006, 0:14 download von klassen ----------------------------------nun habe ich endlich die Klasse demo.Punkt von meinem Web-Server downloaden knnen : public class Main &#123; public static void main(String&#91;&#93; args) &#123; try &#123; URL url = new URL("http://192.168.1.33:8080/export/classes/"); URL&#91;&#93; urls = &#123; url &#125;; URLClassLoader loader = new URLClassLoader(urls); // Klasse 'demo.Punkt' wird geladen Class<?> cls = Class.forName("demo.Punkt", true, loader); if (cls != null) &#123; // Argumentenliste (int, int) Class&#91;&#93; argClass = new Class&#91;&#93; &#123; int.class, int.class &#125;; // Konstruktor erzeugen

Constructor<?> c = cls.getConstructor(argClass); // Eine Instanz erzeugen Object obj = c.newInstance(12, 18); // Ausgabe (toString der Klasse 'demo.Punkt') System.out.println(obj); // Methoden 'setX' und 'setY' holen Method setX = cls.getMethod("setX", int.class); Method setY = cls.getMethod("setY", int.class); // Falls vorhanden, aufrufen if (setX != null && setY != null) &#123; setX.invoke(obj, 52); setY.invoke(obj, 62); &#125; // Ausgabe (toString der Klasse 'demo.Punkt') System.out.println(obj); &#125; &#125; catch (Exception e1) &#123; e1.printStackTrace(); &#125; &#125; &#125; macht man das etwa so? oder, kann man einfacher / eleganter / besser machen? ----------------------------------08. 02. 2006, 21:44 codebase und dynamisches downloaden von klassen ----------------------------------habe ein interessantes artikel zum dynamischen downloaden von klassen gefunden: http://www.eli.sdsu.edu/courses/spring99/cs696/notes/ddc/ddc.html das artikel ist zwar relativ alt, sollte aber immer noch grsstenteils "giltig" se in. leider, ist meine hoffunung, schlauer zu werden, nicht in erfllung gegangen. meine frage bleibt weiter: wozu dient codebase??? ich habe mit einem einfachen beispiel (unabhngig von RMI) herausfinden probiert, wie das dynamische laden von klassen funktioniert. dazu habe ich folgende klasse n definiert: package hsw.fhw.calc; public abstract class Calculator &#123; public abstract double add(double a, public abstract double sub(double a, public abstract double mul(double a, public abstract double div(double a, public abstract double getMax(double public abstract double getMin(double &#125;

double b); double b); double b); double b); ... array); ... array);

package hsw.fhw.calc.model; import java.util.Arrays; import hsw.fhw.calc.Calculator; public class CalculatorImpl extends Calculator &#123; @Override public double add(double a, double b) &#123; Printer.print("Addition von " + a + " und " + b + ":"); return a + b; &#125; @Override public double sub(double a, double b) &#123; Printer.print("Subtrachtion von " + a + " und " + b + ":"); return a-b; &#125; @Override public double mul(double a, double b) &#123; Printer.print("Multiplikation von " + a + " und " + b + ":"); return a*b; &#125; @Override public double div(double a, double b) &#123; Printer.print("Division von " + a + " und " + b + ":"); return a/b; &#125; @Override public double getMax(double... array) &#123; Printer.print("Maximum:"); Arrays.sort(array); return array&#91;array.length-1&#93;; &#125; @Override public double getMin(double... array) &#123; Printer.print("Minimum:"); Arrays.sort(array); return array&#91;0&#93;; &#125; &#125; package hsw.fhw.calc.model; public class Printer &#123;

public static void print(String msg) &#123; System.out.println(msg); &#125; &#125; package hsw.fhw.calc.test; import hsw.fhw.calc.Calculator; import java.net.URL; import java.net.URLClassLoader; public class Main &#123; public static void main(String&#91;&#93; args) &#123; try &#123; URL url = new URL("http://192.168.1.33:8080/export/classes/"); URL&#91;&#93; urls = &#123; url &#125;; URLClassLoader loader = new URLClassLoader(urls); // Klasse 'hsw.fhw.calc.model.CalculatorImpl' wird geladen Class<?> cls = Class.forName("hsw.fhw.calc.model.CalculatorImpl", tr ue, loader); if (cls != null) &#123; Calculator calc = (Calculator)cls.newInstance(); double a = 2.5; double b = 2; double double double double summe = calc.add(a, b); differenz = calc.sub(a, b); produkt = calc.mul(a, b); quotient = calc.div(a, b); " " " " + + + + summe); differenz); produkt); quotient);

System.out.println("Summe: System.out.println("Differnz: System.out.println("Produkt: System.out.println("Quotient: &#125; &#125; catch(Exception e) &#123; e.printStackTrace(); &#125; &#125; &#125;

auf der client-seite befindet sich nur die klasse Main und das interface Calcula tor. 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:

java hsw.fhw.calc.test.Main und, die ausfhrung funktioniert. dadurch, dass ich das interface Calculator auf d er client-seite habe, kann ich das casten von Object in Calculator realisieren u nd damit alle methoden direkt (ohne reflection-gebrauch) einsetzten. so weit, so gut. aber, zurck zu codebase. ich gehe davon aus, dass man codebase a uch gebrauchen kann. nun wie? ich habe jetzt die klasse Printer in das verzeichnis <root>/public auf dem web-s erver verschoben, mit dem ziel, diese lokation mit codebase anzugeben. der aufru f sah wie folgt aus: java -Djava.rmi.server.codebase=http://192.168.1.33:8080/public/ hsw.fhz.calc.te st.Main ergebnis: klasse Printer kann nicht gefunden werden. der nchste versuch: ich benutze noch useCodebaseOnly=true java -Djava.rmi.server.useCodebaseOnly=true -Djava.rmi.server.codebase=http://19 2.168.1.33:8080/public/ hsw.fhz.calc.test.Main ergebnis: klasse Printer kann nicht gefunden werden. schlussfolgerung: mein versuch ist gescheitert!!! im nchsten schritt habe ich die lokation der klasse Printer im code direkt angege ben: URL&#91;&#93; urls = &#123; new URL("http://192.168.1.33:8080/export/classes/"), new URL("http://192.168.1.33:8080/public/") &#125;; URLClassLoader loader = new URLClassLoader(urls); das programm wird wie folgt aufgerufen: java hsw.fhw.calc.test.Main ergebnis: es funktioniert. obwohl ich klasse Printer nicht explizit lade, wird das laden dynamisch realisie rt, sobald die klasse bentigt wird. auf meine frage, wozu codebase dient, habe ich keine antwort gefunden. kann mir jemand aus meinem albtraum helfen? ----------------------------------12. 02. 2006, 23:36 ----------------------------------Msste eigentlich funktionieren. Mit codebase sollte, nach meinem bescheidenen Wi ssen, der URLClassLoader automatisch erzeugt und zum Laden von Klassen von der a ngegebenen URL eingesetzt werden. So etwa wie mit SecurityManger, der von der Co mmandozeile erzeugt wird, wobei ihm die Policy-Datei mitgegeben wird. import java.util.*;

import import import import

java.io.*; org.jdom.*; org.jdom.input.*; org.jdom.output.*;

public class ExampleJdomAddWrite { public static void main( String[] args ) { if( args.length != 6 ) { System.err.println( "Attention:" ); System.err.println( "jdom.jar must be added to classpath." ); System.err.println( "Usage:" ); System.err.println( "java ExampleJdomAddWrite <XmlFile> <NewFi le>" + " <MainElem> <Child> <FindVal> <New>" ); System.err.println( "Example:" ); System.err.println( "java -classpath .;jdom.jar ExampleJdomAdd Write" + " MyXmlFile.xml NewXmlFile.xml Button Title" + " \"Mein dritter Button\" \"Mein neuer Button\"" ); System.exit( 1 ); } try { // ---- Read XML file ---SAXBuilder builder = new SAXBuilder(); Document doc = builder.build( new File( args[0] ) ); // ---- Modify XML data ---Element root = doc.getRootElement(); List listMainElements = root.getChildren( args[2] ); // <Main Elem> for( int i=0; i<listMainElements.size(); i++ ) { // Find searched element with given text: Element elMain = (Element)(listMainElements.get( i )); if( null == elMain ) continue; Element elChild = elMain.getChild( args[3] ); // <Chil d> if( null == elChild ) continue; String s = elChild.getTextTrim(); if( null == s || !s.equals( args[4] ) ) continue; // <Find Val> // Add new element at correct positeon: Element elNew = new Element( args[2] ); Elem> elNew.addContent( (new Element( args[3] )).addContent( args[ 5] ) ); listMainElements.add( i, elNew ); // <New> // ---- Write XML file ---XMLOutputter outp = new XMLOutputter(); outp.setIndent( " " ); outp.setNewlines( true ); outp.output( doc, new FileOutputStream( new File( args[1] ) ) ); break; ile> // <NewF // <Main

} } catch( Exception ex ) { ex.printStackTrace(); } } }