1 package org.apache.maven.doxia.siterenderer;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.LineNumberReader;
29 import java.io.OutputStream;
30 import java.io.Reader;
31 import java.io.StringReader;
32 import java.io.StringWriter;
33 import java.io.UnsupportedEncodingException;
34 import java.io.Writer;
35
36 import java.net.MalformedURLException;
37 import java.net.URL;
38 import java.net.URLClassLoader;
39
40 import java.text.DateFormat;
41 import java.text.SimpleDateFormat;
42
43 import java.util.Arrays;
44 import java.util.Collection;
45 import java.util.Collections;
46 import java.util.Date;
47 import java.util.Enumeration;
48 import java.util.Iterator;
49 import java.util.LinkedHashMap;
50 import java.util.LinkedList;
51 import java.util.List;
52 import java.util.Locale;
53 import java.util.Map;
54 import java.util.Properties;
55 import java.util.zip.ZipEntry;
56 import java.util.zip.ZipException;
57 import java.util.zip.ZipFile;
58
59 import org.apache.maven.doxia.Doxia;
60 import org.apache.maven.doxia.logging.PlexusLoggerWrapper;
61 import org.apache.maven.doxia.sink.render.RenderingContext;
62 import org.apache.maven.doxia.parser.ParseException;
63 import org.apache.maven.doxia.parser.Parser;
64 import org.apache.maven.doxia.parser.manager.ParserNotFoundException;
65 import org.apache.maven.doxia.site.decoration.DecorationModel;
66 import org.apache.maven.doxia.module.site.SiteModule;
67 import org.apache.maven.doxia.module.site.manager.SiteModuleManager;
68 import org.apache.maven.doxia.module.site.manager.SiteModuleNotFoundException;
69 import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink;
70 import org.apache.maven.doxia.util.XmlValidator;
71
72 import org.apache.velocity.Template;
73 import org.apache.velocity.context.Context;
74 import org.apache.velocity.tools.ToolManager;
75
76 import org.codehaus.plexus.i18n.I18N;
77 import org.codehaus.plexus.logging.AbstractLogEnabled;
78 import org.codehaus.plexus.util.DirectoryScanner;
79 import org.codehaus.plexus.util.FileUtils;
80 import org.codehaus.plexus.util.IOUtil;
81 import org.codehaus.plexus.util.Os;
82 import org.codehaus.plexus.util.PathTool;
83 import org.codehaus.plexus.util.ReaderFactory;
84 import org.codehaus.plexus.util.StringUtils;
85 import org.codehaus.plexus.util.WriterFactory;
86 import org.codehaus.plexus.velocity.SiteResourceLoader;
87 import org.codehaus.plexus.velocity.VelocityComponent;
88
89
90
91
92
93
94
95
96
97
98 public class DefaultSiteRenderer
99 extends AbstractLogEnabled
100 implements Renderer
101 {
102
103
104
105
106
107 private VelocityComponent velocity;
108
109
110
111
112 private SiteModuleManager siteModuleManager;
113
114
115 private Doxia doxia;
116
117
118 private I18N i18n;
119
120 private static final String RESOURCE_DIR = "org/apache/maven/doxia/siterenderer/resources";
121
122 private static final String DEFAULT_TEMPLATE = RESOURCE_DIR + "/default-site.vm";
123
124 private static final String SKIN_TEMPLATE_LOCATION = "META-INF/maven/site.vm";
125
126
127
128
129
130
131 public void render( Collection<DocumentRenderer> documents, SiteRenderingContext siteRenderingContext,
132 File outputDirectory )
133 throws RendererException, IOException
134 {
135 renderModule( documents, siteRenderingContext, outputDirectory );
136
137 for ( File siteDirectory : siteRenderingContext.getSiteDirectories() )
138 {
139 copyResources( siteRenderingContext, new File( siteDirectory, "resources" ), outputDirectory );
140 }
141 }
142
143
144 public Map<String, DocumentRenderer> locateDocumentFiles( SiteRenderingContext siteRenderingContext )
145 throws IOException, RendererException
146 {
147 Map<String, DocumentRenderer> files = new LinkedHashMap<String, DocumentRenderer>();
148 Map<String, String> moduleExcludes = siteRenderingContext.getModuleExcludes();
149
150 for ( File siteDirectory : siteRenderingContext.getSiteDirectories() )
151 {
152 if ( siteDirectory.exists() )
153 {
154 Collection<SiteModule> modules = siteModuleManager.getSiteModules();
155 for ( SiteModule module : modules )
156 {
157 File moduleBasedir = new File( siteDirectory, module.getSourceDirectory() );
158
159 if ( moduleExcludes != null && moduleExcludes.containsKey( module.getParserId() ) )
160 {
161 addModuleFiles( moduleBasedir, module, moduleExcludes.get( module.getParserId() ),
162 files );
163 }
164 else
165 {
166 addModuleFiles( moduleBasedir, module, null, files );
167 }
168 }
169 }
170 }
171
172 for ( ModuleReference module : siteRenderingContext.getModules() )
173 {
174 try
175 {
176 if ( moduleExcludes != null && moduleExcludes.containsKey( module.getParserId() ) )
177 {
178 addModuleFiles( module.getBasedir(), siteModuleManager.getSiteModule( module.getParserId() ),
179 moduleExcludes.get( module.getParserId() ), files );
180 }
181 else
182 {
183 addModuleFiles( module.getBasedir(), siteModuleManager.getSiteModule( module.getParserId() ), null,
184 files );
185 }
186 }
187 catch ( SiteModuleNotFoundException e )
188 {
189 throw new RendererException( "Unable to find module: " + e.getMessage(), e );
190 }
191 }
192 return files;
193 }
194
195 private void addModuleFiles( File moduleBasedir, SiteModule module, String excludes,
196 Map<String, DocumentRenderer> files )
197 throws IOException, RendererException
198 {
199 if ( moduleBasedir.exists() )
200 {
201 @SuppressWarnings ( "unchecked" )
202 List<String> allFiles = FileUtils.getFileNames( moduleBasedir, "**/*.*", excludes, false );
203
204 String lowerCaseExtension = module.getExtension().toLowerCase( Locale.ENGLISH );
205 List<String> docs = new LinkedList<String>( allFiles );
206
207 for ( Iterator<String> it = docs.iterator(); it.hasNext(); )
208 {
209 String name = it.next().trim();
210
211 if ( !name.toLowerCase( Locale.ENGLISH ).endsWith( "." + lowerCaseExtension ) )
212 {
213 it.remove();
214 }
215 }
216
217 List<String> velocityFiles = new LinkedList<String>( allFiles );
218
219 for ( Iterator<String> it = velocityFiles.iterator(); it.hasNext(); )
220 {
221 String name = it.next().trim();
222
223 if ( !name.toLowerCase( Locale.ENGLISH ).endsWith( lowerCaseExtension + ".vm" ) )
224 {
225 it.remove();
226 }
227 }
228 docs.addAll( velocityFiles );
229
230 for ( String doc : docs )
231 {
232 String docc = doc.trim();
233
234 RenderingContext context =
235 new RenderingContext( moduleBasedir, docc, module.getParserId(), module.getExtension() );
236
237
238 if ( docc.toLowerCase( Locale.ENGLISH ).endsWith( ".vm" ) )
239 {
240 context.setAttribute( "velocity", "true" );
241 }
242
243 String key = context.getOutputName();
244 key = StringUtils.replace( key, "\\", "/" );
245
246 if ( files.containsKey( key ) )
247 {
248 DocumentRenderer renderer = files.get( key );
249
250 RenderingContext originalContext = renderer.getRenderingContext();
251
252 File originalDoc = new File( originalContext.getBasedir(), originalContext.getInputName() );
253
254 throw new RendererException( "Files '" + module.getSourceDirectory() + File.separator + docc
255 + "' clashes with existing '" + originalDoc + "'." );
256 }
257
258
259
260 for ( Map.Entry<String, DocumentRenderer> entry : files.entrySet() )
261 {
262 if ( entry.getKey().equalsIgnoreCase( key ) )
263 {
264 RenderingContext originalContext = entry.getValue().getRenderingContext();
265
266 File originalDoc = new File( originalContext.getBasedir(), originalContext.getInputName() );
267
268 if ( Os.isFamily( Os.FAMILY_WINDOWS ) )
269 {
270 throw new RendererException( "Files '" + module.getSourceDirectory() + File.separator
271 + docc + "' clashes with existing '" + originalDoc + "'." );
272 }
273
274 if ( getLogger().isWarnEnabled() )
275 {
276 getLogger().warn(
277 "Files '" + module.getSourceDirectory() + File.separator + docc
278 + "' could clashes with existing '" + originalDoc + "'." );
279 }
280 }
281 }
282
283 files.put( key, new DoxiaDocumentRenderer( context ) );
284 }
285 }
286 }
287
288 private void renderModule( Collection<DocumentRenderer> docs, SiteRenderingContext siteRenderingContext,
289 File outputDirectory )
290 throws IOException, RendererException
291 {
292 for ( DocumentRenderer docRenderer : docs )
293 {
294 RenderingContext renderingContext = docRenderer.getRenderingContext();
295
296 File outputFile = new File( outputDirectory, docRenderer.getOutputName() );
297
298 File inputFile = new File( renderingContext.getBasedir(), renderingContext.getInputName() );
299
300 boolean modified = !outputFile.exists() || ( inputFile.lastModified() > outputFile.lastModified() )
301 || ( siteRenderingContext.getDecoration().getLastModified() > outputFile.lastModified() );
302
303 if ( modified || docRenderer.isOverwrite() )
304 {
305 if ( !outputFile.getParentFile().exists() )
306 {
307 outputFile.getParentFile().mkdirs();
308 }
309
310 if ( getLogger().isDebugEnabled() )
311 {
312 getLogger().debug( "Generating " + outputFile );
313 }
314
315 Writer writer = null;
316 try
317 {
318 writer = WriterFactory.newWriter( outputFile, siteRenderingContext.getOutputEncoding() );
319 docRenderer.renderDocument( writer, this, siteRenderingContext );
320 }
321 finally
322 {
323 IOUtil.close( writer );
324 }
325 }
326 else
327 {
328 if ( getLogger().isDebugEnabled() )
329 {
330 getLogger().debug( inputFile + " unchanged, not regenerating..." );
331 }
332 }
333 }
334 }
335
336
337 public void renderDocument( Writer writer, RenderingContext renderingContext, SiteRenderingContext siteContext )
338 throws RendererException, FileNotFoundException, UnsupportedEncodingException
339 {
340 SiteRendererSink sink = new SiteRendererSink( renderingContext );
341
342 File doc = new File( renderingContext.getBasedir(), renderingContext.getInputName() );
343
344 Reader reader = null;
345 try
346 {
347 String resource = doc.getAbsolutePath();
348
349 Parser parser = doxia.getParser( renderingContext.getParserId() );
350
351
352 if ( renderingContext.getAttribute( "velocity" ) != null )
353 {
354 try
355 {
356 SiteResourceLoader.setResource( resource );
357
358 Context vc = createVelocityContext( sink, siteContext );
359
360 StringWriter sw = new StringWriter();
361
362 velocity.getEngine().mergeTemplate( resource, siteContext.getInputEncoding(), vc, sw );
363
364 reader = new StringReader( sw.toString() );
365 if ( parser.getType() == Parser.XML_TYPE && siteContext.isValidate() )
366 {
367 reader = validate( reader, resource );
368 }
369 }
370 catch ( Exception e )
371 {
372 if ( getLogger().isDebugEnabled() )
373 {
374 getLogger().error( "Error parsing " + resource + " as a velocity template, using as text.", e );
375 }
376 else
377 {
378 getLogger().error( "Error parsing " + resource + " as a velocity template, using as text." );
379 }
380 }
381 }
382 else
383 {
384 switch ( parser.getType() )
385 {
386 case Parser.XML_TYPE:
387 reader = ReaderFactory.newXmlReader( doc );
388 if ( siteContext.isValidate() )
389 {
390 reader = validate( reader, resource );
391 }
392 break;
393
394 case Parser.TXT_TYPE:
395 case Parser.UNKNOWN_TYPE:
396 default:
397 reader = ReaderFactory.newReader( doc, siteContext.getInputEncoding() );
398 }
399 }
400 sink.enableLogging( new PlexusLoggerWrapper( getLogger() ) );
401 doxia.parse( reader, renderingContext.getParserId(), sink );
402 }
403 catch ( ParserNotFoundException e )
404 {
405 throw new RendererException( "Error getting a parser for '" + doc + "': " + e.getMessage(), e );
406 }
407 catch ( ParseException e )
408 {
409 throw new RendererException( "Error parsing '"
410 + doc + "': line [" + e.getLineNumber() + "] " + e.getMessage(), e );
411 }
412 catch ( IOException e )
413 {
414 throw new RendererException( "IOException when processing '" + doc + "'", e );
415 }
416 finally
417 {
418 sink.flush();
419
420 sink.close();
421
422 IOUtil.close( reader );
423 }
424
425 generateDocument( writer, sink, siteContext );
426 }
427
428 private Context createVelocityContext( SiteRendererSink sink, SiteRenderingContext siteRenderingContext )
429 {
430 ToolManager toolManager = new ToolManager( true );
431 Context context = toolManager.createContext();
432
433
434
435
436
437 RenderingContext renderingContext = sink.getRenderingContext();
438 context.put( "relativePath", renderingContext.getRelativePath() );
439
440
441 context.put( "authors", sink.getAuthors() );
442
443 context.put( "shortTitle", sink.getTitle() );
444
445
446 String title = "";
447 if ( siteRenderingContext.getDecoration() != null
448 && siteRenderingContext.getDecoration().getName() != null )
449 {
450 title = siteRenderingContext.getDecoration().getName();
451 }
452 else if ( siteRenderingContext.getDefaultWindowTitle() != null )
453 {
454 title = siteRenderingContext.getDefaultWindowTitle();
455 }
456
457 if ( title.length() > 0 )
458 {
459 title += " - ";
460 }
461 title += sink.getTitle();
462
463 context.put( "title", title );
464
465 context.put( "headContent", sink.getHead() );
466
467 context.put( "bodyContent", sink.getBody() );
468
469 context.put( "decoration", siteRenderingContext.getDecoration() );
470
471 SimpleDateFormat sdf = new SimpleDateFormat( "yyyyMMdd" );
472 if ( StringUtils.isNotEmpty( sink.getDate() ) )
473 {
474 try
475 {
476
477 context.put( "dateCreation",
478 sdf.format( new SimpleDateFormat( "yyyy-MM-dd" ).parse( sink.getDate() ) ) );
479 }
480 catch ( java.text.ParseException e )
481 {
482 getLogger().debug( "Could not parse date: " + sink.getDate() + ", ignoring!", e );
483 }
484 }
485 context.put( "dateRevision", sdf.format( new Date() ) );
486
487 context.put( "currentDate", new Date() );
488
489 context.put( "publishDate", siteRenderingContext.getPublishDate() );
490
491 Locale locale = siteRenderingContext.getLocale();
492 context.put( "dateFormat", DateFormat.getDateInstance( DateFormat.DEFAULT, locale ) );
493
494 String currentFileName = renderingContext.getOutputName().replace( '\\', '/' );
495 context.put( "currentFileName", currentFileName );
496
497 context.put( "alignedFileName", PathTool.calculateLink( currentFileName, renderingContext.getRelativePath() ) );
498
499 context.put( "locale", locale );
500 context.put( "supportedLocales", Collections.unmodifiableList( siteRenderingContext.getSiteLocales() ) );
501
502 InputStream inputStream = null;
503 try
504 {
505 inputStream = this.getClass().getClassLoader().getResourceAsStream( "META-INF/maven/org.apache.maven.doxia/doxia-site-renderer/pom.properties" );
506 if ( inputStream == null )
507 {
508 getLogger().debug( "pom.properties for doxia-site-renderer could not be found." );
509 }
510 else
511 {
512 Properties properties = new Properties();
513 properties.load( inputStream );
514 context.put( "doxiaSiteRendererVersion", properties.getProperty( "version" ) );
515 }
516 }
517 catch( IOException e )
518 {
519 getLogger().debug( "Failed to load pom.properties, so doxiaVersion is not available in the velocityContext." );
520 }
521 finally
522 {
523 IOUtil.close( inputStream );
524 }
525
526
527 Map<String, ?> templateProperties = siteRenderingContext.getTemplateProperties();
528
529 if ( templateProperties != null )
530 {
531 for ( Map.Entry<String, ?> entry : templateProperties.entrySet() )
532 {
533 context.put( entry.getKey(), entry.getValue() );
534 }
535 }
536
537
538
539
540
541 context.put( "PathTool", new PathTool() );
542
543 context.put( "FileUtils", new FileUtils() );
544
545 context.put( "StringUtils", new StringUtils() );
546
547 context.put( "i18n", i18n );
548
549 return context;
550 }
551
552
553 public void generateDocument( Writer writer, SiteRendererSink sink, SiteRenderingContext siteRenderingContext )
554 throws RendererException
555 {
556 Context context = createVelocityContext( sink, siteRenderingContext );
557
558 writeTemplate( writer, context, siteRenderingContext );
559 }
560
561 private void writeTemplate( Writer writer, Context context, SiteRenderingContext siteContext )
562 throws RendererException
563 {
564 ClassLoader old = null;
565
566 if ( siteContext.getTemplateClassLoader() != null )
567 {
568
569
570
571
572 old = Thread.currentThread().getContextClassLoader();
573
574 Thread.currentThread().setContextClassLoader( siteContext.getTemplateClassLoader() );
575 }
576
577 try
578 {
579 processTemplate( siteContext.getTemplateName(), context, writer );
580 }
581 finally
582 {
583 IOUtil.close( writer );
584
585 if ( old != null )
586 {
587 Thread.currentThread().setContextClassLoader( old );
588 }
589 }
590 }
591
592
593
594
595 private void processTemplate( String templateName, Context context, Writer writer )
596 throws RendererException
597 {
598 Template template;
599
600 try
601 {
602 template = velocity.getEngine().getTemplate( templateName );
603 }
604 catch ( Exception e )
605 {
606 throw new RendererException( "Could not find the template '" + templateName, e );
607 }
608
609 try
610 {
611 template.merge( context, writer );
612 }
613 catch ( Exception e )
614 {
615 throw new RendererException( "Error while generating code.", e );
616 }
617 }
618
619
620 public SiteRenderingContext createContextForSkin( File skinFile, Map<String, ?> attributes, DecorationModel decoration,
621 String defaultWindowTitle, Locale locale )
622 throws IOException
623 {
624 SiteRenderingContext context = new SiteRenderingContext();
625
626 ZipFile zipFile = getZipFile( skinFile );
627
628 try
629 {
630 if ( zipFile.getEntry( SKIN_TEMPLATE_LOCATION ) != null )
631 {
632 context.setTemplateName( SKIN_TEMPLATE_LOCATION );
633 context.setTemplateClassLoader( new URLClassLoader( new URL[]{skinFile.toURI().toURL()} ) );
634 }
635 else
636 {
637 context.setTemplateName( DEFAULT_TEMPLATE );
638 context.setTemplateClassLoader( getClass().getClassLoader() );
639 context.setUsingDefaultTemplate( true );
640 }
641 }
642 finally
643 {
644 closeZipFile( zipFile );
645 }
646
647 context.setTemplateProperties( attributes );
648 context.setLocale( locale );
649 context.setDecoration( decoration );
650 context.setDefaultWindowTitle( defaultWindowTitle );
651 context.setSkinJarFile( skinFile );
652
653 return context;
654 }
655
656 private static ZipFile getZipFile( File file )
657 throws IOException
658 {
659 if ( file == null )
660 {
661 throw new IOException( "Error opening ZipFile: null" );
662 }
663
664 try
665 {
666
667 return new ZipFile( file );
668 }
669 catch ( ZipException ex )
670 {
671 IOException ioe = new IOException( "Error opening ZipFile: " + file.getAbsolutePath() );
672 ioe.initCause( ex );
673 throw ioe;
674 }
675 }
676
677
678 public SiteRenderingContext createContextForTemplate( File templateFile, File skinFile, Map<String, ?> attributes,
679 DecorationModel decoration, String defaultWindowTitle,
680 Locale locale )
681 throws MalformedURLException
682 {
683 SiteRenderingContext context = new SiteRenderingContext();
684
685 context.setTemplateName( templateFile.getName() );
686 context.setTemplateClassLoader( new URLClassLoader( new URL[]{templateFile.getParentFile().toURI().toURL()} ) );
687
688 context.setTemplateProperties( attributes );
689 context.setLocale( locale );
690 context.setDecoration( decoration );
691 context.setDefaultWindowTitle( defaultWindowTitle );
692 context.setSkinJarFile( skinFile );
693
694 return context;
695 }
696
697 private static void closeZipFile( ZipFile zipFile )
698 {
699
700 try
701 {
702 zipFile.close();
703 }
704 catch ( IOException e )
705 {
706
707 }
708 }
709
710
711 public void copyResources( SiteRenderingContext siteRenderingContext, File resourcesDirectory, File outputDirectory )
712 throws IOException
713 {
714 if ( siteRenderingContext.getSkinJarFile() != null )
715 {
716 ZipFile file = getZipFile( siteRenderingContext.getSkinJarFile() );
717
718 try
719 {
720 for ( Enumeration<? extends ZipEntry> e = file.entries(); e.hasMoreElements(); )
721 {
722 ZipEntry entry = e.nextElement();
723
724 if ( !entry.getName().startsWith( "META-INF/" ) )
725 {
726 File destFile = new File( outputDirectory, entry.getName() );
727 if ( !entry.isDirectory() )
728 {
729 destFile.getParentFile().mkdirs();
730
731 copyFileFromZip( file, entry, destFile );
732 }
733 else
734 {
735 destFile.mkdirs();
736 }
737 }
738 }
739 }
740 finally
741 {
742 closeZipFile( file );
743 }
744 }
745
746 if ( siteRenderingContext.isUsingDefaultTemplate() )
747 {
748 InputStream resourceList = getClass().getClassLoader()
749 .getResourceAsStream( RESOURCE_DIR + "/resources.txt" );
750
751 if ( resourceList != null )
752 {
753 Reader r = null;
754 try
755 {
756 r = ReaderFactory.newReader( resourceList, ReaderFactory.UTF_8 );
757 LineNumberReader reader = new LineNumberReader( r );
758
759 String line = reader.readLine();
760
761 while ( line != null )
762 {
763 InputStream is = getClass().getClassLoader().getResourceAsStream( RESOURCE_DIR + "/" + line );
764
765 if ( is == null )
766 {
767 throw new IOException( "The resource " + line + " doesn't exist." );
768 }
769
770 File outputFile = new File( outputDirectory, line );
771
772 if ( !outputFile.getParentFile().exists() )
773 {
774 outputFile.getParentFile().mkdirs();
775 }
776
777 OutputStream os = null;
778 try
779 {
780
781 os = new FileOutputStream( outputFile );
782 IOUtil.copy( is, os );
783 }
784 finally
785 {
786 IOUtil.close( os );
787 }
788
789 IOUtil.close( is );
790
791 line = reader.readLine();
792 }
793 }
794 finally
795 {
796 IOUtil.close( r );
797 }
798 }
799 }
800
801
802 if ( resourcesDirectory != null && resourcesDirectory.exists() )
803 {
804 copyDirectory( resourcesDirectory, outputDirectory );
805 }
806
807
808 File siteCssFile = new File( outputDirectory, "/css/site.css" );
809 if ( !siteCssFile.exists() )
810 {
811
812 File cssDirectory = new File( outputDirectory, "/css/" );
813 boolean created = cssDirectory.mkdirs();
814 if ( created && getLogger().isDebugEnabled() )
815 {
816 getLogger().debug(
817 "The directory '" + cssDirectory.getAbsolutePath() + "' did not exist. It was created." );
818 }
819
820
821 if ( getLogger().isDebugEnabled() )
822 {
823 getLogger().debug(
824 "The file '" + siteCssFile.getAbsolutePath() + "' does not exists. Creating an empty file." );
825 }
826 Writer writer = null;
827 try
828 {
829 writer = WriterFactory.newWriter( siteCssFile, siteRenderingContext.getOutputEncoding() );
830
831 writer.write( "/* You can override this file with your own styles */" );
832 }
833 finally
834 {
835 IOUtil.close( writer );
836 }
837 }
838 }
839
840 private static void copyFileFromZip( ZipFile file, ZipEntry entry, File destFile )
841 throws IOException
842 {
843 FileOutputStream fos = new FileOutputStream( destFile );
844
845 try
846 {
847 IOUtil.copy( file.getInputStream( entry ), fos );
848 }
849 finally
850 {
851 IOUtil.close( fos );
852 }
853 }
854
855
856
857
858
859
860
861
862 protected void copyDirectory( File source, File destination )
863 throws IOException
864 {
865 if ( source.exists() )
866 {
867 DirectoryScanner scanner = new DirectoryScanner();
868
869 String[] includedResources = {"**/**"};
870
871 scanner.setIncludes( includedResources );
872
873 scanner.addDefaultExcludes();
874
875 scanner.setBasedir( source );
876
877 scanner.scan();
878
879 List<String> includedFiles = Arrays.asList( scanner.getIncludedFiles() );
880
881 for ( String name : includedFiles )
882 {
883 File sourceFile = new File( source, name );
884
885 File destinationFile = new File( destination, name );
886
887 FileUtils.copyFile( sourceFile, destinationFile );
888 }
889 }
890 }
891
892 private Reader validate( Reader source, String resource )
893 throws ParseException, IOException
894 {
895 getLogger().debug( "Validating: " + resource );
896
897 try
898 {
899 String content = IOUtil.toString( new BufferedReader( source ) );
900
901 new XmlValidator( new PlexusLoggerWrapper( getLogger() ) ).validate( content );
902
903 return new StringReader( content );
904 }
905 finally
906 {
907 IOUtil.close( source );
908 }
909 }
910
911 }