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 org.apache.maven.artifact.repository.ArtifactRepository;
23  import org.apache.maven.doxia.linkcheck.HttpBean;
24  import org.apache.maven.doxia.linkcheck.LinkCheck;
25  import org.apache.maven.doxia.linkcheck.LinkCheckException;
26  import org.apache.maven.doxia.linkcheck.model.LinkcheckModel;
27  import org.apache.maven.plugin.MojoExecutionException;
28  import org.apache.maven.plugins.annotations.Component;
29  import org.apache.maven.plugins.annotations.Mojo;
30  import org.apache.maven.plugins.annotations.Parameter;
31  import org.apache.maven.reporting.AbstractMavenReport;
32  import org.apache.maven.reporting.MavenReportException;
33  import org.apache.maven.settings.Proxy;
34  import org.apache.maven.settings.Settings;
35  import org.codehaus.plexus.i18n.I18N;
36  import org.codehaus.plexus.util.FileUtils;
37  import org.codehaus.plexus.util.ReaderFactory;
38  import org.codehaus.plexus.util.StringUtils;
39  
40  import java.io.File;
41  import java.io.IOException;
42  import java.net.URL;
43  import java.util.ArrayList;
44  import java.util.Arrays;
45  import java.util.List;
46  import java.util.Locale;
47  import java.util.Properties;
48  
49  
50  
51  
52  
53  
54  
55  
56  @Mojo( name = "linkcheck" )
57  public class LinkcheckReport
58      extends AbstractMavenReport
59  {
60      
61      
62      
63  
64      
65  
66  
67      @Component
68      private I18N i18n;
69  
70      
71  
72  
73      @Component
74      private LinkCheck linkCheck;
75  
76      
77      
78      
79  
80      
81  
82  
83      @Parameter( defaultValue = "${localRepository}", required = true, readonly = true )
84      private ArtifactRepository localRepository;
85  
86      
87  
88  
89      @Parameter( defaultValue = "${settings}", readonly = true, required = true )
90      private Settings settings;
91  
92      
93      
94      
95  
96      
97  
98  
99      @Parameter( property = "linkcheck.offline", defaultValue = "${settings.offline}", required = true )
100     private boolean offline;
101 
102     
103 
104 
105 
106 
107 
108     @Parameter( defaultValue = "true" )
109     private boolean httpFollowRedirect;
110 
111     
112 
113 
114     @Parameter( defaultValue = "${project.build.directory}/linkcheck/linkcheck.cache", required = true )
115     protected File linkcheckCache;
116 
117     
118 
119 
120     @Parameter( defaultValue = "${project.build.directory}/linkcheck/linkcheck.xml", required = true )
121     protected File linkcheckOutput;
122 
123     
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142     @Parameter( defaultValue = "head", required = true )
143     private String httpMethod;
144 
145     
146 
147 
148 
149 
150     @Parameter
151     private Integer[] excludedHttpStatusErrors;
152 
153     
154 
155 
156 
157 
158     @Parameter
159     private Integer[] excludedHttpStatusWarnings;
160 
161     
162 
163 
164 
165 
166 
167 
168 
169 
170 
171     @Parameter
172     private String[] excludedPages;
173 
174     
175 
176 
177 
178 
179     @Parameter
180     private String[] excludedLinks;
181 
182     
183 
184 
185 
186     @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
187     private String encoding;
188 
189     
190 
191 
192 
193 
194 
195 
196 
197 
198 
199 
200 
201     @Parameter( property = "httpClientParameters" )
202     private Properties httpClientParameters;
203 
204     
205 
206 
207     @Parameter( property = "timeout", defaultValue = "2000" )
208     private int timeout;
209 
210     
211 
212 
213 
214     @Parameter( property = "linkcheck.skip", defaultValue = "false" )
215     private boolean skip;
216 
217     
218 
219 
220 
221     @Parameter( property = "linkcheck.forceSite", defaultValue = "true" )
222     private boolean forceSite;
223 
224     
225 
226 
227     @Parameter( property = "linkcheck.baseURL", defaultValue = "${project.url}" )
228     private String baseURL;
229 
230     
231     
232     
233 
234     
235     private LinkcheckModel result;
236 
237     protected static final String ICON_SUCCESS = "images/icon_success_sml.gif";
238     protected static final String ICON_WARNING = "images/icon_warning_sml.gif";
239     protected static final String ICON_INFO = "images/icon_info_sml.gif";
240     protected static final String ICON_ERROR = "images/icon_error_sml.gif";
241     private static final String pluginResourcesBase = "org/apache/maven/plugin/linkcheck";
242     private static final String resourceNames[] = { ICON_SUCCESS, ICON_WARNING, ICON_INFO, ICON_ERROR };
243 
244     
245     
246     
247 
248     
249     public String getDescription( Locale locale )
250     {
251         return i18n.getString( "linkcheck-report", locale, "report.linkcheck.description" );
252     }
253 
254     
255     public String getName( Locale locale )
256     {
257         return i18n.getString( "linkcheck-report", locale, "report.linkcheck.name" );
258     }
259 
260     
261     public String getOutputName()
262     {
263         return "linkcheck";
264     }
265 
266     
267     public boolean canGenerateReport()
268     {
269         return !skip;
270     }
271 
272     
273     public void execute()
274         throws MojoExecutionException
275     {
276         if ( !canGenerateReport() )
277         {
278             return;
279         }
280 
281         checkEncoding();
282 
283         try
284         {
285             result = executeLinkCheck( getBasedir() );
286         }
287         catch ( LinkCheckException e )
288         {
289             throw new MojoExecutionException( "LinkCheckException: " + e.getMessage(), e );
290         }
291     }
292 
293     
294     
295     
296 
297     
298     protected void executeReport( Locale locale )
299         throws MavenReportException
300     {
301         if ( result == null )
302         {
303             getLog().debug( "Calling execute()" );
304 
305             try
306             {
307                 this.execute();
308             }
309             catch ( MojoExecutionException e )
310             {
311                 throw new MavenReportException( "MojoExecutionException: " + e.getMessage(), e );
312             }
313         }
314 
315         if ( result != null )
316         {
317             generateReport( locale, result );
318             
319             result = null;
320         }
321     }
322 
323     
324     
325     
326 
327     private void checkEncoding()
328     {
329         if ( StringUtils.isEmpty( encoding ) )
330         {
331             if ( getLog().isWarnEnabled() )
332             {
333                 getLog().warn( "File encoding has not been set, using platform encoding "
334                     + ReaderFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
335             }
336 
337             encoding = ReaderFactory.FILE_ENCODING;
338         }
339     }
340 
341     private File getBasedir()
342         throws MojoExecutionException
343     {
344         File basedir;
345 
346         if ( forceSite )
347         {
348             basedir = new File( linkcheckOutput.getParentFile(), "tmpsite" );
349             basedir.mkdirs();
350 
351             List documents = null;
352             try
353             {
354                 documents = FileUtils.getFiles( basedir, "**/*.html", null );
355             }
356             catch ( IOException e )
357             {
358                 getLog().error( "IOException: " + e.getMessage() );
359                 getLog().debug( e );
360             }
361 
362             
363             if ( documents == null || ( documents != null && documents.size() == 0 ) )
364             {
365                 getLog().info( "Invoking the maven-site-plugin to ensure that all files are generated..." );
366 
367                 try
368                 {
369                     SiteInvoker invoker = new SiteInvoker( localRepository, getLog() );
370                     invoker.invokeSite( project, basedir );
371                 }
372                 catch ( IOException e )
373                 {
374                     throw new MojoExecutionException( "IOException: " + e.getMessage(), e );
375                 }
376             }
377         }
378         else
379         {
380             getLog().warn( "The number of documents analyzed by Linkcheck could differ from the actual "
381                                    + "number of documents!" );
382 
383             basedir = outputDirectory;
384             basedir.mkdirs();
385         }
386 
387         return basedir;
388     }
389 
390     
391 
392 
393 
394 
395 
396     private LinkcheckModel executeLinkCheck( File basedir )
397         throws LinkCheckException
398     {
399         
400         linkCheck.setOnline( !offline );
401         linkCheck.setBasedir( basedir );
402         linkCheck.setBaseURL( baseURL );
403         linkCheck.setReportOutput( linkcheckOutput );
404         linkCheck.setLinkCheckCache( linkcheckCache );
405         linkCheck.setExcludedLinks( excludedLinks );
406         linkCheck.setExcludedPages( getExcludedPages() );
407         linkCheck.setExcludedHttpStatusErrors( asIntArray( excludedHttpStatusErrors ) );
408         linkCheck.setExcludedHttpStatusWarnings( asIntArray( excludedHttpStatusWarnings ) );
409         linkCheck.setEncoding( ( StringUtils.isNotEmpty( encoding ) ? encoding : ReaderFactory.UTF_8 ) );
410 
411         HttpBean bean = new HttpBean();
412         bean.setMethod( httpMethod );
413         bean.setFollowRedirects( httpFollowRedirect );
414         bean.setTimeout( timeout );
415         if ( httpClientParameters != null )
416         {
417             bean.setHttpClientParameters( httpClientParameters );
418         }
419 
420         Proxy proxy = settings.getActiveProxy();
421         if ( proxy != null )
422         {
423             bean.setProxyHost( proxy.getHost() );
424             bean.setProxyPort( proxy.getPort() );
425             bean.setProxyUser( proxy.getUsername() );
426             bean.setProxyPassword( proxy.getPassword() );
427         }
428         linkCheck.setHttp( bean );
429 
430         return linkCheck.execute();
431     }
432 
433     
434 
435 
436     private String[] getExcludedPages()
437     {
438         List pagesToExclude =
439             ( excludedPages != null ? new ArrayList( Arrays.asList( excludedPages ) ) : new ArrayList() );
440 
441         
442         pagesToExclude.add( getOutputName() + ".html" );
443 
444         return (String[]) pagesToExclude.toArray(new String[pagesToExclude.size()]);
445     }
446 
447     
448     
449     
450 
451     private void generateReport( Locale locale, LinkcheckModel linkcheckModel )
452     {
453         LinkcheckReportGenerator reportGenerator = new LinkcheckReportGenerator( i18n );
454 
455         reportGenerator.setExcludedHttpStatusErrors( excludedHttpStatusErrors );
456         reportGenerator.setExcludedHttpStatusWarnings( excludedHttpStatusWarnings );
457         reportGenerator.setExcludedLinks( excludedLinks );
458         reportGenerator.setExcludedPages( excludedPages );
459         reportGenerator.setHttpFollowRedirect( httpFollowRedirect );
460         reportGenerator.setHttpMethod( httpMethod );
461         reportGenerator.setOffline( offline );
462 
463         reportGenerator.generateReport( locale, linkcheckModel, getSink() );
464         closeReport();
465 
466         
467         copyStaticResources();
468     }
469 
470     private void copyStaticResources()
471     {
472         try
473         {
474             getLog().debug( "Copying static linkcheck resources." );
475             for (String resourceName : resourceNames) {
476                 URL url = this.getClass().getClassLoader().getResource(pluginResourcesBase + "/" + resourceName);
477                 FileUtils.copyURLToFile(url, new File(getReportOutputDirectory(), resourceName));
478             }
479         }
480         catch ( IOException e )
481         {
482             getLog().error( "Unable to copy icons for linkcheck report." );
483             getLog().debug( e );
484         }
485     }
486 
487     private static int[] asIntArray( Integer[] array )
488     {
489         if ( array == null )
490         {
491             return null;
492         }
493 
494         int[] newArray = new int[array.length];
495 
496         for ( int i = 0; i < array.length; i++ )
497         {
498             newArray[i] = array[i];
499         }
500 
501         return newArray;
502     }
503 }