Java-Programme durch PlugIns erweitern: Unterschied zwischen den Versionen

Aus Byte-Welt Wiki
Zur Navigation springenZur Suche springen
K
Zeile 17: Zeile 17:
 
===Das Plugin-Interface===
 
===Das Plugin-Interface===
 
Das Interface für die Plugins muss keine Methoden (Markerinterface), kann aber auch beliebig viele definieren. Es hat sich bewärt, dass das Plugin-Interface mindestens zwei Methoden besitzt '''start()''' und '''stop()'''. Außerdem eine Methode um die Manager-Klasse zu setzen, sollte das Plugin auf irgendwelche Eigenschaften der Anwendung zugreifen können.
 
Das Interface für die Plugins muss keine Methoden (Markerinterface), kann aber auch beliebig viele definieren. Es hat sich bewärt, dass das Plugin-Interface mindestens zwei Methoden besitzt '''start()''' und '''stop()'''. Außerdem eine Methode um die Manager-Klasse zu setzen, sollte das Plugin auf irgendwelche Eigenschaften der Anwendung zugreifen können.
<code=java>
+
<syntaxhighlight lang="java">
 
package net.byte_welt.wiki;
 
package net.byte_welt.wiki;
 
public interface PluginInterface{
 
public interface PluginInterface{
Zeile 25: Zeile 25:
 
   public void hello();
 
   public void hello();
 
}
 
}
</code=java>
+
</syntaxhighlight>
 
Zusätzlich wurde das Interface um die Methode ''hello'' erweitert, somit kann das Plugin von der Anwendung auch benachrichtigt werden.
 
Zusätzlich wurde das Interface um die Methode ''hello'' erweitert, somit kann das Plugin von der Anwendung auch benachrichtigt werden.
  
 
===Das PluginManager-Interface===
 
===Das PluginManager-Interface===
 
Das Interface für den Pluginmanager bildet die Schnittstelle vom Plugin zur Anwendung. Hier werden alle Methoden aufgeführt die das Plugin aufrufen darf.
 
Das Interface für den Pluginmanager bildet die Schnittstelle vom Plugin zur Anwendung. Hier werden alle Methoden aufgeführt die das Plugin aufrufen darf.
<code=java>
+
<syntaxhighlight lang="java">
 
package net.byte_welt.wiki;
 
package net.byte_welt.wiki;
 
public interface PluginManager{
 
public interface PluginManager{
 
   public void openWindow(String msg);
 
   public void openWindow(String msg);
 
}
 
}
</code=java>
+
</syntaxhighlight>
 
Unser Plugin-Manager erlaubt nur das Öffnen eines Fensters mit einem String als Nachricht.
 
Unser Plugin-Manager erlaubt nur das Öffnen eines Fensters mit einem String als Nachricht.
  
Zeile 43: Zeile 43:
 
===Hello-Plugin===
 
===Hello-Plugin===
 
Unser Plugin soll beim Aufruf der ''hello()''-Methode nur ein Fenster öffnen und dort ''Hallo'' ausgeben, daher fällt die Implementierung sehr einfach aus. Die ''start()''- und ''stop()''-Methoden werden garnicht benötigt, würde der Text aus einer [[Datenbank]] oder [[Datei]] gelesen werden könnte dies in der ''start''-Methode erledigt werden
 
Unser Plugin soll beim Aufruf der ''hello()''-Methode nur ein Fenster öffnen und dort ''Hallo'' ausgeben, daher fällt die Implementierung sehr einfach aus. Die ''start()''- und ''stop()''-Methoden werden garnicht benötigt, würde der Text aus einer [[Datenbank]] oder [[Datei]] gelesen werden könnte dies in der ''start''-Methode erledigt werden
<code=java>
+
<syntaxhighlight lang="java">
 
package net.byte_welt.wiki;
 
package net.byte_welt.wiki;
 
public class HelloPlugin implements PluginInterface{
 
public class HelloPlugin implements PluginInterface{
Zeile 62: Zeile 62:
 
   }
 
   }
 
}
 
}
</code=java>
+
</syntaxhighlight>
  
 
===PluginManager===
 
===PluginManager===
 
Der Plugin-Manager kann für zwei Aufgaben verwendet werden. Er kann dem Plugin übergeben werden und zusätzlich kann er die Kontrolle der Plugins übernehmen. Unser Pluginmanager übernimmt beide Aufgaben, daher implementiert er das PluginManager-Interface. Zusätzlich werden die Methoden ''loadPlugin'', ''start'' und ''stop'' implementiert.
 
Der Plugin-Manager kann für zwei Aufgaben verwendet werden. Er kann dem Plugin übergeben werden und zusätzlich kann er die Kontrolle der Plugins übernehmen. Unser Pluginmanager übernimmt beide Aufgaben, daher implementiert er das PluginManager-Interface. Zusätzlich werden die Methoden ''loadPlugin'', ''start'' und ''stop'' implementiert.
<code=java>
+
<syntaxhighlight lang="java">
 
package net.byte_welt.wiki;
 
package net.byte_welt.wiki;
 
import java.io.*;
 
import java.io.*;
Zeile 86: Zeile 86:
 
   }
 
   }
 
}
 
}
</code=java>
+
</syntaxhighlight>
  
 
====Start-Methode====
 
====Start-Methode====
 
Die ''start''-Methode wird aufgerufen, wenn die Anwendung gestartet wird und alle vorhandenen Plugins geladen werden sollen. Die Pfade zu den vorhandenen Plugins lassen sich z.B. extra speichern, oder es wird gesagt, alles was im Ordner '''plugins''' liegt gilt als Plugin. In unserem Fall wird gesagt, was im Ordner '''plugins''' liegt wird geladen, dafür wird nur die ''loadPlugin''-Methode aufgerufen.
 
Die ''start''-Methode wird aufgerufen, wenn die Anwendung gestartet wird und alle vorhandenen Plugins geladen werden sollen. Die Pfade zu den vorhandenen Plugins lassen sich z.B. extra speichern, oder es wird gesagt, alles was im Ordner '''plugins''' liegt gilt als Plugin. In unserem Fall wird gesagt, was im Ordner '''plugins''' liegt wird geladen, dafür wird nur die ''loadPlugin''-Methode aufgerufen.
<code=java>
+
<syntaxhighlight lang="java">
 
public void start(){
 
public void start(){
 
   File[] files = new File("plugins").listFiles();
 
   File[] files = new File("plugins").listFiles();
Zeile 98: Zeile 98:
 
     pi.start();
 
     pi.start();
 
}
 
}
</code=java>
+
</syntaxhighlight>
 
Sind alle Plugins geladen werden sie gestartet.
 
Sind alle Plugins geladen werden sie gestartet.
  
 
====Stop-Methode====
 
====Stop-Methode====
Mit der ''stop''-Methode wird den Plugins signalisiert, dass sie runterfahren sollen. Dies ist der Fall, wenn z.B. das Programm beendet wird.<code=java>
+
Mit der ''stop''-Methode wird den Plugins signalisiert, dass sie runterfahren sollen. Dies ist der Fall, wenn z.B. das Programm beendet wird.<syntaxhighlight lang="java">
 
public void stop(){
 
public void stop(){
 
   for(PluginInterface pi:loadedplugins)
 
   for(PluginInterface pi:loadedplugins)
 
     pi.stop();
 
     pi.stop();
 
}
 
}
</code=java>
+
</syntaxhighlight>
  
 
====LoadPlugin-Methode====
 
====LoadPlugin-Methode====
Zeile 114: Zeile 114:
 
=====JAR-Dateien laden=====
 
=====JAR-Dateien laden=====
 
Um ein Plugin aus einer JAR-Datei zu laden, muss deren Pfad und die Main-Class bekannt sein. Im Gegensatz zu einer normalen Anwendung ist die Main-Class bei einem Plugin die Klasse, die das Interface für die Plugin-Schnittstelle implementiert. Es ist aber auch möglich, alle Klassen der JAR zu durchlaufen.
 
Um ein Plugin aus einer JAR-Datei zu laden, muss deren Pfad und die Main-Class bekannt sein. Im Gegensatz zu einer normalen Anwendung ist die Main-Class bei einem Plugin die Klasse, die das Interface für die Plugin-Schnittstelle implementiert. Es ist aber auch möglich, alle Klassen der JAR zu durchlaufen.
<code=java>
+
<syntaxhighlight lang="java">
 
//Erzeugen des JAR-Objekts
 
//Erzeugen des JAR-Objekts
 
JarFile file = new JarFile("Plugin.jar");
 
JarFile file = new JarFile("Plugin.jar");
Zeile 123: Zeile 123:
 
// holen der Mainclass aus den Attributen
 
// holen der Mainclass aus den Attributen
 
String main = attrib.getValue(Attributes.Name.MAIN_CLASS);
 
String main = attrib.getValue(Attributes.Name.MAIN_CLASS);
</code=java>
+
</syntaxhighlight>
  
 
Aus dem Manifest-Objekt lassen sich jetzt beliebige Daten auslesen, jedoch werden hier nur die Informationen über die Main-Class benötigt. Mit diesen Daten lässt sich jetzt das Plugin laden, dazu wird ein neuer [[ClassLoader (Java) |ClassLoader]] erzeugt.
 
Aus dem Manifest-Objekt lassen sich jetzt beliebige Daten auslesen, jedoch werden hier nur die Informationen über die Main-Class benötigt. Mit diesen Daten lässt sich jetzt das Plugin laden, dazu wird ein neuer [[ClassLoader (Java) |ClassLoader]] erzeugt.
<code=java>
+
<syntaxhighlight lang="java">
 
// laden der Klasse mit dem File als URL und der Mainclass
 
// laden der Klasse mit dem File als URL und der Mainclass
 
Class cl = new URLClassLoader(new URL[]{new File("Plugin.jar").toURL()}).loadClass(main);
 
Class cl = new URLClassLoader(new URL[]{new File("Plugin.jar").toURL()}).loadClass(main);
Zeile 140: Zeile 140:
 
   loadedplugins.add(plugin);
 
   loadedplugins.add(plugin);
 
}
 
}
</code=java>
+
</syntaxhighlight>
 
Anschließend werden die Interfaces der Klasse betrachtet, ob es sich wirklich um ein Plugin handelt. Ist es ein Plugin wird eine neue Instanz erzeugt und diese abgespeichert.
 
Anschließend werden die Interfaces der Klasse betrachtet, ob es sich wirklich um ein Plugin handelt. Ist es ein Plugin wird eine neue Instanz erzeugt und diese abgespeichert.
  
Zeile 149: Zeile 149:
 
===OpenWindow-Methode===
 
===OpenWindow-Methode===
 
Die ''openWindow''-Methode ist für die Interaktion mit den Plugins nötig, über diese Methode kann ein Fenster geöffnet werden.
 
Die ''openWindow''-Methode ist für die Interaktion mit den Plugins nötig, über diese Methode kann ein Fenster geöffnet werden.
<code=java>
+
<syntaxhighlight lang="java">
 
public void openWindow(String msg){
 
public void openWindow(String msg){
 
   javax.swing.JOptionPane.showMessageDialog(null, msg);
 
   javax.swing.JOptionPane.showMessageDialog(null, msg);
 
}
 
}
</code=java>
+
</syntaxhighlight>
  
 
=Weblinks=
 
=Weblinks=

Version vom 8. März 2018, 19:49 Uhr

Unvollstaendig.png Dieser Artikel ist unvollständig. Hilf mit ihn zu verbessern, erweitere ihn oder beteilige dich an der Diskussion.

Damit Programme leicht um neue Teile erweitert werden können, ist es hilfreich und komfortabel, diese mit einer Plugin-Schnittstelle auszustatten.

Voraussetzungen

Als Voraussetzung für die Verwendung von Plugins sollten verschiedene Klassen und Interfaces vorhanden sein:

  1. Plugin-Interface - das die Plugins implementieren müssen. Hiermit wird festgelegt welche Funktionen das Plugin der Anwendung anbieten muss.
  2. Anwendung-Interface - das die Schnittstelle von den Plugins zur Anwendung darstellt, hiermit kann kontrolliert werden, was die Anwendungen dürfen und was sie sehen.
  3. Manager - gesonderte Klasse für das Laden, Starten und Beenden der Plugins.

Die Interfaces

Das gesamte Plugin-System könnte auch ohne Interfaces geschrieben werden, jedoch ist dies unsicherer. Interfaces standardisieren durch vordefinierte Methoden die Entwicklung und Verwendung von Klassen, was innerhalb der Anwendung sicher stellt, dass nachgerüstete Klassen alle benötigten Methoden bereit stellen. Dadurch ist mit einfachen Mitteln eine gewisse Vielgestaltigkeit möglich.

Das Plugin-Interface

Das Interface für die Plugins muss keine Methoden (Markerinterface), kann aber auch beliebig viele definieren. Es hat sich bewärt, dass das Plugin-Interface mindestens zwei Methoden besitzt start() und stop(). Außerdem eine Methode um die Manager-Klasse zu setzen, sollte das Plugin auf irgendwelche Eigenschaften der Anwendung zugreifen können.

package net.byte_welt.wiki;
public interface PluginInterface{
  public boolean start();
  public boolean stop();
  public void setPluginManager(PluginManager manager);
  public void hello();
}

Zusätzlich wurde das Interface um die Methode hello erweitert, somit kann das Plugin von der Anwendung auch benachrichtigt werden.

Das PluginManager-Interface

Das Interface für den Pluginmanager bildet die Schnittstelle vom Plugin zur Anwendung. Hier werden alle Methoden aufgeführt die das Plugin aufrufen darf.

package net.byte_welt.wiki;
public interface PluginManager{
  public void openWindow(String msg);
}

Unser Plugin-Manager erlaubt nur das Öffnen eines Fensters mit einem String als Nachricht.

Implementierungen

Durch die Interfaces muss für die Entwicklung des Plugins nur die Class- oder Java-Dateien weiter gegeben werden, die Implementierungen des PluginManagers dagegen nicht.

Hello-Plugin

Unser Plugin soll beim Aufruf der hello()-Methode nur ein Fenster öffnen und dort Hallo ausgeben, daher fällt die Implementierung sehr einfach aus. Die start()- und stop()-Methoden werden garnicht benötigt, würde der Text aus einer Datenbank oder Datei gelesen werden könnte dies in der start-Methode erledigt werden

package net.byte_welt.wiki;
public class HelloPlugin implements PluginInterface{
  private PluginManager manager;
  public boolean start(){
    System.out.println("ich starte");
    return true;
  }
  public boolean stop(){
    System.out.println("ich stoppe");
    return true;
  }
  public void setPluginManager(PluginManager manager){
    this.manager = manager;
  }
  public void hello(){
    manager.openWindow("hallo");
  }
}

PluginManager

Der Plugin-Manager kann für zwei Aufgaben verwendet werden. Er kann dem Plugin übergeben werden und zusätzlich kann er die Kontrolle der Plugins übernehmen. Unser Pluginmanager übernimmt beide Aufgaben, daher implementiert er das PluginManager-Interface. Zusätzlich werden die Methoden loadPlugin, start und stop implementiert.

package net.byte_welt.wiki;
import java.io.*;
import java.util.jar.*;
import java.net.*;
public class PluginManagerImpl implements PluginManager{
  private Vector<PluginInterface> loadedplugins = new Vector<PluginInterface>();
  public void start(){
  ...
  }
  public void stop(){
  ...
  }
  public void loadPlugin(File file){
  ...
  }
  public void openWindow(String msg){
  ...
  }
}

Start-Methode

Die start-Methode wird aufgerufen, wenn die Anwendung gestartet wird und alle vorhandenen Plugins geladen werden sollen. Die Pfade zu den vorhandenen Plugins lassen sich z.B. extra speichern, oder es wird gesagt, alles was im Ordner plugins liegt gilt als Plugin. In unserem Fall wird gesagt, was im Ordner plugins liegt wird geladen, dafür wird nur die loadPlugin-Methode aufgerufen.

public void start(){
  File[] files = new File("plugins").listFiles();
  for(File f:files)
    loadPlugin(f);
  for(PluginInterface pi:loadedplugins)
    pi.start();
}

Sind alle Plugins geladen werden sie gestartet.

Stop-Methode

Mit der stop-Methode wird den Plugins signalisiert, dass sie runterfahren sollen. Dies ist der Fall, wenn z.B. das Programm beendet wird.

public void stop(){
  for(PluginInterface pi:loadedplugins)
    pi.stop();
}

LoadPlugin-Methode

Um Plugins zu laden, gibt es zwei Ansätze. Zum einen gibt es die Möglichkeit Class-Dateien aber auch JAR-Dateien zu laden.

JAR-Dateien laden

Um ein Plugin aus einer JAR-Datei zu laden, muss deren Pfad und die Main-Class bekannt sein. Im Gegensatz zu einer normalen Anwendung ist die Main-Class bei einem Plugin die Klasse, die das Interface für die Plugin-Schnittstelle implementiert. Es ist aber auch möglich, alle Klassen der JAR zu durchlaufen.

//Erzeugen des JAR-Objekts
JarFile file = new JarFile("Plugin.jar");
//Laden der MANIFEST.MF
Manifest manifest = file.getManifest();
// auslesen der Attribute aus der Manifest
Attributes attrib = manifest.getMainAttributes();
// holen der Mainclass aus den Attributen
String main = attrib.getValue(Attributes.Name.MAIN_CLASS);

Aus dem Manifest-Objekt lassen sich jetzt beliebige Daten auslesen, jedoch werden hier nur die Informationen über die Main-Class benötigt. Mit diesen Daten lässt sich jetzt das Plugin laden, dazu wird ein neuer ClassLoader erzeugt.

// laden der Klasse mit dem File als URL und der Mainclass
Class cl = new URLClassLoader(new URL[]{new File("Plugin.jar").toURL()}).loadClass(main);
// holen der Interfaces die die Klasse impementiert
Class[] interfaces = cl.getInterfaces();
// Durchlaufen durch die Interfaces der Klasse und nachsehn ob es das passende Plugin implementiert
boolean isplugin = false;
for(int y = 0; y < interfaces.length && !isplugin; y++)
  if(interfaces[y].getName().equals("net.byte_welt.wiki.PluginInterface"))
    isplugin = true;
if(isplugin){
  PluginInterface plugin = (PluginInterface) cl.newInstance();
  loadedplugins.add(plugin);
}

Anschließend werden die Interfaces der Klasse betrachtet, ob es sich wirklich um ein Plugin handelt. Ist es ein Plugin wird eine neue Instanz erzeugt und diese abgespeichert.

Class-Dateien laden
  • wird nachgeliefert.


OpenWindow-Methode

Die openWindow-Methode ist für die Interaktion mit den Plugins nötig, über diese Methode kann ein Fenster geöffnet werden.

public void openWindow(String msg){
  javax.swing.JOptionPane.showMessageDialog(null, msg);
}

Weblinks