/** * Copyright (C) 2001-2017 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 com.rapidminer.io.process.XMLTools; import com.rapidminer.tools.I18N; import com.rapidminer.tools.LogService; import com.rapidminer.tools.XMLException; 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; /** * 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()); } }