All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.maven.plugins.linkcheck.LinkcheckReport Maven / Gradle / Ivy

Go to download

This plugin allows you to generate a linkcheck report of your project's documentation.

There is a newer version: 1.2
Show newest version
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