You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by hb...@apache.org on 2018/06/03 21:21:53 UTC

[maven-pdf-plugin] branch master updated: [MPDF-8] pdf:aggregate creates one PDF from a multi module project

This is an automated email from the ASF dual-hosted git repository.

hboutemy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-pdf-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new b03faf6  [MPDF-8] pdf:aggregate creates one PDF from a multi module project
b03faf6 is described below

commit b03faf60df1ba44f284bc294c0bf8bda8e3ec99b
Author: Hervé Boutemy <he...@free.fr>
AuthorDate: Wed May 30 16:32:12 2018 +0200

    [MPDF-8] pdf:aggregate creates one PDF from a multi module project
---
 pom.xml                                            |  13 ++
 src/it/pdf-aggregate/invoker.properties            |  19 ++
 src/it/pdf-aggregate/mod-a/pom.xml                 |  36 +++
 src/it/pdf-aggregate/mod-a/src/site/apt/index.apt  |  31 +++
 src/it/pdf-aggregate/mod-a/src/site/site.xml       |  28 +++
 src/it/pdf-aggregate/mod-b/pom.xml                 |  36 +++
 src/it/pdf-aggregate/mod-b/src/site/apt/index.apt  |  31 +++
 src/it/pdf-aggregate/mod-b/src/site/site.xml       |  28 +++
 src/it/pdf-aggregate/pom.xml                       | 105 +++++++++
 src/it/pdf-aggregate/src/site/apt/index.apt        |  35 +++
 src/it/pdf-aggregate/src/site/site.xml             |  28 +++
 src/it/pdf-aggregate/verify.groovy                 |  25 ++
 .../apache/maven/plugins/pdf/AbstractPdfMojo.java  |  68 ++++++
 .../apache/maven/plugins/pdf/PdfAggregateMojo.java | 257 +++++++++++++++++++++
 .../java/org/apache/maven/plugins/pdf/PdfMojo.java | 106 +++++----
 .../apache/maven/plugins/pdf/TocFileHelper.java    |  91 ++++++++
 16 files changed, 889 insertions(+), 48 deletions(-)

diff --git a/pom.xml b/pom.xml
index fd2c995..38f0be8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -44,6 +44,12 @@ under the License.
       </roles>
     </contributor>
     <contributor>
+      <name>Anthony Beurive</name>
+      <roles>
+        <role>MPDF-8: pdf:aggregate to create one PDF for a multi-module project</role>
+      </roles>
+    </contributor>
+    <contributor>
       <name>Taciano Tres</name>
       <roles>
         <role>Translator: Portuguese (Brazil)</role>
@@ -246,6 +252,13 @@ under the License.
       </exclusions>
     </dependency>
 
+    <!-- JSON -->
+    <dependency>
+      <groupId>org.kopitubruk.util</groupId>
+      <artifactId>JSONUtil</artifactId>
+      <version>1.10.2-java6</version>
+    </dependency>
+
     <!-- test dependencies -->
     <dependency>
       <groupId>junit</groupId>
diff --git a/src/it/pdf-aggregate/invoker.properties b/src/it/pdf-aggregate/invoker.properties
new file mode 100644
index 0000000..fa2c540
--- /dev/null
+++ b/src/it/pdf-aggregate/invoker.properties
@@ -0,0 +1,19 @@
+# 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.
+
+invoker.goals = pdf:aggregate
+invoker.debug = false
\ No newline at end of file
diff --git a/src/it/pdf-aggregate/mod-a/pom.xml b/src/it/pdf-aggregate/mod-a/pom.xml
new file mode 100644
index 0000000..b70ddff
--- /dev/null
+++ b/src/it/pdf-aggregate/mod-a/pom.xml
@@ -0,0 +1,36 @@
+<?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 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/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.its.pdf</groupId>
+    <artifactId>root</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>mod-a</artifactId>
+  <name>PDF:aggregate test: module A</name>
+  <description>
+    This is module A for multi-module PDF.
+  </description>
+</project>
diff --git a/src/it/pdf-aggregate/mod-a/src/site/apt/index.apt b/src/it/pdf-aggregate/mod-a/src/site/apt/index.apt
new file mode 100644
index 0000000..95721b4
--- /dev/null
+++ b/src/it/pdf-aggregate/mod-a/src/site/apt/index.apt
@@ -0,0 +1,31 @@
+ ------
+ Multi-module PDF: module A
+ ------
+ Lukas Theussl
+ ------
+ 2009-05-31
+ ------
+
+~~ 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/doxia/references/apt-format.html
+
+Overview
+
+  This is module A.
diff --git a/src/it/pdf-aggregate/mod-a/src/site/site.xml b/src/it/pdf-aggregate/mod-a/src/site/site.xml
new file mode 100644
index 0000000..3aac823
--- /dev/null
+++ b/src/it/pdf-aggregate/mod-a/src/site/site.xml
@@ -0,0 +1,28 @@
+<?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"/>
+    </menu>
+  </body>
+</project>
diff --git a/src/it/pdf-aggregate/mod-b/pom.xml b/src/it/pdf-aggregate/mod-b/pom.xml
new file mode 100644
index 0000000..336d785
--- /dev/null
+++ b/src/it/pdf-aggregate/mod-b/pom.xml
@@ -0,0 +1,36 @@
+<?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 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/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.apache.maven.its.pdf</groupId>
+    <artifactId>root</artifactId>
+    <version>1.0-SNAPSHOT</version>
+  </parent>
+
+  <artifactId>mod-b</artifactId>
+  <name>PDF:aggregate test: module B</name>
+  <description>
+    This is module B for multi-module PDF.
+  </description>
+</project>
diff --git a/src/it/pdf-aggregate/mod-b/src/site/apt/index.apt b/src/it/pdf-aggregate/mod-b/src/site/apt/index.apt
new file mode 100644
index 0000000..c283fc1
--- /dev/null
+++ b/src/it/pdf-aggregate/mod-b/src/site/apt/index.apt
@@ -0,0 +1,31 @@
+ ------
+ Multi-module PDF: module B
+ ------
+ Lukas Theussl
+ ------
+ 2009-05-31
+ ------
+
+~~ 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/doxia/references/apt-format.html
+
+Overview
+
+  This is module B.
diff --git a/src/it/pdf-aggregate/mod-b/src/site/site.xml b/src/it/pdf-aggregate/mod-b/src/site/site.xml
new file mode 100644
index 0000000..3aac823
--- /dev/null
+++ b/src/it/pdf-aggregate/mod-b/src/site/site.xml
@@ -0,0 +1,28 @@
+<?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"/>
+    </menu>
+  </body>
+</project>
diff --git a/src/it/pdf-aggregate/pom.xml b/src/it/pdf-aggregate/pom.xml
new file mode 100644
index 0000000..40b4898
--- /dev/null
+++ b/src/it/pdf-aggregate/pom.xml
@@ -0,0 +1,105 @@
+<?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 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/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>org.apache.maven.its.pdf</groupId>
+  <artifactId>root</artifactId>
+  <version>1.0-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <name>PDF:aggregate test: multi-module root</name>
+  <description>
+    Tests a PDF generation for a multi-module, running pdf:aggregate (that forks pdf:pdf for each module before aggregating).
+  </description>
+
+  <organization>
+    <name>The Apache Software Foundation</name>
+    <url>http://www.apache.org/</url>
+  </organization>
+
+  <contributors>
+    <contributor>
+      <name>Anthony Beurivé</name>
+    </contributor>
+  </contributors>
+
+  <issueManagement>
+    <system>JIRA</system>
+    <url>https://issues.apache.org/jira/browse/MPDF</url>
+  </issueManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+
+  <modules>
+    <module>mod-a</module>
+    <module>mod-b</module>
+  </modules>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-clean-plugin</artifactId>
+        <version>2.4.1</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-pdf-plugin</artifactId>
+        <version>@project.version@</version>
+      </plugin>
+    </plugins>
+  </build>
+  
+  <reporting>
+    <plugins>
+      <plugin>
+        <artifactId>maven-project-info-reports-plugin</artifactId>
+        <version>2.9</version>
+        <reportSets>
+          <reportSet>
+            <reports>
+              <report>cim</report>
+              <report>dependencies</report><!-- generated xdoc is not valid XML: missing <table> -->
+              <report>dependency-convergence</report><!-- generated xdoc is not valid XML: missing <table> -->
+              <report>dependency-info</report>
+              <report>dependency-management</report>
+              <report>issue-tracking</report>
+              <report>license</report>
+              <report>mailing-list</report>
+              <report>plugins</report>
+              <report>summary</report>
+            </reports>
+          </reportSet>
+        </reportSets>
+      </plugin>
+    </plugins>
+  </reporting>  
+  
+</project>
diff --git a/src/it/pdf-aggregate/src/site/apt/index.apt b/src/it/pdf-aggregate/src/site/apt/index.apt
new file mode 100644
index 0000000..edf3806
--- /dev/null
+++ b/src/it/pdf-aggregate/src/site/apt/index.apt
@@ -0,0 +1,35 @@
+ ------
+ Multi-module PDF
+ ------
+ Lukas Theussl
+ ------
+ 2009-05-31
+ ------
+
+~~ 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/doxia/references/apt-format.html
+
+Overview
+
+  This test shows how multi-module PDF generation works, running:
+
++--------+
+mvn pdf:stage
++--------+
diff --git a/src/it/pdf-aggregate/src/site/site.xml b/src/it/pdf-aggregate/src/site/site.xml
new file mode 100644
index 0000000..3aac823
--- /dev/null
+++ b/src/it/pdf-aggregate/src/site/site.xml
@@ -0,0 +1,28 @@
+<?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"/>
+    </menu>
+  </body>
+</project>
diff --git a/src/it/pdf-aggregate/verify.groovy b/src/it/pdf-aggregate/verify.groovy
new file mode 100644
index 0000000..bc03a20
--- /dev/null
+++ b/src/it/pdf-aggregate/verify.groovy
@@ -0,0 +1,25 @@
+
+/*
+ * 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.
+ */
+
+pdfFile = new File( basedir, "target/pdf-aggregate/root.pdf" )
+
+assert pdfFile.text.contains( "PDF:aggregate test: multi-module root" )
+assert pdfFile.text.contains( "PDF:aggregate test: module A" )
+assert pdfFile.text.contains( "PDF:aggregate test: module B" )
diff --git a/src/main/java/org/apache/maven/plugins/pdf/AbstractPdfMojo.java b/src/main/java/org/apache/maven/plugins/pdf/AbstractPdfMojo.java
new file mode 100644
index 0000000..152ed69
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/pdf/AbstractPdfMojo.java
@@ -0,0 +1,68 @@
+package org.apache.maven.plugins.pdf;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.maven.plugin.AbstractMojo;
+
+/**
+ * Common code to create pdf, either module pdf or reactor aggregate.
+ * 
+ * @since 1.5
+ */
+public abstract class AbstractPdfMojo
+    extends AbstractMojo
+{
+    protected abstract File getOutputDirectory();
+    protected abstract File getWorkingDirectory();
+    protected abstract boolean isIncludeReports();
+
+    /**
+     * The temp Site dir to have all site and generated-site files.
+     *
+     * @since 1.1
+     */
+    private File siteDirectoryTmp;
+
+    protected abstract void prepareTempSiteDirectory( final File tmpSiteDir )
+        throws IOException;
+
+    /**
+     * @return the default tmpSiteDirectory.
+     * @throws IOException if any
+     * @since 1.1
+     */
+    protected File getSiteDirectoryTmp()
+        throws IOException
+    {
+        if ( this.siteDirectoryTmp == null )
+        {
+            final File tmpSiteDir = new File( getWorkingDirectory(), "site.tmp" );
+            prepareTempSiteDirectory( tmpSiteDir );
+
+            this.siteDirectoryTmp = tmpSiteDir;
+        }
+
+        return this.siteDirectoryTmp;
+    }
+
+}
diff --git a/src/main/java/org/apache/maven/plugins/pdf/PdfAggregateMojo.java b/src/main/java/org/apache/maven/plugins/pdf/PdfAggregateMojo.java
new file mode 100644
index 0000000..e45342c
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/pdf/PdfAggregateMojo.java
@@ -0,0 +1,257 @@
+package org.apache.maven.plugins.pdf;
+
+/*
+ * 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.
+ */
+
+import org.apache.maven.doxia.document.DocumentModel;
+import org.apache.maven.doxia.document.DocumentTOC;
+import org.apache.maven.doxia.document.DocumentTOCItem;
+import org.apache.maven.model.Reporting;
+import org.apache.maven.plugins.annotations.Execute;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+import org.codehaus.plexus.util.FileUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Forks {@code pdf} goal then aggregates PDF content from all modules in the reactor.
+ *
+ * @author anthony-beurive
+ * @since 1.5
+ */
+@Mojo( name = "aggregate", aggregator = true, requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true )
+@Execute( goal = "pdf" )
+public class PdfAggregateMojo
+    extends PdfMojo // TODO should extend AbstractPdfMojo, but requires extensive refactoring
+{
+    /**
+     * The reactor projects.
+     */
+    @Parameter( defaultValue = "${reactorProjects}", required = true, readonly = true )
+    private List<MavenProject> reactorProjects;
+
+    /**
+     * Output directory where aggregated PDF files should be created.
+     */
+    @Parameter( defaultValue = "${project.build.directory}/pdf-aggregate", required = true )
+    private File aggregatedOutputDirectory;
+
+    /**
+     * Working directory for aggregated working files like temp files/resources.
+     */
+    @Parameter( defaultValue = "${project.build.directory}/pdf-aggregate", required = true )
+    private File aggregatedWorkingDirectory;
+
+    protected File getOutputDirectory()
+    {
+        return aggregatedOutputDirectory;
+    }
+
+    protected File getWorkingDirectory()
+    {
+        return aggregatedWorkingDirectory;
+    }
+
+    protected boolean isIncludeReports()
+    {
+        return false; // reports were generate (or not) during pdf:pdf: here, we only aggregate
+    }
+
+    protected void prepareTempSiteDirectory( final File tmpSiteDir )
+        throws IOException
+    {
+        tmpSiteDir.mkdirs();
+    }
+
+    @Override
+    protected void appendGeneratedReports( DocumentModel model, Locale locale )
+    {
+        super.appendGeneratedReports( model, locale );
+
+        getLog().info( "Appending staged reports." );
+
+        DocumentTOC toc = model.getToc();
+
+        File dstSiteTmp = null;
+        try
+        {
+            dstSiteTmp = getSiteDirectoryTmp();
+        }
+        catch ( IOException ioe )
+        {
+            getLog().error( "unexpected IOException while getting aggregator root tmp site dir", ioe );
+        }
+        if ( !dstSiteTmp.exists() )
+        {
+            getLog().error( "Top-level project does not have src.tmp directory" );
+            return;
+        }
+
+        for ( MavenProject reactorProject : reactorProjects )
+        {
+            getLog().info( "Appending " + reactorProject.getArtifactId() + " reports." );
+
+            copySiteDirectoryTmp( reactorProject, dstSiteTmp );
+
+            addTOCItems( toc, reactorProject );
+        }
+    }
+
+    private void copySiteDirectoryTmp( MavenProject project, File dstSiteTmp )
+    {
+        Reporting reporting = project.getReporting();
+        if ( reporting == null )
+        {
+            getLog().info( "Skipping reactor project " + project + ": no reporting" );
+            return;
+        }
+
+        File srcSiteTmp = getModuleSiteDirectoryTmp( project );
+        if ( !srcSiteTmp.exists() )
+        {
+            getLog().info( "Skipping reactor project " + project + ": no site.tmp directory" );
+            return;
+        }
+
+        String stagedId = getStagedId( project );
+
+        try
+        {
+            String defaultExcludes = FileUtils.getDefaultExcludesAsString();
+            List<String> srcDirNames = FileUtils.getDirectoryNames( srcSiteTmp, "*", defaultExcludes, false );
+            for ( String srcDirName : srcDirNames )
+            {
+                File srcDir = new File( srcSiteTmp, srcDirName );
+                File dstDir = new File( new File( dstSiteTmp, srcDirName ), stagedId );
+                if ( !dstDir.exists() && !dstDir.mkdirs() )
+                {
+                    getLog().error( "Could not create directory: " + dstDir );
+                    return;
+                }
+
+                FileUtils.copyDirectoryStructure( srcDir, dstDir );
+            }
+        }
+        catch ( IOException e )
+        {
+            getLog().error( "Error while copying sub-project " + project.getArtifactId()
+                                    + " site.tmp: " + e.getMessage(), e );
+        }
+    }
+
+    private void addTOCItems( DocumentTOC topLevelToc, MavenProject project )
+    {
+        String stagedId = getStagedId( project );
+
+        Map<String, Object> toc = loadToc( project );
+
+        List<Map<String, Object>> items = (ArrayList) toc.get( "items" );
+
+        DocumentTOCItem tocItem = new DocumentTOCItem();
+        tocItem.setName( project.getName() );
+        tocItem.setRef( stagedId );
+
+        if ( items.size() == 1 && "project-info".equals( items.get( 0 ).get( "ref" ) ) )
+        {
+            // Special case where a sub-project only contains generated reports.
+            items = (List) items.get( 0 ).get( "items" );
+        }
+
+        for ( Map<String, Object> item : items )
+        {
+            addTOCItems( tocItem, item, stagedId );
+        }
+
+        topLevelToc.addItem( tocItem );
+    }
+
+    private Map<String, Object> loadToc( MavenProject project )
+    {
+        try
+        {
+            return TocFileHelper.loadToc( getModuleWorkingDirectory( project ) );
+        }
+        catch ( IOException e )
+        {
+            getLog().error( "Error while reading table of contents of module " + project.getArtifactId(), e );
+            return Collections.<String, Object>emptyMap();
+        }
+    }
+
+    private void addTOCItems( DocumentTOCItem parent, Map<String, Object> item, String stagedId )
+    {
+        DocumentTOCItem tocItem = new DocumentTOCItem();
+        tocItem.setName( (String) item.get( "name" ) );
+        tocItem.setRef( stagedId + "/" + item.get( "ref" ) );
+
+        List<Map<String, Object>> items = (ArrayList) item.get( "items" );
+
+        for ( Map<String, Object> it : items )
+        {
+            addTOCItems( tocItem, it, stagedId );
+        }
+
+        parent.addItem( tocItem );
+    }
+
+    private String getStagedId( MavenProject p )
+    {
+        Deque<String> projectPath = new ArrayDeque<String>();
+        projectPath.addFirst( p.getArtifactId() );
+        while ( p.getParent() != null )
+        {
+            p = p.getParent();
+            projectPath.addFirst( p.getArtifactId() );
+        }
+
+        StringBuilder stagedId = new StringBuilder();
+        Iterator<String> artifactIds = projectPath.iterator();
+        while ( artifactIds.hasNext() )
+        {
+            stagedId.append( artifactIds.next() );
+            if ( artifactIds.hasNext() )
+            {
+                stagedId.append( '/' );
+            }
+        }
+        return stagedId.toString();
+    }
+
+    private File getModuleWorkingDirectory( MavenProject project )
+    {
+        return new File( project.getBuild().getDirectory(), "pdf" );
+    }
+
+    private File getModuleSiteDirectoryTmp( MavenProject project )
+    {
+        return new File( getModuleWorkingDirectory( project ), "site.tmp" );
+    }
+}
diff --git a/src/main/java/org/apache/maven/plugins/pdf/PdfMojo.java b/src/main/java/org/apache/maven/plugins/pdf/PdfMojo.java
index dc8cdbc..86bd35c 100644
--- a/src/main/java/org/apache/maven/plugins/pdf/PdfMojo.java
+++ b/src/main/java/org/apache/maven/plugins/pdf/PdfMojo.java
@@ -48,6 +48,7 @@ import org.apache.maven.doxia.docrenderer.DocumentRendererException;
 import org.apache.maven.doxia.docrenderer.pdf.PdfRenderer;
 import org.apache.maven.doxia.document.DocumentMeta;
 import org.apache.maven.doxia.document.DocumentModel;
+import org.apache.maven.doxia.document.DocumentTOC;
 import org.apache.maven.doxia.document.DocumentTOCItem;
 import org.apache.maven.doxia.document.io.xpp3.DocumentXpp3Writer;
 import org.apache.maven.doxia.index.IndexEntry;
@@ -68,13 +69,13 @@ import org.apache.maven.doxia.tools.SiteToolException;
 import org.apache.maven.execution.MavenSession;
 import org.apache.maven.model.ReportPlugin;
 import org.apache.maven.model.Reporting;
-import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoExecutionException;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.PluginManager;
 import org.apache.maven.plugins.annotations.Component;
 import org.apache.maven.plugins.annotations.Mojo;
 import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
 import org.apache.maven.project.MavenProject;
 import org.apache.maven.project.MavenProjectBuilder;
 import org.apache.maven.reporting.AbstractMavenReportRenderer;
@@ -104,9 +105,9 @@ import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
  *
  * @author ltheussl
  */
-@Mojo( name = "pdf", threadSafe = true )
+@Mojo( name = "pdf", requiresDependencyResolution = ResolutionScope.TEST, threadSafe = true )
 public class PdfMojo
-    extends AbstractMojo implements Contextualizable
+    extends AbstractPdfMojo implements Contextualizable
 {
 
     /**
@@ -187,7 +188,7 @@ public class PdfMojo
      * The Maven Project Object.
      */
     @Parameter( defaultValue = "${project}", readonly = true, required = true )
-    private MavenProject project;
+    protected MavenProject project;
 
     /**
      * The Maven Settings.
@@ -343,13 +344,6 @@ public class PdfMojo
     private DecorationModel defaultDecorationModel;
 
     /**
-     * The temp Site dir to have all site and generated-site files.
-     *
-     * @since 1.1
-     */
-    private File siteDirectoryTmp;
-
-    /**
      * The temp Generated Site dir to have generated reports by this plugin.
      *
      * @since 1.1
@@ -406,6 +400,21 @@ public class PdfMojo
         container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
     }
 
+    protected File getOutputDirectory()
+    {
+        return outputDirectory;
+    }
+
+    protected File getWorkingDirectory()
+    {
+        return workingDirectory;
+    }
+
+    protected boolean isIncludeReports()
+    {
+        return includeReports;
+    }
+
     // ----------------------------------------------------------------------
     // Private methods
     // ----------------------------------------------------------------------
@@ -451,7 +460,8 @@ public class PdfMojo
     private void copyGeneratedPdf()
         throws MojoExecutionException, IOException
     {
-        boolean requireCopy = !outputDirectory.getCanonicalPath().equals( workingDirectory.getCanonicalPath() );
+        boolean requireCopy =
+            !getOutputDirectory().getCanonicalPath().equals( getWorkingDirectory().getCanonicalPath() );
 
         String outputName = getDocumentModel( getDefaultLocale() ).getOutputName().trim();
         if ( !outputName.endsWith( ".pdf" ) )
@@ -461,7 +471,7 @@ public class PdfMojo
 
         for ( final Locale locale : getAvailableLocales() )
         {
-            File generatedPdfSource = new File( getLocaleDirectory( workingDirectory, locale ), outputName );
+            File generatedPdfSource = new File( getLocaleDirectory( getWorkingDirectory(), locale ), outputName );
 
             if ( !generatedPdfSource.exists() )
             {
@@ -469,7 +479,7 @@ public class PdfMojo
                 continue;
             }
 
-            File generatedPdfDest = new File( getLocaleDirectory( outputDirectory, locale ), outputName );
+            File generatedPdfDest = new File( getLocaleDirectory( getOutputDirectory(), locale ), outputName );
 
             if ( requireCopy )
             {
@@ -495,7 +505,7 @@ public class PdfMojo
 
         for ( final Locale locale : getAvailableLocales() )
         {
-            final File workingDir = getLocaleDirectory( workingDirectory, locale );
+            final File workingDir = getLocaleDirectory( getWorkingDirectory(), locale );
 
             File siteDirectoryFile = getLocaleDirectory( getSiteDirectoryTmp(), locale );
 
@@ -536,25 +546,6 @@ public class PdfMojo
     }
 
     /**
-     * @return the default tmpSiteDirectory.
-     * @throws IOException if any
-     * @since 1.1
-     */
-    private File getSiteDirectoryTmp()
-        throws IOException
-    {
-        if ( this.siteDirectoryTmp == null )
-        {
-            final File tmpSiteDir = new File( workingDirectory, "site.tmp" );
-            prepareTempSiteDirectory( tmpSiteDir );
-
-            this.siteDirectoryTmp = tmpSiteDir;
-        }
-
-        return this.siteDirectoryTmp;
-    }
-
-    /**
      * @return the default tmpGeneratedSiteDirectory when report will be created.
      * @since 1.1
      */
@@ -562,7 +553,7 @@ public class PdfMojo
     {
         if ( this.generatedSiteDirectoryTmp == null )
         {
-            this.generatedSiteDirectoryTmp = new File( workingDirectory, "generated-site.tmp" );
+            this.generatedSiteDirectoryTmp = new File( getWorkingDirectory(), "generated-site.tmp" );
         }
 
         return this.generatedSiteDirectoryTmp;
@@ -578,7 +569,7 @@ public class PdfMojo
      * @throws IOException if any
      * @since 1.1
      */
-    private void prepareTempSiteDirectory( final File tmpSiteDir )
+    protected void prepareTempSiteDirectory( final File tmpSiteDir )
         throws IOException
     {
         // safety
@@ -696,6 +687,8 @@ public class PdfMojo
 
             appendGeneratedReports( doc, locale );
 
+            saveTOC( doc.getToc(), locale );
+
             return doc;
         }
 
@@ -708,6 +701,8 @@ public class PdfMojo
 
         appendGeneratedReports( model, locale );
 
+        saveTOC( model.getToc(), locale );
+
         debugLogGeneratedModel( model );
 
         return model;
@@ -902,7 +897,7 @@ public class PdfMojo
                                                    project.getName(), locale );
             context.addSiteDirectory( new File( siteDirectory, locale.getLanguage() ) );
 
-            siteRenderer.copyResources( context, workingDirectory );
+            siteRenderer.copyResources( context, getWorkingDirectory() );
         }
         catch ( IOException e )
         {
@@ -976,7 +971,7 @@ public class PdfMojo
     private void generateMavenReports( Locale locale )
         throws MojoExecutionException, IOException
     {
-        if ( !includeReports )
+        if ( !isIncludeReports() )
         {
             getLog().info( "Skipped report generation." );
             return;
@@ -1086,6 +1081,9 @@ public class PdfMojo
             getLog().info( "Generating \"" + localReportName + "\" report." );
         }
 
+        // The report will eventually generate output by itself, so we set its output directory anyway.
+        report.setReportOutputDirectory( outDir );
+
         StringWriter sw = new StringWriter();
 
         PdfXdocSink pdfXdocSink = null;
@@ -1190,10 +1188,10 @@ public class PdfMojo
     /**
      * Append generated reports to the toc only if <code>generateReports</code> is enabled, for instance:
      * <pre>
-     * &lt;item name="Project Reports" ref="/project-info"&gt;
-     * &nbsp;&nbsp;&lt;item name="Project License" ref="/license" /&gt;
-     * &nbsp;&nbsp;&lt;item name="Project Team" ref="/team-list" /&gt;
-     * &nbsp;&nbsp;&lt;item name="Continuous Integration" ref="/integration" /&gt;
+     * &lt;item name="Project Reports" ref="project-info"&gt;
+     * &nbsp;&nbsp;&lt;item name="Project License" ref="license" /&gt;
+     * &nbsp;&nbsp;&lt;item name="Project Team" ref="team-list" /&gt;
+     * &nbsp;&nbsp;&lt;item name="Continuous Integration" ref="integration" /&gt;
      * &nbsp;&nbsp;...
      * &lt;/item&gt;
      * </pre>
@@ -1203,9 +1201,9 @@ public class PdfMojo
      * @see #generateMavenReports(Locale)
      * @since 1.1
      */
-    private void appendGeneratedReports( DocumentModel model, Locale locale )
+    protected void appendGeneratedReports( DocumentModel model, Locale locale )
     {
-        if ( !includeReports )
+        if ( !isIncludeReports() )
         {
             return;
         }
@@ -1216,7 +1214,7 @@ public class PdfMojo
 
         final DocumentTOCItem documentTOCItem = new DocumentTOCItem();
         documentTOCItem.setName( i18n.getString( "pdf-plugin", locale, "toc.project-info.item" ) );
-        documentTOCItem.setRef( "/project-info" ); // see #generateMavenReports(Locale)
+        documentTOCItem.setRef( "project-info" ); // see #generateMavenReports(Locale)
 
         List<String> addedRef = new ArrayList<String>( 4 );
 
@@ -1227,7 +1225,7 @@ public class PdfMojo
         {
             final DocumentTOCItem reportItem = new DocumentTOCItem();
             reportItem.setName( report.getName( locale ) );
-            reportItem.setRef( "/" + report.getOutputName() );
+            reportItem.setRef( report.getOutputName() );
 
             items.add( reportItem );
 
@@ -1267,7 +1265,7 @@ public class PdfMojo
                             {
                                 final DocumentTOCItem reportItem = new DocumentTOCItem();
                                 reportItem.setName( title );
-                                reportItem.setRef( "/" + ref );
+                                reportItem.setRef( ref );
 
                                 items.add( reportItem );
                             }
@@ -1287,6 +1285,18 @@ public class PdfMojo
         model.getToc().addItem( documentTOCItem );
     }
 
+    private void saveTOC( DocumentTOC toc, Locale locale )
+    {
+        try
+        {
+            TocFileHelper.saveTOC( getWorkingDirectory(), toc, locale );
+        }
+        catch ( IOException e )
+        {
+            getLog().error( "Error while writing table of contents", e );
+        }
+    }
+
     /**
      * Parse a generated Doxia file and returns its title.
      *
@@ -1348,7 +1358,7 @@ public class PdfMojo
         {
             reader = ReaderFactory.newXmlReader( generatedReport );
 
-            doxia.parse( reader, generatedReport.getParentFile().getName(), sinkAdapter );
+            doxia.parse( reader, "xdoc", sinkAdapter );
 
             reader.close();
             reader = null;
diff --git a/src/main/java/org/apache/maven/plugins/pdf/TocFileHelper.java b/src/main/java/org/apache/maven/plugins/pdf/TocFileHelper.java
new file mode 100644
index 0000000..c42b29f
--- /dev/null
+++ b/src/main/java/org/apache/maven/plugins/pdf/TocFileHelper.java
@@ -0,0 +1,91 @@
+package org.apache.maven.plugins.pdf;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.maven.doxia.document.DocumentTOC;
+import org.apache.maven.doxia.document.DocumentTOCItem;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.WriterFactory;
+import org.kopitubruk.util.json.IndentPadding;
+import org.kopitubruk.util.json.JSONConfig;
+import org.kopitubruk.util.json.JSONParser;
+import org.kopitubruk.util.json.JSONUtil;
+
+/**
+ * Helper to save then reload TOC content (to a json file), to be able to aggregate TOCs.
+ * 
+ * @author anthony-beurive
+ * @since 1.5
+ */
+class TocFileHelper
+{
+    private static final String FILENAME = "toc.json";
+
+    static void saveTOC( File workingDirectory, DocumentTOC toc, Locale locale )
+        throws IOException
+    {
+        // FIXME: manage locales.
+        JSONConfig jsonConfig = new JSONConfig();
+        jsonConfig.setIndentPadding( new IndentPadding( "  ", "\n" ) );
+        jsonConfig.addReflectClass( DocumentTOC.class );
+        jsonConfig.addReflectClass( DocumentTOCItem.class );
+
+        Writer writer = null;
+        try
+        {
+            writer = WriterFactory.newWriter( getTocFile( workingDirectory ), "UTF-8" );
+            JSONUtil.toJSON( toc, jsonConfig, writer );
+            writer.close();
+            writer = null;
+        }
+        finally
+        {
+            IOUtil.close( writer );
+        }
+    }
+
+    static Map<String, Object> loadToc( File workingDirectory )
+        throws IOException
+    {
+        Reader reader = null;
+        try
+        {
+            reader = ReaderFactory.newReader( getTocFile( workingDirectory ), "UTF-8" );
+            return (Map) JSONParser.parseJSON( reader );
+        }
+        finally
+        {
+            IOUtil.close( reader );
+        }
+    }
+
+    private static File getTocFile( File workingDirectory )
+    {
+        return new File( workingDirectory, FILENAME );
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
hboutemy@apache.org.