Author: aadamchik
Date: Mon Dec 18 02:21:25 2006
New Revision: 488198

URL: http://svn.apache.org/viewvc?view=rev&rev=488198
Log:
making a self-contained Confluence doc plugin

Added:
    incubator/cayenne/main/trunk/other/confluence-maven-plugin/.classpath
    incubator/cayenne/main/trunk/other/confluence-maven-plugin/.project
    
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocGenerator.java
    
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPage.java
    
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPageRenderer.java
    
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/resources/
    
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/resources/doctemplates/
    
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/resources/doctemplates/default.vm
Modified:
    incubator/cayenne/main/trunk/other/confluence-maven-plugin/pom.xml
    
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/ConfluenceExportMojo.java

Added: incubator/cayenne/main/trunk/other/confluence-maven-plugin/.classpath
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/other/confluence-maven-plugin/.classpath?view=auto&rev=488198
==============================================================================
--- incubator/cayenne/main/trunk/other/confluence-maven-plugin/.classpath 
(added)
+++ incubator/cayenne/main/trunk/other/confluence-maven-plugin/.classpath Mon 
Dec 18 02:21:25 2006
@@ -0,0 +1,7 @@
+<classpath>
+       <classpathentry kind="src" path="src/main/java" />
+       <classpathentry kind="src" path="src/test/java" 
output="target/test-classes" />
+       <classpathentry kind="output" path="target/classes" />
+       <classpathentry kind="con" 
path="org.eclipse.jdt.launching.JRE_CONTAINER" />
+       <classpathentry kind="con" 
path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER" />
+</classpath>
\ No newline at end of file

Added: incubator/cayenne/main/trunk/other/confluence-maven-plugin/.project
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/other/confluence-maven-plugin/.project?view=auto&rev=488198
==============================================================================
--- incubator/cayenne/main/trunk/other/confluence-maven-plugin/.project (added)
+++ incubator/cayenne/main/trunk/other/confluence-maven-plugin/.project Mon Dec 
18 02:21:25 2006
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+       <name>confluence-maven-plugin</name>
+       <comment>Apache Cayenne is a powerful, full-featured Java Object
+               Relational Mapping framework currently in incubation.</comment>
+       <projects>
+       </projects>
+       <buildSpec>
+               <buildCommand>
+                       <name>org.eclipse.jdt.core.javabuilder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+               <buildCommand>
+                       <name>org.maven.ide.eclipse.maven2Builder</name>
+                       <arguments>
+                       </arguments>
+               </buildCommand>
+       </buildSpec>
+       <natures>
+               <nature>org.eclipse.jdt.core.javanature</nature>
+               <nature>org.maven.ide.eclipse.maven2Nature</nature>
+       </natures>
+</projectDescription>

Modified: incubator/cayenne/main/trunk/other/confluence-maven-plugin/pom.xml
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/other/confluence-maven-plugin/pom.xml?view=diff&rev=488198&r1=488197&r2=488198
==============================================================================
--- incubator/cayenne/main/trunk/other/confluence-maven-plugin/pom.xml 
(original)
+++ incubator/cayenne/main/trunk/other/confluence-maven-plugin/pom.xml Mon Dec 
18 02:21:25 2006
@@ -1,18 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-    Copyright 2006 The Apache Software Foundation
-
-    Licensed 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.
+       Copyright 2006 The Apache Software Foundation
+       
+       Licensed 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>
        <parent>
@@ -27,23 +27,34 @@
        <name>Cayenne Maven2 Plugins :: Confluence</name>
        <dependencies>
                <dependency>
-                       <groupId>org.apache.cayenne.other</groupId>
-                       <artifactId>cayenne-build-tools</artifactId>
-                       <version>${pom.version}</version>
-               </dependency>
-               <dependency>
                        <groupId>org.apache.maven</groupId>
                        <artifactId>maven-archiver</artifactId>
                        <version>2.2</version>
                </dependency>
                <dependency>
-                       <groupId>commons-logging</groupId>
-                       <artifactId>commons-logging</artifactId>
-               </dependency>
-               <dependency>
                        <groupId>org.apache.maven</groupId>
                        <artifactId>maven-plugin-api</artifactId>
                        <version>2.0.4</version>
+               </dependency>
+               <dependency>
+                       <groupId>com.atlassian.confluence</groupId>
+                       <artifactId>confluence-soap</artifactId>
+                       <version>2.0</version>
+               </dependency>
+               <dependency>
+                       <groupId>axis</groupId>
+                       <artifactId>axis</artifactId>
+                       <version>1.4</version>
+               </dependency>
+               <dependency>
+                       <groupId>velocity</groupId>
+                       <artifactId>velocity</artifactId>
+                       <version>1.4</version>
+               </dependency>
+               <dependency>
+                       <groupId>org.apache.cayenne.core</groupId>
+                       <artifactId>cayenne-jdk1.4</artifactId>
+                       <version>3.0-incubating-SNAPSHOT</version>
                </dependency>
        </dependencies>
 </project>

Modified: 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/ConfluenceExportMojo.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/ConfluenceExportMojo.java?view=diff&rev=488198&r1=488197&r2=488198
==============================================================================
--- 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/ConfluenceExportMojo.java
 (original)
+++ 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/ConfluenceExportMojo.java
 Mon Dec 18 02:21:25 2006
@@ -20,49 +20,46 @@
 
 import java.net.URL;
 
-import org.apache.cayenne.tools.ant.docgen.DocGenerator;
 import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 
 /**
- * A goal to export confluence documentation
+ * A goal to export Confluence documentation.
  * 
  * @author <a href="mailto:[EMAIL PROTECTED]">Bill Dudney</a>
- * @version $Id$
- *
+ * 
  * @goal export
  */
 public class ConfluenceExportMojo extends AbstractMojo {
        /**
         * The directory to put the exported documentation into
         * 
-        * @parameter 
expression="${project.build.directory}/${export.spaceName}"
+        * @parameter 
expression="${project.build.directory}/${confluence.spaceName}"
         */
        private String outputDirectory;
 
        /**
-        * The velocity template to use - defaults to 
-        * loading 'doctemplates/default.vm' from the classpath
+        * The velocity template to use - defaults to loading
+        * 'doctemplates/default.vm' from the classpath
         * 
         * @parameter
         */
        private String velocityTemplate;
 
        /**
-        * The root url to the confluence instance
-        * For example in Cayenne: http://cwiki.apache.org/confluence/
-        * is the root URL and the space name is CAYDOC
+        * The root url to the Confluence instance For example in Cayenne:
+        * http://cwiki.apache.org/confluence/ is the base URL.
         * 
-        * @parameter expression="${export.rootURL}"
+        * @parameter expression="${confluence.baseUrl}"
         * @required
         */
-       private URL rootURL;
+       private URL baseUrl;
 
        /**
         * The name of the confluence space to export
         * 
-        * @parameter expression="${export.spaceName}"
+        * @parameter expression="${confluence.spaceName}"
         * @required
         */
        private String spaceName;
@@ -70,40 +67,41 @@
        /**
         * The page in the space to start with
         * 
-        * @parameter expression="${export.startPage}"
+        * @parameter expression="${confluence.startPage}"
         * @required
         */
        private String startPage;
 
        /**
-        * The username to log in as - define it on the commandline via the 
-        * -Dconfluence.userName=user_name option
-        * or set the userName and password in your ~/.m2/settings.xml file
-        * like this;
+        * The username to log in as - define it on the commandline via the
+        * -Dconfluence.userName=user_name option or set the userName and 
password
+        * in your ~/.m2/settings.xml file like this;
+        * 
         * <pre>
-  &lt;profiles&gt;
-    &lt;profile&gt;
-      &lt;properties&gt;
-       &lt;property&gt;
-         &lt;name&gt;confluence.userName&lt;/name&gt;
-         &lt;value&gt;user name&lt;/value&gt;
-       &lt;/property&gt;
-       &lt;property&gt;
-         &lt;name&gt;confluence.password&lt;/name&gt;
-         &lt;value&gt;password&lt;/value&gt;
-       &lt;/property&gt;
-      &lt;/properties&gt;
-      &lt;id&gt;confluence&lt;/id&gt;
-    &lt;/profile&gt;
-  &lt;/profiles&gt;
-        * </pre> 
+        *       &lt;profiles&gt;
+        *       &lt;profile&gt;
+        *       &lt;properties&gt;
+        *       &lt;property&gt;
+        *       &lt;name&gt;confluence.userName&lt;/name&gt;
+        *       &lt;value&gt;user name&lt;/value&gt;
+        *       &lt;/property&gt;
+        *       &lt;property&gt;
+        *       &lt;name&gt;confluence.password&lt;/name&gt;
+        *       &lt;value&gt;password&lt;/value&gt;
+        *       &lt;/property&gt;
+        *       &lt;/properties&gt;
+        *       &lt;id&gt;confluence&lt;/id&gt;
+        *       &lt;/profile&gt;
+        *       &lt;/profiles&gt;
+        * </pre>
+        * 
         * @parameter expression="${confluence.userName}"
         * @required
         */
        private String userName;
 
        /**
-        * The username to log in as - define it on the commandline via the 
+        * The username to log in as - define it on the commandline via the
         * -Dconfluence.password=password option
         * 
         * @parameter expression="${confluence.password}"
@@ -112,28 +110,25 @@
        private String password;
 
        /**
-        * where the actual work takes place
+        * Worker method.
         */
        public void execute() throws MojoExecutionException, 
MojoFailureException {
-        getLog().info("Exporting space '" + spaceName + "' to " + 
outputDirectory);
+               getLog().info(
+                               "Exporting space '" + spaceName + "' to " + 
outputDirectory);
 
-        try {
-            DocGenerator generator = new DocGenerator(
-                    rootURL.toString(),
-                    spaceName,
-                    outputDirectory,
-                    startPage,
-                    userName,
-                    password,
-                    velocityTemplate);
-
-            getLog().info("Confluence base URL '" + generator.getBaseUrl() + 
"'");
-            generator.generateDocs();
-        }
-        catch (Exception e) {
-               e.printStackTrace();
-            throw new MojoExecutionException("Failed to export: " + spaceName 
+ " from: " + rootURL, e);
-        }
+               try {
+                       DocGenerator generator = new 
DocGenerator(baseUrl.toString(),
+                                       spaceName, outputDirectory, startPage, 
userName, password,
+                                       velocityTemplate);
+
+                       getLog().info(
+                                       "Confluence base URL '" + 
generator.getBaseUrl() + "'");
+                       generator.generateDocs();
+               } catch (Exception e) {
+                       e.printStackTrace();
+                       throw new MojoExecutionException("Failed to export: " + 
spaceName
+                                       + " from: " + baseUrl, e);
+               }
        }
 
        public String getOutputDirectory() {
@@ -160,12 +155,12 @@
                this.password = password;
        }
 
-       public URL getRootURL() {
-               return rootURL;
+       public URL getBaseUrl() {
+               return baseUrl;
        }
 
-       public void setRootURL(URL rootURL) {
-               this.rootURL = rootURL;
+       public void setBaseUrl(URL rootURL) {
+               this.baseUrl = rootURL;
        }
 
        public String getSpaceName() {
@@ -191,5 +186,4 @@
        public void setUserName(String userName) {
                this.userName = userName;
        }
-
 }

Added: 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocGenerator.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocGenerator.java?view=auto&rev=488198
==============================================================================
--- 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocGenerator.java
 (added)
+++ 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocGenerator.java
 Mon Dec 18 02:21:25 2006
@@ -0,0 +1,207 @@
+/*****************************************************************
+ *   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.cayenne.other.plugin.confluence;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Iterator;
+
+import 
org.objectstyle.confluence.rpc.soap_axis.confluenceservice_v1.ConfluenceSoapService;
+import 
org.objectstyle.confluence.rpc.soap_axis.confluenceservice_v1.ConfluenceSoapServiceProxy;
+
+import com.atlassian.confluence.rpc.soap.beans.RemoteAttachment;
+import com.atlassian.confluence.rpc.soap.beans.RemotePage;
+import com.atlassian.confluence.rpc.soap.beans.RemotePageSummary;
+
+/**
+ * Generates standalone documentation for Cayenne based on Confluence content.
+ * 
+ * @author Cris Daniluk
+ */
+public class DocGenerator {
+       private static final String DEFAULT_TEMPLATE = 
"doctemplates/default.vm";
+
+       private static final String ENDPOINT_SUFFIX = 
"/rpc/soap-axis/confluenceservice-v1";
+
+       private String baseUrl;
+
+       private String spaceKey;
+
+       private String docBase;
+
+       private String startPage;
+
+       private String token;
+
+       private ConfluenceSoapService service;
+
+       private String username;
+
+       private String password;
+
+       private String template;
+
+       private DocPageRenderer parser;
+
+       public DocGenerator(String baseUrl, String spaceKey, String docBase,
+                       String startPage, String username, String password, 
String template) {
+
+               ConfluenceSoapServiceProxy service = new 
ConfluenceSoapServiceProxy();
+
+               // derive service URL from base URL
+               if (baseUrl != null) {
+                       if (baseUrl.endsWith("/")) {
+                               baseUrl = baseUrl.substring(0, baseUrl.length() 
- 1);
+                       }
+
+                       String endpoint = baseUrl + ENDPOINT_SUFFIX;
+                       service.setEndpoint(endpoint);
+               }
+               // service base URL from service default URL
+               else if (service.getEndpoint().endsWith(ENDPOINT_SUFFIX)) {
+                       String endpoint = service.getEndpoint();
+                       baseUrl = endpoint.substring(0, endpoint.length()
+                                       - ENDPOINT_SUFFIX.length());
+               } else {
+                       throw new IllegalArgumentException(
+                                       "Null base url and invalid service 
URL");
+               }
+
+               this.baseUrl = baseUrl;
+               this.service = service;
+               this.spaceKey = spaceKey;
+               this.docBase = docBase;
+               this.startPage = startPage;
+               this.username = username;
+               this.password = password;
+
+               if (template == null) {
+                       this.template = DEFAULT_TEMPLATE;
+               } else {
+                       this.template = template;
+               }
+       }
+
+       public void generateDocs() throws Exception {
+
+               login();
+
+               // only works for adminstrators
+               // String url = service.exportSite(token, true);
+
+               // URL foo = new URL(url);
+               createPath(docBase);
+
+               // Build a page hierarchy first..
+               DocPage page = getPage(null, startPage);
+
+               iterateChildren(page);
+
+               // Now render the content nodes..
+               renderPage(page, docBase);
+
+       }
+
+       protected void iterateChildren(DocPage parent) throws Exception {
+
+               RemotePageSummary[] children = getChildren(parent);
+               for (int i = 0; i < children.length; i++) {
+
+                       DocPage child = getPage(parent, children[i].getTitle());
+                       parent.addChild(child);
+                       iterateChildren(child);
+
+               }
+
+       }
+
+       protected void renderPage(DocPage page, String basePath) throws 
Exception {
+               String currentPath = basePath + "/" + page.getTitle();
+
+               createPath(currentPath);
+
+               FileWriter fw = new FileWriter(currentPath + "/index.html");
+               parser.render(page, fw);
+               fw.close();
+
+               writeAttachments(currentPath, page);
+
+               for (Iterator childIter = page.getChildren().iterator(); 
childIter
+                               .hasNext();) {
+                       renderPage((DocPage) childIter.next(), currentPath);
+               }
+
+       }
+
+       protected RemotePageSummary[] getChildren(DocPage page) throws 
Exception {
+               return service.getChildren(token, page.getId());
+       }
+
+       protected void writeAttachments(String basePath, DocPage page)
+                       throws Exception {
+               RemoteAttachment[] attachments = service.getAttachments(token, 
page
+                               .getId());
+
+               for (int j = 0; j < attachments.length; j++) {
+
+                       FileOutputStream fos = null;
+                       try {
+                               fos = new FileOutputStream(basePath + "/"
+                                               + attachments[j].getFileName());
+
+                               fos.write(getAttachmentData(page, 
attachments[j]));
+                       } finally {
+                               fos.close();
+                       }
+
+               }
+       }
+
+       protected byte[] getAttachmentData(DocPage page, RemoteAttachment 
attachment)
+                       throws Exception {
+               return service.getAttachmentData(token, page.getId(), attachment
+                               .getFileName(), 0);
+       }
+
+       protected void login() throws Exception {
+               token = service.login(username, password);
+               parser = new DocPageRenderer(service, baseUrl, token, spaceKey,
+                               template);
+       }
+
+       protected DocPage getPage(DocPage parentPage, String pageTitle)
+                       throws Exception {
+               RemotePage page = service.getPage(token, spaceKey, pageTitle);
+               return new DocPage(parentPage, page.getTitle(), page.getId(), 
page
+                               .getContent());
+       }
+
+       protected void createPath(String path) {
+               new File(path).mkdirs();
+
+       }
+
+       public String getBaseUrl() {
+               return baseUrl;
+       }
+}

Added: 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPage.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPage.java?view=auto&rev=488198
==============================================================================
--- 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPage.java
 (added)
+++ 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPage.java
 Mon Dec 18 02:21:25 2006
@@ -0,0 +1,209 @@
+/*****************************************************************
+ *   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.cayenne.other.plugin.confluence;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Represents a TOC entry. This has a lot of tree-like search functions, but I
+ * did not find a tree implementation that I thought was worth using for this.
+ * 
+ * @author Cris Daniluk
+ */
+public class DocPage {
+
+       private static final Pattern orderingPattern = Pattern
+                       .compile("\n?\\{excerpt(.*?)\\}");
+
+       private static final Map titleMap = new HashMap();
+
+       private String title = null;
+
+       private long id;
+
+       private String rawContent;
+
+       private DocPage parentRef;
+
+       private List children = null;
+
+       private List ordering;
+
+       private int depth;
+
+       public static DocPage getPageByTitle(String title) {
+               return (DocPage) titleMap.get(title);
+       }
+
+       public DocPage(DocPage parentRef, String title, long id, String 
rawContent) {
+               this.parentRef = parentRef;
+               this.title = title;
+               this.id = id;
+               this.rawContent = rawContent;
+
+               titleMap.put(title, this);
+
+               // Look for a page ordering...
+               Matcher matcher = orderingPattern.matcher(rawContent);
+               if (matcher.find()) {
+                       int regionStart = matcher.end() + 1;
+                       matcher.find();
+
+                       ordering = 
Arrays.asList(rawContent.substring(regionStart,
+                                       matcher.start()).split("\n"));
+
+               }
+
+               if (parentRef == null) {
+                       depth = 1;
+               } else if (ordering == null && parentRef.ordering != null) {
+                       ordering = parentRef.ordering;
+               }
+
+               children = new ArrayList();
+       }
+
+       public void addChild(DocPage child) {
+               child.depth = depth + 1;
+               children.add(child);
+       }
+
+       public String getTitle() {
+               return title;
+       }
+
+       public int getDepth() {
+               return depth;
+       }
+
+       public List getChildren() {
+               // If an ordering is present, sort by it...
+               if (ordering != null) {
+
+                       Collections.sort(children, new Comparator() {
+
+                               public int compare(Object arg0, Object arg1) {
+                                       // we're the only one who modified this 
list, so we can
+                                       // trust it
+                                       // (and live with the consequences if 
we're wrong)
+                                       DocPage child0 = (DocPage) arg0;
+                                       DocPage child1 = (DocPage) arg1;
+
+                                       if 
(child0.getTitle().equals(child1.getTitle())) {
+                                               return 0;
+                                       } else if 
(ordering.indexOf(child1.getTitle()) == -1) {
+                                               // if its not on the list, 
float it to the bottom
+                                               return 1;
+                                       }
+                                       if (ordering.indexOf(child0.getTitle()) 
< ordering
+                                                       
.indexOf(child1.getTitle())) {
+                                               return -1;
+                                       } else {
+                                               return 1;
+                                       }
+                               }
+
+                       });
+               } else {
+
+                       // no beanutils, so do this manually...
+                       Collections.sort(children, new Comparator() {
+
+                               public int compare(Object arg0, Object arg1) {
+                                       DocPage child0 = (DocPage) arg0;
+                                       DocPage child1 = (DocPage) arg1;
+                                       return 
(child0.getTitle().compareTo(child1.getTitle()));
+                               }
+
+                       });
+               }
+               return Collections.unmodifiableList(children);
+       }
+
+       public long getId() {
+               return id;
+       }
+
+       public String getRawContent() {
+               return rawContent;
+       }
+
+       public DocPage getParentRef() {
+               return parentRef;
+       }
+
+       public DocPage findPageId(long searchId) {
+
+               return findChild(this, searchId);
+       }
+
+       public boolean hasDescendent(DocPage page) {
+               if (findChild(this, page.getId()) != null) {
+                       return true;
+               }
+               return false;
+       }
+
+       /**
+        * Get the "module" root. This returns the next-to-top element in the 
tree.
+        */
+       public DocPage getRoot() {
+               DocPage base = this;
+               while (base.parentRef != null && base.parentRef.parentRef != 
null) {
+                       base = base.parentRef;
+               }
+               return base;
+       }
+
+       private DocPage findChild(DocPage page, long searchId) {
+
+               if (page.getId() == searchId) {
+                       return page;
+               }
+               Iterator pageIter = page.getChildren().iterator();
+               while (pageIter.hasNext()) {
+                       DocPage match = findChild((DocPage) pageIter.next(), 
searchId);
+                       if (match != null) {
+                               return match;
+                       }
+               }
+               return null;
+       }
+
+       public String getLinkPath() {
+               return buildLinkPath(this);
+       }
+
+       private String buildLinkPath(DocPage page) {
+               if (page.getParentRef() == null) {
+                       return page.getTitle();
+               }
+               return buildLinkPath(page.getParentRef()) + "/" + 
page.getTitle();
+       }
+}

Added: 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPageRenderer.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPageRenderer.java?view=auto&rev=488198
==============================================================================
--- 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPageRenderer.java
 (added)
+++ 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/java/org/apache/cayenne/other/plugin/confluence/DocPageRenderer.java
 Mon Dec 18 02:21:25 2006
@@ -0,0 +1,245 @@
+/*****************************************************************
+ *   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.cayenne.other.plugin.confluence;
+
+import java.io.Writer;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.cayenne.CayenneRuntimeException;
+import org.apache.cayenne.gen.ClassGeneratorResourceLoader;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.apache.velocity.runtime.log.NullLogSystem;
+import 
org.objectstyle.confluence.rpc.soap_axis.confluenceservice_v1.ConfluenceSoapService;
+
+/**
+ * Extracts embedded links from Confluence documentation and converts them to
+ * local fs references
+ * 
+ * @author Cris Daniluk
+ */
+public class DocPageRenderer {
+
+       private static final String URL_PREFIX = "/confluence";
+
+       /**
+        * Only attachments within the page are supported right now. This could
+        * easily be adjusted to find attachments in external documents if
+        * necessary.
+        */
+       private static final Pattern attachmentPattern = Pattern
+                       .compile("(href|src)=\"" + URL_PREFIX
+                                       + 
"/download/attachments/(.*?)/(.*?)\"");
+
+       /**
+        * When browsing the local filesystem, browsers like %20 (hex encoded)
+        * instead of + (legacy HTTP 0.9) for spaces.
+        */
+       private static final Pattern spaceEncoderPattern = Pattern
+                       .compile("href=\"(?!http://).*?\\+.*?\"");
+
+       /**
+        * Not all images are supported - only the ones referenced by current 
docs.
+        */
+       private static final Pattern confluenceImagePattern = Pattern
+                       .compile("src=\"" + URL_PREFIX + 
"/images/icons/(.*?)\"");
+
+       /**
+        * Take any confluence links to non-doc content and add the url
+        */
+       private Pattern confluenceLinkPattern = Pattern.compile("href=\"("
+                       + URL_PREFIX + "/display/.*?)\"");
+
+       private Pattern embeddedLinkPattern;
+
+       private ConfluenceSoapService service;
+
+       private String token;
+
+       private String spaceKey;
+
+       private String baseUrl;
+
+       private VelocityContext velCtxt;
+
+       private Template pageTemplate;
+
+       public DocPageRenderer(ConfluenceSoapService service, String baseUrl,
+                       String token, String spaceKey, String template) throws 
Exception {
+
+               // Note that these regexps have a fairly narrow capture - since 
the HTML
+               // is
+               // machine-generated,
+               // we're kind of assuming it is well-formed
+               embeddedLinkPattern = Pattern.compile("href=\"" + URL_PREFIX
+                               + "/display/" + spaceKey + "/(.*?)\"");
+
+               this.service = service;
+               this.baseUrl = baseUrl;
+               this.token = token;
+               this.spaceKey = spaceKey;
+
+               velCtxt = new VelocityContext();
+
+               initializeClassTemplate(template);
+       }
+
+       private void initializeClassTemplate(String template) throws Exception {
+               VelocityEngine velocityEngine = new VelocityEngine();
+               try {
+
+                       // use ClasspathResourceLoader for velocity templates 
lookup
+                       // if Cayenne URL is not null, load resource from this 
URL
+                       Properties props = new Properties();
+
+                       // null logger that will prevent velocity.log from 
being generated
+                       props.put(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
+                                       NullLogSystem.class.getName());
+
+                       props.put("resource.loader", "cayenne");
+
+                       props.put("cayenne.resource.loader.class",
+                                       
ClassGeneratorResourceLoader.class.getName());
+
+                       velocityEngine.init(props);
+               } catch (Exception ex) {
+                       throw new CayenneRuntimeException("Can't initialize 
Velocity", ex);
+               }
+
+               pageTemplate = velocityEngine.getTemplate(template);
+       }
+
+       public void render(DocPage page, Writer out) throws Exception {
+
+               // Add the TOC, unless this is the top-level page
+               StringBuffer toc = new StringBuffer();
+               if (page.getParentRef() != null) {
+                       toc.append("<div id=\"cayenne_toc\">\n");
+
+                       DocPage root = page.getRoot();
+
+                       iterateChildren(toc, page, root);
+                       toc.append("</div>\n");
+               }
+
+               // Figure out the level of nesting for relative links
+               String basePath = "";
+               for (int i = 1; i <= page.getDepth(); i++) {
+                       basePath += "../";
+               }
+
+               String renderedContent = null;
+               try {
+                       renderedContent = service.renderContent(token, 
spaceKey, page
+                                       .getId(), page.getRawContent(), new 
HashMap(Collections
+                                       .singletonMap("style", "clean")));
+               } catch (Throwable t) {
+                       // could have hit a DOS prevention bit so
+                       // sleep for 250ms and try again
+                       Thread.sleep(250);
+                       renderedContent = service.renderContent(token, 
spaceKey, page
+                                       .getId(), page.getRawContent(), new 
HashMap(Collections
+                                       .singletonMap("style", "clean")));
+               }
+               // Replace cross-doc links
+               Matcher linkMatcher = 
embeddedLinkPattern.matcher(renderedContent);
+               StringBuffer replacementBuffer = new StringBuffer();
+               while (linkMatcher.find()) {
+                       DocPage destPage = 
DocPage.getPageByTitle(linkMatcher.group(1)
+                                       .replace('+', ' '));
+
+                       // If we don't understand the link, just leave it alone 
to be safe
+                       if (destPage == null) {
+                               continue;
+                       }
+                       linkMatcher.appendReplacement(replacementBuffer, 
"href=\""
+                                       + basePath + destPage.getLinkPath() + 
"/index.html\"");
+               }
+               linkMatcher.appendTail(replacementBuffer);
+
+               renderedContent = replacementBuffer.toString();
+
+               // renderedContent =
+               // 
embeddedLinkPattern.matcher(renderedContent).replaceAll("href=\"$1/index.html\"");
+
+               // Replace attachment links
+               renderedContent = attachmentPattern.matcher(renderedContent)
+                               .replaceAll("$1=\"$3\"");
+
+               // Convert confluence images to relative links
+               renderedContent = 
confluenceImagePattern.matcher(renderedContent)
+                               .replaceAll("src=\"" + basePath + 
"images/$1\"");
+
+               // Replace wiki links
+               renderedContent = confluenceLinkPattern.matcher(renderedContent)
+                               .replaceAll("href=\"" + baseUrl + "$1\"");
+
+               // Convert local links with + to %20 to make browsers happy 
(wtf?)
+               Matcher matcher = spaceEncoderPattern.matcher(renderedContent);
+
+               replacementBuffer = new StringBuffer();
+               while (matcher.find()) {
+                       matcher.appendReplacement(replacementBuffer, 
matcher.group(0)
+                                       .replace("+", "%20"));
+               }
+               matcher.appendTail(replacementBuffer);
+
+               renderedContent = replacementBuffer.toString();
+
+               velCtxt.put("page", page);
+               velCtxt.put("basePath", basePath);
+               velCtxt.put("pageContent", toc.toString() + renderedContent);
+
+               pageTemplate.merge(velCtxt, out);
+
+       }
+
+       private void iterateChildren(StringBuffer toc, DocPage currentPage,
+                       DocPage basePage) {
+               toc.append("<ul>\n");
+               for (Iterator baseIter = basePage.getChildren().iterator(); 
baseIter
+                               .hasNext();) {
+
+                       DocPage child = (DocPage) baseIter.next();
+
+                       toc.append("<li>").append("<a href=\"");
+                       for (int i = 1; i <= currentPage.getDepth(); i++) {
+                               toc.append("../");
+                       }
+                       
toc.append(child.getLinkPath()).append("/index.html\">");
+                       toc.append(child.getTitle()).append("</a>");
+                       if (child.hasDescendent(currentPage)) {
+                               // render children
+                               iterateChildren(toc, currentPage, child);
+                       }
+
+                       toc.append("</li>\n");
+               }
+
+               toc.append("</ul>\n");
+       }
+}

Added: 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/resources/doctemplates/default.vm
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/resources/doctemplates/default.vm?view=auto&rev=488198
==============================================================================
--- 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/resources/doctemplates/default.vm
 (added)
+++ 
incubator/cayenne/main/trunk/other/confluence-maven-plugin/src/main/resources/doctemplates/default.vm
 Mon Dec 18 02:21:25 2006
@@ -0,0 +1,40 @@
+<!--
+   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.
+-->
+<html>
+  <head>
+    <title>Apache Cayenne Documentation - ${page.title}</title>
+    <style type="text/css">@import "${basePath}style.css";</style>
+  </head>
+<body>
+  <div class="header">
+    <div style="float: left;"><a 
href="http://incubator.apache.org/cayenne/";><img 
src="${basePath}images/logo.gif" align="absmiddle" border="0"></a></div>
+    <span class="logoSpaceLink"><a href="${basePath}index.html">Cayenne User 
Documentation</a></span><br />
+    <span class="pagetitle">${page.title}</span>
+  </div>
+${pageContent}
+</div>
+  <div class="clearer">.</div>
+  <div style="height: 12px; background-image: 
url('${basePath}images/border_bottom.gif'); background-repeat: repeat-x;"></div>
+
+  <div class="smalltext copyright">
+    Copyright &copy;2001-2006 Apache Software Foundation
+  </div>
+
+</body>
+</html>


Reply via email to