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.component.annotations.Component;
77 import org.codehaus.plexus.component.annotations.Requirement;
78 import org.codehaus.plexus.i18n.I18N;
79 import org.codehaus.plexus.logging.AbstractLogEnabled;
80 import org.codehaus.plexus.util.DirectoryScanner;
81 import org.codehaus.plexus.util.FileUtils;
82 import org.codehaus.plexus.util.IOUtil;
83 import org.codehaus.plexus.util.Os;
84 import org.codehaus.plexus.util.PathTool;
85 import org.codehaus.plexus.util.ReaderFactory;
86 import org.codehaus.plexus.util.StringUtils;
87 import org.codehaus.plexus.util.WriterFactory;
88 import org.codehaus.plexus.velocity.SiteResourceLoader;
89 import org.codehaus.plexus.velocity.VelocityComponent;
90
91
92
93
94
95
96
97
98
99 @Component( role = Renderer.class )
100 public class DefaultSiteRenderer
101 extends AbstractLogEnabled
102 implements Renderer
103 {
104
105
106
107
108 @Requirement
109 private VelocityComponent velocity;
110
111 @Requirement
112 private SiteModuleManager siteModuleManager;
113
114 @Requirement
115 private Doxia doxia;
116
117 @Requirement
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
402 if ( reader == null )
403 {
404 throw new RendererException( "Error getting a parser for '" + doc + "'" );
405 }
406 doxia.parse( reader, renderingContext.getParserId(), sink );
407 }
408 catch ( ParserNotFoundException e )
409 {
410 throw new RendererException( "Error getting a parser for '" + doc + "': " + e.getMessage(), e );
411 }
412 catch ( ParseException e )
413 {
414 throw new RendererException( "Error parsing '"
415 + doc + "': line [" + e.getLineNumber() + "] " + e.getMessage(), e );
416 }
417 catch ( IOException e )
418 {
419 throw new RendererException( "IOException when processing '" + doc + "'", e );
420 }
421 finally
422 {
423 sink.flush();
424
425 sink.close();
426
427 IOUtil.close( reader );
428 }
429
430 generateDocument( writer, sink, siteContext );
431 }
432
433 private Context createVelocityContext( SiteRendererSink sink, SiteRenderingContext siteRenderingContext )
434 {
435 ToolManager toolManager = new ToolManager( true );
436 Context context = toolManager.createContext();
437
438
439
440
441
442 RenderingContext renderingContext = sink.getRenderingContext();
443 context.put( "relativePath", renderingContext.getRelativePath() );
444
445
446 context.put( "authors", sink.getAuthors() );
447
448 context.put( "shortTitle", sink.getTitle() );
449
450
451 String title = "";
452 if ( siteRenderingContext.getDecoration() != null
453 && siteRenderingContext.getDecoration().getName() != null )
454 {
455 title = siteRenderingContext.getDecoration().getName();
456 }
457 else if ( siteRenderingContext.getDefaultWindowTitle() != null )
458 {
459 title = siteRenderingContext.getDefaultWindowTitle();
460 }
461
462 if ( title.length() > 0 )
463 {
464 title += " - ";
465 }
466 title += sink.getTitle();
467
468 context.put( "title", title );
469
470 context.put( "headContent", sink.getHead() );
471
472 context.put( "bodyContent", sink.getBody() );
473
474 context.put( "decoration", siteRenderingContext.getDecoration() );
475
476 SimpleDateFormat sdf = new SimpleDateFormat( "yyyyMMdd" );
477 if ( StringUtils.isNotEmpty( sink.getDate() ) )
478 {
479 try
480 {
481
482 context.put( "dateCreation",
483 sdf.format( new SimpleDateFormat( "yyyy-MM-dd" ).parse( sink.getDate() ) ) );
484 }
485 catch ( java.text.ParseException e )
486 {
487 getLogger().debug( "Could not parse date: " + sink.getDate() + ", ignoring!", e );
488 }
489 }
490 context.put( "dateRevision", sdf.format( new Date() ) );
491
492 context.put( "currentDate", new Date() );
493
494 context.put( "publishDate", siteRenderingContext.getPublishDate() );
495
496 Locale locale = siteRenderingContext.getLocale();
497
498 DateFormat dateFormat = DateFormat.getDateInstance( DateFormat.DEFAULT, locale );
499
500 if ( siteRenderingContext.getDecoration().getPublishDate() != null )
501 {
502 if ( StringUtils.isNotBlank( siteRenderingContext.getDecoration().getPublishDate().getFormat() ) )
503 {
504 dateFormat =
505 new SimpleDateFormat( siteRenderingContext.getDecoration().getPublishDate().getFormat(), locale );
506 }
507 }
508
509 context.put( "dateFormat", dateFormat );
510
511 String currentFileName = renderingContext.getOutputName().replace( '\\', '/' );
512 context.put( "currentFileName", currentFileName );
513
514 context.put( "alignedFileName", PathTool.calculateLink( currentFileName, renderingContext.getRelativePath() ) );
515
516 context.put( "locale", locale );
517 context.put( "supportedLocales", Collections.unmodifiableList( siteRenderingContext.getSiteLocales() ) );
518
519 InputStream inputStream = null;
520 try
521 {
522 inputStream = this.getClass().getClassLoader().getResourceAsStream( "META-INF/maven/org.apache.maven.doxia/doxia-site-renderer/pom.properties" );
523 if ( inputStream == null )
524 {
525 getLogger().debug( "pom.properties for doxia-site-renderer could not be found." );
526 }
527 else
528 {
529 Properties properties = new Properties();
530 properties.load( inputStream );
531 context.put( "doxiaSiteRendererVersion", properties.getProperty( "version" ) );
532 }
533 }
534 catch( IOException e )
535 {
536 getLogger().debug( "Failed to load pom.properties, so doxiaVersion is not available in the velocityContext." );
537 }
538 finally
539 {
540 IOUtil.close( inputStream );
541 }
542
543
544 Map<String, ?> templateProperties = siteRenderingContext.getTemplateProperties();
545
546 if ( templateProperties != null )
547 {
548 for ( Map.Entry<String, ?> entry : templateProperties.entrySet() )
549 {
550 context.put( entry.getKey(), entry.getValue() );
551 }
552 }
553
554
555
556
557
558 context.put( "PathTool", new PathTool() );
559
560 context.put( "FileUtils", new FileUtils() );
561
562 context.put( "StringUtils", new StringUtils() );
563
564 context.put( "i18n", i18n );
565
566 return context;
567 }
568
569
570 public void generateDocument( Writer writer, SiteRendererSink sink, SiteRenderingContext siteRenderingContext )
571 throws RendererException
572 {
573 Context context = createVelocityContext( sink, siteRenderingContext );
574
575 writeTemplate( writer, context, siteRenderingContext );
576 }
577
578 private void writeTemplate( Writer writer, Context context, SiteRenderingContext siteContext )
579 throws RendererException
580 {
581 ClassLoader old = null;
582
583 if ( siteContext.getTemplateClassLoader() != null )
584 {
585
586
587
588
589 old = Thread.currentThread().getContextClassLoader();
590
591 Thread.currentThread().setContextClassLoader( siteContext.getTemplateClassLoader() );
592 }
593
594 try
595 {
596 processTemplate( siteContext.getTemplateName(), context, writer );
597 }
598 finally
599 {
600 IOUtil.close( writer );
601
602 if ( old != null )
603 {
604 Thread.currentThread().setContextClassLoader( old );
605 }
606 }
607 }
608
609
610
611
612 private void processTemplate( String templateName, Context context, Writer writer )
613 throws RendererException
614 {
615 Template template;
616
617 try
618 {
619 template = velocity.getEngine().getTemplate( templateName );
620 }
621 catch ( Exception e )
622 {
623 throw new RendererException( "Could not find the template '" + templateName, e );
624 }
625
626 try
627 {
628 template.merge( context, writer );
629 }
630 catch ( Exception e )
631 {
632 throw new RendererException( "Error while generating code.", e );
633 }
634 }
635
636
637 public SiteRenderingContext createContextForSkin( File skinFile, Map<String, ?> attributes, DecorationModel decoration,
638 String defaultWindowTitle, Locale locale )
639 throws IOException
640 {
641 SiteRenderingContext context = new SiteRenderingContext();
642
643 ZipFile zipFile = getZipFile( skinFile );
644
645 try
646 {
647 if ( zipFile.getEntry( SKIN_TEMPLATE_LOCATION ) != null )
648 {
649 context.setTemplateName( SKIN_TEMPLATE_LOCATION );
650 context.setTemplateClassLoader( new URLClassLoader( new URL[]{skinFile.toURI().toURL()} ) );
651 }
652 else
653 {
654 context.setTemplateName( DEFAULT_TEMPLATE );
655 context.setTemplateClassLoader( getClass().getClassLoader() );
656 context.setUsingDefaultTemplate( true );
657 }
658 }
659 finally
660 {
661 closeZipFile( zipFile );
662 }
663
664 context.setTemplateProperties( attributes );
665 context.setLocale( locale );
666 context.setDecoration( decoration );
667 context.setDefaultWindowTitle( defaultWindowTitle );
668 context.setSkinJarFile( skinFile );
669
670 return context;
671 }
672
673 private static ZipFile getZipFile( File file )
674 throws IOException
675 {
676 if ( file == null )
677 {
678 throw new IOException( "Error opening ZipFile: null" );
679 }
680
681 try
682 {
683
684 return new ZipFile( file );
685 }
686 catch ( ZipException ex )
687 {
688 IOException ioe = new IOException( "Error opening ZipFile: " + file.getAbsolutePath() );
689 ioe.initCause( ex );
690 throw ioe;
691 }
692 }
693
694
695 public SiteRenderingContext createContextForTemplate( File templateFile, File skinFile, Map<String, ?> attributes,
696 DecorationModel decoration, String defaultWindowTitle,
697 Locale locale )
698 throws MalformedURLException
699 {
700 SiteRenderingContext context = new SiteRenderingContext();
701
702 context.setTemplateName( templateFile.getName() );
703 context.setTemplateClassLoader( new URLClassLoader( new URL[]{templateFile.getParentFile().toURI().toURL()} ) );
704
705 context.setTemplateProperties( attributes );
706 context.setLocale( locale );
707 context.setDecoration( decoration );
708 context.setDefaultWindowTitle( defaultWindowTitle );
709 context.setSkinJarFile( skinFile );
710
711 return context;
712 }
713
714 private static void closeZipFile( ZipFile zipFile )
715 {
716
717 try
718 {
719 zipFile.close();
720 }
721 catch ( IOException e )
722 {
723
724 }
725 }
726
727
728 public void copyResources( SiteRenderingContext siteRenderingContext, File resourcesDirectory, File outputDirectory )
729 throws IOException
730 {
731 if ( siteRenderingContext.getSkinJarFile() != null )
732 {
733 ZipFile file = getZipFile( siteRenderingContext.getSkinJarFile() );
734
735 try
736 {
737 for ( Enumeration<? extends ZipEntry> e = file.entries(); e.hasMoreElements(); )
738 {
739 ZipEntry entry = e.nextElement();
740
741 if ( !entry.getName().startsWith( "META-INF/" ) )
742 {
743 File destFile = new File( outputDirectory, entry.getName() );
744 if ( !entry.isDirectory() )
745 {
746 destFile.getParentFile().mkdirs();
747
748 copyFileFromZip( file, entry, destFile );
749 }
750 else
751 {
752 destFile.mkdirs();
753 }
754 }
755 }
756 }
757 finally
758 {
759 closeZipFile( file );
760 }
761 }
762
763 if ( siteRenderingContext.isUsingDefaultTemplate() )
764 {
765 InputStream resourceList = getClass().getClassLoader()
766 .getResourceAsStream( RESOURCE_DIR + "/resources.txt" );
767
768 if ( resourceList != null )
769 {
770 Reader r = null;
771 LineNumberReader reader = null;
772 try
773 {
774 r = ReaderFactory.newReader( resourceList, ReaderFactory.UTF_8 );
775 reader = new LineNumberReader( r );
776
777 String line = reader.readLine();
778
779 while ( line != null )
780 {
781 InputStream is = getClass().getClassLoader().getResourceAsStream( RESOURCE_DIR + "/" + line );
782
783 if ( is == null )
784 {
785 throw new IOException( "The resource " + line + " doesn't exist." );
786 }
787
788 File outputFile = new File( outputDirectory, line );
789
790 if ( !outputFile.getParentFile().exists() )
791 {
792 outputFile.getParentFile().mkdirs();
793 }
794
795 OutputStream os = null;
796 try
797 {
798
799 os = new FileOutputStream( outputFile );
800 IOUtil.copy( is, os );
801 }
802 finally
803 {
804 IOUtil.close( os );
805 }
806
807 IOUtil.close( is );
808
809 line = reader.readLine();
810 }
811 }
812 finally
813 {
814 IOUtil.close( reader );
815 IOUtil.close( r );
816 }
817 }
818 }
819
820
821 if ( resourcesDirectory != null && resourcesDirectory.exists() )
822 {
823 copyDirectory( resourcesDirectory, outputDirectory );
824 }
825
826
827 File siteCssFile = new File( outputDirectory, "/css/site.css" );
828 if ( !siteCssFile.exists() )
829 {
830
831 File cssDirectory = new File( outputDirectory, "/css/" );
832 boolean created = cssDirectory.mkdirs();
833 if ( created && getLogger().isDebugEnabled() )
834 {
835 getLogger().debug(
836 "The directory '" + cssDirectory.getAbsolutePath() + "' did not exist. It was created." );
837 }
838
839
840 if ( getLogger().isDebugEnabled() )
841 {
842 getLogger().debug(
843 "The file '" + siteCssFile.getAbsolutePath() + "' does not exists. Creating an empty file." );
844 }
845 Writer writer = null;
846 try
847 {
848 writer = WriterFactory.newWriter( siteCssFile, siteRenderingContext.getOutputEncoding() );
849
850 writer.write( "/* You can override this file with your own styles */" );
851 }
852 finally
853 {
854 IOUtil.close( writer );
855 }
856 }
857 }
858
859 private static void copyFileFromZip( ZipFile file, ZipEntry entry, File destFile )
860 throws IOException
861 {
862 FileOutputStream fos = new FileOutputStream( destFile );
863
864 try
865 {
866 IOUtil.copy( file.getInputStream( entry ), fos );
867 }
868 finally
869 {
870 IOUtil.close( fos );
871 }
872 }
873
874
875
876
877
878
879
880
881 protected void copyDirectory( File source, File destination )
882 throws IOException
883 {
884 if ( source.exists() )
885 {
886 DirectoryScanner scanner = new DirectoryScanner();
887
888 String[] includedResources = {"**/**"};
889
890 scanner.setIncludes( includedResources );
891
892 scanner.addDefaultExcludes();
893
894 scanner.setBasedir( source );
895
896 scanner.scan();
897
898 List<String> includedFiles = Arrays.asList( scanner.getIncludedFiles() );
899
900 for ( String name : includedFiles )
901 {
902 File sourceFile = new File( source, name );
903
904 File destinationFile = new File( destination, name );
905
906 FileUtils.copyFile( sourceFile, destinationFile );
907 }
908 }
909 }
910
911 private Reader validate( Reader source, String resource )
912 throws ParseException, IOException
913 {
914 getLogger().debug( "Validating: " + resource );
915
916 try
917 {
918 String content = IOUtil.toString( new BufferedReader( source ) );
919
920 new XmlValidator( new PlexusLoggerWrapper( getLogger() ) ).validate( content );
921
922 return new StringReader( content );
923 }
924 finally
925 {
926 IOUtil.close( source );
927 }
928 }
929
930 }