1 package org.apache.maven.doxia.docrenderer.pdf.fo;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.Writer;
25 import java.util.Collection;
26 import java.util.List;
27 import java.util.Locale;
28 import java.util.Map;
29
30 import javax.xml.transform.TransformerException;
31
32 import org.apache.maven.doxia.docrenderer.DocumentRendererContext;
33 import org.apache.maven.doxia.docrenderer.DocumentRendererException;
34 import org.apache.maven.doxia.docrenderer.pdf.AbstractPdfRenderer;
35 import org.apache.maven.doxia.docrenderer.pdf.PdfRenderer;
36 import org.apache.maven.doxia.document.DocumentModel;
37 import org.apache.maven.doxia.document.DocumentTOC;
38 import org.apache.maven.doxia.document.DocumentTOCItem;
39 import org.apache.maven.doxia.module.fo.FoAggregateSink;
40 import org.apache.maven.doxia.module.fo.FoSink;
41 import org.apache.maven.doxia.module.fo.FoSinkFactory;
42 import org.apache.maven.doxia.module.fo.FoUtils;
43 import org.apache.maven.doxia.module.site.SiteModule;
44
45 import org.codehaus.plexus.component.annotations.Component;
46 import org.codehaus.plexus.util.IOUtil;
47 import org.codehaus.plexus.util.StringUtils;
48 import org.codehaus.plexus.util.WriterFactory;
49
50 import org.xml.sax.SAXParseException;
51
52
53
54
55
56
57
58
59 @Component( role = PdfRenderer.class, hint = "fo" )
60 public class FoPdfRenderer
61 extends AbstractPdfRenderer
62 {
63
64
65
66
67 public void generatePdf( File inputFile, File pdfFile )
68 throws DocumentRendererException
69 {
70
71 generatePdf( inputFile, pdfFile, null );
72 }
73
74
75 @Override
76 public void render( Map<String, SiteModule> filesToProcess, File outputDirectory, DocumentModel documentModel )
77 throws DocumentRendererException, IOException
78 {
79 render( filesToProcess, outputDirectory, documentModel, null );
80 }
81
82
83 @Override
84 public void render( Map<String, SiteModule> filesToProcess, File outputDirectory, DocumentModel documentModel,
85 DocumentRendererContext context )
86 throws DocumentRendererException, IOException
87 {
88
89 copyResources( outputDirectory );
90
91 if ( documentModel == null )
92 {
93 getLogger().debug( "No document model, generating all documents individually." );
94
95 renderIndividual( filesToProcess, outputDirectory, context );
96 return;
97 }
98
99 String outputName = getOutputName( documentModel );
100
101 File outputFOFile = new File( outputDirectory, outputName + ".fo" );
102 if ( !outputFOFile.getParentFile().exists() )
103 {
104 outputFOFile.getParentFile().mkdirs();
105 }
106
107 File pdfOutputFile = new File( outputDirectory, outputName + ".pdf" );
108 if ( !pdfOutputFile.getParentFile().exists() )
109 {
110 pdfOutputFile.getParentFile().mkdirs();
111 }
112
113 Writer writer = null;
114 try
115 {
116 writer = WriterFactory.newXmlWriter( outputFOFile );
117
118 FoAggregateSink sink = new FoAggregateSink( writer );
119
120 File fOConfigFile = new File( outputDirectory, "pdf-config.xml" );
121
122 if ( fOConfigFile.exists() )
123 {
124 sink.load( fOConfigFile );
125 getLogger().debug( "Loaded pdf config file: " + fOConfigFile.getAbsolutePath() );
126 }
127
128 String generateTOC =
129 ( context != null && context.get( "generateTOC" ) != null ? context.get( "generateTOC" ).toString().trim()
130 : "start" );
131 int tocPosition = 0;
132 if ( "start".equalsIgnoreCase( generateTOC ) )
133 {
134 tocPosition = FoAggregateSink.TOC_START;
135 }
136 else if ( "end".equalsIgnoreCase( generateTOC ) )
137 {
138 tocPosition = FoAggregateSink.TOC_END;
139 }
140 else
141 {
142 tocPosition = FoAggregateSink.TOC_NONE;
143 }
144 sink.setDocumentModel( documentModel, tocPosition );
145
146 sink.beginDocument();
147
148 sink.coverPage();
149
150 if ( tocPosition == FoAggregateSink.TOC_START )
151 {
152 sink.toc();
153 }
154
155 if ( ( documentModel.getToc() == null ) || ( documentModel.getToc().getItems() == null ) )
156 {
157 getLogger().info( "No TOC is defined in the document descriptor. Merging all documents." );
158
159 mergeAllSources( filesToProcess, sink, context );
160 }
161 else
162 {
163 getLogger().debug( "Using TOC defined in the document descriptor." );
164
165 mergeSourcesFromTOC( documentModel.getToc(), sink, context );
166 }
167
168 if ( tocPosition == FoAggregateSink.TOC_END )
169 {
170 sink.toc();
171 }
172
173 sink.endDocument();
174 }
175 finally
176 {
177 IOUtil.close( writer );
178 }
179
180 generatePdf( outputFOFile, pdfOutputFile, documentModel );
181 }
182
183
184 @Override
185 public void renderIndividual( Map<String, SiteModule> filesToProcess, File outputDirectory )
186 throws DocumentRendererException, IOException
187 {
188 renderIndividual( filesToProcess, outputDirectory, null );
189 }
190
191
192 @Override
193 public void renderIndividual( Map<String, SiteModule> filesToProcess, File outputDirectory,
194 DocumentRendererContext context )
195 throws DocumentRendererException, IOException
196 {
197 for ( Map.Entry<String, SiteModule> entry : filesToProcess.entrySet() )
198 {
199 String key = entry.getKey();
200 SiteModule module = entry.getValue();
201
202 File fullDoc = new File( getBaseDir(), module.getSourceDirectory() + File.separator + key );
203
204 String output = key;
205 String lowerCaseExtension = module.getExtension().toLowerCase( Locale.ENGLISH );
206 if ( output.toLowerCase( Locale.ENGLISH ).indexOf( "." + lowerCaseExtension ) != -1 )
207 {
208 output =
209 output.substring( 0, output.toLowerCase( Locale.ENGLISH ).indexOf( "." + lowerCaseExtension ) );
210 }
211
212 File outputFOFile = new File( outputDirectory, output + ".fo" );
213 if ( !outputFOFile.getParentFile().exists() )
214 {
215 outputFOFile.getParentFile().mkdirs();
216 }
217
218 File pdfOutputFile = new File( outputDirectory, output + ".pdf" );
219 if ( !pdfOutputFile.getParentFile().exists() )
220 {
221 pdfOutputFile.getParentFile().mkdirs();
222 }
223
224 FoSink sink =
225 (FoSink) new FoSinkFactory().createSink( outputFOFile.getParentFile(), outputFOFile.getName() );
226 sink.beginDocument();
227 parse( fullDoc.getAbsolutePath(), module.getParserId(), sink, context );
228 sink.endDocument();
229
230 generatePdf( outputFOFile, pdfOutputFile, null );
231 }
232 }
233
234 private void mergeAllSources( Map<String, SiteModule> filesToProcess, FoAggregateSink sink,
235 DocumentRendererContext context )
236 throws DocumentRendererException, IOException
237 {
238 for ( Map.Entry<String, SiteModule> entry : filesToProcess.entrySet() )
239 {
240 String key = entry.getKey();
241 SiteModule module = entry.getValue();
242 sink.setDocumentName( key );
243 File fullDoc = new File( getBaseDir(), module.getSourceDirectory() + File.separator + key );
244
245 parse( fullDoc.getAbsolutePath(), module.getParserId(), sink, context );
246 }
247 }
248
249 private void mergeSourcesFromTOC( DocumentTOC toc, FoAggregateSink sink, DocumentRendererContext context )
250 throws IOException, DocumentRendererException
251 {
252 parseTocItems( toc.getItems(), sink, context );
253 }
254
255 private void parseTocItems( List<DocumentTOCItem> items, FoAggregateSink sink, DocumentRendererContext context )
256 throws IOException, DocumentRendererException
257 {
258 for ( DocumentTOCItem tocItem : items )
259 {
260 if ( tocItem.getRef() == null )
261 {
262 if ( getLogger().isInfoEnabled() )
263 {
264 getLogger().info( "No ref defined for tocItem " + tocItem.getName() );
265 }
266
267 continue;
268 }
269
270 String href = StringUtils.replace( tocItem.getRef(), "\\", "/" );
271 if ( href.lastIndexOf( '.') != -1 )
272 {
273 href = href.substring( 0, href.lastIndexOf( '.') );
274 }
275
276 renderModules( href, sink, tocItem, context );
277
278 if ( tocItem.getItems() != null )
279 {
280 parseTocItems( tocItem.getItems(), sink, context );
281 }
282 }
283 }
284
285 private void renderModules( String href, FoAggregateSink sink, DocumentTOCItem tocItem,
286 DocumentRendererContext context )
287 throws DocumentRendererException, IOException
288 {
289 Collection<SiteModule> modules = siteModuleManager.getSiteModules();
290 for ( SiteModule module : modules )
291 {
292 File moduleBasedir = new File( getBaseDir(), module.getSourceDirectory() );
293
294 if ( moduleBasedir.exists() )
295 {
296 String doc = href + "." + module.getExtension();
297 File source = new File( moduleBasedir, doc );
298
299
300 if ( !source.exists() )
301 {
302 if ( href.indexOf( "." + module.getExtension() ) != -1 )
303 {
304 doc = href + ".vm";
305 }
306 else
307 {
308 doc = href + "." + module.getExtension() + ".vm";
309 }
310 source = new File( moduleBasedir, doc );
311 }
312
313 if ( source.exists() )
314 {
315 sink.setDocumentName( doc );
316 sink.setDocumentTitle( tocItem.getName() );
317
318 parse( source.getPath(), module.getParserId(), sink, context );
319 }
320 }
321 }
322 }
323
324
325
326
327
328
329
330
331 private void generatePdf( File inputFile, File pdfFile, DocumentModel documentModel )
332 throws DocumentRendererException
333 {
334 if ( getLogger().isDebugEnabled() )
335 {
336 getLogger().debug( "Generating: " + pdfFile );
337 }
338
339 try
340 {
341 FoUtils.convertFO2PDF( inputFile, pdfFile, null, documentModel );
342 }
343 catch ( TransformerException e )
344 {
345 if ( ( e.getCause() != null ) && ( e.getCause() instanceof SAXParseException ) )
346 {
347 SAXParseException sax = (SAXParseException) e.getCause();
348
349 StringBuilder sb = new StringBuilder();
350 sb.append( "Error creating PDF from " ).append( inputFile.getAbsolutePath() ).append( ":" )
351 .append( sax.getLineNumber() ).append( ":" ).append( sax.getColumnNumber() ).append( "\n" );
352 sb.append( e.getMessage() );
353
354 throw new DocumentRendererException( sb.toString() );
355 }
356
357 throw new DocumentRendererException( "Error creating PDF from " + inputFile + ": " + e.getMessage() );
358 }
359 }
360 }