/* * 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.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.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+"."); 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+"."); try { return new XMLOperatorDocBundle(url, resourceName); } catch (Exception e) { LogService.getRoot().log(Level.WARNING, "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); 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); } addOperatorDoc(operatorKey, operatorDocumentation); } catch (XMLException e) { LogService.getRoot().log(Level.WARNING, "Malformed operoator 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."); } /** 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()); } }