org.apache.maven.plugins.linkcheck.LinkcheckReport Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of maven-linkcheck-plugin Show documentation
Show all versions of maven-linkcheck-plugin Show documentation
This plugin allows you to generate a linkcheck report of your project's documentation.
package org.apache.maven.plugins.linkcheck;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.SystemUtils;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.doxia.linkcheck.HttpBean;
import org.apache.maven.doxia.linkcheck.LinkCheck;
import org.apache.maven.doxia.linkcheck.LinkCheckException;
import org.apache.maven.doxia.linkcheck.model.LinkcheckFile;
import org.apache.maven.doxia.linkcheck.model.LinkcheckFileResult;
import org.apache.maven.doxia.linkcheck.model.LinkcheckModel;
import org.apache.maven.doxia.siterenderer.Renderer;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.reporting.AbstractMavenReport;
import org.apache.maven.reporting.MavenReportException;
import org.apache.maven.settings.Proxy;
import org.apache.maven.settings.Settings;
import org.apache.maven.shared.invoker.DefaultInvocationRequest;
import org.apache.maven.shared.invoker.DefaultInvoker;
import org.apache.maven.shared.invoker.InvocationOutputHandler;
import org.apache.maven.shared.invoker.InvocationRequest;
import org.apache.maven.shared.invoker.InvocationResult;
import org.apache.maven.shared.invoker.Invoker;
import org.apache.maven.shared.invoker.MavenInvocationException;
import org.apache.maven.shared.invoker.PrintStreamHandler;
import org.codehaus.plexus.i18n.I18N;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.ReaderFactory;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.WriterFactory;
import org.codehaus.plexus.util.cli.CommandLineUtils;
/**
* Generates a Linkcheck
report.
*
* @author Vincent Siveton
* @version $Id: LinkcheckReport.java 981302 2010-08-01 20:00:29Z dennisl $
* @since 1.0
* @goal linkcheck
*/
public class LinkcheckReport
extends AbstractMavenReport
{
// ----------------------------------------------------------------------
// Report Components
// ----------------------------------------------------------------------
/**
* Internationalization.
*
* @component
*/
private I18N i18n;
/**
* Doxia Site Renderer.
*
* @component
*/
private Renderer siteRenderer;
/**
* LinkCheck component.
*
* @component
*/
private LinkCheck linkCheck;
// ----------------------------------------------------------------------
// Report Parameters
// ----------------------------------------------------------------------
/**
* The Maven Project.
*
* @parameter expression="${project}"
* @required
* @readonly
*/
private MavenProject project;
/**
* Local Repository.
*
* @parameter expression="${localRepository}"
* @required
* @readonly
*/
private ArtifactRepository localRepository;
/**
* Report output directory.
*
* @parameter expression="${project.reporting.outputDirectory}"
* @required
*/
private File outputDirectory;
/**
* The Maven Settings.
*
* @parameter default-value="${settings}"
* @required
* @readonly
*/
private Settings settings;
// ----------------------------------------------------------------------
// Linkcheck parameters
// ----------------------------------------------------------------------
/**
* Whether we are offline or not.
*
* @parameter default-value="${settings.offline}" expression="${linkcheck.offline}"
* @required
*/
private boolean offline;
/**
* If online, the HTTP method should automatically follow HTTP redirects,
* false otherwise.
*
* @parameter default-value="true"
*/
private boolean httpFollowRedirect;
/**
* The location of the Linkcheck cache file.
*
* @parameter default-value="${project.build.directory}/linkcheck/linkcheck.cache"
* @required
*/
protected File linkcheckCache;
/**
* The location of the Linkcheck report file.
*
* @parameter default-value="${project.build.directory}/linkcheck/linkcheck.xml"
* @required
*/
protected File linkcheckOutput;
/**
* The HTTP method to use. Currently supported are "GET" and "HEAD".
*
* - HTTP GET
* -
* The HTTP GET method is defined in section 9.3 of
* RFC2616:
* The GET method means retrieve whatever information (in the form of an
* entity) is identified by the Request-URI.
*
* - HTTP HEAD
* -
* The HTTP HEAD method is defined in section 9.4 of
* RFC2616:
* The HEAD method is identical to GET except that the server MUST NOT
* return a message-body in the response.
*
*
*
* @parameter default-value="head"
* @required
*/
private String httpMethod;
/**
* The list of HTTP errors to ignored, like 404
.
*
* @parameter
* @see {@link org.apache.commons.httpclient.HttpStatus} for all defined values.
*/
private int[] excludedHttpStatusErrors;
/**
* The list of HTTP warnings to ignored, like 301
.
*
* @parameter
* @see {@link org.apache.commons.httpclient.HttpStatus} for all defined values.
*/
private int[] excludedHttpStatusWarnings;
/**
* The list of site pages to exclude. By default, this report, i.e. linkcheck.html
, will be excluded.
*
* Note: No pattern is allowed for excludedPage, only specific file names.
*
* @parameter
*/
private String[] excludedPages;
/**
* The list of links to exclude.
*
* Note: Patterns like **/dummy/*
are allowed for excludedLink.
*
* @parameter
*/
private String[] excludedLinks;
/**
* The file encoding to use when Linkcheck reads the source files. If the property
* project.build.sourceEncoding
is not set, the platform default encoding is used.
*
* @parameter expression="${encoding}" default-value="${project.build.sourceEncoding}"
*/
private String encoding;
/**
* The extra HttpClient parameters to be used when fetching links. For instance:
*
* <httpClientParameters>
* <property>
* <name>http.protocol.max-redirects</name>
* <value>10</value>
* </property>
* </httpClientParameters>
*
* See HttpClient preference page
*
* @parameter expression="${httpClientParameters}"
*/
private Properties httpClientParameters;
/**
* Set the timeout to be used when fetching links. A value of zero means the timeout is not used.
*
* @parameter expression="${timeout}" default-value="2000"
*/
private int timeout;
/**
* true
to skip the report execution, false
otherwise.
* The purpose is to prevent infinite call when {@link #forceSite} is enable.
*
* @parameter expression="${linkcheck.skip}" default-value="false"
*/
private boolean skip;
/**
* true
to force the site generation, false
otherwise.
* Using this parameter ensures that all documents have been correctly generated.
*
* @parameter expression="${linkcheck.forceSite}" default-value="true"
*/
private boolean forceSite;
/**
* The base URL to use for absolute links (eg /index.html
) in the site.
*
* @parameter expression="${linkcheck.baseURL}" default-value="${project.url}"
*/
private String baseURL;
// ----------------------------------------------------------------------
// Instance fields
// ----------------------------------------------------------------------
/** Result of the linkcheck in {@link #execute()} */
private LinkcheckModel result;
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
/** {@inheritDoc} */
public String getDescription( Locale locale )
{
return i18n.getString( "linkcheck-report", locale, "report.linkcheck.description" );
}
/** {@inheritDoc} */
public String getName( Locale locale )
{
return i18n.getString( "linkcheck-report", locale, "report.linkcheck.name" );
}
/** {@inheritDoc} */
public String getOutputName()
{
return "linkcheck";
}
/** {@inheritDoc} */
public boolean canGenerateReport()
{
if ( skip )
{
return false;
}
return true;
}
/** {@inheritDoc} */
public void execute()
throws MojoExecutionException
{
if ( !canGenerateReport() )
{
return;
}
// encoding
if ( StringUtils.isEmpty( encoding ) )
{
if ( getLog().isWarnEnabled() )
{
getLog().warn(
"File encoding has not been set, using platform encoding "
+ ReaderFactory.FILE_ENCODING + ", i.e. build is platform dependent!" );
}
encoding = ReaderFactory.FILE_ENCODING;
}
File tmpReportingOutputDirectory = new File( linkcheckOutput.getParentFile(), "tmpsite" );
tmpReportingOutputDirectory.mkdirs();
File basedir;
if ( forceSite )
{
basedir = tmpReportingOutputDirectory;
List documents = null;
try
{
documents = FileUtils.getFiles( basedir, "**/*.html", null );
}
catch ( IOException e )
{
String msg = "IOException: " + e.getMessage();
if ( getLog().isDebugEnabled() )
{
getLog().error( msg, e );
}
else
{
getLog().error( msg );
}
}
// if the site was not already generated, invoke it
if ( documents == null || ( documents != null && documents.size() == 0 ) )
{
getLog().info( "Trying to invoke the maven-site-plugin to be sure that all files are generated..." );
try
{
invokeSite( tmpReportingOutputDirectory );
}
catch ( IOException e )
{
throw new MojoExecutionException( "IOException: " + e.getMessage(), e );
}
}
}
else
{
if ( getLog().isWarnEnabled() )
{
getLog().warn(
"WARRANTY: The number of documents analyzed by Linkcheck could differ with the real "
+ "number of documents!" );
}
basedir = outputDirectory;
basedir.mkdirs();
}
try
{
result = executeLinkCheck( basedir );
}
catch ( LinkCheckException e )
{
throw new MojoExecutionException( "LinkCheckException: " + e.getMessage(), e );
}
}
// ----------------------------------------------------------------------
// Protected methods
// ----------------------------------------------------------------------
/** {@inheritDoc} */
protected String getOutputDirectory()
{
return outputDirectory.getAbsolutePath();
}
/** {@inheritDoc} */
protected MavenProject getProject()
{
return project;
}
/** {@inheritDoc} */
protected Renderer getSiteRenderer()
{
return siteRenderer;
}
/** {@inheritDoc} */
protected void executeReport( Locale locale )
throws MavenReportException
{
if ( result == null )
{
getLog().debug( "Calling execute()" );
try
{
this.execute();
}
catch ( MojoExecutionException e )
{
throw new MavenReportException( "MojoExecutionException: " + e.getMessage(), e );
}
}
if ( result != null )
{
generateReport( locale, result );
// free memory
result = null;
}
}
// ----------------------------------------------------------------------
// Private methods
// ----------------------------------------------------------------------
/**
* Execute the Linkcheck
tool.
*
* @param basedir not null
* @throws LinkCheckException if any
*/
private LinkcheckModel executeLinkCheck( File basedir )
throws LinkCheckException
{
// Wrap linkcheck
linkCheck.setOnline( !offline );
linkCheck.setBasedir( basedir );
linkCheck.setBaseURL( baseURL );
linkCheck.setReportOutput( linkcheckOutput );
linkCheck.setLinkCheckCache( linkcheckCache );
linkCheck.setExcludedLinks( excludedLinks );
linkCheck.setExcludedPages( getExcludedPages() );
linkCheck.setExcludedHttpStatusErrors( excludedHttpStatusErrors );
linkCheck.setExcludedHttpStatusWarnings( excludedHttpStatusWarnings );
linkCheck.setEncoding( ( StringUtils.isNotEmpty( encoding ) ? encoding : WriterFactory.UTF_8 ) );
HttpBean bean = new HttpBean();
bean.setMethod( httpMethod );
bean.setFollowRedirects( httpFollowRedirect );
bean.setTimeout( timeout );
if ( httpClientParameters != null )
{
bean.setHttpClientParameters( httpClientParameters );
}
Proxy proxy = settings.getActiveProxy();
if ( proxy != null )
{
bean.setProxyHost( proxy.getHost() );
bean.setProxyPort( proxy.getPort() );
bean.setProxyUser( proxy.getUsername() );
bean.setProxyPassword( proxy.getPassword() );
}
linkCheck.setHttp( bean );
return linkCheck.execute();
}
/**
* @return the excludedPages defined by the user and also this report.
*/
private String[] getExcludedPages()
{
List pagesToExclude =
( excludedPages != null ? new ArrayList( Arrays.asList( excludedPages ) ) : new ArrayList() );
// Exclude this report
pagesToExclude.add( getOutputName() + ".html" );
return (String[]) pagesToExclude.toArray( new String[0] );
}
/**
* Invoke Maven for the site
phase for a temporary Maven project using tmpReportingOutputDirectory
* as ${project.reporting.outputDirectory}
. This is a workaround to be sure that all site files have been
* correctly generated.
*
* Note 1: the Maven Home should be defined in the maven.home
Java system property or defined in
* M2_HOME
system env variables.
* Note 2: we can't use siteOutputDirectory
param from site plugin because some plugins
* ${project.reporting.outputDirectory}
in there conf.
*
* @param tmpReportingOutputDirectory not null
* @throws IOException if any
*/
private void invokeSite( File tmpReportingOutputDirectory )
throws IOException
{
String mavenHome = getMavenHome();
if ( StringUtils.isEmpty( mavenHome ) )
{
if ( getLog().isErrorEnabled() )
{
String msg =
"Could NOT invoke Maven because no Maven Home is defined. You need to have set the M2_HOME "
+ "system env variable or a 'maven.home' Java system properties.";
getLog().error( msg );
}
return;
}
// invoker site parameters
List goals = Collections.singletonList( "site" );
Properties properties = new Properties();
properties.put( "linkcheck.skip", "true" ); // to stop recursion
File invokerLog =
FileUtils
.createTempFile( "invoker-site-plugin", ".txt", new File( project.getBuild().getDirectory() ) );
// clone project and set a new reporting output dir
MavenProject clone;
try
{
clone = (MavenProject) project.clone();
}
catch ( CloneNotSupportedException e )
{
IOException ioe = new IOException( "CloneNotSupportedException: " + e.getMessage() );
ioe.setStackTrace( e.getStackTrace() );
throw ioe;
}
clone.getOriginalModel().getReporting().setOutputDirectory( tmpReportingOutputDirectory.getAbsolutePath() );
// create the original model as tmp pom file for the invoker
File tmpProjectFile = FileUtils.createTempFile( "pom", ".xml", project.getBasedir() );
Writer writer = null;
try
{
writer = WriterFactory.newXmlWriter( tmpProjectFile );
clone.writeOriginalModel( writer );
}
finally
{
IOUtil.close( writer );
}
// invoke it
try
{
invoke( tmpProjectFile, invokerLog, mavenHome, goals, properties );
}
finally
{
if ( !getLog().isDebugEnabled() )
{
tmpProjectFile.delete();
}
}
}
/**
* @param projectFile not null, should be in the ${project.basedir}
* @param invokerLog not null
* @param mavenHome not null
* @param goals the list of goals
* @param properties the properties for the invoker
*/
private void invoke( File projectFile, File invokerLog, String mavenHome, List goals, Properties properties )
{
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome( new File( mavenHome ) );
invoker.setLocalRepositoryDirectory( new File( localRepository.getBasedir() ) );
InvocationRequest request = new DefaultInvocationRequest();
request.setBaseDirectory( projectFile.getParentFile() );
request.setPomFile( projectFile );
request.setDebug( getLog().isDebugEnabled() );
request.setGoals( goals );
request.setProperties( properties );
File javaHome = getJavaHome();
if ( javaHome != null )
{
request.setJavaHome( javaHome );
}
InvocationResult result;
try
{
if ( getLog().isDebugEnabled() )
{
getLog().debug( "Invoking Maven for the goals: " + goals + " with properties=" + properties );
}
result = invoke( invoker, request, invokerLog, goals, properties, null );
}
catch ( MavenInvocationException e )
{
if ( getLog().isDebugEnabled() )
{
getLog().error( "MavenInvocationException: " + e.getMessage(), e );
}
getLog().error( "Error when invoking Maven, consult the invoker log." );
return;
}
String invokerLogContent = null;
Reader reader = null;
try
{
reader = ReaderFactory.newReader( invokerLog, "UTF-8" );
invokerLogContent = IOUtil.toString( reader );
}
catch ( IOException e )
{
String msg = "IOException: " + e.getMessage();
if ( getLog().isDebugEnabled() )
{
getLog().error( msg, e );
}
else
{
getLog().error( msg );
}
}
finally
{
IOUtil.close( reader );
}
if ( invokerLogContent != null
&& invokerLogContent.indexOf( "Error occurred during initialization of VM" ) != -1 )
{
getLog().info( "Error occurred during initialization of VM, try to use an empty MAVEN_OPTS." );
if ( getLog().isDebugEnabled() )
{
getLog().debug( "Reinvoking Maven for the goals: " + goals + " with an empty MAVEN_OPTS" );
}
try
{
result = invoke( invoker, request, invokerLog, goals, properties, "" );
}
catch ( MavenInvocationException e )
{
if ( getLog().isDebugEnabled() )
{
getLog().error( "MavenInvocationException: " + e.getMessage(), e );
}
getLog().error( "Error when reinvoking Maven, consult the invoker log." );
return;
}
}
if ( result.getExitCode() != 0 )
{
if ( getLog().isErrorEnabled() )
{
getLog().error(
"Error when invoking Maven, consult the invoker log file: "
+ invokerLog.getAbsolutePath() );
}
}
}
/**
* @param invoker not null
* @param request not null
* @param invokerLog not null
* @param goals the list of goals
* @param properties the properties for the invoker
* @param mavenOpts could be null
* @return the invocation result
* @throws MavenInvocationException if any
*/
private InvocationResult invoke( Invoker invoker, InvocationRequest request, File invokerLog, List goals,
Properties properties, String mavenOpts )
throws MavenInvocationException
{
PrintStream ps;
OutputStream os = null;
if ( invokerLog != null )
{
if ( getLog().isDebugEnabled() )
{
getLog().debug( "Using " + invokerLog.getAbsolutePath() + " to log the invoker" );
}
try
{
if ( !invokerLog.exists() )
{
invokerLog.getParentFile().mkdirs();
}
os = new FileOutputStream( invokerLog );
ps = new PrintStream( os, true, "UTF-8" );
}
catch ( FileNotFoundException e )
{
if ( getLog().isErrorEnabled() )
{
getLog().error(
"FileNotFoundException: " + e.getMessage()
+ ". Using System.out to log the invoker." );
}
ps = System.out;
}
catch ( UnsupportedEncodingException e )
{
if ( getLog().isErrorEnabled() )
{
getLog().error(
"UnsupportedEncodingException: " + e.getMessage()
+ ". Using System.out to log the invoker." );
}
ps = System.out;
}
}
else
{
getLog().debug( "Using System.out to log the invoker." );
ps = System.out;
}
if ( mavenOpts != null )
{
request.setMavenOpts( mavenOpts );
}
InvocationOutputHandler outputHandler = new PrintStreamHandler( ps, false );
request.setOutputHandler( outputHandler );
outputHandler.consumeLine( "Invoking Maven for the goals: " + goals + " with properties=" + properties );
outputHandler.consumeLine( "" );
outputHandler.consumeLine( "M2_HOME=" + getMavenHome() );
outputHandler.consumeLine( "MAVEN_OPTS=" + getMavenOpts() );
outputHandler.consumeLine( "JAVA_HOME=" + getJavaHome() );
outputHandler.consumeLine( "JAVA_OPTS=" + getJavaOpts() );
outputHandler.consumeLine( "" );
try
{
return invoker.execute( request );
}
finally
{
IOUtil.close( os );
ps = null;
}
}
/**
* @return the Maven home defined in the maven.home
system property or defined
* in M2_HOME
system env variables or null if never setted.
* @see #invoke(Invoker, InvocationRequest, File, List, Properties, String)
*/
private String getMavenHome()
{
String mavenHome = System.getProperty( "maven.home" );
if ( mavenHome == null )
{
try
{
mavenHome = CommandLineUtils.getSystemEnvVars().getProperty( "M2_HOME" );
}
catch ( IOException e )
{
String msg = "IOException: " + e.getMessage();
if ( getLog().isDebugEnabled() )
{
getLog().error( msg, e );
}
else
{
getLog().error( msg );
}
}
}
File m2Home = new File( mavenHome );
if ( !m2Home.exists() )
{
if ( getLog().isErrorEnabled() )
{
getLog().error(
"Cannot find Maven application directory. Either specify \'maven.home\' "
+ "system property, or M2_HOME environment variable." );
}
}
return mavenHome;
}
/**
* @return the MAVEN_OPTS
env variable value or null if not setted.
* @see #invoke(Invoker, InvocationRequest, File, List, Properties, String)
*/
private String getMavenOpts()
{
String mavenOpts = null;
try
{
mavenOpts = CommandLineUtils.getSystemEnvVars().getProperty( "MAVEN_OPTS" );
}
catch ( IOException e )
{
String msg = "IOException: " + e.getMessage();
if ( getLog().isDebugEnabled() )
{
getLog().error( msg, e );
}
else
{
getLog().error( msg );
}
}
return mavenOpts;
}
/**
* @return the JAVA_HOME
from System.getProperty( "java.home" )
* By default, System.getProperty( "java.home" ) = JRE_HOME
and JRE_HOME
* should be in the JDK_HOME
or null if not setted.
* @see #invoke(Invoker, InvocationRequest, File, List, Properties, String)
*/
private File getJavaHome()
{
File javaHome;
if ( SystemUtils.IS_OS_MAC_OSX )
{
javaHome = SystemUtils.getJavaHome();
}
else
{
javaHome = new File( SystemUtils.getJavaHome(), ".." );
}
if ( javaHome == null || !javaHome.exists() )
{
try
{
javaHome = new File( CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_HOME" ) );
}
catch ( IOException e )
{
String msg = "IOException: " + e.getMessage();
if ( getLog().isDebugEnabled() )
{
getLog().error( msg, e );
}
else
{
getLog().error( msg );
}
}
}
if ( javaHome == null || !javaHome.exists() )
{
if ( getLog().isErrorEnabled() )
{
getLog().error(
"Cannot find Java application directory. Either specify \'java.home\' "
+ "system property, or JAVA_HOME environment variable." );
}
}
return javaHome;
}
/**
* @return the JAVA_OPTS
env variable value or null if not setted.
* @see #invoke(Invoker, InvocationRequest, File, List, Properties, String)
*/
private String getJavaOpts()
{
String javaOpts = null;
try
{
javaOpts = CommandLineUtils.getSystemEnvVars().getProperty( "JAVA_OPTS" );
}
catch ( IOException e )
{
String msg = "IOException: " + e.getMessage();
if ( getLog().isDebugEnabled() )
{
getLog().error( msg, e );
}
else
{
getLog().error( msg );
}
}
return javaOpts;
}
// ----------------------------------------------------------------------
// Linkcheck report
// ----------------------------------------------------------------------
private void generateReport( Locale locale, LinkcheckModel linkcheckModel )
{
getSink().head();
getSink().title();
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.title" ) );
getSink().title_();
getSink().head_();
getSink().body();
if ( linkcheckModel == null )
{
getSink().section1();
getSink().sectionTitle1();
getSink().text( getName( locale ) );
getSink().sectionTitle1_();
getSink().paragraph();
getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.empty" ) );
getSink().paragraph_();
getSink().section1_();
getSink().body_();
getSink().flush();
getSink().close();
return;
}
// Overview
getSink().section1();
getSink().sectionTitle1();
getSink().text( getName( locale ) );
getSink().sectionTitle1_();
getSink().paragraph();
getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.overview" ) );
getSink().paragraph_();
getSink().section1_();
// Statistics
generateSummarySection( locale, linkcheckModel );
if ( linkcheckModel.getFiles().size() > 0 )
{
// Details
generateDetailsSection( locale, linkcheckModel );
}
getSink().body_();
getSink().flush();
getSink().close();
closeReport();
}
private void generateSummarySection( Locale locale, LinkcheckModel linkcheckModel )
{
// Calculus
List linkcheckFiles = linkcheckModel.getFiles();
int totalFiles = linkcheckFiles.size();
int totalLinks = 0;
int totalValidLinks = 0;
int totalErrorLinks = 0;
int totalWarningLinks = 0;
for ( Iterator it = linkcheckFiles.iterator(); it.hasNext(); )
{
LinkcheckFile linkcheckFile = (LinkcheckFile) it.next();
totalLinks += linkcheckFile.getNumberOfLinks();
totalValidLinks += linkcheckFile.getNumberOfLinks( LinkcheckFileResult.VALID_LEVEL );
totalErrorLinks += linkcheckFile.getNumberOfLinks( LinkcheckFileResult.ERROR_LEVEL );
totalWarningLinks += linkcheckFile.getNumberOfLinks( LinkcheckFileResult.WARNING_LEVEL );
}
getSink().section1();
getSink().sectionTitle1();
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary" ) );
getSink().sectionTitle1_();
// Summary of the analysis parameters
getSink().paragraph();
getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.overview1" ) );
getSink().paragraph_();
getSink().table();
getSink().tableRow();
getSink().tableHeaderCell();
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.parameter" ) );
getSink().tableHeaderCell_();
getSink().tableHeaderCell();
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.value" ) );
getSink().tableHeaderCell_();
getSink().tableRow_();
getSink().tableRow();
getSink().tableCell();
getSink().rawText(
i18n.getString( "linkcheck-report", locale,
"report.linkcheck.summary.table.httpFollowRedirect" ) );
getSink().tableCell_();
getSink().tableCell();
getSink().text( String.valueOf( httpFollowRedirect ) );
getSink().tableCell_();
getSink().tableRow_();
getSink().tableRow();
getSink().tableCell();
getSink()
.rawText(
i18n
.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.httpMethod" ) );
getSink().tableCell_();
getSink().tableCell();
if ( StringUtils.isEmpty( httpMethod ) )
{
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
}
else
{
getSink().text( httpMethod );
}
getSink().tableCell_();
getSink().tableRow_();
getSink().tableRow();
getSink().tableCell();
getSink().rawText(
i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.offline" ) );
getSink().tableCell_();
getSink().tableCell();
getSink().text( String.valueOf( offline ) );
getSink().tableCell_();
getSink().tableRow_();
getSink().tableRow();
getSink().tableCell();
getSink().rawText(
i18n.getString( "linkcheck-report", locale,
"report.linkcheck.summary.table.excludedPages" ) );
getSink().tableCell_();
getSink().tableCell();
if ( getExcludedPages() == null || getExcludedPages().length == 0 )
{
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
}
else
{
getSink().text( StringUtils.join( getExcludedPages(), "," ) );
}
getSink().tableCell_();
getSink().tableRow_();
getSink().tableRow();
getSink().tableCell();
getSink().rawText(
i18n.getString( "linkcheck-report", locale,
"report.linkcheck.summary.table.excludedLinks" ) );
getSink().tableCell_();
getSink().tableCell();
if ( excludedLinks == null || excludedLinks.length == 0 )
{
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
}
else
{
getSink().text( StringUtils.join( excludedLinks, "," ) );
}
getSink().tableCell_();
getSink().tableRow_();
getSink().tableRow();
getSink().tableCell();
getSink().rawText(
i18n.getString( "linkcheck-report", locale,
"report.linkcheck.summary.table.excludedHttpStatusErrors" ) );
getSink().tableCell_();
getSink().tableCell();
if ( excludedHttpStatusErrors == null || excludedHttpStatusErrors.length == 0 )
{
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
}
else
{
getSink().text( toString( excludedHttpStatusErrors ) );
}
getSink().tableCell_();
getSink().tableRow_();
getSink().tableRow();
getSink().tableCell();
getSink().rawText(
i18n.getString( "linkcheck-report", locale,
"report.linkcheck.summary.table.excludedHttpStatusWarnings" ) );
getSink().tableCell_();
getSink().tableCell();
if ( excludedHttpStatusWarnings == null || excludedHttpStatusWarnings.length == 0 )
{
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
}
else
{
getSink().text( toString( excludedHttpStatusWarnings ) );
}
getSink().tableCell_();
getSink().tableRow_();
getSink().table_();
// Summary of the checked files
getSink().paragraph();
getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.overview2" ) );
getSink().paragraph_();
getSink().table();
// Header
generateTableHeader( locale, false );
// Content
getSink().tableRow();
getSink().tableCell();
getSink().bold();
getSink().text( totalFiles + "" );
getSink().bold_();
getSink().tableCell_();
getSink().tableCell();
getSink().bold();
getSink().text( totalLinks + "" );
getSink().bold_();
getSink().tableCell_();
getSink().tableCell();
getSink().bold();
getSink().text( String.valueOf( totalValidLinks ) );
getSink().bold_();
getSink().tableCell_();
getSink().tableCell();
getSink().bold();
getSink().text( String.valueOf( totalWarningLinks ) );
getSink().bold_();
getSink().tableCell_();
getSink().tableCell();
getSink().bold();
getSink().text( String.valueOf( totalErrorLinks ) );
getSink().bold_();
getSink().tableCell_();
getSink().tableRow_();
getSink().table_();
getSink().section1_();
}
private void generateDetailsSection( Locale locale, LinkcheckModel linkcheckModel )
{
getSink().section1();
getSink().sectionTitle1();
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.detail" ) );
getSink().sectionTitle1_();
getSink().paragraph();
getSink().rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.detail.overview" ) );
getSink().paragraph_();
getSink().table();
// Header
generateTableHeader( locale, true );
// Content
List linkcheckFiles = linkcheckModel.getFiles();
for ( Iterator it = linkcheckFiles.iterator(); it.hasNext(); )
{
LinkcheckFile linkcheckFile = (LinkcheckFile) it.next();
getSink().tableRow();
getSink().tableCell();
if ( linkcheckFile.getUnsuccessful() == 0 )
{
iconValid( locale );
}
else
{
iconError( locale );
}
getSink().tableCell_();
// tableCell( createLinkPatternedText( linkcheckFile.getRelativePath(), "./"
// + linkcheckFile.getRelativePath() ) );
getSink().tableCell();
getSink().link( linkcheckFile.getRelativePath() );
getSink().text( linkcheckFile.getRelativePath() );
getSink().link_();
getSink().tableCell_();
getSink().tableCell();
getSink().text( String.valueOf( linkcheckFile.getNumberOfLinks() ) );
getSink().tableCell_();
getSink().tableCell();
getSink().text( String.valueOf( linkcheckFile.getNumberOfLinks( LinkcheckFileResult.VALID_LEVEL ) ) );
getSink().tableCell_();
getSink().tableCell();
getSink().text( String.valueOf( linkcheckFile.getNumberOfLinks( LinkcheckFileResult.WARNING_LEVEL ) ) );
getSink().tableCell_();
getSink().tableCell();
getSink().text( String.valueOf( linkcheckFile.getNumberOfLinks( LinkcheckFileResult.ERROR_LEVEL ) ) );
getSink().tableCell_();
getSink().tableRow_();
// Detail error
if ( linkcheckFile.getUnsuccessful() != 0 )
{
getSink().tableRow();
getSink().tableCell();
getSink().text( "" );
getSink().tableCell_();
// TODO it is due to DOXIA-78
getSink().rawText( "" );
getSink().table();
for ( Iterator it2 = linkcheckFile.getResults().iterator(); it2.hasNext(); )
{
LinkcheckFileResult linkcheckFileResult = (LinkcheckFileResult) it2.next();
if ( linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.VALID_LEVEL )
{
continue;
}
getSink().tableRow();
getSink().tableCell();
if ( linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.WARNING_LEVEL )
{
iconWarning( locale );
}
else if ( linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.ERROR_LEVEL )
{
iconError( locale );
}
getSink().tableCell_();
getSink().tableCell();
getSink().italic();
if ( linkcheckFileResult.getTarget().startsWith( "#" ) )
{
getSink().link( linkcheckFile.getRelativePath() + linkcheckFileResult.getTarget() );
}
else if ( linkcheckFileResult.getTarget().startsWith( "." ) )
{
// We need to calculate a correct absolute path here, because target is a relative path
String absolutePath = FilenameUtils.getFullPath( linkcheckFile.getRelativePath() )
+ linkcheckFileResult.getTarget();
String normalizedPath = FilenameUtils.normalize( absolutePath );
if( normalizedPath == null )
{
normalizedPath = absolutePath;
}
getSink().link( normalizedPath );
}
else
{
getSink().link( linkcheckFileResult.getTarget() );
}
// Show the link as it was written to make it easy for
// the author to find it in the source document
getSink().text( linkcheckFileResult.getTarget() );
getSink().link_();
getSink().text( ": " );
getSink().text( linkcheckFileResult.getErrorMessage() );
getSink().italic_();
getSink().tableCell_();
getSink().tableRow_();
}
getSink().table_();
getSink().tableCell_();
getSink().tableRow_();
}
}
getSink().table_();
getSink().section1_();
}
private void generateTableHeader( Locale locale, boolean detail )
{
getSink().tableRow();
if ( detail )
{
getSink().rawText( " " );
getSink().text( "" );
getSink().tableHeaderCell_();
}
getSink().rawText( " " );
getSink().text(
detail ? i18n.getString( "linkcheck-report", locale,
"report.linkcheck.detail.table.documents" )
: i18n.getString( "linkcheck-report", locale,
"report.linkcheck.summary.table.documents" ) );
getSink().tableHeaderCell_();
// TODO it is due to DOXIA-78
getSink().rawText( " " );
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.table.links" ) );
getSink().tableHeaderCell_();
getSink().tableRow_();
getSink().tableRow();
getSink().tableHeaderCell();
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.table.totalLinks" ) );
getSink().tableHeaderCell_();
getSink().tableHeaderCell();
iconValid( locale );
getSink().tableHeaderCell_();
getSink().tableHeaderCell();
iconWarning( locale );
getSink().tableHeaderCell_();
getSink().tableHeaderCell();
iconError( locale );
getSink().tableHeaderCell_();
getSink().tableRow_();
}
private void iconError( Locale locale )
{
getSink().figure();
getSink().figureCaption();
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.error" ) );
getSink().figureCaption_();
// should be defined in skins
getSink().figureGraphics( "images/icon_error_sml.gif" );
getSink().figure_();
}
private void iconValid( Locale locale )
{
getSink().figure();
getSink().figureCaption();
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.valid" ) );
getSink().figureCaption_();
// should be defined in skins
getSink().figureGraphics( "images/icon_success_sml.gif" );
getSink().figure_();
}
private void iconWarning( Locale locale )
{
getSink().figure();
getSink().figureCaption();
getSink().text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.warning" ) );
getSink().figureCaption_();
// should be defined in skins
getSink().figureGraphics( "images/icon_warning_sml.gif" );
getSink().figure_();
}
// ----------------------------------------------------------------------
// static methods
// ----------------------------------------------------------------------
/**
* Similar to {@link Arrays#toString(int[])} in 1.5.
*
* @param a not null
* @return the array comma separated.
*/
private static String toString( int[] a )
{
if ( a == null || a.length == 0 )
{
return "";
}
StringBuffer buf = new StringBuffer();
buf.append( a[0] );
for ( int i = 1; i < a.length; i++ )
{
buf.append( ", " );
buf.append( a[i] );
}
return buf.toString();
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy