Dans le cadre de notre projet d'introspection en java, nous voulons reprendre une idée vue en cours, à savoir réaliser un programme pouvant recevoir des extensions. L'idée est à double but:
1) Nous allons pouvoir nous entrainer avec java.lang.reflect et ainsi commencer à mettre les pieds dans l'introspection java
2) Une fois la classe permettant de charger des plugins terminé nous pourrons élaborer une interface graphique qui viendra se greffer dessus et ainsi nous posséderons une base pour nos futur projet dans ce domaine.
La classe se nommera "PluginLoader" et aura comme particularité de charger des extensions qui seront des JPanel.
Voici l'idée générale:
1) le programme contient un répertoire par défaut où se trouvent les plugins, pour faciliter on nommera ce répertoire "/plugins"
2) notre programme doit pouvoir repérer un fichier extensions dans ce répertoire, on considère qu'un fichier dit "plugin" possède une extension .jar
3) le programme regarde le nom du fichier .jar et recherche à l'intérieur de celui-ci un fichier .class du même nom. Attention le fichier .class du même nom ne doit se trouver dans aucun package, question de facilité
4) un cherche alors le constructeur par défaut du .class et on crée une nouvelle instance de l'objet
5) Comme on souhaite créer des plugins qui seront des JPanels il ne reste plus qu'a "caster" l'objet obtenu et à l'ajouter au modèle avec les autres plugins précédemment chargé.
Voici le code source correspondant :
package net.sourceforge.introspectionjava;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;
import java.util.jar.JarFile;
import javax.swing.JOptionPane;
import main.support.LanguageManager;
import org.apache.log4j.Logger;
public class PluginLoader {
// Allow log4j for this class
private static Logger log = Logger.getLogger(PluginLoader.class);
private LanguageManager lang; // allow this class to be internationalized
// default constructor of the class
public PluginLoader(){
this.lang=new LanguageManager("net/sourceforge/introspectionjava/lang/","PluginLoader"); // create an instance of LanguageManager
}
@SuppressWarnings("deprecation")
// method which load a plugin include in a .jar file
public Object loadFile(File f){
try{
String temp=f.getName(); // gte the name of the file
String path = temp.substring(0,temp.length()-4); // get the name without .jar extendsion
// load the .jar file into memory
URLClassLoader loader;
// will be used for compare strings
String tmp = "";
// get the content of the .jar file
Enumeration enumeration;
URL u = f.toURL();
// create a new URLClassLoader to load .jar file which is'nt in the CLASSPATH
loader = new URLClassLoader(new URL[] {u});
// load the jar file into memory
JarFile jar = new JarFile(f.getAbsolutePath());
// get all the content of the .jar
enumeration = jar.entries();
while(enumeration.hasMoreElements()){
tmp = enumeration.nextElement().toString();
// verify if the file is a .class
if(tmp.length() > 6 && tmp.substring(tmp.length()-6).compareTo(".class") == 0 && tmp.equals(path+".class")) {
tmp = tmp.substring(0,tmp.length()-6);
tmp = tmp.replaceAll("/",".");
Class tmpClass = Class.forName(tmp ,true,loader);
Class[] ctorArgs1 = new Class[]{};
Constructor constructor=tmpClass.getConstructor(ctorArgs1);
log.info("Load..."+f.getCanonicalFile()+" OK!");
return constructor.newInstance();
}
}
} catch (IOException e ){
log.error(e.getMessage(), e);
JOptionPane.showMessageDialog(null, lang.getAnInternationalizeString("$io_error")+"\n"+f.getName(), lang.getAnInternationalizeString("$error_title"),JOptionPane.OK_OPTION);
} catch (ClassNotFoundException e) {
log.error(e.getMessage(), e);
JOptionPane.showMessageDialog(null, lang.getAnInternationalizeString("$class_error")+"\n"+f.getName(), lang.getAnInternationalizeString("$error_title"),JOptionPane.OK_OPTION);
} catch (Exception e) {
log.error(e.getMessage(), e);
JOptionPane.showMessageDialog(null, lang.getAnInternationalizeString("$load_error")+"\n"+f.getName(), lang.getAnInternationalizeString("$error_title"),JOptionPane.OK_OPTION);
}
log.error("Plugin: "+f.getName()+" can't be load!");
JOptionPane.showMessageDialog(null, lang.getAnInternationalizeString("$load_error")+"\n"+f.getName(), lang.getAnInternationalizeString("$error_title"),JOptionPane.OK_OPTION);
return null;
}
}
Cette classe est déjà implantée dans un programme lié à notre projet, nommé: "XProcessor"