package net.sourceforge.pain.plugin;
import net.sourceforge.pain.*;
import net.sourceforge.pain.util.*;
import java.io.*;
import java.util.*;
public final class PluginManager {
public final static String PLUGINS_HOME = "net.sourceforge.pain.plugin.";
public final static int PLUGINS_HOME_LENGTH = PLUGINS_HOME.length();
private Map loadersByPlugName = new Hashtable();
private Map loadersByPlugDir = new Hashtable();
private LinkedList pluginsList = new LinkedList();
protected String dirPath = null;
protected int counter = 0;
public PluginManager(String dirPath) {
this.dirPath = dirPath;
}
public void init() throws Exception {
String fileName = Core.getApplicationPath() + "/etc/plugin.cfg"; //plugins to load during startup
BufferedReader reader = new BufferedReader(new FileReader(fileName));
List plugNames = new ArrayList();
try {
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
if (line.length() == 0 || line.charAt(0) == '#' || line.charAt(0) == '!') {
continue;
}
plugNames.add(line.trim());
}
} finally {
reader.close();
}
for (Iterator it = plugNames.iterator(); it.hasNext();) {
String className = (String) it.next();
Log.debug("initializing plugin:" + className);
loadPlugin(className);
}
Log.debug("Plugin Manager initialization COMPLETE");
}
/**
*
* @param pluginName - is className without PLUGINS_HOME prefix
* @return
*/
public synchronized Plugin getPlugin(String pluginName) {
Log.debug("PlugM: getPlugin:" + pluginName);
PluginClassLoader loader = (PluginClassLoader) loadersByPlugName.get(pluginName);
if (loader != null) {
return loader.getPlugin();
}
return null;
}
// public synchronized Plugin getPluginWithLoad(String pluginName) throws Exception {
// Plugin p = getPlugin(pluginName);
// if (p == null) {
// p = loadPlugin(pluginName);
// }
// return p;
// }
/**
*
* @param pluginName is className without PLUGINS_HOME prefix
* @return
* @throws Exception
*/
public synchronized Plugin loadPlugin(String pluginName) throws Exception {
Log.debug("PlugM: loadPlugin:" + pluginName);
PluginClassLoader loader = (PluginClassLoader) loadersByPlugName.get(pluginName);
if (loader == null) {
boolean loaded = false;
try {
loader = new PluginClassLoader(this, pluginName);
pluginsList.add(loader.getPlugin());
loadersByPlugName.put(pluginName, loader);
loadersByPlugDir.put(loader.pluginDir, loader);
loaded = true;
} finally {
if (!loaded) { //during plugin loading pluginCL
//can ask some classes from other plugins
//and loading plugin becomes they child (it's name cached),
// we should remove this data if plugin was not loaded!
for (Iterator it = pluginsList.iterator(); it.hasNext();) {
((Plugin) it.next()).removeChild(pluginName);
}
}
}
}
return loader.getPlugin();
}
/** if plugin A uses classes from plugin B this dialog will be called during plugin A class instantiation
this method is also used in LogicLoader to provide plugin classes to logic ones
todo: logic classes should be reloaded only if they use this plugin
*/
public Class loadClassByPluginClassloader(String requesterPluginName, String requestedClassName) throws ClassNotFoundException {
final String pluginDir = requestedClassName.substring(PLUGINS_HOME_LENGTH, requestedClassName.indexOf('.', PLUGINS_HOME_LENGTH) + 1);
PluginClassLoader cl = (PluginClassLoader) loadersByPlugDir.get(pluginDir);
if (cl == null) {
throw new RuntimeException("Plugin is not loaded:" + pluginDir + "asker:" + requesterPluginName);
}
final Class clazz = cl.loadClass(requestedClassName);
final Plugin p = cl.getPlugin();
if (requesterPluginName != null) {
p.addChild(requesterPluginName);
}
return clazz;
}
/**
* WARN: all net.sourceforge.pain.logic.* classes have direct access to plugins
* we will unload all this code after plugin is unloaded in this method
* WARN: all child plugins will be unloaded!
*/
public void unloadPlugin(Plugin p) {
if (p == null) {
return;
}
Log.debug("PlugM: unloadPlugin:" + p.pluginName);
_unloadPlugin(p);
Core.getLogicLoader().reload(); //todo: do it only if logic had direct access to this plug (trace it with classloader)
}
private void _unloadPlugin(Plugin p) {
final Set childs = p.childs;
Log.debug("PlugM: has childs:" + !childs.isEmpty());
if (!childs.isEmpty()) {
for (Iterator it = childs.iterator(); it.hasNext();) {
Plugin child = getPlugin((String) it.next());
if (child == null) {
return;
}
Log.debug("PlugM: unloading child plugin:" + child.pluginName);
unloadPlugin(child);
}
}
try {
p.deinit();
} catch (Exception e) {
Log.error(e.getMessage(), e);
}
//++ remove mapping
PluginClassLoader l = (PluginClassLoader) loadersByPlugName.remove(p.pluginName);
loadersByPlugDir.remove(l.pluginDir);
pluginsList.remove(p);
}
public List getActivePluginsList() {
return Collections.unmodifiableList(pluginsList);
}
}