/* * RapidMiner * * Copyright (C) 2001-2011 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 org.w3c.dom.Document; import org.w3c.dom.Element; import com.rapidminer.MacroHandler; import com.rapidminer.io.process.XMLTools; import com.rapidminer.tools.Tools; import com.rapidminer.tools.XMLException; /** * A parameter type for parameter lists. Operators ask for the list of the specified values with * {@link com.rapidminer.operator.Operator#getParameterList(String)}. Please note that in principle arbitrary parameter * types can be used for the list values. Internally, however, all values are transformed to strings. Therefore, * operators retrieving values from non-string lists (for example for a parameter type category) have to transform the * values themself, e.g. with the following code:<br/> * <br/> * * <code>int index = ((ParameterTypeCategory)((ParameterTypeList)getParameters().getParameterType(PARAMETER_LIST)).getValueType()).getIndex(pair[1]);</code> * * @author Ingo Mierswa, Simon Fischer */ public class ParameterTypeList extends CombinedParameterType { private static final long serialVersionUID = -6101604413822993455L; private static final String ELEMENT_KEY_TYPE = "KeyType"; private static final String ELEMENT_VALUE_TYPE = "ValueType"; private static final String ELEMENT_DEFAULT_ENTRIES = "DefaultEntries"; private static final String ELEMENT_ENTRY= "Entry"; private static final String ATTRIBUTE_KEY= "key"; private static final String ATTRIBUTE_VALUE= "value"; private List<String[]> defaultList = new LinkedList<String[]>(); private final ParameterType valueType; private final ParameterType keyType; public ParameterTypeList(Element element) throws XMLException { super(element); valueType = ParameterType.createType(XMLTools.getChildElement(element, ELEMENT_VALUE_TYPE, true)); keyType = ParameterType.createType(XMLTools.getChildElement(element, ELEMENT_KEY_TYPE, true)); // now default values Element defaultEntriesElement = XMLTools.getChildElement(element, ELEMENT_DEFAULT_ENTRIES, true); for (Element entryElement: XMLTools.getChildElements(defaultEntriesElement, ELEMENT_ENTRY)) { defaultList.add(new String[] {entryElement.getAttribute(ATTRIBUTE_KEY), entryElement.getAttribute(ATTRIBUTE_VALUE)}); } } @Deprecated /** * This constructor is deprecated, because it does not provide enough information for user guidance */ public ParameterTypeList(String key, String description, ParameterType valueType) { this(key, description, valueType, new LinkedList<String[]>()); } @Deprecated /** * This constructor is deprecated, because it does not provide enough information for user guidance */ public ParameterTypeList(String key, String description, ParameterType valueType, List<String[]> defaultList) { super(key, description); this.defaultList = defaultList; this.valueType = valueType; this.keyType = new ParameterTypeString(key, description); if (valueType.getDescription() == null) valueType.setDescription(description); } public ParameterTypeList(String key, String description, ParameterType keyType, ParameterType valueType, boolean expert) { this(key, description, keyType, valueType, new LinkedList<String[]>()); setExpert(expert); } public ParameterTypeList(String key, String description, ParameterType keyType, ParameterType valueType) { this(key, description, keyType, valueType, new LinkedList<String[]>()); } public ParameterTypeList(String key, String description, ParameterType keyType, ParameterType valueType, List<String[]> defaultList, boolean expert) { this(key, description, keyType, valueType, defaultList); setExpert(expert); } public ParameterTypeList(String key, String description, ParameterType keyType, ParameterType valueType, List<String[]> defaultList) { super(key, description, keyType, valueType); this.defaultList = defaultList; this.valueType = valueType; this.keyType = keyType; } public ParameterType getValueType() { return valueType; } public ParameterType getKeyType() { return keyType; } @Override public Object getDefaultValue() { return defaultList; } @SuppressWarnings("unchecked") @Override // TODO: Introduce Typing?? public void setDefaultValue(Object defaultValue) { this.defaultList = (List<String[]>) defaultValue; } /** Returns false. */ @Override public boolean isNumerical() { return false; } @Override public Element getXML(String key, String value, boolean hideDefault, Document doc) { Element element = doc.createElement("list"); element.setAttribute("key", key); List list = null; if (value != null) { list = transformString2List(value); } else { list = (List) getDefaultValue(); } if (list != null) { for (Object object : list) { Object[] entry = (Object[]) object; element.appendChild(valueType.getXML((String) entry[0], entry[1].toString(), false, doc)); } } return element; } /** @deprecated Replaced by DOM. */ @Override @Deprecated public String getXML(String indent, String key, String value, boolean hideDefault) { StringBuffer result = new StringBuffer(); result.append(indent + "<list key=\"" + key + "\">" + Tools.getLineSeparator()); if (value != null) { List list = Parameters.transformString2List(value); Iterator i = list.iterator(); while (i.hasNext()) { Object[] current = (Object[]) i.next(); result.append(valueType.getXML(indent + " ", (String) current[0], current[1].toString(), false)); } } else { Object defaultValue = getDefaultValue(); if (defaultValue != null) { List defaultList = (List) defaultValue; Iterator i = defaultList.iterator(); while (i.hasNext()) { Object[] current = (Object[]) i.next(); result.append(valueType.getXML(indent + " ", (String) current[0], current[1].toString(), false)); } } } result.append(indent + "</list>" + Tools.getLineSeparator()); return result.toString(); } @Override public String getRange() { return "list"; } @SuppressWarnings("unchecked") @Override public String toString(Object value) { if (value instanceof String) return transformList2String(transformString2List(value.toString())); else return transformList2String((List<String[]>) value); } public static String transformList2String(List<String[]> parameterList) { StringBuffer result = new StringBuffer(); Iterator<String[]> i = parameterList.iterator(); boolean first = true; while (i.hasNext()) { String[] objects = i.next(); if (objects.length != 2) continue; String firstToken = objects[0]; String secondToken = objects[1]; if (!first) result.append(Parameters.RECORD_SEPARATOR); if (secondToken != null) { if (firstToken != null) { result.append(firstToken); } result.append(Parameters.PAIR_SEPARATOR); if (secondToken != null) { result.append(secondToken); } } first = false; } return result.toString(); } public static List<String[]> transformString2List(String listString) { List<String[]> result = new LinkedList<String[]>(); String[] splittedList = listString.split(Character.valueOf(Parameters.RECORD_SEPARATOR).toString()); for (String record : splittedList) { if (record.length() > 0) { String[] pair = record.split(Character.valueOf(Parameters.PAIR_SEPARATOR).toString()); if (pair.length == 2 && pair[0].length() > 0 && pair[1].length() > 0) result.add(new String[] { pair[0], pair[1] }); } } return result; } @Override public String notifyOperatorRenaming(String oldOperatorName, String newOperatorName, String parameterValue) { List<String[]> list = transformString2List(parameterValue); for (String[] pair : list) { pair[0] = keyType.notifyOperatorRenaming(oldOperatorName, newOperatorName, pair[0]); pair[1] = valueType.notifyOperatorRenaming(oldOperatorName, newOperatorName, pair[1]); } return transformList2String(list); } @Override public String substituteMacros(String parameterValue, MacroHandler mh) { if (parameterValue.indexOf("%{") == -1) { return parameterValue; } List<String[]> list = transformString2List(parameterValue); List<String[]> result = new LinkedList<String[]>(); for (String[] entry : list) { result.add(new String[] { getKeyType().substituteMacros(entry[0], mh), getValueType().substituteMacros(entry[1], mh) }); } return transformList2String(result); } @Override protected void writeDefinitionToXML(Element typeElement) { Element keyTypeElement = XMLTools.addTag(typeElement, ELEMENT_KEY_TYPE); keyType.writeDefinitionToXML(keyTypeElement); Element valueTypeElement = XMLTools.addTag(typeElement, ELEMENT_VALUE_TYPE); valueType.writeDefinitionToXML(valueTypeElement); // now default list Element defaultEntriesElement = XMLTools.addTag(typeElement, ELEMENT_DEFAULT_ENTRIES); for (String[] pair: defaultList) { Element defaultEntryElement = XMLTools.addTag(defaultEntriesElement, ELEMENT_ENTRY); defaultEntryElement.setAttribute(ATTRIBUTE_KEY, pair[0]); defaultEntryElement.setAttribute(ATTRIBUTE_VALUE, pair[1]); } } }