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

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

Go to download

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

The 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.util.List;
import java.util.Locale;

import org.apache.commons.io.FilenameUtils;

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.sink.Sink;

import org.codehaus.plexus.i18n.I18N;
import org.codehaus.plexus.util.StringUtils;

/**
 * @author ltheussl
 * @since 1.1
 */
public class LinkcheckReportGenerator
{
    private final I18N i18n;

    private String httpMethod;

    private boolean offline;

    private String[] excludedLinks;

    private Integer[] excludedHttpStatusErrors;

    private Integer[] excludedHttpStatusWarnings;

    private String[] excludedPages;

    private boolean httpFollowRedirect;

    /**
     * @param i18n not null.
     */
    public LinkcheckReportGenerator( I18N i18n )
    {
        this.i18n = i18n;
    }

    /**
     * @param excludedHttpStatusErrors may be null.
     */
    public void setExcludedHttpStatusErrors( Integer[] excludedHttpStatusErrors )
    {
        this.excludedHttpStatusErrors = excludedHttpStatusErrors;
    }

    /**
     * @param excludedHttpStatusWarnings may be null.
     */
    public void setExcludedHttpStatusWarnings( Integer[] excludedHttpStatusWarnings )
    {
        this.excludedHttpStatusWarnings = excludedHttpStatusWarnings;
    }

    /**
     * @param excludedLinks may be null.
     */
    public void setExcludedLinks( String[] excludedLinks )
    {
        this.excludedLinks = excludedLinks;
    }

    /**
     * @param excludedPages may be null.
     */
    public void setExcludedPages( String[] excludedPages )
    {
        this.excludedPages = excludedPages;
    }

    /**
     * @param httpFollowRedirect default is false.
     */
    public void setHttpFollowRedirect( boolean httpFollowRedirect )
    {
        this.httpFollowRedirect = httpFollowRedirect;
    }

    /**
     * @param httpMethod may be null.
     */
    public void setHttpMethod( String httpMethod )
    {
        this.httpMethod = httpMethod;
    }

    /**
     * @param offline default is false.
     */
    public void setOffline( boolean offline )
    {
        this.offline = offline;
    }

    /**
     * Genarate a report for the given LinkcheckModel and emit it into a Sink.
     * Note that the Sink is flushed and closed.
     *
     * @param locale not null.
     * @param linkcheckModel may be null.
     * @param sink not null.
     */
    public void generateReport( Locale locale, LinkcheckModel linkcheckModel, Sink sink )
    {
        String name = i18n.getString( "linkcheck-report", locale, "report.linkcheck.name" );

        sink.head();
        sink.title();
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.title" ) );
        sink.title_();
        sink.head_();

        sink.body();

        if ( linkcheckModel == null )
        {
            sink.section1();
            sink.sectionTitle1();
            sink.text( name );
            sink.sectionTitle1_();

            sink.paragraph();
            sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.empty" ) );
            sink.paragraph_();

            sink.section1_();

            sink.body_();
            sink.flush();
            sink.close();

            return;
        }

        // Overview
        sink.section1();
        sink.sectionTitle1();
        sink.text( name );
        sink.sectionTitle1_();

        sink.paragraph();
        sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.overview" ) );
        sink.paragraph_();

        sink.section1_();

        // Statistics
        generateSummarySection( locale, linkcheckModel, sink );

        if ( linkcheckModel.getFiles().size() > 0 )
        {
            // Details
            generateDetailsSection( locale, linkcheckModel, sink );
        }

        sink.body_();
        sink.flush();
        sink.close();
    }

    private void generateSummarySection( Locale locale, LinkcheckModel linkcheckModel, Sink sink )
    {
        // CHECKSTYLE_OFF: LineLength
        // Calculus
        List linkcheckFiles = linkcheckModel.getFiles();

        int totalFiles = linkcheckFiles.size();

        int totalLinks = 0;
        int totalValidLinks = 0;
        int totalErrorLinks = 0;
        int totalWarningLinks = 0;
        for ( Object linkcheckFile1 : linkcheckFiles )
        {
            LinkcheckFile linkcheckFile = (LinkcheckFile) linkcheckFile1;

            totalLinks += linkcheckFile.getNumberOfLinks();
            totalValidLinks += linkcheckFile.getNumberOfLinks( LinkcheckFileResult.VALID_LEVEL );
            totalErrorLinks += linkcheckFile.getNumberOfLinks( LinkcheckFileResult.ERROR_LEVEL );
            totalWarningLinks += linkcheckFile.getNumberOfLinks( LinkcheckFileResult.WARNING_LEVEL );
        }

        sink.section1();
        sink.sectionTitle1();
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary" ) );
        sink.sectionTitle1_();

        // Summary of the analysis parameters
        sink.paragraph();
        sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.overview1" ) );
        sink.paragraph_();

        sink.table();

        sink.tableRow();
        sink.tableHeaderCell();
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.parameter" ) );
        sink.tableHeaderCell_();
        sink.tableHeaderCell();
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.value" ) );
        sink.tableHeaderCell_();
        sink.tableRow_();

        sink.tableRow();
        sink.tableCell();
        sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.httpFollowRedirect" ) );
        sink.tableCell_();
        sink.tableCell();
        sink.text( String.valueOf( httpFollowRedirect ) );
        sink.tableCell_();
        sink.tableRow_();

        sink.tableRow();
        sink.tableCell();
        sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.httpMethod" ) );
        sink.tableCell_();
        sink.tableCell();
        if ( StringUtils.isEmpty( httpMethod ) )
        {
            sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
        }
        else
        {
            sink.text( httpMethod );
        }
        sink.tableCell_();
        sink.tableRow_();

        sink.tableRow();
        sink.tableCell();
        sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.offline" ) );
        sink.tableCell_();
        sink.tableCell();
        sink.text( String.valueOf( offline ) );
        sink.tableCell_();
        sink.tableRow_();

        sink.tableRow();
        sink.tableCell();
        sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.excludedPages" ) );
        sink.tableCell_();
        sink.tableCell();
        if ( excludedPages == null || excludedPages.length == 0 )
        {
            sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
        }
        else
        {
            sink.text( StringUtils.join( excludedPages, "," ) );
        }
        sink.tableCell_();
        sink.tableRow_();

        sink.tableRow();
        sink.tableCell();
        sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.excludedLinks" ) );
        sink.tableCell_();
        sink.tableCell();
        if ( excludedLinks == null || excludedLinks.length == 0 )
        {
            sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
        }
        else
        {
            sink.text( StringUtils.join( excludedLinks, "," ) );
        }
        sink.tableCell_();
        sink.tableRow_();

        sink.tableRow();
        sink.tableCell();
        sink.rawText( i18n.getString( "linkcheck-report", locale,
                                      "report.linkcheck.summary.table.excludedHttpStatusErrors" ) );
        sink.tableCell_();
        sink.tableCell();
        if ( excludedHttpStatusErrors == null || excludedHttpStatusErrors.length == 0 )
        {
            sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
        }
        else
        {
            sink.text( toString( excludedHttpStatusErrors ) );
        }
        sink.tableCell_();
        sink.tableRow_();

        sink.tableRow();
        sink.tableCell();
        sink.rawText( i18n.getString( "linkcheck-report", locale,
                                      "report.linkcheck.summary.table.excludedHttpStatusWarnings" ) );
        sink.tableCell_();
        sink.tableCell();
        if ( excludedHttpStatusWarnings == null || excludedHttpStatusWarnings.length == 0 )
        {
            sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.none" ) );
        }
        else
        {
            sink.text( toString( excludedHttpStatusWarnings ) );
        }
        sink.tableCell_();
        sink.tableRow_();

        sink.table_();

        // Summary of the checked files
        sink.paragraph();
        sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.overview2" ) );
        sink.paragraph_();

        sink.table();

        // Header
        generateTableHeader( locale, false, sink );

        // Content
        sink.tableRow();

        sink.tableCell();
        sink.bold();
        sink.text( totalFiles + "" );
        sink.bold_();
        sink.tableCell_();
        sink.tableCell();
        sink.bold();
        sink.text( totalLinks + "" );
        sink.bold_();
        sink.tableCell_();
        sink.tableCell();
        sink.bold();
        sink.text( String.valueOf( totalValidLinks ) );
        sink.bold_();
        sink.tableCell_();
        sink.tableCell();
        sink.bold();
        sink.text( String.valueOf( totalWarningLinks ) );
        sink.bold_();
        sink.tableCell_();
        sink.tableCell();
        sink.bold();
        sink.text( String.valueOf( totalErrorLinks ) );
        sink.bold_();
        sink.tableCell_();

        sink.tableRow_();

        sink.table_();

        sink.section1_();
        // CHECKSTYLE_ON: LineLength

    }

    private void generateDetailsSection( Locale locale, LinkcheckModel linkcheckModel, Sink sink )
    {
        sink.section1();
        sink.sectionTitle1();
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.detail" ) );
        sink.sectionTitle1_();

        sink.paragraph();
        sink.rawText( i18n.getString( "linkcheck-report", locale, "report.linkcheck.detail.overview" ) );
        sink.paragraph_();

        sink.table();

        // Header
        generateTableHeader( locale, true, sink );

        // Content
        List linkcheckFiles = linkcheckModel.getFiles();
        for ( Object linkcheckFile1 : linkcheckFiles )
        {
            LinkcheckFile linkcheckFile = (LinkcheckFile) linkcheckFile1;

            sink.tableRow();

            sink.tableCell();
            if ( linkcheckFile.getUnsuccessful() == 0 )
            {
                iconValid( locale, sink );
            }
            else
            {
                iconError( locale, sink );
            }
            sink.tableCell_();

            // tableCell( createLinkPatternedText( linkcheckFile.getRelativePath(), "./"
            // + linkcheckFile.getRelativePath() ) );
            sink.tableCell();
            sink.link( linkcheckFile.getRelativePath() );
            sink.text( linkcheckFile.getRelativePath() );
            sink.link_();
            sink.tableCell_();
            sink.tableCell();
            sink.text( String.valueOf( linkcheckFile.getNumberOfLinks() ) );
            sink.tableCell_();
            sink.tableCell();
            sink.text( String.valueOf( linkcheckFile.getNumberOfLinks( LinkcheckFileResult.VALID_LEVEL ) ) );
            sink.tableCell_();
            sink.tableCell();
            sink.text( String.valueOf( linkcheckFile.getNumberOfLinks( LinkcheckFileResult.WARNING_LEVEL ) ) );
            sink.tableCell_();
            sink.tableCell();
            sink.text( String.valueOf( linkcheckFile.getNumberOfLinks( LinkcheckFileResult.ERROR_LEVEL ) ) );
            sink.tableCell_();

            sink.tableRow_();

            // Detail error
            if ( linkcheckFile.getUnsuccessful() != 0 )
            {
                sink.tableRow();

                sink.tableCell();
                sink.text( "" );
                sink.tableCell_();

                // TODO it is due to DOXIA-78
                sink.rawText( "" );

                sink.table();

                for ( Object o : linkcheckFile.getResults() )
                {
                    LinkcheckFileResult linkcheckFileResult = (LinkcheckFileResult) o;

                    if ( linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.VALID_LEVEL )
                    {
                        continue;
                    }

                    sink.tableRow();

                    sink.tableCell();
                    if ( linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.WARNING_LEVEL )
                    {
                        iconWarning( locale, sink );
                    }
                    else if ( linkcheckFileResult.getStatusLevel() == LinkcheckFileResult.ERROR_LEVEL )
                    {
                        iconError( locale, sink );
                    }
                    sink.tableCell_();

                    sink.tableCell();
                    sink.italic();
                    if ( linkcheckFileResult.getTarget().startsWith( "#" ) )
                    {
                        sink.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;
                        }
                        sink.link( normalizedPath );
                    }
                    else
                    {
                        sink.link( linkcheckFileResult.getTarget() );
                    }
                    // Show the link as it was written to make it easy for
                    // the author to find it in the source document
                    sink.text( linkcheckFileResult.getTarget() );
                    sink.link_();
                    sink.text( ": " );
                    sink.text( linkcheckFileResult.getErrorMessage() );
                    sink.italic_();
                    sink.tableCell_();

                    sink.tableRow_();
                }

                sink.table_();

                sink.tableCell_();

                sink.tableRow_();
            }
        }

        sink.table_();

        sink.section1_();
    }

    private void generateTableHeader( Locale locale, boolean detail, Sink sink )
    {
        sink.tableRow();
        if ( detail )
        {
            sink.rawText( "" );
            sink.text( "" );
            sink.tableHeaderCell_();
        }
        sink.rawText( "" );
        sink.text( detail ? i18n.getString( "linkcheck-report", locale, "report.linkcheck.detail.table.documents" )
                        : i18n.getString( "linkcheck-report", locale, "report.linkcheck.summary.table.documents" ) );
        sink.tableHeaderCell_();
        // TODO it is due to DOXIA-78
        sink.rawText( "" );
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.table.links" ) );
        sink.tableHeaderCell_();
        sink.tableRow_();

        sink.tableRow();
        sink.tableHeaderCell();
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.table.totalLinks" ) );
        sink.tableHeaderCell_();
        sink.tableHeaderCell();
        iconValid( locale, sink );
        sink.tableHeaderCell_();
        sink.tableHeaderCell();
        iconWarning( locale, sink );
        sink.tableHeaderCell_();
        sink.tableHeaderCell();
        iconError( locale, sink );
        sink.tableHeaderCell_();
        sink.tableRow_();
    }

    private void iconError( Locale locale, Sink sink )
    {
        sink.figure();
        sink.figureCaption();
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.error" ) );
        sink.figureCaption_();
        sink.figureGraphics( LinkcheckReport.ICON_ERROR );
        sink.figure_();
    }

    private void iconValid( Locale locale, Sink sink )
    {
        sink.figure();
        sink.figureCaption();
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.valid" ) );
        sink.figureCaption_();
        sink.figureGraphics( LinkcheckReport.ICON_SUCCESS );
        sink.figure_();
    }

    private void iconWarning( Locale locale, Sink sink )
    {
        sink.figure();
        sink.figureCaption();
        sink.text( i18n.getString( "linkcheck-report", locale, "report.linkcheck.icon.warning" ) );
        sink.figureCaption_();
        sink.figureGraphics( LinkcheckReport.ICON_WARNING );
        sink.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( Object[] a )
    {
        if ( a == null || a.length == 0 )
        {
            return "";
        }

        StringBuilder buf = new StringBuilder();
        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