1 package org.apache.maven.plugin.linkcheck;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
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 }