weka.gui.GenericPropertiesCreator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of weka-dev Show documentation
Show all versions of weka-dev Show documentation
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.
/*
* 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 .
*/
/*
* GenericPropertiesCreator.java
* Copyright (C) 2005-2012 University of Waikato, Hamilton, New Zealand
*
*/
package weka.gui;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.lang.annotation.Annotation;
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;
import weka.core.ClassDiscovery;
import weka.core.ClassDiscovery.StringCompare;
import weka.core.Utils;
import weka.core.WekaPackageManager;
/**
* This class can generate the properties object that is normally loaded from
* the GenericObjectEditor.props
file (= PROPERTY_FILE). It takes
* the GenericPropertiesCreator.props
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).
* E.g. if we want to have all the subclasses of the Classifier
* class then we specify the superclass ("weka.classifiers.Classifier") and the
* packages where to look for ("weka.classifiers.bayes" etc.):
*
*
*
* weka.classifiers.Classifier=\
* weka.classifiers.bayes,\
* weka.classifiers.functions,\
* weka.classifiers.lazy,\
* weka.classifiers.meta,\
* weka.classifiers.trees,\
* weka.classifiers.rules
*
*
*
* This creates the same list as stored in the
* GenericObjectEditor.props
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.
*
* 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).
*
* The dynamic discovery can be turned off via the UseDyanmic
* 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: 11346 $
*/
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
* PROPERTY_FILE
*
* @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 (
* USE_DYNAMIC
= false
)
*
* @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 -> Hashtable(prefix ->
* Vector of classnames)
*/
protected Hashtable>> m_Excludes;
static {
try {
GenericPropertiesCreator creator = new GenericPropertiesCreator();
GLOBAL_CREATOR = creator;
if (creator.useDynamic()
&& !WekaPackageManager.m_initialPackageLoadingInProcess) {
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_INPUT_PROPERTIES = GLOBAL_CREATOR.getInputProperties();
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 = t.get(EXCLUDE_INTERFACE);
} else if (item.startsWith(EXCLUDE_CLASS + ":")) {
list = t.get(EXCLUDE_CLASS);
} else if (item.startsWith(EXCLUDE_SUPERCLASS)) {
list = 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;
try {
clsCurrent = Class.forName(classname);
// check for GPCIgnore
for (Annotation a : clsCurrent.getAnnotations()) {
if (a instanceof GPCIgnore) {
return false;
}
}
} catch (Exception ex) {
clsCurrent = null;
}
// are there excludes for this key?
if (m_Excludes.containsKey(key)) {
// interface
if ((clsCurrent != null) && result) {
list = 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 = 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 = 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 store
is TRUE. If it is FALSE then the generated
* properties file can be retrieved via the getOutputProperties
* 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:
*
* -
* no parameter: see default constructor
* -
* 1 parameter (i.e., filename): see default constructor +
* setOutputFilename(String)
* -
* 2 parameters (i.e, filenames): see constructor with String argument +
* setOutputFilename(String)
*
*
* @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()
+ " [] []");
System.exit(1);
}
c.execute(true);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy