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 2020/01/23 08:14:11 UTC
[maven-doxia-book-renderer] 01/34: Move book and plugin since they
don't belong in the base of Doxia, and rename them in the process.
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-doxia-book-renderer.git
commit 534db7d2aee83a09c56867d323700a036681afc6
Author: Dennis Lundberg <de...@apache.org>
AuthorDate: Sat Mar 31 16:42:15 2012 +0000
Move book and plugin since they don't belong in the base of Doxia, and rename them in the process.
doxia/doxia-book --> doxia-tools/doxia-book-renderer
doxia/doxia-maven-plugin -> doxia/doxia-book-maven-plugin
git-svn-id: https://svn.apache.org/repos/asf/maven/doxia/doxia-tools/trunk@1307847 13f79535-47bb-0310-9956-ffa450edef68
---
pom.xml | 165 +++++++
.../org/apache/maven/doxia/book/BookDoxia.java | 79 +++
.../maven/doxia/book/BookDoxiaException.java | 55 +++
.../apache/maven/doxia/book/DefaultBookDoxia.java | 155 ++++++
.../doxia/book/InvalidBookDescriptorException.java | 61 +++
.../maven/doxia/book/context/BookContext.java | 258 ++++++++++
.../apache/maven/doxia/book/context/BookIndex.java | 40 ++
.../doxia/book/services/indexer/BookIndexer.java | 46 ++
.../book/services/indexer/DefaultBookIndexer.java | 147 ++++++
.../maven/doxia/book/services/io/BookIo.java | 57 +++
.../doxia/book/services/io/DefaultBookIo.java | 144 ++++++
.../renderer/AbstractITextBookRenderer.java | 338 +++++++++++++
.../doxia/book/services/renderer/BookRenderer.java | 44 ++
.../services/renderer/DocbookBookRenderer.java | 223 +++++++++
.../book/services/renderer/LatexBookRenderer.java | 246 ++++++++++
.../book/services/renderer/PdfBookRenderer.java | 52 ++
.../book/services/renderer/RtfBookRenderer.java | 52 ++
.../book/services/renderer/XHtmlBookRenderer.java | 208 ++++++++
.../book/services/renderer/XdocBookRenderer.java | 445 +++++++++++++++++
.../services/renderer/docbook/DocBookBookSink.java | 270 +++++++++++
.../services/renderer/latex/LatexBookSink.java | 124 +++++
.../renderer/xdoc/AbstractXdocBookSink.java | 126 +++++
.../renderer/xdoc/ChapterXdocBookSink.java | 151 ++++++
.../services/renderer/xdoc/IndexXdocBookSink.java | 84 ++++
.../renderer/xdoc/SectionXdocBookSink.java | 166 +++++++
.../services/renderer/xhtml/XhtmlBookSink.java | 248 ++++++++++
.../book/services/validation/BookValidator.java | 42 ++
.../services/validation/DefaultBookValidator.java | 104 ++++
.../book/services/validation/ValidationResult.java | 78 +++
src/main/modello/book.mdo | 537 +++++++++++++++++++++
src/main/resources/book-renderer.properties | 21 +
src/main/resources/book-renderer_en.properties | 23 +
src/main/resources/book-renderer_fr.properties | 21 +
src/site/apt/index.apt | 20 +
src/site/apt/usage.apt | 31 ++
src/site/apt/using-book-xsd.apt | 41 ++
src/site/site.xml | 48 ++
.../apache/maven/doxia/book/BookRendererTest.java | 75 +++
.../book/services/indexer/BookIndexerTest.java | 118 +++++
.../renderer/docbook/DocBookBookSinkTest.java | 490 +++++++++++++++++++
src/test/resources/book-1.xml | 51 ++
src/test/resources/book-1/section-1.apt | 61 +++
src/test/resources/book-1/section-2.apt | 16 +
src/test/resources/book-1/section-3.apt | 17 +
src/test/resources/book-1/section-4.apt | 16 +
.../expected/doc-book/plexus-user-guide.xml | 124 +++++
46 files changed, 5918 insertions(+)
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..cc90293
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,165 @@
+<?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.doxia</groupId>
+ <artifactId>doxia</artifactId>
+ <version>1.3-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <artifactId>doxia-book</artifactId>
+ <name>Doxia :: Book Component</name>
+ <description>A component to write books like user manuals and guides in any format supported by Doxia.</description>
+ <url>http://maven.apache.org/doxia/doxia/doxia-book/</url>
+
+ <dependencies>
+ <!-- doxia core -->
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-sink-api</artifactId>
+ </dependency>
+
+ <!-- doxia modules ordered -->
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-module-apt</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-module-docbook-simple</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-module-itext</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-module-latex</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-module-xdoc</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-module-xhtml</artifactId>
+ </dependency>
+
+ <!-- plexus -->
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-container-default</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-i18n</artifactId>
+ <version>1.0-beta-6</version>
+ </dependency>
+ <dependency>
+ <groupId>org.codehaus.plexus</groupId>
+ <artifactId>plexus-utils</artifactId>
+ </dependency>
+
+ <!-- test -->
+ <dependency>
+ <groupId>org.apache.maven.doxia</groupId>
+ <artifactId>doxia-core</artifactId>
+ <type>test-jar</type>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.modello</groupId>
+ <artifactId>modello-maven-plugin</artifactId>
+ <configuration>
+ <models>
+ <model>src/main/modello/book.mdo</model>
+ </models>
+ <version>1.0.0</version>
+ </configuration>
+ <executions>
+ <execution>
+ <id>site-docs</id>
+ <phase>pre-site</phase>
+ <goals>
+ <goal>xdoc</goal>
+ <goal>xsd</goal>
+ </goals>
+ </execution>
+ <execution>
+ <id>descriptor</id>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>java</goal>
+ <goal>xpp3-reader</goal>
+ <goal>xsd</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <!-- To be sure that JVM will implement AWT in software -->
+ <systemProperties>
+ <property>
+ <name>java.awt.headless</name>
+ <value>true</value>
+ </property>
+ </systemProperties>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>reporting</id>
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>l10n-maven-plugin</artifactId>
+ <version>1.0-alpha-2</version>
+ <configuration>
+ <locales>
+ <locale>en</locale>
+ <locale>fr</locale>
+ </locales>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+ </profile>
+ </profiles>
+</project>
\ No newline at end of file
diff --git a/src/main/java/org/apache/maven/doxia/book/BookDoxia.java b/src/main/java/org/apache/maven/doxia/book/BookDoxia.java
new file mode 100644
index 0000000..3d4ef96
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/BookDoxia.java
@@ -0,0 +1,79 @@
+package org.apache.maven.doxia.book;
+
+/*
+ * 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.book.model.BookModel;
+
+import java.io.File;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * An interface to create books in different output formats from a book descriptor.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public interface BookDoxia
+{
+ /** The plexus lookup role. */
+ String ROLE = BookDoxia.class.getName();
+
+ /**
+ * Load a BookModel from a descriptor file.
+ *
+ * @param bookDescriptor the book descriptor file.
+ * @return BookModel
+ * @throws org.apache.maven.doxia.book.BookDoxiaException if the model cannot be loaded.
+ */
+ BookModel loadBook( File bookDescriptor )
+ throws BookDoxiaException;
+
+ /**
+ * Creates a book from a BookModel using the {@link Locale#getDefault()} and UTF-8 as default encoding.
+ *
+ * @param book the BookModel.
+ * @param bookRendererId the id of the output format.
+ * @param files a list of source files.
+ * @param outputDirectory the output directory.
+ * @throws org.apache.maven.doxia.book.BookDoxiaException if the model cannot be loaded.
+ * @see #renderBook(BookModel, String, List, File, Locale, String, String)
+ * @see Locale#getDefault()
+ */
+ void renderBook( BookModel book, String bookRendererId, List<File> files, File outputDirectory )
+ throws BookDoxiaException;
+
+ /**
+ * Creates a book from a BookModel.
+ *
+ * @param book the BookModel.
+ * @param bookRendererId the id of the output format.
+ * @param files a list of source files.
+ * @param outputDirectory the output directory.
+ * @param locale the wanted locale.
+ * @param inputEncoding the input encoding when processing <code>files</code>.
+ * @param outputEncoding the output encoding when writing files in <code>ouputDirectory</code>.
+ * @throws org.apache.maven.doxia.book.BookDoxiaException if the model cannot be loaded.
+ * @since 1.1
+ */
+ void renderBook( BookModel book, String bookRendererId, List<File> files, File outputDirectory, Locale locale,
+ String inputEncoding, String outputEncoding )
+ throws BookDoxiaException;
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/BookDoxiaException.java b/src/main/java/org/apache/maven/doxia/book/BookDoxiaException.java
new file mode 100644
index 0000000..db02e25
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/BookDoxiaException.java
@@ -0,0 +1,55 @@
+package org.apache.maven.doxia.book;
+
+/*
+ * 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.
+ */
+
+/**
+ * Wraps an exception when rendering books.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class BookDoxiaException
+ extends Exception
+{
+ /** serialVersionUID */
+ private static final long serialVersionUID = 87146681585045106L;
+
+ /**
+ * Construct a new BookDoxiaException with the specified detail message.
+ *
+ * @param message The detailed message. This can later be retrieved by the Throwable.getMessage() method.
+ */
+ public BookDoxiaException( String message )
+ {
+ super( message );
+ }
+
+ /**
+ * Construct a new BookDoxiaException with the specified detail message and cause.
+ *
+ * @param message The detailed message. This can later be retrieved by the Throwable.getMessage() method.
+ * @param cause the cause. This can be retrieved later by the Throwable.getCause() method
+ * (a null value is permitted, and indicates that the cause is nonexistent or unknown).
+ */
+ public BookDoxiaException( String message, Throwable cause )
+ {
+ super( message, cause );
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/DefaultBookDoxia.java b/src/main/java/org/apache/maven/doxia/book/DefaultBookDoxia.java
new file mode 100644
index 0000000..02fb421
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/DefaultBookDoxia.java
@@ -0,0 +1,155 @@
+package org.apache.maven.doxia.book;
+
+/*
+ * 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.book.context.BookContext;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.services.indexer.BookIndexer;
+import org.apache.maven.doxia.book.services.io.BookIo;
+import org.apache.maven.doxia.book.services.renderer.BookRenderer;
+import org.apache.maven.doxia.book.services.validation.BookValidator;
+import org.apache.maven.doxia.book.services.validation.ValidationResult;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+
+import java.io.File;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Default implementation of BookDoxia.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ * @plexus.component
+ */
+public class DefaultBookDoxia
+ extends AbstractLogEnabled
+ implements BookDoxia
+{
+ /**
+ * @plexus.requirement
+ */
+ private BookIo bookIo;
+
+ /**
+ * @plexus.requirement
+ */
+ private BookValidator bookValidator;
+
+ /**
+ * @plexus.requirement
+ */
+ private BookIndexer bookIndexer;
+
+ /**
+ * @plexus.requirement role="org.apache.maven.doxia.book.services.renderer.BookRenderer"
+ */
+ private Map<String, BookRenderer> bookRenderers;
+
+ // ----------------------------------------------------------------------
+ // BookDoxia Implementation
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public BookModel loadBook( File bookDescriptor )
+ throws BookDoxiaException
+ {
+ return bookIo.readBook( bookDescriptor );
+ }
+
+ /** {@inheritDoc} */
+ public void renderBook( BookModel book, String bookRendererId, List<File> files, File outputDirectory )
+ throws BookDoxiaException
+ {
+ renderBook( book, bookRendererId, files, outputDirectory, Locale.getDefault(), "UTF-8", "UTF-8" );
+ }
+
+ /** {@inheritDoc} */
+ public void renderBook( BookModel book, String bookRendererId, List<File> files, File outputDirectory,
+ Locale locale, String inputEncoding, String outputEncoding )
+ throws BookDoxiaException
+ {
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ ValidationResult validationResult = bookValidator.validateBook( book );
+
+ if ( !validationResult.isAllOk() )
+ {
+ throw new InvalidBookDescriptorException( validationResult );
+ }
+
+ // ----------------------------------------------------------------------
+ // Create and initialize the context
+ // ----------------------------------------------------------------------
+
+ BookContext context = new BookContext();
+
+ context.setBook( book );
+
+ context.setOutputDirectory( outputDirectory );
+
+ context.setLocale( locale );
+
+ context.setInputEncoding( inputEncoding );
+
+ context.setOutputEncoding( outputEncoding );
+
+ // -----------------------------------------------------------------------
+ //
+ // -----------------------------------------------------------------------
+
+ bookIo.loadFiles( context, files );
+
+ // ----------------------------------------------------------------------
+ // Generate indexes
+ // ----------------------------------------------------------------------
+
+ bookIndexer.indexBook( book, context );
+
+ // ----------------------------------------------------------------------
+ // Render the book
+ // ----------------------------------------------------------------------
+
+ BookRenderer bookRenderer = bookRenderers.get( bookRendererId );
+
+ if ( bookRenderer == null )
+ {
+ throw new BookDoxiaException( "No such book renderer '" + bookRendererId + "'." );
+ }
+
+ bookRenderer.renderBook( context );
+ }
+
+ /**
+ * Returns a Set of ids of the BookRenderers that are available in this BookDoxia.
+ *
+ * @return Set
+ */
+ public Set<String> getAvailableBookRenderers()
+ {
+ return Collections.unmodifiableSet( bookRenderers.keySet() );
+ }
+
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/InvalidBookDescriptorException.java b/src/main/java/org/apache/maven/doxia/book/InvalidBookDescriptorException.java
new file mode 100644
index 0000000..efc9c80
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/InvalidBookDescriptorException.java
@@ -0,0 +1,61 @@
+package org.apache.maven.doxia.book;
+
+/*
+ * 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.book.services.validation.ValidationResult;
+
+/**
+ * Indicates that the book descriptor file could not be parsed correctly.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class InvalidBookDescriptorException
+ extends BookDoxiaException
+{
+
+ /** serialVersionUID */
+ private static final long serialVersionUID = -5706648416915909753L;
+
+ /** ValidationResult. */
+ private ValidationResult validationResult;
+
+ /**
+ * Construct a new InvalidBookDescriptorException and stores the given ValidationResult.
+ *
+ * @param validationResult The ValidationResult to store.
+ */
+ public InvalidBookDescriptorException( ValidationResult validationResult )
+ {
+ super( "Invalid book descriptor." );
+
+ this.validationResult = validationResult;
+ }
+
+ /**
+ * Return the ValidationResult.
+ *
+ * @return the ValidationResult associated with this Exception.
+ */
+ public ValidationResult getValidationResult()
+ {
+ return validationResult;
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/context/BookContext.java b/src/main/java/org/apache/maven/doxia/book/context/BookContext.java
new file mode 100644
index 0000000..3e78b19
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/context/BookContext.java
@@ -0,0 +1,258 @@
+package org.apache.maven.doxia.book.context;
+
+/*
+ * 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.book.model.BookModel;
+
+import java.io.File;
+import java.util.Locale;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * Context to render a book.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class BookContext
+{
+ /** The BookModel of this context. */
+ private BookModel book;
+
+ /** The files. */
+ private Map<String, BookContext.BookFile> files;
+
+ /** The output directory. */
+ private File outputDirectory;
+
+ /** The BookIndex of this context. */
+ private BookIndex index;
+
+ /** The Locale used to generate the navigation. */
+ private Locale locale;
+
+ /** The input encoding used to read Doxia file. */
+ private String inputEncoding;
+
+ /** The output encoding used to write the renderer files. */
+ private String outputEncoding;
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /** Represents a BookFile. */
+ public static class BookFile
+ {
+ /** The file. */
+ private File file;
+
+ /** The id of the parser. */
+ private String parserId;
+
+ /**
+ * Constructor.
+ *
+ * @param file the file.
+ * @param parserId the parser id.
+ */
+ public BookFile( File file, String parserId )
+ {
+ this.file = file;
+ this.parserId = parserId;
+ }
+
+ /**
+ * Return the file of this BookFile.
+ *
+ * @return File.
+ */
+ public File getFile()
+ {
+ return file;
+ }
+
+ /**
+ * Return the parserId of this BookFile.
+ *
+ * @return String.
+ */
+ public String getParserId()
+ {
+ return parserId;
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Accessors
+ // ----------------------------------------------------------------------
+
+ /**
+ * Return the BookModel of this BookContext.
+ *
+ * @return BookModel.
+ */
+ public BookModel getBook()
+ {
+ return book;
+ }
+
+ /**
+ * Set the BookModel of this BookContext.
+ *
+ * @param book the BookModel.
+ */
+ public void setBook( BookModel book )
+ {
+ this.book = book;
+ }
+
+ /**
+ * Return the files of this BookContext.
+ *
+ * @return Map. A new HashMap is constructed if the current Map is null.
+ */
+ public Map<String, BookContext.BookFile> getFiles()
+ {
+ if ( files == null )
+ {
+ files = new HashMap<String, BookContext.BookFile>();
+ }
+
+ return files;
+ }
+
+ /**
+ * Set the files of this BookContext.
+ *
+ * @param files the Map of files.
+ */
+ public void setFiles( Map<String, BookContext.BookFile> files )
+ {
+ this.files = files;
+ }
+
+ /**
+ * Return the outputDirectory of this BookContext.
+ *
+ * @return File.
+ */
+ public File getOutputDirectory()
+ {
+ return outputDirectory;
+ }
+
+ /**
+ * Set the outputDirectory of this BookContext.
+ *
+ * @param outputDirectory the output directory.
+ */
+ public void setOutputDirectory( File outputDirectory )
+ {
+ this.outputDirectory = outputDirectory;
+ }
+
+ /**
+ * Return the index of this BookContext.
+ *
+ * @return BookIndex.
+ */
+ public BookIndex getIndex()
+ {
+ return index;
+ }
+
+ /**
+ * Set the index of this BookContext.
+ *
+ * @param index the index to set.
+ */
+ public void setIndex( BookIndex index )
+ {
+ this.index = index;
+ }
+
+ /**
+ * <p>Getter for the field <code>locale</code>.</p>
+ *
+ * @return the locale
+ * @since 1.1
+ */
+ public Locale getLocale()
+ {
+ return locale;
+ }
+
+ /**
+ * <p>Setter for the field <code>locale</code>.</p>
+ *
+ * @param locale the locale to set
+ * @since 1.1
+ */
+ public void setLocale( Locale locale )
+ {
+ this.locale = locale;
+ }
+
+ /**
+ * <p>Getter for the field <code>inputEncoding</code>.</p>
+ *
+ * @return the inputEncoding
+ * @since 1.1
+ */
+ public String getInputEncoding()
+ {
+ return inputEncoding;
+ }
+
+ /**
+ * <p>Setter for the field <code>inputEncoding</code>.</p>
+ *
+ * @param inputEncoding the inputEncoding to set
+ * @since 1.1
+ */
+ public void setInputEncoding( String inputEncoding )
+ {
+ this.inputEncoding = inputEncoding;
+ }
+
+ /**
+ * <p>Getter for the field <code>outputEncoding</code>.</p>
+ *
+ * @return the outputEncoding
+ * @since 1.1
+ */
+ public String getOutputEncoding()
+ {
+ return outputEncoding;
+ }
+
+ /**
+ * <p>Setter for the field <code>outputEncoding</code>.</p>
+ *
+ * @param outputEncoding the outputEncoding to set
+ * @since 1.1
+ */
+ public void setOutputEncoding( String outputEncoding )
+ {
+ this.outputEncoding = outputEncoding;
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/context/BookIndex.java b/src/main/java/org/apache/maven/doxia/book/context/BookIndex.java
new file mode 100644
index 0000000..b1d9ca0
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/context/BookIndex.java
@@ -0,0 +1,40 @@
+package org.apache.maven.doxia.book.context;
+
+/*
+ * 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.index.IndexEntry;
+
+/**
+ * <p>BookIndex class.</p>
+ *
+ * @author <a href="mailto:trygve.laugstol@objectware.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class BookIndex
+ extends IndexEntry
+{
+ /**
+ * Constructs a new BookIndex.
+ */
+ public BookIndex()
+ {
+ super( "book" );
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/indexer/BookIndexer.java b/src/main/java/org/apache/maven/doxia/book/services/indexer/BookIndexer.java
new file mode 100644
index 0000000..61129fa
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/indexer/BookIndexer.java
@@ -0,0 +1,46 @@
+package org.apache.maven.doxia.book.services.indexer;
+
+/*
+ * 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.book.model.BookModel;
+import org.apache.maven.doxia.book.context.BookContext;
+import org.apache.maven.doxia.book.BookDoxiaException;
+
+/**
+ * Index a book.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public interface BookIndexer
+{
+ /** The plexus lookup role. */
+ String ROLE = BookIndexer.class.getName();
+
+ /**
+ * Index a book.
+ *
+ * @param book the book to index.
+ * @param bookContext the BookContext.
+ * @throws org.apache.maven.doxia.book.BookDoxiaException if the book cannot be indexed.
+ */
+ void indexBook( BookModel book, BookContext bookContext )
+ throws BookDoxiaException;
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/indexer/DefaultBookIndexer.java b/src/main/java/org/apache/maven/doxia/book/services/indexer/DefaultBookIndexer.java
new file mode 100644
index 0000000..420859b
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/indexer/DefaultBookIndexer.java
@@ -0,0 +1,147 @@
+package org.apache.maven.doxia.book.services.indexer;
+
+/*
+ * 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.FileNotFoundException;
+import java.io.FileReader;
+
+import org.apache.maven.doxia.Doxia;
+import org.apache.maven.doxia.book.BookDoxiaException;
+import org.apache.maven.doxia.book.context.BookContext;
+import org.apache.maven.doxia.book.context.BookIndex;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.model.Chapter;
+import org.apache.maven.doxia.book.model.Section;
+import org.apache.maven.doxia.index.IndexEntry;
+import org.apache.maven.doxia.index.IndexingSink;
+import org.apache.maven.doxia.parser.ParseException;
+import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+
+/**
+ * Default implementation of BookIndexer.
+ *
+ * @plexus.component
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class DefaultBookIndexer
+ extends AbstractLogEnabled
+ implements BookIndexer
+{
+ /**
+ * @plexus.requirement
+ */
+ private Doxia doxia;
+
+ // ----------------------------------------------------------------------
+ // BookIndexer Implementation
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public void indexBook( BookModel book, BookContext bookContext )
+ throws BookDoxiaException
+ {
+ BookIndex index = new BookIndex();
+
+ for ( Chapter chapter : book.getChapters() )
+ {
+ indexChapter( bookContext, index, chapter );
+ }
+
+ bookContext.setIndex( index );
+ }
+
+ // ----------------------------------------------------------------------
+ // Private
+ // ----------------------------------------------------------------------
+
+ /**
+ * Index a chapter.
+ *
+ * @param context the BookContext.
+ * @param bookEntry the IndexEntry.
+ * @param chapter the Chapter to index.
+ * @throws BookDoxiaException if the chapter cannot be indexed.
+ */
+ private void indexChapter( BookContext context, IndexEntry bookEntry, Chapter chapter )
+ throws BookDoxiaException
+ {
+ IndexEntry chapterEntry = new IndexEntry( bookEntry, chapter.getId( ) );
+
+ chapterEntry.setTitle( chapter.getTitle() );
+
+ for ( Section section : chapter.getSections() )
+ {
+ indexSection( context, chapterEntry, section );
+ }
+ }
+
+ /**
+ * Index a section.
+ *
+ * @param bookContext the BookContext.
+ * @param chapterEntry the IndexEntry.
+ * @param section the Section to index.
+ * @throws BookDoxiaException if the section cannot be indexed.
+ */
+ private void indexSection( BookContext bookContext, IndexEntry chapterEntry, Section section )
+ throws BookDoxiaException
+ {
+ BookContext.BookFile bookFile = (BookContext.BookFile) bookContext.getFiles().get( section.getId() );
+
+ if ( bookFile == null )
+ {
+ throw new BookDoxiaException( "No document that matches section with id="
+ + section.getId() + "." );
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ IndexEntry sectionEntry = new IndexEntry( chapterEntry, section.getId() );
+
+ IndexingSink sink = new IndexingSink( sectionEntry );
+
+ try
+ {
+ doxia.parse( new FileReader( bookFile.getFile() ), bookFile.getParserId(), sink );
+ }
+ catch ( ParserNotFoundException e )
+ {
+ throw new BookDoxiaException( "Parser not found: "
+ + bookFile.getParserId() + ".", e );
+ }
+ catch ( ParseException e )
+ {
+ throw new BookDoxiaException( "Error while parsing document: "
+ + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ catch ( FileNotFoundException e )
+ {
+ throw new BookDoxiaException( "Could not find document: "
+ + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+
+ sectionEntry.setTitle( sink.getTitle() );
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/io/BookIo.java b/src/main/java/org/apache/maven/doxia/book/services/io/BookIo.java
new file mode 100644
index 0000000..517f7fd
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/io/BookIo.java
@@ -0,0 +1,57 @@
+package org.apache.maven.doxia.book.services.io;
+
+/*
+ * 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.book.model.BookModel;
+import org.apache.maven.doxia.book.BookDoxiaException;
+import org.apache.maven.doxia.book.context.BookContext;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * Common book-related IO methods.
+ *
+ * @author <a href="mailto:trygve.laugstol@objectware.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public interface BookIo
+{
+ /** The plexus lookup role. */
+ String ROLE = BookIo.class.getName();
+
+ /**
+ * Read a BookModel from a descriptor file.
+ *
+ * @param bookDescriptor the book descriptor file.
+ * @return BookModel
+ * @throws org.apache.maven.doxia.book.BookDoxiaException if the model cannot be read.
+ */
+ BookModel readBook( File bookDescriptor )
+ throws BookDoxiaException;
+
+ /**
+ * Loads files in a given context.
+ *
+ * @param context the BookContext.
+ * @param files a list of files.
+ */
+ void loadFiles( BookContext context, List<File> files );
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/io/DefaultBookIo.java b/src/main/java/org/apache/maven/doxia/book/services/io/DefaultBookIo.java
new file mode 100644
index 0000000..9509d1d
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/io/DefaultBookIo.java
@@ -0,0 +1,144 @@
+package org.apache.maven.doxia.book.services.io;
+
+/*
+ * 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.book.model.io.xpp3.BookModelXpp3Reader;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.BookDoxiaException;
+import org.apache.maven.doxia.book.context.BookContext;
+import org.apache.maven.doxia.module.site.SiteModule;
+import org.apache.maven.doxia.module.site.manager.SiteModuleManager;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+
+import java.io.IOException;
+import java.io.File;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.List;
+
+/**
+ * <p>DefaultBookIo class.</p>
+ *
+ * @plexus.component
+ * @author <a href="mailto:trygve.laugstol@objectware.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class DefaultBookIo
+ extends AbstractLogEnabled
+ implements BookIo
+{
+ /**
+ * @plexus.requirement
+ */
+ private SiteModuleManager siteModuleManager;
+
+ // -----------------------------------------------------------------------
+ // DefaultBookIo Implementation
+ // -----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public BookModel readBook( File bookDescriptor )
+ throws BookDoxiaException
+ {
+ Reader reader = null;
+ try
+ {
+ reader = ReaderFactory.newXmlReader( bookDescriptor );
+ return new BookModelXpp3Reader().read( reader, true );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while reading book descriptor.", e );
+ }
+ catch ( XmlPullParserException e )
+ {
+ throw new BookDoxiaException( "Error while reading book descriptor.", e );
+ }
+ finally
+ {
+ IOUtil.close( reader );
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void loadFiles( BookContext context, List<File> files )
+ {
+ // ----------------------------------------------------------------------
+ // Find all the files, map the file names to ids
+ // ----------------------------------------------------------------------
+
+ Collection<SiteModule> siteModules = siteModuleManager.getSiteModules();
+
+ for ( SiteModule siteModule : siteModules )
+ {
+ String extension = siteModule.getExtension();
+
+ String sourceDirectory = File.separator + siteModule.getSourceDirectory() + File.separator;
+
+ String parserId = siteModule.getParserId();
+
+ for ( File file : files )
+ {
+ String name = file.getName();
+
+ String path = file.getAbsolutePath();
+
+ // first check if the file path contains one of the recognized source dir identifiers
+ // (there's trouble if a pathname contains 2 identifiers), then match file extensions (not unique).
+
+ if ( path.indexOf( sourceDirectory ) != -1 )
+ {
+ name = name.substring( 0, name.length() - extension.length() - 1 );
+
+ context.getFiles().put( name, new BookContext.BookFile( file, parserId ) );
+ }
+ else if ( name.endsWith( extension ) )
+ {
+ name = name.substring( 0, name.length() - extension.length() - 1 );
+
+ // don't overwrite if it's there already
+ if ( !context.getFiles().containsKey( name ) )
+ {
+ context.getFiles().put( name, new BookContext.BookFile( file, parserId ) );
+ }
+ }
+ }
+ }
+
+ if ( getLogger().isDebugEnabled() )
+ {
+ getLogger().debug( "Dumping document <-> id mapping:" );
+
+ Map<String, BookContext.BookFile> map = new TreeMap<String, BookContext.BookFile>( context.getFiles() );
+
+ for ( Map.Entry<String, BookContext.BookFile> entry : map.entrySet() )
+ {
+ BookContext.BookFile file = entry.getValue();
+
+ getLogger().debug( " " + entry.getKey() + "=" + file.getFile() + ", parser: " + file.getParserId() );
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/AbstractITextBookRenderer.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/AbstractITextBookRenderer.java
new file mode 100644
index 0000000..78e18ff
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/AbstractITextBookRenderer.java
@@ -0,0 +1,338 @@
+package org.apache.maven.doxia.book.services.renderer;
+
+/*
+ * 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.FileNotFoundException;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.text.DateFormat;
+import java.util.Date;
+
+import org.apache.maven.doxia.Doxia;
+import org.apache.maven.doxia.book.BookDoxiaException;
+import org.apache.maven.doxia.book.context.BookContext;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.model.Chapter;
+import org.apache.maven.doxia.book.model.Section;
+import org.apache.maven.doxia.module.itext.ITextSinkFactory;
+import org.apache.maven.doxia.parser.ParseException;
+import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
+import org.apache.maven.doxia.sink.Sink;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.WriterFactory;
+import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
+
+/**
+ * Base class for <code>iText</code> renderer.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
+ * @version $Id$
+ */
+public abstract class AbstractITextBookRenderer
+ extends AbstractLogEnabled
+ implements BookRenderer
+{
+ /**
+ * @plexus.requirement
+ */
+ private Doxia doxia;
+
+ // ----------------------------------------------------------------------
+ // BookRenderer Implementation
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public void renderBook( BookContext context )
+ throws BookDoxiaException
+ {
+ BookModel book = context.getBook();
+
+ if ( !context.getOutputDirectory().exists() )
+ {
+ if ( !context.getOutputDirectory().mkdirs() )
+ {
+ throw new BookDoxiaException( "Could not make directory: "
+ + context.getOutputDirectory().getAbsolutePath() + "." );
+ }
+ }
+
+ File bookFile = new File( context.getOutputDirectory(), book.getId() + ".xml" );
+
+ Writer fileWriter;
+ try
+ {
+ fileWriter = WriterFactory.newXmlWriter( bookFile );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while opening file.", e );
+ }
+
+ // ----------------------------------------------------------------------
+ // Create the XML File
+ // ----------------------------------------------------------------------
+
+ PrettyPrintXMLWriter writer = new PrettyPrintXMLWriter( fileWriter, "UTF-8", null );
+ writer.startElement( "itext" );
+ writer.addAttribute( "creationdate", DateFormat.getDateTimeInstance().format( new Date() ) );
+ writer.addAttribute( "producer", "Doxia iText" );
+
+ // writer.startElement( "paragraph" );
+ // writer.addAttribute( "leading", "18.0" );
+ // writer.addAttribute( "font", "unknown" );
+ // writer.addAttribute( "align", "Default" );
+ // writer.writeText( "Please visit my" + System.getProperty( "line.separator" ) );
+ //
+ // writer.startElement( "anchor" );
+ // writer.addAttribute( "leading", "18.0" );
+ // writer.addAttribute( "font", "Helvetica" );
+ // writer.addAttribute( "size", "12.0" );
+ // writer.addAttribute( "fontstyle", "normal, underline" );
+ // writer.addAttribute( "red", "0" );
+ // writer.addAttribute( "green", "0" );
+ // writer.addAttribute( "blue", "255" );
+ // writer.addAttribute( "name", "top" );
+ // writer.addAttribute( "reference", "http://www.lowagie.com/iText/" );
+ //
+ // writer.startElement( "chunk" );
+ // writer.addAttribute( "font", "Helvetica" );
+ // writer.addAttribute( "size", "12.0" );
+ // writer.addAttribute( "fontstyle", "normal, underline" );
+ // writer.addAttribute( "red", "0" );
+ // writer.addAttribute( "green", "0" );
+ // writer.addAttribute( "blue", "255" );
+ // writer.writeText( "website (external reference)" );
+ // writer.endElement();
+ //
+ // writer.endElement(); // anchor
+ //
+ // writer.endElement(); // paragraph
+
+ // TODO: Write out TOC
+
+ System.setProperty( "itext.basedir", bookFile.getParentFile().getAbsolutePath() );
+ Sink sink = new ITextSinkFactory().createSink( writer );
+
+ try
+ {
+ for ( Chapter chapter : book.getChapters() )
+ {
+ renderChapter( sink, writer, chapter, context );
+ }
+
+ writer.endElement(); // itext
+ }
+ finally
+ {
+ sink.flush();
+ sink.close();
+
+ IOUtil.close( fileWriter );
+ System.getProperties().remove( "itext.basedir" );
+ }
+
+ // ----------------------------------------------------------------------
+ // Render the XML to PDF
+ // ----------------------------------------------------------------------
+ File outputFile = new File( context.getOutputDirectory(), book.getId() + "." + getOutputExtension() );
+ try
+ {
+ renderXML( bookFile, outputFile );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while rendering file", e );
+ }
+ }
+
+ /**
+ * Get the output extension supported.
+ *
+ * @return the ouput extension supported.
+ */
+ public abstract String getOutputExtension();
+
+ /**
+ * Generate an ouput file with the iText framework.
+ *
+ * @param iTextFile the input file.
+ * @param iTextOutput the output file.
+ * @throws java.io.IOException if any.
+ */
+ public abstract void renderXML( File iTextFile, File iTextOutput )
+ throws IOException;
+
+ // ----------------------------------------------------------------------
+ // Private
+ // ----------------------------------------------------------------------
+
+ /**
+ * Write a chapter.
+ *
+ * @param writer the writer.
+ * @param chapter the Chapter.
+ * @param context the BookContext.
+ * @throws BookDoxiaException if the chapter cannot be written.
+ */
+ private void renderChapter( Sink sink, PrettyPrintXMLWriter writer, Chapter chapter, BookContext context )
+ throws BookDoxiaException
+ {
+ writer.startElement( "chapter" );
+ writer.addAttribute( "numberdepth", "1" );
+ writer.addAttribute( "depth", "1" );
+ writer.addAttribute( "indent", "1" );
+
+ startTitle( writer, "36.0", "Helvetica", "24.0", "normal", "255", "0", "0" );
+ chunk( writer, chapter.getTitle(), "Helvetica", "24.0", "normal", "255", "0", "0" );
+ writer.endElement(); // title
+
+ // writer.startElement( "sectioncontent" );
+ for ( Section section : chapter.getSections() )
+ {
+ renderSection( sink, writer, section, context );
+ }
+ // writer.endElement(); // sectioncontent
+
+ writer.endElement(); // chapter
+ }
+
+ /**
+ * Write a section.
+ *
+ * @param writer the writer.
+ * @param section the Section.
+ * @param context the BookContext.
+ * @throws BookDoxiaException if the section cannot be written.
+ */
+ private void renderSection( Sink sink, PrettyPrintXMLWriter writer, Section section, BookContext context )
+ throws BookDoxiaException
+ {
+ // writer.startElement( "section" );
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ BookContext.BookFile bookFile = (BookContext.BookFile) context.getFiles().get( section.getId() );
+
+ if ( bookFile == null )
+ {
+ throw new BookDoxiaException( "No document that matches section with id=" + section.getId() + "." );
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ Reader reader = null;
+ try
+ {
+ reader = ReaderFactory.newReader( bookFile.getFile(), context.getInputEncoding() );
+ doxia.parse( reader, bookFile.getParserId(), sink );
+ }
+ catch ( ParserNotFoundException e )
+ {
+ throw new BookDoxiaException( "Parser not found: " + bookFile.getParserId() + ".", e );
+ }
+ catch ( ParseException e )
+ {
+ throw new BookDoxiaException(
+ "Error while parsing document: " + bookFile.getFile().getAbsolutePath() + ".",
+ e );
+ }
+ catch ( FileNotFoundException e )
+ {
+ throw new BookDoxiaException( "Could not find document: " + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while rendering book: "
+ + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ finally
+ {
+ IOUtil.close( reader );
+ }
+ }
+
+ /**
+ * Start a title.
+ *
+ * @param writer the writer.
+ * @param leading leading.
+ * @param font the font.
+ * @param size the size.
+ * @param fontstyle the fontstyle.
+ * @param red red.
+ * @param green green.
+ * @param blue blue.
+ */
+ private void startTitle( PrettyPrintXMLWriter writer, String leading, String font, String size, String fontstyle,
+ String red, String green, String blue )
+ {
+ writer.startElement( "title" );
+ writer.addAttribute( "leading", leading );
+ writer.addAttribute( "font", font );
+ writer.addAttribute( "size", size );
+ writer.addAttribute( "fontstyle", fontstyle );
+ writer.addAttribute( "red", red );
+ writer.addAttribute( "green", green );
+ writer.addAttribute( "blue", blue );
+ }
+
+ /**
+ * Write a chunk.
+ *
+ * @param writer the writer.
+ * @param title the title.
+ * @param font the font.
+ * @param size the size.
+ * @param fontstyle the fontstyle.
+ * @param red red.
+ * @param green green.
+ * @param blue blue.
+ */
+ private void chunk( PrettyPrintXMLWriter writer, String title, String font, String size, String fontstyle,
+ String red, String green, String blue )
+ {
+ writer.startElement( "chunk" );
+ writer.addAttribute( "font", font );
+ writer.addAttribute( "size", size );
+ writer.addAttribute( "fontstyle", fontstyle );
+ writer.addAttribute( "red", red );
+ writer.addAttribute( "green", green );
+ writer.addAttribute( "blue", blue );
+ if ( StringUtils.isNotEmpty( title ) )
+ {
+ writer.writeText( title );
+ }
+ else
+ {
+ writer.writeText( "<Missing title>" );
+ }
+ writer.endElement(); // chunk
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/BookRenderer.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/BookRenderer.java
new file mode 100644
index 0000000..759831f
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/BookRenderer.java
@@ -0,0 +1,44 @@
+package org.apache.maven.doxia.book.services.renderer;
+
+/*
+ * 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.book.context.BookContext;
+import org.apache.maven.doxia.book.BookDoxiaException;
+
+/**
+ * Render a book.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public interface BookRenderer
+{
+ /** The plexus lookup role. */
+ String ROLE = BookRenderer.class.getName();
+
+ /**
+ * Render a book.
+ *
+ * @param context the BookContext.
+ * @throws org.apache.maven.doxia.book.BookDoxiaException if the book cannot be rendered.
+ */
+ void renderBook( BookContext context )
+ throws BookDoxiaException;
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/DocbookBookRenderer.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/DocbookBookRenderer.java
new file mode 100644
index 0000000..0d86ebd
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/DocbookBookRenderer.java
@@ -0,0 +1,223 @@
+package org.apache.maven.doxia.book.services.renderer;
+
+/*
+ * 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.FileNotFoundException;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+import org.apache.maven.doxia.Doxia;
+import org.apache.maven.doxia.book.BookDoxiaException;
+import org.apache.maven.doxia.book.context.BookContext;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.model.Chapter;
+import org.apache.maven.doxia.book.model.Section;
+import org.apache.maven.doxia.book.services.renderer.docbook.DocBookBookSink;
+import org.apache.maven.doxia.parser.ParseException;
+import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
+import org.apache.maven.doxia.sink.Sink;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.WriterFactory;
+
+/**
+ * An implementation of <code>BookRenderer</code> for docbook
+ *
+ * @plexus.component role-hint="doc-book"
+ * @author Eric Redmond
+ * @version $Id$
+ */
+public class DocbookBookRenderer
+ extends AbstractLogEnabled
+ implements BookRenderer
+{
+ /**
+ * @plexus.requirement
+ */
+ private Doxia doxia;
+
+ // ----------------------------------------------------------------------
+ // BookRenderer Implementation
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public void renderBook( BookContext context )
+ throws BookDoxiaException
+ {
+ BookModel book = context.getBook();
+
+ if ( !context.getOutputDirectory().exists() )
+ {
+ if ( !context.getOutputDirectory().mkdirs() )
+ {
+ throw new BookDoxiaException( "Could not make directory: "
+ + context.getOutputDirectory().getAbsolutePath() + "." );
+ }
+ }
+
+ File bookFile = new File( context.getOutputDirectory(), book.getId() + ".xml" );
+
+ Writer fileWriter;
+ try
+ {
+ fileWriter = WriterFactory.newXmlWriter( bookFile );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while opening file.", e );
+ }
+
+ // ----------------------------------------------------------------------
+ // Create the Dockbook File
+ // ----------------------------------------------------------------------
+
+ // TODO: Write out TOC?
+
+ DocBookBookSink sink = new DocBookBookSink( fileWriter );
+
+ try
+ {
+ sink.book();
+
+ // TODO: symmetrize bookHead?
+
+ if ( StringUtils.isNotEmpty( book.getTitle() ) )
+ {
+ sink.bookTitle();
+ sink.text( book.getTitle() );
+ sink.bookTitle_();
+ }
+
+ if ( StringUtils.isNotEmpty( book.getDate() ) )
+ {
+ sink.bookDate();
+ sink.text( book.getDate() );
+ sink.bookDate_();
+ }
+
+ if ( StringUtils.isNotEmpty( book.getAuthor() ) )
+ {
+ sink.bookAuthor();
+ sink.text( book.getAuthor() );
+ sink.bookAuthor_();
+ }
+
+ sink.bookHead_();
+
+ for ( Chapter chapter : book.getChapters() )
+ {
+ sink.chapter();
+
+ if ( StringUtils.isNotEmpty( chapter.getTitle() ) )
+ {
+ sink.chapterTitle();
+ sink.text( chapter.getTitle() );
+ sink.chapterTitle_();
+ }
+
+ renderChapter( chapter, context, sink );
+
+ sink.chapter_();
+ }
+
+ sink.book_();
+ }
+ finally
+ {
+ sink.flush();
+
+ sink.close();
+
+ IOUtil.close( fileWriter );
+ }
+ }
+
+ /**
+ * Write a chapter.
+ *
+ * @param writer the writer.
+ * @param chapter the Chapter.
+ * @param context the BookContext.
+ * @param sink a Sink.
+ * @throws BookDoxiaException if the chapter cannot be written.
+ */
+ private void renderChapter( Chapter chapter, BookContext context, Sink sink )
+ throws BookDoxiaException
+ {
+ for ( Section section : chapter.getSections() )
+ {
+ renderSection( section, context, sink );
+ }
+ }
+
+ /**
+ * Write a section.
+ *
+ * @param writer the writer.
+ * @param section the Section.
+ * @param context the BookContext.
+ * @param sink a Sink.
+ * @throws BookDoxiaException if the section cannot be written.
+ */
+ private void renderSection( Section section, BookContext context, Sink sink )
+ throws BookDoxiaException
+ {
+ BookContext.BookFile bookFile = (BookContext.BookFile) context.getFiles().get( section.getId() );
+
+ if ( bookFile == null )
+ {
+ throw new BookDoxiaException( "No document that matches section with id=" + section.getId() + "." );
+ }
+
+ Reader reader = null;
+ try
+ {
+ reader = ReaderFactory.newReader( bookFile.getFile(), context.getInputEncoding() );
+ doxia.parse( reader, bookFile.getParserId(), sink );
+ }
+ catch ( ParserNotFoundException e )
+ {
+ throw new BookDoxiaException( "Parser not found: " + bookFile.getParserId() + ".", e );
+ }
+ catch ( ParseException e )
+ {
+ throw new BookDoxiaException(
+ "Error while parsing document: " + bookFile.getFile().getAbsolutePath() + ".",
+ e );
+ }
+ catch ( FileNotFoundException e )
+ {
+ throw new BookDoxiaException( "Could not find document: " + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while rendering book: "
+ + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ finally
+ {
+ IOUtil.close( reader );
+ }
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/LatexBookRenderer.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/LatexBookRenderer.java
new file mode 100644
index 0000000..0c5b383
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/LatexBookRenderer.java
@@ -0,0 +1,246 @@
+package org.apache.maven.doxia.book.services.renderer;
+
+/*
+ * 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.book.BookDoxiaException;
+import org.apache.maven.doxia.book.services.renderer.latex.LatexBookSink;
+import org.apache.maven.doxia.book.context.BookContext;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.model.Chapter;
+import org.apache.maven.doxia.book.model.Section;
+import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
+import org.apache.maven.doxia.parser.ParseException;
+import org.apache.maven.doxia.Doxia;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.WriterFactory;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.FileNotFoundException;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * <p>LatexBookRenderer class.</p>
+ *
+ * @plexus.component role-hint="latex"
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class LatexBookRenderer
+ implements BookRenderer
+{
+ /**
+ * @plexus.requirement
+ */
+ private Doxia doxia;
+
+ // ----------------------------------------------------------------------
+ // BookRenderer Implementatino
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public void renderBook( BookContext context )
+ throws BookDoxiaException
+ {
+ BookModel book = context.getBook();
+
+ if ( !context.getOutputDirectory().exists() )
+ {
+ if ( !context.getOutputDirectory().mkdirs() )
+ {
+ throw new BookDoxiaException(
+ "Could not make directory: " + context.getOutputDirectory().getAbsolutePath() + "." );
+ }
+ }
+
+ File bookFile = new File( context.getOutputDirectory(), book.getId() + ".tex" );
+
+ FileWriter fileWriter = null;
+
+ try
+ {
+ fileWriter = new FileWriter( bookFile );
+
+ PrintWriter writer = new PrintWriter( fileWriter );
+
+ writeBook( book, context, writer );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while opening file.", e );
+ }
+ finally
+ {
+ IOUtil.close( fileWriter );
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Private
+ // ----------------------------------------------------------------------
+
+ /** SectionInfo: id and title. */
+ static class SectionInfo
+ {
+ /** id. */
+ String id;
+
+ /** title. */
+ String title;
+ }
+
+ /**
+ * Write a book.
+ *
+ * @param book the BookModel to write.
+ * @param context the BookContext.
+ * @param writer the writer to use.
+ * @throws IOException if any.
+ * @throws BookDoxiaException if the section cannot be written.
+ */
+ private void writeBook( BookModel book, BookContext context, PrintWriter writer )
+ throws IOException, BookDoxiaException
+ {
+ // ----------------------------------------------------------------------
+ // Process all the section documents and collect their names
+ // ----------------------------------------------------------------------
+
+ Map<String, SectionInfo> sectionInfos = new HashMap<String, SectionInfo>();
+
+ for ( Chapter chapter : book.getChapters() )
+ {
+ for ( Section section : chapter.getSections() )
+ {
+ SectionInfo info = writeSection( section, context );
+
+ sectionInfos.put( info.id, info );
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Write the main .tex file
+ // ----------------------------------------------------------------------
+
+ writer.println( "\\documentclass{book}" );
+ writer.println( "\\title{" + book.getTitle() + "}" );
+
+ if ( StringUtils.isNotEmpty( book.getAuthor() ) )
+ {
+ writer.println( "\\author{" + book.getAuthor() + "}" );
+ }
+
+ if ( StringUtils.isNotEmpty( book.getDate() ) )
+ {
+ writer.println( "\\date{" + book.getDate() + "}" );
+ }
+
+ LatexBookSink sink = new LatexBookSink( writer );
+ sink.defaultBookPreamble();
+
+ writer.println( "\\begin{document}" );
+ writer.println( "\\maketitle" );
+ writer.println( "\\tableofcontents" );
+// writer.println( "\\listoffigures" );
+
+ for ( Chapter chapter : book.getChapters() )
+ {
+ writer.println( "\\chapter{" + chapter.getTitle() + "}" );
+
+ for ( Section section : chapter.getSections() )
+ {
+ SectionInfo info = sectionInfos.get( section.getId() );
+
+ writer.println( "\\input{" + info.id + "}" );
+ }
+ }
+
+ writer.println( "\\end{document}" );
+ }
+
+ /**
+ * Write a section.
+ *
+ * @param section the Section to write.
+ * @param context the BookContext.
+ * @return SectionInfo
+ * @throws IOException if any.
+ * @throws BookDoxiaException if the section cannot be written.
+ */
+ private SectionInfo writeSection( Section section, BookContext context )
+ throws IOException, BookDoxiaException
+ {
+ File file = new File( context.getOutputDirectory(), ( section.getId() + ".tex" ) );
+
+ Writer writer = WriterFactory.newWriter( file, context.getOutputEncoding() );
+
+ LatexBookSink sink = new LatexBookSink( writer );
+
+ BookContext.BookFile bookFile = (BookContext.BookFile) context.getFiles().get( section.getId() );
+
+ if ( bookFile == null )
+ {
+ throw new BookDoxiaException( "No document that matches section with id="
+ + section.getId() + "." );
+ }
+
+ Reader reader = null;
+ try
+ {
+ reader = ReaderFactory.newReader( bookFile.getFile(), context.getInputEncoding() );
+ doxia.parse( reader, bookFile.getParserId(), sink );
+ }
+ catch ( ParserNotFoundException e )
+ {
+ throw new BookDoxiaException( "Parser not found: "
+ + bookFile.getParserId() + ".", e );
+ }
+ catch ( ParseException e )
+ {
+ throw new BookDoxiaException( "Error while parsing document: "
+ + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ catch ( FileNotFoundException e )
+ {
+ throw new BookDoxiaException( "Could not find document: "
+ + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ finally
+ {
+ sink.flush();
+ sink.close();
+
+ IOUtil.close( reader );
+ IOUtil.close( writer );
+ }
+
+ SectionInfo info = new SectionInfo();
+ info.id = section.getId();
+ info.title = sink.getTitle();
+
+ return info;
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/PdfBookRenderer.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/PdfBookRenderer.java
new file mode 100644
index 0000000..b6a1ae5
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/PdfBookRenderer.java
@@ -0,0 +1,52 @@
+package org.apache.maven.doxia.book.services.renderer;
+
+/*
+ * 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.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.maven.doxia.module.itext.ITextUtil;
+
+/**
+ * PDF book renderer with the <code>iText</code> framework.
+ *
+ * @plexus.component role-hint="pdf"
+ *
+ * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
+ * @version $Id$
+ */
+public class PdfBookRenderer
+ extends AbstractITextBookRenderer
+{
+ /** {@inheritDoc} */
+ public String getOutputExtension()
+ {
+ return "pdf";
+ }
+
+ /** {@inheritDoc} */
+ public void renderXML( File iTextFile, File iTextOutput )
+ throws IOException
+ {
+ ITextUtil.writePdf( new FileInputStream( iTextFile ), new FileOutputStream( iTextOutput ) );
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/RtfBookRenderer.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/RtfBookRenderer.java
new file mode 100644
index 0000000..0e60e13
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/RtfBookRenderer.java
@@ -0,0 +1,52 @@
+package org.apache.maven.doxia.book.services.renderer;
+
+/*
+ * 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.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.apache.maven.doxia.module.itext.ITextUtil;
+
+/**
+ * RTF book renderer with the <code>iText</code> framework.
+ *
+ * @plexus.component role-hint="rtf"
+ *
+ * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
+ * @version $Id$
+ */
+public class RtfBookRenderer
+ extends AbstractITextBookRenderer
+{
+ /** {@inheritDoc} */
+ public String getOutputExtension()
+ {
+ return "rtf";
+ }
+
+ /** {@inheritDoc} */
+ public void renderXML( File iTextFile, File iTextOutput )
+ throws IOException
+ {
+ ITextUtil.writeRtf( new FileInputStream( iTextFile ), new FileOutputStream( iTextOutput ) );
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/XHtmlBookRenderer.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/XHtmlBookRenderer.java
new file mode 100644
index 0000000..ad6f585
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/XHtmlBookRenderer.java
@@ -0,0 +1,208 @@
+package org.apache.maven.doxia.book.services.renderer;
+
+/*
+ * 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.Doxia;
+import org.apache.maven.doxia.book.context.BookContext;
+import org.apache.maven.doxia.book.BookDoxiaException;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.model.Chapter;
+import org.apache.maven.doxia.book.model.Section;
+import org.apache.maven.doxia.book.services.renderer.xhtml.XhtmlBookSink;
+import org.apache.maven.doxia.sink.render.RenderingContext;
+import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
+import org.apache.maven.doxia.parser.ParseException;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+
+/**
+ * <p>XHtmlBookRenderer class.</p>
+ *
+ * @plexus.component role-hint="xhtml"
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class XHtmlBookRenderer
+ extends AbstractLogEnabled
+ implements BookRenderer
+{
+ /**
+ * @plexus.requirement
+ */
+ private Doxia doxia;
+
+ // ----------------------------------------------------------------------
+ // BookRenderer Implementation
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public void renderBook( BookContext context )
+ throws BookDoxiaException
+ {
+ BookModel book = context.getBook();
+
+ if ( !context.getOutputDirectory().exists() )
+ {
+ if ( !context.getOutputDirectory().mkdirs() )
+ {
+ throw new BookDoxiaException( "Could not make directory: "
+ + context.getOutputDirectory().getAbsolutePath() + "." );
+ }
+ }
+
+ File bookFile = new File( context.getOutputDirectory(), book.getId() + ".xhtml" );
+
+ Writer fileWriter;
+
+ try
+ {
+ fileWriter = new FileWriter( bookFile );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while opening file.", e );
+ }
+
+ XhtmlBookSink sink = new XhtmlBookSink( fileWriter,
+ new RenderingContext( context.getOutputDirectory(), bookFile.getAbsolutePath() ) );
+
+ try
+ {
+ sink.bookHead();
+ sink.bookTitle();
+ sink.text( context.getBook().getTitle() );
+ sink.bookTitle_();
+ sink.bookAuthor();
+ sink.text( context.getBook().getAuthor() );
+ sink.bookAuthor_();
+ sink.bookDate();
+ sink.text( context.getBook().getDate() );
+ sink.bookDate_();
+ sink.bookHead_();
+ sink.bookBody();
+
+ int chapterNumber = 1;
+
+ for ( Chapter chapter : book.getChapters() )
+ {
+ sink.sectionTitle();
+ sink.text( Integer.toString( chapterNumber ) + ". " + chapter.getTitle() );
+ sink.sectionTitle_();
+
+ renderChapter( sink, chapter, context );
+
+ chapterNumber++;
+ }
+
+ sink.bookBody_();
+ }
+ finally
+ {
+ sink.flush();
+
+ sink.close();
+
+ IOUtil.close( fileWriter );
+ }
+ }
+
+ // ----------------------------------------------------------------------
+ // Private
+ // ----------------------------------------------------------------------
+
+ /**
+ * Write a chapter.
+ *
+ * @param sink the XhtmlBookSink.
+ * @param chapter the Chapter.
+ * @param context the BookContext.
+ * @throws BookDoxiaException if the chapter cannot be written.
+ */
+ private void renderChapter( XhtmlBookSink sink, Chapter chapter, BookContext context )
+ throws BookDoxiaException
+ {
+ for ( Section section : chapter.getSections() )
+ {
+ renderSection( sink, section, context );
+ }
+ }
+
+ /**
+ * Write a section.
+ *
+ * @param sink the XhtmlBookSink.
+ * @param section the Section.
+ * @param context the BookContext.
+ * @throws BookDoxiaException if the section cannot be written.
+ */
+ private void renderSection( XhtmlBookSink sink, Section section, BookContext context )
+ throws BookDoxiaException
+ {
+ sink.section2();
+
+ BookContext.BookFile bookFile = context.getFiles().get( section.getId() );
+
+ if ( bookFile == null )
+ {
+ throw new BookDoxiaException( "No document that matches section with id=" + section.getId() + "." );
+ }
+
+ Reader reader = null;
+ try
+ {
+ reader = ReaderFactory.newReader( bookFile.getFile(), context.getInputEncoding() );
+ doxia.parse( reader, bookFile.getParserId(), sink );
+ }
+ catch ( ParserNotFoundException e )
+ {
+ throw new BookDoxiaException( "Parser not found: "
+ + bookFile.getParserId() + ".", e );
+ }
+ catch ( ParseException e )
+ {
+ throw new BookDoxiaException( "Error while parsing document: "
+ + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ catch ( FileNotFoundException e )
+ {
+ throw new BookDoxiaException( "Could not find document: "
+ + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while rendering book: "
+ + bookFile.getFile().getAbsolutePath() + ".", e );
+ }
+ finally
+ {
+ IOUtil.close( reader );
+ }
+
+ sink.section2_();
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/XdocBookRenderer.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/XdocBookRenderer.java
new file mode 100644
index 0000000..f5c6541
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/XdocBookRenderer.java
@@ -0,0 +1,445 @@
+package org.apache.maven.doxia.book.services.renderer;
+
+/*
+ * 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.FileNotFoundException;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Iterator;
+import java.util.Locale;
+
+import org.apache.maven.doxia.Doxia;
+import org.apache.maven.doxia.book.BookDoxiaException;
+import org.apache.maven.doxia.book.context.BookContext;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.model.Chapter;
+import org.apache.maven.doxia.book.model.Section;
+import org.apache.maven.doxia.book.services.renderer.xdoc.ChapterXdocBookSink;
+import org.apache.maven.doxia.book.services.renderer.xdoc.IndexXdocBookSink;
+import org.apache.maven.doxia.book.services.renderer.xdoc.SectionXdocBookSink;
+import org.apache.maven.doxia.index.IndexEntry;
+import org.apache.maven.doxia.module.xdoc.XdocSink;
+import org.apache.maven.doxia.parser.ParseException;
+import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
+import org.apache.maven.doxia.util.HtmlTools;
+import org.codehaus.plexus.i18n.I18N;
+import org.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.util.IOUtil;
+import org.codehaus.plexus.util.ReaderFactory;
+import org.codehaus.plexus.util.StringUtils;
+import org.codehaus.plexus.util.WriterFactory;
+
+/**
+ * An implementation of <code>BookRenderer</code> for Xdoc
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
+ * @version $Id$
+ * @plexus.component role-hint="xdoc"
+ */
+public class XdocBookRenderer
+ extends AbstractLogEnabled
+ implements BookRenderer
+{
+ /**
+ * @plexus.requirement
+ */
+ private Doxia doxia;
+
+ /**
+ * @plexus.requirement
+ */
+ private I18N i18n;
+
+ // ----------------------------------------------------------------------
+ // BookRenderer Implementation
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public void renderBook( BookContext context )
+ throws BookDoxiaException
+ {
+ BookModel book = context.getBook();
+
+ if ( !context.getOutputDirectory().exists() )
+ {
+ if ( !context.getOutputDirectory().mkdirs() )
+ {
+ throw new BookDoxiaException( "Could not make directory: "
+ + context.getOutputDirectory().getAbsolutePath() + "." );
+ }
+ }
+
+ renderBook( book, context );
+ }
+
+ // -----------------------------------------------------------------------
+ // Protected
+ // -----------------------------------------------------------------------
+
+ /**
+ * Gets a trimmed String for the given key from the resource bundle defined by Plexus.
+ *
+ * @param locale the locale used
+ * @param key the key for the desired string
+ * @return the string for the given key and the given locale
+ */
+ protected String getString( Locale locale, String key )
+ {
+ if ( StringUtils.isEmpty( key ) )
+ {
+ throw new IllegalArgumentException( "The key cannot be empty" );
+ }
+
+ return i18n.getString( "book-renderer", locale, key ).trim();
+ }
+
+ // -----------------------------------------------------------------------
+ // Private
+ // -----------------------------------------------------------------------
+
+ /**
+ * Render the book, ie the book index and all chapter index and pages
+ *
+ * @param book the BookModel.
+ * @param context the BookContext.
+ * @throws BookDoxiaException if any
+ */
+ private void renderBook( BookModel book, BookContext context )
+ throws BookDoxiaException
+ {
+ // -----------------------------------------------------------------------
+ // Render the book index.xml page
+ // -----------------------------------------------------------------------
+
+ File index = new File( context.getOutputDirectory(), "index.xml" );
+
+ try
+ {
+ writeBookIndex( index, book, context );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while rendering index page to: '"
+ + index.getAbsolutePath() + "'.", e );
+ }
+
+ // -----------------------------------------------------------------------
+ // Render all the chapter pages
+ // -----------------------------------------------------------------------
+
+ Iterator<IndexEntry> ii = context.getIndex().getChildEntries().iterator();
+
+ for ( Chapter chapter : book.getChapters() )
+ {
+ renderChapter( chapter, context, ii.next() );
+ }
+ }
+
+ /**
+ * Write the book index, ie a TOC.
+ *
+ * @param index the File.
+ * @param book the BookModel.
+ * @param context the BookContext.
+ * @throws IOException if any
+ */
+ private void writeBookIndex( File index, BookModel book, BookContext context )
+ throws IOException
+ {
+ Writer writer = WriterFactory.newXmlWriter( index );
+
+ XdocSink sink = new IndexXdocBookSink( writer, context.getIndex().getFirstEntry(), i18n, context.getLocale() );
+
+ try
+ {
+ // -----------------------------------------------------------------------
+ // Head
+ // -----------------------------------------------------------------------
+
+ sink.head();
+
+ sink.title();
+ sink.text( book.getTitle() + " - " + getString( context.getLocale(), "toc" ) );
+ sink.title_();
+
+ sink.head_();
+
+ // -----------------------------------------------------------------------
+ // Body
+ // -----------------------------------------------------------------------
+
+ sink.body();
+
+ sink.section1();
+ sink.sectionTitle1();
+ sink.text( book.getTitle() + " - " + getString( context.getLocale(), "toc" ) );
+ sink.sectionTitle1_();
+
+ sink.list();
+ for ( IndexEntry entry : context.getIndex().getChildEntries() )
+ {
+ writeChapterIndexForBookIndex( sink, entry );
+ }
+ sink.list_();
+
+ sink.section1_();
+
+ sink.body_();
+ }
+ finally
+ {
+ sink.flush();
+
+ sink.close();
+
+ IOUtil.close( writer );
+ }
+ }
+
+ /**
+ * Write the chapter index for the book index.
+ *
+ * @param sink the XdocSink.
+ * @param chapterEntry the chapter IndexEntry.
+ */
+ private void writeChapterIndexForBookIndex( XdocSink sink, IndexEntry chapterEntry )
+ {
+ sink.listItem();
+ sink.link( chapterEntry.getId() + ".html" );
+ sink.text( chapterEntry.getTitle() );
+ sink.link_();
+
+ sink.list();
+ for ( IndexEntry sectionIndex : chapterEntry.getChildEntries() )
+ {
+ writeSectionIndexForBookIndex( sink, sectionIndex );
+ }
+ sink.list_();
+
+ sink.listItem_();
+ }
+
+ /**
+ * Write the section index for the book index.
+ *
+ * @param sink the XdocSink.
+ * @param sectionIndex the section IndexEntry.
+ */
+ private void writeSectionIndexForBookIndex( XdocSink sink, IndexEntry sectionIndex )
+ {
+ sink.listItem();
+ sink.link( sectionIndex.getId() + ".html" );
+ sink.text( sectionIndex.getTitle() );
+ sink.link_();
+
+ sink.list();
+ for ( IndexEntry subsectionIndex : sectionIndex.getChildEntries() )
+ {
+ writeSubsectionIndexForBookIndex( sink, sectionIndex, subsectionIndex );
+ }
+ sink.list_();
+
+ sink.listItem_();
+ }
+
+ /**
+ * Write subsection index for the book index.
+ *
+ * @param sink the XdocSink.
+ * @param sectionIndex the section IndexEntry.
+ * @param subsectionIndex the subsection IndexEntry.
+ */
+ private void writeSubsectionIndexForBookIndex( XdocSink sink, IndexEntry sectionIndex, IndexEntry subsectionIndex )
+ {
+ sink.listItem();
+ sink.link( sectionIndex.getId() + ".html#" + HtmlTools.encodeId( subsectionIndex.getId() ) );
+ sink.text( subsectionIndex.getTitle() );
+ sink.link_();
+ sink.listItem_();
+ }
+
+ // -----------------------------------------------------------------------
+ // Rendering
+ // -----------------------------------------------------------------------
+
+ /**
+ * Render the chapter index and all section pages.
+ *
+ * @param chapter the Chapter.
+ * @param context the BookContext.
+ * @param chapterIndex the IndexEntry.
+ * @throws BookDoxiaException if any
+ */
+ private void renderChapter( Chapter chapter, BookContext context, IndexEntry chapterIndex )
+ throws BookDoxiaException
+ {
+ // -----------------------------------------------------------------------
+ // Render the chapter index page
+ // -----------------------------------------------------------------------
+
+ File index = new File( context.getOutputDirectory(), chapter.getId() + ".xml" );
+
+ try
+ {
+ writeChapterIndex( index, chapter, chapterIndex, context );
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while rendering index page to: '"
+ + index.getAbsolutePath() + "'.", e );
+ }
+
+ // -----------------------------------------------------------------------
+ // Render all section pages
+ // -----------------------------------------------------------------------
+
+ Iterator<IndexEntry> ii = chapterIndex.getChildEntries().iterator();
+
+ for ( Section section : chapter.getSections() )
+ {
+ renderSection( context, section, ii.next() );
+ }
+ }
+
+ /**
+ * Write a chapter index
+ *
+ * @param index the File.
+ * @param context the context.
+ * @param chapter the Chapter.
+ * @param chapterIndex the IndexEntry.
+ * @throws IOException if any.
+ */
+ private void writeChapterIndex( File index, Chapter chapter, IndexEntry chapterIndex, BookContext context )
+ throws IOException
+ {
+ Writer writer = WriterFactory.newXmlWriter( index );
+
+ ChapterXdocBookSink sink = new ChapterXdocBookSink( writer, chapterIndex, i18n, context.getLocale() );
+
+ try
+ {
+ // -----------------------------------------------------------------------
+ // Head
+ // -----------------------------------------------------------------------
+
+ sink.head();
+
+ sink.title();
+ sink.text( chapter.getTitle() );
+ sink.title_();
+
+ sink.head_();
+
+ // -----------------------------------------------------------------------
+ // Body
+ // -----------------------------------------------------------------------
+
+ sink.body();
+
+ sink.section1();
+ sink.sectionTitle1();
+ sink.text( chapter.getTitle() );
+ sink.sectionTitle1_();
+
+ sink.list();
+ for ( IndexEntry sectionIndex : chapterIndex.getChildEntries() )
+ {
+ writeSectionIndexForBookIndex( sink, sectionIndex );
+ }
+ sink.list_();
+
+ sink.section1_();
+
+ sink.body_();
+ }
+ finally
+ {
+ sink.flush();
+
+ sink.close();
+
+ IOUtil.close( writer );
+ }
+ }
+
+ /**
+ * Render all section pages.
+ *
+ * @param context the BookContext.
+ * @param section the Section.
+ * @param sectionIndex the IndexEntry.
+ * @throws BookDoxiaException if any.
+ */
+ private void renderSection( BookContext context, Section section, IndexEntry sectionIndex )
+ throws BookDoxiaException
+ {
+ try
+ {
+ Writer writer = WriterFactory.newXmlWriter( new File( context.getOutputDirectory()
+ + "/" + section.getId() + ".xml" ) );
+
+ SectionXdocBookSink sink = new SectionXdocBookSink( writer, sectionIndex, i18n, context.getLocale() );
+
+ BookContext.BookFile bookFile = (BookContext.BookFile) context.getFiles().get( section.getId() );
+
+ if ( bookFile == null )
+ {
+ throw new BookDoxiaException( "No document that matches section with id=" + section.getId() + "." );
+ }
+
+ Reader reader = null;
+ try
+ {
+ reader = ReaderFactory.newReader( bookFile.getFile(), context.getInputEncoding() );
+ doxia.parse( reader, bookFile.getParserId(), sink );
+ }
+ catch ( ParserNotFoundException e )
+ {
+ throw new BookDoxiaException( "Parser not found: " + bookFile.getParserId() + ".", e );
+ }
+ catch ( ParseException e )
+ {
+ throw new BookDoxiaException( "Error while parsing document: " + bookFile.getFile().getAbsolutePath()
+ + ".", e );
+ }
+ catch ( FileNotFoundException e )
+ {
+ throw new BookDoxiaException( "Could not find document: " + bookFile.getFile().getAbsolutePath() + ".",
+ e );
+ }
+ finally
+ {
+ sink.flush();
+ sink.close();
+
+ IOUtil.close( reader );
+ IOUtil.close( writer );
+ }
+ }
+ catch ( IOException e )
+ {
+ throw new BookDoxiaException( "Error while rendering book.", e );
+ }
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/docbook/DocBookBookSink.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/docbook/DocBookBookSink.java
new file mode 100644
index 0000000..56a632b
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/docbook/DocBookBookSink.java
@@ -0,0 +1,270 @@
+package org.apache.maven.doxia.book.services.renderer.docbook;
+
+/*
+ * 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.Writer;
+
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.html.HTML.Tag;
+
+import org.apache.maven.doxia.module.docbook.DocBookSink;
+
+/**
+ * An Docbook Sink that doesn't write out head or body elements for every section of a book, and has some convenience
+ * methods relating to the construction of a Doxia Book.
+ *
+ * @author Dave Syer
+ * @version $Id$
+ * @since 1.1
+ */
+public class DocBookBookSink
+ extends DocBookSink
+{
+ /** Indicates if we're inside a head. */
+ private boolean hasHead = false;
+
+ /**
+ * Construct a new DocBookSink.
+ *
+ * @param out the writer for the sink.
+ */
+ public DocBookBookSink( Writer out )
+ {
+ super( out );
+
+ setSystemId( "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd" );
+ setPublicId( "-//OASIS//DTD DocBook V4.4//EN" );
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing because we don't want the header from each document to crop up in the middle of a book.
+ */
+ public void head()
+ {
+ // noop
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing because we don't want the header from each document to crop up in the middle of a book.
+ */
+ public void head_()
+ {
+ // noop
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Marks the skip flag to true so that this element's text is not emitted by the base class.
+ */
+ public void title()
+ {
+ setSkip( true );
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Marks the skip flag to false so that rendering can resume.
+ */
+ public void title_()
+ {
+ setSkip( false );
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Marks the skip flag to true so that this element's text is not emitted by the base class.
+ */
+ public void author()
+ {
+ setSkip( true );
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Marks the skip flag to false so that rendering can resume.
+ */
+ public void author_()
+ {
+ setSkip( false );
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing because we don't want the header from each document to crop up in the middle of a book.
+ */
+ public void body()
+ {
+ // noop
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing because we don't want the header from each document to crop up in the middle of a book.
+ */
+ public void body_()
+ {
+ // noop
+ }
+
+ /**
+ * Emit the start tag for the book.
+ *
+ * @see org.apache.maven.doxia.module.docbook.DocbookMarkup#BOOK_TAG
+ */
+ public void book()
+ {
+ init();
+
+ MutableAttributeSet att = writeXmlHeader( "book" );
+
+ writeStartTag( BOOK_TAG, att );
+
+ }
+
+ /**
+ * Emit the end tag for the book.
+ *
+ * @see org.apache.maven.doxia.module.docbook.DocbookMarkup#BOOK_TAG
+ */
+ public void book_()
+ {
+ writeEndTag( BOOK_TAG );
+ flush();
+ }
+
+ /** If no header matter has yet been encountered emit the book info start tag. */
+ private void bookHead()
+ {
+ if ( !hasHead )
+ {
+ writeStartTag( BOOKINFO_TAG );
+ hasHead = true;
+ }
+ }
+
+ /**
+ * If some header matter has been encountered emit the book info end tag.
+ */
+ public void bookHead_()
+ {
+ if ( hasHead )
+ {
+ writeEndTag( BOOKINFO_TAG );
+ hasHead = false;
+ }
+ }
+
+ /**
+ * Emit the title start tag for the whole book.
+ */
+ public void bookTitle()
+ {
+ bookHead();
+ writeStartTag( Tag.TITLE );
+ }
+
+ /**
+ * Emit the title end tag for the whole book.
+ */
+ public void bookTitle_()
+ {
+ super.title_();
+ }
+
+ /**
+ * Emit the author start tag for the whole book.
+ */
+ public void bookAuthor()
+ {
+ bookHead();
+ super.author();
+ }
+
+ /**
+ * Emit the author end tag for the whole book.
+ */
+ public void bookAuthor_()
+ {
+ super.author_();
+ }
+
+ /**
+ * Emit the date start tag for the whole book.
+ */
+ public void bookDate()
+ {
+ bookHead();
+ super.date();
+ }
+
+ /**
+ * Emit the date end tag for the whole book.
+ */
+ public void bookDate_()
+ {
+ super.date_();
+ }
+
+ /**
+ * Emit the chapter start tag.
+ */
+ public void chapter()
+ {
+ writeStartTag( CHAPTER_TAG );
+ }
+
+ /**
+ * Emit the chapter end tag.
+ */
+ public void chapter_()
+ {
+ writeEndTag( CHAPTER_TAG );
+ }
+
+ /**
+ * Emit the chapter title start tag.
+ */
+ public void chapterTitle()
+ {
+ writeStartTag( Tag.TITLE );
+ }
+
+ /**
+ * Emit the chapter title end tag.
+ */
+ public void chapterTitle_()
+ {
+ writeEndTag( Tag.TITLE );
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/latex/LatexBookSink.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/latex/LatexBookSink.java
new file mode 100644
index 0000000..984093e
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/latex/LatexBookSink.java
@@ -0,0 +1,124 @@
+package org.apache.maven.doxia.book.services.renderer.latex;
+
+/*
+ * 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.module.latex.LatexSink;
+
+import java.io.Writer;
+
+/**
+ * <p>LatexBookSink class.</p>
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class LatexBookSink
+ extends LatexSink
+{
+ /** text. */
+ private String txt;
+
+ /** title. */
+ private String title;
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Construct a new LatexBookSink which is a LatexSink with the given writer,
+ * null sinkCommands, null preamble and fragmentDocument = true.
+ *
+ * @param out the writer for the sink.
+ */
+ public LatexBookSink( Writer out )
+ {
+ super( out, null, null, true );
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ protected String getDocumentStart()
+ {
+ return "";
+// return "\\documentclass{book}";
+ }
+
+ /** {@inheritDoc} */
+ protected String getDocumentBegin()
+ {
+ return null;
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public void text( String text )
+ {
+ this.txt = text;
+
+ super.text( text );
+ }
+
+ /** {@inheritDoc} */
+ public void title_()
+ {
+ super.title_();
+
+ this.title = txt;
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Return the title.
+ *
+ * @return String.
+ */
+ public String getTitle()
+ {
+ return title;
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * Writes the default LaTeX commands and preamble in the main book file.
+ *
+ * @since 1.1
+ */
+ public void defaultBookPreamble()
+ {
+ markup( defaultSinkCommands() );
+ markup( defaultPreamble() );
+ flush();
+ }
+
+
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/AbstractXdocBookSink.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/AbstractXdocBookSink.java
new file mode 100644
index 0000000..11944dc
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/AbstractXdocBookSink.java
@@ -0,0 +1,126 @@
+package org.apache.maven.doxia.book.services.renderer.xdoc;
+
+/*
+ * 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.Writer;
+import java.util.Locale;
+
+import org.apache.maven.doxia.module.xdoc.XdocSink;
+
+import org.codehaus.plexus.i18n.I18N;
+import org.codehaus.plexus.util.StringUtils;
+
+/**
+ * Abstract <code>XdocSink</code> implementation for book.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
+ * @version $Id$
+ */
+public abstract class AbstractXdocBookSink
+ extends XdocSink
+{
+ /** I18N for localized messages. */
+ private final I18N i18n;
+
+ /** The wanted locale */
+ private final Locale locale;
+
+ /**
+ * Default constructor.
+ *
+ * @param out a Writer.
+ * @param i18n I18N.
+ * @param locale the wanted locale.
+ */
+ public AbstractXdocBookSink( Writer out, I18N i18n, Locale locale )
+ {
+ super( out );
+
+ this.i18n = i18n;
+ this.locale = locale;
+ }
+
+ /** {@inheritDoc} */
+ public void date_()
+ {
+ // nop
+ }
+
+ /** {@inheritDoc} */
+ public void body()
+ {
+ writeStartTag( BODY );
+
+ write( "<section name=\"\">" );
+
+ navigationPanel();
+ horizontalRule();
+
+ write( "</section>" );
+ }
+
+ /** {@inheritDoc} */
+ public void body_()
+ {
+ write( "<section name=\"\">" );
+
+ horizontalRule();
+
+ navigationPanel();
+
+ write( "</section>" );
+
+ writeEndTag( BODY );
+
+ writeEndTag( DOCUMENT_TAG );
+
+ flush();
+
+ close();
+
+ init();
+ }
+
+ // -----------------------------------------------------------------------
+ // Protected
+ // -----------------------------------------------------------------------
+
+ /**
+ * Gets a trimmed String for the given key from the resource bundle defined by Plexus.
+ *
+ * @param key the key for the desired string
+ * @return the string for the given key
+ */
+ protected String getString( String key )
+ {
+ if ( StringUtils.isEmpty( key ) )
+ {
+ throw new IllegalArgumentException( "The key cannot be empty" );
+ }
+
+ return i18n.getString( "book-renderer", locale, key ).trim();
+ }
+
+ /**
+ * Add a navigation panel.
+ */
+ protected abstract void navigationPanel();
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/ChapterXdocBookSink.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/ChapterXdocBookSink.java
new file mode 100644
index 0000000..c3d90c1
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/ChapterXdocBookSink.java
@@ -0,0 +1,151 @@
+package org.apache.maven.doxia.book.services.renderer.xdoc;
+
+/*
+ * 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.Writer;
+import java.util.Locale;
+
+import org.apache.maven.doxia.index.IndexEntry;
+import org.codehaus.plexus.i18n.I18N;
+
+/**
+ * A <code>XdocSink</code> implementation for chapter in a book.
+ *
+ * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
+ * @version $Id$
+ */
+public class ChapterXdocBookSink
+ extends AbstractXdocBookSink
+{
+ /** the chapter IndexEntry. */
+ private final IndexEntry chapterIndex;
+
+ /**
+ * Default constructor.
+ *
+ * @param out the Writer.
+ * @param chapterIndex the chapter IndexEntry.
+ * @param i18n I18N.
+ * @param locale wanted locale.
+ */
+ public ChapterXdocBookSink( Writer out, IndexEntry chapterIndex, I18N i18n, Locale locale )
+ {
+ super( out, i18n, locale );
+
+ this.chapterIndex = chapterIndex;
+ }
+
+ /** {@inheritDoc} */
+ protected void navigationPanel()
+ {
+ write( "<!--Navigation Panel-->" );
+
+ write( "<table width=\"100%\" align=\"center\">" );
+ write( "<tr>" );
+
+ // -----------------------------------------------------------------------
+ // Prev
+ // -----------------------------------------------------------------------
+
+ IndexEntry prevChapter = chapterIndex.getPrevEntry();
+
+ write( "<td><div align=\"left\">" );
+
+ previous( prevChapter );
+
+ write( "</div></td>" );
+
+ // -----------------------------------------------------------------------
+ // Parent
+ // -----------------------------------------------------------------------
+
+ write( "<td><div align=\"center\">" );
+ up();
+ write( "</div></td>" );
+
+ // -----------------------------------------------------------------------
+ // Next
+ // -----------------------------------------------------------------------
+
+ write( "<td><div align=\"right\">" );
+
+ next();
+
+ write( "</div></td>" );
+
+ write( "</tr>" );
+ write( "</table>" );
+
+ write( "<!--End of Navigation Panel-->" );
+ }
+
+ /**
+ * Add previous link.
+ *
+ * @param prevChapter the previous IndexEntry.
+ */
+ protected void previous( IndexEntry prevChapter )
+ {
+ if ( prevChapter != null )
+ {
+ IndexEntry lastEntry = prevChapter.getLastEntry();
+ if ( lastEntry == null )
+ {
+ write( "<i>Start of book</i>" );
+ }
+ else
+ {
+ write( getString( "previous" ) + ": <a href=\"" + lastEntry.getId() + ".html\">" );
+ content( lastEntry.getTitle() );
+ write( "</a>" );
+ }
+ }
+ else
+ {
+ write( getString( "previous" ) + ":<a href=\"index.html\">" + getString( "toc" ) + "</a>" );
+ }
+ }
+
+ /**
+ * Add parent/up link.
+ */
+ protected void up()
+ {
+ write( getString( "up" ) + ": <a href=\"index.html\">" + getString( "toc" ) + "</a>" );
+ }
+
+ /**
+ * Add next link
+ */
+ protected void next()
+ {
+ IndexEntry firstEntry = chapterIndex.getFirstEntry();
+ if ( firstEntry == null )
+ {
+ write( "<i>End of book</i>" );
+ }
+ else
+ {
+ write( getString( "next" ) + ": <a href=\"" + firstEntry.getId() + ".html\">" );
+ content( firstEntry.getTitle() );
+ write( "</a>" );
+ }
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/IndexXdocBookSink.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/IndexXdocBookSink.java
new file mode 100644
index 0000000..7832957
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/IndexXdocBookSink.java
@@ -0,0 +1,84 @@
+package org.apache.maven.doxia.book.services.renderer.xdoc;
+
+/*
+ * 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.Writer;
+import java.util.Locale;
+
+import org.apache.maven.doxia.index.IndexEntry;
+import org.codehaus.plexus.i18n.I18N;
+
+/**
+ * A <code>XdocSink</code> implementation for index book.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
+ * @version $Id$
+ */
+public class IndexXdocBookSink
+ extends AbstractXdocBookSink
+{
+ /** the first IndexEntry. */
+ private final IndexEntry firstEntry;
+
+ /**
+ * Default constructor.
+ *
+ * @param out the Writer.
+ * @param firstEntry the first IndexEntry.
+ * @param i18n I18N.
+ * @param locale wanted locale.
+ */
+ public IndexXdocBookSink( Writer out, IndexEntry firstEntry, I18N i18n, Locale locale )
+ {
+ super( out, i18n, locale );
+
+ this.firstEntry = firstEntry;
+ }
+
+ /** {@inheritDoc} */
+ protected void navigationPanel()
+ {
+ write( "<!--Navigation Panel-->" );
+
+ write( "<table width=\"100%\" align=\"center\">" );
+ write( "<tr>" );
+
+ // -----------------------------------------------------------------------
+ // Next
+ // -----------------------------------------------------------------------
+
+ if ( firstEntry != null )
+ {
+ write( "<td><div align=\"right\">" );
+
+ write( getString( "next" ) + ": <a href=\"" + firstEntry.getId() + ".html\">" );
+ content( firstEntry.getTitle() );
+ write( "</a>" );
+
+ write( "</div></td>" );
+ }
+
+ write( "</tr>" );
+ write( "</table>" );
+
+ write( "<!--End of Navigation Panel-->" );
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/SectionXdocBookSink.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/SectionXdocBookSink.java
new file mode 100644
index 0000000..f16a179
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/xdoc/SectionXdocBookSink.java
@@ -0,0 +1,166 @@
+package org.apache.maven.doxia.book.services.renderer.xdoc;
+
+/*
+ * 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.Writer;
+import java.util.Locale;
+
+import org.apache.maven.doxia.index.IndexEntry;
+import org.codehaus.plexus.i18n.I18N;
+
+/**
+ * A <code>XdocSink</code> implementation for section in a book
+ *
+ * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
+ * @version $Id$
+ */
+public class SectionXdocBookSink
+ extends AbstractXdocBookSink
+{
+ /** indexEntry. */
+ private final IndexEntry indexEntry;
+
+ /**
+ * Default constructor.
+ *
+ * @param out the Writer to use.
+ * @param indexEntry the IndexEntry.
+ * @param i18n the I18N.
+ * @param locale wanted locale.
+ */
+ public SectionXdocBookSink( Writer out, IndexEntry indexEntry, I18N i18n, Locale locale )
+ {
+ super( out, i18n, locale );
+
+ this.indexEntry = indexEntry;
+ }
+
+ /** {@inheritDoc} */
+ protected void navigationPanel()
+ {
+ write( "<!--Navigation Panel-->" );
+
+ write( "<table width=\"100%\" align=\"center\" border=\"0\">" );
+ write( "<tr>" );
+
+ IndexEntry parent = indexEntry.getParent();
+
+ // -----------------------------------------------------------------------
+ // Prev
+ // -----------------------------------------------------------------------
+
+ IndexEntry prevEntry = indexEntry.getPrevEntry();
+
+ write( "<td align=\"left\">" );
+
+ previous( parent, prevEntry );
+
+ write( "</td>" );
+
+ // -----------------------------------------------------------------------
+ // Parent
+ // -----------------------------------------------------------------------
+
+ write( "<td align=\"center\">" );
+ up( parent );
+ write( "</td>" );
+
+ // -----------------------------------------------------------------------
+ // Next
+ // -----------------------------------------------------------------------
+
+ IndexEntry nextEntry = indexEntry.getNextEntry();
+
+ write( "<td align=\"right\">" );
+
+ next( parent, nextEntry );
+
+ write( "</td>" );
+
+ write( "</tr>" );
+ write( "</table>" );
+
+ write( "<!--End of Navigation Panel-->" );
+ }
+
+ /**
+ * Add previous link.
+ *
+ * @param parent the parent IndexEntry.
+ * @param prevEntry the previous IndexEntry.
+ */
+ protected void previous( IndexEntry parent, IndexEntry prevEntry )
+ {
+ if ( prevEntry != null )
+ {
+ write( getString( "previous" ) + ": <a href=\"" + prevEntry.getId() + ".html\">" );
+ content( prevEntry.getTitle() );
+ write( "</a>" );
+ }
+ else
+ {
+ write( getString( "previous" ) + ": <a href=\"" + parent.getId() + ".html\">" );
+ content( parent.getTitle() );
+ write( "</a>" );
+ }
+ }
+
+ /**
+ * Add parent/up link.
+ *
+ * @param parent the parent IndexEntry.
+ * @see org.apache.maven.doxia.book.services.renderer.xdoc.ChapterXdocBookSink#up()
+ */
+ protected void up( IndexEntry parent )
+ {
+ write( getString( "up" ) + ": <a href=\"" + parent.getId() + ".html\">" + parent.getTitle() + "</a>" );
+ }
+
+ /**
+ * Add next link.
+ *
+ * @param parent the parent IndexEntry.
+ * @param nextEntry the next IndexEntry.
+ */
+ protected void next( IndexEntry parent, IndexEntry nextEntry )
+ {
+ if ( nextEntry != null )
+ {
+ write( getString( "next" ) + ": <a href=\"" + nextEntry.getId() + ".html\">" );
+ content( nextEntry.getTitle() );
+ write( "</a>" );
+ }
+ else
+ {
+ IndexEntry nextChapter = parent.getNextEntry();
+
+ if ( nextChapter == null )
+ {
+ write( "<i>End of book</i>" );
+ }
+ else
+ {
+ write( getString( "next" ) + ": <a href=\"" + nextChapter.getId() + ".html\">" );
+ content( nextChapter.getTitle() );
+ write( "</a>" );
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/renderer/xhtml/XhtmlBookSink.java b/src/main/java/org/apache/maven/doxia/book/services/renderer/xhtml/XhtmlBookSink.java
new file mode 100644
index 0000000..a6b823e
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/renderer/xhtml/XhtmlBookSink.java
@@ -0,0 +1,248 @@
+package org.apache.maven.doxia.book.services.renderer.xhtml;
+
+/*
+ * 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.module.xhtml.XhtmlSink;
+import org.apache.maven.doxia.sink.render.RenderingContext;
+import org.codehaus.plexus.util.StringUtils;
+
+import java.io.Writer;
+
+/**
+ * An Xhtml Sink that doesn't write out head or body elements.
+ *
+ * @author ltheussl
+ * @version $Id$
+ */
+public class XhtmlBookSink
+ extends XhtmlSink
+{
+ private RenderingContext renderingContext;
+
+ /**
+ * Construct a new XhtmlBookSink.
+ *
+ * @param out the writer for the sink.
+ * @param context the RenderingContext.
+ */
+ public XhtmlBookSink( Writer out, RenderingContext context )
+ {
+ super( out );
+ this.renderingContext = context;
+ }
+
+ // ----------------------------------------------------------------------
+ //
+ // ----------------------------------------------------------------------
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing.
+ */
+ public void head()
+ {
+ init();
+
+ setHeadFlag( true );
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing.
+ */
+ public void head_()
+ {
+ setHeadFlag( false );
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing.
+ */
+ public void title()
+ {
+ // noop
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing.
+ */
+ public void title_()
+ {
+ resetTextBuffer();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing.
+ */
+ public void author_()
+ {
+ resetTextBuffer();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing.
+ */
+ public void date_()
+ {
+ resetTextBuffer();
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing.
+ */
+ public void body()
+ {
+ // noop
+ }
+
+ /**
+ * {@inheritDoc}
+ *
+ * Does nothing.
+ */
+ public void body_()
+ {
+ // noop
+ }
+
+ /**
+ * Calls super.head().
+ */
+ public void bookHead()
+ {
+ super.head();
+ }
+
+ /**
+ * Calls super.head_().
+ */
+ public void bookHead_()
+ {
+ super.head_();
+ }
+
+ /**
+ * Calls super.title().
+ */
+ public void bookTitle()
+ {
+ super.title();
+ }
+
+ /**
+ * Calls super.title_().
+ */
+ public void bookTitle_()
+ {
+ super.title_();
+ }
+
+ /**
+ * Calls super.author().
+ */
+ public void bookAuthor()
+ {
+ super.author();
+ }
+
+ /**
+ * Calls super.author_().
+ */
+ public void bookAuthor_()
+ {
+ super.author_();
+ }
+
+ /**
+ * Calls super.date().
+ */
+ public void bookDate()
+ {
+ super.date();
+ }
+
+ /**
+ * Calls super.date_().
+ */
+ public void bookDate_()
+ {
+ super.date_();
+ }
+
+ /**
+ * Calls super.body().
+ */
+ public void bookBody()
+ {
+ super.body();
+ }
+
+ /**
+ * Calls super.body_().
+ */
+ public void bookBody_()
+ {
+ super.body_();
+ }
+
+ /** {@inheritDoc} */
+ public void sectionTitle()
+ {
+ writeStartTag( H1 );
+ }
+
+ /** {@inheritDoc} */
+ public void sectionTitle_()
+ {
+ writeEndTag( H1 );
+ }
+
+ /** {@inheritDoc} */
+ protected void write( String text )
+ {
+ if ( renderingContext != null )
+ {
+ String relativePathToBasedir = renderingContext.getRelativePath();
+
+ if ( relativePathToBasedir == null )
+ {
+ text = StringUtils.replace( text, "$relativePath", "." );
+ }
+ else
+ {
+ text = StringUtils.replace( text, "$relativePath", relativePathToBasedir );
+ }
+ }
+
+ super.write( text );
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/validation/BookValidator.java b/src/main/java/org/apache/maven/doxia/book/services/validation/BookValidator.java
new file mode 100644
index 0000000..878300d
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/validation/BookValidator.java
@@ -0,0 +1,42 @@
+package org.apache.maven.doxia.book.services.validation;
+
+/*
+ * 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.book.model.BookModel;
+
+/**
+ * Ensure a BookModel is valid.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public interface BookValidator
+{
+ /** The plexus lookup role. */
+ String ROLE = BookValidator.class.getName();
+
+ /**
+ * Validate a BookModel.
+ *
+ * @param book the BookModel to validate.
+ * @return ValidationResult
+ */
+ ValidationResult validateBook( BookModel book );
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/validation/DefaultBookValidator.java b/src/main/java/org/apache/maven/doxia/book/services/validation/DefaultBookValidator.java
new file mode 100644
index 0000000..19a06ec
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/validation/DefaultBookValidator.java
@@ -0,0 +1,104 @@
+package org.apache.maven.doxia.book.services.validation;
+
+/*
+ * 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.codehaus.plexus.logging.AbstractLogEnabled;
+import org.codehaus.plexus.util.StringUtils;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.model.Chapter;
+
+/**
+ * Default implementation of BookValidator.
+ *
+ * @plexus.component
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class DefaultBookValidator
+ extends AbstractLogEnabled
+ implements BookValidator
+{
+ // ----------------------------------------------------------------------
+ // BookValidator Implementation
+ // ----------------------------------------------------------------------
+
+ /** {@inheritDoc} */
+ public ValidationResult validateBook( BookModel book )
+ {
+ ValidationResult result = new ValidationResult();
+
+ if ( StringUtils.isEmpty( book.getId() ) )
+ {
+ result.getErrors().add( "Book is missing id." );
+ }
+
+ if ( StringUtils.isEmpty( book.getTitle() ) )
+ {
+ result.getErrors().add( "Book is missing title." );
+ }
+
+ if ( book.getChapters().size() == 0 )
+ {
+ result.getErrors().add( "The book must have at least one chaper" );
+ }
+ else
+ {
+ for ( Chapter chapter : book.getChapters() )
+ {
+ validateChapter( result, chapter );
+
+ // TODO: Validate the chapter id
+ }
+ }
+
+ return result;
+ }
+
+ // ----------------------------------------------------------------------
+ // Private
+ // ----------------------------------------------------------------------
+
+ /**
+ * Validate a Chapter.
+ *
+ * @param result the ValidationResult to receive the results.
+ * @param chapter the chapter to validate.
+ */
+ private void validateChapter( ValidationResult result, Chapter chapter )
+ {
+ if ( StringUtils.isEmpty( chapter.getId() ) )
+ {
+ result.getErrors().add( "Each chapter has to have an id." );
+
+ return;
+ }
+
+ if ( StringUtils.isEmpty( chapter.getTitle() ) )
+ {
+ result.getErrors().add( "Missing title. Chapter id: " + chapter.getId() );
+ }
+
+ if ( chapter.getSections().size() == 0 )
+ {
+ result.getErrors().add( "Chapter doesn't have any sections. Chapter id: " + chapter.getId() );
+ }
+ }
+}
diff --git a/src/main/java/org/apache/maven/doxia/book/services/validation/ValidationResult.java b/src/main/java/org/apache/maven/doxia/book/services/validation/ValidationResult.java
new file mode 100644
index 0000000..47e218c
--- /dev/null
+++ b/src/main/java/org/apache/maven/doxia/book/services/validation/ValidationResult.java
@@ -0,0 +1,78 @@
+package org.apache.maven.doxia.book.services.validation;
+
+/*
+ * 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.util.List;
+import java.util.ArrayList;
+
+/**
+ * Encapsulates the result of a validation.
+ *
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class ValidationResult
+{
+ /** List of errors. */
+ private List<String> errors;
+
+ /** List of warnings. */
+ private List<String> warnings;
+
+ /**
+ * Checks if there were any errors or warnings.
+ *
+ * @return True if there were no errors or warnings.
+ */
+ public boolean isAllOk()
+ {
+ return getErrors().size() == 0 && getWarnings().size() == 0;
+ }
+
+ /**
+ * Return the list of errors.
+ *
+ * @return List. A new ArrayList is constructed if the current List is null.
+ */
+ public List<String> getErrors()
+ {
+ if ( errors == null )
+ {
+ errors = new ArrayList<String>();
+ }
+
+ return errors;
+ }
+
+ /**
+ * Return the list of warnings.
+ *
+ * @return List. A new ArrayList is constructed if the current List is null.
+ */
+ public List<String> getWarnings()
+ {
+ if ( warnings == null )
+ {
+ warnings = new ArrayList<String>();
+ }
+
+ return warnings;
+ }
+}
diff --git a/src/main/modello/book.mdo b/src/main/modello/book.mdo
new file mode 100644
index 0000000..13068f6
--- /dev/null
+++ b/src/main/modello/book.mdo
@@ -0,0 +1,537 @@
+<?xml version="1.0"?>
+
+<!--
+ 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.
+-->
+
+<model xmlns="http://modello.codehaus.org/MODELLO/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://modello.codehaus.org/MODELLO/1.0.0 http://modello.codehaus.org/xsd/modello-1.0.0.xsd"
+ xml.namespace="http://maven.apache.org/BOOK/${version}">
+ <id>book</id>
+ <name>BookModel</name>
+ <description>
+ <![CDATA[
+ <p>
+ This descriptor specifies the metadatas and the content for a book.
+ </p>
+ <p>
+ A book is defined by a collection of chapters, a chapter by a
+ collection of sections, a section by a file.
+ </p>
+ <p>An XSD is available at:</p>
+ <ul>
+ <li><a href="http://maven.apache.org/xsd/book-1.0.0.xsd">http://maven.apache.org/xsd/book-1.0.0.xsd</a>.</li>
+ </ul>
+ ]]>
+ </description>
+ <defaults>
+ <default>
+ <key>package</key>
+ <value>org.apache.maven.doxia.book.model</value>
+ </default>
+ </defaults>
+ <classes>
+ <class rootElement="true" xml.tagName="book">
+ <name>BookModel</name>
+ <description>
+ Describes the book layout and packaging.
+ </description>
+ <version>1.0.0</version>
+ <fields>
+ <field>
+ <name>id</name>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ <description>
+ Specifies the id of this book. This is a symbolic name for a
+ particular book from this project.
+ </description>
+ </field>
+ <field>
+ <name>title</name>
+ <version>1.0.0</version>
+ <type>String</type>
+ <description>
+ Specifies the title of this book.
+ </description>
+ </field>
+ <field>
+ <name>author</name>
+ <version>1.0.0</version>
+ <type>String</type>
+ <description>
+ Specifies the author of this book.
+ </description>
+ </field>
+ <field>
+ <name>date</name>
+ <version>1.0.0</version>
+ <type>String</type>
+ <description>
+ Specifies the date of this book.
+ </description>
+ </field>
+ <field>
+ <name>chapters</name>
+ <version>1.0.0</version>
+ <description>
+ Specifies a collection of chapters.
+ </description>
+ <association>
+ <type>Chapter</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ </field>
+<!--
+ <field>
+ <name>bannerLeft</name>
+ <description>Banner logo on the masthead of the site to the left.</description>
+ <version>1.0.0</version>
+ <association>
+ <type>Banner</type>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>bannerRight</name>
+ <description>Banner logo on the masthead of the site to the right.</description>
+ <version>1.0.0</version>
+ <association>
+ <type>Banner</type>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>publishDate</name>
+ <description>Modify the date published display properties.</description>
+ <version>1.0.0</version>
+ <association>
+ <type>PublishDate</type>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>version</name>
+ <description>Modify the version display properties.</description>
+ <version>1.0.0</version>
+ <association>
+ <type>Version</type>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>poweredBy</name>
+ <description>Powered by logos.</description>
+ <version>1.0.0</version>
+ <association xml.tagName="logo">
+ <type>Logo</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>skin</name>
+ <description>The artifact containing the skin for the site</description>
+ <version>1.0.0</version>
+ <association>
+ <type>Skin</type>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>body</name>
+ <description>The main site content decoration.</description>
+ <version>1.0.0</version>
+ <association>
+ <type>Body</type>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>custom</name>
+ <description>Custom configuration for use with customised velocity templates.</description>
+ <version>1.0.0</version>
+ <type>DOM</type>
+ <identifier>true</identifier>
+ </field>
+-->
+ </fields>
+ </class>
+ <class>
+ <name>Chapter</name>
+ <version>1.0.0</version>
+ <fields>
+ <field>
+ <name>id</name>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ <description>
+ Specifies the id of this chapter. This is a symbolic name for a
+ particular chapter.
+ </description>
+ </field>
+ <field>
+ <name>title</name>
+ <version>1.0.0</version>
+ <type>String</type>
+ <description>
+ Specifies the title of this chapter.
+ </description>
+ </field>
+ <field>
+ <name>sections</name>
+ <version>1.0.0</version>
+ <description>
+ Specifies a collection of sections.
+ </description>
+ <association>
+ <type>Section</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ </field>
+ </fields>
+ </class>
+ <class>
+ <name>Section</name>
+ <version>1.0.0</version>
+ <fields>
+ <field>
+ <name>id</name>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ <description>
+ Specifies the id of this section. This is a symbolic name for a
+ particular section.
+ </description>
+ </field>
+ <field>
+ <name>title</name>
+ <version>1.0.0</version>
+ <type>String</type>
+ <description>
+ Specifies the title of this section.
+ </description>
+ </field>
+ <field>
+ <name>file</name>
+ <version>1.0.0</version>
+ <type>String</type>
+ <description>
+ Specifies the file of this section.
+ </description>
+ </field>
+ </fields>
+ </class>
+<!--
+ <class>
+ <name>Banner</name>
+ <description>A banner logo on the masthead of the site.</description>
+ <version>1.0.0</version>
+ <fields>
+ <field>
+ <name>name</name>
+ <version>1.0.0</version>
+ <description>Description of the banner.</description>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>src</name>
+ <version>1.0.0</version>
+ <description>The href of an image for the banner</description>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>alt</name>
+ <version>1.0.0</version>
+ <description>Alt description for the banner image.</description>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>href</name>
+ <version>1.0.0</version>
+ <description>The href of a link to use for the banner</description>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ </fields>
+ </class>
+ <class>
+ <name>PublishDate</name>
+ <description>Modify display properties for date published.</description>
+ <version>1.0.0</version>
+ <fields>
+ <field xml.attribute="true">
+ <name>position</name>
+ <description>Where to place the date published (left, right, navigation-top, navigation-bottom,
+ bottom).</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field xml.attribute="true">
+ <name>format</name>
+ <description>Date format to use. The default is MM/dd/yyyy.</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ </fields>
+ </class>
+ <class>
+ <name>Version</name>
+ <description>Modify display properties for version.</description>
+ <version>1.0.0</version>
+ <fields>
+ <field xml.attribute="true">
+ <name>position</name>
+ <description>Where to place the date published (left, right, navigation-top, navigation-bottom,
+ bottom).</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ </fields>
+ </class>
+ <class>
+ <name>Logo</name>
+ <description>Logo.</description>
+ <version>1.0.0</version>
+ <superClass>LinkItem</superClass>
+ <fields>
+ <field xml.attribute="true">
+ <name>img</name>
+ <description>Logo image href.</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ </fields>
+ </class>
+ <class>
+ <name>Body</name>
+ <description>The main content decoration.</description>
+ <version>1.0.0</version>
+ <fields>
+ <field>
+ <name>head</name>
+ <description>Additional content to include in the HEAD block of the generated pages.</description>
+ <version>1.0.0</version>
+ <type>DOM</type>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>links</name>
+ <description>A list of links to display in the navigation.</description>
+ <version>1.0.0</version>
+ <association xml.tagName="item">
+ <type>LinkItem</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>breadcrumbs</name>
+ <description>A list of breadcrumbs to display in the navigation.</description>
+ <version>1.0.0</version>
+ <association xml.tagName="item">
+ <type>LinkItem</type>
+ <multiplicity>*</multiplicity>
+ <identifier>true</identifier>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>menus</name>
+ <description>Menus to include in the navigation.</description>
+ <version>1.0.0</version>
+ <association xml.itemsStyle="flat">
+ <type>Menu</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ </fields>
+ </class>
+ <class>
+ <name>LinkItem</name>
+ <description>A link in the navigation.</description>
+ <version>1.0.0</version>
+ <fields>
+ <field xml.attribute="true">
+ <name>name</name>
+ <description>The name to use for the link.</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field xml.attribute="true">
+ <name>href</name>
+ <description>The href to use for the link.</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ </fields>
+ </class>
+ <class>
+ <name>Menu</name>
+ <description>A menu in the navigation.</description>
+ <version>1.0.0</version>
+ <fields>
+ <field xml.attribute="true">
+ <name>name</name>
+ <description>The name to use for the menu.</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field xml.attribute="true">
+ <name>inherit</name>
+ <description>The way in which the menu is inherited.</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field xml.attribute="true">
+ <name>inheritAsRef</name>
+ <description>If this is a reference, setting inheritAsRef means that it will be populated in the project,
+ whereas if it is false it is populated in the parent and then inherited.</description>
+ <version>1.0.0</version>
+ <type>boolean</type>
+ </field>
+ <field xml.attribute="true">
+ <name>ref</name>
+ <description><![CDATA[A reference to a pre-defined menu, such as a <code>reports</code>, <code>modules</code>
+ or <code>parentProject</code>.]]></description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field xml.attribute="true">
+ <name>img</name>
+ <description>Image href.</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>items</name>
+ <description>Menu item.</description>
+ <version>1.0.0</version>
+ <association xml.itemsStyle="flat">
+ <type>MenuItem</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ </fields>
+ </class>
+ <class>
+ <name>MenuItem</name>
+ <description>A menu item.</description>
+ <version>1.0.0</version>
+ <superClass>LinkItem</superClass>
+ <fields>
+ <field>
+ <name>description</name>
+ <description>A description of the menu item. This is used on any summary pages for a menu.</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field xml.attribute="true">
+ <name>collapse</name>
+ <description>Whether the item is collapsed by default when it has children elements.</description>
+ <version>1.0.0</version>
+ <type>boolean</type>
+ <identifier>true</identifier>
+ </field>
+ <field xml.attribute="true">
+ <name>ref</name>
+ <description><![CDATA[A reference to a pre-defined menu item, such as a report (specified by the report goal
+ name). Any elements explicitly given override those from the pre-defined reference.]]></description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>items</name>
+ <description>Menu item.</description>
+ <version>1.0.0</version>
+ <association xml.itemsStyle="flat">
+ <type>MenuItem</type>
+ <multiplicity>*</multiplicity>
+ </association>
+ <identifier>true</identifier>
+ </field>
+ </fields>
+ </class>
+ <class>
+ <name>Skin</name>
+ <description>An skin artifact declaration</description>
+ <version>1.0.0</version>
+ <fields>
+ <field>
+ <name>groupId</name>
+ <description>The group ID</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <required>true</required>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>artifactId</name>
+ <description>The artifact ID</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <required>true</required>
+ <identifier>true</identifier>
+ </field>
+ <field>
+ <name>version</name>
+ <description>The version</description>
+ <version>1.0.0</version>
+ <type>String</type>
+ <identifier>true</identifier>
+ </field>
+ </fields>
+ <codeSegments>
+ <codeSegment>
+ <version>1.0.0</version>
+ <code>
+ <![CDATA[
+ public static Skin getDefaultSkin()
+ {
+ Skin skin = new Skin();
+ skin.setGroupId( "org.apache.maven.skins" );
+ skin.setArtifactId( "maven-default-skin" );
+ return skin;
+ }
+ ]]>
+ </code>
+ </codeSegment>
+ </codeSegments>
+ </class>
+-->
+ </classes>
+</model>
diff --git a/src/main/resources/book-renderer.properties b/src/main/resources/book-renderer.properties
new file mode 100644
index 0000000..9369897
--- /dev/null
+++ b/src/main/resources/book-renderer.properties
@@ -0,0 +1,21 @@
+# 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.
+
+toc=Table Of Content
+previous=Previous
+up=Up
+next=Next
diff --git a/src/main/resources/book-renderer_en.properties b/src/main/resources/book-renderer_en.properties
new file mode 100644
index 0000000..0c479bc
--- /dev/null
+++ b/src/main/resources/book-renderer_en.properties
@@ -0,0 +1,23 @@
+# 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:
+# This bundle is intentionally empty because English strings are provided by the base bundle via the parent chain. It
+# must be provided nevertheless such that a request for locale "en" will not errorneously pick up the bundle for the
+# JVM's default locale (which need not be "en"). See the method javadoc about
+# ResourceBundle.getBundle(String, Locale, ClassLoader)
+# for a full description of the lookup strategy.
diff --git a/src/main/resources/book-renderer_fr.properties b/src/main/resources/book-renderer_fr.properties
new file mode 100644
index 0000000..385696e
--- /dev/null
+++ b/src/main/resources/book-renderer_fr.properties
@@ -0,0 +1,21 @@
+# 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.
+
+toc=Table des mati�res
+previous=Pr�c�dent
+up=Haut
+next=Suivant
diff --git a/src/site/apt/index.apt b/src/site/apt/index.apt
new file mode 100644
index 0000000..968e955
--- /dev/null
+++ b/src/site/apt/index.apt
@@ -0,0 +1,20 @@
+ -----
+ Writing Books in Doxia
+ -----
+ Lukas Theussl
+ -----
+
+Introduction
+
+ Doxia allows you to write books like user manuals and guides in any format supported by Doxia. Combined with the
+ Doxia Book Maven you are able to include the manuals directly in your generated site with links to the off-line
+ friendly formats like XDoc, PDF, RTF and LaTeX.
+
+* How It Works
+
+ The only thing you need in addition to the content files itself is a simple book descriptor which is used to specify
+ the ordering of the sections and the names for the chapters.
+
+ See {{{./book.html}The Book Descriptor Reference}} for a reference to the descriptor. A sample is given on the
+ main Doxia {{{http://maven.apache.org/doxia/book/index.html}site}}.
+
diff --git a/src/site/apt/usage.apt b/src/site/apt/usage.apt
new file mode 100644
index 0000000..e90d983
--- /dev/null
+++ b/src/site/apt/usage.apt
@@ -0,0 +1,31 @@
+ -----
+ Usage
+ -----
+ Lukas Theussl
+ -----
+
+Usage
+
+ Below is a simple example to illustrate how to use it.
+
++------------------------------------------------------
+ BookDoxia doxia = (BookDoxia) lookup( BookDoxia.ROLE );
+
+ // load the book descriptor
+ File book1 = new File( "book-1.xml" );
+
+ BookModel book = doxia.loadBook( book1 );
+
+ // files to include
+ List files = FileUtils.getFiles( new File( "src/resources/book/" ), "**/*.apt, **/*.xml", "" );
+
+ // render books in different formats
+ doxia.renderBook( book, "pdf", files, new File( "target/itext/" ) );
+ doxia.renderBook( book, "xhtml", files, new File( "target/xhtml/" ) );
+ doxia.renderBook( book, "xdoc", files, new File( "target/xdoc/" ) );
+ doxia.renderBook( book, "latex", files, new File( "target/latex/" ) );
+ doxia.renderBook( book, "doc-book", files, new File( "target/doc-book/" ) );
+ doxia.renderBook( book, "rtf", files, new File( "target/rtf/" ) );
++------------------------------------------------------
+
+ See the {{{./apidocs/index.html}Javadocs}} for more details.
diff --git a/src/site/apt/using-book-xsd.apt b/src/site/apt/using-book-xsd.apt
new file mode 100644
index 0000000..1c3fdc9
--- /dev/null
+++ b/src/site/apt/using-book-xsd.apt
@@ -0,0 +1,41 @@
+ -----
+ Using Schema Book 1.0
+ -----
+ Vincent Siveton
+ ------
+ 2009-01-28
+ ------
+
+~~ 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
+
+Using Schema Book 1.0
+
+ The Decoration XSD is located {{{http://maven.apache.org/xsd/book-1.0.0.xsd}here}}.
+
+ Your favorite IDE probably supports XSD schema's for .xml files. You need to specify the following:
+
++-----+
+<book xmlns="http://maven.apache.org/BOOK/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/BOOK/1.0.0 http://maven.apache.org/xsd/book-1.0.0.xsd">
+...
+</book>
++-----+
diff --git a/src/site/site.xml b/src/site/site.xml
new file mode 100644
index 0000000..cc6f0cd
--- /dev/null
+++ b/src/site/site.xml
@@ -0,0 +1,48 @@
+<?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/DECORATION/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/DECORATION/1.1.0 http://maven.apache.org/xsd/decoration-1.1.0.xsd">
+
+ <body>
+
+ <menu ref="parent"/>
+
+ <menu name="About Doxia :: Book Components">
+ <item name="Introduction" href="index.html"/>
+ <item name="Usage" href="usage.html"/>
+ <item name="JavaDocs" href="apidocs/index.html"/>
+ <item name="Source Xref" href="xref/index.html"/>
+ <!--item name="FAQ" href="faq.html"/-->
+ </menu>
+
+ <menu name="Book Schema">
+ <item name="Reference" href="book.html"/>
+ <item name="Using Book Schema" href="using-book-xsd.html"/>
+ </menu>
+
+ <menu ref="reports"/>
+
+ </body>
+
+</project>
diff --git a/src/test/java/org/apache/maven/doxia/book/BookRendererTest.java b/src/test/java/org/apache/maven/doxia/book/BookRendererTest.java
new file mode 100644
index 0000000..b445a97
--- /dev/null
+++ b/src/test/java/org/apache/maven/doxia/book/BookRendererTest.java
@@ -0,0 +1,75 @@
+package org.apache.maven.doxia.book;
+
+/*
+ * 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.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.util.FileUtils;
+import org.codehaus.plexus.util.StringUtils;
+import org.apache.maven.doxia.book.model.BookModel;
+
+import java.io.File;
+import java.util.List;
+
+/**
+ * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class BookRendererTest
+ extends PlexusTestCase
+{
+ public void testBasic()
+ throws Exception
+ {
+ BookDoxia doxia = (BookDoxia) lookup( BookDoxia.ROLE );
+
+ File book1 = getTestFile( "src/test/resources/book-1.xml" );
+
+ List files = FileUtils.getFiles( getTestFile( "src/test/resources/book-1" ), "**/*.apt, **/*.xml", "" );
+
+ BookModel book = doxia.loadBook( book1 );
+
+ doxia.renderBook( book, "pdf", files, getTestFile( "target/test-output/itext" ) );
+ doxia.renderBook( book, "xhtml", files, getTestFile( "target/test-output/xhtml" ) );
+ doxia.renderBook( book, "xdoc", files, getTestFile( "target/test-output/xdoc" ) );
+ doxia.renderBook( book, "latex", files, getTestFile( "target/test-output/latex" ) );
+ doxia.renderBook( book, "doc-book", files, getTestFile( "target/test-output/doc-book" ) );
+ doxia.renderBook( book, "rtf", files, getTestFile( "target/test-output/rtf" ) );
+
+ assertCorrectDocbook();
+ }
+
+ /**
+ * Regression test for the docbook output.
+ */
+ private void assertCorrectDocbook()
+ throws Exception
+ {
+ String expected =
+ FileUtils.fileRead( getTestFile( "src/test/resources/expected/doc-book/plexus-user-guide.xml" ) );
+ expected = StringUtils.deleteWhitespace( expected );
+
+ String actual =
+ FileUtils.fileRead( getTestFile( "target/test-output/doc-book/plexus-user-guide.xml" ) );
+ actual = StringUtils.deleteWhitespace( actual );
+
+ assertEquals( "Wrong docbook output!",
+ StringUtils.replace( expected, "\r", "" ), StringUtils.replace( actual, "\r", "" ) );
+ }
+}
diff --git a/src/test/java/org/apache/maven/doxia/book/services/indexer/BookIndexerTest.java b/src/test/java/org/apache/maven/doxia/book/services/indexer/BookIndexerTest.java
new file mode 100644
index 0000000..1a293ad
--- /dev/null
+++ b/src/test/java/org/apache/maven/doxia/book/services/indexer/BookIndexerTest.java
@@ -0,0 +1,118 @@
+package org.apache.maven.doxia.book.services.indexer;
+
+/*
+ * 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.book.context.BookContext;
+import org.apache.maven.doxia.book.model.BookModel;
+import org.apache.maven.doxia.book.services.io.BookIo;
+import org.apache.maven.doxia.index.IndexEntry;
+import org.apache.maven.doxia.util.HtmlTools;
+import org.codehaus.plexus.PlexusTestCase;
+import org.codehaus.plexus.util.FileUtils;
+
+/**
+ * @author <a href="mailto:trygve.laugstol@objectware.no">Trygve Laugstøl</a>
+ * @version $Id$
+ */
+public class BookIndexerTest
+ extends PlexusTestCase
+{
+ public void testBasic()
+ throws Exception
+ {
+ BookIo io = (BookIo) lookup( BookIo.ROLE );
+
+ BookIndexer indexer = (BookIndexer) lookup( BookIndexer.ROLE );
+
+ BookModel book = io.readBook( getTestFile( "src/test/resources/book-1.xml" ) );
+
+ BookContext context = new BookContext();
+
+ io.loadFiles( context, FileUtils.getFiles( getTestFile( "src/test/resources/book-1" ), "*.apt", "" ) );
+
+ indexer.indexBook( book, context );
+
+ IndexEntry root = context.getIndex();
+
+ assertNotNull( root );
+
+ assertEquals( 2, root.getChildEntries().size() );
+
+ IndexEntry c1 = assertIndexEntry( root, 0, "Chapter 1", "chapter-1", 2 );
+
+ // -----------------------------------------------------------------------
+ // Section 1
+ // -----------------------------------------------------------------------
+
+ IndexEntry s1 = assertIndexEntry( c1, 0, "Section 1", "section-1", 5 );
+
+ IndexEntry ss1 = assertIndexEntry( s1, 0, "Subsection 1", "Subsection_1", 1 );
+
+ assertIndexEntry( ss1, 0, "Subsubsection 1", "Subsubsection_1", 0 );
+
+ assertIndexEntry( s1, 1, "Subsection 2", "Subsection_2", 0 );
+
+ assertIndexEntry( s1, 2, "Subsection 3", "Subsection_3", 0 );
+
+ assertIndexEntry( s1, 3, "Subsection 4", "Subsection_4", 0 );
+
+ // -----------------------------------------------------------------------
+ // Section 2
+ // -----------------------------------------------------------------------
+
+ IndexEntry s2 = assertIndexEntry( c1, 1, "Section 2", "section-2", 1 );
+
+ assertIndexEntry( s2, 0, "Section 1.10.32 of \"de Finibus Bonorum et Malorum\", written by Cicero in 45 BC",
+ "Section_1.10.32_of_\"de_Finibus_Bonorum_et_Malorum\",_written_by_Cicero_in_45_BC", 0 );
+
+ // -----------------------------------------------------------------------
+ // Chapter 2
+ // -----------------------------------------------------------------------
+
+ IndexEntry c2 = assertIndexEntry( root, 1, "Chapter 2", "chapter-2", 2 );
+
+ IndexEntry s3 = assertIndexEntry( c2, 0, "Section 3", "section-3", 1 );
+
+ assertIndexEntry( s3, 0, "1914 translation by H. Rackham", "1914_translation_by_H._Rackham", 0 );
+
+ IndexEntry s4 = assertIndexEntry( c2, 1, "Section 4", "section-4", 1 );
+
+ assertIndexEntry( s4, 0, "Section 1.10.33 of \"de Finibus Bonorum et Malorum\", written by Cicero in 45 BC",
+ "Section_1.10.33_of_\"de_Finibus_Bonorum_et_Malorum\",_written_by_Cicero_in_45_BC", 0 );
+ }
+
+ private IndexEntry assertIndexEntry( IndexEntry parent, int childIndex, String title, String id, int childCount )
+ {
+ assertTrue( "parent: " + parent.getId() + ", " +
+ "required count: " + childCount + ", " +
+ "actual count: " + parent.getChildEntries().size(),
+ childIndex < parent.getChildEntries().size() );
+
+ IndexEntry indexEntry = (IndexEntry) parent.getChildEntries().get( childIndex );
+
+ assertEquals( title, indexEntry.getTitle() );
+
+ assertEquals( HtmlTools.encodeId( id ), indexEntry.getId() );
+
+ assertEquals( childCount, indexEntry.getChildEntries().size() );
+
+ return indexEntry;
+ }
+}
diff --git a/src/test/java/org/apache/maven/doxia/book/services/renderer/docbook/DocBookBookSinkTest.java b/src/test/java/org/apache/maven/doxia/book/services/renderer/docbook/DocBookBookSinkTest.java
new file mode 100644
index 0000000..6a4de45
--- /dev/null
+++ b/src/test/java/org/apache/maven/doxia/book/services/renderer/docbook/DocBookBookSinkTest.java
@@ -0,0 +1,490 @@
+package org.apache.maven.doxia.book.services.renderer.docbook;
+
+/*
+ * 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.Writer;
+
+import java.util.Locale;
+
+import javax.swing.text.MutableAttributeSet;
+import javax.swing.text.SimpleAttributeSet;
+
+import org.apache.maven.doxia.module.docbook.DocBookSink;
+import org.apache.maven.doxia.sink.AbstractSinkTest;
+import org.apache.maven.doxia.sink.Sink;
+import org.apache.maven.doxia.sink.SinkUtils;
+
+import org.apache.maven.doxia.util.DoxiaUtils;
+import org.codehaus.plexus.util.FileUtils;
+
+/**
+ * Test the book path of the DockBook sink
+ * @author Dave Syer
+ */
+public class DocBookBookSinkTest extends AbstractSinkTest
+{
+ /** {@inheritDoc} */
+ protected boolean isXmlSink()
+ {
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ protected String outputExtension()
+ {
+ return "docbook";
+ }
+
+ /** {@inheritDoc} */
+ protected Sink createSink( Writer writer )
+ {
+ return new DocBookBookSink( writer );
+ }
+
+ //
+ // DocBookBookSink specific
+ //
+
+ /**
+ * Checks that the sequence <code>[bookTitle(), text( title ), bookTitle_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getBookTitleBlock getBookTitleBlock}( title ).
+ * NewLines are ignored.
+ */
+ public void testBookTitle()
+ {
+ DocBookBookSink sink = (DocBookBookSink) getSink();
+
+ String title = "Grodek";
+ sink.bookTitle();
+ sink.text( title );
+ sink.bookTitle_();
+ sink.flush();
+
+ String actual = getSinkContent();
+ String expected = getBookTitleBlock( title );
+
+ assertEquals( "Wrong book title!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[bookAuthor(), text( author ), bookAuthor_()]
+ * </code>, invoked on the current sink, produces the same result as
+ * {@link #getBookAuthorBlock getBookAuthorBlock}( author ).
+ * NewLines are ignored.
+ */
+ public void testBookAuthor()
+ {
+ DocBookBookSink sink = (DocBookBookSink) getSink();
+
+ String author = "Georg Trakl";
+ sink.bookAuthor();
+ sink.text( author );
+ sink.bookAuthor_();
+ sink.flush();
+
+ String actual = getSinkContent();
+ String expected = getBookAuthorBlock( author );
+
+ assertEquals( "Wrong book author!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[bookDate(), text( date ), bookDate_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getBookDateBlock getBookDateBlock}( date ). NewLines are ignored.
+ */
+ public void testBookDate()
+ {
+ DocBookBookSink sink = (DocBookBookSink) getSink();
+
+ String date = "1914";
+ sink.bookDate();
+ sink.text( date );
+ sink.bookDate_();
+ sink.flush();
+
+ String actual = getSinkContent();
+ String expected = getBookDateBlock( date );
+
+ assertEquals( "Wrong book date!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[bookHead(), bookHead_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getBookHeadBlock getBookHeadBlock()}. NewLines are ignored.
+ */
+ public void testBookHead()
+ {
+ DocBookBookSink sink = (DocBookBookSink) getSink();
+
+ //sink.bookHead();
+ sink.bookHead_();
+ sink.flush();
+
+ String actual = getSinkContent();
+ String expected = getBookHeadBlock();
+
+ assertEquals( "Wrong book head!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[book(), book_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getBookBlock getBookBlock()}. NewLines are ignored.
+ */
+ public void testBook()
+ {
+ DocBookBookSink sink = (DocBookBookSink) getSink();
+
+ sink.book();
+ sink.book_();
+ sink.flush();
+
+ String actual = getSinkContent();
+ String expected = getBookBlock();
+
+ assertEquals( "Wrong book body!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[chapterTitle(), text( title ),
+ * chapterTitle_()]</code>, invoked on the current sink, produces
+ * the same result as
+ * {@link #getChapterTitleBlock getChapterTitleBlock}( title ).
+ * NewLines are ignored.
+ */
+ public void testChapterTitle()
+ {
+ DocBookBookSink sink = (DocBookBookSink) getSink();
+
+ String title = "Title";
+ sink.chapterTitle();
+ sink.text( title );
+ sink.chapterTitle_();
+ sink.flush();
+
+ String actual = getSinkContent();
+ String expected = getChapterTitleBlock( title );
+
+ assertEquals( "Wrong chapterTitle!", expected, actual );
+ }
+
+ /**
+ * Checks that the sequence <code>[chapter(), chapter_()]</code>,
+ * invoked on the current sink, produces the same result as
+ * {@link #getChapterBlock getChapterBlock}().
+ * NewLines are ignored.
+ */
+ public void testChapter()
+ {
+ DocBookBookSink sink = (DocBookBookSink) getSink();
+
+ sink.chapter();
+ sink.chapter_();
+ sink.flush();
+
+ String actual = getSinkContent();
+ String expected = getChapterBlock();
+
+ assertEquals( "Wrong chapter block!", expected, actual );
+ }
+
+ /**
+ * Returns a title block generated by this sink.
+ * @param title The title to use.
+ * @return The result of invoking a title block on the current sink.
+ * @see #testBookTitle()
+ */
+ protected String getBookTitleBlock( String title )
+ {
+ return "<bookinfo><title>" + title + "</title>";
+ }
+
+ /**
+ * Returns an author block generated by this sink.
+ * @param author The author to use.
+ * @return The result of invoking an author block on the current sink.
+ * @see #testBookAuthor()
+ */
+ protected String getBookAuthorBlock( String author )
+ {
+ return "<bookinfo><corpauthor>" + author + "</corpauthor>";
+ }
+
+ /**
+ * Returns a date block generated by this sink.
+ * @param date The date to use.
+ * @return The result of invoking a date block on the current sink.
+ * @see #testBookDate()
+ */
+ protected String getBookDateBlock( String date )
+ {
+ return "<bookinfo><date>" + date + "</date>";
+ }
+
+ /**
+ * Returns a head block generated by this sink.
+ * @return The result of invoking a head block on the current sink.
+ * @see #testBookHead()
+ */
+ protected String getBookHeadBlock()
+ {
+ return "";
+ }
+
+ /**
+ * Returns a body block generated by this sink.
+ * @return The result of invoking a body block on the current sink.
+ * @see #testBook()
+ */
+ protected String getBookBlock()
+ {
+ return "<?xml version=\"1.0\"?><!DOCTYPE book PUBLIC \"" + DocBookSink.DEFAULT_XML_PUBLIC_ID
+ + "\" \"" + DocBookSink.DEFAULT_XML_SYSTEM_ID + "\"><book></book>";
+ }
+
+ /**
+ * Returns a SectionTitle block generated by this sink.
+ * @param title The title to use.
+ * @return The result of invoking a SectionTitle block on the current sink.
+ * @see #testChapterTitle()
+ */
+ protected String getChapterTitleBlock( String title )
+ {
+ return "<title>" + title + "</title>";
+ }
+
+ /**
+ * Returns a Section1 block generated by this sink.
+ * @param title The title to use.
+ * @return The result of invoking a Section1 block on the current sink.
+ * @see #testChapter()
+ */
+ protected String getChapterBlock()
+ {
+ return "<chapter></chapter>";
+ }
+
+
+ //
+ // from DocBookSink
+ //
+
+
+ /** {@inheritDoc} */
+ protected String getTitleBlock( String title )
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getAuthorBlock( String author )
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getDateBlock( String date )
+ {
+ return "<date>" + date + "</date>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getHeadBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getBodyBlock()
+ {
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSectionTitleBlock( String title )
+ {
+ return "<title>" + title + "</title>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection1Block( String title )
+ {
+ return "<section><title>" + title + "</title></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection2Block( String title )
+ {
+ return "<section><title>" + title + "</title></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection3Block( String title )
+ {
+ return "<section><title>" + title + "</title></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection4Block( String title )
+ {
+ return "<section><title>" + title + "</title></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getSection5Block( String title )
+ {
+ return "<section><title>" + title + "</title></section>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getListBlock( String item )
+ {
+ return "<itemizedlist><listitem><para>" + item + "</para></listitem></itemizedlist>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNumberedListBlock( String item )
+ {
+ return "<orderedlist numeration=\"lowerroman\"><listitem><para>"
+ + item + "</para></listitem></orderedlist>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getDefinitionListBlock( String definum, String definition )
+ {
+ return "<variablelist><varlistentry><term>" + definum
+ + "</term><listitem><para>" + definition
+ + "</para></listitem></varlistentry></variablelist>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getFigureBlock( String source, String caption )
+ {
+ String format = FileUtils.extension( source ).toUpperCase( Locale.ENGLISH );
+
+ return "<mediaobject><imageobject>"
+ + "<imagedata fileref=\"" + source + "\" format=\"" + format + "\" />"
+ + "</imageobject><caption><para>" + caption + "</para></caption></mediaobject>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getTableBlock( String cell, String caption )
+ {
+ // Using the same set ordering than the JVM
+ MutableAttributeSet att = new SimpleAttributeSet();
+ att.addAttribute( "frame", "none" );
+ att.addAttribute( "rowsep", "0" );
+ att.addAttribute( "colsep", "0" );
+
+ return "<table" + SinkUtils.getAttributeString( att ) + "><title>" + caption
+ + "</title><tgroup cols=\"1\"><colspec align=\"center\" /><tbody><row><entry>"
+ + cell + "</entry></row></tbody></tgroup></table>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getParagraphBlock( String text )
+ {
+ return "<para>" + text + "</para>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getVerbatimBlock( String text )
+ {
+ return "<programlisting>" + text + "</programlisting>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getHorizontalRuleBlock()
+ {
+ return "<!-- HR -->";
+ }
+
+ /** {@inheritDoc} */
+ protected String getPageBreakBlock()
+ {
+ return "<!-- PB -->";
+ }
+
+ /** {@inheritDoc} */
+ protected String getAnchorBlock( String anchor )
+ {
+ return "<anchor id=\"" + anchor + "\" />" + anchor + "<!-- anchor_end -->";
+ }
+
+ /** {@inheritDoc} */
+ protected String getLinkBlock( String link, String text )
+ {
+ String linkend = DoxiaUtils.isInternalLink( link ) ? link.substring( 1 ) : link;
+ return "<link linkend=\"" + linkend + "\">" + text + "</link>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getItalicBlock( String text )
+ {
+ return "<emphasis>" + text + "</emphasis>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getBoldBlock( String text )
+ {
+ return "<emphasis role=\"bold\">" + text + "</emphasis>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getMonospacedBlock( String text )
+ {
+ return "<literal>" + text + "</literal>";
+ }
+
+ /** {@inheritDoc} */
+ protected String getLineBreakBlock()
+ {
+ return "<!-- LB -->";
+ }
+
+ /** {@inheritDoc} */
+ protected String getNonBreakingSpaceBlock()
+ {
+ return " ";
+ }
+
+ /** {@inheritDoc} */
+ protected String getTextBlock( String text )
+ {
+ // TODO: retreive those from the sink
+ return "~,_=,_-,_+,_*,_[,_],_<,_>,_{,_},_\\";
+ }
+
+ /** {@inheritDoc} */
+ protected String getRawTextBlock( String text )
+ {
+ // TODO
+ return "";
+ }
+
+ /** {@inheritDoc} */
+ protected String getCommentBlock( String text )
+ {
+ return "<!-- Simple comment with - - - - -->";
+ }
+}
diff --git a/src/test/resources/book-1.xml b/src/test/resources/book-1.xml
new file mode 100644
index 0000000..7364904
--- /dev/null
+++ b/src/test/resources/book-1.xml
@@ -0,0 +1,51 @@
+<!--
+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.
+-->
+
+<book xmlns="http://maven.apache.org/BOOK/1.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/BOOK/1.0.0 ../../../target/generated-site/xsd/book-1.0.0.xsd">
+ <id>plexus-user-guide</id>
+ <title>Test Book</title>
+ <chapters>
+ <chapter>
+ <id>chapter-1</id>
+ <title>Chapter 1</title>
+ <sections>
+ <section>
+ <id>section-1</id>
+ </section>
+ <section>
+ <id>section-2</id>
+ </section>
+ </sections>
+ </chapter>
+ <chapter>
+ <id>chapter-2</id>
+ <title>Chapter 2</title>
+ <sections>
+ <section>
+ <id>section-3</id>
+ </section>
+ <section>
+ <id>section-4</id>
+ </section>
+ </sections>
+ </chapter>
+ </chapters>
+</book>
diff --git a/src/test/resources/book-1/section-1.apt b/src/test/resources/book-1/section-1.apt
new file mode 100644
index 0000000..35d204f
--- /dev/null
+++ b/src/test/resources/book-1/section-1.apt
@@ -0,0 +1,61 @@
+ -----
+ Section 1
+ -----
+ Trygve
+ -----
+
+Subsection 1
+
+ Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec sagittis malesuada nisi. Aliquam orci eros, vestibulum
+ eu, placerat et, pretium sed, nisi. Proin consequat. Praesent faucibus sem id arcu hendrerit nonummy. Aliquam blandit
+ accumsan pede. Vivamus aliquet lacinia nunc. Praesent dapibus orci eu magna. Cras nonummy, pede nec facilisis semper,
+ sem nibh vestibulum massa, sed ornare tortor elit non lectus. Nullam mauris turpis, luctus et, vulputate vitae, commodo
+ sit amet, purus. Fusce erat. Proin ullamcorper imperdiet est. Morbi sit amet dui. Fusce bibendum auctor augue. Sed leo
+ sapien, vehicula ac, nonummy id, cursus at, nulla. Ut sed purus.
+
+* Subsubsection 1
+
+ Suspendisse sagittis metus nec leo. Suspendisse velit. Phasellus ipsum dolor, porttitor ut1, varius id, scelerisque
+ vel, ligula. Aliquam tempor sem in pede tincidunt nonummy. Vestibulum et nulla. Nunc et dolor a risus porttitor tem
+ pus. Sed felis arcu, consectetuer non, imperdiet sollicitudin, ullamcorper vitae, nulla. Vestibulum ante ipsum primis
+ in faucibus.
+
+Subsection 2
+
+ Duis eget libero aliquet quam ultrices malesuada. Donec molestie dignissim nunc. Curabitur turpis. Suspendisse a nibh
+ ut elit vulputate ultrices. Etiam nulla erat, nonummy vel, fringilla at, scelerisque non, ante. Suspendisse adipiscing
+ rhoncus purus. Nulla in augue. Ut ac nisi eu nisi cursus elementum. Pellentesque habitant morbi tristique senectus et
+ netus et malesuada fames ac turpis egestas. Donec et turpis. Donec nec mi. Mauris malesuada congue sem. Maecenas et
+ urna in nisi sagittis facilisis. Cras nibh. Aliquam purus. Donec convallis congue libero. Nulla feugiat. Nulla massa
+ libero, consectetuer ac, aliquet ac, consequat eu, purus. Pellentesque eleifend pretium augue.
+
+Subsection 3
+
+ Integer auctor, nisi ut convallis imperdiet, ligula diam sollicitudin dolor, porttitor mattis urna sapien at velit.
+ Fusce vestibulum, neque nec malesuada tempor, tortor nisi accumsan purus, quis faucibus metus elit ac urna. Aliquam
+ commodo velit vel ipsum. Donec blandit diam blandit eros. Aliquam pretium fermentum neque. Sed nec tellus eu orci
+ ullamcorper facilisis. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.
+ Nulla sed leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos hymenaeos. Fusce
+ suscipit. Sed sit amet diam ac ante tincidunt ornare. Sed sodales vestibulum quam. Fusce accumsan. Ut ut mi.
+
+Subsection 4
+
+ Maecenas tincidunt lobortis nunc. Phasellus euismod diam sit amet felis. Donec lorem metus, vulputate vitae, ornare
+ vel, molestie sit amet, pede. In erat velit, adipiscing sed, varius in, interdum cursus, enim. Quisque dolor ante,
+ tincidunt vel, congue eget, consectetuer id, nunc. Suspendisse hendrerit. Proin egestas, massa eget egestas
+ ullamcorper, nisl elit gravida magna, vitae dignissim odio velit ut tortor. Fusce lobortis consequat nulla.
+ Vestibulum pretium justo at metus. Sed lorem velit, elementum eget, pellentesque ac, ornare id, mi. Pellentesque vel
+ ligula et erat dictum commodo. Integer malesuada lacus nec metus. Aliquam id purus ac neque mattis venenatis. Aenean
+ lobortis accumsan massa. Donec dui ante, facilisis vel, hendrerit ut, vehicula in, eros. Suspendisse potenti. Sed
+ fringilla. Suspendisse vel nibh. Sed sit amet lacus quis massa tincidunt elementum. Ut ut augue vitae ligula dapibus
+ aliquam.
+
+Subsection 5
+
+ Fusce non eros non lectus venenatis bibendum. Nullam pharetra. Nunc commodo pede et metus. Pellentesque habitant morbi
+ tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum imperdiet nisl nec nulla. Morbi congue
+ dictum pede. Aliquam ligula. In pede nulla, varius a, blandit ut, pulvinar vitae, mauris. Suspendisse sit amet magna.
+ Curabitur cursus placerat justo. Vivamus imperdiet magna commodo mi. Vestibulum eget metus quis sem sollicitudin
+ consectetuer. Morbi metus augue, elementum rutrum, luctus quis, porttitor a, est. Phasellus quis sapien et augue
+ adipiscing fermentum. Sed fermentum tristique dui. Vivamus aliquam, tortor at ultricies commodo, urna ipsum fringilla
+ neque, sit amet congue purus enim a justo.
diff --git a/src/test/resources/book-1/section-2.apt b/src/test/resources/book-1/section-2.apt
new file mode 100644
index 0000000..64c1f5f
--- /dev/null
+++ b/src/test/resources/book-1/section-2.apt
@@ -0,0 +1,16 @@
+ -----
+ Section 2
+ -----
+ Trygve
+ -----
+
+Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
+
+ Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam,
+ eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam
+ voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione
+ voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
+ velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim
+ ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi
+ consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur,
+ vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
diff --git a/src/test/resources/book-1/section-3.apt b/src/test/resources/book-1/section-3.apt
new file mode 100644
index 0000000..f5d07ec
--- /dev/null
+++ b/src/test/resources/book-1/section-3.apt
@@ -0,0 +1,17 @@
+ -----
+ Section 3
+ -----
+ Trygve
+ -----
+
+1914 translation by H. Rackham
+
+ But I must explain to you how all this mistaken idea of denouncing pleasure and praising pain was born and I will
+ give you a complete account of the system, and expound the actual teachings of the great explorer of the truth, the
+ master-builder of human happiness. No one rejects, dislikes, or avoids pleasure itself, because it is pleasure, but
+ because those who do not know how to pursue pleasure rationally encounter consequences that are extremely painful.
+ Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because
+ occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial
+ example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who
+ has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who
+ avoids a pain that produces no resultant pleasure?
diff --git a/src/test/resources/book-1/section-4.apt b/src/test/resources/book-1/section-4.apt
new file mode 100644
index 0000000..a148762
--- /dev/null
+++ b/src/test/resources/book-1/section-4.apt
@@ -0,0 +1,16 @@
+ -----
+ Section 4
+ -----
+ Trygve
+ -----
+
+Section 1.10.33 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC
+
+ At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque
+ corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique sunt in culpa
+ qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita
+ distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime
+ placeat facere possimus, omnis voluptas assumenda est, omnis dolor repellendus. Temporibus autem quibusdam et aut
+ officiis debitis aut rerum necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae non recusandae.
+ Itaque earum rerum hic tenetur a sapiente delectus, ut aut reiciendis voluptatibus maiores alias consequatur aut
+ perferendis doloribus asperiores repellat.
diff --git a/src/test/resources/expected/doc-book/plexus-user-guide.xml b/src/test/resources/expected/doc-book/plexus-user-guide.xml
new file mode 100644
index 0000000..37ed826
--- /dev/null
+++ b/src/test/resources/expected/doc-book/plexus-user-guide.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0"?><!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.4//EN"
+"http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
+<book><bookinfo><title>Test Book</title>
+</bookinfo>
+<chapter><title>Chapter 1</title>
+<section><title>Subsection 1</title>
+<para>Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Donec sagittis
+malesuada nisi. Aliquam orci eros, vestibulum eu, placerat et, pretium sed,
+nisi. Proin consequat. Praesent faucibus sem id arcu hendrerit nonummy.
+Aliquam blandit accumsan pede. Vivamus aliquet lacinia nunc. Praesent dapibus
+orci eu magna. Cras nonummy, pede nec facilisis semper, sem nibh vestibulum
+massa, sed ornare tortor elit non lectus. Nullam mauris turpis, luctus et,
+vulputate vitae, commodo sit amet, purus. Fusce erat. Proin ullamcorper
+imperdiet est. Morbi sit amet dui. Fusce bibendum auctor augue. Sed leo
+sapien, vehicula ac, nonummy id, cursus at, nulla. Ut sed purus.</para>
+<section><title>Subsubsection 1</title>
+<para>Suspendisse sagittis metus nec leo. Suspendisse velit. Phasellus ipsum
+dolor, porttitor ut1, varius id, scelerisque vel, ligula. Aliquam tempor sem
+in pede tincidunt nonummy. Vestibulum et nulla. Nunc et dolor a risus
+porttitor tem pus. Sed felis arcu, consectetuer non, imperdiet sollicitudin,
+ullamcorper vitae, nulla. Vestibulum ante ipsum primis in faucibus.</para>
+</section>
+</section>
+<section><title>Subsection 2</title>
+<para>Duis eget libero aliquet quam ultrices malesuada. Donec molestie
+dignissim nunc. Curabitur turpis. Suspendisse a nibh ut elit vulputate
+ultrices. Etiam nulla erat, nonummy vel, fringilla at, scelerisque non, ante.
+Suspendisse adipiscing rhoncus purus. Nulla in augue. Ut ac nisi eu nisi
+cursus elementum. Pellentesque habitant morbi tristique senectus et netus et
+malesuada fames ac turpis egestas. Donec et turpis. Donec nec mi. Mauris
+malesuada congue sem. Maecenas et urna in nisi sagittis facilisis. Cras nibh.
+Aliquam purus. Donec convallis congue libero. Nulla feugiat. Nulla massa
+libero, consectetuer ac, aliquet ac, consequat eu, purus. Pellentesque
+eleifend pretium augue.</para>
+</section>
+<section><title>Subsection 3</title>
+<para>Integer auctor, nisi ut convallis imperdiet, ligula diam sollicitudin
+dolor, porttitor mattis urna sapien at velit. Fusce vestibulum, neque nec
+malesuada tempor, tortor nisi accumsan purus, quis faucibus metus elit ac
+urna. Aliquam commodo velit vel ipsum. Donec blandit diam blandit eros.
+Aliquam pretium fermentum neque. Sed nec tellus eu orci ullamcorper facilisis.
+Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac
+turpis egestas. Nulla sed leo. Class aptent taciti sociosqu ad litora torquent
+per conubia nostra, per inceptos hymenaeos. Fusce suscipit. Sed sit amet diam
+ac ante tincidunt ornare. Sed sodales vestibulum quam. Fusce accumsan. Ut ut
+mi.</para>
+</section>
+<section><title>Subsection 4</title>
+<para>Maecenas tincidunt lobortis nunc. Phasellus euismod diam sit amet felis.
+Donec lorem metus, vulputate vitae, ornare vel, molestie sit amet, pede. In
+erat velit, adipiscing sed, varius in, interdum cursus, enim. Quisque dolor
+ante, tincidunt vel, congue eget, consectetuer id, nunc. Suspendisse
+hendrerit. Proin egestas, massa eget egestas ullamcorper, nisl elit gravida
+magna, vitae dignissim odio velit ut tortor. Fusce lobortis consequat nulla.
+Vestibulum pretium justo at metus. Sed lorem velit, elementum eget,
+pellentesque ac, ornare id, mi. Pellentesque vel ligula et erat dictum
+commodo. Integer malesuada lacus nec metus. Aliquam id purus ac neque mattis
+venenatis. Aenean lobortis accumsan massa. Donec dui ante, facilisis vel,
+hendrerit ut, vehicula in, eros. Suspendisse potenti. Sed fringilla.
+Suspendisse vel nibh. Sed sit amet lacus quis massa tincidunt elementum. Ut ut
+augue vitae ligula dapibus aliquam.</para>
+</section>
+<section><title>Subsection 5</title>
+<para>Fusce non eros non lectus venenatis bibendum. Nullam pharetra. Nunc
+commodo pede et metus. Pellentesque habitant morbi tristique senectus et netus
+et malesuada fames ac turpis egestas. Vestibulum imperdiet nisl nec nulla.
+Morbi congue dictum pede. Aliquam ligula. In pede nulla, varius a, blandit ut,
+pulvinar vitae, mauris. Suspendisse sit amet magna. Curabitur cursus placerat
+justo. Vivamus imperdiet magna commodo mi. Vestibulum eget metus quis sem
+sollicitudin consectetuer. Morbi metus augue, elementum rutrum, luctus quis,
+porttitor a, est. Phasellus quis sapien et augue adipiscing fermentum. Sed
+fermentum tristique dui. Vivamus aliquam, tortor at ultricies commodo, urna
+ipsum fringilla neque, sit amet congue purus enim a justo.</para>
+</section>
+<section><title>Section 1.10.32 of "de Finibus Bonorum et Malorum",
+written by Cicero in 45 BC</title>
+<para>Sed ut perspiciatis unde omnis iste natus error sit voluptatem
+accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo
+inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo.
+Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit,
+sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt.
+Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur,
+adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et
+dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis
+nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex
+ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea
+voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem
+eum fugiat quo voluptas nulla pariatur?</para>
+</section>
+</chapter>
+<chapter><title>Chapter 2</title>
+<section><title>1914 translation by H. Rackham</title>
+<para>But I must explain to you how all this mistaken idea of denouncing
+pleasure and praising pain was born and I will give you a complete account of
+the system, and expound the actual teachings of the great explorer of the
+truth, the master-builder of human happiness. No one rejects, dislikes, or
+avoids pleasure itself, because it is pleasure, but because those who do not
+know how to pursue pleasure rationally encounter consequences that are
+extremely painful. Nor again is there anyone who loves or pursues or desires
+to obtain pain of itself, because it is pain, but because occasionally
+circumstances occur in which toil and pain can procure him some great
+pleasure. To take a trivial example, which of us ever undertakes laborious
+physical exercise, except to obtain some advantage from it? But who has any
+right to find fault with a man who chooses to enjoy a pleasure that has no
+annoying consequences, or one who avoids a pain that produces no resultant
+pleasure?</para>
+</section>
+<section><title>Section 1.10.33 of "de Finibus Bonorum et Malorum",
+written by Cicero in 45 BC</title>
+<para>At vero eos et accusamus et iusto odio dignissimos ducimus qui
+blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas
+molestias excepturi sint occaecati cupiditate non provident, similique sunt in
+culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et
+harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum
+soluta nobis est eligendi optio cumque nihil impedit quo minus id quod maxime
+placeat facere possimus, omnis voluptas assumenda est, omnis dolor
+repellendus. Temporibus autem quibusdam et aut officiis debitis aut rerum
+necessitatibus saepe eveniet ut et voluptates repudiandae sint et molestiae
+non recusandae. Itaque earum rerum hic tenetur a sapiente delectus, ut aut
+reiciendis voluptatibus maiores alias consequatur aut perferendis doloribus
+asperiores repellat.</para>
+</section>
+</chapter>
+</book>