Java tutorial
/* * 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/>. */ /* * WekaDatabaseWriter.java * Copyright (C) 2011-2013 University of Waikato, Hamilton, New Zealand */ package adams.flow.sink; import java.util.Hashtable; import weka.core.Instance; import weka.core.Instances; import weka.core.converters.DatabaseSaver; import adams.core.QuickInfoHelper; import adams.core.base.BasePassword; import adams.core.io.PlaceholderFile; import adams.db.DatabaseConnection; /** <!-- globalinfo-start --> * Actor for saving a weka.core.Instances object in a database.<br> * The relation name of the incoming dataset can be used to replace the current filename (path and extension are kept). * <br><br> <!-- globalinfo-end --> * <!-- flow-summary-start --> * Input/output:<br> * - accepts:<br> * weka.core.Instances<br> * weka.core.Instance<br> * <br><br> <!-- flow-summary-end --> * <!-- options-start --> * Valid options are: <br><br> * * <pre>-D <int> (property: debugLevel) * The greater the number the more additional info the scheme may output to * the console (0 = off). * default: 0 * minimum: 0 * </pre> * * <pre>-name <java.lang.String> (property: name) * The name of the actor. * default: WekaDatabaseWriter * </pre> * * <pre>-annotation <adams.core.base.BaseText> (property: annotations) * The annotations to attach to this actor. * default: * </pre> * * <pre>-skip (property: skip) * If set to true, transformation is skipped and the input token is just forwarded * as it is. * </pre> * * <pre>-stop-flow-on-error (property: stopFlowOnError) * If set to true, the flow gets stopped in case this actor encounters an error; * useful for critical actors. * </pre> * * <pre>-url <java.lang.String> (property: URL) * The JDBC URL of the database to query. * </pre> * * <pre>-user <java.lang.String> (property: user) * The user for connecting to the database. * </pre> * * <pre>-password <adams.core.base.BasePassword> (property: password) * The password for the database user. * </pre> * * <pre>-table <java.lang.String> (property: tableName) * The name of the table to store the data in. * default: weka * </pre> * * <pre>-auto-key-generation (property: autoKeyGeneration) * If set to true, a primary key is automatically generated. * </pre> * * <pre>-use-relation-as-table (property: useRelationNameAsTable) * If set to true, the relation name is used as table name. * </pre> * * <pre>-custom-props <adams.core.io.PlaceholderFile> (property: customPropsFile) * Custom properties file to override the default database settings, eg, for * accessing a different type of database; ignored if pointing to a directory. * default: . * </pre> * <!-- options-end --> * * @author fracpete (fracpete at waikato dot ac dot nz) * @version $Revision$ */ public class WekaDatabaseWriter extends AbstractSink { /** for serialization. */ private static final long serialVersionUID = 7509908838736709270L; /** the key for storing the current incremental clusterer in the backup. */ public final static String BACKUP_SAVER = "saver"; /** the database URL to query. */ protected String m_URL; /** the database user to use for connecting. */ protected String m_User; /** the password for the user used for connecting. */ protected BasePassword m_Password; /** protected the name of the table to store the data in. */ protected String m_TableName; /** whether to automatically generate a primary key. */ protected boolean m_AutoKeyGeneration; /** whether to use the relation as table name. */ protected boolean m_UseRelationNameAsTable; /** a custom properties file to use instead of default one. */ protected PlaceholderFile m_CustomPropsFile; /** the database saver. */ protected DatabaseSaver m_Saver; /** * Returns a string describing the object. * * @return a description suitable for displaying in the gui */ @Override public String globalInfo() { return "Actor for saving a weka.core.Instances object in a database.\n" + "The relation name of the incoming dataset can be used to replace the " + "current filename (path and extension are kept)."; } /** * Adds options to the internal list of options. */ @Override public void defineOptions() { super.defineOptions(); m_OptionManager.add("url", "URL", DatabaseConnection.getSingleton().getDefaultURL(), false); m_OptionManager.add("user", "user", DatabaseConnection.getSingleton().getDefaultUser(), false); m_OptionManager.add("password", "password", DatabaseConnection.getSingleton().getDefaultPassword(), false); m_OptionManager.add("table", "tableName", "weka"); m_OptionManager.add("auto-key-generation", "autoKeyGeneration", false); m_OptionManager.add("use-relation-as-table", "useRelationNameAsTable", false); m_OptionManager.add("custom-props", "customPropsFile", new PlaceholderFile(".")); } /** * Resets the actor. */ @Override protected void reset() { super.reset(); m_Saver = null; } /** * Returns a quick info about the actor, which will be displayed in the GUI. * * @return null if no info available, otherwise short string */ @Override public String getQuickInfo() { String result; String value; value = QuickInfoHelper.toString(this, "user", m_User); if (value == null) value = ""; else value += "@"; result = value; result += QuickInfoHelper.toString(this, "URL", m_URL, "@"); value = QuickInfoHelper.toString(this, "customPropsFile", (m_CustomPropsFile.isDirectory() ? null : " (custom props: " + m_CustomPropsFile + ")")); if (value != null) result += value; return result; } /** * Removes entries from the backup. */ @Override protected void pruneBackup() { super.pruneBackup(); pruneBackup(BACKUP_SAVER); } /** * Backs up the current state of the actor before update the variables. * * @return the backup */ @Override protected Hashtable<String, Object> backupState() { Hashtable<String, Object> result; result = super.backupState(); if (m_Saver != null) result.put(BACKUP_SAVER, m_Saver); return result; } /** * Restores the state of the actor before the variables got updated. * * @param state the backup of the state to restore from */ @Override protected void restoreState(Hashtable<String, Object> state) { if (state.containsKey(BACKUP_SAVER)) { m_Saver = (weka.core.converters.DatabaseSaver) state.get(BACKUP_SAVER); state.remove(BACKUP_SAVER); } super.restoreState(state); } /** * Sets the database URL to query. * * @param value the JDBC URL */ public void setURL(String value) { m_URL = value; reset(); } /** * Returns the query to execute. * * @return the query */ public String getURL() { return m_URL; } /** * Returns the tip text for this property. * * @return tip text for this property suitable for * displaying in the GUI or for listing the options. */ public String URLTipText() { return "The JDBC URL of the database to query."; } /** * Sets the database user. * * @param value the user */ public void setUser(String value) { m_User = value; reset(); } /** * Returns the database user. * * @return the user */ public String getUser() { return m_User; } /** * Returns the tip text for this property. * * @return tip text for this property suitable for * displaying in the GUI or for listing the options. */ public String userTipText() { return "The user for connecting to the database."; } /** * Sets the database password. * * @param value the password */ public void setPassword(BasePassword value) { m_Password = value; reset(); } /** * Returns the database password. * * @return the password */ public BasePassword getPassword() { return m_Password; } /** * Returns the tip text for this property. * * @return tip text for this property suitable for * displaying in the GUI or for listing the options. */ public String passwordTipText() { return "The password for the database user."; } /** * Sets the table name to store the data in. * * @param value the table name */ public void setTableName(String value) { m_TableName = value; reset(); } /** * Returns the table name to store the data in. * * @return the table name */ public String getTableName() { return m_TableName; } /** * Returns the tip text for this property. * * @return tip text for this property suitable for * displaying in the GUI or for listing the options. */ public String tableNameTipText() { return "The name of the table to store the data in."; } /** * Sets whether to automatically generate a primary key. * * @param value if true then a primary key is generated */ public void setAutoKeyGeneration(boolean value) { m_AutoKeyGeneration = value; reset(); } /** * Returns whether a primary key is automatically generated. * * @return true if a primary key is generated */ public boolean getAutoKeyGeneration() { return m_AutoKeyGeneration; } /** * Returns the tip text for this property. * * @return tip text for this property suitable for * displaying in the GUI or for listing the options. */ public String autoKeyGenerationTipText() { return "If set to true, a primary key is automatically generated."; } /** * Sets whether to output single Instance objects or just one Instances object. * * @param value if true then a single Instance objects are output */ public void setUseRelationNameAsTable(boolean value) { m_UseRelationNameAsTable = value; reset(); } /** * Returns whether to output single Instance objects or just one Instances * object. * * @return true if single Instance objects are output */ public boolean getUseRelationNameAsTable() { return m_UseRelationNameAsTable; } /** * Returns the tip text for this property. * * @return tip text for this property suitable for * displaying in the GUI or for listing the options. */ public String useRelationNameAsTableTipText() { return "If set to true, the relation name is used as table name."; } /** * Sets the custom properties file to use for initializing the database * setup instead of WEKA's default one. * * @param value the custom props file, ignored if a directory */ public void setCustomPropsFile(PlaceholderFile value) { m_CustomPropsFile = value; reset(); } /** * Returns the custom properties file to use for initializing the database * setup instead of WEKA's default one. * * @return the custom props file, ignored if a directory */ public PlaceholderFile getCustomPropsFile() { return m_CustomPropsFile; } /** * Returns the tip text for this property. * * @return tip text for this property suitable for * displaying in the GUI or for listing the options. */ public String customPropsFileTipText() { return "Custom properties file to override the default database settings, " + "eg, for accessing a different type of database; ignored if pointing " + "to a directory."; } /** * Returns the class that the consumer accepts. * * @return <!-- flow-accepts-start -->weka.core.Instances.class, weka.core.Instance.class<!-- flow-accepts-end --> */ public Class[] accepts() { return new Class[] { Instances.class, Instance.class }; } /** * Executes the flow item. * * @return null if everything is fine, otherwise error message */ @Override protected String doExecute() { String result; Instances data; Instance inst; result = null; if (m_InputToken.getPayload() instanceof Instance) { inst = (Instance) m_InputToken.getPayload(); data = inst.dataset(); } else { data = (Instances) m_InputToken.getPayload(); inst = null; } try { if (m_Saver == null) { m_Saver = new DatabaseSaver(); m_Saver.setUrl(m_URL); m_Saver.setUser(m_User); m_Saver.setPassword(m_Password.getValue()); m_Saver.setTableName(m_TableName); m_Saver.setRelationForTableName(m_UseRelationNameAsTable); m_Saver.setAutoKeyGeneration(m_AutoKeyGeneration); if (!m_CustomPropsFile.isDirectory()) m_Saver.setCustomPropsFile(m_CustomPropsFile.getAbsoluteFile()); } if (inst == null) { m_Saver.setInstances(data); m_Saver.writeBatch(); } else { m_Saver.writeIncremental(inst); } } catch (Exception e) { result = handleException("Failed to write to database: " + m_URL, e); } return result; } /** * Cleans up after the execution has finished. */ @Override public void wrapUp() { m_Saver = null; super.wrapUp(); } }