Mercurial > hg > release > thermostat-0.9
changeset 955:9a0cd2dcf73c
Add tools and templates to generate plugin documentation
Reviewed-by: vanaltj
Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-January/005434.html
PR 1255
line wrap: on
line diff
--- a/annotations/pom.xml Wed Feb 06 11:40:45 2013 -0500 +++ b/annotations/pom.xml Thu Feb 07 12:05:12 2013 -0500 @@ -76,12 +76,34 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> - <configuration> - <!-- dont try to run the annotation process on this module - it will pick up the service file and try to run the (not yet - compiled) annotation processor and fail mysteriously --> - <compilerArgument>-proc:none</compilerArgument> - </configuration> + <!-- compile in 2 steps --> + <executions> + <execution> + <!-- Step 1: only compile annotation processors and do not run any annotation processors --> + <id>default-compile</id> + <configuration> + <compilerArgument>-proc:none</compilerArgument> + <includes> + <include>**/internal/**</include> + </includes> + </configuration> + </execution> + <execution> + <!-- Step 2: after compiling annotation processors, compile everything else using them --> + <id>compile-everything-else</id> + <phase>compile</phase> + <goals> + <goal>compile</goal> + </goals> + <configuration> + <compilerArguments> + <!-- only use the self annotation processor here instead of the PluginAnnotationProcessor + only meta-docs for the annotations should be generated --> + <processor>com.redhat.thermostat.annotations.internal.SelfAnnotationProcessor</processor> + </compilerArguments> + </configuration> + </execution> + </executions> </plugin> </plugins>
--- a/annotations/src/main/java/com/redhat/thermostat/annotations/internal/AnnotationProcessor.java Wed Feb 06 11:40:45 2013 -0500 +++ b/annotations/src/main/java/com/redhat/thermostat/annotations/internal/AnnotationProcessor.java Thu Feb 07 12:05:12 2013 -0500 @@ -47,9 +47,6 @@ import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.annotation.processing.SupportedSourceVersion; -import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.tools.Diagnostic.Kind; @@ -57,15 +54,29 @@ import javax.tools.StandardLocation; /** - * An annotation processor that runs and finds @Service and @ExtensionPoint - * annotations. A list of classes using these annotations are written to - * a <code>META-INF/thermostat/plugin-docs.xml<code> file. + * An annotation processor that runs and finds {@code @Service} and + * {@code @ExtensionPoint} annotations. A list of classes using these + * annotations are written to a + * {@code META-INF/thermostat/plugin-docs.xml} file. */ -@SupportedAnnotationTypes("com.redhat.thermostat.*") -@SupportedSourceVersion(SourceVersion.RELEASE_7) public class AnnotationProcessor extends AbstractProcessor { - private enum ExposedAs { EXTENSION_POINT, SERVICE } + private enum ExposedAs { + META("meta"), + EXTENSION_POINT("extension-point"), + SERVICE("service"), + ; + + private String elementName; + + private ExposedAs(String elementName) { + this.elementName = elementName; + } + + private String getElementName() { + return elementName; + } + } private boolean firstRound = false; @@ -120,6 +131,8 @@ exposedType = ExposedAs.SERVICE; } else if (annotation.getSimpleName().toString().contains("ExtensionPoint")) { exposedType = ExposedAs.EXTENSION_POINT; + } else if (annotation.getSimpleName().toString().contains("Documented")) { + exposedType = ExposedAs.META; } else { processingEnv.getMessager().printMessage(Kind.WARNING, "Unrecognized annotation: " + annotation.getSimpleName()); continue; @@ -135,22 +148,27 @@ } private void writeXml(PrintWriter writer, List<PluginPointInformation> points) { - writer.println("<?xml?>"); + JavadocToXmlConverter converter = new JavadocToXmlConverter(); + + writer.println("<?xml version=\"1.0\"?>"); writer.println("<!-- autogenerated by " + this.getClass().getName() + " -->"); + writer.println(" <plugin-docs>"); for (PluginPointInformation info: points) { - String tag = info.exposedAs == ExposedAs.SERVICE ? "service" : "extension-point"; + String tag = info.exposedAs.getElementName(); - writer.println(" <" + tag + ">"); - writer.println(" <name>" + info.annotatedClass.getQualifiedName() + "</name>"); + writer.println(" <" + tag + ">"); + writer.println(" <name>" + info.annotatedClass.getQualifiedName() + "</name>"); if (info.javadoc != null) { - writer.println(" <doc><![CDATA["); - writer.println(info.javadoc); - writer.println("]]></doc>"); + writer.println(" <doc>"); + writer.println(converter.convert(info.javadoc)); + writer.println(" </doc>"); } - writer.println(" </" + tag + ">"); + writer.println(" </" + tag + ">"); } + + writer.println(" </plugin-docs>"); } private static class PluginPointInformation {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/annotations/src/main/java/com/redhat/thermostat/annotations/internal/JavadocToXmlConverter.java Thu Feb 07 12:05:12 2013 -0500 @@ -0,0 +1,88 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.annotations.internal; + +/** + * Converts javadoc comments into valid html-like xml. + * <p> + * Used to generate documentation. + */ +class JavadocToXmlConverter { + + // TODO get rid of this once we use JEP 106 + + /** + * Perform an ad-hoc set of conversions to convert the javadoc input string + * into something that is valid xml and can be used in html documents + * safely. + */ + public String convert(String input) { + String result = input; + + // @see Foo -> See Also: <code>Foo</code> + result = result.replaceAll("@see (.+?)(\n|$)", "See Also: <code>$1</code><p>\n"); + + // <p> is valid html but bad xml (without a </p>) + // convert it to 2 <br />'s so we get one blank line + result = result.replace("<p>", "<br /> <br />"); + result = result.replace("</p>", ""); + + // {@code foobar} -> <code>foobar</code> + result = result.replaceAll("\\{@code (.*?)\\}", "<code>$1</code>"); + + // {@link foobar} -> <code>foobar</code> + result = result.replaceAll("\\{@link (.*?)\\}", "<code>$1</code>"); + + // Foo#bar(Baz) -> Foo.bar(Baz) + result = result.replaceAll("(\\w+)#(\\w+)", "$1.$2"); + + // <h1>Foo</h1> -> <h4>Foo</h4> + int offset = 4; + for (int i = 1; i < offset; i++) { + result = convertHeadingLevel(result, i, i + offset); + } + + + return result; + } + + private String convertHeadingLevel(String replace, int source, int target) { + return replace + .replaceAll("<h" + source + ">", "<h" + target + ">") + .replaceAll("</h" + source + ">", "</h" + target + ">"); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/annotations/src/main/java/com/redhat/thermostat/annotations/internal/PluginAnnotationProcessor.java Thu Feb 07 12:05:12 2013 -0500 @@ -0,0 +1,60 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.annotations.internal; + +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; + +/** + * An annotation processor that runs and finds {@code @Service} and + * {@code @ExtensionPoint} annotations. A list of classes using these + * annotations are written to a + * {@code META-INF/thermostat/plugin-docs.xml} file. + */ +@SupportedAnnotationTypes("com.redhat.thermostat.*") +@SupportedSourceVersion(SourceVersion.RELEASE_7) +public class PluginAnnotationProcessor extends AnnotationProcessor { + + /* + * Inherit all the behaviour of AnnotationProcessor + * + * The SupportedAnnotationType annotation on this class ensures it will only + * execute on Service and ExtensionPoint annotations + */ + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/annotations/src/main/java/com/redhat/thermostat/annotations/internal/SelfAnnotationProcessor.java Thu Feb 07 12:05:12 2013 -0500 @@ -0,0 +1,61 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.annotations.internal; + +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; + +/** + * An annotation processor that runs and finds {@code Documented} annotation. A + * list of classes using these + * annotations are written to a {@code META-INF/thermostat/plugin-docs.xml} + * file. + */ +@SupportedAnnotationTypes("java.lang.annotation.Documented") +@SupportedSourceVersion(SourceVersion.RELEASE_7) +public class SelfAnnotationProcessor extends AnnotationProcessor { + + /* + * Inherit all the behaviour of AnnotationProcessor + * + * The SupportedAnnotationType annotation on this class ensures it will only + * execute on Documented annotations + */ + +} +
--- a/annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor Wed Feb 06 11:40:45 2013 -0500 +++ b/annotations/src/main/resources/META-INF/services/javax.annotation.processing.Processor Thu Feb 07 12:05:12 2013 -0500 @@ -1,2 +1,3 @@ -# This jar provides the following annotation processors: -com.redhat.thermostat.annotations.internal.AnnotationProcessor +# This jar provides the following annotation processors +# these are for use by jars that depend on this jar +com.redhat.thermostat.annotations.internal.PluginAnnotationProcessor \ No newline at end of file
--- a/annotations/src/test/java/com/redhat/thermostat/annotations/internal/AnnotationProcessorTest.java Wed Feb 06 11:40:45 2013 -0500 +++ b/annotations/src/test/java/com/redhat/thermostat/annotations/internal/AnnotationProcessorTest.java Thu Feb 07 12:05:12 2013 -0500 @@ -143,14 +143,16 @@ processor.process(annotations, roundEnv); String actualFileContents = out.toString("UTF-8"); - String expectedFileContents = "<?xml?>\n" + String expectedFileContents = "<?xml version=\"1.0\"?>\n" + AUTO_GENERATED_COMMENT + "\n" - + " <service>\n" - + " <name>" + CLASS_NAME + "</name>\n" - + " <doc><![CDATA[\n" + + " <plugin-docs>\n" + + " <service>\n" + + " <name>" + CLASS_NAME + "</name>\n" + + " <doc>\n" + JAVADOC + "\n" - + "]]></doc>\n" - + " </service>\n" + + " </doc>\n" + + " </service>\n" + + " </plugin-docs>\n" + ""; assertEquals(expectedFileContents, actualFileContents); @@ -189,14 +191,16 @@ processor.process(annotations, roundEnv); String actualFileContents = out.toString("UTF-8"); - String expectedFileContents = "<?xml?>\n" + String expectedFileContents = "<?xml version=\"1.0\"?>\n" + AUTO_GENERATED_COMMENT + "\n" - + " <extension-point>\n" - + " <name>" + CLASS_NAME + "</name>\n" - + " <doc><![CDATA[\n" + + " <plugin-docs>\n" + + " <extension-point>\n" + + " <name>" + CLASS_NAME + "</name>\n" + + " <doc>\n" + JAVADOC + "\n" - + "]]></doc>\n" - + " </extension-point>\n" + + " </doc>\n" + + " </extension-point>\n" + + " </plugin-docs>\n" + ""; assertEquals(expectedFileContents, actualFileContents);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/annotations/src/test/java/com/redhat/thermostat/annotations/internal/JavadocToXmlConverterTest.java Thu Feb 07 12:05:12 2013 -0500 @@ -0,0 +1,138 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.annotations.internal; + +import static org.junit.Assert.assertEquals; + +import org.junit.Before; +import org.junit.Test; + +public class JavadocToXmlConverterTest { + + private JavadocToXmlConverter converter; + + @Before + public void setUp() { + converter = new JavadocToXmlConverter(); + } + + @Test + public void testParagraphs() { + String input = "" + + "Foo bar baz\n" + + "<p>\n" + + "frob\n"; + + String expected = "" + + "Foo bar baz\n" + + "<br /> <br />\n" + + "frob\n"; + + assertEquals(expected, converter.convert(input)); + } + + @Test + public void testCodeSegments() { + String input = "" + + "Foo bar baz\n" + + "<p>\n" + + "frob\n"; + + String expected = "" + + "Foo bar baz\n" + + "<br /> <br />\n" + + "frob\n"; + + assertEquals(expected, converter.convert(input)); + } + + @Test + public void testHeadingConversion() { + String input = "" + + "<h1>test</h1>\n" + + "frob\n"; + + String expected = "" + + "<h5>test</h5>\n" + + "frob\n"; + + assertEquals(expected, converter.convert(input)); + } + + @Test + public void testSeeAlsoSections() { + String input = "" + + " foo\n" + + " @see Foo#bar(baz)\n" + + " @see Spam#EGGS"; + + String expected = "" + + " foo\n" + + " See Also: <code>Foo.bar(baz)</code><br /> <br />\n" + + " See Also: <code>Spam.EGGS</code><br /> <br />\n"; + + assertEquals(expected, converter.convert(input)); + } + + @Test + public void testComplexJavadoc() { + String input = "" + + " foo \n" + + " bar.\n" + + " <p>\n" + + " baz (eggs) spam \n" + + " {@link BundleContext#getService(ServiceReference)} or\n" + + " {@link OSGIUtils#getService(Class)}.\n" + + " <p>\n" + + " ham\n" + + " \n"; + + String expected = "" + + " foo \n" + + " bar.\n" + + " <br /> <br />\n" + + " baz (eggs) spam \n" + + " <code>BundleContext.getService(ServiceReference)</code> or\n" + + " <code>OSGIUtils.getService(Class)</code>.\n" + + " <br /> <br />\n" + + " ham\n" + + " \n"; + + assertEquals(expected, converter.convert(input)); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/distribution/tools/MergePluginDocs.java Thu Feb 07 12:05:12 2013 -0500 @@ -0,0 +1,133 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * <http://www.gnu.org/licenses/>. + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.LinkedList; +import java.util.List; + +import javax.xml.namespace.QName; +import javax.xml.stream.XMLEventFactory; +import javax.xml.stream.XMLEventReader; +import javax.xml.stream.XMLEventWriter; +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.events.XMLEvent; + +public class MergePluginDocs { + + private static final String CORE = "plugin-docs"; + private static final String DOCS_FILE_NAME = CORE + ".xml"; + private static final String DOCS_ELEMENT = CORE; + + public static void main(String[] args) throws IOException, XMLStreamException { + String startPath = "."; + if (args.length > 0) { + startPath = args[0]; + } + + List<Path> paths = findAllPluginDocs(startPath); + String mergedXml = mergePluginDocs(paths); + System.out.println(mergedXml); + } + + private static List<Path> findAllPluginDocs(String startPath) throws IOException { + final List<Path> paths = new LinkedList<>(); + + Files.walkFileTree(Paths.get(startPath), new SimpleFileVisitor<Path>() { + @Override + public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException { + if (!Files.isRegularFile(file)) { + throw new AssertionError("lrn2code, nub!"); + } + + if (file.getFileName().toString().equals(DOCS_FILE_NAME)) { + paths.add(file); + } + + return FileVisitResult.CONTINUE; + } + }); + return paths; + } + + private static String mergePluginDocs(List<Path> paths) throws IOException, XMLStreamException { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + XMLEventFactory eventFactory = XMLEventFactory.newFactory(); + XMLOutputFactory outputFactory = XMLOutputFactory.newFactory(); + XMLEventWriter writer = outputFactory.createXMLEventWriter(outputStream); + XMLInputFactory inputFactory = XMLInputFactory.newFactory(); + + QName docsElement = new QName("", DOCS_ELEMENT, ""); + + writer.add(eventFactory.createStartDocument()); + writer.add(eventFactory.createSpace("\n")); + writer.add(eventFactory.createStartElement(docsElement, null, null)); + + for (Path path : paths) { + XMLEventReader reader = inputFactory.createXMLEventReader(Files.newInputStream(path)); + XMLEvent event; + while (reader.hasNext()) { + event = reader.nextEvent(); + if (event.getEventType() != XMLEvent.START_DOCUMENT && event.getEventType() != XMLEvent.END_DOCUMENT) { + if (event.isStartElement() && event.asStartElement().getName().equals(docsElement)) { + // skip + } else if (event.isEndElement() && event.asEndElement().getName().equals(docsElement)) { + // skip + } else if (event.getEventType() == XMLEvent.COMMENT) { + // skip + } else { + writer.add(event); + } + } + } + } + + writer.add(eventFactory.createEndElement(docsElement, null)); + writer.add(eventFactory.createEndDocument()); + writer.close(); + + return outputStream.toString("UTF-8"); + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/distribution/tools/plugin-docs-html.xslt Thu Feb 07 12:05:12 2013 -0500 @@ -0,0 +1,137 @@ +<?xml version="1.0"?> + +<!-- + + Copyright 2012, 2013 Red Hat, Inc. + + This file is part of Thermostat. + + Thermostat is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 2, or (at your + option) any later version. + + Thermostat 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Thermostat; see the file COPYING. If not see + <http://www.gnu.org/licenses />. + + Linking this code with other modules is making a combined work + based on this code. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + As a special exception, the copyright holders of this code give + you permission to link this code with independent modules to + produce an executable, regardless of the license terms of these + independent modules, and to copy and distribute the resulting + executable under terms of your choice, provided that you also + meet, for each linked independent module, the terms and conditions + of the license of that module. An independent module is a module + which is not derived from or based on this code. If you modify + this code, you may extend this exception to your version of the + library, but you are not obligated to do so. If you do not wish + to do so, delete this exception statement from your version. + +--> +<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> + <xsl:output method="html" indent="yes" encoding="UTF-8"/> + + <xsl:template match="/plugin-docs"> + <xsl:text disable-output-escaping="yes"><!DOCTYPE html></xsl:text> + <html> + <head> + <title>Plugin Documentation For Thermostat</title> + + <style> + body { background: #f9f9f9; font-family: sans-serif; font-size: 10pt; } + table { width: 90%; border-width:0; border-collapse: collapse; } + thead { font-weight: bold } + thead tr:nth-child(odd) { background: #f9f9f9; } + tr:nth-child(odd) { background: #e0e0e0; } + td { vertical-align: top; padding: 0.5em 1em } + .description { margin: 1em; } + .javadoc { margin: 0; padding:0; } + .javadoc h5, .javadoc h6, .javadoc h7 { display:inline; } + </style> + </head> + + <body> + <h1>Points of Interest for Plugin Developers</h1> + + <p>Jump to</p> + <ol> + <li><a href="#extension-points">Extension Points</a></li> + <li><a href="#services">Services</a></li> + </ol> + + <h2><a id="extension-points">Extension Points</a></h2> + <div class="description"> + <p> + <xsl:apply-templates select="meta[contains(name/text(), 'ExtensionPoint')]"/> + </p> + </div> + <table> + <thead> + <tr> + <td>Extension Point Name</td> + <td>Documentation</td> + </tr> + </thead> + <tbody> + <xsl:apply-templates select="extension-point"> + <xsl:sort select="name" /> + </xsl:apply-templates> + </tbody> + </table> + + <h2><a id="services">Services</a></h2> + <div class="description"> + <p> + <xsl:apply-templates select="meta[contains(name/text(), 'Service')]"/> + </p> + </div> + <table> + <thead> + <tr> + <td>Service Name</td> + <td>Documentation</td> + </tr> + </thead> + <tbody> + <xsl:apply-templates select="service"> + <xsl:sort select="name" /> + </xsl:apply-templates> + </tbody> + </table> + + </body> + </html> + </xsl:template> + + <xsl:template match="extension-point|service"> + <tr> + <td> + <code class="point"> <xsl:value-of select="name" /> </code> + </td> + <td> + <div class="javadoc"> + <xsl:apply-templates select="doc" /> + </div> + </td> + </tr> + </xsl:template> + + <xsl:template match="meta"> + <xsl:apply-templates select="doc" /> + </xsl:template> + + <xsl:template match="doc"> + <xsl:copy-of select="."/> + </xsl:template> + +</xsl:stylesheet> +