| package org.apache.maven.doxia.docrenderer.itext; |
| |
| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.io.Reader; |
| import java.io.Writer; |
| import java.net.URL; |
| import java.net.URLClassLoader; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.transform.OutputKeys; |
| import javax.xml.transform.Transformer; |
| import javax.xml.transform.TransformerConfigurationException; |
| import javax.xml.transform.TransformerException; |
| import javax.xml.transform.TransformerFactory; |
| import javax.xml.transform.dom.DOMSource; |
| import javax.xml.transform.stream.StreamResult; |
| import javax.xml.transform.stream.StreamSource; |
| |
| import org.apache.maven.doxia.Doxia; |
| import org.apache.maven.doxia.docrenderer.DocRenderer; |
| import org.apache.maven.doxia.docrenderer.DocumentRendererException; |
| import org.apache.maven.doxia.document.DocumentModel; |
| import org.apache.maven.doxia.document.DocumentTOCItem; |
| import org.apache.maven.doxia.document.io.xpp3.DocumentXpp3Reader; |
| import org.apache.maven.doxia.module.itext.ITextSink; |
| import org.apache.maven.doxia.module.itext.ITextSinkFactory; |
| import org.apache.maven.doxia.module.itext.ITextUtil; |
| import org.apache.maven.doxia.module.site.SiteModule; |
| import org.apache.maven.doxia.module.site.manager.SiteModuleManager; |
| import org.apache.maven.doxia.parser.ParseException; |
| import org.apache.maven.doxia.parser.manager.ParserNotFoundException; |
| import org.apache.xml.utils.DefaultErrorHandler; |
| import org.codehaus.plexus.logging.AbstractLogEnabled; |
| import org.codehaus.plexus.util.FileUtils; |
| 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.XmlUtil; |
| import org.codehaus.plexus.util.xml.pull.XmlPullParserException; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Node; |
| import org.xml.sax.SAXException; |
| |
| import com.lowagie.text.ElementTags; |
| |
| /** |
| * Abstract <code>document</code> render with the <code>iText</code> framework |
| * |
| * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a> |
| * @version $Id$ |
| */ |
| public abstract class AbstractITextRender |
| extends AbstractLogEnabled |
| implements DocRenderer |
| { |
| private static final String XSLT_RESOURCE = "org/apache/maven/doxia/docrenderer/itext/xslt/TOC.xslt"; |
| |
| private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance(); |
| |
| private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance(); |
| |
| /** |
| * @plexus.requirement |
| */ |
| protected SiteModuleManager siteModuleManager; |
| |
| /** |
| * @plexus.requirement |
| */ |
| protected Doxia doxia; |
| |
| static |
| { |
| TRANSFORMER_FACTORY.setErrorListener( new DefaultErrorHandler() ); |
| } |
| |
| /** {@inheritDoc} */ |
| public void render( File siteDirectory, File outputDirectory ) |
| throws DocumentRendererException, IOException |
| { |
| for ( Iterator i = siteModuleManager.getSiteModules().iterator(); i.hasNext(); ) |
| { |
| SiteModule module = (SiteModule) i.next(); |
| |
| File moduleBasedir = new File( siteDirectory, module.getSourceDirectory() ); |
| |
| if ( moduleBasedir.exists() ) |
| { |
| List docs = FileUtils.getFileNames( moduleBasedir, "**/*." + module.getExtension(), null, false ); |
| |
| for ( Iterator j = docs.iterator(); j.hasNext(); ) |
| { |
| String doc = (String) j.next(); |
| String fullPathDoc = new File( moduleBasedir, doc ).getPath(); |
| |
| String outputITextName = doc.substring( 0, doc.indexOf( "." ) + 1 ) + "xml"; |
| File outputITextFile = new File( outputDirectory, outputITextName ); |
| if ( !outputITextFile.getParentFile().exists() ) |
| { |
| outputITextFile.getParentFile().mkdirs(); |
| } |
| String iTextOutputName = doc.substring( 0, doc.indexOf( "." ) + 1 ) + getOutputExtension(); |
| File iTextOutputFile = new File( outputDirectory, iTextOutputName ); |
| if ( !iTextOutputFile.getParentFile().exists() ) |
| { |
| iTextOutputFile.getParentFile().mkdirs(); |
| } |
| |
| parse( fullPathDoc, module, outputITextFile ); |
| |
| generateOutput( outputITextFile, iTextOutputFile ); |
| } |
| } |
| } |
| } |
| |
| /** {@inheritDoc} */ |
| public void render( File siteDirectory, File outputDirectory, File documentDescriptor ) |
| throws DocumentRendererException, IOException |
| { |
| if ( ( documentDescriptor == null ) || ( !documentDescriptor.exists() ) ) |
| { |
| if ( getLogger().isInfoEnabled() ) |
| { |
| getLogger().info( "No documentDescriptor is found. Generate all documents." ); |
| } |
| render( siteDirectory, outputDirectory ); |
| return; |
| } |
| |
| DocumentModel documentModel; |
| Reader reader = null; |
| try |
| { |
| reader = ReaderFactory.newXmlReader( documentDescriptor ); |
| documentModel = new DocumentXpp3Reader().read( reader ); |
| } |
| catch ( XmlPullParserException e ) |
| { |
| throw new DocumentRendererException( "Error parsing document descriptor", e ); |
| } |
| catch ( IOException e ) |
| { |
| throw new DocumentRendererException( "Error reading document descriptor", e ); |
| } |
| finally |
| { |
| IOUtil.close( reader ); |
| } |
| |
| if ( documentModel.getOutputName() == null ) |
| { |
| if ( getLogger().isInfoEnabled() ) |
| { |
| getLogger().info( "No outputName is defined in the document descriptor. Using 'generated_itext'" ); |
| } |
| documentModel.setOutputName( "generated_itext" ); |
| } |
| |
| if ( ( documentModel.getToc() == null ) || ( documentModel.getToc().getItems() == null ) ) |
| { |
| if ( getLogger().isInfoEnabled() ) |
| { |
| getLogger().info( "No TOC is defined in the document descriptor. Merging all documents." ); |
| } |
| } |
| |
| List iTextFiles = new LinkedList(); |
| for ( Iterator i = siteModuleManager.getSiteModules().iterator(); i.hasNext(); ) |
| { |
| SiteModule module = (SiteModule) i.next(); |
| |
| File moduleBasedir = new File( siteDirectory, module.getSourceDirectory() ); |
| |
| if ( moduleBasedir.exists() ) |
| { |
| List docs = FileUtils.getFileNames( moduleBasedir, "**/*." + module.getExtension(), null, false ); |
| |
| for ( Iterator j = docs.iterator(); j.hasNext(); ) |
| { |
| String doc = (String) j.next(); |
| String fullPathDoc = new File( moduleBasedir, doc ).getPath(); |
| |
| String outputITextName = doc.substring( 0, doc.lastIndexOf( "." ) + 1 ) + "xml"; |
| File outputITextFile = new File( outputDirectory, outputITextName ); |
| |
| if ( ( documentModel.getToc() == null ) || ( documentModel.getToc().getItems() == null ) ) |
| { |
| iTextFiles.add( outputITextFile ); |
| |
| if ( !outputITextFile.getParentFile().exists() ) |
| { |
| outputITextFile.getParentFile().mkdirs(); |
| } |
| |
| parse( fullPathDoc, module, outputITextFile ); |
| } |
| else |
| { |
| for ( Iterator k = documentModel.getToc().getItems().iterator(); k.hasNext(); ) |
| { |
| DocumentTOCItem tocItem = (DocumentTOCItem) k.next(); |
| |
| if ( tocItem.getRef() == null ) |
| { |
| if ( getLogger().isInfoEnabled() ) |
| { |
| getLogger().info( "No ref defined for an tocItem in the document descriptor." ); |
| } |
| continue; |
| } |
| |
| String outTmp = StringUtils.replace( outputITextFile.getAbsolutePath(), "\\", "/" ); |
| outTmp = outTmp.substring( 0, outTmp.lastIndexOf( "." ) ); |
| |
| String outRef = StringUtils.replace( tocItem.getRef(), "\\", "/" ); |
| if ( outRef.lastIndexOf( "." ) != -1 ) |
| { |
| outRef = outRef.substring( 0, outRef.lastIndexOf( "." ) ); |
| } |
| else |
| { |
| outRef = outRef.substring( 0, outRef.length() ); |
| } |
| |
| if ( outTmp.indexOf( outRef ) != -1 ) |
| { |
| iTextFiles.add( outputITextFile ); |
| |
| if ( !outputITextFile.getParentFile().exists() ) |
| { |
| outputITextFile.getParentFile().mkdirs(); |
| } |
| |
| parse( fullPathDoc, module, outputITextFile ); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| File iTextFile = new File( outputDirectory, documentModel.getOutputName() + ".xml" ); |
| File iTextOutput = new File( outputDirectory, documentModel.getOutputName() + "." + getOutputExtension() ); |
| Document document = generateDocument( iTextFiles ); |
| transform( documentModel, document, iTextFile ); |
| generateOutput( iTextFile, iTextOutput ); |
| } |
| |
| /** |
| * Generate an ouput file with the iText framework |
| * |
| * @param iTextFile |
| * @param iTextOutput |
| * @throws org.apache.maven.doxia.docrenderer.DocumentRendererException if any |
| * @throws java.io.IOException if any |
| */ |
| public abstract void generateOutput( File iTextFile, File iTextOutput ) |
| throws DocumentRendererException, IOException; |
| |
| /** |
| * Parse a sink |
| * |
| * @param fullPathDoc |
| * @param module |
| * @param outputITextFile |
| * @throws org.apache.maven.doxia.docrenderer.DocumentRendererException |
| * @throws java.io.IOException |
| */ |
| private void parse( String fullPathDoc, SiteModule module, File outputITextFile ) |
| throws DocumentRendererException, IOException |
| { |
| Writer writer = WriterFactory.newXmlWriter( outputITextFile ); |
| ITextSink sink = (ITextSink) new ITextSinkFactory().createSink( writer ); |
| |
| sink.setClassLoader( new URLClassLoader( new URL[] { outputITextFile.getParentFile().toURI().toURL() } ) ); |
| |
| Reader reader = null; |
| try |
| { |
| File f = new File( fullPathDoc ); |
| if ( XmlUtil.isXml( f ) ) |
| { |
| reader = ReaderFactory.newXmlReader( f ); |
| } |
| else |
| { |
| // TODO Platform dependent? |
| reader = ReaderFactory.newPlatformReader( f ); |
| } |
| |
| doxia.parse( reader, module.getParserId(), sink ); |
| } |
| catch ( ParserNotFoundException e ) |
| { |
| throw new DocumentRendererException( "Error getting a parser for '" |
| + fullPathDoc + "': " + e.getMessage() ); |
| } |
| catch ( ParseException e ) |
| { |
| throw new DocumentRendererException( "Error parsing '" |
| + fullPathDoc + "': line [" + e.getLineNumber() + "] " + e.getMessage(), e ); |
| } |
| finally |
| { |
| IOUtil.close( reader ); |
| |
| sink.flush(); |
| |
| sink.close(); |
| } |
| } |
| |
| /** |
| * Merge all iTextFiles to a single one |
| * |
| * @param iTextFiles |
| * @return a document |
| * @throws org.apache.maven.doxia.docrenderer.DocumentRendererException if any |
| * @throws java.io.IOException if any |
| */ |
| private Document generateDocument( List iTextFiles ) |
| throws DocumentRendererException, IOException |
| { |
| Document document; |
| try |
| { |
| document = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder().newDocument(); |
| } |
| catch ( ParserConfigurationException e ) |
| { |
| throw new DocumentRendererException( "Error building document :" + e.getMessage() ); |
| } |
| document.appendChild( document.createElement( ElementTags.ITEXT ) ); // Used only to set a root |
| |
| for ( int i = 0; i < iTextFiles.size(); i++ ) |
| { |
| File iTextFile = (File) iTextFiles.get( i ); |
| |
| Document iTextDocument; |
| try |
| { |
| iTextDocument = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder().parse( iTextFile ); |
| } |
| catch ( SAXException e ) |
| { |
| throw new DocumentRendererException( "SAX Error : " + e.getMessage() ); |
| } |
| catch ( ParserConfigurationException e ) |
| { |
| throw new DocumentRendererException( "Error parsing configuration : " + e.getMessage() ); |
| } |
| |
| // Only one chapter per doc |
| Node chapter = iTextDocument.getElementsByTagName( ElementTags.CHAPTER ).item( 0 ); |
| try |
| { |
| document.getDocumentElement().appendChild( document.importNode( chapter, true ) ); |
| } |
| catch ( DOMException e ) |
| { |
| throw new DocumentRendererException( "Error appending chapter for " |
| + iTextFile + " : " + e.getMessage() ); |
| } |
| } |
| |
| return document; |
| } |
| |
| /** |
| * Init the transformer object |
| * |
| * @return an instanced transformer object |
| * @throws org.apache.maven.doxia.docrenderer.DocumentRendererException if any |
| */ |
| private Transformer initTransformer() |
| throws DocumentRendererException |
| { |
| try |
| { |
| Transformer transformer = TRANSFORMER_FACTORY.newTransformer( new StreamSource( DefaultPdfRenderer.class |
| .getResourceAsStream( "/" + XSLT_RESOURCE ) ) ); |
| transformer.setErrorListener( TRANSFORMER_FACTORY.getErrorListener() ); |
| |
| transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "false" ); |
| transformer.setOutputProperty( OutputKeys.INDENT, "yes" ); |
| transformer.setOutputProperty( OutputKeys.METHOD, "xml" ); |
| transformer.setOutputProperty( OutputKeys.ENCODING, "UTF-8" ); |
| |
| return transformer; |
| } |
| catch ( TransformerConfigurationException e ) |
| { |
| throw new DocumentRendererException( "Error configuring Transformer for " + XSLT_RESOURCE + ": " |
| + e.getMessage() ); |
| } |
| catch ( IllegalArgumentException e ) |
| { |
| throw new DocumentRendererException( "Error configuring Transformer for " + XSLT_RESOURCE + ": " |
| + e.getMessage() ); |
| } |
| } |
| |
| /** |
| * Add transformer parameters |
| * |
| * @param transformer |
| * @param documentModel |
| */ |
| private void addTransformerParameters( Transformer transformer, DocumentModel documentModel ) |
| { |
| if ( documentModel.getMeta().getTitle() != null ) |
| { |
| transformer.setParameter( "title", documentModel.getMeta().getTitle() ); |
| } |
| if ( documentModel.getMeta().getAuthor() != null ) |
| { |
| transformer.setParameter( "author", documentModel.getMeta().getAuthor() ); |
| } |
| transformer.setParameter( "creationdate", new Date().toString() ); |
| if ( documentModel.getMeta().getSubject() != null ) |
| { |
| transformer.setParameter( "subject", documentModel.getMeta().getSubject() ); |
| } |
| if ( documentModel.getMeta().getKeywords() != null ) |
| { |
| transformer.setParameter( "keywords", documentModel.getMeta().getKeywords() ); |
| } |
| transformer.setParameter( "producer", "Generated with Doxia by " + System.getProperty( "user.name" ) ); |
| if ( ITextUtil.isPageSizeSupported( documentModel.getMeta().getTitle() ) ) |
| { |
| transformer.setParameter( "pagesize", documentModel.getMeta().getPageSize() ); |
| } |
| else |
| { |
| transformer.setParameter( "pagesize", "A4" ); |
| } |
| |
| transformer.setParameter( "frontPageHeader", "" ); |
| if ( documentModel.getMeta().getTitle() != null ) |
| { |
| transformer.setParameter( "frontPageTitle", documentModel.getMeta().getTitle() ); |
| } |
| transformer.setParameter( "frontPageFooter", "Generated date " + new Date().toString() ); |
| } |
| |
| /** |
| * Transform a document to an iTextFile |
| * |
| * @param documentModel |
| * @param document |
| * @param iTextFile |
| * @throws org.apache.maven.doxia.docrenderer.DocumentRendererException if any. |
| */ |
| private void transform( DocumentModel documentModel, Document document, File iTextFile ) |
| throws DocumentRendererException |
| { |
| Transformer transformer = initTransformer(); |
| |
| addTransformerParameters( transformer, documentModel ); |
| |
| try |
| { |
| transformer.transform( new DOMSource( document ), new StreamResult( iTextFile ) ); |
| } |
| catch ( TransformerException e ) |
| { |
| throw new DocumentRendererException( "Error transformer Document from " |
| + document + ": " + e.getMessage() ); |
| } |
| } |
| } |