Package weka.gui

Source Code of weka.gui.GenericPropertiesCreator

/*
*    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 2 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, write to the Free Software
*    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

/*
* GenericPropertiesCreator.java
* Copyright (C) 2005 University of Waikato, Hamilton, New Zealand
*
*/
package weka.gui;

import weka.core.ClassDiscovery;
import weka.core.Utils;
import weka.core.ClassDiscovery.StringCompare;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;

/**
* This class can generate the properties object that is normally loaded from
* the <code>GenericObjectEditor.props</code> file (= PROPERTY_FILE). It takes
* the <code>GenericPropertiesCreator.props</code> file as a template to
* determine all the derived classes by checking the classes in the given
* packages (a file with the same name in your home directory overrides the
* the one in the weka/gui directory/package). <br>
* E.g. if we want to have all the subclasses of the <code>Classifier</code>
* class then we specify the superclass ("weka.classifiers.Classifier") and the
* packages where to look for ("weka.classifiers.bayes" etc.):
*
* <pre>
*
*   weka.classifiers.Classifier=\
*     weka.classifiers.bayes,\
*     weka.classifiers.functions,\
*     weka.classifiers.lazy,\
*     weka.classifiers.meta,\
*     weka.classifiers.trees,\
*     weka.classifiers.rules
* </pre>
*
* This creates the same list as stored in the
* <code>GenericObjectEditor.props</code> file, but it will also add
* additional classes, that are not listed in the static list (e.g. a newly
* developed Classifier), but still in the classpath. <br>
* <br>
* For discovering the subclasses the whole classpath is inspected, which means
* that you can have several parallel directories with the same package
* structure (e.g. a release directory and a developer directory with additional
* classes). <br>
* <br>
* The dynamic discovery can be turned off via the <code>UseDyanmic</code>
* property in the props file (values: true|false).
*
* @see #CREATOR_FILE
* @see #PROPERTY_FILE
* @see #USE_DYNAMIC
* @see GenericObjectEditor
* @see weka.core.ClassDiscovery
* @author FracPete (fracpete at waikato dot ac dot nz)
* @version $Revision: 6857 $
*/
public class GenericPropertiesCreator {
 
  /** whether to output some debug information */
  public final static boolean VERBOSE = false;

  /** name of property whether to use the dynamic approach or the old
   * GenericObjectEditor.props file */
  public final static String USE_DYNAMIC = "UseDynamic";
 
  /** The name of the properties file to use as a template. Contains the
   * packages in which to look for derived classes. It has the same structure
   * as the <code>PROPERTY_FILE</code>
   * @see #PROPERTY_FILE
   */
  protected static String CREATOR_FILE = "weka/gui/GenericPropertiesCreator.props";
 
  /** The name of the properties file that lists classes/interfaces/superclasses
   * to exclude from being shown in the GUI. See the file for more information.
   */
  protected static String EXCLUDE_FILE = "weka/gui/GenericPropertiesCreator.excludes";

  /** the prefix for an interface exclusion */
  protected static String EXCLUDE_INTERFACE = "I";

  /** the prefix for an (exact) class exclusion */
  protected static String EXCLUDE_CLASS = "C";

  /** the prefix for a superclass exclusion */
  protected static String EXCLUDE_SUPERCLASS = "S";
 
  /** The name of the properties file for the static GenericObjectEditor
   * (<code>USE_DYNAMIC</code> = <code>false</code>)
   * @see GenericObjectEditor
   * @see #USE_DYNAMIC
   */
  protected static String PROPERTY_FILE = "weka/gui/GenericObjectEditor.props";
 
  /** the input file with the packages */
  protected String m_InputFilename;
 
  /** the output props file for the GenericObjectEditor */
  protected String m_OutputFilename;
 
  /** the "template" properties file with the layout and the packages */
  protected Properties m_InputProperties;
 
  /** the output properties file with the filled in classes */
  protected Properties m_OutputProperties;
 
  /** Globally available properties */
  protected static GenericPropertiesCreator GLOBAL_CREATOR;
  protected static Properties GLOBAL_INPUT_PROPERTIES;
  protected static Properties GLOBAL_OUTPUT_PROPERTIES;
 
  /** whether an explicit input file was given - if false, the Utils class
   * is used to locate the props-file */
  protected boolean m_ExplicitPropsFile;
 
  /** the hashtable that stores the excludes:
   * key -&gt; Hashtable(prefix -&gt; Vector of classnames) */
  protected Hashtable m_Excludes;
 
  static {
    try {
      GenericPropertiesCreator creator = new GenericPropertiesCreator();
      GLOBAL_CREATOR = creator;
      if (creator.useDynamic()) {
        creator.execute(false, true);
        GLOBAL_INPUT_PROPERTIES = creator.getInputProperties();
        GLOBAL_OUTPUT_PROPERTIES = creator.getOutputProperties();
      } else {
        // Read the static information from the GenericObjectEditor.props
        GLOBAL_OUTPUT_PROPERTIES =
          Utils.readProperties("weka/gui/GenericObjectEditor.props");
      }
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
 
  /**
   * Get the global output properties
   *
   * @return the global output properties
   */
  public static Properties getGlobalOutputProperties() {
    return GLOBAL_OUTPUT_PROPERTIES;
  }
 
  /**
   * Get the global input properties
   *
   * @return the global input properties
   */
  public static Properties getGlobalInputProperties() {
    return GLOBAL_INPUT_PROPERTIES;
  }
 
  /**
   * Regenerate the global output properties. Does not load the
   * input properties, instead uses the GLOBAL_INPUT_PROPERTIES
   */
  public static void regenerateGlobalOutputProperties() {
    if (GLOBAL_CREATOR != null) {
      try {
        GLOBAL_CREATOR.execute(false, false);
        GLOBAL_OUTPUT_PROPERTIES = GLOBAL_CREATOR.getOutputProperties();
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
  }
 
  /**
   * initializes the creator, locates the props file with the Utils class.
   *
   * @throws Exception if loading of CREATOR_FILE fails
   * @see #CREATOR_FILE
   * @see Utils#readProperties(String)
   * @see #loadInputProperties()
   */
  public GenericPropertiesCreator() throws Exception {
    this(CREATOR_FILE);
    m_ExplicitPropsFile = false;
  }

  /**
   * initializes the creator, the given file overrides the props-file search
   * of the Utils class
   *
   * @param filename the file containing the packages to create a props file from
   * @throws Exception if loading of the file fails
   * @see #CREATOR_FILE
   * @see Utils#readProperties(String)
   * @see #loadInputProperties()
   */
  public GenericPropertiesCreator(String filename) throws Exception {
    super();
    m_InputFilename     = filename;
    m_OutputFilename    = PROPERTY_FILE;
    m_InputProperties   = null;
    m_OutputProperties  = null;
    m_ExplicitPropsFile = true;
    m_Excludes          = new Hashtable();
  }

  /**
   * if FALSE, the locating of a props-file of the Utils-class is used,
   * otherwise it's tried to load the specified file
   *
   * @param value   if true the specified file will be loaded not via the
   *       Utils-class
   * @see Utils#readProperties(String)
   * @see #loadInputProperties()
   */
  public void setExplicitPropsFile(boolean value) {
    m_ExplicitPropsFile = value;
  }
 
  /**
   * returns TRUE, if a file is loaded and not the Utils class used for
   * locating the props file.
   *
   * @return  true if the specified file is used and not the one found by
   *     the Utils class
   * @see Utils#readProperties(String)
   * @see #loadInputProperties()
   */
  public boolean getExplicitPropsFile() {
    return m_ExplicitPropsFile;
  }
 
  /**
   * returns the name of the output file
   *
   * @return the name of the output file
   */
  public String getOutputFilename() {
    return m_OutputFilename;
  }
 
  /**
   * sets the file to output the properties for the GEO to
   *
   * @param filename the filename for the output
   */
  public void setOutputFilename(String filename) {
    m_OutputFilename = filename;
  }

  /**
   * returns the name of the input file
   *
   * @return the name of the input file
   */
  public String getInputFilename() {
    return m_InputFilename;
  }
 
  /**
   * sets the file to get the information about the packages from.
   * automatically sets explicitPropsFile to TRUE.
   *
   * @param filename the filename for the input
   * @see #setExplicitPropsFile(boolean)
   */
  public void setInputFilename(String filename) {
    m_InputFilename = filename;
    setExplicitPropsFile(true);
  }
 
  /**
   * returns the input properties object (template containing the packages)
   *
   * @return    the input properties (the template)
   */
  public Properties getInputProperties() {
    return m_InputProperties;
  }
 
  /**
   * returns the output properties object (structure like the template, but
   * filled with classes instead of packages)
   *
   * @return    the output properties (filled with classes)
   */
  public Properties getOutputProperties() {
    return m_OutputProperties;
  }
 
  /**
   * loads the property file containing the layout and the packages of
   * the output-property-file. The exlcude property file is also read here.
   *
   * @see #m_InputProperties
   * @see #m_InputFilename
   */
  protected void loadInputProperties()  {
    if (VERBOSE)
      System.out.println("Loading '" + getInputFilename() + "'...");
    m_InputProperties = new Properties();
    try {
      File f = new File(getInputFilename());
      if (getExplicitPropsFile() && f.exists())
        m_InputProperties.load(new FileInputStream(getInputFilename()));
      else
        m_InputProperties = Utils.readProperties(getInputFilename());
     
      // excludes
      m_Excludes.clear();
      Properties p = Utils.readProperties(EXCLUDE_FILE);
      Enumeration enm = p.propertyNames();
      while (enm.hasMoreElements()) {
  String name = enm.nextElement().toString();
  // new Hashtable for key
  Hashtable t = new Hashtable();
  m_Excludes.put(name, t);
  t.put(EXCLUDE_INTERFACE, new Vector());
  t.put(EXCLUDE_CLASS, new Vector());
  t.put(EXCLUDE_SUPERCLASS, new Vector());
 
  // process entries
  StringTokenizer tok = new StringTokenizer(p.getProperty(name), ",");
  while (tok.hasMoreTokens()) {
    String item = tok.nextToken();
    // get list
    Vector list = new Vector();
    if (item.startsWith(EXCLUDE_INTERFACE + ":"))
      list = (Vector) t.get(EXCLUDE_INTERFACE);
    else if (item.startsWith(EXCLUDE_CLASS + ":"))
      list = (Vector) t.get(EXCLUDE_CLASS);
    else if (item.startsWith(EXCLUDE_SUPERCLASS))
      list = (Vector) t.get(EXCLUDE_SUPERCLASS);
    // add to list
    list.add(item.substring(item.indexOf(":") + 1));
  }
      }
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * gets whether the dynamic approach should be used or not
   *
   * @return    true if the dynamic approach is to be used
   */
  public boolean useDynamic() {
    if (getInputProperties() == null)
      loadInputProperties();
   
    // check our classloader against the system one - if different then
    // return false (as dynamic classloading only works for classes discoverable
    // in the system classpath
    /*if (!ClassLoader.getSystemClassLoader().equals(this.getClass().getClassLoader())) {
      if (Boolean.parseBoolean(getInputProperties().getProperty(USE_DYNAMIC, "true")) == true) {
        System.out.println("[GenericPropertiesCreator] classloader in use is not the system "
            + "classloader: using static entries in weka/gui/GenericObjectEditor.props rather "
            + "than dynamic class discovery.");
      }
      return false;
    }*/
   
    return Boolean.parseBoolean(
  getInputProperties().getProperty(USE_DYNAMIC, "true"));
  }
 
  /**
   * checks whether the classname is a valid one, i.e., from a public class
   *
   * @param classname   the classname to check
   * @return            whether the classname is a valid one
   */
  protected boolean isValidClassname(String classname) {
    return (classname.indexOf("$") == -1);
  }

  /**
   * Checks whether the classname is a valid one for the given key. This is
   * based on the settings in the Exclude file.
   *
   * @param key         the property key
   * @param classname   the classname to check
   * @return            whether the classname is a valid one
   * @see    #EXCLUDE_FILE
   */
  protected boolean isValidClassname(String key, String classname) {
    boolean  result;
    Class  cls;
    Class  clsCurrent;
    Vector  list;
    int    i;

    result = true;

    // are there excludes for this key?
    if (m_Excludes.containsKey(key)) {
      try {
  clsCurrent = Class.forName(classname);
      }
      catch (Exception e) {
  // we ignore this Exception
  clsCurrent = null;
      }
     
      // interface
      if ((clsCurrent != null) && result) {
  list = (Vector) ((Hashtable) m_Excludes.get(key)).get(EXCLUDE_INTERFACE);
  for (i = 0; i < list.size(); i++) {
    try {
      cls = Class.forName(list.get(i).toString());
      if (ClassDiscovery.hasInterface(cls, clsCurrent)) {
        result = false;
        break;
      }
    }
    catch (Exception e) {
      // we ignore this Exception
    }
  }
      }
     
      // superclass
      if ((clsCurrent != null) && result) {
  list = (Vector) ((Hashtable) m_Excludes.get(key)).get(EXCLUDE_SUPERCLASS);
  for (i = 0; i < list.size(); i++) {
    try {
      cls = Class.forName(list.get(i).toString());
      if (ClassDiscovery.isSubclass(cls, clsCurrent)) {
        result = false;
        break;
      }
    }
    catch (Exception e) {
      // we ignore this Exception
    }
  }
      }
     
      // class
      if ((clsCurrent != null) && result) {
  list = (Vector) ((Hashtable) m_Excludes.get(key)).get(EXCLUDE_CLASS);
  for (i = 0; i < list.size(); i++) {
    try {
      cls = Class.forName(list.get(i).toString());
      if (cls.getName().equals(clsCurrent.getName()))
        result = false;
    }
    catch (Exception e) {
      // we ignore this Exception
    }
  }
      }
    }

    return result;
  }
 
  /**
   * fills in all the classes (based on the packages in the input properties
   * file) into the output properties file
   *    
   * @throws Exception   if something goes wrong
   * @see #m_OutputProperties
   */
  protected void generateOutputProperties() throws Exception {
    Enumeration       keys;
    String            key;
    String            value;
    String            pkg;
    StringTokenizer   tok;
    Vector            classes;
    HashSet           names;
    int               i;
   
    m_OutputProperties = new Properties();
    keys               = m_InputProperties.propertyNames();
    while (keys.hasMoreElements()) {
      key   = keys.nextElement().toString();
      if (key.equals(USE_DYNAMIC))
  continue;
      tok   = new StringTokenizer(m_InputProperties.getProperty(key), ",");
      names = new HashSet();
     
      // get classes for all packages
      while (tok.hasMoreTokens()) {
        pkg = tok.nextToken().trim();
       
        try {
          classes = ClassDiscovery.find(Class.forName(key), pkg);
        }
        catch (Exception e) {
          System.out.println("Problem with '" + key + "': " + e);
          classes = new Vector();
        }
       
        for (i = 0; i < classes.size(); i++) {
          // skip non-public classes
          if (!isValidClassname(classes.get(i).toString()))
            continue;
          // some classes should not be listed for some keys
          if (!isValidClassname(key, classes.get(i).toString()))
            continue;
          names.add(classes.get(i));
        }
      }
     
      // generate list
      value   = "";
      classes = new Vector();
      classes.addAll(names);
      Collections.sort(classes, new StringCompare());
      for (i = 0; i < classes.size(); i++) {
        if (!value.equals(""))
          value += ",";
        value += classes.get(i).toString();
      }
      if (VERBOSE)
        System.out.println(pkg + " -> " + value);
     
      // set value
      m_OutputProperties.setProperty(key, value);
    }
  }
 
  /**
   * stores the generated output properties file
   *
   * @throws Exception  if the saving fails
   * @see #m_OutputProperties
   * @see #m_OutputFilename
   */
  protected void storeOutputProperties() throws Exception {
    if (VERBOSE)
      System.out.println("Saving '" + getOutputFilename() + "'...");
    m_OutputProperties.store(
        new FileOutputStream(getOutputFilename()),
        " Customises the list of options given by the GenericObjectEditor\n# for various superclasses.");
  }
 
  /**
   * generates the props-file for the GenericObjectEditor and stores it
   *
   * @throws Exception  if something goes wrong
   * @see #execute(boolean)
   */
  public void execute() throws Exception {
    execute(true, true);
  }
 
  /**
   * generates the props-file for the GenericObjectEditor
   *
   * @param store true if the generated props should be stored
   * @throws Exception
   */
  public void execute(boolean store) throws Exception {
    execute(store, true);
  }
 
  /**
   * generates the props-file for the GenericObjectEditor and stores it only
   * if the the param <code>store</code> is TRUE. If it is FALSE then the
   * generated properties file can be retrieved via the <code>getOutputProperties</code>
   * method.
   *
   * @param store       if TRUE then the properties file is stored to the stored
   *                    filename
   * @param loadInputProps true if the input properties should be loaded
   * @throws Exception  if something goes wrong
   * @see #getOutputFilename()
   * @see #setOutputFilename(String)
   * @see #getOutputProperties()
   */
  public void execute(boolean store, boolean loadInputProps) throws Exception {
    // read properties file
    if (loadInputProps) {
      loadInputProperties();
    }
   
    // generate the props file
    generateOutputProperties();
   
    // write properties file
    if (store)
      storeOutputProperties();
  }
 
  /**
   * for generating props file:
   * <ul>
   *   <li>
   *     no parameter:
   *     see default constructor
   *   </li>
   *   <li>
   *     1 parameter (i.e., filename):
   *     see default constructor + setOutputFilename(String)
   *   </li>
   *   <li>
   *     2 parameters (i.e, filenames):
   *     see constructor with String argument + setOutputFilename(String)
   *   </li>
   * </ul>
   *
   * @param args  the commandline arguments
   * @throws Exception   if something goes wrong
   * @see #GenericPropertiesCreator()
   * @see #GenericPropertiesCreator(String)
   * @see #setOutputFilename(String)
   */
  public static void main(String[] args) throws Exception {
    GenericPropertiesCreator   c = null;
   
    if (args.length == 0) {
      c = new GenericPropertiesCreator();
    }
    else if (args.length == 1) {
      c = new GenericPropertiesCreator();
      c.setOutputFilename(args[0]);
    }
    else if (args.length == 2) {
      c = new GenericPropertiesCreator(args[0]);
      c.setOutputFilename(args[1]);
    }
    else {
      System.out.println("usage: " + GenericPropertiesCreator.class.getName() + " [<input.props>] [<output.props>]");
      System.exit(1);
    }
   
    c.execute(true);
  }
}
TOP

Related Classes of weka.gui.GenericPropertiesCreator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.