/*
* Copyright 2004 - 2008 Christian Sprajc. All rights reserved.
*
* This file is part of PowerFolder.
*
* PowerFolder is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*
* PowerFolder is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with PowerFolder. If not, see <http://www.gnu.org/licenses/>.
*
* $Id$
*/
package de.dal33t.powerfolder.plugin;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import de.dal33t.powerfolder.ConfigurationEntry;
import de.dal33t.powerfolder.Controller;
import de.dal33t.powerfolder.PFComponent;
import de.dal33t.powerfolder.event.ListenerSupportFactory;
import de.dal33t.powerfolder.util.Reject;
import de.dal33t.powerfolder.util.StringUtils;
/** @author <A HREF="mailto:schaatser@powerfolder.com">Jan van Oosterom</A> */
public class PluginManager extends PFComponent {
private static final Logger log = Logger.getLogger(PluginManager.class
.getName());
private static final String OLD_WEBINTERFACE_PLUGIN_CLASS_NAME = "de.dal33t.powerfolder.AB";
private static final String OLD_PLUGIN_CLASS_NAME = "de.dal33t.powerfolder.HI";
private List<Plugin> plugins;
private List<Plugin> disabledPlugins;
private PluginManagerListener listeners;
public PluginManager(Controller controller) {
super(controller);
plugins = new CopyOnWriteArrayList<Plugin>();
disabledPlugins = new CopyOnWriteArrayList<Plugin>();
listeners = ListenerSupportFactory
.createListenerSupport(PluginManagerListener.class);
}
// Start / Stop ***********************************************************
public void init() {
readEnabledPlugins();
readDisabledPlugins();
}
/**
* Starts the plugin manager, reads and starts all plugins.
*/
public void start() {
if (plugins.size() + disabledPlugins.size() == 0) {
logFine("No plugins found to start. Maybe PluginManager not initialized?");
}
startEnabledPlugins();
}
/** stops all plugins */
public void shutdown() {
if (plugins != null) {
for (Plugin plugin : plugins) {
try {
plugin.stop();
plugin.destroy();
} catch (Exception e) {
logSevere("Exception while stopping/destroying plugin: "
+ plugin + ". " + e, e);
}
logFine(plugin.getName() + " stopped and destroyed");
}
plugins.clear();
}
if (disabledPlugins != null) {
for (Plugin plugin : disabledPlugins) {
try {
plugin.destroy();
} catch (Exception e) {
logSevere("Exception while destroying plugin: " + plugin
+ ". " + e, e);
}
logFine(plugin.getName() + " destroyed");
}
disabledPlugins.clear();
}
}
/**
* Initializes all plugins
*/
private void readEnabledPlugins() {
readAndInitPlugins(
ConfigurationEntry.PLUGINS.getValue(getController()), plugins,
"enabled");
}
/**
* reads disabled plugins
*/
private void readDisabledPlugins() {
readAndInitPlugins(ConfigurationEntry.PLUGINS_DISABLED
.getValue(getController()), disabledPlugins, "disabled");
}
private void readAndInitPlugins(String pluginsStr, List<Plugin> plugins,
String typeInfo)
{
plugins.clear();
if (StringUtils.isBlank(pluginsStr)) {
return;
}
logFine("Initalizing (" + typeInfo + ") plugins: " + pluginsStr);
StringTokenizer nizer = new StringTokenizer(pluginsStr, ",");
while (nizer.hasMoreElements()) {
String pluginClassName = nizer.nextToken().trim();
if (StringUtils.isBlank(pluginClassName)) {
continue;
}
if (alreadyLoaded(pluginClassName)) {
continue;
}
Plugin plugin = newPluginInstance(pluginClassName);
if (plugin != null) {
plugins.add(plugin);
plugin.init();
}
}
}
/**
* Initalized a plugin by classname
*
* @param pluginClassName
* the classname of the plugin
*/
private Plugin newPluginInstance(String pluginClassName) {
if (StringUtils.isBlank(pluginClassName)) {
throw new IllegalArgumentException("Plugin string blank");
}
if (OLD_WEBINTERFACE_PLUGIN_CLASS_NAME
.equalsIgnoreCase(pluginClassName))
{
logFine("Not loading web interface. "
+ "It not longer available in v4.0 of PowerFolder.");
return null;
}
if (OLD_PLUGIN_CLASS_NAME.equalsIgnoreCase(pluginClassName)) {
logFine("Not loading old plugin. "
+ "It not longer available in v5.0 of PowerFolder.");
return null;
}
if (log.isLoggable(Level.FINE)) {
logFine("Initializing plugin: " + pluginClassName);
}
try {
Class<?> pluginClass = Class.forName(pluginClassName);
Plugin plugin;
try {
// NoSuchMethodException
// try to instantiate AbstractPFPlugin
Constructor<?> constr = pluginClass
.getConstructor(Controller.class);
plugin = (Plugin) constr.newInstance(getController());
} catch (NoSuchMethodException e) {
// No constructor with Controller as parameter.
try {
plugin = (Plugin) pluginClass.newInstance();
} catch (ClassCastException e2) {
// failed, not a Plugin to...!
log
.log(
Level.SEVERE,
"failed to load: "
+ pluginClassName
+ "does not extends AbstractPFPlugin or implements Plugin",
e);
return null;
}
}
return plugin;
} catch (Exception e) {
log.log(Level.SEVERE, "Exception while initializing plugin '"
+ pluginClassName + '\'', e);
}
return null;
}
/**
* Starts the enabled plugins
*/
private void startEnabledPlugins() {
for (Plugin plugin : plugins) {
logFine("Starting plugin: " + plugin.getName());
try {
plugin.start();
} catch (Exception e) {
logSevere("Exception while starting plugin: " + plugin + ". "
+ e, e);
}
}
}
/**
* is this plugin enabled ?
*
* @param plugin
* @return true if yes
*/
public boolean isEnabled(Plugin plugin) {
if (plugin == null) {
return false;
}
for (Plugin canidate : plugins) {
if (canidate.equals(plugin)) {
return true;
}
if (canidate instanceof PluginWrapper) {
PluginWrapper wrapper = (PluginWrapper) canidate;
if (wrapper.getDeligate().equals(plugin)) {
return true;
}
}
}
return false;
}
/**
* @param thePlugin
* @param enabled
* new status of the plugin
*/
public void setEnabled(Plugin thePlugin, boolean enabled) {
Plugin plugin = findPlugin(thePlugin);
logFine("enable: " + enabled + ' ' + plugin);
if (enabled) {
disabledPlugins.remove(plugin);
if (!plugins.contains(plugin)) {
plugins.add(plugin);
}
try {
plugin.start();
} catch (Exception e) {
logSevere("Exception while starting plugin: " + plugin + ". "
+ e, e);
}
} else {
plugins.remove(plugin);
if (!disabledPlugins.contains(plugin)) {
disabledPlugins.add(plugin);
}
try {
plugin.stop();
} catch (Exception e) {
logSevere("Exception while stopping plugin: " + plugin + ". "
+ e, e);
}
}
saveConfig();
firePluginStatusChange(plugin);
}
/**
* Writes the config file.
*/
public void saveConfig() {
String enabledPluginsPropertyValue = "";
String seperator = "";
for (Plugin plug : plugins) {
enabledPluginsPropertyValue += seperator
+ plug.getClass().getName();
seperator = ",";
}
ConfigurationEntry.PLUGINS.setValue(getController(),
enabledPluginsPropertyValue);
String disabledPluginsPropertyValue = "";
seperator = "";
for (Plugin plug : disabledPlugins) {
disabledPluginsPropertyValue += seperator
+ plug.getClass().getName();
seperator = ",";
}
ConfigurationEntry.PLUGINS_DISABLED.setValue(getController(),
disabledPluginsPropertyValue);
getController().saveConfig();
}
/**
* returns all installed plugins
*
* @return the list of all plugins
*/
public List<Plugin> getPlugins() {
List<Plugin> pluginsAll = new ArrayList<Plugin>();
pluginsAll.addAll(plugins);
pluginsAll.addAll(disabledPlugins);
return pluginsAll;
}
/**
* the total number of installed plugins
*
* @return the number of plugins
*/
public int countPlugins() {
return plugins.size() + disabledPlugins.size();
}
/**
* @param searchPlugin
* @return the first plugin with the given instance or it's wrapper.
*/
public Plugin findPlugin(Plugin searchPlugin) {
Reject.ifNull(searchPlugin, "searchPlugin");
for (Plugin plugin : plugins) {
if (searchPlugin.equals(plugin)) {
return plugin;
}
if (plugin instanceof PluginWrapper) {
if (((PluginWrapper) plugin).getDeligate().equals(searchPlugin))
{
return plugin;
}
}
}
for (Plugin plugin : disabledPlugins) {
if (searchPlugin.equals(plugin)) {
return plugin;
}
if (plugin instanceof PluginWrapper) {
if (((PluginWrapper) plugin).getDeligate().equals(searchPlugin))
{
return plugin;
}
}
}
return searchPlugin;
}
/**
* @param searchClass
* @return the first plugin with the given class.
*/
public Plugin findPluginByClass(Class<?> searchClass) {
Reject.ifNull(searchClass, "Clazz is null");
for (Plugin plugin : plugins) {
if (plugin instanceof PluginWrapper) {
plugin = ((PluginWrapper) plugin).getDeligate();
}
if (searchClass.isInstance(plugin)) {
return plugin;
}
}
for (Plugin plugin : disabledPlugins) {
if (plugin instanceof PluginWrapper) {
plugin = ((PluginWrapper) plugin).getDeligate();
}
if (searchClass.isInstance(plugin)) {
return plugin;
}
}
return null;
}
public void addPluginManagerListener(
PluginManagerListener pluginManagerListener)
{
ListenerSupportFactory.addListener(listeners, pluginManagerListener);
}
public void removePluginManagerListener(
PluginManagerListener pluginManagerListener)
{
ListenerSupportFactory.removeListener(listeners, pluginManagerListener);
}
private void firePluginStatusChange(Plugin plugin) {
listeners.pluginStatusChanged(new PluginEvent(this, plugin));
}
private boolean alreadyLoaded(String pluginClassName) {
for (Plugin p : plugins) {
if (p.getClass().getName().equals(pluginClassName)) {
return true;
}
}
for (Plugin p : disabledPlugins) {
if (p.getClass().getName().equals(pluginClassName)) {
return true;
}
}
return false;
}
}