/* * 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.parameter; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import com.rapidminer.tools.LogService; import com.rapidminer.tools.Tools; /** * This class is a collection of the parameter values of a single operator. * Instances of <code>Parameters</code> are created with respect to the * declared list of <code>ParameterTypes</code> of an operator. If parameters * are set using the <code>setParameter()</code> method and the value exceeds * the range, it is automatically corrected. If parameters are queried that are * not set, their default value is returned. * * @author Ingo Mierswa, Simon Fischer * @version $Id: Parameters.java,v 1.8 2008/07/06 09:53:00 ingomierswa Exp $ */ public class Parameters implements Cloneable, Iterable<String> { /** Maps parameter keys (i.e. Strings) to their value (Objects). */ private SortedMap<String, Object> keyToValueMap = new TreeMap<String, Object>(); /** Maps parameter keys (i.e. Strings) to their <code>ParameterType</code>. */ private SortedMap<String, ParameterType> keyToTypeMap = new TreeMap<String, ParameterType>(); /** A list with all keys in insertion order. */ private List<String> keys = new LinkedList<String>(); /** Creates an empty parameters object without any parameter types. */ public Parameters() {} /** * Constructs an instance of <code>Parameters</code> for the given list of * <code>ParameterTypes</code>. The list might be empty but not null. */ public Parameters(List<ParameterType> parameterTypes) { Iterator<ParameterType> i = parameterTypes.iterator(); while (i.hasNext()) { ParameterType type = i.next(); keyToTypeMap.put(type.getKey(), type); keys.add(type.getKey()); } } /** * Copies the values and types of the given Parameters object into this one. * Performs a check if both objects contain the same ParameterTypes. * Especially all parameter types of this object must also be defined in the * given Parameters instance. If a parameter type is missing a * NullPointerException will be thrown. */ public void copy(Parameters parameters) { SortedMap<String, Object> newKey2ValueMap = new TreeMap<String, Object>(); SortedMap<String, ParameterType> newKey2TypeMap = new TreeMap<String, ParameterType>(); Iterator<String> i = keyToTypeMap.keySet().iterator(); while (i.hasNext()) { String key = i.next(); ParameterType newType = parameters.keyToTypeMap.get(key); if (newType == null) throw new NullPointerException("Error during copying a parameters object: the new parameters does not contain '" + key + "'!"); newKey2TypeMap.put(key, newType); } i = keyToValueMap.keySet().iterator(); while (i.hasNext()) { String key = i.next(); try { Object newValue = parameters.getParameter(key); newKey2ValueMap.put(key, newValue); } catch (UndefinedParameterError e) { LogService.getGlobal().log("Parameter '" + key + "' is not set and has no default value: using empty parameter value for copied parameters.", LogService.ERROR); } } this.keyToValueMap = newKey2ValueMap; this.keyToTypeMap = newKey2TypeMap; } /** Performs a deep clone on this parameters object. */ public Object clone() { Parameters clone = new Parameters(); Iterator<String> i = keyToValueMap.keySet().iterator(); while (i.hasNext()) { String key = i.next(); Object value = keyToValueMap.get(key); ParameterType type = keyToTypeMap.get(key); if (type != null) { clone.keyToValueMap.put(key, type.copyValue(value)); } } i = keyToTypeMap.keySet().iterator(); while (i.hasNext()) { String key = i.next(); clone.keyToTypeMap.put(key, keyToTypeMap.get(key)); } return clone; } public Iterator<String> iterator() { return keys.iterator(); } /** Returns the type of the parameter with the given type. */ public ParameterType getParameterType(String key) { return keyToTypeMap.get(key); } /** Sets the parameter for the given key after performing a range-check. */ public void setParameter(String key, Object value) { ParameterType type = keyToTypeMap.get(key); if (type == null) { LogService.getGlobal().log("Illegal key: '" + key + "'", LogService.WARNING); if (value instanceof List) { type = new ParameterTypeList(key, "guessed", new ParameterTypeString(null, null)); } else { type = new ParameterTypeString(key, "guessed"); } keyToTypeMap.put(key, type); } Object transformedValue = type.transformNewValue(value); keyToValueMap.put(key, type.checkValue(transformedValue)); } /** Sets the parameter without performing a range and type check. */ public void setParameterWithoutCheck(String key, Object value) { if (value == null) { keyToValueMap.remove(key); } else { keyToValueMap.put(key, value); } } /** * Returns the value of the given parameter. If it was not yet set, the * default value is set now and a log message is issued. If the * <code>ParameterType</code> does not provide a default value, this may * result in an error message. In subsequent calls of this method, the * parameter will be set. An OperatorException (UserError) will be thrown if * a non-optional parameter was not set. */ public Object getParameter(String key) throws UndefinedParameterError { if (keyToValueMap.containsKey(key)) { return keyToValueMap.get(key); } else { ParameterType type = keyToTypeMap.get(key); if (type == null) { return null; } Object value = type.getDefaultValue(); if ((value == null) && !type.isOptional()) { LogService.getGlobal().log("Parameter '" + key + "' is not set and has no default value.", LogService.ERROR); throw new UndefinedParameterError(key); } else { keyToValueMap.put(key, value); LogService.getGlobal().log("Parameter '" + key + "' is not set. Using default ('" + type.toString(value) + "').", LogService.MINIMUM); } return value; } } /** Returns a set view of all parameter keys. */ public Set<String> getKeys() { return keyToValueMap.keySet(); } /** * Returns true if the given parameters are not null and are the same like * this parameters. */ public boolean equals(Object o) { if (!(o instanceof Parameters)) { return false; } else { String thisXML = this.getXML(""); String otherXML = ((Parameters) o).getXML(""); if (!thisXML.equals(otherXML)) { return false; } return true; } } public int hashCode() { return this.getXML("").hashCode(); } /** * Writes a portion of the xml configuration file specifying the parameters * that differ from their default value. */ public String getXML(String indent) { StringBuffer result = new StringBuffer(); Iterator<String> i = keyToValueMap.keySet().iterator(); while (i.hasNext()) { String key = i.next(); Object value = keyToValueMap.get(key); ParameterType type = keyToTypeMap.get(key); if (type != null) { result.append(type.getXML(indent, key, value, true)); } else { result.append(indent + "<parameter key=\"" + key + "\"\tvalue=\"" + value.toString() + "\"/>" + Tools.getLineSeparator()); } } return result.toString(); } public String toString() { return this.keyToValueMap.toString(); } }