1. Dashboard
  2. Forum
    1. Unerledigte Themen
  3. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team-Mitglieder
    4. Trophäen
    5. Mitgliedersuche
  4. Tutorial Bereich
  • Anmelden
  • Registrieren
  • Suche
Dieses Thema
  • Alles
  • Dieses Thema
  • Dieses Forum
  • Seiten
  • Forum
  • Lexikon
  • Erweiterte Suche
  1. Informatik Forum
  2. Webmaster & Internet
  3. Entwicklung

Java Plugin-System mit jar-Dateien

  • Stephe
  • 5. Juli 2008 um 01:27
  • Unerledigt
  • Stephe
    24
    Stephe
    Mitglied
    Reaktionen
    43
    Punkte
    6.038
    Beiträge
    968
    • 5. Juli 2008 um 01:27
    • #1

    Gute Nacht :)

    Ich hab da eine Java-Anwendung die man per Plugins (JAR-Files, wo alles drin is was vom Plugin gebraucht wird) erweitern kann. Dh. die Applikation soll beim Starten den Ordner "plugins" scannen und man kann dann Plugins auswählen, deren Hauptklassen ein gemeinsames Interface implementieren. Hab im Internet nur prinzipielle Ansätze für Plugins gefunden, aber nix mit JAR-Dateien.

  • laborg
    14
    laborg
    Mitglied
    Reaktionen
    11
    Punkte
    1.966
    Beiträge
    360
    • 5. Juli 2008 um 07:37
    • #2

    :shinner:

  • Paulchen
    1
    Paulchen
    Gast
    • 5. Juli 2008 um 09:28
    • #3

    Was ist das Problem?

    In Aufgabe 2 von "Technologien für verteilte Systeme" war dieses Semester unter anderem "Dynamic Plugin Loading" zu implementieren. Da wurde ein bestimmtes Verzeichnis überwacht, ob Dateien hinzugekommen sind. Handelte es sich um eine .jar-Datei, wird diese analysiert:

    • JarFile hab ich eingesetzt, um eine Liste der im Archiv enthaltenen Dateien zu erhalten.
    • Der Name wird dann entsprechend angepasst ("." durch "/" ersetzt etc.); die Klasse mit diesem Namen wird dann mit einem URLClassLoader aus dem Archiv geladen.
    • Die Reflection API von Java bietet nun eine Reihe von Möglichkeiten, unter anderem, um herauszufinden, welche Interfaces eine bestimmte Klasse implementiert. Siehe Class. Wenn du irgendwelche Typhierarchien verwendest, musst du darauf achten, dass Class.getInterfaces() keine Interfaces zurückliefert, die von einem Obertyp implementiert werden.
  • a9bejo
    21
    a9bejo
    Mitglied
    Reaktionen
    42
    Punkte
    4.697
    Beiträge
    913
    • 5. Juli 2008 um 10:18
    • #4

    Der uebliche Weg, um alle Klassen, die ein bestimmtes Interface implementieren, aus dem Jar File zu laden ist dieses Service Provider Pattern. Das hab ich auch heuer in "Technologien für verteilte Systeme" gelernt.

    Uebrigens:
    Ein wenig bloed ist, das diese Service Klasse in dem sun.* namespace liegt und nicht in java.* oder org.*. D.h. eigentlich sollte man von sun.* packages die Finger lassen, weil die nicht Teil der JDK Spec sind.. Ich habe da aber auch Diskussionen zu gefunden, und die Klasse wird wohl demnachst in einen oeffentlichen Namespace wandern.

    lg, Benjamin Ferrari, bookworm.at

    2 Mal editiert, zuletzt von a9bejo (5. Juli 2008 um 10:21)

  • phudy
    10
    phudy
    Mitglied
    Reaktionen
    12
    Punkte
    1.087
    Beiträge
    182
    • 5. Juli 2008 um 10:30
    • #5

    hihi, das hat mich jetzt aber interessiert.
    hab mal schnell was zusammen gehackt:

    Code
    public class App {
    	public static void main(String[] args) throws Exception {
    		File pluginDir = new File("plugins");
    
    		System.out.println("loading plugins from: " + pluginDir.getAbsolutePath());
    		File[] jars = pluginDir.listFiles(new FileFilter() {
    			public boolean accept(File pathname) {
    				return pathname.getName().endsWith(".jar");
    			}
    		});
    		for (File f : jars) {
    			System.out.println("processing jar: " + f.getName());
    			final JarFile jar = new JarFile(f);
    
    			for (Enumeration<JarEntry> entries = jar.entries(); entries.hasMoreElements(); ) {
    				JarEntry entry = entries.nextElement();
    				String name = entry.getName();
    				if(name.endsWith(".class") == false) {
    					continue;
    				}
    				String className = name.replaceAll("/", ".");
    				className = className.substring(0, className.length() - ".class".length());
    
    				URLClassLoader loader = URLClassLoader.newInstance(new URL[] { f.toURL() });
    				ISub sub = (ISub) loader.loadClass(className).newInstance();
    				System.out.println("Sub says ----> " + sub.getMsg());
    			}
    		}
    	}
    }
    Alles anzeigen
  • phudy
    10
    phudy
    Mitglied
    Reaktionen
    12
    Punkte
    1.087
    Beiträge
    182
    • 5. Juli 2008 um 10:45
    • #6
    Zitat von a9bejo

    Der uebliche Weg, um alle Klassen, die ein bestimmtes Interface implementieren, aus dem Jar File zu laden ist dieses Service Provider Pattern. Das hab ich auch heuer in "Technologien für verteilte Systeme" gelernt.

    hm.... service provider? warum nicht eine einfache variante davon nachprogrammieren?! eine "service.properties" datei in das plugin jar file reinhaun mit inhalt:

    Code
    pkg.plugininterfaces.ISub = pkg.plugin1.Sub1

    dann geht auch das:

    Code
    public class App {
    	public static void main(String[] args) throws Exception {
    		File pluginDir = new File("plugins");
    
    		System.out.println("loading plugins from: " + pluginDir.getAbsolutePath());
    		File[] jars = pluginDir.listFiles(new FileFilter() {
    			public boolean accept(File pathname) {
    				return pathname.getName().endsWith(".jar");
    			}
    		});
    		for (File f : jars) {
    			System.out.println("processing jar: " + f.getName());
    
    			URLClassLoader loader = URLClassLoader.newInstance(new URL[] { f.toURL() });
    			ResourceBundle props = ResourceBundle.getBundle("service", Locale.getDefault(), loader);
    			final String isubClassName = props.getString("pkg.plugininterfaces.ISub");
    
    			ISub sub = (ISub) loader.loadClass(isubClassName).newInstance();
    			System.out.println("Sub says ----> " + sub.getMsg());
    		}
    	}
    }
    Alles anzeigen

    Einmal editiert, zuletzt von phudy (5. Juli 2008 um 10:48)

  • a9bejo
    21
    a9bejo
    Mitglied
    Reaktionen
    42
    Punkte
    4.697
    Beiträge
    913
    • 5. Juli 2008 um 10:56
    • #7
    Zitat von phudy

    hm.... service provider? warum nicht eine einfache variante davon nachprogrammieren?!

    Was hast du denn davon, wenn du etwas nachprogrammierst, das es bereits gibt? Die 0815 Loesung ist (halbwegs) dokumentiert, sie hat tool support (z.b. ant kann damit umgehen) und sie funktioniert.

    lg, Benjamin Ferrari, bookworm.at

  • phudy
    10
    phudy
    Mitglied
    Reaktionen
    12
    Punkte
    1.087
    Beiträge
    182
    • 6. Juli 2008 um 11:52
    • #8
    Zitat von a9bejo

    Was hast du denn davon, wenn du etwas nachprogrammierst, das es bereits gibt?

    es macht spaß :grinning_squinting_face:

    (mal vom lerneffekt abgesehen)


    [edit] oder man kann sich auch OSGi "antun"...

    Einmal editiert, zuletzt von phudy (6. Juli 2008 um 11:55)

  • a9bejo
    21
    a9bejo
    Mitglied
    Reaktionen
    42
    Punkte
    4.697
    Beiträge
    913
    • 6. Juli 2008 um 12:11
    • #9

    OK, das ist natuerlich ein guter Grund. Ich habe

    Zitat


    hm.... service provider? warum nicht eine einfache variante davon nachprogrammieren?!

    als einen Loesungsvorschlag fuer Stephes Problem gelesen, als bessere Variante gegenueber der fertigen Implementierung. Vielleicht wegen des entsetzten "?!" .

    lg, Benjamin Ferrari, bookworm.at

  • Stephe
    24
    Stephe
    Mitglied
    Reaktionen
    43
    Punkte
    6.038
    Beiträge
    968
    • 7. Juli 2008 um 10:30
    • #10

    @Paulchen: schön wenn es für dich kein Problem is, aber nicht alle machen diese Technologie-Vorlesung :winking_face:
    aber danke für alle Antworten, werd das mal so versuchen

  • phudy
    10
    phudy
    Mitglied
    Reaktionen
    12
    Punkte
    1.087
    Beiträge
    182
    • 7. Juli 2008 um 20:59
    • #11
    Zitat von a9bejo

    Vielleicht wegen des entsetzten "?!" .

    was ist an dem "?!" so entsetzend?!
    fuer mich ist das nur eine frage, die leicht etwas von einer aufforderung hat (in dem fall halt an mich selbst).

    Stephe: evtl kannst nachher ueber deine erfahrungen kurz berichten? wuerd mich naemlich auch interessen...

  • Stephe
    24
    Stephe
    Mitglied
    Reaktionen
    43
    Punkte
    6.038
    Beiträge
    968
    • 12. Dezember 2008 um 00:00
    • #12

    [mehr recherchieren, weniger fragen]

    Einmal editiert, zuletzt von Stephe (12. Dezember 2008 um 00:08)

  • sutupud
    13
    sutupud
    Mitglied
    Reaktionen
    59
    Punkte
    1.659
    Beiträge
    320
    • 12. Dezember 2008 um 00:15
    • #13

    das funktioniert nur, wenn das plugin-jar bereits beim start der vm als teil des classpath angegeben wird.
    diese art der einbindung von plugins ist aber nicht wirklich schön und funktioniert zu laufzeit überhaupt nicht. dafür braucht man einen URLClassLoader, wie oben schon beschrieben.

    "All through my life I've had this strange unaccountable feeling that something was going on in the world, something big, even sinister, and no one would tell me what it was."
    "No," said the old man, "that's just perfectly normal paranoia. Everyone in the Universe has that."

    &#128513;&#128514;&#128515;&#128516;&#128517;&#128518;&#128519;&#128520;&#128521;&#128522;&#128523;&#128524;&#128525;&#128526;&#128527;&#128528;&#128530;&#128531;&#128532;&#128534;&#128536;&#128538;&#128540;&#128542;&#128544;&#128545;&#128546;&#128547;&#128549;&#128552;&#128553;&#128554;&#128555;&#128557;&#128560;&#128561;&#128562;&#128563;&#128565;&#128566;&#128567;

  • Lord Binary
    18
    Lord Binary
    Mitglied
    Reaktionen
    11
    Punkte
    3.301
    Beiträge
    647
    • 12. Dezember 2008 um 00:37
    • #14

    hallo,

    zur realen anwendbarkeit fehlen jetzt eigentlich nur noch live-updatebarkeit
    und eine sinnvolle test-methodik :)

    mfg, lb


    Trading for a living [equities,futures,forex]

  • Stephe
    24
    Stephe
    Mitglied
    Reaktionen
    43
    Punkte
    6.038
    Beiträge
    968
    • 12. Dezember 2008 um 12:40
    • #15

    Keine Ahnung was jetzt schön ist und was nicht aber ich habs jetzt so gelöst und es funktioniert wunderbar mit Jar-Archiven:

    (jarfiles ist ein String-Array mit zB. "Plugin1.jar", "Plugin2.jar")

    Code
    URL urlList[] = {new File("plugins/"+jarfiles[i]).toURI().toURL()};
    classLoader = new URLClassLoader(urlList);
    Class pluginclass = classLoader.loadClass("main.Main");
    Object plugin = pluginclass.newInstance();
    Method method_render = pluginclass.getMethod("render", new Class[]{});
    
    
    method_render.invoke(plugin, new Object[]{});

    Im Endeffekt hab ich jetzt ein openGL-Canvas in meiner Swing-Applikation und kann jetzt mittels Buttons die Plugins auswählen, die dann jeweils was anderes in dieses Canvas rendern. :bounce:

    Einmal editiert, zuletzt von Stephe (12. Dezember 2008 um 12:45)

  • sutupud
    13
    sutupud
    Mitglied
    Reaktionen
    59
    Punkte
    1.659
    Beiträge
    320
    • 12. Dezember 2008 um 12:59
    • #16

    theoretisch könntest du alle deine plugins auch ein gemeinsames interface implementieren lassen, dann könntest du die klasse aufs interface casten und könntest die methoden direkt aufrufen...
    würd ich jedenfalls so machen, weil ich reflection vermeide wo es nur geht.

    "All through my life I've had this strange unaccountable feeling that something was going on in the world, something big, even sinister, and no one would tell me what it was."
    "No," said the old man, "that's just perfectly normal paranoia. Everyone in the Universe has that."

    &#128513;&#128514;&#128515;&#128516;&#128517;&#128518;&#128519;&#128520;&#128521;&#128522;&#128523;&#128524;&#128525;&#128526;&#128527;&#128528;&#128530;&#128531;&#128532;&#128534;&#128536;&#128538;&#128540;&#128542;&#128544;&#128545;&#128546;&#128547;&#128549;&#128552;&#128553;&#128554;&#128555;&#128557;&#128560;&#128561;&#128562;&#128563;&#128565;&#128566;&#128567;

  • Stephe
    24
    Stephe
    Mitglied
    Reaktionen
    43
    Punkte
    6.038
    Beiträge
    968
    • 12. Dezember 2008 um 14:57
    • #17

    Hatte ich auch vor, ist mittlerweile auch so implementiert.

    Einmal editiert, zuletzt von Stephe (12. Dezember 2008 um 15:26)

  • kubuntu
    6
    kubuntu
    Mitglied
    Reaktionen
    2
    Punkte
    352
    Beiträge
    65
    • 13. Dezember 2008 um 14:15
    • #18

    Wenn man ein existierendes Plugin Framework verwenden will und nicht unbedingt OSGI, dann kann ich nur http://jpf.sf.net/ empfehlen.


  • Stephe
    24
    Stephe
    Mitglied
    Reaktionen
    43
    Punkte
    6.038
    Beiträge
    968
    • 14. Dezember 2008 um 20:31
    • #19
    Zitat von kubuntu

    Wenn man ein existierendes Plugin Framework verwenden will und nicht unbedingt OSGI, dann kann ich nur http://jpf.sf.net/ empfehlen.

    Ich hatte auch schon überlegt das zu verwenden, aber irgendwie war mir das dann doch zu komplex.

  • phudy
    10
    phudy
    Mitglied
    Reaktionen
    12
    Punkte
    1.087
    Beiträge
    182
    • 27. Dezember 2008 um 00:05
    • #20

    also, ich hab mich jetzt einige zeit intensivst mit JPF auseinandergesetzt (vorm schlafen gehn denk ich immer nur ), und muss sagen dass es aeusserst einfach und bequem einzusetzen ist im vergleich zu anderen frameworks a la osgi. es ist sogar ein selbstgestecktes ziel von den JPF leuten nicht zuuu komplex zu sein.
    von daher: JPF :thumb:

    interessant koennten auch noch folgende blogeintraege sein ueber "sich-selber-ein-plugin-framework-schreiben":
    java-dynamic-loading-of-class-and-jar-file
    develop-a-java-plugin-framework
    develop-a-java-plugin-framework-search-for-plugin-dynamically

    bzw noch besser: du verwendest neue moeglichkeiten von java 6 mit hilfe des service providers:
    http://java.sun.com/developer/tech…ase/extensible/

    ---- edit ----
    wenn man java6 zur verfuegung hat, geht das mit dem ServiceLoader echt ur geschmeidig:

    1) jar bauen, welches eine datei /META-INF/services/com.example.ISomeServiceInterface mit inhalt com.example.plugin.SomeServiceImpl hat (natuerlich auch noch diese impl klasse korrekt erstellen)
    2) die hauptanwendung hat dann dieses jar im classpath und folgende zwei zeilen reichen dann aus um die angemeldeten service provider zu nutzen:

    Code
    ServiceLoader<ISomeServiceInterface> loader = ServiceLoader.load(ISomeServiceInterface.class);
    for (ISomeServiceInterface service : loader) { /* do something with service */ }

    Einmal editiert, zuletzt von phudy (27. Dezember 2008 um 00:43)

  • Maximilian Rupp 27. Dezember 2024 um 00:26

    Hat das Thema aus dem Forum Programmieren nach Entwicklung verschoben.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!

Benutzerkonto erstellen Anmelden

Benutzer online in diesem Thema

  • 1 Besucher

Rechtliches

Impressum

Datenschutzerklärung