View Javadoc

1   package org.apache.maven.plugin.linkcheck;
2   
3   /* ====================================================================
4    *   Licensed to the Apache Software Foundation (ASF) under one or more
5    *   contributor license agreements.  See the NOTICE file distributed with
6    *   this work for additional information regarding copyright ownership.
7    *   The ASF licenses this file to You under the Apache License, Version 2.0
8    *   (the "License"); you may not use this file except in compliance with
9    *   the License.  You may obtain a copy of the License at
10   *
11   *       http://www.apache.org/licenses/LICENSE-2.0
12   *
13   *   Unless required by applicable law or agreed to in writing, software
14   *   distributed under the License is distributed on an "AS IS" BASIS,
15   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   *   See the License for the specific language governing permissions and
17   *   limitations under the License.
18   * ====================================================================
19   */
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.maven.jelly.MavenJellyContext;
24  import org.apache.maven.plugin.linkcheck.validation.FileLinkValidator;
25  import org.apache.maven.plugin.linkcheck.validation.LinkValidatorManager;
26  import org.apache.maven.plugin.linkcheck.validation.MailtoLinkValidator;
27  import org.apache.maven.plugin.linkcheck.validation.OfflineHTTPLinkValidator;
28  import org.apache.maven.plugin.linkcheck.validation.OnlineHTTPLinkValidator;
29  import org.apache.maven.project.Project;
30  
31  import java.io.File;
32  import java.io.FileNotFoundException;
33  import java.io.FileOutputStream;
34  import java.io.FilenameFilter;
35  import java.io.IOException;
36  import java.io.OutputStreamWriter;
37  import java.io.PrintWriter;
38  import java.io.UnsupportedEncodingException;
39  import java.util.Iterator;
40  import java.util.LinkedList;
41  import java.util.List;
42  import java.util.StringTokenizer;
43  
44  /**
45   * The main bean to be called whenever a set of documents should have their links checked.
46   * 
47   * @author <a href="mailto:bwalding@apache.org">Ben Walding</a>
48   * @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
49   * @author <a href="mailto:aheritier@apache.org">Arnaud Heritier</a>
50   * @version $Id: LinkCheck.java 532339 2007-04-25 12:28:56Z ltheussl $
51   */
52  public final class LinkCheck
53  {
54      /** Log */
55      private static final Log LOG = LogFactory.getLog( LinkCheck.class );
56  
57      private static final FilenameFilter CUSTOM_FF = new LinkCheck.CustomFilenameFilter();
58  
59      private static final long MEG = 1024 * 1024;
60  
61      private static final String MAVEN_PROXY_HOST = "maven.linkcheck.proxy.host";
62  
63      private static final String MAVEN_PROXY_PORT = "maven.linkcheck.proxy.port";
64  
65      private static final String MAVEN_PROXY_USERNAME = "maven.linkcheck.proxy.username";
66  
67      private static final String MAVEN_PROXY_PASSWORD = "maven.linkcheck.proxy.password";
68  
69      private static final String MAVEN_PROXY_NTLM_HOST = "maven.linkcheck.proxy.ntlm.host";
70  
71      private static final String MAVEN_PROXY_NTLM_DOMAIN = "maven.linkcheck.proxy.ntlm.domain";
72  
73      private File basedir;
74  
75      private String cache;
76  
77      private String exclude;
78  
79      private String method;
80  
81      private List filesToCheck = null;
82  
83      private LinkValidatorManager lvm = null;
84  
85      /**
86       * Output file for xml document
87       */
88      private File output;
89  
90      /**
91       * Output encoding for the xml document
92       */
93      private String outputEncoding;
94  
95      private Project project;
96  
97      /**
98       * Get the base directory for the change log generator.
99       * 
100      * @return the base directory
101      */
102     public File getBasedir()
103     {
104         return this.basedir;
105     }
106 
107     /**
108      * Set the base directory for the change log generator.
109      * 
110      * @param base
111      *            the base directory
112      */
113     public void setBasedir( File base )
114     {
115         this.basedir = base;
116     }
117 
118     /**
119      * Returns the cacheFile.
120      * 
121      * @return String
122      */
123     public String getCache()
124     {
125         return this.cache;
126     }
127 
128     /**
129      * Sets the cacheFile.
130      * 
131      * @param cacheFile
132      *            The cacheFile to set
133      */
134     public void setCache( String cache )
135     {
136         this.cache = cache;
137     }
138 
139     /**
140      * Returns the exclude.
141      * 
142      * @return String
143      */
144     public String getExclude()
145     {
146         return this.exclude;
147     }
148 
149     /**
150      * Sets the exclude, a string with exclude locations delimited by the space character, the comma character, the tab
151      * character, the newline character, the carriage-return character, and the form-feed character.
152      * 
153      * @param exclude
154      *            The exclude to set
155      */
156     public void setExclude( String exclude )
157     {
158         this.exclude = exclude;
159     }
160 
161     /**
162      * @return the method
163      */
164     public String getMethod()
165     {
166         return this.method;
167     }
168 
169     /**
170      * @param method
171      *            the method to set
172      */
173     public void setMethod( String method )
174     {
175         this.method = method;
176     }
177 
178     public List getFiles()
179     {
180         return this.filesToCheck;
181     }
182 
183     public LinkValidatorManager getLinkValidatorManager()
184     {
185         if ( this.lvm == null )
186         {
187             this.lvm = new LinkValidatorManager();
188             if ( this.exclude != null )
189             {
190                 StringTokenizer st = new StringTokenizer( this.exclude, " ,\t\n\r\f" );
191                 String[] tokens = new String[st.countTokens()];
192                 for ( int i = 0; i < tokens.length; i++ )
193                 {
194                     tokens[i] = st.nextToken();
195                 }
196                 this.lvm.setExcludes( tokens );
197                 tokens = null;
198                 st = null;
199             }
200             this.lvm.addLinkValidator( new FileLinkValidator() );
201             // Project is only null in test cases
202             if ( getProject() != null )
203             {
204                 MavenJellyContext ctx = ( (Project) getProject() ).getContext();
205                 if ( ctx.getOnline().booleanValue() )
206                 {
207                     this.lvm.addLinkValidator( new OnlineHTTPLinkValidator(
208                                                                        getMethod(),
209                                                                        (String) ctx.getVariable( MAVEN_PROXY_HOST ),
210                                                                        (String) ctx.getVariable( MAVEN_PROXY_PORT ),
211                                                                        (String) ctx.getVariable( MAVEN_PROXY_USERNAME ),
212                                                                        (String) ctx.getVariable( MAVEN_PROXY_PASSWORD ),
213                                                                        (String) ctx.getVariable( MAVEN_PROXY_NTLM_HOST ),
214                                                                        (String) ctx.getVariable( MAVEN_PROXY_NTLM_DOMAIN ) ) );
215                 }
216                 else
217                 {
218                     this.lvm.addLinkValidator( new OfflineHTTPLinkValidator() );
219 
220                 }
221                 ctx = null;
222             }
223             this.lvm.addLinkValidator( new MailtoLinkValidator() );
224         }
225         return this.lvm;
226     }
227 
228     /**
229      * Set the output file for the log.
230      * 
231      * @param output
232      *            the output file
233      */
234     public void setOutput( File output )
235     {
236         this.output = output;
237     }
238 
239     /**
240      * Returns the outputEncoding.
241      * 
242      * @return String
243      */
244     public String getOutputEncoding()
245     {
246         return this.outputEncoding;
247     }
248 
249     /**
250      * Sets the outputEncoding.
251      * 
252      * @param outputEncoding
253      *            The outputEncoding to set
254      */
255     public void setOutputEncoding( String outputEncoding )
256     {
257         this.outputEncoding = outputEncoding;
258     }
259 
260     /**
261      * @return Project
262      */
263     public Object getProject()
264     {
265         return this.project;
266     }
267 
268     /**
269      * Sets the project.
270      * 
271      * @param project
272      *            The project to set
273      */
274     public void setProject( Object project )
275     {
276         this.project = (Project) project;
277     }
278 
279     public void findFiles( List allFiles, File base )
280     {
281         File[] f = base.listFiles( CUSTOM_FF );
282         if ( f != null )
283         {
284             File file;
285             for ( int i = 0; i < f.length; i++ )
286             {
287                 file = f[i];
288                 if ( file.isDirectory() )
289                 {
290                     findFiles( allFiles, file );
291                 }
292                 else
293                 {
294                     if ( LOG.isDebugEnabled() )
295                     {
296                         LOG.debug( " File - " + file );
297                     }
298                     allFiles.add( new FileToCheck( this.basedir, file ) );
299                     if ( allFiles.size() % 100 == 0 )
300                     {
301                         LOG.info( "Found " + allFiles.size() + " files so far." );
302                     }
303                 }
304             }
305             file = null;
306         }
307         f = null;
308     }
309 
310     /**
311      * Execute task.
312      * 
313      * @throws FileNotFoundException
314      *             if {@link ChangeLog#base} doesn't exist
315      * @throws IOException
316      *             if there are problems running CVS
317      * @throws UnsupportedEncodingException
318      *             if the underlying platform doesn't support ISO-8859-1 encoding
319      */
320 
321     public void doExecute() throws FileNotFoundException, IOException, UnsupportedEncodingException
322     {
323         if ( this.output == null )
324         {
325             throw new NullPointerException( "output must be set" );
326         }
327         if ( LOG.isDebugEnabled() )
328         {
329             displayMemoryConsumption();
330         }
331         LinkValidatorManager validator = getLinkValidatorManager();
332         this.filesToCheck = new LinkedList();
333         validator.loadCache( this.cache );
334         List files = new LinkedList();
335         LOG.debug( "Locating all files to be checked..." );
336         findFiles( files, this.basedir );
337         LOG.debug( "Located all files to be checked." );
338         LOG.info( "Found " + files.size() + " files to check." );
339         displayMemoryConsumption();
340         LOG.info( "Begin to check links in files..." );
341         Iterator fileIter = files.iterator();
342         FileToCheck flc;
343         while ( fileIter.hasNext() )
344         {
345             flc = (FileToCheck) fileIter.next();
346             try
347             {
348                 this.filesToCheck.add( flc );
349                 flc.check( validator );
350             }
351             catch ( Exception e )
352             {
353                 LOG.error( "Error while checking : " + flc.getName(), e );
354             }
355         }
356         flc = null;
357         LOG.info( "Links checked." );
358         displayMemoryConsumption();
359         createDocument( files );
360         validator.saveCache( this.cache );
361         displayMemoryConsumption();
362     }
363 
364     public String toXML()
365     {
366         StringBuffer buf = new StringBuffer();
367         buf.append( "<linkcheck>\n" );
368         FileToCheck ftc;
369         for ( Iterator iter = getFiles().iterator(); iter.hasNext(); )
370         {
371             ftc = (FileToCheck) iter.next();
372             buf.append( ftc.toXML() );
373         }
374         ftc = null;
375         buf.append( "</linkcheck>\n" );
376         return buf.toString();
377     }
378 
379     private void displayMemoryConsumption()
380     {
381         if ( LOG.isDebugEnabled() )
382         {
383             Runtime r = Runtime.getRuntime();
384             LOG.debug( "Memory: " + ( r.totalMemory() - r.freeMemory() ) / MEG + "M/" + r.totalMemory() / MEG
385                             + "M" );
386         }
387     }
388 
389     /**
390      * Create the XML document from the currently available details
391      * 
392      * @throws FileNotFoundException
393      *             when the output file previously provided does not exist
394      * @throws UnsupportedEncodingException
395      *             when the platform doesn't support ISO-8859-1 encoding
396      */
397     private void createDocument( List files ) throws FileNotFoundException, UnsupportedEncodingException
398 
399     {
400         File dir = this.output.getParentFile();
401         if ( dir != null )
402         {
403             dir.mkdirs();
404         }
405         PrintWriter out =
406             new PrintWriter( new OutputStreamWriter( new FileOutputStream( this.output ), getOutputEncoding() ) );
407         StringBuffer buffer = new StringBuffer();
408         buffer.append( "<?xml version=\"1.0\" encoding=\"" ).append( getOutputEncoding() ).append( "\" ?>\n" );
409         out.write( buffer.toString() );
410         out.write( toXML() );
411         out.close();
412         out = null;
413         buffer = null;
414         dir = null;
415     }
416 
417     /** Custom FilenameFilter used to search html files */
418     static class CustomFilenameFilter implements FilenameFilter
419     {
420         /**
421          * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
422          */
423         public boolean accept( File dir, String name )
424         {
425             File n = new File( dir, name );
426             if ( n.isDirectory() )
427             {
428                 return true;
429             }
430             if ( name.endsWith( ".html" ) )
431             {
432                 return true;
433             }
434             return false;
435         }
436     }
437 
438 }