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