package org.apache.maven.plugin.linkcheck;
/* ====================================================================
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ====================================================================
*/
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.maven.jelly.MavenJellyContext;
import org.apache.maven.plugin.linkcheck.validation.FileLinkValidator;
import org.apache.maven.plugin.linkcheck.validation.LinkValidatorManager;
import org.apache.maven.plugin.linkcheck.validation.MailtoLinkValidator;
import org.apache.maven.plugin.linkcheck.validation.OfflineHTTPLinkValidator;
import org.apache.maven.plugin.linkcheck.validation.OnlineHTTPLinkValidator;
import org.apache.maven.project.Project;
/**
* The main bean to be called whenever a set of documents should have
* their links checked.
*
* @author <a href="mailto:bwalding@apache.org">Ben Walding</a>
* @author <a href="mailto:carlos@apache.org">Carlos Sanchez</a>
* @author <a href="mailto:aheritier@apache.org">Arnaud Heritier</a>
* @version $Id: LinkCheck.java 374800 2006-02-04 00:59:13Z aheritier $
*/
public final class LinkCheck
{
/** Log */
private static final Log LOG = LogFactory.getLog( LinkCheck.class );
private static final FilenameFilter CUSTOM_FF = new LinkCheck.CustomFilenameFilter();
private static final long MEG = 1024 * 1024;
private static final String MAVEN_PROXY_HOST = "maven.linkcheck.proxy.host";
private static final String MAVEN_PROXY_PORT = "maven.linkcheck.proxy.port";
private static final String MAVEN_PROXY_USERNAME = "maven.linkcheck.proxy.username";
private static final String MAVEN_PROXY_PASSWORD = "maven.linkcheck.proxy.password";
private static final String MAVEN_PROXY_NTLM_HOST = "maven.linkcheck.proxy.ntlm.host";
private static final String MAVEN_PROXY_NTLM_DOMAIN = "maven.linkcheck.proxy.ntlm.domain";
private File basedir;
private String cache;
private String exclude;
private String method;
private List filesToCheck = null;
private LinkValidatorManager lvm = null;
/**
* Output file for xml document
*/
private File output;
/**
* Output encoding for the xml document
*/
private String outputEncoding;
private Project project;
/**
* Get the base directory for the change log generator.
*
* @return the base directory
*/
public File getBasedir()
{
return basedir;
}
/**
* Set the base directory for the change log generator.
* @param base the base directory
*/
public void setBasedir( File base )
{
this.basedir = base;
}
/**
* Returns the cacheFile.
* @return String
*/
public String getCache()
{
return cache;
}
/**
* Sets the cacheFile.
* @param cacheFile The cacheFile to set
*/
public void setCache( String cache )
{
this.cache = cache;
}
/**
* Returns the exclude.
* @return String
*/
public String getExclude()
{
return exclude;
}
/**
* Sets the exclude, a string with exclude locations delimited by the space
* character, the comma character, the tab character, the newline character,
* the carriage-return character, and the form-feed character.
*
* @param exclude
* The exclude to set
*/
public void setExclude( String exclude )
{
this.exclude = exclude;
}
/**
* @return the method
*/
public String getMethod()
{
return method;
}
/**
* @param method the method to set
*/
public void setMethod( String method )
{
this.method = method;
}
public List getFiles()
{
return filesToCheck;
}
public LinkValidatorManager getLinkValidatorManager()
{
if ( lvm == null )
{
lvm = new LinkValidatorManager();
if ( exclude != null )
{
StringTokenizer st = new StringTokenizer( exclude, " ,\t\n\r\f" );
String[] tokens = new String[st.countTokens()];
for ( int i = 0; i < tokens.length; i++ )
{
tokens[i] = st.nextToken();
}
lvm.setExcludes( tokens );
tokens = null;
st = null;
}
lvm.addLinkValidator( new FileLinkValidator() );
// Project is only null in test cases
if ( getProject() != null )
{
MavenJellyContext ctx = ( (Project) getProject() ).getContext();
if ( ctx.getOnline().booleanValue() )
{
lvm
.addLinkValidator( new OnlineHTTPLinkValidator(
getMethod(),
(String) ctx.getVariable( MAVEN_PROXY_HOST ),
(String) ctx.getVariable( MAVEN_PROXY_PORT ),
(String) ctx.getVariable( MAVEN_PROXY_USERNAME ),
(String) ctx.getVariable( MAVEN_PROXY_PASSWORD ),
(String) ctx
.getVariable( MAVEN_PROXY_NTLM_HOST ),
(String) ctx
.getVariable( MAVEN_PROXY_NTLM_DOMAIN ) ) );
}
else
{
lvm.addLinkValidator( new OfflineHTTPLinkValidator() );
}
ctx = null;
}
lvm.addLinkValidator( new MailtoLinkValidator() );
}
return lvm;
}
/**
* Set the output file for the log.
* @param output the output file
*/
public void setOutput( File output )
{
this.output = output;
}
/**
* Returns the outputEncoding.
* @return String
*/
public String getOutputEncoding()
{
return outputEncoding;
}
/**
* Sets the outputEncoding.
* @param outputEncoding The outputEncoding to set
*/
public void setOutputEncoding( String outputEncoding )
{
this.outputEncoding = outputEncoding;
}
/**
* @return Project
*/
public Object getProject()
{
return project;
}
/**
* Sets the project.
* @param project The project to set
*/
public void setProject( Object project )
{
this.project = (Project) project;
}
public void findFiles( List allFiles, File base )
{
File[] f = base.listFiles( CUSTOM_FF );
if ( f != null )
{
File file;
for ( int i = 0; i < f.length; i++ )
{
file = f[i];
if ( file.isDirectory() )
{
findFiles( allFiles, file );
}
else
{
if ( LOG.isDebugEnabled() )
{
LOG.debug( " File - " + file );
}
allFiles.add( new FileToCheck( basedir, file ) );
if ( allFiles.size() % 100 == 0 )
{
LOG.info( "Found " + allFiles.size() + " files so far." );
}
}
}
file = null;
}
f = null;
}
/**
* Execute task.
* @throws FileNotFoundException if {@link ChangeLog#base} doesn't exist
* @throws IOException if there are problems running CVS
* @throws UnsupportedEncodingException if the underlying platform doesn't
* support ISO-8859-1 encoding
*/
public void doExecute()
throws FileNotFoundException, IOException, UnsupportedEncodingException
{
if ( output == null )
{
throw new NullPointerException( "output must be set" );
}
if ( LOG.isDebugEnabled() )
{
displayMemoryConsumption();
}
LinkValidatorManager validator = getLinkValidatorManager();
filesToCheck = new LinkedList();
validator.loadCache( cache );
List files = new LinkedList();
LOG.debug( "Locating all files to be checked..." );
findFiles( files, basedir );
LOG.debug( "Located all files to be checked." );
LOG.info( "Found " + files.size() + " files to check." );
displayMemoryConsumption();
LOG.info( "Begin to check links in files..." );
Iterator fileIter = files.iterator();
FileToCheck flc;
while ( fileIter.hasNext() )
{
flc = (FileToCheck) fileIter.next();
try
{
filesToCheck.add( flc );
flc.check( validator );
}
catch ( Exception e )
{
LOG.error( "Error while checking : " + flc.getName(), e );
}
}
flc = null;
LOG.info( "Links checked." );
displayMemoryConsumption();
createDocument( files );
validator.saveCache( cache );
displayMemoryConsumption();
}
public String toXML()
{
StringBuffer buf = new StringBuffer();
buf.append( "<linkcheck>\n" );
FileToCheck ftc;
for ( Iterator iter = getFiles().iterator(); iter.hasNext(); )
{
ftc = (FileToCheck) iter.next();
buf.append( ftc.toXML() );
}
ftc = null;
buf.append( "</linkcheck>\n" );
return buf.toString();
}
private void displayMemoryConsumption()
{
if ( LOG.isDebugEnabled() )
{
Runtime r = Runtime.getRuntime();
LOG.debug( "Memory: " + ( ( r.totalMemory() - r.freeMemory() ) / MEG ) + "M/" + ( r.totalMemory() / MEG )
+ "M" );
}
}
/**
* Create the XML document from the currently available details
* @throws FileNotFoundException when the output file previously provided
* does not exist
* @throws UnsupportedEncodingException when the platform doesn't support
* ISO-8859-1 encoding
*/
private void createDocument( List files )
throws FileNotFoundException, UnsupportedEncodingException
{
File dir = output.getParentFile();
if ( dir != null )
{
dir.mkdirs();
}
PrintWriter out = new PrintWriter( new OutputStreamWriter( new FileOutputStream( output ), getOutputEncoding() ) );
StringBuffer buffer = new StringBuffer();
buffer.append( "<?xml version=\"1.0\" encoding=\"" ).append( getOutputEncoding() ).append( "\" ?>\n" );
out.write( buffer.toString() );
out.write( toXML() );
out.close();
out = null;
buffer = null;
dir = null;
}
/** Custom FilenameFilter used to search html files */
static class CustomFilenameFilter
implements FilenameFilter
{
/**
* @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
*/
public boolean accept( File dir, String name )
{
File n = new File( dir, name );
if ( n.isDirectory() )
return true;
if ( name.endsWith( ".html" ) )
{
return true;
}
return false;
}
}
}