View Javadoc

1   package org.apache.maven.doxia.siterenderer;
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.FileOutputStream;
25  import java.io.FileWriter;
26  import java.io.IOException;
27  import java.io.InputStream;
28  import java.io.InputStreamReader;
29  import java.io.LineNumberReader;
30  import java.io.OutputStreamWriter;
31  import java.io.Reader;
32  import java.io.StringReader;
33  import java.io.StringWriter;
34  import java.io.UnsupportedEncodingException;
35  import java.io.Writer;
36  
37  import java.net.MalformedURLException;
38  import java.net.URL;
39  import java.net.URLClassLoader;
40  
41  import java.text.DateFormat;
42  
43  import java.util.ArrayList;
44  import java.util.Arrays;
45  import java.util.Collection;
46  import java.util.Date;
47  import java.util.Enumeration;
48  import java.util.Iterator;
49  import java.util.LinkedHashMap;
50  import java.util.List;
51  import java.util.Locale;
52  import java.util.Map;
53  import java.util.zip.ZipEntry;
54  import java.util.zip.ZipFile;
55  
56  import org.apache.maven.doxia.Doxia;
57  import org.apache.maven.doxia.module.xhtml.decoration.render.RenderingContext;
58  import org.apache.maven.doxia.parser.ParseException;
59  import org.apache.maven.doxia.parser.Parser;
60  import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
61  import org.apache.maven.doxia.site.decoration.DecorationModel;
62  import org.apache.maven.doxia.module.site.SiteModule;
63  import org.apache.maven.doxia.module.site.manager.SiteModuleManager;
64  import org.apache.maven.doxia.module.site.manager.SiteModuleNotFoundException;
65  import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
66  
67  import org.apache.velocity.Template;
68  import org.apache.velocity.VelocityContext;
69  import org.apache.velocity.context.Context;
70  
71  import org.codehaus.plexus.i18n.I18N;
72  import org.codehaus.plexus.logging.AbstractLogEnabled;
73  import org.codehaus.plexus.util.DirectoryScanner;
74  import org.codehaus.plexus.util.FileUtils;
75  import org.codehaus.plexus.util.IOUtil;
76  import org.codehaus.plexus.util.Os;
77  import org.codehaus.plexus.util.PathTool;
78  import org.codehaus.plexus.util.ReaderFactory;
79  import org.codehaus.plexus.util.StringUtils;
80  import org.codehaus.plexus.velocity.SiteResourceLoader;
81  import org.codehaus.plexus.velocity.VelocityComponent;
82  
83  
84  /**
85   * @author <a href="mailto:evenisse@codehaus.org">Emmanuel Venisse</a>
86   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
87   * @version $Id: DefaultSiteRenderer.java 746600 2009-02-21 23:07:32Z brianf $
88   * @since 1.0
89   * @plexus.component role-hint="default"
90   */
91  public class DefaultSiteRenderer
92      extends AbstractLogEnabled
93      implements Renderer
94  {
95      // ----------------------------------------------------------------------
96      // Requirements
97      // ----------------------------------------------------------------------
98  
99      /**
100      * @plexus.requirement
101      */
102     private VelocityComponent velocity;
103 
104     /**
105      * @plexus.requirement
106      */
107     private SiteModuleManager siteModuleManager;
108 
109     /**
110      * @plexus.requirement
111      */
112     private Doxia doxia;
113 
114     /**
115      * @plexus.requirement
116      */
117     private I18N i18n;
118 
119     private static final String RESOURCE_DIR = "org/apache/maven/doxia/siterenderer/resources";
120 
121     private static final String DEFAULT_TEMPLATE = RESOURCE_DIR + "/default-site.vm";
122 
123     private static final String SKIN_TEMPLATE_LOCATION = "META-INF/maven/site.vm";
124 
125     // ----------------------------------------------------------------------
126     // Renderer implementation
127     // ----------------------------------------------------------------------
128 
129     /** {@inheritDoc} */
130     public void render( Collection documents,
131                         SiteRenderingContext siteRenderingContext,
132                         File outputDirectory )
133             throws RendererException, IOException
134     {
135         renderModule( documents, siteRenderingContext, outputDirectory );
136 
137         for ( Iterator i = siteRenderingContext.getSiteDirectories().iterator(); i.hasNext(); )
138         {
139             File siteDirectory = (File) i.next();
140             copyResources( siteRenderingContext, new File( siteDirectory, "resources" ), outputDirectory );
141         }
142     }
143 
144     /** {@inheritDoc} */
145     public Map locateDocumentFiles( SiteRenderingContext siteRenderingContext )
146             throws IOException, RendererException
147     {
148         Map files = new LinkedHashMap();
149         Map moduleExcludes = siteRenderingContext.getModuleExcludes();
150 
151         for ( Iterator i = siteRenderingContext.getSiteDirectories().iterator(); i.hasNext(); )
152         {
153             File siteDirectory = (File) i.next();
154             if ( siteDirectory.exists() )
155             {
156                 for ( Iterator j = siteModuleManager.getSiteModules().iterator(); j.hasNext(); )
157                 {
158                     SiteModule module = (SiteModule) j.next();
159 
160                     File moduleBasedir = new File( siteDirectory, module.getSourceDirectory() );
161 
162                     if ( moduleExcludes != null && moduleExcludes.containsKey( module.getParserId() ) )
163                     {
164                         addModuleFiles( moduleBasedir, module, (String) moduleExcludes.get( module.getParserId() ),
165                                 files );
166                     }
167                     else
168                     {
169                         addModuleFiles( moduleBasedir, module, null, files );
170                     }
171                 }
172             }
173         }
174 
175         for ( Iterator i = siteRenderingContext.getModules().iterator(); i.hasNext(); )
176         {
177             ModuleReference module = (ModuleReference) i.next();
178 
179             try
180             {
181                 if ( moduleExcludes != null && moduleExcludes.containsKey( module.getParserId() ) )
182                 {
183                     addModuleFiles( module.getBasedir(), siteModuleManager.getSiteModule( module.getParserId() ),
184                             (String) moduleExcludes.get( module.getParserId() ), files );
185                 }
186                 else
187                 {
188                     addModuleFiles( module.getBasedir(), siteModuleManager.getSiteModule( module.getParserId() ), null,
189                             files );
190                 }
191             }
192             catch ( SiteModuleNotFoundException e )
193             {
194                 throw new RendererException( "Unable to find module: " + e.getMessage(), e );
195             }
196         }
197         return files;
198     }
199 
200     private void addModuleFiles( File moduleBasedir,
201                                  SiteModule module,
202                                  String excludes,
203                                  Map files )
204             throws IOException, RendererException
205     {
206         if ( moduleBasedir.exists() )
207         {
208             List docs = new ArrayList();
209 
210             docs.addAll( FileUtils.getFileNames( moduleBasedir, "**/*." + module.getExtension(), excludes, false ) );
211 
212             // download.apt.vm
213             docs.addAll( FileUtils.getFileNames( moduleBasedir, "**/*." + module.getExtension() + ".vm", excludes, false ) );
214 
215             for ( Iterator k = docs.iterator(); k.hasNext(); )
216             {
217                 String doc = (String) k.next();
218 
219                 RenderingContext context = new RenderingContext( moduleBasedir, doc, module.getParserId(), module.getExtension() );
220 
221                 // DOXIA-111: we need a general filter here that knows how to alter the context
222                 if ( doc.endsWith( ".vm" ) )
223                 {
224                     context.setAttribute( "velocity", "true" );
225                 }
226 
227                 String key = context.getOutputName();
228 
229                 if ( files.containsKey( key ) )
230                 {
231                     DocumentRenderer renderer = (DocumentRenderer) files.get( key );
232 
233                     RenderingContext originalContext = renderer.getRenderingContext();
234 
235                     File originalDoc = new File( originalContext.getBasedir(), originalContext.getInputName() );
236 
237                     throw new RendererException( "Files '" + doc + "' clashes with existing '" + originalDoc + "'." );
238                 }
239                 // -----------------------------------------------------------------------
240                 // Handle key without case differences
241                 // -----------------------------------------------------------------------
242                 for ( Iterator iter = files.entrySet().iterator(); iter.hasNext(); )
243                 {
244                     Map.Entry entry = (Map.Entry) iter.next();
245                     if ( entry.getKey().toString().toLowerCase().equals( key.toLowerCase() ) )
246                     {
247                         DocumentRenderer renderer = (DocumentRenderer) files.get( entry.getKey() );
248 
249                         RenderingContext originalContext = renderer.getRenderingContext();
250 
251                         File originalDoc = new File( originalContext.getBasedir(), originalContext.getInputName() );
252 
253                         if ( Os.isFamily( "windows" ) )
254                         {
255                             throw new RendererException(
256                                     "Files '" + doc + "' clashes with existing '" + originalDoc + "'." );
257                         }
258 
259                         getLogger().warn( "Files '" + doc + "' could clashes with existing '" + originalDoc + "'." );
260                     }
261                 }
262 
263                 files.put( key, new DoxiaDocumentRenderer( context ) );
264             }
265         }
266     }
267 
268     private void renderModule( Collection docs,
269                                SiteRenderingContext siteRenderingContext,
270                                File outputDirectory )
271             throws IOException, RendererException
272     {
273         for ( Iterator i = docs.iterator(); i.hasNext(); )
274         {
275             DocumentRenderer docRenderer = (DocumentRenderer) i.next();
276 
277             RenderingContext renderingContext = docRenderer.getRenderingContext();
278 
279             File outputFile = new File( outputDirectory, docRenderer.getOutputName() );
280 
281             File inputFile = new File( renderingContext.getBasedir(), renderingContext.getInputName() );
282 
283             boolean modified = false;
284             if ( !outputFile.exists() || inputFile.lastModified() > outputFile.lastModified() )
285             {
286                 modified = true;
287             }
288 
289             if ( modified || docRenderer.isOverwrite() )
290             {
291                 if ( !outputFile.getParentFile().exists() )
292                 {
293                     outputFile.getParentFile().mkdirs();
294                 }
295 
296                 getLogger().debug( "Generating " + outputFile );
297 
298                 OutputStreamWriter writer = new OutputStreamWriter( new FileOutputStream( outputFile ),
299                         siteRenderingContext.getOutputEncoding() );
300 
301                 try
302                 {
303                     docRenderer.renderDocument( writer, this, siteRenderingContext );
304                 }
305                 finally
306                 {
307                     IOUtil.close( writer );
308                 }
309             }
310             else
311             {
312                 getLogger().debug( inputFile + " unchanged, not regenerating..." );
313             }
314         }
315     }
316 
317     /** {@inheritDoc} */
318     public void renderDocument( Writer writer,
319                                 RenderingContext renderingContext,
320                                 SiteRenderingContext context )
321             throws RendererException, FileNotFoundException, UnsupportedEncodingException
322     {
323         SiteRendererSink sink = new SiteRendererSink( renderingContext );
324 
325         File doc = new File( renderingContext.getBasedir(), renderingContext.getInputName() );
326 
327         try
328         {
329             Reader reader = null;
330             Parser parser = doxia.getParser( renderingContext.getParserId() );
331 
332             // DOXIA-111: the filter used here must be checked generally.
333             if ( renderingContext.getAttribute( "velocity" ) != null )
334             {
335                 String resource = doc.getAbsolutePath();
336 
337                 try
338                 {
339                     SiteResourceLoader.setResource( resource );
340 
341                     Context vc = createContext( sink, context );
342 
343                     StringWriter sw = new StringWriter();
344 
345                     velocity.getEngine().mergeTemplate( resource, context.getInputEncoding(), vc, sw );
346 
347                     reader = new StringReader( sw.toString() );
348                 }
349                 catch ( Exception e )
350                 {
351                     if ( getLogger().isDebugEnabled() )
352                     {
353                         getLogger().error( "Error parsing " + resource + " as a velocity template, using as text.", e );
354                     }
355                     else
356                     {
357                         getLogger().error( "Error parsing " + resource + " as a velocity template, using as text." );
358                     }
359                 }
360             }
361             else
362             {
363                 switch ( parser.getType() )
364                 {
365                     case Parser.XML_TYPE:
366                         reader = ReaderFactory.newXmlReader( doc );
367                         break;
368 
369                     case Parser.TXT_TYPE:
370                     case Parser.UNKNOWN_TYPE:
371                     default:
372                         reader = ReaderFactory.newReader( doc, context.getInputEncoding() );
373                 }
374             }
375 
376             doxia.parse( reader, renderingContext.getParserId(), sink );
377 
378             generateDocument( writer, sink, context );
379         }
380         catch ( ParserNotFoundException e )
381         {
382             throw new RendererException( "Error getting a parser for " + doc + ": " + e.getMessage() );
383         }
384         catch ( ParseException e )
385         {
386             getLogger().error( "Error parsing " + doc + ": line [" + e.getLineNumber() + "] " + e.getMessage(), e );
387         }
388         catch ( IOException e )
389         {
390             getLogger().error( "Error parsing " + doc + " to detect encoding", e );
391         }
392         finally
393         {
394             sink.flush();
395 
396             sink.close();
397         }
398     }
399 
400     private Context createContext( SiteRendererSink sink,
401                                    SiteRenderingContext siteRenderingContext )
402     {
403         VelocityContext context = new VelocityContext();
404 
405         // ----------------------------------------------------------------------
406         // Data objects
407         // ----------------------------------------------------------------------
408 
409         RenderingContext renderingContext = sink.getRenderingContext();
410         context.put( "relativePath", renderingContext.getRelativePath() );
411 
412         // Add infos from document
413         context.put( "authors", sink.getAuthors() );
414 
415         String title = "";
416         if ( siteRenderingContext.getDecoration().getName() != null )
417         {
418             title = siteRenderingContext.getDecoration().getName();
419         }
420         else if ( siteRenderingContext.getDefaultWindowTitle() != null )
421         {
422             title = siteRenderingContext.getDefaultWindowTitle();
423         }
424 
425         if ( title.length() > 0 )
426         {
427             title += " - ";
428         }
429         title += sink.getTitle();
430 
431         context.put( "title", title );
432 
433         context.put( "bodyContent", sink.getBody() );
434 
435         context.put( "decoration", siteRenderingContext.getDecoration() );
436 
437         context.put( "currentDate", new Date() );
438 
439         Locale locale = siteRenderingContext.getLocale();
440         context.put( "dateFormat", DateFormat.getDateInstance( DateFormat.DEFAULT, locale ) );
441 
442         String currentFileName = renderingContext.getOutputName().replace( '\\', '/' );
443         context.put( "currentFileName", currentFileName );
444 
445         context.put( "alignedFileName", PathTool.calculateLink( currentFileName, renderingContext.getRelativePath() ) );
446 
447         context.put( "locale", locale );
448 
449         // Add user properties
450         Map templateProperties = siteRenderingContext.getTemplateProperties();
451 
452         if ( templateProperties != null )
453         {
454             for ( Iterator i = templateProperties.keySet().iterator(); i.hasNext(); )
455             {
456                 String key = (String) i.next();
457 
458                 context.put( key, templateProperties.get( key ) );
459             }
460         }
461 
462         // ----------------------------------------------------------------------
463         // Tools
464         // ----------------------------------------------------------------------
465 
466         context.put( "PathTool", new PathTool() );
467 
468         context.put( "FileUtils", new FileUtils() );
469 
470         context.put( "StringUtils", new StringUtils() );
471 
472         context.put( "i18n", i18n );
473 
474         return context;
475     }
476 
477     /** {@inheritDoc} */
478     public void generateDocument( Writer writer,
479                                   SiteRendererSink sink,
480                                   SiteRenderingContext siteRenderingContext )
481             throws RendererException
482     {
483         Context context = createContext( sink, siteRenderingContext );
484 
485         writeTemplate( writer, context, siteRenderingContext );
486     }
487 
488     private void writeTemplate( Writer writer,
489                                 Context context,
490                                 SiteRenderingContext siteContext )
491             throws RendererException
492     {
493         ClassLoader old = null;
494 
495         if ( siteContext.getTemplateClassLoader() != null )
496         {
497             // -------------------------------------------------------------------------
498             // If no template classloader was set we'll just use the context classloader
499             // -------------------------------------------------------------------------
500 
501             old = Thread.currentThread().getContextClassLoader();
502 
503             Thread.currentThread().setContextClassLoader( siteContext.getTemplateClassLoader() );
504         }
505 
506         try
507         {
508             processTemplate( siteContext.getTemplateName(), context, writer );
509         }
510         finally
511         {
512             IOUtil.close( writer );
513 
514             if ( old != null )
515             {
516                 Thread.currentThread().setContextClassLoader( old );
517             }
518         }
519     }
520 
521     /**
522      * @noinspection OverlyBroadCatchBlock,UnusedCatchParameter
523      */
524     private void processTemplate( String templateName,
525                                   Context context,
526                                   Writer writer )
527             throws RendererException
528     {
529         Template template;
530 
531         try
532         {
533             template = velocity.getEngine().getTemplate( templateName );
534         }
535         catch ( Exception e )
536         {
537             throw new RendererException( "Could not find the template '" + templateName );
538         }
539 
540         try
541         {
542             template.merge( context, writer );
543         }
544         catch ( Exception e )
545         {
546             throw new RendererException( "Error while generating code.", e );
547         }
548     }
549 
550     /** {@inheritDoc} */
551     public SiteRenderingContext createContextForSkin( File skinFile,
552                                                       Map attributes,
553                                                       DecorationModel decoration,
554                                                       String defaultWindowTitle,
555                                                       Locale locale )
556             throws IOException
557     {
558         SiteRenderingContext context = new SiteRenderingContext();
559 
560         // TODO: plexus-archiver, if it could do the excludes
561         ZipFile zipFile = new ZipFile( skinFile );
562         try
563         {
564             if ( zipFile.getEntry( SKIN_TEMPLATE_LOCATION ) != null )
565             {
566                 context.setTemplateName( SKIN_TEMPLATE_LOCATION );
567                 context.setTemplateClassLoader( new URLClassLoader( new URL[]{skinFile.toURL()} ) );
568             }
569             else
570             {
571                 context.setTemplateName( DEFAULT_TEMPLATE );
572                 context.setTemplateClassLoader( getClass().getClassLoader() );
573                 context.setUsingDefaultTemplate( true );
574             }
575         }
576         finally
577         {
578             closeZipFile( zipFile );
579         }
580 
581         context.setTemplateProperties( attributes );
582         context.setLocale( locale );
583         context.setDecoration( decoration );
584         context.setDefaultWindowTitle( defaultWindowTitle );
585         context.setSkinJarFile( skinFile );
586 
587         return context;
588     }
589 
590     /** {@inheritDoc} */
591     public SiteRenderingContext createContextForTemplate( File templateFile,
592                                                           File skinFile,
593                                                           Map attributes,
594                                                           DecorationModel decoration,
595                                                           String defaultWindowTitle,
596                                                           Locale locale )
597             throws MalformedURLException
598     {
599         SiteRenderingContext context = new SiteRenderingContext();
600 
601         context.setTemplateName( templateFile.getName() );
602         context.setTemplateClassLoader( new URLClassLoader( new URL[]{templateFile.getParentFile().toURI().toURL()} ) );
603 
604         context.setTemplateProperties( attributes );
605         context.setLocale( locale );
606         context.setDecoration( decoration );
607         context.setDefaultWindowTitle( defaultWindowTitle );
608         context.setSkinJarFile( skinFile );
609 
610         return context;
611     }
612 
613     private void closeZipFile( ZipFile zipFile )
614     {
615         // TODO: move to plexus utils
616         try
617         {
618             zipFile.close();
619         }
620         catch ( IOException e )
621         {
622             // ignore
623         }
624     }
625 
626     /** {@inheritDoc} */
627     public void copyResources( SiteRenderingContext siteRenderingContext,
628                                File resourcesDirectory,
629                                File outputDirectory  )
630             throws IOException
631     {
632         if ( siteRenderingContext.getSkinJarFile() != null )
633         {
634             // TODO: plexus-archiver, if it could do the excludes
635             ZipFile file = new ZipFile( siteRenderingContext.getSkinJarFile() );
636             try
637             {
638                 for ( Enumeration e = file.entries(); e.hasMoreElements(); )
639                 {
640                     ZipEntry entry = (ZipEntry) e.nextElement();
641 
642                     if ( !entry.getName().startsWith( "META-INF/" ) )
643                     {
644                         File destFile = new File( outputDirectory, entry.getName() );
645                         if ( !entry.isDirectory() )
646                         {
647                             destFile.getParentFile().mkdirs();
648 
649                             copyFileFromZip( file, entry, destFile );
650                         }
651                         else
652                         {
653                             destFile.mkdirs();
654                         }
655                     }
656                 }
657             }
658             finally
659             {
660                 file.close();
661             }
662         }
663 
664         if ( siteRenderingContext.isUsingDefaultTemplate() )
665         {
666             InputStream resourceList = getClass().getClassLoader()
667                     .getResourceAsStream( RESOURCE_DIR + "/resources.txt" );
668 
669             if ( resourceList != null )
670             {
671                 LineNumberReader reader = new LineNumberReader( new InputStreamReader( resourceList ) );
672 
673                 String line = reader.readLine();
674 
675                 while ( line != null )
676                 {
677                     InputStream is = getClass().getClassLoader().getResourceAsStream( RESOURCE_DIR + "/" + line );
678 
679                     if ( is == null )
680                     {
681                         throw new IOException( "The resource " + line + " doesn't exist." );
682                     }
683 
684                     File outputFile = new File( outputDirectory, line );
685 
686                     if ( !outputFile.getParentFile().exists() )
687                     {
688                         outputFile.getParentFile().mkdirs();
689                     }
690 
691                     FileOutputStream w = new FileOutputStream( outputFile );
692 
693                     IOUtil.copy( is, w );
694 
695                     IOUtil.close( is );
696 
697                     IOUtil.close( w );
698 
699                     line = reader.readLine();
700                 }
701             }
702         }
703 
704         // Copy extra site resources
705         if ( resourcesDirectory != null && resourcesDirectory.exists() )
706         {
707             copyDirectory( resourcesDirectory, outputDirectory );
708         }
709 
710         // Check for the existence of /css/site.css
711         File siteCssFile = new File( outputDirectory, "/css/site.css" );
712         if ( !siteCssFile.exists() )
713         {
714             // Create the subdirectory css if it doesn't exist, DOXIA-151
715             File cssDirectory = new File( outputDirectory, "/css/" );
716             boolean created = cssDirectory.mkdirs();
717             if ( created && getLogger().isDebugEnabled() )
718             {
719                 getLogger().debug(
720                     "The directory '" + cssDirectory.getAbsolutePath() + "' did not exist. It was created." );
721             }
722 
723             // If the file is not there - create an empty file, DOXIA-86
724             if ( getLogger().isDebugEnabled() )
725             {
726                 getLogger().debug(
727                     "The file '" + siteCssFile.getAbsolutePath() + "' does not exists. Creating an empty file." );
728             }
729             FileWriter w = new FileWriter( siteCssFile );
730             
731             //put something in the file so it's not completely empty - DOXIA-290
732             w.write( "/* You can override this file with your own styles */" );
733             IOUtil.close( w );
734         }
735     }
736 
737     private void copyFileFromZip( ZipFile file,
738                                   ZipEntry entry,
739                                   File destFile )
740             throws IOException
741     {
742         FileOutputStream fos = new FileOutputStream( destFile );
743 
744         try
745         {
746             IOUtil.copy( file.getInputStream( entry ), fos );
747         }
748         finally
749         {
750             IOUtil.close( fos );
751         }
752     }
753 
754     /**
755      * Copy the directory
756      *
757      * @param source      source file to be copied
758      * @param destination destination file
759      * @throws java.io.IOException if any
760      */
761     protected void copyDirectory( File source,
762                                   File destination )
763             throws IOException
764     {
765         if ( source.exists() )
766         {
767             DirectoryScanner scanner = new DirectoryScanner();
768 
769             String[] includedResources = {"**/**"};
770 
771             scanner.setIncludes( includedResources );
772 
773             scanner.addDefaultExcludes();
774 
775             scanner.setBasedir( source );
776 
777             scanner.scan();
778 
779             List includedFiles = Arrays.asList( scanner.getIncludedFiles() );
780 
781             for ( Iterator j = includedFiles.iterator(); j.hasNext(); )
782             {
783                 String name = (String) j.next();
784 
785                 File sourceFile = new File( source, name );
786 
787                 File destinationFile = new File( destination, name );
788 
789                 FileUtils.copyFile( sourceFile, destinationFile );
790             }
791         }
792     }
793 
794 }