Cet outil permet de lister une catègorie de plugins disponible.
Il permet l'abstraction de l'emplacement physiques des plugins.
Ceux-ci peuvent être dans plusieurs JAR, des repertoires etc.
La recherche des plugins se fait sur 3 critères :
- Accessiblent par le classpath de l'application
- Doivent se trouver dans un package determiné (sous-packages inclus)
- Doivent hériter d'une classe mère de plugin (definit par vos soin)
Cette classe à pour rôle de vous aider a réaliser un mécanisme de plugins au sein d'une application JAVA.
package org.XXXXXXXX;
import java.util.*;
import java.util.zip.*;
import java.io.*;
import java.net.*;
/**
* PluginInspector
* Ce module s'occupe de dresser une liste des "plugins" disponibles au sein d'une application JAVA
* Ce code n'est qu'a titre d'exemple sur comment faire un outils permettant d'ajouter des plugins.
*
* L'idée de cet inspecteur est d'imposer un package pour les plugins et d'utiliser le classLoader afin
* de determiner toutes les classes.
* Il est ainsi possible de rajouter par la suite un fichier JAR contenant de nouveaux plugins et qu'ils
* soient automatiquement pris en comptes par l'application (pour peu que le fichier JAR soit rajouté correctement au classpath)
*
* Un "PluginInspector" s'appuie sur deux elements pour identifier les plugins
* - Le package de recherche (ainsi que tous les sous-packages)
* - La classe mère des plugins afin de s'assurer qu'une classe est effectivement un plugin
*
* Il est possible d'avoir plusieurs "PluginInspector" pour gérer differentes natures de plugins
*
* Exemple :
* - les plugins sont installés dans le package org.myApplic.plugins
* - La classe mère des plugins est org.myApplic.util.Plugin
*
* Récuperation des plugins de l'application :
* Iterator plugins = new PluginInspector("org.myApplic.plugins",org.myApplic.util.Plugin.class).plugins();
* while( plugins.hasNext() )
* { Class plugin = (Class)plugins.next();
* System.out.println("Plugin Loaded : " + plugin);
* }
*
* Remarque : le PluginInspector charge les classes lors de l'examen, ce qui n'est pas un mauvais choix pour
* un mécanisme de plugins, mais ce mécanisme pourait être assez pénalisant pour un usage detourné
*
* @author André Sébastien
*/
public class PluginInspector {
/** Nom du package des plugins **/
private String pluginPackage = null;
/** Classe mere de tous les plugins **/
private Class pluginHomeClass = null;
/** Repertoire (en terme de resource) des plugins **/
private String pluginResourceName = null;
/** Repertoire (en terme de fileSystem) des plugins **/
private String pluginFileName = null;
/** Liste des plugins **/
private List plugins = new ArrayList();
/** Filtre utilisé lors d'un examen de repertoire physique **/
private static final FileFilter filter = new FileFilter()
{
public boolean accept(File pathname)
{ if(pathname.isDirectory() ) return true;
if(!pathname.isFile() ) return false;
String path = pathname.getAbsolutePath();
if( ! path.endsWith(".class") ) return false;
if( path.indexOf('$') >= 0 ) return false;
return true;
}
};
/** Constructeur
* @param packageName Package dont doivent faire partie les plugins (sous-packages compris)
* @param pluginHomeClass Class mére de tous les plugins, si null alors, il sera considéré Object.class comme class mère de tous les plugins
**/
public PluginInspector(String packageName , Class pluginHomeClass )
{
/** Initialisation **/
this.pluginPackage = packageName;
this.pluginHomeClass = pluginHomeClass;
if( this.pluginHomeClass == null ) this.pluginHomeClass = Object.class;
/** On calcul le repertoire d'acces aux repertoires **/
this.pluginResourceName = this.pluginPackage.replace('.','/');
this.pluginFileName = this.pluginPackage.replace('.', File.separatorChar );
/** Lance l'examen de l'application **/
this.examine();
}
/** Retourne la liste des plugins accessiblent (objets "Class") **/
public Iterator plugins()
{ return this.plugins.iterator(); }
/** Examine l'application pour determiner les plugins accessibles **/
private void examine()
{ try
{ Enumeration e = this.getClass().getClassLoader().getResources( this.pluginResourceName );
while( e.hasMoreElements() )
{ URL url = (URL)e.nextElement();
String protocol = url.getProtocol();
if( protocol.equals("file") ) this.examineFromDirectory( new File(url.getFile() ) );
else if( protocol.equals("jar")) this.examineFromJar(url);
}
}
catch(Exception e){ e.printStackTrace(); }
}
/** Examine les plugins à partir d'un repertoire physique **/
private void examineFromDirectory(File directory)
{ if( ! directory.isDirectory() ) return;
try
{
File[] files = directory.listFiles( this.filter );
for(int i = 0 ; i < files.length ; i++)
{ File file = files[i];
if( file.isDirectory() )
{ this.examineFromDirectory( file );
continue;
}
/** Transformer le chemin en package **/
String name = file.getAbsolutePath();
int pos = name.indexOf( this.pluginFileName );
if( pos == -1 ) continue;
name = name.substring( pos , name.length() - 6 ).replace( File.separatorChar , '.');
/** Charger le plugin **/
Class plugin = this.getClass().forName(name);
if( ! this.pluginHomeClass.isAssignableFrom( plugin ) ) continue;
if( this.plugins.contains( plugin ) ) continue;
this.plugins.add(plugin);
}
}
catch(Exception e){ e.printStackTrace(); }
}
/** Examine les plugins à partir d'un JAR **/
private void examineFromJar(URL url)
{ String jarName = url.getFile();
jarName = jarName.substring( jarName.indexOf(':') );
jarName = jarName.substring(0 , jarName.indexOf('!' ) );
jarName = jarName.replace('/', File.separatorChar );
try
{
ZipFile zipFile = new ZipFile(jarName);
Enumeration e = zipFile.entries();
while( e.hasMoreElements() )
{ ZipEntry entry = (ZipEntry)e.nextElement();
String name = entry.getName();
if( ! name.endsWith(".class") ) continue;
if( ! name.startsWith( this.pluginResourceName ) ) continue;
if( name.indexOf('$') >= 0 ) continue;
/** suppression du .class et remise sous forme de package **/
name = name.substring(0, name.length() - 6 );
name = name.replace('/','.');
/** Charger le plugin **/
Class plugin = this.getClass().forName(name);
if( ! this.pluginHomeClass.isAssignableFrom( plugin ) ) continue;
if( this.plugins.contains( plugin ) ) continue;
this.plugins.add(plugin);
}
zipFile.close();
}
catch(Exception e){ e.printStackTrace(); }
}
}
|