/*
* RapidMiner
*
* Copyright (C) 2001-2014 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.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.tools.documentation;
import java.io.IOException;
import java.net.URL;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;
import java.util.logging.Level;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import com.rapidminer.io.process.XMLTools;
import com.rapidminer.tools.I18N;
import com.rapidminer.tools.LogService;
import com.rapidminer.tools.XMLException;
/** A resource bundle that maps operator names to {@link OperatorDocumentation} instances.
* Instances of this class always return {@link OperatorDocumentation}s from their
* {@link #getObject(String)} methods.
*
* The XML structure of the documentation is as follows: For every operator there is a tag
* <pre>
* <operator>
* <synopsis>SYNOPSIS</synopsis>
* <help>LONG HELP TEXT</help>
* <example>
* <process>XML process string</process>
* <comment>COMMENT</comment>
* </example>
* <example>
* ...
* </example>
* </operator>
* </pre>
* @author Simon Fischer
*
*/
public class XMLOperatorDocBundle extends OperatorDocBundle {
/** Control to load XML files. Code is largely stolen from the javadoc of
* {@link Control}.
*
* @author Simon Fischer
*
*/
private static class XMLControl extends Control {
@Override
public List<String> getFormats(String baseName) {
if (baseName == null) {
throw new NullPointerException("baseName is null.");
}
return Arrays.asList("xml");
}
@Override
public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IllegalAccessException, InstantiationException, IOException {
if ((baseName == null) || (locale == null) || (format == null) || (loader == null)) {
throw new NullPointerException();
}
//LogService.getRoot().fine("Looking up operator documentation for "+baseName+", locale "+locale+".");
LogService.getRoot().log(Level.FINE, "com.rapidminer.tools.documentation.XMLOperatorDocBundle.looking_up_operator_documentation",
new Object[] {baseName, locale});
if (format.equals("xml")) {
String bundleName = toBundleName(baseName, locale);
String resourceName = toResourceName(bundleName, format);
URL url = loader.getResource(resourceName);
if (url != null) {
//LogService.getRoot().config("Loading operator documentation from "+url+".");
LogService.getRoot().log(Level.CONFIG, "com.rapidminer.tools.documentation.XMLOperatorDocBundle.loading_operator_documentation", url);
try {
return new XMLOperatorDocBundle(url, resourceName);
} catch (Exception e) {
//LogService.getRoot().log(Level.WARNING, "Exception creating OperatorDocBundle: "+e, e);
LogService.getRoot().log(Level.WARNING,
I18N.getMessage(LogService.getRoot().getResourceBundle(),
"com.rapidminer.tools.documentation.XMLOperatorDocBundle.exception_creating_operatordocbundle",
e),
e);
return null;
}
}
}
return null;
}
}
/** Constructs a new OperatorDocBundle
*
* @param url The URL from which we are reading.
* @param resourceName The original resource name. This is the last part of the path of the URL and will be used to locate the source file,
* when this bundle is saved.
* @throws IOException
*/
public XMLOperatorDocBundle(URL url, String resourceName) throws IOException {
Document document;
try {
document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(url.openStream());
} catch (SAXException e) {
throw new IOException("Malformed XML operator help bundle: "+e, e);
} catch (ParserConfigurationException e) {
//LogService.getRoot().log(Level.WARNING, "Cannot create XML parser: "+e, e);
LogService.getRoot().log(Level.WARNING,
I18N.getMessage(LogService.getRoot().getResourceBundle(),
"com.rapidminer.tools.documentation.XMLOperatorDocBundle.creating_xml_parser_error",
e),
e);
return;
}
NodeList helpElements = document.getDocumentElement().getElementsByTagName("operator");
for (int i = 0; i < helpElements.getLength(); i++) {
Element element = (Element)helpElements.item(i);
OperatorDocumentation operatorDocumentation = new OperatorDocumentation(this, element);
try {
String operatorKey = XMLTools.getTagContents(element, "key", false);
if (operatorKey == null) {
operatorKey = XMLTools.getTagContents(element, "name", true);
//LogService.getRoot().fine("Operator help is missing <key> tag. Using <name> as <key>: "+operatorKey);
LogService.getRoot().log(Level.FINE, "com.rapidminer.tools.documentation.XMLOperatorDocBundle.missing_operator_help", operatorKey);
}
addOperatorDoc(operatorKey, operatorDocumentation);
} catch (XMLException e) {
//LogService.getRoot().log(Level.WARNING, "Malformed operoator documentation: "+e, e);
LogService.getRoot().log(Level.WARNING,
I18N.getMessage(LogService.getRoot().getResourceBundle(),
"com.rapidminer.tools.documentation.XMLOperatorDocBundle.malformed_operator_documentation",
e),
e);
}
}
NodeList groupElements = document.getDocumentElement().getElementsByTagName("group");
for (int i = 0; i < groupElements.getLength(); i++) {
Element element = (Element)groupElements.item(i);
GroupDocumentation doc = new GroupDocumentation(element);
addGroupDoc(doc.getKey(), doc);
}
//LogService.getRoot().fine("Loaded documentation for "+ helpElements.getLength() +" operators and " + groupElements.getLength() + " groups.");
LogService.getRoot().log(Level.FINE, "com.rapidminer.tools.documentation.XMLOperatorDocBundle.loaded_documentation",
new Object[] {helpElements.getLength(), groupElements.getLength()});
}
/** Loads the default "OperatorDoc.xml" file from the given resource base name. */
public static OperatorDocBundle load(ClassLoader classLoader, String resource) {
return (OperatorDocBundle) ResourceBundle.getBundle(resource, Locale.getDefault(), classLoader, new XMLControl());
}
}