View Javadoc
1   package org.apache.maven.doxia.docrenderer.pdf.itext;
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.FileInputStream;
24  import java.io.FileOutputStream;
25  import java.io.IOException;
26  import java.io.Writer;
27  import java.net.MalformedURLException;
28  import java.net.URL;
29  import java.net.URLClassLoader;
30  import java.text.SimpleDateFormat;
31  import java.util.Collection;
32  import java.util.Date;
33  import java.util.Iterator;
34  import java.util.LinkedList;
35  import java.util.List;
36  import java.util.Locale;
37  import java.util.Map;
38  
39  import javax.xml.parsers.DocumentBuilder;
40  import javax.xml.parsers.DocumentBuilderFactory;
41  import javax.xml.parsers.ParserConfigurationException;
42  import javax.xml.transform.OutputKeys;
43  import javax.xml.transform.Transformer;
44  import javax.xml.transform.TransformerConfigurationException;
45  import javax.xml.transform.TransformerException;
46  import javax.xml.transform.TransformerFactory;
47  import javax.xml.transform.dom.DOMSource;
48  import javax.xml.transform.stream.StreamResult;
49  import javax.xml.transform.stream.StreamSource;
50  
51  import org.apache.maven.doxia.docrenderer.DocumentRendererContext;
52  import org.apache.maven.doxia.docrenderer.DocumentRendererException;
53  import org.apache.maven.doxia.docrenderer.pdf.AbstractPdfRenderer;
54  import org.apache.maven.doxia.docrenderer.pdf.PdfRenderer;
55  import org.apache.maven.doxia.document.DocumentCover;
56  import org.apache.maven.doxia.document.DocumentMeta;
57  import org.apache.maven.doxia.document.DocumentModel;
58  import org.apache.maven.doxia.document.DocumentTOCItem;
59  import org.apache.maven.doxia.module.itext.ITextSink;
60  import org.apache.maven.doxia.module.itext.ITextSinkFactory;
61  import org.apache.maven.doxia.module.itext.ITextUtil;
62  import org.apache.maven.doxia.parser.module.ParserModule;
63  import org.apache.xml.utils.DefaultErrorHandler;
64  import org.codehaus.plexus.component.annotations.Component;
65  import org.codehaus.plexus.util.IOUtil;
66  import org.codehaus.plexus.util.StringUtils;
67  import org.codehaus.plexus.util.WriterFactory;
68  import org.w3c.dom.DOMException;
69  import org.w3c.dom.Document;
70  import org.w3c.dom.Node;
71  import org.xml.sax.SAXException;
72  
73  import com.lowagie.text.ElementTags;
74  
75  /**
76   * Abstract <code>document</code> render with the <code>iText</code> framework
77   *
78   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
79   * @author ltheussl
80   * @version $Id: ITextPdfRenderer.java 1726406 2016-01-23 15:06:45Z hboutemy $
81   * @since 1.1
82   */
83  @Component( role = PdfRenderer.class, hint = "itext" )
84  public class ITextPdfRenderer
85      extends AbstractPdfRenderer
86  {
87      /** The xslt style sheet used to transform a Document to an iText file. */
88      private static final String XSLT_RESOURCE = "TOC.xslt";
89  
90      /** The TransformerFactory. */
91      private static final TransformerFactory TRANSFORMER_FACTORY = TransformerFactory.newInstance();
92  
93      /** The DocumentBuilderFactory. */
94      private static final DocumentBuilderFactory DOCUMENT_BUILDER_FACTORY = DocumentBuilderFactory.newInstance();
95  
96      /** The DocumentBuilder. */
97      private static final DocumentBuilder DOCUMENT_BUILDER;
98  
99      static
100     {
101         TRANSFORMER_FACTORY.setErrorListener( new DefaultErrorHandler() );
102 
103         try
104         {
105             DOCUMENT_BUILDER = DOCUMENT_BUILDER_FACTORY.newDocumentBuilder();
106         }
107         catch ( ParserConfigurationException e )
108         {
109             throw new RuntimeException( "Error building document :" + e.getMessage() );
110         }
111     }
112 
113     /** {@inheritDoc} */
114     public void generatePdf( File inputFile, File pdfFile )
115         throws DocumentRendererException
116     {
117         if ( getLogger().isDebugEnabled() )
118         {
119             getLogger().debug( "Generating : " + pdfFile );
120         }
121 
122         try
123         {
124             ITextUtil.writePdf( new FileInputStream( inputFile ), new FileOutputStream( pdfFile ) );
125         }
126         catch ( IOException e )
127         {
128             throw new DocumentRendererException( "Cannot create PDF from " + inputFile + ": " + e.getMessage(), e );
129         }
130         catch ( RuntimeException e )
131         {
132             throw new DocumentRendererException( "Error creating PDF from " + inputFile + ": " + e.getMessage(), e );
133         }
134     }
135 
136     /** {@inheritDoc} */
137     @Override
138     public void render( Map<String, ParserModule> filesToProcess, File outputDirectory, DocumentModel documentModel )
139         throws DocumentRendererException, IOException
140     {
141         render( filesToProcess, outputDirectory, documentModel, null );
142     }
143 
144     /** {@inheritDoc} */
145     @Override
146     public void render( Map<String, ParserModule> filesToProcess, File outputDirectory, DocumentModel documentModel,
147                         DocumentRendererContext context )
148         throws DocumentRendererException, IOException
149     {
150         // copy resources, images, etc.
151         copyResources( outputDirectory );
152 
153         if ( documentModel == null )
154         {
155             getLogger().debug( "No document model, generating all documents individually." );
156 
157             renderIndividual( filesToProcess, outputDirectory, context );
158             return;
159         }
160 
161         String outputName = getOutputName( documentModel );
162 
163         File outputITextFile = new File( outputDirectory, outputName + ".xml" );
164         if ( !outputITextFile.getParentFile().exists() )
165         {
166             outputITextFile.getParentFile().mkdirs();
167         }
168 
169         File pdfOutputFile = new File( outputDirectory, outputName + ".pdf" );
170         if ( !pdfOutputFile.getParentFile().exists() )
171         {
172             pdfOutputFile.getParentFile().mkdirs();
173         }
174 
175         List<File> iTextFiles;
176         if ( ( documentModel.getToc() == null ) || ( documentModel.getToc().getItems() == null ) )
177         {
178             getLogger().info( "No TOC is defined in the document descriptor. Merging all documents." );
179 
180             iTextFiles = parseAllFiles( filesToProcess, outputDirectory, context );
181         }
182         else
183         {
184             getLogger().debug( "Using TOC defined in the document descriptor." );
185 
186             iTextFiles = parseTOCFiles( outputDirectory, documentModel, context );
187         }
188 
189         String generateTOC =
190             ( context != null && context.get( "generateTOC" ) != null ? context.get( "generateTOC" ).toString()
191                             : "start" );
192 
193         File iTextFile = new File( outputDirectory, outputName + ".xml" );
194         File iTextOutput = new File( outputDirectory, outputName + "." + getOutputExtension() );
195         Document document = generateDocument( iTextFiles );
196         transform( documentModel, document, iTextFile, generateTOC );
197         generatePdf( iTextFile, iTextOutput );
198     }
199 
200     /** {@inheritDoc} */
201     @Override
202     public void renderIndividual( Map<String, ParserModule> filesToProcess, File outputDirectory )
203         throws DocumentRendererException, IOException
204     {
205         renderIndividual( filesToProcess, outputDirectory, null );
206     }
207 
208     /** {@inheritDoc} */
209     @Override
210     public void renderIndividual( Map<String, ParserModule> filesToProcess, File outputDirectory,
211                                   DocumentRendererContext context )
212         throws DocumentRendererException, IOException
213     {
214         for ( Map.Entry<String, ParserModule> entry : filesToProcess.entrySet() )
215         {
216             String key = entry.getKey();
217             ParserModule module = entry.getValue();
218             File fullDoc = new File( getBaseDir(), module.getSourceDirectory() + File.separator + key );
219 
220             String output = key;
221             for ( String extension : module.getExtensions() )
222             {
223                 String lowerCaseExtension = extension.toLowerCase( Locale.ENGLISH );
224                 if ( output.toLowerCase( Locale.ENGLISH ).indexOf( "." + lowerCaseExtension ) != -1 )
225                 {
226                     output =
227                         output.substring( 0, output.toLowerCase( Locale.ENGLISH ).indexOf( "." + lowerCaseExtension ) );
228                 }
229             }
230 
231             File outputITextFile = new File( outputDirectory, output + ".xml" );
232             if ( !outputITextFile.getParentFile().exists() )
233             {
234                 outputITextFile.getParentFile().mkdirs();
235             }
236 
237             File pdfOutputFile = new File( outputDirectory, output + ".pdf" );
238             if ( !pdfOutputFile.getParentFile().exists() )
239             {
240                 pdfOutputFile.getParentFile().mkdirs();
241             }
242 
243             parse( fullDoc, module, outputITextFile, context );
244 
245             generatePdf( outputITextFile, pdfOutputFile );
246         }
247     }
248 
249       //--------------------------------------------
250      //
251     //--------------------------------------------
252 
253 
254     /**
255      * Parse a source document and emit results into a sink.
256      *
257      * @param fullDocPath file to the source document.
258      * @param module the site module associated with the source document (determines the parser to use).
259      * @param iTextFile the resulting iText xml file.
260      * @throws DocumentRendererException in case of a parsing problem.
261      * @throws IOException if the source and/or target document cannot be opened.
262      */
263     private void parse( File fullDoc, ParserModule module, File iTextFile, DocumentRendererContext context )
264         throws DocumentRendererException, IOException
265     {
266         if ( getLogger().isDebugEnabled() )
267         {
268             getLogger().debug( "Parsing file " + fullDoc.getAbsolutePath() );
269         }
270 
271         System.setProperty( "itext.basedir", iTextFile.getParentFile().getAbsolutePath() );
272 
273         Writer writer = null;
274         ITextSink sink = null;
275         try
276         {
277             writer = WriterFactory.newXmlWriter( iTextFile );
278             sink = (ITextSink) new ITextSinkFactory().createSink( writer );
279 
280             sink.setClassLoader( new URLClassLoader( new URL[] { iTextFile.getParentFile().toURI().toURL() } ) );
281 
282             parse( fullDoc.getAbsolutePath(), module.getParserId(), sink, context );
283         }
284         finally
285         {
286             if ( sink != null )
287             {
288                 sink.flush();
289                 sink.close();
290             }
291             IOUtil.close( writer );
292             System.getProperties().remove( "itext.basedir" );
293         }
294     }
295 
296     /**
297      * Merge all iTextFiles to a single one.
298      *
299      * @param iTextFiles list of iText xml files.
300      * @return Document.
301      * @throws DocumentRendererException if any.
302      * @throws IOException if any.
303      */
304     private Document generateDocument( List<File> iTextFiles )
305         throws DocumentRendererException, IOException
306     {
307         Document document = DOCUMENT_BUILDER.newDocument();
308         document.appendChild( document.createElement( ElementTags.ITEXT ) ); // Used only to set a root
309 
310         for ( File iTextFile : iTextFiles )
311         {
312             Document iTextDocument;
313 
314             try
315             {
316                 iTextDocument = DOCUMENT_BUILDER.parse( iTextFile );
317             }
318             catch ( SAXException e )
319             {
320                 throw new DocumentRendererException( "SAX Error : " + e.getMessage() );
321             }
322 
323             // Only one chapter per doc
324             Node chapter = iTextDocument.getElementsByTagName( ElementTags.CHAPTER ).item( 0 );
325 
326             try
327             {
328                 document.getDocumentElement().appendChild( document.importNode( chapter, true ) );
329             }
330             catch ( DOMException e )
331             {
332                 throw new DocumentRendererException( "Error appending chapter for "
333                         + iTextFile + " : " + e.getMessage() );
334             }
335         }
336 
337         return document;
338     }
339 
340     /**
341      * Initialize the transformer object.
342      *
343      * @return an instance of a transformer object.
344      * @throws DocumentRendererException if any.
345      */
346     private Transformer initTransformer()
347         throws DocumentRendererException
348     {
349         try
350         {
351             Transformer transformer = TRANSFORMER_FACTORY.newTransformer( new StreamSource( ITextPdfRenderer.class
352                 .getResourceAsStream( XSLT_RESOURCE ) ) );
353 
354             transformer.setErrorListener( TRANSFORMER_FACTORY.getErrorListener() );
355 
356             transformer.setOutputProperty( OutputKeys.OMIT_XML_DECLARATION, "false" );
357 
358             transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
359 
360             transformer.setOutputProperty( OutputKeys.METHOD, "xml" );
361 
362             transformer.setOutputProperty( OutputKeys.ENCODING, "UTF-8" );
363 
364             // No doctype since itext doctype is not up to date!
365 
366             return transformer;
367         }
368         catch ( TransformerConfigurationException e )
369         {
370             throw new DocumentRendererException( "Error configuring Transformer for " + XSLT_RESOURCE + ": "
371                 + e.getMessage() );
372         }
373         catch ( IllegalArgumentException e )
374         {
375             throw new DocumentRendererException( "Error configuring Transformer for " + XSLT_RESOURCE + ": "
376                 + e.getMessage() );
377         }
378     }
379 
380     /**
381      * Add transformer parameters from a DocumentModel.
382      *
383      * @param transformer the Transformer to set the parameters.
384      * @param documentModel the DocumentModel to take the parameters from, could be null.
385      * @param iTextFile the iTextFile not null for the relative paths.
386      * @param generateTOC not null, possible values are: 'none', 'start' and 'end'.
387      */
388     private void addTransformerParameters( Transformer transformer, DocumentModel documentModel, File iTextFile,
389                                            String generateTOC )
390     {
391         if ( documentModel == null )
392         {
393             return;
394         }
395 
396         // TOC
397         addTransformerParameter( transformer, "toc.position", generateTOC );
398 
399         // Meta parameters
400         boolean hasNullMeta = false;
401         if ( documentModel.getMeta() == null )
402         {
403             hasNullMeta = true;
404             documentModel.setMeta( new DocumentMeta() );
405         }
406         addTransformerParameter( transformer, "meta.author", documentModel.getMeta().getAllAuthorNames(),
407                                  System.getProperty( "user.name", "null" ) );
408         addTransformerParameter( transformer, "meta.creator", documentModel.getMeta().getCreator(),
409                                  System.getProperty( "user.name", "null" ) );
410         // see com.lowagie.text.Document#addCreationDate()
411         SimpleDateFormat sdf = new SimpleDateFormat( "EEE MMM dd HH:mm:ss zzz yyyy" );
412         addTransformerParameter( transformer, "meta.creationdate", documentModel.getMeta().getCreationdate(),
413                                  sdf.format( new Date() ) );
414         addTransformerParameter( transformer, "meta.keywords", documentModel.getMeta().getAllKeyWords() );
415         addTransformerParameter( transformer, "meta.pagesize", documentModel.getMeta().getPageSize(),
416                                  ITextUtil.getPageSize( ITextUtil.getDefaultPageSize() ) );
417         addTransformerParameter( transformer, "meta.producer", documentModel.getMeta().getGenerator(),
418                                  "Apache Doxia iText" );
419         addTransformerParameter( transformer, "meta.subject", documentModel.getMeta().getSubject(),
420                                  ( documentModel.getMeta().getTitle() != null ? documentModel.getMeta().getTitle()
421                                                  : "" ) );
422         addTransformerParameter( transformer, "meta.title", documentModel.getMeta().getTitle() );
423         if ( hasNullMeta )
424         {
425             documentModel.setMeta( null );
426         }
427 
428         // cover parameter
429         boolean hasNullCover = false;
430         if ( documentModel.getCover() == null )
431         {
432             hasNullCover = true;
433             documentModel.setCover( new DocumentCover() );
434         }
435         addTransformerParameter( transformer, "cover.author", documentModel.getCover().getAllAuthorNames(),
436                                  System.getProperty( "user.name", "null" ) );
437         String companyLogo = getLogoURL( documentModel.getCover().getCompanyLogo(), iTextFile.getParentFile() );
438         addTransformerParameter( transformer, "cover.companyLogo", companyLogo );
439         addTransformerParameter( transformer, "cover.companyName", documentModel.getCover().getCompanyName() );
440         if ( documentModel.getCover().getCoverdate() == null )
441         {
442             documentModel.getCover().setCoverDate( new Date() );
443             addTransformerParameter( transformer, "cover.date", documentModel.getCover().getCoverdate() );
444             documentModel.getCover().setCoverDate( null );
445         }
446         else
447         {
448             addTransformerParameter( transformer, "cover.date", documentModel.getCover().getCoverdate() );
449         }
450         addTransformerParameter( transformer, "cover.subtitle", documentModel.getCover().getCoverSubTitle() );
451         addTransformerParameter( transformer, "cover.title", documentModel.getCover().getCoverTitle() );
452         addTransformerParameter( transformer, "cover.type", documentModel.getCover().getCoverType() );
453         addTransformerParameter( transformer, "cover.version", documentModel.getCover().getCoverVersion() );
454         String projectLogo = getLogoURL( documentModel.getCover().getProjectLogo(), iTextFile.getParentFile() );
455         addTransformerParameter( transformer, "cover.projectLogo", projectLogo );
456         addTransformerParameter( transformer, "cover.projectName", documentModel.getCover().getProjectName() );
457         if ( hasNullCover )
458         {
459             documentModel.setCover( null );
460         }
461     }
462 
463     /**
464      * @param transformer not null
465      * @param name not null
466      * @param value could be empty
467      * @param defaultValue could be empty
468      * @since 1.1.1
469      */
470     private void addTransformerParameter( Transformer transformer, String name, String value, String defaultValue )
471     {
472         if ( StringUtils.isEmpty( value ) )
473         {
474             addTransformerParameter( transformer, name, defaultValue );
475         }
476         else
477         {
478             addTransformerParameter( transformer, name, value );
479         }
480     }
481 
482     /**
483      * @param transformer not null
484      * @param name not null
485      * @param value could be empty
486      * @since 1.1.1
487      */
488     private void addTransformerParameter( Transformer transformer, String name, String value )
489     {
490         if ( StringUtils.isEmpty( value ) )
491         {
492             return;
493         }
494 
495         transformer.setParameter( name, value );
496     }
497 
498     /**
499      * Transform a document to an iTextFile.
500      *
501      * @param documentModel the DocumentModel to take the parameters from, could be null.
502      * @param document the Document to transform.
503      * @param iTextFile the resulting iText xml file.
504      * @param generateTOC not null, possible values are: 'none', 'start' and 'end'.
505      * @throws DocumentRendererException in case of a transformation error.
506      */
507     private void transform( DocumentModel documentModel, Document document, File iTextFile, String generateTOC )
508         throws DocumentRendererException
509     {
510         Transformer transformer = initTransformer();
511 
512         addTransformerParameters( transformer, documentModel, iTextFile, generateTOC );
513 
514         // need a writer for StreamResult to prevent FileNotFoundException when iTextFile contains spaces
515         Writer writer = null;
516         try
517         {
518             writer = WriterFactory.newXmlWriter( iTextFile );
519             transformer.transform( new DOMSource( document ), new StreamResult( writer ) );
520         }
521         catch ( TransformerException e )
522         {
523             throw new DocumentRendererException(
524                                                  "Error transforming Document " + document + ": " + e.getMessage(),
525                                                  e );
526         }
527         catch ( IOException e )
528         {
529             throw new DocumentRendererException(
530                                                  "Error transforming Document " + document + ": " + e.getMessage(),
531                                                  e );
532         }
533         finally
534         {
535             IOUtil.close( writer );
536         }
537     }
538 
539     /**
540      * @param filesToProcess not null
541      * @param outputDirectory not null
542      * @return a list of all parsed files.
543      * @throws DocumentRendererException if any
544      * @throws IOException if any
545      * @since 1.1.1
546      */
547     private List<File> parseAllFiles( Map<String, ParserModule> filesToProcess, File outputDirectory,
548                                       DocumentRendererContext context )
549         throws DocumentRendererException, IOException
550     {
551         List<File> iTextFiles = new LinkedList<File>();
552         for ( Map.Entry<String, ParserModule> entry : filesToProcess.entrySet() )
553         {
554             String key = entry.getKey();
555             ParserModule module = entry.getValue();
556             File fullDoc = new File( getBaseDir(), module.getSourceDirectory() + File.separator + key );
557 
558             String outputITextName = key.substring( 0, key.lastIndexOf( '.' ) + 1 ) + "xml";
559             File outputITextFileTmp = new File( outputDirectory, outputITextName );
560             outputITextFileTmp.deleteOnExit();
561             if ( !outputITextFileTmp.getParentFile().exists() )
562             {
563                 outputITextFileTmp.getParentFile().mkdirs();
564             }
565 
566             iTextFiles.add( outputITextFileTmp );
567             parse( fullDoc, module, outputITextFileTmp, context );
568         }
569 
570         return iTextFiles;
571     }
572 
573     /**
574      * @param filesToProcess not null
575      * @param outputDirectory not null
576      * @return a list of all parsed files.
577      * @throws DocumentRendererException if any
578      * @throws IOException if any
579      * @since 1.1.1
580      */
581     private List<File> parseTOCFiles( File outputDirectory, DocumentModel documentModel,
582                                       DocumentRendererContext context )
583         throws DocumentRendererException, IOException
584     {
585         List<File> iTextFiles = new LinkedList<File>();
586         for ( Iterator<DocumentTOCItem> it = documentModel.getToc().getItems().iterator(); it.hasNext(); )
587         {
588             DocumentTOCItem tocItem = it.next();
589 
590             if ( tocItem.getRef() == null )
591             {
592                 getLogger().debug(
593                                    "No ref defined for the tocItem '" + tocItem.getName()
594                                        + "' in the document descriptor. IGNORING" );
595                 continue;
596             }
597 
598             String href = StringUtils.replace( tocItem.getRef(), "\\", "/" );
599             if ( href.lastIndexOf( '.' ) != -1 )
600             {
601                 href = href.substring( 0, href.lastIndexOf( '.' ) );
602             }
603 
604             Collection<ParserModule> modules = parserModuleManager.getParserModules();
605             for ( ParserModule module : modules )
606             {
607                 File moduleBasedir = new File( getBaseDir(), module.getSourceDirectory() );
608 
609                 if ( moduleBasedir.exists() )
610                 {
611                     for ( String extension : module.getExtensions() )
612                     {
613                         String doc = href + "." + extension;
614                         File source = new File( moduleBasedir, doc );
615     
616                         // Velocity file?
617                         if ( !source.exists() )
618                         {
619                             if ( href.indexOf( "." + extension ) != -1 )
620                             {
621                                 doc = href + ".vm";
622                             }
623                             else
624                             {
625                                 doc = href + "." + extension + ".vm";
626                             }
627                             source = new File( moduleBasedir, doc );
628                         }
629     
630                         if ( source.exists() )
631                         {
632                             String outputITextName = doc.substring( 0, doc.lastIndexOf( '.' ) + 1 ) + "xml";
633                             File outputITextFileTmp = new File( outputDirectory, outputITextName );
634                             outputITextFileTmp.deleteOnExit();
635                             if ( !outputITextFileTmp.getParentFile().exists() )
636                             {
637                                 outputITextFileTmp.getParentFile().mkdirs();
638                             }
639     
640                             iTextFiles.add( outputITextFileTmp );
641                             parse( source, module, outputITextFileTmp, context );
642                         }
643                     }
644                 }
645             }
646         }
647 
648         return iTextFiles;
649     }
650 
651     /**
652      * @param logo
653      * @param parentFile
654      * @return the logo url or null if unable to create it.
655      * @since 1.1.1
656      */
657     private String getLogoURL( String logo, File parentFile )
658     {
659         if ( logo == null )
660         {
661             return null;
662         }
663 
664         try
665         {
666             return new URL( logo ).toString();
667         }
668         catch ( MalformedURLException e )
669         {
670             try
671             {
672                 File f = new File( parentFile, logo );
673                 if ( !f.exists() )
674                 {
675                     getLogger().warn( "The logo " + f.getAbsolutePath() + " doesnt exist. IGNORING" );
676                 }
677                 else
678                 {
679                     return f.toURI().toURL().toString();
680                 }
681             }
682             catch ( MalformedURLException e1 )
683             {
684                 getLogger().debug( "Failed to convert to URL: " + logo, e1 );
685             }
686         }
687 
688         return null;
689     }
690 }