You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by fe...@apache.org on 2008/08/04 15:27:03 UTC

svn commit: r682379 - in /cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin: ./ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/cocoon/ src/main/java/org/apache/cocoon/maven/ src/main/java/org/apache/cocoon/maven/do...

Author: felixk
Date: Mon Aug  4 06:27:02 2008
New Revision: 682379

URL: http://svn.apache.org/viewvc?rev=682379&view=rev
Log:
The mojo and some docs

Added:
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/documentation/
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/documentation/daisy/
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/documentation/daisy/SitemapTagsToDaisyMojo.java   (with props)
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/index.apt
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/usage.apt
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/site.xml   (with props)
Modified:
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/   (props changed)
    cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/pom.xml

Propchange: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Mon Aug  4 06:27:02 2008
@@ -2,3 +2,5 @@
 .settings
 .classpath
 .project
+.externalToolBuilders
+maven-eclipse.xml

Modified: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/pom.xml
URL: http://svn.apache.org/viewvc/cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/pom.xml?rev=682379&r1=682378&r2=682379&view=diff
==============================================================================
--- cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/pom.xml (original)
+++ cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/pom.xml Mon Aug  4 06:27:02 2008
@@ -7,9 +7,9 @@
   to you under the Apache License, Version 2.0 (the
   "License"); you may not use this file except in compliance
   with the License.  You may obtain a copy of the License at
-
-   http://www.apache.org/licenses/LICENSE-2.0
-
+  
+  http://www.apache.org/licenses/LICENSE-2.0
+  
   Unless required by applicable law or agreed to in writing,
   software distributed under the License is distributed on an
   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,7 +18,10 @@
   under the License.
 -->
 <!-- @version $Id$ -->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project
+  xmlns="http://maven.apache.org/POM/4.0.0"
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 
   <modelVersion>4.0.0</modelVersion>
   <parent>
@@ -156,12 +159,6 @@
       <scope>runtime</scope>
     </dependency>
     <dependency>
-      <groupId>xerces</groupId>
-      <artifactId>xmlParserAPIs</artifactId>
-      <version>2.6.2</version>
-      <scope>runtime</scope>
-    </dependency>
-    <dependency>
       <groupId>avalon-framework</groupId>
       <artifactId>avalon-framework-api</artifactId>
       <version>4.2.0</version>
@@ -174,23 +171,15 @@
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
-      <artifactId>maven-artifact</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
       <artifactId>maven-model</artifactId>
     </dependency>
     <dependency>
       <groupId>org.apache.maven</groupId>
-      <artifactId>maven-artifact</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.maven</groupId>
       <artifactId>maven-project</artifactId>
     </dependency>
     <dependency>
-      <groupId>org.apache.maven.plugins</groupId>
-      <artifactId>maven-war-plugin</artifactId>
+      <groupId>org.apache.maven</groupId>
+      <artifactId>maven-settings</artifactId>
     </dependency>
   </dependencies>
 
@@ -237,9 +226,9 @@
             <configuration>
               <navDocId>???</navDocId>
               <collection>cdocs-maven-plugin</collection>
-      	      <skipFirstNavigationDocumentLevel>false</skipFirstNavigationDocumentLevel>
-      	    </configuration>
-      	  </plugin>
+              <skipFirstNavigationDocumentLevel>false</skipFirstNavigationDocumentLevel>
+            </configuration>
+          </plugin>
         </plugins>
       </build>
     </profile>

Added: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/documentation/daisy/SitemapTagsToDaisyMojo.java
URL: http://svn.apache.org/viewvc/cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/documentation/daisy/SitemapTagsToDaisyMojo.java?rev=682379&view=auto
==============================================================================
--- cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/documentation/daisy/SitemapTagsToDaisyMojo.java (added)
+++ cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/documentation/daisy/SitemapTagsToDaisyMojo.java Mon Aug  4 06:27:02 2008
@@ -0,0 +1,709 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.cocoon.maven.documentation.daisy;
+
+import java.io.File;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.project.MavenProject;
+import org.apache.maven.settings.Server;
+import org.apache.maven.settings.Settings;
+import org.outerj.daisy.htmlcleaner.HtmlCleanerFactory;
+import org.outerj.daisy.htmlcleaner.HtmlCleanerTemplate;
+import org.outerj.daisy.repository.CollectionManager;
+import org.outerj.daisy.repository.CollectionNotFoundException;
+import org.outerj.daisy.repository.Credentials;
+import org.outerj.daisy.repository.Document;
+import org.outerj.daisy.repository.DocumentCollection;
+import org.outerj.daisy.repository.Repository;
+import org.outerj.daisy.repository.RepositoryException;
+import org.outerj.daisy.repository.RepositoryManager;
+import org.outerj.daisy.repository.clientimpl.RemoteRepositoryManager;
+import org.outerj.daisy.repository.query.QueryHelper;
+import org.outerx.daisy.x10.SearchResultDocument;
+import org.xml.sax.InputSource;
+
+import com.thoughtworks.qdox.JavaDocBuilder;
+import com.thoughtworks.qdox.model.DocletTag;
+import com.thoughtworks.qdox.model.JavaClass;
+
+/**
+ * A plugin to sync the information about sitemap components from the Java
+ * sources to the Daisy documentation, supports custom annotations using
+ * cocoon.sitemap.* tags.
+ * 
+ * Since you normally never use sitemap components by their Java API, but rather
+ * just from the sitemap, it makes more sense to document these components in
+ * Daisy. This makes it easier to manage longer and better formatted
+ * documentation, and doesn't scare non-Java-developers away from Cocoon.
+ * 
+ * The sync tool takes a few special javadoc-style annotations into account:
+ * 
+ * <pre>
+ * &#064;cocoon.sitemap.component.name
+ *    default name with which this component is declared in the sitemap
+ * &lt;p/&gt;
+ * &#064;cocoon.sitemap.component.documentation.disabled
+ *    excludes the component from the documentation
+ * &lt;p/&gt;
+ * &#064;cocoon.sitemap.component.documentation
+ *    A short (one-paragraph) description of the component.
+ *    Can contain HTML markup (preferably only inline tags).
+ * &lt;p/&gt;
+ * &#064;cocoon.sitemap.component.documentation.caching
+ *    A comment about the caching of this component. The cacheability of the
+ *    component is figured out automatially by its implemented interfaces, but
+ *    this tag allows to provide a short comment on the chaching conditions.
+ *    This is mapped to a field in Daisy, thus should not contain HTML markup.
+ * </pre>
+ * 
+ * The tool will not update documents unnecessarily, to avoid generating new
+ * document versions in Daisy each time it is run. <p/> Reuses some ideas from
+ * the Ant SitemapTask in Cocoon 2.1.
+ * 
+ * @goal sitemaptags2daisy
+ */
+public class SitemapTagsToDaisyMojo extends AbstractMojo {
+    /**
+     * POM
+     * 
+     * @parameter expression="${project}"
+     * @readonly
+     * @required
+     */
+    protected MavenProject project;
+
+    /**
+     * The id of the the daisy server. It is used to look up the server
+     * configuration from settings.xml.
+     * 
+     * @parameter expression="${daisyServerId}" default-value="cocoon-daisy"
+     * @required
+     */
+    protected String daisyServerId;
+
+    /**
+     * Run in simulate mode (won't update documents). Values are 'true|false'.
+     * 
+     * @parameter expression="${simulateInput}" default-value=false
+     * @required
+     */
+    protected Boolean simulateInput;
+
+    /**
+     * The current user system settings for use in Maven.
+     * 
+     * @parameter expression="${settings}"
+     * @required
+     * @readonly
+     */
+    protected Settings settings;
+
+    /**
+     * The URL of the Daisy repository server.
+     * 
+     * @parameter expression="${repoUrl}"
+     *            default-value="http://cocoon.zones.apache.org:9263"
+     * @required
+     */
+    protected String repoUrl;
+
+    private static final String GENERATOR = "org.apache.cocoon.generation.Generator";
+    private static final String TRANSFORMER = "org.apache.cocoon.transformation.Transformer";
+    private static final String SERIALIZER = "org.apache.cocoon.serialization.Serializer";
+    private static final String READER = "org.apache.cocoon.reading.Reader";
+    private static final String MATCHER = "org.apache.cocoon.matching.Matcher";
+    private static final String SELECTOR = "org.apache.cocoon.selection.Selector";
+    private static final String ACTION = "org.apache.cocoon.acting.Action";
+    private static final String PIPELINE = "org.apache.cocoon.components.pipeline.ProcessingPipeline";
+
+    private static final String CACHEABLE = "org.apache.cocoon.caching.CacheableProcessingComponent";
+    private static final String DEPRECATED_CACHEABLE = "org.apache.cocoon.caching.Cacheable";
+
+    /** The name of the component in the sitemap (required) */
+    public static final String NAME_TAG = "cocoon.sitemap.component.name";
+    /** If this tag is specified no documentation is generated (optional) */
+    public static final String NO_DOC_TAG = "cocoon.sitemap.component.documentation.disabled";
+    /** The documentation (optional) */
+    public static final String DOC_TAG = "cocoon.sitemap.component.documentation";
+    /** Caching info (optional) */
+    public static final String CACHING_INFO_TAG = "cocoon.sitemap.component.documentation.caching";
+
+    private static final String DAISY_BLOCK_FIELD = "CocoonBlock";
+    private static final String DAISY_CLASSNAME_FIELD = "JavaClassName";
+    private static final String DAISY_COMPONENT_TYPE_FIELD = "CocoonComponentReference";
+    private static final String DAISY_CACHEABLE_FIELD = "SitemapComponentCacheabilityInfo";
+    private static final String DAISY_DEPRECATED_FIELD = "SitemapComponentDeprecationInfo";
+    private static final String DAISY_COMPONENT_NAME_FIELD = "SitemapComponentName";
+    private static final String DAISY_SHORTDESCR_PART = "SitemapComponentShortDescription";
+    private static final String DAISY_DOCTYPE = "SitemapComponent";
+
+    private static final String COLLECTION_PREFIX = "cdocs-";
+
+    private HtmlCleanerTemplate htmlCleanerTemplate;
+    private Repository daisyRepository;
+    private boolean simulate;
+
+    /**
+     * @throws MojoExecutionException
+     */
+    public void execute() throws MojoExecutionException {
+        getLog()
+                .info(
+                        "This is the source annotations to Daisy documents sync tool for sitemap components.");
+
+        if (!this.settings.isOffline()) {
+            try {
+                File rootDir = project.getBasedir();
+                getLog()
+                        .info("Path to the Cocoon source directory: " + rootDir);
+                File cocoonCoreDir = new File(new File(rootDir, "core"),
+                        "cocoon-core");
+                if (!cocoonCoreDir.exists()) {
+                    throw new MojoExecutionException(
+                            "This is not a valid Cocoon source directory, did not find the following path: "
+                                    + cocoonCoreDir.getPath());
+                }
+
+                // Normalize path
+                String rootPath = rootDir.getPath();
+
+                setupHtmlCleanerTemplate();
+
+                Server server = this.settings.getServer(this.daisyServerId);
+                if (server == null) {
+                    throw new MojoExecutionException(
+                            "You have to configure the Daisy CMS server with the id '"
+                                    + this.daisyServerId
+                                    + "' in your settings.xml file.");
+                }
+
+                setupDaisyRepositoryClient(repoUrl, server.getUsername(),
+                        server.getPassword());
+
+                JavaDocBuilder javaDocBuilder = getJavaDocBuilder(rootPath);
+
+                JavaClass[] allClasses = javaDocBuilder.getClasses();
+                int newDocs = 0;
+                int updatedDocs = 0;
+                int unmodifiedDocs = 0;
+
+                try {
+                    for (int i = 0; i < allClasses.length; i++) {
+                        JavaClass currentClass = allClasses[i];
+                        if (!currentClass.isAbstract()
+                                && !currentClass.isPrivate()
+                                && !currentClass.isProtected()
+                                && !currentClass.isInterface()
+                                && !currentClass.isInner()) {
+                            String componentType = getComponentTypeName(currentClass);
+                            if (componentType != null) {
+                                if (currentClass.getTagByName(NO_DOC_TAG) != null)
+                                    continue;
+
+                                String blockName = determineBlock(rootPath,
+                                        currentClass);
+                                if (blockName == null)
+                                    continue;
+
+                                ComponentDocs docs = getComponentDocs(
+                                        currentClass, componentType, blockName);
+
+                                Document daisyDoc = getDaisyDoc(docs);
+                                if (daisyDoc == null) {
+                                    getLog()
+                                            .info(
+                                                    "Creating the document for "
+                                                            + currentClass
+                                                                    .getFullyQualifiedName());
+                                    createDocument(docs, currentClass.getName());
+                                    newDocs++;
+                                } else {
+                                    ComponentDocs oldDocs = getComponentDocs(daisyDoc);
+                                    boolean collectionsNeedUpdating = updateCollections(
+                                            daisyDoc, blockName);
+                                    if (collectionsNeedUpdating
+                                            || !docs.equals(oldDocs)) {
+                                        getLog()
+                                                .info(
+                                                        "Will update the document for "
+                                                                + currentClass
+                                                                        .getFullyQualifiedName());
+                                        updateDocument(daisyDoc, docs);
+                                        updatedDocs++;
+                                    } else {
+                                        getLog()
+                                                .info(
+                                                        "No update required for "
+                                                                + currentClass
+                                                                        .getFullyQualifiedName());
+                                        unmodifiedDocs++;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                } finally {
+                    getLog().info("New documents: " + newDocs);
+                    getLog().info("Updated documents: " + updatedDocs);
+                    getLog().info("Unmodified documents: " + unmodifiedDocs);
+                }
+            } catch (Exception e) {
+                throw new MojoExecutionException("SitemapTagsToDaisy failed.",
+                        e);
+            }
+        } else {
+            getLog()
+                    .info(
+                            "Daisy documentation can't be synced when maven is run in offline mode. Nothing will be done.");
+        }
+    }
+
+    private JavaDocBuilder getJavaDocBuilder(String rootPath) {
+        File rootFile = new File(rootPath);
+
+        getLog().info("Searching java directories in " + rootPath + " ...");
+        List javaDirs = new ArrayList(100);
+        collectJavaDirs(javaDirs, rootFile);
+        getLog().info("Found " + javaDirs.size() + " java directories.");
+
+        JavaDocBuilder javaDocBuilder = new JavaDocBuilder();
+        Iterator javaDirsIt = javaDirs.iterator();
+        getLog().info("Parsing sources ...");
+        while (javaDirsIt.hasNext()) {
+            File currentDir = (File) javaDirsIt.next();
+            getLog().info("Parsing sources in " + currentDir.getPath());
+            javaDocBuilder.addSourceTree(currentDir);
+        }
+        getLog().info("Done parsing sources.");
+
+        return javaDocBuilder;
+    }
+
+    private void collectJavaDirs(List javaDirs, File currentDir) {
+        File[] files = currentDir.listFiles();
+        for (int i = 0; i < files.length; i++) {
+            if (files[i].isDirectory()) {
+                if (files[i].getName().equals("java")) {
+                    javaDirs.add(files[i]);
+                } else {
+                    collectJavaDirs(javaDirs, files[i]);
+                }
+            }
+        }
+    }
+
+    private String getComponentTypeName(JavaClass javaClass) {
+        if (javaClass.isA(GENERATOR)) {
+            return "Generator";
+        } else if (javaClass.isA(TRANSFORMER)) {
+            return "Transformer";
+        } else if (javaClass.isA(READER)) {
+            return "Reader";
+        } else if (javaClass.isA(SERIALIZER)) {
+            return "Serializer";
+        } else if (javaClass.isA(ACTION)) {
+            return "Action";
+        } else if (javaClass.isA(MATCHER)) {
+            return "Matcher";
+        } else if (javaClass.isA(SELECTOR)) {
+            return "Selector";
+        } else if (javaClass.isA(PIPELINE)) {
+            return "Pipe";
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Extracts the block name from the directory name.
+     */
+    private String determineBlock(String rootPath, JavaClass javaClass) {
+        String path = javaClass.getSource().getURL().getPath();
+        if (!path.startsWith(rootPath))
+            return null;
+
+        String subPath = path.substring(rootPath.length());
+        if (subPath.startsWith("/"))
+            subPath = subPath.substring(1);
+
+        if (subPath.startsWith("blocks/"))
+            subPath = subPath.substring("blocks/".length());
+        else if (subPath.startsWith("blocks-tobeconverted/"))
+            subPath = subPath.substring("blocks-tobeconverted/".length());
+        else if (subPath.startsWith("core/"))
+            return "core"; // all subprojects below core are considered to be
+        // block "core"
+        else
+            return null;
+
+        if (!subPath.startsWith("cocoon-"))
+            return null;
+
+        int slashPos = subPath.indexOf("/");
+        if (slashPos == -1) // very unlikely
+            return null;
+
+        String blockName = subPath.substring("cocoon-".length(), slashPos);
+        return blockName;
+    }
+
+    /**
+     * This class contains the information that is synced from the source file
+     * to a Daisy document.
+     */
+    static class ComponentDocs {
+        /** The name of the block in which this component occurs. */
+        String blockName;
+        /** Fully-qualified Java class name of the component. */
+        String className;
+        /** Component type: generator, transformer, etc. */
+        String componentType;
+        /** Short component name as used in the sitemamp. */
+        String componentName;
+        /** The short description of this component, as HTML. */
+        String documentation;
+        /** Information about the caceability of this component. */
+        String cacheInfo;
+        /** Deprecated info about this component. */
+        String deprecated;
+
+        public boolean equals(Object obj) {
+            ComponentDocs other = (ComponentDocs) obj;
+            if (!safeComp(blockName, other.blockName))
+                return false;
+            if (!safeComp(className, other.className))
+                return false;
+            if (!safeComp(componentType, other.componentType))
+                return false;
+            if (!safeComp(componentName, other.componentName))
+                return false;
+            if (!safeComp(documentation, other.documentation))
+                return false;
+            if (!safeComp(cacheInfo, other.cacheInfo))
+                return false;
+            if (!safeComp(deprecated, other.deprecated))
+                return false;
+            return true;
+        }
+
+        private boolean safeComp(String value1, String value2) {
+            if (value1 == null && value2 == null)
+                return true;
+            if (value1 == null || value2 == null)
+                return false;
+            else
+                return value1.equals(value2);
+        }
+    }
+
+    /**
+     * Gets a {@link ComponentDocs} instance by extracting info from a Java
+     * source file.
+     */
+    private ComponentDocs getComponentDocs(JavaClass javaClass,
+            String componentType, String blockName) throws Exception {
+        ComponentDocs componentDocs = new ComponentDocs();
+        componentDocs.componentType = componentType;
+        componentDocs.className = javaClass.getFullyQualifiedName();
+        componentDocs.blockName = blockName;
+
+        DocletTag documentationTag = javaClass.getTagByName(DOC_TAG);
+        if (documentationTag != null) {
+            String documentation = documentationTag.getValue();
+            if (documentation != null) {
+                componentDocs.documentation = cleanupDocumentation(documentation);
+            }
+        }
+
+        // Sitemap component name
+        DocletTag nameTag = javaClass.getTagByName(NAME_TAG);
+        if (nameTag != null)
+            componentDocs.componentName = nameTag.getValue();
+
+        // Deprecated
+        DocletTag deprecatedTag = javaClass.getTagByName("deprecated");
+        if (deprecatedTag != null) {
+            if (deprecatedTag.getValue() != null) {
+                componentDocs.deprecated = limitLength("Yes: "
+                        + deprecatedTag.getValue());
+            } else {
+                componentDocs.deprecated = "Yes.";
+            }
+        }
+
+        // Caching
+        if (javaClass.isA(GENERATOR) || javaClass.isA(TRANSFORMER)
+                || javaClass.isA(SERIALIZER) || javaClass.isA(READER)) {
+            String cacheInfo;
+            if (javaClass.isA(CACHEABLE)) {
+                cacheInfo = getTagValue(javaClass, CACHING_INFO_TAG, null);
+                if (cacheInfo != null) {
+                    cacheInfo = limitLength("Yes - " + cacheInfo);
+                } else {
+                    cacheInfo = "Yes";
+                }
+            } else if (javaClass.isA(DEPRECATED_CACHEABLE)) {
+                cacheInfo = getTagValue(javaClass, CACHING_INFO_TAG, null);
+                if (cacheInfo != null) {
+                    cacheInfo = limitLength("Yes (2.0 Caching) - " + cacheInfo);
+                } else {
+                    cacheInfo = "Yes (2.0 Caching)";
+                }
+            } else {
+                cacheInfo = "No";
+            }
+            componentDocs.cacheInfo = cacheInfo;
+        }
+
+        return componentDocs;
+    }
+
+    private String getTagValue(JavaClass javaClass, String tagName,
+            String defaultValue) {
+        final DocletTag tag = javaClass.getTagByName(tagName);
+        if (tag != null) {
+            return tag.getValue();
+        }
+        return defaultValue;
+    }
+
+    private String limitLength(String value) {
+        if (value.length() > 254)
+            return value.substring(0, 254);
+        else
+            return value;
+    }
+
+    private String cleanupDocumentation(String documentation) throws Exception {
+        // <code> tag is often used but not handled by Daisy, translate it to
+        // <tt>
+        documentation = documentation.replaceAll("<code>", "<tt>");
+        documentation = documentation.replaceAll("</code>", "</tt>");
+
+        // make it into a complete HTML doc
+        documentation = "<html><body>" + documentation + "</body></html>";
+
+        // pull it through a HTMLCleaner
+        return htmlCleanerTemplate.newHtmlCleaner()
+                .cleanToString(documentation);
+    }
+
+    private void setupHtmlCleanerTemplate() throws Exception {
+        InputStream is = null;
+        try {
+            is = getClass().getClassLoader().getResourceAsStream(
+                    "org/apache/cocoon/documentation/daisy/htmlcleaner.xml");
+            htmlCleanerTemplate = new HtmlCleanerFactory()
+                    .buildTemplate(new InputSource(is));
+        } finally {
+            if (is != null)
+                is.close();
+        }
+    }
+
+    private void setupDaisyRepositoryClient(String url, String username,
+            String password) throws Exception {
+        RepositoryManager repositoryManager = new RemoteRepositoryManager(url,
+                new Credentials(username, password));
+        this.daisyRepository = repositoryManager.getRepository(new Credentials(
+                username, password));
+    }
+
+    /**
+     * Gets the Daisy document for a certain component, based on a field
+     * containing the fully qualified class name. Returns null if there is no
+     * such document, throws an exception if there are multiple such documents.
+     */
+    private Document getDaisyDoc(ComponentDocs docs) throws Exception {
+        String query = "select id where documentType = "
+                + QueryHelper.formatString(DAISY_DOCTYPE)
+                + " and $JavaClassName = "
+                + QueryHelper.formatString(docs.className);
+        SearchResultDocument.SearchResult.Rows.Row[] rows = daisyRepository
+                .getQueryManager().performQuery(query, Locale.US)
+                .getSearchResult().getRows().getRowArray();
+        if (rows.length == 0) {
+            return null;
+        } else if (rows.length > 1) {
+            throw new Exception(
+                    "There are multiple documents in Daisy for the class "
+                            + docs.className + ". Please correct this first.");
+        } else {
+            return daisyRepository.getDocument(rows[0].getDocumentId(), rows[0]
+                    .getBranchId(), rows[0].getLanguageId(), true);
+        }
+    }
+
+    /**
+     * Gets a {@link ComponentDocs} instance from a Daisy document.
+     */
+    private ComponentDocs getComponentDocs(Document daisyDoc) throws Exception {
+        ComponentDocs docs = new ComponentDocs();
+
+        if (daisyDoc.hasField(DAISY_BLOCK_FIELD))
+            docs.blockName = (String) daisyDoc.getField(DAISY_BLOCK_FIELD)
+                    .getValue();
+
+        if (daisyDoc.hasField(DAISY_CACHEABLE_FIELD))
+            docs.cacheInfo = (String) daisyDoc.getField(DAISY_CACHEABLE_FIELD)
+                    .getValue();
+
+        if (daisyDoc.hasField(DAISY_CLASSNAME_FIELD))
+            docs.className = (String) daisyDoc.getField(DAISY_CLASSNAME_FIELD)
+                    .getValue();
+
+        if (daisyDoc.hasField(DAISY_COMPONENT_NAME_FIELD))
+            docs.componentName = (String) daisyDoc.getField(
+                    DAISY_COMPONENT_NAME_FIELD).getValue();
+
+        if (daisyDoc.hasField(DAISY_COMPONENT_TYPE_FIELD))
+            docs.componentType = (String) daisyDoc.getField(
+                    DAISY_COMPONENT_TYPE_FIELD).getValue();
+
+        if (daisyDoc.hasField(DAISY_DEPRECATED_FIELD))
+            docs.deprecated = (String) daisyDoc
+                    .getField(DAISY_DEPRECATED_FIELD).getValue();
+
+        if (daisyDoc.hasPart(DAISY_SHORTDESCR_PART))
+            docs.documentation = new String(daisyDoc.getPart(
+                    DAISY_SHORTDESCR_PART).getData(), "UTF-8");
+
+        return docs;
+    }
+
+    /**
+     * Updates the Daisy collections the document belongs too, if needed, and
+     * returns true if updated.
+     */
+    private boolean updateCollections(Document daisyDoc, String blockName)
+            throws Exception {
+        if (blockName != null) {
+            boolean belongsToRequiredCollection = false;
+            boolean updated = false;
+            String expectedCollection = COLLECTION_PREFIX + blockName;
+
+            DocumentCollection[] collections = daisyDoc.getCollections()
+                    .getArray();
+            for (int i = 0; i < collections.length; i++) {
+                String collectionName = collections[i].getName();
+                if (collectionName.equals(expectedCollection)) {
+                    belongsToRequiredCollection = true;
+                } else if (collectionName.startsWith(COLLECTION_PREFIX)) {
+                    // belongs to cdocs- collection it shouldn't belong too
+                    updated = true;
+                    daisyDoc.removeFromCollection(collections[i]);
+                }
+            }
+
+            if (!belongsToRequiredCollection) {
+                DocumentCollection collection = null;
+                CollectionManager collectionManager = daisyRepository
+                        .getCollectionManager();
+                try {
+                    try {
+                        collection = collectionManager.getCollectionByName(
+                                expectedCollection, false);
+                    } catch (CollectionNotFoundException e) {
+                        // ok, collection will be null
+                    }
+
+                    if (collection == null) {
+                        getLog().info(
+                                "Will create collection " + expectedCollection);
+                        if (!simulate) {
+                            collection = collectionManager
+                                    .createCollection(expectedCollection);
+                            collection.save();
+                        }
+                    }
+                } catch (RepositoryException e) {
+                    throw new Exception(
+                            "Error trying to get or create the collection "
+                                    + expectedCollection, e);
+                }
+
+                if (!simulate) // when in simulate mode, collection might not
+                    // have been created
+                    daisyDoc.addToCollection(collection);
+
+                updated = true;
+            }
+
+            return updated;
+        } else {
+            return false;
+        }
+    }
+
+    private void updateDocument(Document daisyDoc, ComponentDocs docs)
+            throws Exception {
+        updateField(daisyDoc, DAISY_BLOCK_FIELD, docs.blockName);
+        updateField(daisyDoc, DAISY_CACHEABLE_FIELD, docs.cacheInfo);
+        updateField(daisyDoc, DAISY_CLASSNAME_FIELD, docs.className);
+        updateField(daisyDoc, DAISY_COMPONENT_NAME_FIELD, docs.componentName);
+        updateField(daisyDoc, DAISY_COMPONENT_TYPE_FIELD, docs.componentType);
+        updateField(daisyDoc, DAISY_DEPRECATED_FIELD, docs.deprecated);
+
+        if (docs.documentation != null) {
+            boolean setPart = false;
+            if (daisyDoc.hasPart(DAISY_SHORTDESCR_PART)) {
+                String oldDescr = new String(daisyDoc.getPart(
+                        DAISY_SHORTDESCR_PART).getData(), "UTF-8");
+                // Note: for parts we need to check ourselves if the content has
+                // not changed
+                // (in contrasts to fields, for which Daisy does the comparison
+                // itself)
+                if (!oldDescr.equals(docs.documentation)) {
+                    setPart = true;
+                }
+            } else {
+                setPart = true;
+            }
+            if (setPart)
+                daisyDoc.setPart(DAISY_SHORTDESCR_PART, "text/xml",
+                        docs.documentation.getBytes("UTF-8"));
+        } else if (daisyDoc.hasPart(DAISY_SHORTDESCR_PART)) {
+            daisyDoc.deletePart(DAISY_SHORTDESCR_PART);
+        }
+
+        if (!simulate)
+            daisyDoc.save();
+    }
+
+    private void createDocument(ComponentDocs docs, String name)
+            throws Exception {
+        Document daisyDoc = daisyRepository.createDocument(name, DAISY_DOCTYPE);
+        updateCollections(daisyDoc, docs.blockName);
+        updateDocument(daisyDoc, docs);
+    }
+
+    private void updateField(Document daisyDoc, String fieldName, String value)
+            throws Exception {
+        if (value != null)
+            daisyDoc.setField(fieldName, value);
+        else if (daisyDoc.hasField(fieldName))
+            daisyDoc.deleteField(fieldName);
+    }
+
+}

Propchange: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/documentation/daisy/SitemapTagsToDaisyMojo.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/main/java/org/apache/cocoon/maven/documentation/daisy/SitemapTagsToDaisyMojo.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/index.apt
URL: http://svn.apache.org/viewvc/cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/index.apt?rev=682379&view=auto
==============================================================================
--- cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/index.apt (added)
+++ cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/index.apt Mon Aug  4 06:27:02 2008
@@ -0,0 +1,49 @@
+ ------
+ Cocoon SitemapTagsToDaisy Plugin
+ ------
+
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+~~ NOTE: For help with the syntax of this file, see:
+~~ http://maven.apache.org/guides/mini/guide-apt-format.html
+
+Overview
+
+  The plugin is a tool to sync information about sitemap components to
+  Daisy documents.
+
+  Since you normally never use sitemap components by their Java API, but rather
+  just from the sitemap, it makes more sense to document these components in
+  Daisy. This makes it easier to manage longer and better formatted documentation,
+  and doesn't scare non-Java-developers away from Cocoon.
+
+* Goals Overview
+
+  The SitemapTagsToDaisy Plugin only has one goal.
+
+  * {{{sitemaptags2daisy-mojo.html}cocoon-sitemaptags2daisy:sitemaptags2daisy}} attempts to
+    sync cocoon.sitemap annotations with documents in Daisy.
+    The plugin will not update documents unnecessarily, to avoid generating
+    new document versions in Daisy each time it is run.
+
+* Usage
+
+  Instructions on the basic usage of the SitemapTagsToDaisy Plugin can be found
+  {{{usage.html}here}}.
+
+  []

Added: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/usage.apt
URL: http://svn.apache.org/viewvc/cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/usage.apt?rev=682379&view=auto
==============================================================================
--- cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/usage.apt (added)
+++ cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/apt/usage.apt Mon Aug  4 06:27:02 2008
@@ -0,0 +1,25 @@
+ ------
+ Cocoon SitemapTagsToDaisy Plugin
+ ------
+ 
+~~ Licensed to the Apache Software Foundation (ASF) under one
+~~ or more contributor license agreements.  See the NOTICE file
+~~ distributed with this work for additional information
+~~ regarding copyright ownership.  The ASF licenses this file
+~~ to you under the Apache License, Version 2.0 (the
+~~ "License"); you may not use this file except in compliance
+~~ with the License.  You may obtain a copy of the License at
+~~
+~~   http://www.apache.org/licenses/LICENSE-2.0
+~~
+~~ Unless required by applicable law or agreed to in writing,
+~~ software distributed under the License is distributed on an
+~~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+~~ KIND, either express or implied.  See the License for the
+~~ specific language governing permissions and limitations
+~~ under the License.
+
+~~ NOTE: For help with the syntax of this file, see:
+~~ http://maven.apache.org/guides/mini/guide-apt-format.html
+
+TODO

Added: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/site.xml
URL: http://svn.apache.org/viewvc/cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/site.xml?rev=682379&view=auto
==============================================================================
--- cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/site.xml (added)
+++ cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/site.xml Mon Aug  4 06:27:02 2008
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+
+<project>
+  <body>
+    <menu name="Overview">
+      <item name="Introduction" href="index.html" />
+      <item name="Goals" href="plugin-info.html" />
+      <item name="Usage" href="usage.html" />
+    </menu>
+    <menu ref="reports" />
+  </body>
+</project>
+ 
\ No newline at end of file

Propchange: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/site.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cocoon/whiteboard/cocoon-sitemaptags2daisy-plugin/src/site/site.xml
------------------------------------------------------------------------------
    svn:keywords = Id