/*
* This program 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, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* PluginManager.java
* Copyright (C) 2011-2012 University of Waikato, Hamilton, New Zealand
*
*/
package weka.classifiers.evaluation;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
/**
* Class that manages a global map of plugins. The knowledge flow uses this to
* manage plugins other than step components and perspectives. Is general
* purpose, so can be used by other Weka components. Provides static methods for
* registering and instantiating plugins.
*
* @author Mark Hall (mhall{[at]}pentaho{[dot]}com)
* @version $Revision: 9312 $
*/
public class PluginManager {
/**
* Global map that is keyed by plugin base class/interface type. The inner Map
* then stores individual plugin instances of the interface type, keyed by
* plugin name/short title with values the actual fully qualified class name
*/
protected static Map<String, Map<String, String>> PLUGINS = new HashMap<String, Map<String, String>>();
/**
* Set of concrete fully qualified class names or abstract/interface base
* types to "disable". Entries in this list wont ever be returned by any of
* the getPlugin() methods. Registering an abstract/interface base name will
* disable all concrete implementations of that type
*/
protected static Set<String> DISABLED = new HashSet<String>();
/**
* Add the supplied list of fully qualified class names to the disabled list
*
* @param classnames a list of class names to add
*/
public static synchronized void addToDisabledList(List<String> classnames) {
for (String s : classnames) {
addToDisabledList(s);
}
}
/**
* Add the supplied fully qualified class name to the list of disabled plugins
*
* @param classname the fully qualified name of a class to add
*/
public static synchronized void addToDisabledList(String classname) {
DISABLED.add(classname);
}
/**
* Remove the supplied list of fully qualified class names to the disabled
* list
*
* @param classnames a list of class names to remove
*/
public static synchronized void removeFromDisabledList(List<String> classnames) {
for (String s : classnames) {
removeFromDisabledList(s);
}
}
/**
* Remove the supplied fully qualified class name from the list of disabled
* plugins
*
* @param classname the fully qualified name of a class to remove
*/
public static synchronized void removeFromDisabledList(String classname) {
DISABLED.remove(classname);
}
/**
* Returns true if the supplied fully qualified class name is in the disabled
* list
*
* @param classname the name of the class to check
* @return true if the supplied class name is in the disabled list
*/
public static boolean isInDisabledList(String classname) {
return DISABLED.contains(classname);
}
/**
* Add all key value pairs from the supplied property file
*
* @param propsFile the properties file to add
* @throws Exception if a problem occurs
*/
public static synchronized void addFromProperties(File propsFile)
throws Exception {
BufferedInputStream bi = new BufferedInputStream(new FileInputStream(
propsFile));
addFromProperties(bi);
}
/**
* Add all key value pairs from the supplied properties stream
*
* @param propsStream an input stream to a properties file
* @throws Exception if a problem occurs
*/
public static synchronized void addFromProperties(InputStream propsStream)
throws Exception {
Properties expProps = new Properties();
expProps.load(propsStream);
propsStream.close();
propsStream = null;
addFromProperties(expProps);
}
/**
* Add all key value pairs from the supplied properties object
*
* @param props a Properties object
* @throws Exception if a problem occurs
*/
public static synchronized void addFromProperties(Properties props)
throws Exception {
Set keys = props.keySet();
Iterator keysI = keys.iterator();
while (keysI.hasNext()) {
String baseType = (String) keysI.next();
String implementations = props.getProperty(baseType);
if (implementations != null && implementations.length() > 0) {
String[] parts = implementations.split(",");
for (String impl : parts) {
PluginManager.addPlugin(baseType, impl.trim(), impl.trim());
}
}
}
}
/**
* Get a set of names of plugins that implement the supplied interface.
*
* @param interfaceName the fully qualified name of the interface to list
* plugins for
*
* @return a set of names of plugins
*/
public static Set<String> getPluginNamesOfType(String interfaceName) {
if (PLUGINS.get(interfaceName) != null) {
Set<String> match = PLUGINS.get(interfaceName).keySet();
Set<String> result = new HashSet<String>();
for (String s : match) {
String impl = PLUGINS.get(interfaceName).get(s);
if (!DISABLED.contains(impl)) {
result.add(s);
}
}
// return PLUGINS.get(interfaceName).keySet();
return result;
}
return null;
}
/**
* Add a plugin.
*
* @param interfaceName the fully qualified interface name that the plugin
* implements
*
* @param name the name/short description of the plugin
* @param concreteType the fully qualified class name of the actual concrete
* implementation
*/
public static void addPlugin(String interfaceName, String name,
String concreteType) {
if (PLUGINS.get(interfaceName) == null) {
Map<String, String> pluginsOfInterfaceType = new TreeMap<String, String>();
pluginsOfInterfaceType.put(name, concreteType);
PLUGINS.put(interfaceName, pluginsOfInterfaceType);
} else {
PLUGINS.get(interfaceName).put(name, concreteType);
}
}
/**
* Remove plugins of a specific type.
*
* @param interfaceName the fully qualified interface name that the plugins to
* be remove implement
* @param names a list of named plugins to remove
*/
public static void removePlugins(String interfaceName, List<String> names) {
for (String name : names) {
removePlugin(interfaceName, name);
}
}
/**
* Remove a plugin.
*
* @param interfaceName the fully qualified interface name that the plugin
* implements
*
* @param name the name/short description of the plugin
*/
public static void removePlugin(String interfaceName, String name) {
if (PLUGINS.get(interfaceName) != null) {
PLUGINS.get(interfaceName).remove(name);
}
}
/**
* Get an instance of a concrete implementation of a plugin type
*
* @param interfaceType the fully qualified interface name of the plugin type
* @param name the name/short description of the plugin to get
* @return the concrete plugin or null if the plugin is disabled
* @throws Exception if the plugin can't be found or instantiated
*/
public static Object getPluginInstance(String interfaceType, String name)
throws Exception {
if (PLUGINS.get(interfaceType) == null
|| PLUGINS.get(interfaceType).size() == 0) {
throw new Exception("No plugins of interface type: " + interfaceType
+ " available!!");
}
Map<String, String> pluginsOfInterfaceType = PLUGINS.get(interfaceType);
if (pluginsOfInterfaceType.get(name) == null) {
throw new Exception("Can't find named plugin '" + name + "' of type '"
+ interfaceType + "'!");
}
String concreteImpl = pluginsOfInterfaceType.get(name);
Object plugin = null;
if (!DISABLED.contains(concreteImpl)) {
plugin = Class.forName(concreteImpl).newInstance();
}
return plugin;
}
}