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