001package org.apache.maven.doxia.module.fo;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.BufferedOutputStream;
023import java.io.File;
024import java.io.FileOutputStream;
025import java.io.IOException;
026import java.io.OutputStream;
027import java.util.Date;
028
029import javax.xml.transform.Result;
030import javax.xml.transform.Transformer;
031import javax.xml.transform.TransformerConfigurationException;
032import javax.xml.transform.TransformerException;
033import javax.xml.transform.TransformerFactory;
034import javax.xml.transform.sax.SAXResult;
035import javax.xml.transform.stream.StreamSource;
036
037import org.apache.fop.apps.FOPException;
038import org.apache.fop.apps.FOUserAgent;
039import org.apache.fop.apps.Fop;
040import org.apache.fop.apps.FopFactory;
041import org.apache.fop.apps.MimeConstants;
042import org.apache.maven.doxia.document.DocumentModel;
043import org.codehaus.plexus.util.IOUtil;
044import org.codehaus.plexus.util.StringUtils;
045
046/**
047 * <code>FO Sink</code> utilities.
048 *
049 * @author ltheussl
050 * @version $Id$
051 * @since 1.1
052 */
053public class FoUtils
054{
055    /** To reuse the FopFactory **/
056    private static final FopFactory FOP_FACTORY = FopFactory.newInstance();
057
058    /** To reuse the TransformerFactory **/
059    private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
060
061    /**
062     * Converts an FO file to a PDF file using FOP.
063     *
064     * @param fo the FO file, not null.
065     * @param pdf the target PDF file, not null.
066     * @param resourceDir The base directory for relative path resolution, could be null.
067     * If null, defaults to the parent directory of fo.
068     * @param documentModel the document model to add PDF metadatas like author, title and keywords, could be null.
069     * @throws javax.xml.transform.TransformerException In case of a conversion problem.
070     * @since 1.1.1
071     */
072    public static void convertFO2PDF( File fo, File pdf, String resourceDir, DocumentModel documentModel )
073        throws TransformerException
074    {
075        FOUserAgent foUserAgent = getDefaultUserAgent( fo, resourceDir );
076
077        if ( documentModel != null && documentModel.getMeta() != null )
078        {
079            // http://xmlgraphics.apache.org/fop/embedding.html#user-agent
080            String authors = documentModel.getMeta().getAllAuthorNames();
081            if ( StringUtils.isNotEmpty( authors ) )
082            {
083                foUserAgent.setAuthor( authors );
084            }
085            if ( StringUtils.isNotEmpty( documentModel.getMeta().getTitle() ) )
086            {
087                foUserAgent.setTitle( documentModel.getMeta().getTitle() );
088            }
089            String keywords = documentModel.getMeta().getAllKeyWords();
090            if ( StringUtils.isNotEmpty( keywords ) )
091            {
092                foUserAgent.setKeywords( keywords );
093            }
094            if ( StringUtils.isNotEmpty( documentModel.getMeta().getCreator() ) )
095            {
096                foUserAgent.setCreator( documentModel.getMeta().getCreator() );
097            }
098            if ( StringUtils.isNotEmpty( documentModel.getMeta().getGenerator() ) )
099            {
100                foUserAgent.setProducer( documentModel.getMeta().getGenerator() );
101            }
102            if ( documentModel.getMeta().getCreationDate() != null )
103            {
104                foUserAgent.setCreationDate( documentModel.getMeta().getCreationDate() );
105            }
106        }
107
108        if ( foUserAgent.getCreator() == null )
109        {
110            foUserAgent.setCreator( System.getProperty( "user.name" ) );
111        }
112        if ( foUserAgent.getCreationDate() == null )
113        {
114            foUserAgent.setCreationDate( new Date() );
115        }
116
117        convertFO2PDF( fo, pdf, resourceDir, foUserAgent );
118    }
119
120    /**
121     * Converts an FO file to a PDF file using FOP.
122     *
123     * @param fo the FO file, not null.
124     * @param pdf the target PDF file, not null.
125     * @param resourceDir The base directory for relative path resolution, could be null.
126     * If null, defaults to the parent directory of fo.
127     * @param foUserAgent the FOUserAgent to use.
128     *      May be null, in which case a default user agent will be used.
129     * @throws javax.xml.transform.TransformerException In case of a conversion problem.
130     * @since 1.1.1
131     */
132    public static void convertFO2PDF( File fo, File pdf, String resourceDir, FOUserAgent foUserAgent )
133        throws TransformerException
134    {
135        FOUserAgent userAgent = ( foUserAgent == null ? getDefaultUserAgent( fo, resourceDir ) : foUserAgent );
136
137        OutputStream out = null;
138        try
139        {
140            try
141            {
142                out = new BufferedOutputStream( new FileOutputStream( pdf ) );
143            }
144            catch ( IOException e )
145            {
146                throw new TransformerException( e );
147            }
148
149            Result res = null;
150            try
151            {
152                Fop fop = FOP_FACTORY.newFop( MimeConstants.MIME_PDF, userAgent, out );
153                res = new SAXResult( fop.getDefaultHandler() );
154            }
155            catch ( FOPException e )
156            {
157                throw new TransformerException( e );
158            }
159
160            Transformer transformer = null;
161            try
162            {
163                // identity transformer
164                transformer = TRANSFORMER_FACTORY.newTransformer();
165            }
166            catch ( TransformerConfigurationException e )
167            {
168                throw new TransformerException( e );
169            }
170
171            transformer.transform( new StreamSource( fo ), res );
172        }
173        finally
174        {
175            IOUtil.close( out );
176        }
177    }
178
179    /**
180     * Converts an FO file to a PDF file using FOP.
181     *
182     * @param fo the FO file, not null.
183     * @param pdf the target PDF file, not null.
184     * @param resourceDir The base directory for relative path resolution, could be null.
185     * If null, defaults to the parent directory of fo.
186     * @throws javax.xml.transform.TransformerException In case of a conversion problem.
187     * @see #convertFO2PDF(File, File, String, DocumentModel)
188     */
189    public static void convertFO2PDF( File fo, File pdf, String resourceDir )
190        throws TransformerException
191    {
192        convertFO2PDF( fo, pdf, resourceDir, (DocumentModel) null );
193    }
194
195    /**
196     * Returns a base URL to be used by the FOUserAgent.
197     *
198     * @param fo the FO file.
199     * @param resourceDir the resource directory.
200     * @return String.
201     */
202    private static String getBaseURL( File fo, String resourceDir )
203    {
204        String url = null;
205
206        if ( resourceDir == null )
207        {
208            url = "file:///" + fo.getParent() + "/";
209        }
210        else
211        {
212            url = "file:///" + resourceDir + "/";
213        }
214
215        return url;
216    }
217
218    private static FOUserAgent getDefaultUserAgent( File fo, String resourceDir )
219    {
220        FOUserAgent foUserAgent = FOP_FACTORY.newFOUserAgent();
221        foUserAgent.setBaseURL( getBaseURL( fo, resourceDir ) );
222
223        return foUserAgent;
224    }
225
226    private FoUtils()
227    {
228        // Utility class
229    }
230}