Coverage Report - org.apache.maven.doxia.book.services.renderer.XdocBookRenderer
 
Classes in this File Line Coverage Branch Coverage Complexity
XdocBookRenderer
86%
107/123
75%
15/20
3,5
 
 1  
 package org.apache.maven.doxia.book.services.renderer;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.File;
 23  
 import java.io.FileNotFoundException;
 24  
 import java.io.IOException;
 25  
 import java.io.Reader;
 26  
 import java.io.Writer;
 27  
 import java.util.Iterator;
 28  
 import java.util.Locale;
 29  
 
 30  
 import org.apache.maven.doxia.Doxia;
 31  
 import org.apache.maven.doxia.book.BookDoxiaException;
 32  
 import org.apache.maven.doxia.book.context.BookContext;
 33  
 import org.apache.maven.doxia.book.model.BookModel;
 34  
 import org.apache.maven.doxia.book.model.Chapter;
 35  
 import org.apache.maven.doxia.book.model.Section;
 36  
 import org.apache.maven.doxia.book.services.renderer.xdoc.ChapterXdocBookSink;
 37  
 import org.apache.maven.doxia.book.services.renderer.xdoc.IndexXdocBookSink;
 38  
 import org.apache.maven.doxia.book.services.renderer.xdoc.SectionXdocBookSink;
 39  
 import org.apache.maven.doxia.index.IndexEntry;
 40  
 import org.apache.maven.doxia.module.xdoc.XdocSink;
 41  
 import org.apache.maven.doxia.parser.ParseException;
 42  
 import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
 43  
 import org.apache.maven.doxia.util.HtmlTools;
 44  
 import org.codehaus.plexus.i18n.I18N;
 45  
 import org.codehaus.plexus.logging.AbstractLogEnabled;
 46  
 import org.codehaus.plexus.util.IOUtil;
 47  
 import org.codehaus.plexus.util.ReaderFactory;
 48  
 import org.codehaus.plexus.util.StringUtils;
 49  
 import org.codehaus.plexus.util.WriterFactory;
 50  
 
 51  
 /**
 52  
  * An implementation of <code>BookRenderer</code> for Xdoc
 53  
  *
 54  
  * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
 55  
  * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
 56  
  * @version $Id: XdocBookRenderer.java 1090706 2011-04-09 23:15:28Z hboutemy $
 57  
  * @plexus.component role-hint="xdoc"
 58  
  */
 59  1
 public class XdocBookRenderer
 60  
     extends AbstractLogEnabled
 61  
     implements BookRenderer
 62  
 {
 63  
     /**
 64  
      * @plexus.requirement
 65  
      */
 66  
     private Doxia doxia;
 67  
 
 68  
     /**
 69  
      * @plexus.requirement
 70  
      */
 71  
     private I18N i18n;
 72  
 
 73  
     // ----------------------------------------------------------------------
 74  
     // BookRenderer Implementation
 75  
     // ----------------------------------------------------------------------
 76  
 
 77  
     /** {@inheritDoc} */
 78  
     public void renderBook( BookContext context )
 79  
         throws BookDoxiaException
 80  
     {
 81  1
         BookModel book = context.getBook();
 82  
 
 83  1
         if ( !context.getOutputDirectory().exists() )
 84  
         {
 85  0
             if ( !context.getOutputDirectory().mkdirs() )
 86  
             {
 87  0
                 throw new BookDoxiaException( "Could not make directory: "
 88  
                     + context.getOutputDirectory().getAbsolutePath() + "." );
 89  
             }
 90  
         }
 91  
 
 92  1
         renderBook( book, context );
 93  1
     }
 94  
 
 95  
     // -----------------------------------------------------------------------
 96  
     // Protected
 97  
     // -----------------------------------------------------------------------
 98  
 
 99  
     /**
 100  
      * Gets a trimmed String for the given key from the resource bundle defined by Plexus.
 101  
      *
 102  
      * @param locale the locale used
 103  
      * @param key the key for the desired string
 104  
      * @return the string for the given key and the given locale
 105  
      */
 106  
     protected String getString( Locale locale, String key )
 107  
     {
 108  2
         if ( StringUtils.isEmpty( key ) )
 109  
         {
 110  0
             throw new IllegalArgumentException( "The key cannot be empty" );
 111  
         }
 112  
 
 113  2
         return i18n.getString( "book-renderer", locale, key ).trim();
 114  
     }
 115  
 
 116  
     // -----------------------------------------------------------------------
 117  
     // Private
 118  
     // -----------------------------------------------------------------------
 119  
 
 120  
     /**
 121  
      * Render the book, ie the book index and all chapter index and pages
 122  
      *
 123  
      * @param book the BookModel.
 124  
      * @param context the BookContext.
 125  
      * @throws BookDoxiaException if any
 126  
      */
 127  
     private void renderBook( BookModel book, BookContext context )
 128  
         throws BookDoxiaException
 129  
     {
 130  
         // -----------------------------------------------------------------------
 131  
         // Render the book index.xml page
 132  
         // -----------------------------------------------------------------------
 133  
 
 134  1
         File index = new File( context.getOutputDirectory(), "index.xml" );
 135  
 
 136  
         try
 137  
         {
 138  1
             writeBookIndex( index, book, context );
 139  
         }
 140  0
         catch ( IOException e )
 141  
         {
 142  0
             throw new BookDoxiaException( "Error while rendering index page to: '"
 143  
                         + index.getAbsolutePath() + "'.", e );
 144  1
         }
 145  
 
 146  
         // -----------------------------------------------------------------------
 147  
         // Render all the chapter pages
 148  
         // -----------------------------------------------------------------------
 149  
 
 150  1
         Iterator<IndexEntry> ii = context.getIndex().getChildEntries().iterator();
 151  
 
 152  1
         for ( Chapter chapter : book.getChapters() )
 153  
         {
 154  2
             renderChapter( chapter, context, ii.next() );
 155  
         }
 156  1
     }
 157  
 
 158  
     /**
 159  
      * Write the book index, ie a TOC.
 160  
      *
 161  
      * @param index the File.
 162  
      * @param book the BookModel.
 163  
      * @param context the BookContext.
 164  
      * @throws IOException if any
 165  
      */
 166  
     private void writeBookIndex( File index, BookModel book, BookContext context )
 167  
         throws IOException
 168  
     {
 169  1
         Writer writer = WriterFactory.newXmlWriter( index );
 170  
 
 171  1
         XdocSink sink = new IndexXdocBookSink( writer, context.getIndex().getFirstEntry(), i18n, context.getLocale() );
 172  
 
 173  
         try
 174  
         {
 175  
             // -----------------------------------------------------------------------
 176  
             // Head
 177  
             // -----------------------------------------------------------------------
 178  
 
 179  1
             sink.head();
 180  
 
 181  1
             sink.title();
 182  1
             sink.text( book.getTitle() + " - " + getString( context.getLocale(), "toc" ) );
 183  1
             sink.title_();
 184  
 
 185  1
             sink.head_();
 186  
 
 187  
             // -----------------------------------------------------------------------
 188  
             // Body
 189  
             // -----------------------------------------------------------------------
 190  
 
 191  1
             sink.body();
 192  
 
 193  1
             sink.section1();
 194  1
             sink.sectionTitle1();
 195  1
             sink.text( book.getTitle() + " - " + getString( context.getLocale(), "toc" ) );
 196  1
             sink.sectionTitle1_();
 197  
 
 198  1
             sink.list();
 199  1
             for ( IndexEntry entry : context.getIndex().getChildEntries() )
 200  
             {
 201  2
                 writeChapterIndexForBookIndex( sink, entry );
 202  
             }
 203  1
             sink.list_();
 204  
 
 205  1
             sink.section1_();
 206  
 
 207  1
             sink.body_();
 208  
         }
 209  
         finally
 210  
         {
 211  1
             sink.flush();
 212  
 
 213  1
             sink.close();
 214  
 
 215  1
             IOUtil.close( writer );
 216  1
         }
 217  1
     }
 218  
 
 219  
     /**
 220  
      * Write the chapter index for the book index.
 221  
      *
 222  
      * @param sink the XdocSink.
 223  
      * @param chapterEntry the chapter IndexEntry.
 224  
      */
 225  
     private void writeChapterIndexForBookIndex( XdocSink sink, IndexEntry chapterEntry )
 226  
     {
 227  2
         sink.listItem();
 228  2
         sink.link( chapterEntry.getId() + ".html" );
 229  2
         sink.text( chapterEntry.getTitle() );
 230  2
         sink.link_();
 231  
 
 232  2
         sink.list();
 233  2
         for ( IndexEntry sectionIndex : chapterEntry.getChildEntries() )
 234  
         {
 235  4
             writeSectionIndexForBookIndex( sink, sectionIndex );
 236  
         }
 237  2
         sink.list_();
 238  
 
 239  2
         sink.listItem_();
 240  2
     }
 241  
 
 242  
     /**
 243  
      * Write the section index for the book index.
 244  
      *
 245  
      * @param sink the XdocSink.
 246  
      * @param sectionIndex the section IndexEntry.
 247  
      */
 248  
     private void writeSectionIndexForBookIndex( XdocSink sink, IndexEntry sectionIndex )
 249  
     {
 250  8
         sink.listItem();
 251  8
         sink.link( sectionIndex.getId() + ".html" );
 252  8
         sink.text( sectionIndex.getTitle() );
 253  8
         sink.link_();
 254  
 
 255  8
         sink.list();
 256  8
         for ( IndexEntry subsectionIndex : sectionIndex.getChildEntries() )
 257  
         {
 258  16
             writeSubsectionIndexForBookIndex( sink, sectionIndex, subsectionIndex );
 259  
         }
 260  8
         sink.list_();
 261  
 
 262  8
         sink.listItem_();
 263  8
     }
 264  
 
 265  
     /**
 266  
      * Write subsection index for the book index.
 267  
      *
 268  
      * @param sink the XdocSink.
 269  
      * @param sectionIndex the section IndexEntry.
 270  
      * @param subsectionIndex the subsection IndexEntry.
 271  
      */
 272  
     private void writeSubsectionIndexForBookIndex( XdocSink sink, IndexEntry sectionIndex, IndexEntry subsectionIndex )
 273  
     {
 274  16
         sink.listItem();
 275  16
         sink.link( sectionIndex.getId() + ".html#" + HtmlTools.encodeId( subsectionIndex.getId() ) );
 276  16
         sink.text( subsectionIndex.getTitle() );
 277  16
         sink.link_();
 278  16
         sink.listItem_();
 279  16
     }
 280  
 
 281  
     // -----------------------------------------------------------------------
 282  
     // Rendering
 283  
     // -----------------------------------------------------------------------
 284  
 
 285  
     /**
 286  
      * Render the chapter index and all section pages.
 287  
      *
 288  
      * @param chapter the Chapter.
 289  
      * @param context the BookContext.
 290  
      * @param chapterIndex the IndexEntry.
 291  
      * @throws BookDoxiaException if any
 292  
      */
 293  
     private void renderChapter( Chapter chapter, BookContext context, IndexEntry chapterIndex )
 294  
         throws BookDoxiaException
 295  
     {
 296  
         // -----------------------------------------------------------------------
 297  
         // Render the chapter index page
 298  
         // -----------------------------------------------------------------------
 299  
 
 300  2
         File index = new File( context.getOutputDirectory(), chapter.getId() + ".xml" );
 301  
 
 302  
         try
 303  
         {
 304  2
             writeChapterIndex( index, chapter, chapterIndex, context );
 305  
         }
 306  0
         catch ( IOException e )
 307  
         {
 308  0
             throw new BookDoxiaException( "Error while rendering index page to: '"
 309  
                         + index.getAbsolutePath() + "'.", e );
 310  2
         }
 311  
 
 312  
         // -----------------------------------------------------------------------
 313  
         // Render all section pages
 314  
         // -----------------------------------------------------------------------
 315  
 
 316  2
         Iterator<IndexEntry> ii = chapterIndex.getChildEntries().iterator();
 317  
 
 318  2
         for ( Section section : chapter.getSections() )
 319  
         {
 320  4
             renderSection( context, section, ii.next() );
 321  
         }
 322  2
     }
 323  
 
 324  
     /**
 325  
      * Write a chapter index
 326  
      *
 327  
      * @param index the File.
 328  
      * @param context the context.
 329  
      * @param chapter the Chapter.
 330  
      * @param chapterIndex the IndexEntry.
 331  
      * @throws IOException if any.
 332  
      */
 333  
     private void writeChapterIndex( File index, Chapter chapter, IndexEntry chapterIndex, BookContext context )
 334  
         throws IOException
 335  
     {
 336  2
         Writer writer = WriterFactory.newXmlWriter( index );
 337  
 
 338  2
         ChapterXdocBookSink sink = new ChapterXdocBookSink( writer, chapterIndex, i18n, context.getLocale() );
 339  
 
 340  
         try
 341  
         {
 342  
             // -----------------------------------------------------------------------
 343  
             // Head
 344  
             // -----------------------------------------------------------------------
 345  
 
 346  2
             sink.head();
 347  
 
 348  2
             sink.title();
 349  2
             sink.text( chapter.getTitle() );
 350  2
             sink.title_();
 351  
 
 352  2
             sink.head_();
 353  
 
 354  
             // -----------------------------------------------------------------------
 355  
             // Body
 356  
             // -----------------------------------------------------------------------
 357  
 
 358  2
             sink.body();
 359  
 
 360  2
             sink.section1();
 361  2
             sink.sectionTitle1();
 362  2
             sink.text( chapter.getTitle() );
 363  2
             sink.sectionTitle1_();
 364  
 
 365  2
             sink.list();
 366  2
             for ( IndexEntry sectionIndex : chapterIndex.getChildEntries() )
 367  
             {
 368  4
                 writeSectionIndexForBookIndex( sink, sectionIndex );
 369  
             }
 370  2
             sink.list_();
 371  
 
 372  2
             sink.section1_();
 373  
 
 374  2
             sink.body_();
 375  
         }
 376  
         finally
 377  
         {
 378  2
             sink.flush();
 379  
 
 380  2
             sink.close();
 381  
 
 382  2
             IOUtil.close( writer );
 383  2
         }
 384  2
     }
 385  
 
 386  
     /**
 387  
      * Render all section pages.
 388  
      *
 389  
      * @param context the BookContext.
 390  
      * @param section the Section.
 391  
      * @param sectionIndex the IndexEntry.
 392  
      * @throws BookDoxiaException if any.
 393  
      */
 394  
     private void renderSection( BookContext context, Section section, IndexEntry sectionIndex )
 395  
         throws BookDoxiaException
 396  
     {
 397  
         try
 398  
         {
 399  4
             Writer writer = WriterFactory.newXmlWriter( new File( context.getOutputDirectory()
 400  
                     + "/" + section.getId() + ".xml" ) );
 401  
 
 402  4
             SectionXdocBookSink sink = new SectionXdocBookSink( writer, sectionIndex, i18n, context.getLocale() );
 403  
 
 404  4
             BookContext.BookFile bookFile = (BookContext.BookFile) context.getFiles().get( section.getId() );
 405  
 
 406  4
             if ( bookFile == null )
 407  
             {
 408  0
                 throw new BookDoxiaException( "No document that matches section with id=" + section.getId() + "." );
 409  
             }
 410  
 
 411  4
             Reader reader = null;
 412  
             try
 413  
             {
 414  4
                 reader = ReaderFactory.newReader( bookFile.getFile(), context.getInputEncoding() );
 415  4
                 doxia.parse( reader, bookFile.getParserId(), sink );
 416  
             }
 417  0
             catch ( ParserNotFoundException e )
 418  
             {
 419  0
                 throw new BookDoxiaException( "Parser not found: " + bookFile.getParserId() + ".", e );
 420  
             }
 421  0
             catch ( ParseException e )
 422  
             {
 423  0
                 throw new BookDoxiaException( "Error while parsing document: " + bookFile.getFile().getAbsolutePath()
 424  
                     + ".", e );
 425  
             }
 426  0
             catch ( FileNotFoundException e )
 427  
             {
 428  0
                 throw new BookDoxiaException( "Could not find document: " + bookFile.getFile().getAbsolutePath() + ".",
 429  
                                               e );
 430  
             }
 431  
             finally
 432  
             {
 433  4
                 sink.flush();
 434  4
                 sink.close();
 435  
 
 436  4
                 IOUtil.close( reader );
 437  4
                 IOUtil.close( writer );
 438  4
             }
 439  
         }
 440  0
         catch ( IOException e )
 441  
         {
 442  0
             throw new BookDoxiaException( "Error while rendering book.", e );
 443  4
         }
 444  4
     }
 445  
 }