/*
* RapidMiner
*
* Copyright (C) 2001-2008 by Rapid-I and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapid-i.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer;
import java.awt.Frame;
import java.awt.Image;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Locale;
import javax.imageio.ImageIO;
import com.rapidminer.gui.renderer.RendererService;
import com.rapidminer.gui.tools.SplashScreen;
import com.rapidminer.parameter.ParameterType;
import com.rapidminer.parameter.ParameterTypeBoolean;
import com.rapidminer.parameter.ParameterTypeInt;
import com.rapidminer.parameter.ParameterTypeString;
import com.rapidminer.tools.LogService;
import com.rapidminer.tools.ObjectVisualizerService;
import com.rapidminer.tools.OperatorService;
import com.rapidminer.tools.ParameterService;
import com.rapidminer.tools.Tools;
import com.rapidminer.tools.WekaTools;
import com.rapidminer.tools.XMLException;
import com.rapidminer.tools.XMLSerialization;
import com.rapidminer.tools.cipher.CipherTools;
import com.rapidminer.tools.cipher.KeyGenerationException;
import com.rapidminer.tools.cipher.KeyGeneratorTool;
import com.rapidminer.tools.jdbc.DatabaseService;
import com.rapidminer.tools.plugin.Plugin;
/**
* Main program. Entry point for command line programm, GUI and wrappers. Please note
* that applications which use RapidMiner as a data mining library will have to invoke one of the
* init methods provided by this class before applying processes or operators.
* Several init methods exist and choosing the correct one with optimal parameters
* might drastically reduce runtime and / or initialization time.
*
* @author Ingo Mierswa
* @version $Id: RapidMiner.java,v 1.38 2008/08/12 17:23:38 ingomierswa Exp $
*/
public class RapidMiner {
public static final String SYSTEM_ENCODING_NAME = "SYSTEM";
// --- GENERAL PROPERTIES ---
/** The name of the property indicating the home directory of RapidMiner. */
public static final String PROPERTY_RAPIDMINER_HOME = "rapidminer.home";
/** The name of the property indicating the version of RapidMiner. */
public static final String PROPERTY_RAPIDMINER_VERSION = "rapidminer.version";
/** The name of the property indicating the path to an additional operator description XML file. */
public static final String PROPERTY_RAPIDMINER_OPERATORS_ADDITIONAL = "rapidminer.operators.additional";
/** The name of the property indicating the path to an RC file (settings). */
public static final String PROPERTY_RAPIDMINER_RC_FILE = "rapidminer.rcfile";
/** The name of the property indicating the path to the Weka Jar file. */
public static final String PROPERTY_RAPIDMINER_WEKA_JAR = "rapidminer.weka.jar";
/** The name of the property indicating the path to the global logging file. */
public static final String PROPERTY_RAPIDMINER_GLOBAL_LOG_FILE = "rapidminer.global.logging.file";
/** The name of the property indicating the path to the global logging file. */
public static final String PROPERTY_RAPIDMINER_GLOBAL_LOG_VERBOSITY = "rapidminer.global.logging.verbosity";
// --- INIT PROPERTIES ---
/** A file path to an operator description XML file. */
public static final String PROPERTY_RAPIDMINER_INIT_OPERATORS = "rapidminer.init.operators";
/** Boolean parameter indicating if the operators based on Weka should be initialized. */
public static final String PROPERTY_RAPIDMINER_INIT_WEKA = "rapidminer.init.weka";
/** A file path to the directory containing the JDBC drivers (usually the lib/jdbc directory of RapidMiner). */
public static final String PROPERTY_RAPIDMINER_INIT_JDBC_LIB_LOCATION = "rapidminer.init.jdbc.location";
/** Boolean parameter indicating if the drivers located in the lib directory of RapidMiner should be initialized. */
public static final String PROPERTY_RAPIDMINER_INIT_JDBC_LIB = "rapidminer.init.jdbc.lib";
/** Boolean parameter indicating if the drivers located somewhere in the classpath should be initialized. */
public static final String PROPERTY_RAPIDMINER_INIT_JDBC_CLASSPATH = "rapidminer.init.jdbc.classpath";
/** Boolean parameter indicating if the plugins should be initialized at all. */
public static final String PROPERTY_RAPIDMINER_INIT_PLUGINS = "rapidminer.init.plugins";
/** A file path to the directory containing the plugin Jar files. */
public static final String PROPERTY_RAPIDMINER_INIT_PLUGINS_LOCATION = "rapidminer.init.plugins.location";
// --- OTHER PROPERTIES ---
/** The property name for "The number of fraction digits of formatted numbers." */
public static final String PROPERTY_RAPIDMINER_GENERAL_FRACTIONDIGITS_NUMBERS = "rapidminer.general.fractiondigits.numbers";
/** The property name for "The number of fraction digits of formatted percent values." */
public static final String PROPERTY_RAPIDMINER_GENERAL_FRACTIONDIGITS_PERCENT = "rapidminer.general.fractiondigits.percent";
/** The property name for "Path to external Java editor. %f is replaced by filename and %l by the linenumber." */
public static final String PROPERTY_RAPIDMINER_TOOLS_EDITOR = "rapidminer.tools.editor";
/** The property name for "Path to sendmail. Used for email notifications." */
public static final String PROPERTY_RAPIDMINER_TOOLS_SENDMAIL_COMMAND = "rapidminer.tools.sendmail.command";
/** The property name for "Use unix special characters for logfile highlighting (requires new RapidMiner instance)." */
public static final String PROPERTY_RAPIDMINER_GENERAL_LOGFILE_FORMAT = "rapidminer.general.logfile.format";
/** The property name for "Indicates if RapidMiner should be used in debug mode (print exception stacks and shows more technical error messages)" */
public static final String PROPERTY_RAPIDMINER_GENERAL_DEBUGMODE = "rapidminer.general.debugmode";
/** The name of the property indicating the default encoding for files. */
public static final String PROPERTY_RAPIDMINER_GENERAL_DEFAULT_ENCODING = "rapidminer.general.encoding";
public static boolean isInitialized = false;
/**
* A set of some non-gui and operator related system properties (starting with "rapidminer."). Properties
* can be registered using {@link RapidMiner#registerRapidMinerProperty(ParameterType)}.
*/
private static final java.util.Set<ParameterType> PROPERTY_TYPES = new java.util.TreeSet<ParameterType>();
static {
System.setProperty(PROPERTY_RAPIDMINER_VERSION, RapidMiner.getLongVersion());
registerRapidMinerProperty(new ParameterTypeInt(PROPERTY_RAPIDMINER_GENERAL_FRACTIONDIGITS_NUMBERS, "The number of fraction digits of formatted numbers.", 0, Integer.MAX_VALUE, 3));
registerRapidMinerProperty(new ParameterTypeInt(PROPERTY_RAPIDMINER_GENERAL_FRACTIONDIGITS_PERCENT, "The number of fraction digits of formatted percent values.", 0, Integer.MAX_VALUE, 2));
registerRapidMinerProperty(new ParameterTypeString(PROPERTY_RAPIDMINER_TOOLS_EDITOR, "Path to external Java editor. %f is replaced by filename and %l by the linenumber.", true));
registerRapidMinerProperty(new ParameterTypeString(PROPERTY_RAPIDMINER_TOOLS_SENDMAIL_COMMAND, "Path to sendmail. Used for email notifications.", true));
registerRapidMinerProperty(new ParameterTypeBoolean(PROPERTY_RAPIDMINER_GENERAL_LOGFILE_FORMAT, "Use unix special characters for logfile highlighting (requires new RapidMiner instance).", false));
registerRapidMinerProperty(new ParameterTypeBoolean(PROPERTY_RAPIDMINER_GENERAL_DEBUGMODE, "Indicates if RapidMiner should be used in debug mode (print exception stacks and shows more technical error messages)", false));
registerRapidMinerProperty(new ParameterTypeString(PROPERTY_RAPIDMINER_GENERAL_DEFAULT_ENCODING, "The default encoding used for file operations (default: 'SYSTEM' uses the underlying system encoding, 'UTF-8' or 'ISO-8859-1' are other common options)", SYSTEM_ENCODING_NAME));
}
private static InputHandler inputHandler = new ConsoleInputHandler();
private static SplashScreen splashScreen;
public static String getShortVersion() {
return Version.getShortVersion();
}
public static String getLongVersion() {
return Version.getLongVersion();
}
/**
* @deprecated Use {@link #readProcessFile(File)} instead
*/
@Deprecated
public static Process readExperimentFile(File experimentfile) throws XMLException, IOException, InstantiationException, IllegalAccessException {
return readProcessFile(experimentfile);
}
public static Process readProcessFile(File processFile) throws XMLException, IOException, InstantiationException, IllegalAccessException {
try {
LogService.getGlobal().log("Reading process file '" + processFile + "'.", LogService.STATUS);
if (!processFile.exists() || !processFile.canRead()) {
LogService.getGlobal().log("Cannot read config file '" + processFile + "'!", LogService.FATAL);
}
return new Process(processFile);
} catch (XMLException e) {
throw new XMLException(processFile.getName() + ":" + e.getMessage());
}
}
/**
* Initializes RapidMiner.
*
* @param operatorsXMLStream the stream to the operators.xml (operator description), use core operators.xml if null
* @param pluginDir the directory where plugins are located, use core plugin directory if null
* @param addWekaOperators inidcates if the operator wrappers for Weka should be loaded
* @param searchJDBCInLibDir indicates if JDBC drivers from the directory RAPID_MINER_HOME/lib/jdbc should be loaded
* @param searchJDBCInClasspath indicates if JDBC drivers from the classpath libraries should be loaded
* @param addPlugins indicates if the plugins should be loaded
*/
public static void init(InputStream operatorsXMLStream,
File pluginDir,
boolean addWekaOperators,
boolean searchJDBCInLibDir,
boolean searchJDBCInClasspath,
boolean addPlugins) {
init(operatorsXMLStream, null, pluginDir, addWekaOperators, searchJDBCInLibDir, searchJDBCInClasspath, addPlugins);
}
/**
* Initializes RapidMiner.
*
* @param operatorsXMLStream the stream to the operators.xml (operator description), use core operators.xml if null
* @param pluginDir the directory where plugins are located, use core plugin directory if null
* @param addWekaOperators inidcates if the operator wrappers for Weka should be loaded
* @param searchJDBCInLibDir indicates if JDBC drivers from the directory RAPID_MINER_HOME/lib/jdbc should be loaded
* @param searchJDBCInClasspath indicates if JDBC drivers from the classpath libraries should be loaded
* @param addPlugins indicates if the plugins should be loaded
*/
public static void init(InputStream operatorsXMLStream,
File pluginDir,
File jdbcDir,
boolean addWekaOperators,
boolean searchJDBCInLibDir,
boolean searchJDBCInClasspath,
boolean addPlugins) {
init(operatorsXMLStream, null, pluginDir, jdbcDir, addWekaOperators, searchJDBCInLibDir, searchJDBCInClasspath, addPlugins);
}
/**
* Initializes RapidMiner.
*
* @param operatorsXMLStream the stream to the core operators.xml (operator description), use core operators.xml if null
* @param additionalXMLStream the stream to possibly additional operators.xml (operator description), use no additional if null
* @param pluginDir the directory where plugins are located, use core plugin directory if null
* @param jdbcDir the directory where the JDBC drivers are located, use core lib/jdbc directory if null
* @param addWekaOperators inidcates if the operator wrappers for Weka should be loaded
* @param searchJDBCInLibDir indicates if JDBC drivers from the directory RAPID_MINER_HOME/lib/jdbc should be loaded
* @param searchJDBCInClasspath indicates if JDBC drivers from the classpath libraries should be loaded
* @param addPlugins indicates if the plugins should be loaded
*/
public static void init(InputStream operatorsXMLStream,
InputStream additionalXMLStream,
File pluginDir,
File jdbcDir,
boolean addWekaOperators,
boolean searchJDBCInLibDir,
boolean searchJDBCInClasspath,
boolean addPlugins) {
isInitialized = true;
// set locale fix to US
RapidMiner.splashMessage("Using US Local");
Locale.setDefault(Locale.US);
// ensure rapidminer.home is set
RapidMiner.splashMessage("Ensure RapidMiner Home is set");
ParameterService.ensureRapidMinerHomeSet();
if (addPlugins) {
RapidMiner.splashMessage("Register Plugins");
Plugin.registerAllPlugins(pluginDir, true);
}
Plugin.initPluginSplashTexts();
RapidMiner.showSplashInfos();
RapidMiner.splashMessage("Init Setup");
// search for Weka
File wekaJar = null;
try {
wekaJar = WekaTools.getWekaJarAsFile();
} catch (Throwable e) {
// do nothing
}
String wekaMessage = addWekaOperators + "";
if ((wekaJar == null) || (!wekaJar.exists())) {
wekaMessage = "weka not found";
addWekaOperators = false;
}
LogService.getGlobal().log("----------------------------------------------------", LogService.INIT);
LogService.getGlobal().log("Initialization Settings", LogService.INIT);
LogService.getGlobal().log("----------------------------------------------------", LogService.INIT);
LogService.getGlobal().log("Default system encoding for IO: " + Tools.getDefaultEncoding(), LogService.INIT);
LogService.getGlobal().log("Load " + (operatorsXMLStream == null ? "core" : "specific") + " operators...", LogService.INIT);
LogService.getGlobal().log("Load Weka operators: " + wekaMessage, LogService.INIT);
LogService.getGlobal().log("Load JDBC drivers from lib directory: " + searchJDBCInLibDir, LogService.INIT);
LogService.getGlobal().log("Load JDBC drivers from classpath: " + searchJDBCInClasspath, LogService.INIT);
LogService.getGlobal().log("Load plugins: " + addPlugins, LogService.INIT);
LogService.getGlobal().log("Load plugins from '" + (pluginDir == null ? ParameterService.getPluginDir() : pluginDir) + "'", LogService.INIT);
LogService.getGlobal().log("----------------------------------------------------", LogService.INIT);
RapidMiner.splashMessage("Initializing Operators");
ParameterService.init(operatorsXMLStream, additionalXMLStream, addWekaOperators);
RapidMiner.splashMessage("Loading JDBC Drivers");
DatabaseService.init(jdbcDir, searchJDBCInLibDir, searchJDBCInClasspath);
RapidMiner.splashMessage("Initialize XML serialization");
XMLSerialization.init(Plugin.getMajorClassLoader());
RapidMiner.splashMessage("Define XML Serialization Alias Pairs");
OperatorService.defineXMLAliasPairs();
// generate encryption key if necessary
if (!CipherTools.isKeyAvailable()) {
RapidMiner.splashMessage("Generate Encryption Key");
try {
KeyGeneratorTool.createAndStoreKey();
} catch (KeyGenerationException e) {
LogService.getGlobal().logError("Cannot generate encryption key: " + e.getMessage());
}
}
// initialize renderers
RapidMiner.splashMessage("Initialize renderers");
RendererService.init();
}
private static void showSplashInfos() {
if (getSplashScreen() != null)
getSplashScreen().setInfosVisible(true);
}
/**
* Initializes RapidMiner.
*
* @param operatorsXMLStream the stream to the operators.xml (operator description), use core operators.xml if null
* @param addWekaOperators inidcates if the operator wrappers for Weka should be loaded
* @param searchJDBCInLibDir indicates if JDBC drivers from the directory RAPID_MINER_HOME/lib/jdbc should be loaded
* @param searchJDBCInClasspath indicates if JDBC drivers from the classpath libraries should be loaded
* @param addPlugins indicates if the plugins should be loaded
*/
public static void init(InputStream operatorsXMLStream,
boolean addWekaOperators,
boolean searchJDBCInLibDir,
boolean searchJDBCInClasspath,
boolean addPlugins) {
init(operatorsXMLStream, null, addWekaOperators, searchJDBCInLibDir, searchJDBCInClasspath, addPlugins);
}
/**
* Initializes RapidMiner with its core operators.
*
* @param addWekaOperators inidcates if the operator wrappers for Weka should be loaded
* @param searchJDBCInLibDir indicates if JDBC drivers from the directory RAPID_MINER_HOME/lib/jdbc should be loaded
* @param searchJDBCInClasspath indicates if JDBC drivers from the classpath libraries should be loaded
* @param addPlugins indicates if the plugins should be loaded
*/
public static void init(boolean addWekaOperators, boolean searchJDBCInLibDir, boolean searchJDBCInClasspath, boolean addPlugins) {
init(null, addWekaOperators, searchJDBCInLibDir, searchJDBCInClasspath, addPlugins);
}
/**
* Initializes RapidMiner. Will use the core operators.xml operator description, all
* available Weka operators, and all JDBC drivers found in the directory
* RAPID_MINER_HOME/lib/jdbc. Will not search for JDBC drivers in other classpath
* libraries. Will use all plugins in the plugins directory.
* Use the method {@link #init(InputStream, File, boolean, boolean, boolean, boolean)}
* for more sophisticated initialization possibilities. Alternatively, you could
* also set the following system properties, e.g. during startup via
* "-Drapidminer.init.weka=false" or with {@link System#setProperty(String, String)}:
* <ul>
* <li>rapidminer.init.operators (file path)</li>
* <li>rapidminer.init.plugins (true or false)</li>
* <li>rapidminer.init.plugins.location (directory path)</li>
* <li>rapidminer.init.weka (true or false)</li>
* <li>rapidminer.init.jdbc.lib (true or false)</li>
* <li>rapidminer.init.jdbc.lib.location (directory path)</li>
* <li>rapidminer.init.jdbc.classpath (true or false)</li>
* </ul>
*/
public static void init() {
File pluginDir = null;
String pluginDirString = System.getProperty(PROPERTY_RAPIDMINER_INIT_PLUGINS_LOCATION);
if (pluginDirString != null)
pluginDir = new File(pluginDirString);
String loadWekaString = System.getProperty(PROPERTY_RAPIDMINER_INIT_WEKA);
boolean loadWeka = Tools.booleanValue(loadWekaString, true);
String loadJDBCDirString = System.getProperty(PROPERTY_RAPIDMINER_INIT_JDBC_LIB);
boolean loadJDBCDir = Tools.booleanValue(loadJDBCDirString, true);
File jdbcDir = null;
String jdbcDirString = System.getProperty(PROPERTY_RAPIDMINER_INIT_JDBC_LIB_LOCATION);
if (jdbcDirString != null)
jdbcDir = new File(jdbcDirString);
String loadJDBCClasspathString = System.getProperty(PROPERTY_RAPIDMINER_INIT_JDBC_CLASSPATH);
boolean loadJDBCClasspath = Tools.booleanValue(loadJDBCClasspathString, false);
String loadPluginsString = System.getProperty(PROPERTY_RAPIDMINER_INIT_PLUGINS);
boolean loadPlugins = Tools.booleanValue(loadPluginsString, true);
InputStream operatorStream = null;
try {
String operatorsXML = System.getProperty(PROPERTY_RAPIDMINER_INIT_OPERATORS);
if (operatorsXML != null) {
operatorStream = new FileInputStream(operatorsXML);
}
init(operatorStream, pluginDir, jdbcDir, loadWeka, loadJDBCDir, loadJDBCClasspath, loadPlugins);
} catch (IOException e) {
// do nothing
} finally {
if (operatorStream != null) {
try {
operatorStream.close();
} catch (IOException e) {
}
}
}
}
/** Cleans up the object visualizers available for this process and clears the
* current temp directory. This method should be performed in cases where RapidMiner
* is embedded into other applications and only single operators (in contrast to
* a complete process) are performed within several runs, e.g. in a loop.
*
* TODO: bind object visualizers and temp file service to a
* process instead of managing these things in a static way.
*/
public static void cleanUp() {
ObjectVisualizerService.clearVisualizers();
}
public static SplashScreen showSplash() {
URL url = Tools.getResource("rapidminer_logo.png");
Image logo = null;
try {
if (url != null) {
logo = ImageIO.read(url);
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return showSplash(logo);
}
public static SplashScreen showSplash(Image productLogo) {
RapidMiner.splashScreen = new SplashScreen(getShortVersion(), productLogo);
RapidMiner.splashScreen.showSplashScreen();
return RapidMiner.splashScreen;
}
public static void hideSplash() {
RapidMiner.splashScreen.dispose();
}
public static void splashMessage(String message) {
if (RapidMiner.splashScreen != null) {
RapidMiner.splashScreen.setMessage(message);
}
}
public static SplashScreen getSplashScreen() {
return RapidMiner.splashScreen;
}
public static Frame getSplashScreenFrame() {
if (RapidMiner.splashScreen != null)
return RapidMiner.splashScreen.getSplashScreenFrame();
else
return null;
}
public static void setInputHandler(InputHandler inputHandler) {
RapidMiner.inputHandler = inputHandler;
}
public static InputHandler getInputHandler() {
return inputHandler;
}
/** Returns a set of {@link ParameterType}s for the RapidMiner system properties.
* @deprecated Use {@link #getRapidMinerProperties()} instead*/
@Deprecated
public static java.util.Set<ParameterType> getYaleProperties() {
return getRapidMinerProperties();
}
/** Returns a set of {@link ParameterType}s for the RapidMiner system properties. */
public static java.util.Set<ParameterType> getRapidMinerProperties() {
return PROPERTY_TYPES;
}
/**
* @deprecated Use {@link #registerRapidMinerProperty(ParameterType)} instead
*/
@Deprecated
public static void registerYaleProperty(ParameterType type) {
registerRapidMinerProperty(type);
}
public static void registerRapidMinerProperty(ParameterType type) {
PROPERTY_TYPES.add(type);
}
public static void quit(int errorcode) {
try {
Runtime.getRuntime().runFinalization();
} catch (Exception e) {
System.err.println("ERROR during SHUTDOWN: " + e.getMessage());
}
System.exit(errorcode);
}
public static boolean isInitialized() {
return isInitialized;
}
}