1 package org.apache.maven.plugins.linkcheck;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.FileNotFoundException;
24 import java.io.FileOutputStream;
25 import java.io.IOException;
26 import java.io.OutputStream;
27 import java.io.PrintStream;
28 import java.io.Reader;
29 import java.io.UnsupportedEncodingException;
30 import java.io.Writer;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.Locale;
37 import java.util.Properties;
38
39 import org.apache.commons.io.FilenameUtils;
40 import org.apache.commons.lang.SystemUtils;
41 import org.apache.maven.artifact.repository.ArtifactRepository;
42 import org.apache.maven.doxia.linkcheck.HttpBean;
43 import org.apache.maven.doxia.linkcheck.LinkCheck;
44 import org.apache.maven.doxia.linkcheck.LinkCheckException;
45 import org.apache.maven.doxia.linkcheck.model.LinkcheckFile;
46 import org.apache.maven.doxia.linkcheck.model.LinkcheckFileResult;
47 import org.apache.maven.doxia.linkcheck.model.LinkcheckModel;
48 import org.apache.maven.doxia.siterenderer.Renderer;
49 import org.apache.maven.model.Reporting;
50 import org.apache.maven.plugin.MojoExecutionException;
51 import org.apache.maven.project.MavenProject;
52 import org.apache.maven.reporting.AbstractMavenReport;
53 import org.apache.maven.reporting.MavenReportException;
54 import org.apache.maven.settings.Proxy;
55 import org.apache.maven.settings.Settings;
56 import org.apache.maven.shared.invoker.DefaultInvocationRequest;
57 import org.apache.maven.shared.invoker.DefaultInvoker;
58 import org.apache.maven.shared.invoker.InvocationOutputHandler;
59 import org.apache.maven.shared.invoker.InvocationRequest;
60 import org.apache.maven.shared.invoker.InvocationResult;
61 import org.apache.maven.shared.invoker.Invoker;
62 import org.apache.maven.shared.invoker.MavenInvocationException;
63 import org.apache.maven.shared.invoker.PrintStreamHandler;
64 import org.codehaus.plexus.i18n.I18N;
65 import org.codehaus.plexus.util.FileUtils;
66 import org.codehaus.plexus.util.IOUtil;
67 import org.codehaus.plexus.util.ReaderFactory;
68 import org.codehaus.plexus.util.StringUtils;
69 import org.codehaus.plexus.util.WriterFactory;
70 import org.codehaus.plexus.util.cli.CommandLineUtils;
71
72
73
74
75
76
77
78
79
80 public class LinkcheckReport
81 extends AbstractMavenReport
82 {
83
84
85
86
87
88
89
90
91
92 private I18N i18n;
93
94
95
96
97
98
99 private Renderer siteRenderer;
100
101
102
103
104
105
106 private LinkCheck linkCheck;
107
108
109
110
111
112
113
114
115
116
117
118
119 private MavenProject project;
120
121
122
123
124
125
126
127
128 private ArtifactRepository localRepository;
129
130
131
132
133
134
135
136 private File outputDirectory;
137
138
139
140
141
142
143
144
145 private Settings settings;
146
147
148
149
150
151
152
153
154
155
156
157 private boolean offline;
158
159
160
161
162
163
164
165 private boolean httpFollowRedirect;
166
167
168
169
170
171
172
173 protected File linkcheckCache;
174
175
176
177
178
179
180
181 protected File linkcheckOutput;
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205 private String httpMethod;
206
207
208
209
210
211
212
213 private int[] excludedHttpStatusErrors;
214
215
216
217
218
219
220
221 private int[] excludedHttpStatusWarnings;
222
223
224
225
226
227
228
229
230 private String[] excludedPages;
231
232
233
234
235
236
237
238
239 private String[] excludedLinks;
240
241
242
243
244
245
246
247 private String encoding;
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263 private Properties httpClientParameters;
264
265
266
267
268
269
270 private int timeout;
271
272
273
274
275
276
277
278 private boolean skip;
279
280
281
282
283
284
285
286 private boolean forceSite;
287
288
289
290
291
292
293 private String baseURL;
294
295
296
297
298
299
300 private LinkcheckModel result;
301
302
303
304
305
306
307 public String getDescription( Locale locale )
308 {
309 return i18n.getString( "linkcheck-report", locale, "report.linkcheck.description" );
310 }
311
312
313 public String getName( Locale locale )
314 {
315 return i18n.getString( "linkcheck-report", locale, "report.linkcheck.name" );
316 }
317
318
319 public String getOutputName()
320 {
321 return "linkcheck";
322 }
323
324
325 public boolean canGenerateReport()
326 {
327 if ( skip )
328 {
329 return false;
330 }
331
332 return true;
333 }
334
335
336 public void execute()
337 throws MojoExecutionException
338 {
339 if ( !canGenerateReport() )
340 {
341 return;
342 }
343
344
345 if ( StringUtils.isEmpty( encoding ) )
346 {
347 if ( getLog().isWarnEnabled() )
348 {
349 getLog().warn(
350 "File encoding has not been set, using platform encoding "
351 + ReaderFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
352 }
353 encoding = ReaderFactory.FILE_ENCODING;
354 }
355
356 File tmpReportingOutputDirectory = new File( linkcheckOutput.getParentFile(), "tmpsite" );
357 tmpReportingOutputDirectory.mkdirs();
358
359 File basedir;
360 if ( forceSite )
361 {
362 basedir = tmpReportingOutputDirectory;
363
364 List documents = null;
365 try
366 {
367 documents = FileUtils.getFiles( basedir, "**/*.html", null );
368 }
369 catch ( IOException e )
370 {
371 String msg = "IOException: " + e.getMessage();
372 if ( getLog().isDebugEnabled() )
373 {
374 getLog().error( msg, e );
375 }
376 else
377 {
378 getLog().error( msg );
379 }
380 }
381
382
383 if ( documents == null || ( documents != null && documents.size() == 0 ) )
384 {
385 getLog().info( "Trying to invoke the maven-site-plugin to be sure that all files are generated..." );
386
387 try
388 {
389 invokeSite( tmpReportingOutputDirectory );
390 }
391 catch ( IOException e )
392 {
393 throw new MojoExecutionException( "IOException: " + e.getMessage(), e );
394 }
395 }
396 }
397 else
398 {
399 if ( getLog().isWarnEnabled() )
400 {
401 getLog().warn(
402 "WARRANTY: The number of documents analyzed by Linkcheck could differ with the real "
403 + "number of documents!" );
404 }
405
406 basedir = outputDirectory;
407 basedir.mkdirs();
408 }
409
410 try
411 {
412 result = executeLinkCheck( basedir );
413 }
414 catch ( LinkCheckException e )
415 {
416 throw new MojoExecutionException( "LinkCheckException: " + e.getMessage(), e );
417 }
418 }
419
420
421
422
423
424
425 protected String getOutputDirectory()
426 {
427 return outputDirectory.getAbsolutePath();
428 }
429
430
431 protected MavenProject getProject()
432 {
433 return project;
434 }
435
436
437 protected Renderer getSiteRenderer()
438 {
439 return siteRenderer;
440 }
441
442
443 protected void executeReport( Locale locale )
444 throws MavenReportException
445 {
446 if ( result == null )
447 {
448 getLog().debug( "Calling execute()" );
449
450 try
451 {
452 this.execute();
453 }
454 catch ( MojoExecutionException e )
455 {
456 throw new MavenReportException( "MojoExecutionException: " + e.getMessage(), e );
457 }
458 }
459
460 if ( result != null )
461 {
462 generateReport( locale, result );
463
464 result = null;
465 }
466 }
467
468
469
470
471
472
473
474
475
476
477
478 private LinkcheckModel executeLinkCheck( File basedir )
479 throws LinkCheckException
480 {
481
482 linkCheck.setOnline( !offline );
483 linkCheck.setBasedir( basedir );
484 linkCheck.setBaseURL( baseURL );
485 linkCheck.setReportOutput( linkcheckOutput );
486 linkCheck.setLinkCheckCache( linkcheckCache );
487 linkCheck.setExcludedLinks( excludedLinks );
488 linkCheck.setExcludedPages( getExcludedPages() );
489 linkCheck.setExcludedHttpStatusErrors( excludedHttpStatusErrors );
490 linkCheck.setExcludedHttpStatusWarnings( excludedHttpStatusWarnings );
491 linkCheck.setEncoding( ( StringUtils.isNotEmpty( encoding ) ? encoding : WriterFactory.UTF_8 ) );
492
493 HttpBean bean = new HttpBean();
494 bean.setMethod( httpMethod );
495 bean.setFollowRedirects( httpFollowRedirect );
496 bean.setTimeout( timeout );
497 if ( httpClientParameters != null )
498 {
499 bean.setHttpClientParameters( httpClientParameters );
500 }
501
502 Proxy proxy = settings.getActiveProxy();
503 if ( proxy != null )
504 {
505 bean.setProxyHost( proxy.getHost() );
506 bean.setProxyPort( proxy.getPort() );
507 bean.setProxyUser( proxy.getUsername() );
508 bean.setProxyPassword( proxy.getPassword() );
509 }
510 linkCheck.setHttp( bean );
511
512 return linkCheck.execute();
513 }
514
515
516
517
518 private String[] getExcludedPages()
519 {
520 List pagesToExclude =
521 ( excludedPages != null ? new ArrayList( Arrays.asList( excludedPages ) ) : new ArrayList() );
522
523
524 pagesToExclude.add( getOutputName() + ".html" );
525
526 return (String[]) pagesToExclude.toArray( new String[0] );
527 }
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542 private void invokeSite( File tmpReportingOutputDirectory )
543 throws IOException
544 {
545 String mavenHome = getMavenHome();
546 if ( StringUtils.isEmpty( mavenHome ) )
547 {
548 if ( getLog().isErrorEnabled() )
549 {
550 String msg =
551 "Could NOT invoke Maven because no Maven Home is defined. You need to have set the M2_HOME "
552 + "system env variable or a 'maven.home' Java system properties.";
553 getLog().error( msg );
554 }
555 return;
556 }
557
558
559 List goals = Collections.singletonList( "site" );
560 Properties properties = new Properties();
561 properties.put( "linkcheck.skip", "true" );
562
563 File invokerLog =
564 FileUtils
565 .createTempFile( "invoker-site-plugin", ".txt", new File( project.getBuild().getDirectory() ) );
566
567
568 MavenProject clone;
569 try
570 {
571 clone = (MavenProject) project.clone();
572 }
573 catch ( CloneNotSupportedException e )
574 {
575 IOException ioe = new IOException( "CloneNotSupportedException: " + e.getMessage() );
576 ioe.setStackTrace( e.getStackTrace() );
577 throw ioe;
578 }
579
580
581 if ( clone.getOriginalModel().getReporting() == null )
582 {
583 clone.getOriginalModel().setReporting( new Reporting() );
584 }
585
586 clone.getOriginalModel().getReporting().setOutputDirectory( tmpReportingOutputDirectory.getAbsolutePath() );
587
588
589 File tmpProjectFile = FileUtils.createTempFile( "pom", ".xml", project.getBasedir() );
590 Writer writer = null;
591 try
592 {
593 writer = WriterFactory.newXmlWriter( tmpProjectFile );
594 clone.writeOriginalModel( writer );
595 }
596 finally
597 {
598 IOUtil.close( writer );
599 }
600
601
602 try
603 {
604 invoke( tmpProjectFile, invokerLog, mavenHome, goals, properties );
605 }
606 finally
607 {
608 if ( !getLog().isDebugEnabled() )
609 {
610 tmpProjectFile.delete();
611 }
612 }
613 }
614
615
616
617
618
619
620
621
622 private void invoke( File projectFile, File invokerLog, String mavenHome, List goals, Properties properties )
623 {
624 Invoker invoker = new DefaultInvoker();
625 invoker.setMavenHome( new File( mavenHome ) );
626 invoker.setLocalRepositoryDirectory( new File( localRepository.getBasedir() ) );
627
628 InvocationRequest request = new DefaultInvocationRequest();
629 request.setBaseDirectory( projectFile.getParentFile() );
630 request.setPomFile( projectFile );
631 request.setDebug( getLog().isDebugEnabled() );
632 request.setGoals( goals );
633 request.setProperties( properties );
634 File javaHome = getJavaHome();
635 if ( javaHome != null )
636 {
637 request.setJavaHome( javaHome );
638 }
639
640 InvocationResult invocationResult;
641 try
642 {
643 if ( getLog().isDebugEnabled() )
644 {
645 getLog().debug( "Invoking Maven for the goals: " + goals + " with properties=" + properties );
646 }
647 invocationResult = invoke( invoker, request, invokerLog, goals, properties, null );
648 }
649 catch ( MavenInvocationException e )
650 {
651 if ( getLog().isDebugEnabled() )
652 {
653 getLog().error( "MavenInvocationException: " + e.getMessage(), e );
654 }
655 getLog().error( "Error when invoking Maven, consult the invoker log." );
656 return;
657 }
658
659 String invokerLogContent = null;
660 Reader reader = null;
661 try
662 {
663 reader = ReaderFactory.newReader( invokerLog, "UTF-8" );
664 invokerLogContent = IOUtil.toString( reader );
665 }
666 catch ( IOException e )
667 {
668 String msg = "IOException: " + e.getMessage();
669 if ( getLog().isDebugEnabled() )
670 {
671 getLog().error( msg, e );
672 }
673 else
674 {
675 getLog().error( msg );
676 }
677 }
678 finally
679 {
680 IOUtil.close( reader );
681 }
682
683 if ( invokerLogContent != null
684 && invokerLogContent.indexOf( "Error occurred during initialization of VM" ) != -1 )
685 {
686 getLog().info( "Error occurred during initialization of VM, try to use an empty MAVEN_OPTS." );
687
688 if ( getLog().isDebugEnabled() )
689 {
690 getLog().debug( "Reinvoking Maven for the goals: " + goals + " with an empty MAVEN_OPTS" );
691 }
692
693 try
694 {
695 invocationResult = invoke( invoker, request, invokerLog, goals, properties, "" );
696 }
697 catch ( MavenInvocationException e )
698 {
699 if ( getLog().isDebugEnabled() )
700 {
701 getLog().error( "MavenInvocationException: " + e.getMessage(), e );
702 }
703 getLog().error( "Error when reinvoking Maven, consult the invoker log." );
704 return;
705 }
706 }
707
708 if ( invocationResult.getExitCode() != 0 )
709 {
710 if ( getLog().isErrorEnabled() )
711 {
712 getLog().error(
713 "Error when invoking Maven, consult the invoker log file: "
714 + invokerLog.getAbsolutePath() );
715 }
716 }
717 }
718
719
720
721
722
723
724
725
726
727
728
729 private InvocationResult invoke( Invoker invoker, InvocationRequest request, File invokerLog, List goals,
730 Properties properties, String mavenOpts )
731 throws MavenInvocationException
732 {
733 PrintStream ps;
734 OutputStream os = null;
735 if ( invokerLog != null )
736 {
737 if ( getLog().isDebugEnabled() )
738 {
739 getLog().debug( "Using " + invokerLog.getAbsolutePath() + " to log the invoker" );
740 }
741
742 try
743 {
744 if ( !invokerLog.exists() )
745 {
746 invokerLog.getParentFile().mkdirs();
747 }
748 os = new FileOutputStream( invokerLog );
749 ps = new PrintStream( os, true, "UTF-8" );
750 }
751 catch ( FileNotFoundException e )
752 {
753 if ( getLog().isErrorEnabled() )
754 {
755 getLog().error(
756 "FileNotFoundException: " + e.getMessage()
757 + ". Using System.out to log the invoker." );
758 }
759 ps = System.out;
760 }
761 catch ( UnsupportedEncodingException e )
762 {
763 if ( getLog().isErrorEnabled() )
764 {
765 getLog().error(
766 "UnsupportedEncodingException: " + e.getMessage()
767 + ". Using System.out to log the invoker." );
768 }
769 ps = System.out;
770 }
771 }
772 else
773 {
774 getLog().debug( "Using System.out to log the invoker." );
775
776 ps = System.out;
777 }
778
779 if ( mavenOpts != null )
780 {
781 request.setMavenOpts( mavenOpts );
782 }
783
784 InvocationOutputHandler outputHandler = new PrintStreamHandler( ps, false );
785 request.setOutputHandler( outputHandler );
786
787 outputHandler.consumeLine( "Invoking Maven for the goals: " + goals + " with properties=" + properties );
788 outputHandler.consumeLine( "" );
789 outputHandler.consumeLine( "M2_HOME=" + getMavenHome() );
790 outputHandler.consumeLine( "MAVEN_OPTS=" + getMavenOpts() );
791 outputHandler.consumeLine( "JAVA_HOME=" + getJavaHome() );
792 outputHandler.consumeLine( "JAVA_OPTS=" + getJavaOpts() );
793 outputHandler.consumeLine( "" );
794
795 try
796 {
797 return invoker.execute( request );
798 }
799 finally
800 {
801 IOUtil.close( os );
802 ps = null;
803 }
804 }
805
806
807
808
809
810
811 private String getMavenHome()
812 {
813 String mavenHome = System.getProperty( "maven.home" );
814 if ( mavenHome == null )
815 {
816 try
817 {
818 mavenHome = CommandLineUtils.getSystemEnvVars().getProperty( "M2_HOME" );
819 }
820 catch ( IOException e )
821 {
822 String msg = "IOException: " + e.getMessage();
823 if ( getLog().isDebugEnabled() )
824 {
825 getLog().error( msg, e );
826 }
827 else
828 {
829 getLog().error( msg );
830 }
831 }
832 }
833
834 File m2Home = new File( mavenHome );
835 if ( !m2Home.exists() )
836 {
837 if ( getLog().isErrorEnabled() )
838 {
839 getLog().error(
840 "Cannot find Maven application directory. Either specify \'maven.home\' "
841 + "system property, or M2_HOME environment variable." );
842 }
843 }
844
845 return mavenHome;
846 }
847
848
849
850
851
852 private String getMavenOpts()
853 {
854 String mavenOpts = null;
855 try
856 {
857 mavenOpts = CommandLineUtils.getSystemEnvVars().getProperty( "MAVEN_OPTS" );
858 }
859 catch ( IOException e )
860 {
861 String msg = "IOException: " + e.getMessage();
862 if ( getLog().isDebugEnabled() )
863 {
864 getLog().error( msg, e );
865 }
866 else
867 {
868 getLog().error( msg );
869 }
870 }
871
872 return mavenOpts;
873 }
874
875
876
877
878
879
880
881 private File getJavaHome()
882 {
883 File javaHome;
884 if ( SystemUtils.IS_OS_MAC_OSX )
885 {
886 javaHome = SystemUtils.getJavaHome();
887 }
888 else
889 {
890 javaHome = new File( SystemUtils.getJavaHome(), ".." );
891 }
892
893 if ( javaHome == null || !javaHome.exists() )
894 {
895 try
896 {
897 javaHome = new File( CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_HOME" ) );
898 }
899 catch ( IOException e )
900 {
901 String msg = "IOException: " + e.getMessage();
902 if ( getLog().isDebugEnabled() )
903 {
904 getLog().error( msg, e );
905 }
906 else
907 {
908 getLog().error( msg );
909 }
910 }
911 }
912
913 if ( javaHome == null || !javaHome.exists() )
914 {
915 if ( getLog().isErrorEnabled() )
916 {
917 getLog().error(
918 "Cannot find Java application directory. Either specify \'java.home\' "
919 + "system property, or JAVA_HOME environment variable." );
920 }
921 }
922
923 return javaHome;
924 }
925
926
927
928
929
930 private String getJavaOpts()
931 {
932 String javaOpts = null;
933 try
934 {
935 javaOpts = CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_OPTS" );
936 }
937 catch ( IOException e )
938 {
939 String msg = "IOException: " + e.getMessage();
940 if ( getLog().isDebugEnabled() )
941 {
942 getLog().error( msg, e );
943 }
944 else
945 {
946 getLog().error( msg );
947 }
948 }
949
950 return javaOpts;
951 }
952
953
954
955
956
957 private void generateReport( Locale locale, LinkcheckModel linkcheckModel )
958 {
959 getSink().head();
960 getSink().title();
961 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.title" ) );
962 getSink().title_();
963 getSink().head_();
964
965 getSink().body();
966
967 if ( linkcheckModel == null )
968 {
969 getSink().section1();
970 getSink().sectionTitle1();
971 getSink().text( getName( locale ) );
972 getSink().sectionTitle1_();
973
974 getSink().paragraph();
975 getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.empty" ) );
976 getSink().paragraph_();
977
978 getSink().section1_();
979
980 getSink().body_();
981 getSink().flush();
982 getSink().close();
983
984 return;
985 }
986
987
988 getSink().section1();
989 getSink().sectionTitle1();
990 getSink().text( getName( locale ) );
991 getSink().sectionTitle1_();
992
993 getSink().paragraph();
994 getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.overview" ) );
995 getSink().paragraph_();
996
997 getSink().section1_();
998
999
1000 generateSummarySection( locale, linkcheckModel );
1001
1002 if ( linkcheckModel.getFiles().size() > 0 )
1003 {
1004
1005 generateDetailsSection( locale, linkcheckModel );
1006 }
1007
1008 getSink().body_();
1009 getSink().flush();
1010 getSink().close();
1011
1012 closeReport();
1013 }
1014
1015 private void generateSummarySection( Locale locale, LinkcheckModel linkcheckModel )
1016 {
1017
1018 List linkcheckFiles = linkcheckModel.getFiles();
1019
1020 int totalFiles = linkcheckFiles.size();
1021
1022 int totalLinks = 0;
1023 int totalValidLinks = 0;
1024 int totalErrorLinks = 0;
1025 int totalWarningLinks = 0;
1026 for ( Iterator it = linkcheckFiles.iterator(); it.hasNext(); )
1027 {
1028 LinkcheckFile linkcheckFile = (LinkcheckFile) it.next();
1029
1030 totalLinks += linkcheckFile.getNumberOfLinks();
1031 totalValidLinks += linkcheckFile.getNumberOfLinks( LinkcheckFileResult.VALID_LEVEL );
1032 totalErrorLinks += linkcheckFile.getNumberOfLinks( LinkcheckFileResult.ERROR_LEVEL );
1033 totalWarningLinks += linkcheckFile.getNumberOfLinks( LinkcheckFileResult.WARNING_LEVEL );
1034 }
1035
1036 getSink().section1();
1037 getSink().sectionTitle1();
1038 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary" ) );
1039 getSink().sectionTitle1_();
1040
1041
1042 getSink().paragraph();
1043 getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.overview1" ) );
1044 getSink().paragraph_();
1045
1046 getSink().table();
1047
1048 getSink().tableRow();
1049 getSink().tableHeaderCell();
1050 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.parameter" ) );
1051 getSink().tableHeaderCell_();
1052 getSink().tableHeaderCell();
1053 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.value" ) );
1054 getSink().tableHeaderCell_();
1055 getSink().tableRow_();
1056
1057 getSink().tableRow();
1058 getSink().tableCell();
1059 getSink().rawText(
1060 i18n.getString( "linkcheck-report", locale,
1061 "report.linkcheck.summary.table.httpFollowRedirect" ) );
1062 getSink().tableCell_();
1063 getSink().tableCell();
1064 getSink().text( String.valueOf( httpFollowRedirect ) );
1065 getSink().tableCell_();
1066 getSink().tableRow_();
1067
1068 getSink().tableRow();
1069 getSink().tableCell();
1070 getSink()
1071 .rawText(
1072 i18n
1073 .getString( "linkcheck-report", locale, "report.linkcheck.summary.table.httpMethod" ) );
1074 getSink().tableCell_();
1075 getSink().tableCell();
1076 if ( StringUtils.isEmpty( httpMethod ) )
1077 {
1078 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
1079 }
1080 else
1081 {
1082 getSink().text( httpMethod );
1083 }
1084 getSink().tableCell_();
1085 getSink().tableRow_();
1086
1087 getSink().tableRow();
1088 getSink().tableCell();
1089 getSink().rawText(
1090 i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.offline" ) );
1091 getSink().tableCell_();
1092 getSink().tableCell();
1093 getSink().text( String.valueOf( offline ) );
1094 getSink().tableCell_();
1095 getSink().tableRow_();
1096
1097 getSink().tableRow();
1098 getSink().tableCell();
1099 getSink().rawText(
1100 i18n.getString( "linkcheck-report", locale,
1101 "report.linkcheck.summary.table.excludedPages" ) );
1102 getSink().tableCell_();
1103 getSink().tableCell();
1104 if ( getExcludedPages() == null || getExcludedPages().length == 0 )
1105 {
1106 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
1107 }
1108 else
1109 {
1110 getSink().text( StringUtils.join( getExcludedPages(), "," ) );
1111 }
1112 getSink().tableCell_();
1113 getSink().tableRow_();
1114
1115 getSink().tableRow();
1116 getSink().tableCell();
1117 getSink().rawText(
1118 i18n.getString( "linkcheck-report", locale,
1119 "report.linkcheck.summary.table.excludedLinks" ) );
1120 getSink().tableCell_();
1121 getSink().tableCell();
1122 if ( excludedLinks == null || excludedLinks.length == 0 )
1123 {
1124 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
1125 }
1126 else
1127 {
1128 getSink().text( StringUtils.join( excludedLinks, "," ) );
1129 }
1130 getSink().tableCell_();
1131 getSink().tableRow_();
1132
1133 getSink().tableRow();
1134 getSink().tableCell();
1135 getSink().rawText(
1136 i18n.getString( "linkcheck-report", locale,
1137 "report.linkcheck.summary.table.excludedHttpStatusErrors" ) );
1138 getSink().tableCell_();
1139 getSink().tableCell();
1140 if ( excludedHttpStatusErrors == null || excludedHttpStatusErrors.length == 0 )
1141 {
1142 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
1143 }
1144 else
1145 {
1146 getSink().text( toString( excludedHttpStatusErrors ) );
1147 }
1148 getSink().tableCell_();
1149 getSink().tableRow_();
1150
1151 getSink().tableRow();
1152 getSink().tableCell();
1153 getSink().rawText(
1154 i18n.getString( "linkcheck-report", locale,
1155 "report.linkcheck.summary.table.excludedHttpStatusWarnings" ) );
1156 getSink().tableCell_();
1157 getSink().tableCell();
1158 if ( excludedHttpStatusWarnings == null || excludedHttpStatusWarnings.length == 0 )
1159 {
1160 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
1161 }
1162 else
1163 {
1164 getSink().text( toString( excludedHttpStatusWarnings ) );
1165 }
1166 getSink().tableCell_();
1167 getSink().tableRow_();
1168
1169 getSink().table_();
1170
1171
1172 getSink().paragraph();
1173 getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.overview2" ) );
1174 getSink().paragraph_();
1175
1176 getSink().table();
1177
1178
1179 generateTableHeader( locale, false );
1180
1181
1182 getSink().tableRow();
1183
1184 getSink().tableCell();
1185 getSink().bold();
1186 getSink().text( totalFiles + "" );
1187 getSink().bold_();
1188 getSink().tableCell_();
1189 getSink().tableCell();
1190 getSink().bold();
1191 getSink().text( totalLinks + "" );
1192 getSink().bold_();
1193 getSink().tableCell_();
1194 getSink().tableCell();
1195 getSink().bold();
1196 getSink().text( String.valueOf( totalValidLinks ) );
1197 getSink().bold_();
1198 getSink().tableCell_();
1199 getSink().tableCell();
1200 getSink().bold();
1201 getSink().text( String.valueOf( totalWarningLinks ) );
1202 getSink().bold_();
1203 getSink().tableCell_();
1204 getSink().tableCell();
1205 getSink().bold();
1206 getSink().text( String.valueOf( totalErrorLinks ) );
1207 getSink().bold_();
1208 getSink().tableCell_();
1209
1210 getSink().tableRow_();
1211
1212 getSink().table_();
1213
1214 getSink().section1_();
1215 }
1216
1217 private void generateDetailsSection( Locale locale, LinkcheckModel linkcheckModel )
1218 {
1219 getSink().section1();
1220 getSink().sectionTitle1();
1221 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.detail" ) );
1222 getSink().sectionTitle1_();
1223
1224 getSink().paragraph();
1225 getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.detail.overview" ) );
1226 getSink().paragraph_();
1227
1228 getSink().table();
1229
1230
1231 generateTableHeader( locale, true );
1232
1233
1234 List linkcheckFiles = linkcheckModel.getFiles();
1235 for ( Iterator it = linkcheckFiles.iterator(); it.hasNext(); )
1236 {
1237 LinkcheckFile linkcheckFile = (LinkcheckFile) it.next();
1238
1239 getSink().tableRow();
1240
1241 getSink().tableCell();
1242 if ( linkcheckFile.getUnsuccessful() == 0 )
1243 {
1244 iconValid( locale );
1245 }
1246 else
1247 {
1248 iconError( locale );
1249 }
1250 getSink().tableCell_();
1251
1252
1253
1254 getSink().tableCell();
1255 getSink().link( linkcheckFile.getRelativePath() );
1256 getSink().text( linkcheckFile.getRelativePath() );
1257 getSink().link_();
1258 getSink().tableCell_();
1259 getSink().tableCell();
1260 getSink().text( String.valueOf( linkcheckFile.getNumberOfLinks() ) );
1261 getSink().tableCell_();
1262 getSink().tableCell();
1263 getSink().text( String.valueOf( linkcheckFile.getNumberOfLinks( LinkcheckFileResult.VALID_LEVEL ) ) );
1264 getSink().tableCell_();
1265 getSink().tableCell();
1266 getSink().text( String.valueOf( linkcheckFile.getNumberOfLinks( LinkcheckFileResult.WARNING_LEVEL ) ) );
1267 getSink().tableCell_();
1268 getSink().tableCell();
1269 getSink().text( String.valueOf( linkcheckFile.getNumberOfLinks( LinkcheckFileResult.ERROR_LEVEL ) ) );
1270 getSink().tableCell_();
1271
1272 getSink().tableRow_();
1273
1274
1275 if ( linkcheckFile.getUnsuccessful() != 0 )
1276 {
1277 getSink().tableRow();
1278
1279 getSink().tableCell();
1280 getSink().text( "" );
1281 getSink().tableCell_();
1282
1283
1284 getSink().rawText( "<td colspan=\"5\">" );
1285
1286 getSink().table();
1287
1288 for ( Iterator it2 = linkcheckFile.getResults().iterator(); it2.hasNext(); )
1289 {
1290 LinkcheckFileResult linkcheckFileResult = (LinkcheckFileResult) it2.next();
1291
1292 if ( linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.VALID_LEVEL )
1293 {
1294 continue;
1295 }
1296
1297 getSink().tableRow();
1298
1299 getSink().tableCell();
1300 if ( linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.WARNING_LEVEL )
1301 {
1302 iconWarning( locale );
1303 }
1304 else if ( linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.ERROR_LEVEL )
1305 {
1306 iconError( locale );
1307 }
1308 getSink().tableCell_();
1309
1310 getSink().tableCell();
1311 getSink().italic();
1312 if ( linkcheckFileResult.getTarget().startsWith( "#" ) )
1313 {
1314 getSink().link( linkcheckFile.getRelativePath() + linkcheckFileResult.getTarget() );
1315 }
1316 else if ( linkcheckFileResult.getTarget().startsWith( "." ) )
1317 {
1318
1319 String absolutePath = FilenameUtils.getFullPath( linkcheckFile.getRelativePath() )
1320 + linkcheckFileResult.getTarget();
1321 String normalizedPath = FilenameUtils.normalize( absolutePath );
1322 if ( normalizedPath == null )
1323 {
1324 normalizedPath = absolutePath;
1325 }
1326 getSink().link( normalizedPath );
1327 }
1328 else
1329 {
1330 getSink().link( linkcheckFileResult.getTarget() );
1331 }
1332
1333
1334 getSink().text( linkcheckFileResult.getTarget() );
1335 getSink().link_();
1336 getSink().text( ": " );
1337 getSink().text( linkcheckFileResult.getErrorMessage() );
1338 getSink().italic_();
1339 getSink().tableCell_();
1340
1341 getSink().tableRow_();
1342 }
1343
1344 getSink().table_();
1345
1346 getSink().tableCell_();
1347
1348 getSink().tableRow_();
1349 }
1350 }
1351
1352 getSink().table_();
1353
1354 getSink().section1_();
1355 }
1356
1357 private void generateTableHeader( Locale locale, boolean detail )
1358 {
1359 getSink().tableRow();
1360 if ( detail )
1361 {
1362 getSink().rawText( "<th rowspan=\"2\">" );
1363 getSink().text( "" );
1364 getSink().tableHeaderCell_();
1365 }
1366 getSink().rawText( "<th rowspan=\"2\">" );
1367 getSink().text(
1368 detail ? i18n.getString( "linkcheck-report", locale,
1369 "report.linkcheck.detail.table.documents" )
1370 : i18n.getString( "linkcheck-report", locale,
1371 "report.linkcheck.summary.table.documents" ) );
1372 getSink().tableHeaderCell_();
1373
1374 getSink().rawText( "<th colspan=\"4\" align=\"center\">" );
1375 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.table.links" ) );
1376 getSink().tableHeaderCell_();
1377 getSink().tableRow_();
1378
1379 getSink().tableRow();
1380 getSink().tableHeaderCell();
1381 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.table.totalLinks" ) );
1382 getSink().tableHeaderCell_();
1383 getSink().tableHeaderCell();
1384 iconValid( locale );
1385 getSink().tableHeaderCell_();
1386 getSink().tableHeaderCell();
1387 iconWarning( locale );
1388 getSink().tableHeaderCell_();
1389 getSink().tableHeaderCell();
1390 iconError( locale );
1391 getSink().tableHeaderCell_();
1392 getSink().tableRow_();
1393 }
1394
1395 private void iconError( Locale locale )
1396 {
1397 getSink().figure();
1398 getSink().figureCaption();
1399 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.error" ) );
1400 getSink().figureCaption_();
1401
1402 getSink().figureGraphics( "images/icon_error_sml.gif" );
1403 getSink().figure_();
1404 }
1405
1406 private void iconValid( Locale locale )
1407 {
1408 getSink().figure();
1409 getSink().figureCaption();
1410 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.valid" ) );
1411 getSink().figureCaption_();
1412
1413 getSink().figureGraphics( "images/icon_success_sml.gif" );
1414 getSink().figure_();
1415 }
1416
1417 private void iconWarning( Locale locale )
1418 {
1419 getSink().figure();
1420 getSink().figureCaption();
1421 getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.warning" ) );
1422 getSink().figureCaption_();
1423
1424 getSink().figureGraphics( "images/icon_warning_sml.gif" );
1425 getSink().figure_();
1426 }
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438 private static String toString( int[] a )
1439 {
1440 if ( a == null || a.length == 0 )
1441 {
1442 return "";
1443 }
1444
1445 StringBuffer buf = new StringBuffer();
1446 buf.append( a[0] );
1447
1448 for ( int i = 1; i < a.length; i++ )
1449 {
1450 buf.append( ", " );
1451 buf.append( a[i] );
1452 }
1453
1454 return buf.toString();
1455 }
1456 }