/* * 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.Collection; 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; import com.rapidminer.tools.container.Pair; /** * This is a parameter type that contains a number of subtypes. But unlike the * {@link ParameterTypeList} or {@link ParameterTypeEnumeration}, these subtypes * are treated as one value. * In the gui these subtypes are shown beside each other. * * @author Sebastian Land */ public class ParameterTypeTupel extends CombinedParameterType { private static final long serialVersionUID = 7292052301201204321L; private static final String ELEMENT_CHILD_TYPE = "ChildType"; private static final String ELEMENT_CHILD_TYPES = "ChildTypes"; private static final String ELEMENT_DEFAULT_ENTRIES = "DefaultEntries"; private static final String ELEMENT_DEFAULT_ENTRY = "Entry"; private static final String ATTRIBUTE_IS_NULL = "is-null"; // // only one character allowed // private static final String ESCAPE_CHAR = "\\"; // private static final String ESCAPE_CHAR_REGEX = "\\\\"; // // only one character allowed // private static final String SEPERATOR_CHAR_REGEX = "\\."; private static final char ESCAPE_CHAR = '\\'; private static final char XML_SEPERATOR_CHAR = '.'; private static final char[] XML_SPECIAL_CHARACTERS = new char[] { XML_SEPERATOR_CHAR }; private static final char INTERNAL_SEPERATOR_CHAR = '.'; //Parameters.PAIR_SEPARATOR; //'.'; private static final char[] INTERNAL_SPECIAL_CHARACTERS = new char[] { INTERNAL_SEPERATOR_CHAR }; private Object[] defaultValues = null; private ParameterType[] types; public ParameterTypeTupel(Element element) throws XMLException { super(element); Element childTypesElement = XMLTools.getChildElement(element, ELEMENT_CHILD_TYPES, true); Collection<Element> childTypeElements = XMLTools.getChildElements(childTypesElement, ELEMENT_CHILD_TYPE); types = new ParameterType[childTypeElements.size()]; int i = 0; for (Element childTypeElement: childTypeElements) { types[i] = ParameterType.createType(childTypeElement); i++; } // now default values Element defaultEntriesElement = XMLTools.getChildElement(element, ELEMENT_DEFAULT_ENTRIES, true); Collection<Element> defaultEntryElements = XMLTools.getChildElements(defaultEntriesElement, ELEMENT_DEFAULT_ENTRY); defaultValues = new Object[defaultEntryElements.size()]; i = 0; for (Element entryElement: defaultEntryElements) { if (entryElement.hasAttribute(ATTRIBUTE_IS_NULL) && Boolean.valueOf(entryElement.getAttribute(ATTRIBUTE_IS_NULL))) defaultValues[i] = null; else defaultValues[i] = entryElement.getTextContent(); i++; } } public ParameterTypeTupel(String key, String description, ParameterType...parameterTypes) { super(key, description, parameterTypes); this.types = parameterTypes; } @Override public Object getDefaultValue() { if (defaultValues == null) { String[] defaultValues = new String[types.length]; for (int i = 0; i < types.length; i++) { defaultValues[i] = types[i].getDefaultValue() == null ? "" : types[i].getDefaultValue() + ""; } return ParameterTypeTupel.transformTupel2String(defaultValues); } else { String[] defStrings = new String[defaultValues.length]; for(int i = 0; i < defaultValues.length; i++) { defStrings[i] = defaultValues[i] + ""; } return ParameterTypeTupel.transformTupel2String(defStrings); } } @Override public String getDefaultValueAsString() { String[] defaultStrings = new String[types.length]; for (int i = 0; i < types.length; i++) { Object defaultValue = types[i].getDefaultValue(); // if (defaultValue == null) // return null; defaultStrings[i] = types[i].toString(defaultValue); } return ParameterTypeTupel.transformTupel2String(defaultStrings); } @Override public String getRange() { return "tupel"; } @SuppressWarnings("unchecked") @Override public Element getXML(String key, String value, boolean hideDefault, Document doc) { Element element = doc.createElement("parameter"); element.setAttribute("key", key); String[] tupel; if (value == null) { Pair<String, String> defltValue = (Pair<String, String>)getDefaultValue(); tupel = new String[] { defltValue.getFirst(), defltValue.getSecond() }; } else { tupel = transformString2Tupel(value); } StringBuilder valueString = new StringBuilder(); boolean first = true; for (String part : tupel) { if (!first) { valueString.append(XML_SEPERATOR_CHAR); } else { first = false; } if (part == null) { part = ""; } valueString.append(Tools.escape(part, ESCAPE_CHAR, XML_SPECIAL_CHARACTERS)); } // String valueString = value; // if (value == null) { // valueString = transformTupel2String((Pair<String, String>)getDefaultValue()); // } element.setAttribute("value", valueString.toString()); return element; } @SuppressWarnings("unchecked") @Override public String getXML(String indent, String key, String value, boolean hideDefault) { StringBuffer result = new StringBuffer(); String valueString = value; if (value == null) { valueString = transformTupel2String((Pair<String, String>)getDefaultValue()); } result.append(indent + "<parameter key=\"" + key + "\" value=\"" + valueString + "\" />" + Tools.getLineSeparator()); return result.toString(); } @Override public boolean isNumerical() { return false; } @Override public void setDefaultValue(Object defaultValue) { this.defaultValues = (Object[]) defaultValue; } public ParameterType getFirstParameterType() { return types[0]; } public ParameterType getSecondParameterType() { return types[1]; } public ParameterType[] getParameterTypes() { return types; } public static String[] transformString2Tupel(String parameterValue) { if (parameterValue == null || parameterValue.isEmpty()){ return new String[2]; } List<String> split = Tools.unescape(parameterValue, ESCAPE_CHAR, INTERNAL_SPECIAL_CHARACTERS, INTERNAL_SEPERATOR_CHAR); while (split.size() < 2) { split.add(null); } return split.toArray(new String[split.size()]); } public static String transformTupel2String(String firstValue, String secondValue) { return Tools.escape(firstValue, ESCAPE_CHAR, INTERNAL_SPECIAL_CHARACTERS) + INTERNAL_SEPERATOR_CHAR + Tools.escape(secondValue, ESCAPE_CHAR, INTERNAL_SPECIAL_CHARACTERS); } public static String transformTupel2String(Pair<String, String> pair) { return transformTupel2String(pair.getFirst(), pair.getSecond()); } public static String transformTupel2String(String[] tupel) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < tupel.length; i++) { if (i > 0) { builder.append(INTERNAL_SEPERATOR_CHAR); } if (tupel[i] != null) { builder.append(Tools.escape(tupel[i], ESCAPE_CHAR, INTERNAL_SPECIAL_CHARACTERS)); } } return builder.toString(); } @Override public String notifyOperatorRenaming(String oldOperatorName, String newOperatorName, String parameterValue) { String[] tupel = transformString2Tupel(parameterValue); for (int i = 0; i < types.length; i++) { tupel[i] = types[i].notifyOperatorRenaming(oldOperatorName, newOperatorName, tupel[i]); } return transformTupel2String(tupel); } @Override public String transformNewValue(String value) { List<String> split = Tools.unescape(value, ESCAPE_CHAR, XML_SPECIAL_CHARACTERS, XML_SEPERATOR_CHAR); StringBuilder internalEncoded = new StringBuilder(); boolean first = true; for (String part : split) { if (!first) { internalEncoded.append(INTERNAL_SEPERATOR_CHAR); } else { first = false; } internalEncoded.append(Tools.escape(part, ESCAPE_CHAR, INTERNAL_SPECIAL_CHARACTERS)); } return internalEncoded.toString(); } public static String escapeForInternalRepresentation(String string) { return Tools.escape(string, ESCAPE_CHAR, INTERNAL_SPECIAL_CHARACTERS); } @Override public String substituteMacros(String parameterValue, MacroHandler mh) { if (parameterValue.indexOf("%{") == -1) { return parameterValue; } String[] tupel = transformString2Tupel(parameterValue); String[] result = new String[tupel.length]; for (int i = 0; i < tupel.length; i++) { result[i] = types[i].substituteMacros(tupel[i], mh); } return transformTupel2String(result); } @Override protected void writeDefinitionToXML(Element typeElement) { Element childTypesElement = XMLTools.addTag(typeElement, ELEMENT_CHILD_TYPES); for (ParameterType type: types) { Element childTypeElement = XMLTools.addTag(childTypesElement, ELEMENT_CHILD_TYPE); type.writeDefinitionToXML(childTypeElement); } // now default list Element defaultEntriesElement = XMLTools.addTag(typeElement, ELEMENT_DEFAULT_ENTRIES); for (Object defaultValue: defaultValues) { Element defaultEntryElement = XMLTools.addTag(defaultEntriesElement, ELEMENT_DEFAULT_ENTRY); if (defaultValue != null && defaultValue instanceof String) { defaultEntryElement.setTextContent(defaultValue.toString()); } else { defaultEntriesElement.setAttribute(ATTRIBUTE_IS_NULL, "true"); } } } }