All Downloads are FREE. Search and download functionalities are using the official Maven repository.

weka.core.PluginManager Maven / Gradle / Ivy

Go to download

The Waikato Environment for Knowledge Analysis (WEKA), a machine learning workbench. This version represents the developer version, the "bleeding edge" of development, you could say. New functionality gets added to this version.

There is a newer version: 3.9.6
Show newest version
/*
 *   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 .
 */

/*
 *    PluginManager.java
 *    Copyright (C) 2011-2012 University of Waikato, Hamilton, New Zealand
 *
 */

package weka.core;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
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. Provides static methods for
 * registering and instantiating plugins. The package manager looks for, and
 * processes, a PluginManager.props file in the top-level of a package.
 * 
 * @author Mark Hall (mhall{[at]}pentaho{[dot]}com)
 * @version $Revision: 12312 $
 */
public class PluginManager {

  /**
   * Global map of plugin classes 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> PLUGINS =
    new HashMap>();

  /**
   * 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 DISABLED = new HashSet();

  /**
   * Global map of plugin resources (loadable from the classpath). Outer map is
   * keyed by group ID, i.e. an ID of a logical group of resources (e.g.
   * knowledge flow template files). The inner map then stores individual
   * resource paths keyed by their short description.
   */
  protected static Map> RESOURCES =
    new HashMap>();

  /**
   * Global lookup map to locate a package owner for resources. Keyed by group
   * ID:resource description. Used to see if a package owns a resource, in which
   * case the package classloader should be used to load the resource rather
   * than the application classloader
   */
  protected static Map RESOURCE_OWNER_PACKAGE = new HashMap<>();

  /**
   * 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 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 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 {
    addFromProperties(null, propsFile);
  }

  /**
   * Add all key value pairs from the supplied property file
   *
   * @param packageName the name of the Weka package that owns this properties
   *          object. Can be null if not owned by a Weka package
   * @param propsFile the properties file to add
   * @throws Exception if a problem occurs
   */
  public static synchronized void addFromProperties(String packageName,
    File propsFile) throws Exception {
    addFromProperties(packageName, propsFile, false);
  }

  /**
   * Add all key value pairs from the supplied property file
   *
   * @param propsFile the properties file to add
   * @param maintainInsertionOrder true if the order of insertion of
   *          implementations is to be preserved (rather than sorted order)
   * @throws Exception if a problem occurs
   */
  public static synchronized void addFromProperties(File propsFile,
    boolean maintainInsertionOrder) throws Exception {
    addFromProperties(null, propsFile, maintainInsertionOrder);
  }

  /**
   * Add all key value pairs from the supplied property file
   *
   * @param packageName the name of the Weka package that owns this properties
   *          object. Can be null if not owned by a Weka package
   * @param propsFile the properties file to add
   * @param maintainInsertionOrder true if the order of insertion of
   *          implementations is to be preserved (rather than sorted order)
   * @throws Exception if a problem occurs
   */
  public static synchronized void addFromProperties(String packageName,
    File propsFile, boolean maintainInsertionOrder) throws Exception {
    BufferedInputStream bi =
      new BufferedInputStream(new FileInputStream(propsFile));
    addFromProperties(packageName, bi, maintainInsertionOrder);
  }

  /**
   * 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 {
    addFromProperties(null, propsStream);
  }

  /**
   * Add all key value pairs from the supplied properties stream
   *
   * @param packageName the name of the Weka package that owns this properties
   *          object. Can be null if not owned by a Weka package
   * @param propsStream an input stream to a properties file
   * @throws Exception if a problem occurs
   */
  public static synchronized void addFromProperties(String packageName,
    InputStream propsStream) throws Exception {
    addFromProperties(packageName, propsStream, false);
  }

  /**
   * Add all key value pairs from the supplied properties stream
   *
   * @param propsStream an input stream to a properties file
   * @param maintainInsertionOrder true if the order of insertion of
   *          implementations is to be preserved (rather than sorted order)
   * @throws Exception if a problem occurs
   */
  public static synchronized void addFromProperties(InputStream propsStream,
    boolean maintainInsertionOrder) throws Exception {
    addFromProperties(null, propsStream, maintainInsertionOrder);
  }

  /**
   * Add all key value pairs from the supplied properties stream
   *
   * @param packageName the name of the Weka package that owns this properties
   *          object. Can be null if not owned by a Weka package
   * @param propsStream an input stream to a properties file
   * @param maintainInsertionOrder true if the order of insertion of
   *          implementations is to be preserved (rather than sorted order)
   * @throws Exception if a problem occurs
   */
  public static synchronized void addFromProperties(String packageName,
    InputStream propsStream, boolean maintainInsertionOrder) throws Exception {

    Properties expProps = new Properties();

    expProps.load(propsStream);
    propsStream.close();
    propsStream = null;

    addFromProperties(packageName, expProps, maintainInsertionOrder);
  }

  /**
   * 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 {
    addFromProperties(props, false);
  }

  /**
   * Add all key value pairs from the supplied properties object
   *
   * @param packageName the name of the Weka package that owns this properties
   *          object. Can be null if not owned by a Weka package
   * @param props a Properties object
   * @throws Exception if a problem occurs
   */
  public static synchronized void addFromProperties(String packageName,
    Properties props) throws Exception {
    addFromProperties(packageName, props, false);
  }

  /**
   * Add all key value pairs from the supplied properties object
   *
   * @param props a Properties object
   * @param maintainInsertionOrder true if the order of insertion of
   *          implementations is to be preserved (rather than sorted order)
   * @throws Exception if a problem occurs
   */
  public synchronized static void addFromProperties(Properties props,
    boolean maintainInsertionOrder) throws Exception {
    addFromProperties(null, props, maintainInsertionOrder);
  }

  /**
   * Add all key value pairs from the supplied properties object
   *
   * @param packageName the name of the Weka package that owns this properties
   *          object. Can be null if not owned by a Weka package
   * @param props a Properties object
   * @param maintainInsertionOrder true if the order of insertion of
   *          implementations is to be preserved (rather than sorted order)
   * @throws Exception if a problem occurs
   */
  public static synchronized void addFromProperties(String packageName,
    Properties props, boolean maintainInsertionOrder) throws Exception {
    java.util.Enumeration keys = props.propertyNames();

    while (keys.hasMoreElements()) {
      String baseType = (String) keys.nextElement();
      String implementations = props.getProperty(baseType);
      if (baseType.equalsIgnoreCase("*resources*")) {
        addPluginResourcesFromProperty(packageName, implementations);
      } else {
        if (implementations != null && implementations.length() > 0) {
          String[] parts = implementations.split(",");
          for (String impl : parts) {
            impl = impl.trim();
            String name = impl;
            if (impl.charAt(0) == '[') {
              name = impl.substring(1, impl.indexOf(']'));
              impl = impl.substring(impl.indexOf(']') + 1);
            }
            PluginManager.addPlugin(baseType, name.trim(), impl,
              maintainInsertionOrder);
          }
        }
      }
    }
  }

  /**
   * Add resources from a list. String format for a list of resources (as might
   * be supplied from a *resources* entry in an property file:
*
* *
   * [groupID|description|path],[groupID|description|path],...
   * 
* * @param resourceList a list of resources to add */ public static void addPluginResourcesFromProperty(String resourceList) { addPluginResourcesFromProperty(null, resourceList); } /** * Add resources from a list. String format for a list of resources (as might * be supplied from a *resources* entry in an property file:
*
* *
   * [groupID|description|path],[groupID|description|path],...
   * 
* * @param packageName the Weka package that owns these resources. Can be null * if not owned by a Weka package * @param resourceList a list of resources to add */ protected static synchronized void addPluginResourcesFromProperty( String packageName, String resourceList) { // Format: [groupID|description|path],[...],... String[] resources = resourceList.split(","); for (String r : resources) { r = r.trim(); if (!r.startsWith("[") || !r.endsWith("]")) { System.err.println("[PluginManager] Malformed resource in: " + resourceList); continue; } r = r.replace("[", "").replace("]", ""); String[] rParts = r.split("\\|"); if (rParts.length != 3) { System.err .println("[PluginManager] Was expecting 3 pipe separated parts in " + "resource spec: " + r); continue; } String groupID = rParts[0].trim(); String resourceDesc = rParts[1].trim(); String resourcePath = rParts[2].trim(); if (groupID.length() == 0 || resourceDesc.length() == 0 || resourcePath.length() == 0) { System.err.println("[PluginManager] Empty part in resource spec: " + r); continue; } addPluginResource(packageName, groupID, resourceDesc, resourcePath); } } /** * Add a resource. * * @param resourceGroupID the ID of the group under which the resource should * be stored * @param resourceDescription the description/ID of the resource * @param resourcePath the path to the resource */ public static void addPluginResource(String resourceGroupID, String resourceDescription, String resourcePath) { addPluginResource(null, resourceGroupID, resourceDescription, resourcePath); } /** * Add a resource. * * @param packageName the name of the package that owns this resource. Can be * null if not owned by a package, in which case the current * classloader will be used to load the resource. * @param resourceGroupID the ID of the group under which the resource should * be stored * @param resourceDescription the description/ID of the resource * @param resourcePath the path to the resource */ public static synchronized void addPluginResource(String packageName, String resourceGroupID, String resourceDescription, String resourcePath) { Map groupMap = RESOURCES.get(resourceGroupID); if (groupMap == null) { groupMap = new LinkedHashMap(); RESOURCES.put(resourceGroupID, groupMap); } groupMap.put(resourceDescription, resourcePath); if (packageName != null && packageName.length() > 0) { RESOURCE_OWNER_PACKAGE.put(resourceGroupID + ":" + resourceDescription, packageName); } } /** * Get an input stream for a named resource under a given resource group ID. * * @param resourceGroupID the group ID that the resource falls under * @param resourceDescription the description/ID of the resource * @return an InputStream for the resource * @throws IOException if the group ID or resource description/ID are not * known to the PluginManager, or a problem occurs while trying to * open an input stream */ public static InputStream getPluginResourceAsStream(String resourceGroupID, String resourceDescription) throws IOException { Map groupMap = RESOURCES.get(resourceGroupID); if (groupMap == null) { throw new IOException("Unknown resource group ID: " + resourceGroupID); } String resourcePath = groupMap.get(resourceDescription); if (resourcePath == null) { throw new IOException("Unknown resource: " + resourceDescription); } // owned by a package? String ownerPackage = RESOURCE_OWNER_PACKAGE.get(resourceGroupID + ":" + resourceDescription); if (ownerPackage == null) { return PluginManager.class.getClassLoader().getResourceAsStream( resourcePath); } return WekaPackageClassLoaderManager.getWekaPackageClassLoaderManager() .getPackageClassLoader(ownerPackage).getResourceAsStream(resourcePath); } /** * Get the number of resources available under a given resource group ID. * * @param resourceGroupID the group ID of the resources * @return the number of resources registered under the supplied group ID */ public static int numResourcesForWithGroupID(String resourceGroupID) { Map groupMap = RESOURCES.get(resourceGroupID); return groupMap == null ? 0 : groupMap.size(); } /** * Get a map of resources (description,path) registered under a given resource * group ID. * * @param resourceGroupID the group ID of the resources to get * @return a map of resources registered under the supplied group ID, or null * if the resourceGroupID is not known to the plugin manager */ public static Map getResourcesWithGroupID( String resourceGroupID) { return RESOURCES.get(resourceGroupID); } /** * 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 getPluginNamesOfType(String interfaceName) { if (PLUGINS.get(interfaceName) != null) { Set match = PLUGINS.get(interfaceName).keySet(); Set result = new LinkedHashSet(); 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; } /** * Get a sorted list 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 List getPluginNamesOfTypeList(String interfaceName) { List result; Set r = getPluginNamesOfType(interfaceName); result = new ArrayList(); if (r != null) { result.addAll(r); } Collections.sort(result, new ClassDiscovery.StringCompare()); return result; } /** * 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) { addPlugin(interfaceName, name, concreteType, false); } /** * 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 * @param maintainInsertionOrder true if the order of insertion of * implementations is to be preserved (rather than sorted order) */ public static void addPlugin(String interfaceName, String name, String concreteType, boolean maintainInsertionOrder) { if (PLUGINS.get(interfaceName) == null) { Map pluginsOfInterfaceType = maintainInsertionOrder ? new LinkedHashMap() : new TreeMap(); 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 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); } } /** * Checks if a named plugin exists in the map of registered plugins * * @param interfaceType the fully qualified interface name of the plugin type * @param name the name/short description of the plugin to get * @return true if the named plugin exists */ public static boolean pluginRegistered(String interfaceType, String name) { Map pluginsOfInterfaceType = PLUGINS.get(interfaceType); return pluginsOfInterfaceType != null && pluginsOfInterfaceType.get(name) != null; } /** * 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 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 = WekaPackageClassLoaderManager.forName(concreteImpl).newInstance(); } return plugin; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy