1 package org.apache.maven.doxia.book.services.renderer;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.IOException;
25 import java.io.Reader;
26 import java.io.Writer;
27 import java.text.DateFormat;
28 import java.util.Date;
29
30 import org.apache.maven.doxia.Doxia;
31 import org.apache.maven.doxia.book.BookDoxiaException;
32 import org.apache.maven.doxia.book.context.BookContext;
33 import org.apache.maven.doxia.book.model.BookModel;
34 import org.apache.maven.doxia.book.model.Chapter;
35 import org.apache.maven.doxia.book.model.Section;
36 import org.apache.maven.doxia.module.itext.ITextSinkFactory;
37 import org.apache.maven.doxia.parser.ParseException;
38 import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
39 import org.apache.maven.doxia.sink.Sink;
40 import org.codehaus.plexus.logging.AbstractLogEnabled;
41 import org.codehaus.plexus.util.IOUtil;
42 import org.codehaus.plexus.util.ReaderFactory;
43 import org.codehaus.plexus.util.StringUtils;
44 import org.codehaus.plexus.util.WriterFactory;
45 import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
46
47 /**
48 * Base class for <code>iText</code> renderer.
49 *
50 * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
51 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
52 * @version $Id: AbstractITextBookRenderer.java 1090706 2011-04-09 23:15:28Z hboutemy $
53 */
54 public abstract class AbstractITextBookRenderer
55 extends AbstractLogEnabled
56 implements BookRenderer
57 {
58 /**
59 * @plexus.requirement
60 */
61 private Doxia doxia;
62
63 // ----------------------------------------------------------------------
64 // BookRenderer Implementation
65 // ----------------------------------------------------------------------
66
67 /** {@inheritDoc} */
68 public void renderBook( BookContext context )
69 throws BookDoxiaException
70 {
71 BookModel book = context.getBook();
72
73 if ( !context.getOutputDirectory().exists() )
74 {
75 if ( !context.getOutputDirectory().mkdirs() )
76 {
77 throw new BookDoxiaException( "Could not make directory: "
78 + context.getOutputDirectory().getAbsolutePath() + "." );
79 }
80 }
81
82 File bookFile = new File( context.getOutputDirectory(), book.getId() + ".xml" );
83
84 Writer fileWriter;
85 try
86 {
87 fileWriter = WriterFactory.newXmlWriter( bookFile );
88 }
89 catch ( IOException e )
90 {
91 throw new BookDoxiaException( "Error while opening file.", e );
92 }
93
94 // ----------------------------------------------------------------------
95 // Create the XML File
96 // ----------------------------------------------------------------------
97
98 PrettyPrintXMLWriter writer = new PrettyPrintXMLWriter( fileWriter, "UTF-8", null );
99 writer.startElement( "itext" );
100 writer.addAttribute( "creationdate", DateFormat.getDateTimeInstance().format( new Date() ) );
101 writer.addAttribute( "producer", "Doxia iText" );
102
103 // writer.startElement( "paragraph" );
104 // writer.addAttribute( "leading", "18.0" );
105 // writer.addAttribute( "font", "unknown" );
106 // writer.addAttribute( "align", "Default" );
107 // writer.writeText( "Please visit my" + System.getProperty( "line.separator" ) );
108 //
109 // writer.startElement( "anchor" );
110 // writer.addAttribute( "leading", "18.0" );
111 // writer.addAttribute( "font", "Helvetica" );
112 // writer.addAttribute( "size", "12.0" );
113 // writer.addAttribute( "fontstyle", "normal, underline" );
114 // writer.addAttribute( "red", "0" );
115 // writer.addAttribute( "green", "0" );
116 // writer.addAttribute( "blue", "255" );
117 // writer.addAttribute( "name", "top" );
118 // writer.addAttribute( "reference", "http://www.lowagie.com/iText/" );
119 //
120 // writer.startElement( "chunk" );
121 // writer.addAttribute( "font", "Helvetica" );
122 // writer.addAttribute( "size", "12.0" );
123 // writer.addAttribute( "fontstyle", "normal, underline" );
124 // writer.addAttribute( "red", "0" );
125 // writer.addAttribute( "green", "0" );
126 // writer.addAttribute( "blue", "255" );
127 // writer.writeText( "website (external reference)" );
128 // writer.endElement();
129 //
130 // writer.endElement(); // anchor
131 //
132 // writer.endElement(); // paragraph
133
134 // TODO: Write out TOC
135
136 System.setProperty( "itext.basedir", bookFile.getParentFile().getAbsolutePath() );
137 Sink sink = new ITextSinkFactory().createSink( writer );
138
139 try
140 {
141 for ( Chapter chapter : book.getChapters() )
142 {
143 renderChapter( sink, writer, chapter, context );
144 }
145
146 writer.endElement(); // itext
147 }
148 finally
149 {
150 sink.flush();
151 sink.close();
152
153 IOUtil.close( fileWriter );
154 System.getProperties().remove( "itext.basedir" );
155 }
156
157 // ----------------------------------------------------------------------
158 // Render the XML to PDF
159 // ----------------------------------------------------------------------
160 File outputFile = new File( context.getOutputDirectory(), book.getId() + "." + getOutputExtension() );
161 try
162 {
163 renderXML( bookFile, outputFile );
164 }
165 catch ( IOException e )
166 {
167 throw new BookDoxiaException( "Error while rendering file", e );
168 }
169 }
170
171 /**
172 * Get the output extension supported.
173 *
174 * @return the ouput extension supported.
175 */
176 public abstract String getOutputExtension();
177
178 /**
179 * Generate an ouput file with the iText framework.
180 *
181 * @param iTextFile the input file.
182 * @param iTextOutput the output file.
183 * @throws java.io.IOException if any.
184 */
185 public abstract void renderXML( File iTextFile, File iTextOutput )
186 throws IOException;
187
188 // ----------------------------------------------------------------------
189 // Private
190 // ----------------------------------------------------------------------
191
192 /**
193 * Write a chapter.
194 *
195 * @param writer the writer.
196 * @param chapter the Chapter.
197 * @param context the BookContext.
198 * @throws BookDoxiaException if the chapter cannot be written.
199 */
200 private void renderChapter( Sink sink, PrettyPrintXMLWriter writer, Chapter chapter, BookContext context )
201 throws BookDoxiaException
202 {
203 writer.startElement( "chapter" );
204 writer.addAttribute( "numberdepth", "1" );
205 writer.addAttribute( "depth", "1" );
206 writer.addAttribute( "indent", "1" );
207
208 startTitle( writer, "36.0", "Helvetica", "24.0", "normal", "255", "0", "0" );
209 chunk( writer, chapter.getTitle(), "Helvetica", "24.0", "normal", "255", "0", "0" );
210 writer.endElement(); // title
211
212 // writer.startElement( "sectioncontent" );
213 for ( Section section : chapter.getSections() )
214 {
215 renderSection( sink, writer, section, context );
216 }
217 // writer.endElement(); // sectioncontent
218
219 writer.endElement(); // chapter
220 }
221
222 /**
223 * Write a section.
224 *
225 * @param writer the writer.
226 * @param section the Section.
227 * @param context the BookContext.
228 * @throws BookDoxiaException if the section cannot be written.
229 */
230 private void renderSection( Sink sink, PrettyPrintXMLWriter writer, Section section, BookContext context )
231 throws BookDoxiaException
232 {
233 // writer.startElement( "section" );
234
235 // ----------------------------------------------------------------------
236 //
237 // ----------------------------------------------------------------------
238
239 BookContext.BookFile bookFile = (BookContext.BookFile) context.getFiles().get( section.getId() );
240
241 if ( bookFile == null )
242 {
243 throw new BookDoxiaException( "No document that matches section with id=" + section.getId() + "." );
244 }
245
246 // ----------------------------------------------------------------------
247 //
248 // ----------------------------------------------------------------------
249
250 Reader reader = null;
251 try
252 {
253 reader = ReaderFactory.newReader( bookFile.getFile(), context.getInputEncoding() );
254 doxia.parse( reader, bookFile.getParserId(), sink );
255 }
256 catch ( ParserNotFoundException e )
257 {
258 throw new BookDoxiaException( "Parser not found: " + bookFile.getParserId() + ".", e );
259 }
260 catch ( ParseException e )
261 {
262 throw new BookDoxiaException(
263 "Error while parsing document: " + bookFile.getFile().getAbsolutePath() + ".",
264 e );
265 }
266 catch ( FileNotFoundException e )
267 {
268 throw new BookDoxiaException( "Could not find document: " + bookFile.getFile().getAbsolutePath() + ".", e );
269 }
270 catch ( IOException e )
271 {
272 throw new BookDoxiaException( "Error while rendering book: "
273 + bookFile.getFile().getAbsolutePath() + ".", e );
274 }
275 finally
276 {
277 IOUtil.close( reader );
278 }
279 }
280
281 /**
282 * Start a title.
283 *
284 * @param writer the writer.
285 * @param leading leading.
286 * @param font the font.
287 * @param size the size.
288 * @param fontstyle the fontstyle.
289 * @param red red.
290 * @param green green.
291 * @param blue blue.
292 */
293 private void startTitle( PrettyPrintXMLWriter writer, String leading, String font, String size, String fontstyle,
294 String red, String green, String blue )
295 {
296 writer.startElement( "title" );
297 writer.addAttribute( "leading", leading );
298 writer.addAttribute( "font", font );
299 writer.addAttribute( "size", size );
300 writer.addAttribute( "fontstyle", fontstyle );
301 writer.addAttribute( "red", red );
302 writer.addAttribute( "green", green );
303 writer.addAttribute( "blue", blue );
304 }
305
306 /**
307 * Write a chunk.
308 *
309 * @param writer the writer.
310 * @param title the title.
311 * @param font the font.
312 * @param size the size.
313 * @param fontstyle the fontstyle.
314 * @param red red.
315 * @param green green.
316 * @param blue blue.
317 */
318 private void chunk( PrettyPrintXMLWriter writer, String title, String font, String size, String fontstyle,
319 String red, String green, String blue )
320 {
321 writer.startElement( "chunk" );
322 writer.addAttribute( "font", font );
323 writer.addAttribute( "size", size );
324 writer.addAttribute( "fontstyle", fontstyle );
325 writer.addAttribute( "red", red );
326 writer.addAttribute( "green", green );
327 writer.addAttribute( "blue", blue );
328 if ( StringUtils.isNotEmpty( title ) )
329 {
330 writer.writeText( title );
331 }
332 else
333 {
334 writer.writeText( "<Missing title>" );
335 }
336 writer.endElement(); // chunk
337 }
338 }