Das Konzept von Plugins

Unicate

Erfahrenes Mitglied
Hi alle zusammen!

Ich habe ein Programm, welches ich gern per Plugin erweiterbar machen möchte. (ala Firefox,Eclipse oder so ähnlich)
Wie setze ich sowas um?

Weiß jemand wie man's macht oder hat jemand vllt. nen Link?

Danke schonnema!
 
Geht ganz einfach. Ich definiere zuerst ein Interface oder eine abstrakte Klasse. Erzeuge ein neues Projekt, füge eine Klasse ein die davon erbt oder es implemententiert (um Parameter übergeben zu können).
In Eclipse lege ich das Hauptprojekt als Projektverknüpfung fest, damit ich auf die Klasse/Interface zugreifen kann. Dann mache ich aus dem Plugin eine jar, lade ichs einfach per URLClassLoader von der HDD im Hauptprojekt und rufe die geerbte/implementierte Klasse davon auf.
 
OK, ich danke Dir!

Hier Beispielcode für alle die den Thread finden ;)

Zuerst das Interface im Hauptprojekt:
Java:
package de.unicate.playground;

public interface IPlugin {
	
	public String getName();
}
Jetzt das Hauptprojekt, wo das Plugin geladen werden soll:
Java:
package de.unicate.playground;

import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;


public class Playground {

	private IPlugin plugin;	
	private Playground() {
		plugin = null;
	}	
	public static void main(String[] args) throws Exception{
		Playground main = new Playground();
		main.init();
		main.start();
	}
	private void start() {
		if(null != plugin) {
			System.out.println(plugin.getName());
		} else {
			System.err.println("Pluginerror");
		}
	}
	private void init() throws Exception {
		URL pluginFile = null;
		File file = new File("TestPlugin.jar");
		if(!file.exists())
			return;
		pluginFile = new URL("file", "localhost", file.getAbsolutePath());
		URL[] urls = {pluginFile};
		URLClassLoader loader = new URLClassLoader(urls,Thread.currentThread().getContextClassLoader());
		plugin =  (IPlugin)loader.loadClass("de.unicate.playground.plugin.PlaygroundPlugin").newInstance();
	
	}		
}

Und zu guter letzt noch das Plugin, was ich in einem eigenen Projekt erstellt habe und das Hauptprojekt verknüpft habe, damit das Interface auffindbar ist:
Java:
package de.unicate.playground.plugin;

import de.unicate.playground.IPlugin;

public class PlaygroundPlugin implements IPlugin{

	public PlaygroundPlugin() {
		
	}
	@Override
	public String getName() {
		return  "Ich bin ein Plugin";
		
	}

}

Relativ einfach und funktioniert!


Danke nochmal an Kai008!
 
Du kannst eine File auch mit toURI.toURL (oder toURL, aber veraltet, weil keine Sonderzeichen escaped werden) umwandeln. Der 2. Parameter bei der Intialisierung des URLClassLoader ist nicht notwendig. (Constructs a new URLClassLoader for the specified URLs using the default delegation parent ClassLoader.)
 
Howdie.

Ich hab praktisch identischen Code, wie du in deinem Beispielcode gezeigt hast, Unicate. Momentan arbeite ich an einem größeren Projekt, in dem einzelne Module nachladbar sein sollen.
Bei mir ist jetzt das Problem, dass ein AbstractMethodError geworfen wird, obwohl ich über
Java:
// RCBModule ist das Interface, das ich für ladbare Module benutze
RCBModule module = (RCBModule)classLoader.loadClass(modulePackagePath).newInstance();
eigentlich eine Instanz erzeugt haben müsste, oder? Dieser Fehler wird ja eigentlich nur geworfen, wenn eine nicht überschriebene Methode einer abstrakten Klasse (oder wie hier eines Interfaces) aufgerufen wird.
Oder muss ich den Konstruktur der implementierenden Klasse auf irgendeine Art und Weise explizit aufrufen?

Falls alle Stricke reißen muss ich halt doch auch den ServiceLoader benutzen... Wäre aber dankbar für Tipps.

Gruß
miffi
 
Thrown when an application tries to call an abstract method. Normally, this error is caught by the compiler; this error can only occur at run time if the definition of some class has incompatibly changed since the currently executing method was last compiled.

Ich lade die Klassen Problemlos mit dem URLClassLoader aus einer Jar, die ich aus einen übertragenen String der ein Server an den/die Clienten übermittelt.

Java:
public Plugin(File pluginFile)
{
	super();
	
	try
	{
		//TODO Hardcodet, read the Classes from File in Jar
		URLClassLoader classLoader = new URLClassLoader(new URL[] {
			pluginFile.toURI().toURL()
		});
		Class<?> loadetClass = classLoader.loadClass("core.JobExecuter");
		abstractJobExecuter = (AbstractJobExecuter) loadetClass.newInstance();
	}
	catch (MalformedURLException e)
	{
		e.printStackTrace();
	}
	catch (ClassNotFoundException e)
	{
		e.printStackTrace();
	}
	catch (InstantiationException e)
	{
		e.printStackTrace();
	}
	catch (IllegalAccessException e)
	{
		e.printStackTrace();
	}
}

Ist das dass, was du unter dynamischen Nachladen verstehst?
 
Hallo Kai,

hab den Teil der Exception-Beschreibung wohl überlesen, dass der Fehler zur Laufzeit eine andere Bedeutung hat. Wobei es eigentlich logisch ist, bei dem Zugriff auf die Member einer abstrakten Klasse hätte der Compiler ja schon gemeckert.

Hab alle Module gecleant und neu kompiliert, jetzt geht alles.
Danke :)

Gruß
miffi
 
Zurück