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