Author: hboutemy Date: Sat May 2 22:07:56 2009 New Revision: 770983 URL: http://svn.apache.org/viewvc?rev=770983&view=rev Log: merged MNG-2855 fix and unit test from trunk
Modified: maven/shared/branches/maven-reporting-impl-2.0.4.x/src/main/java/org/apache/maven/reporting/AbstractMavenReportRenderer.java Modified: maven/shared/branches/maven-reporting-impl-2.0.4.x/src/main/java/org/apache/maven/reporting/AbstractMavenReportRenderer.java URL: http://svn.apache.org/viewvc/maven/shared/branches/maven-reporting-impl-2.0.4.x/src/main/java/org/apache/maven/reporting/AbstractMavenReportRenderer.java?rev=770983&r1=770982&r2=770983&view=diff ============================================================================== --- maven/shared/branches/maven-reporting-impl-2.0.4.x/src/main/java/org/apache/maven/reporting/AbstractMavenReportRenderer.java (original) +++ maven/shared/branches/maven-reporting-impl-2.0.4.x/src/main/java/org/apache/maven/reporting/AbstractMavenReportRenderer.java Sat May 2 22:07:56 2009 @@ -1,30 +1,36 @@ package org.apache.maven.reporting; /* - * Copyright 2001-2005 The Apache Software Foundation. + * 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 * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * 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. + * 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 org.apache.commons.validator.EmailValidator; import org.apache.commons.validator.UrlValidator; + import org.apache.maven.doxia.sink.Sink; +import org.apache.maven.doxia.util.HtmlTools; + import org.codehaus.plexus.util.StringUtils; +import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import java.util.Properties; /** @@ -33,37 +39,44 @@ * @author <a href="mailto:ja...@maven.org">Jason van Zyl</a> * @author <a href="eveni...@apache.org">Emmanuel Venisse</a> * @author <a href="mailto:vincent.sive...@gmail.com">Vincent Siveton</a> - * @version $Id: AbstractMavenReportRenderer.java 163373 2005-02-22 03:37:00Z brett $ - * @todo Later it may be appropriate to create something like a VelocityMavenReportRenderer that could take a velocity template and pipe that through Doxia rather than coding them up like this. + * @version $Id: AbstractMavenReportRenderer.java 748481 2009-02-27 10:51:56Z vsiveton $ + * @since 2.0 + * @TODO Later it may be appropriate to create something like a VelocityMavenReportRenderer + * that could take a velocity template and pipe that through Doxia rather than coding them + * up like this. */ public abstract class AbstractMavenReportRenderer implements MavenReportRenderer { + /** The current sink to use */ protected Sink sink; + /** The current section number */ private int section; + /** + * Default constructor. + * + * @param sink the sink to use. + */ public AbstractMavenReportRenderer( Sink sink ) { this.sink = sink; } + /** {...@inheritdoc} */ public void render() { sink.head(); sink.title(); - text( getTitle() ); - sink.title_(); sink.head_(); sink.body(); - renderBody(); - sink.body_(); sink.flush(); @@ -71,20 +84,38 @@ sink.close(); } - protected void startTable() - { - sink.table(); - } - - protected void endTable() - { - sink.table_(); - } + // ---------------------------------------------------------------------- + // Section handler + // ---------------------------------------------------------------------- + /** + * Convenience method to wrap section creation in the current sink. An anchor will be add for the name. + * + * @param name the name of this section, could be null. + * @see #text(String) + * @see Sink#section1() + * @see Sink#sectionTitle1() + * @see Sink#sectionTitle1_() + * @see Sink#section2() + * @see Sink#sectionTitle2() + * @see Sink#sectionTitle2_() + * @see Sink#section3() + * @see Sink#sectionTitle3() + * @see Sink#sectionTitle3_() + * @see Sink#section4() + * @see Sink#sectionTitle4() + * @see Sink#sectionTitle4_() + * @see Sink#section5() + * @see Sink#sectionTitle5() + * @see Sink#sectionTitle5_() + */ protected void startSection( String name ) { section = section + 1; + sink.anchor( HtmlTools.encodeId( name ) ); + sink.anchor_(); + switch ( section ) { case 1: @@ -139,6 +170,16 @@ } } + /** + * Convenience method to wrap section ending in the current sink. + * + * @see Sink#section1_() + * @see Sink#section2_() + * @see Sink#section3_() + * @see Sink#section4_() + * @see Sink#section5_() + * @IllegalStateException if too many closing sections. + */ protected void endSection() { switch ( section ) @@ -172,6 +213,38 @@ } } + // ---------------------------------------------------------------------- + // Table handler + // ---------------------------------------------------------------------- + + /** + * Convenience method to wrap the table start in the current sink. + * + * @see Sink#table() + */ + protected void startTable() + { + sink.table(); + } + + /** + * Convenience method to wrap the table ending in the current sink. + * + * @see Sink#table_() + */ + protected void endTable() + { + sink.table_(); + } + + /** + * Convenience method to wrap the table header cell start in the current sink. + * + * @param text the text to put in this cell, could be null. + * @see #text(String) + * @see Sink#tableHeaderCell() + * @see Sink#tableHeaderCell_() + */ protected void tableHeaderCell( String text ) { sink.tableHeaderCell(); @@ -182,11 +255,12 @@ } /** - * Add a cell in a table. + * Convenience method to wrap a table cell start in the current sink. * <p>The text could be a link patterned text defined by <code>{text, url}</code></p> * - * @param text + * @param text the text to put in this cell, could be null. * @see #linkPatternedText(String) + * @see #tableCell(String) */ protected void tableCell( String text ) { @@ -194,11 +268,16 @@ } /** - * Add a cell in a table. + * Convenience method to wrap a table cell start in the current sink. + * <p>The text could be a link patterned text defined by <code>{text, url}</code></p> * <p>If <code>asHtml</code> is true, add the text as Html</p> * - * @param text - * @param asHtml + * @param text the text to put in this cell, could be null. + * @param asHtml <tt>true</tt> to add the text as Html, <tt>false</tt> otherwise. + * @see #linkPatternedText(String) + * @see Sink#tableCell() + * @see Sink#tableCell_() + * @see Sink#rawText(String) */ protected void tableCell( String text, boolean asHtml ) { @@ -216,30 +295,62 @@ sink.tableCell_(); } + /** + * Convenience method to wrap a table row start in the current sink. + * <p>The texts in the <code>content</code> could be link patterned texts defined by <code>{text, url}</code></p> + * + * @param content an array of text to put in the cells in this row, could be null. + * @see #tableCell(String) + * @see Sink#tableRow() + * @see Sink#tableRow_() + */ protected void tableRow( String[] content ) { sink.tableRow(); - for ( int i = 0; i < content.length; i++ ) + if ( content != null ) { - tableCell( content[i] ); + for ( int i = 0; i < content.length; i++ ) + { + tableCell( content[i] ); + } } sink.tableRow_(); } + /** + * Convenience method to wrap a table header row start in the current sink. + * <p>The texts in the <code>content</code> could be link patterned texts defined by <code>{text, url}</code></p> + * + * @param content an array of text to put in the cells in this row header, could be null. + * @see #tableHeaderCell(String) + * @see Sink#tableRow() + * @see Sink#tableRow_() + */ protected void tableHeader( String[] content ) { sink.tableRow(); - for ( int i = 0; i < content.length; i++ ) + if ( content != null ) { - tableHeaderCell( content[i] ); + for ( int i = 0; i < content.length; i++ ) + { + tableHeaderCell( content[i] ); + } } sink.tableRow_(); } + /** + * Convenience method to wrap a table caption in the current sink. + * + * @param caption the caption of the table, could be null. + * @see #text(String) + * @see Sink#tableCaption() + * @see Sink#tableCaption_() + */ protected void tableCaption( String caption ) { sink.tableCaption(); @@ -249,6 +360,18 @@ sink.tableCaption_(); } + // ---------------------------------------------------------------------- + // Paragraph handler + // ---------------------------------------------------------------------- + + /** + * Convenience method to wrap a paragraph in the current sink. + * + * @param paragraph the paragraph to add, could be null. + * @see #text(String) + * @see Sink#paragraph() + * @see Sink#paragraph_() + */ protected void paragraph( String paragraph ) { sink.paragraph(); @@ -258,6 +381,15 @@ sink.paragraph_(); } + /** + * Convenience method to wrap a link in the current sink. + * + * @param href the link to add, cannot be null. + * @param name the link name. + * @see #text(String) + * @see Sink#link(String) + * @see Sink#link_() + */ protected void link( String href, String name ) { sink.link( href ); @@ -268,14 +400,15 @@ } /** - * Add a new text. - * <p>If text is empty of has a null value, add the "-" charater</p> + * Convenience method to wrap a text in the current sink. + * <p>If text is empty or has a <code>null</code> value, add the <code>"-"</code> charater</p> * - * @param text a string + * @param text a text, could be null. + * @see Sink#text(String) */ protected void text( String text ) { - if ( text == null || text.length() == 0 ) // Take care of spaces + if ( StringUtils.isEmpty( text ) ) // Take care of spaces { sink.text( "-" ); } @@ -286,10 +419,12 @@ } /** - * Add a verbatim text. + * Convenience method to wrap a text as verbatim style in the current sink . * - * @param text a string + * @param text a text, could be null. * @see #text(String) + * @see Sink#verbatim(boolean) + * @see Sink#verbatim_() */ protected void verbatimText( String text ) { @@ -301,11 +436,14 @@ } /** - * Add a verbatim text with a specific link. + * Convenience method to wrap a text with a given link href as verbatim style in the current sink. * * @param text a string * @param href an href could be null * @see #link(String, String) + * @see #verbatimText(String) + * @see Sink#verbatim(boolean) + * @see Sink#verbatim_() */ protected void verbatimLink( String text, String href ) { @@ -324,9 +462,10 @@ } /** - * Add a Javascript code. + * Convenience method to add a Javascript code in the current sink. * * @param jsCode a string of Javascript + * @see Sink#rawText(String) */ protected void javaScript( String jsCode ) { @@ -334,12 +473,13 @@ } /** - * Add a text with links inside. + * Convenience method to wrap a patterned text in the current link. * <p>The text variable should contained this given pattern <code>{text, url}</code> * to handle the link creation.</p> * * @param text a text with link pattern defined. * @see #text(String) + * @see #link(String, String) * @see #applyPattern(String) */ public void linkPatternedText( String text ) @@ -350,7 +490,7 @@ } else { - Map segments = applyPattern( text ); + List segments = applyPattern( text ); if ( segments == null ) { @@ -358,12 +498,10 @@ } else { - for ( Iterator it = segments.entrySet().iterator(); it.hasNext(); ) + for ( Iterator it = segments.iterator(); it.hasNext(); ) { - Map.Entry entry = (Map.Entry) it.next(); - - String name = (String) entry.getKey(); - String href = (String) entry.getValue(); + String name = (String) it.next(); + String href = (String) it.next(); if ( href == null ) { @@ -414,9 +552,9 @@ } /** - * Convenience method to display a <code>Properties</code> object comma separated. + * Convenience method to display a <code>Properties</code> object as comma separated String. * - * @param props + * @param props the properties to display. * @return the properties object as comma separated String */ protected static String propertiesToString( Properties props ) @@ -441,16 +579,25 @@ return sb.toString(); } + // ---------------------------------------------------------------------- + // Private methods + // ---------------------------------------------------------------------- + /** * Return a valid href. * <p>A valid href could start by <code>mailto:</code>.</p> * <p>For a relative path, the href should start by <code>./</code> to be valid.</p> * - * @param href an href - * @return a valid href or null if the href is not valid. + * @param href an href, could be null. + * @return a valid href or <code>null</code> if the href is null or not valid. */ private static String getValidHref( String href ) { + if ( StringUtils.isEmpty( href ) ) + { + return null; + } + href = href.trim(); String[] schemes = {"http", "https"}; @@ -472,8 +619,6 @@ } else { - // TODO Waiting for new release of Validator - // http://issues.apache.org/bugzilla/show_bug.cgi?id=30686 String hrefTmp; if ( !href.endsWith( "/" ) ) { @@ -495,10 +640,8 @@ { return href.substring(2, href.length() ); } - else - { - return "."; - } + + return "."; } return null; @@ -512,7 +655,7 @@ * @param text a text with or without the pattern <code>{text, url}</code> * @return a map of text/href */ - private static Map applyPattern( String text ) + private static List applyPattern( String text ) { if ( StringUtils.isEmpty( text ) ) { @@ -521,7 +664,7 @@ // Map defined by key/value name/href // If href == null, it means - Map segments = new LinkedHashMap(); + List segments = new ArrayList(); // TODO Special case http://jira.codehaus.org/browse/MEV-40 if ( text.indexOf( "${" ) != -1 ) @@ -530,11 +673,13 @@ int lastSemi = text.lastIndexOf( "}" ); if ( lastComma != -1 && lastSemi != -1 ) { - segments.put( text.substring( lastComma + 1, lastSemi ).trim(), null ); + segments.add( text.substring( lastComma + 1, lastSemi ).trim() ); + segments.add( null ); } else { - segments.put( text, null ); + segments.add( text ); + segments.add( null ); } return segments; @@ -554,6 +699,9 @@ if ( i + 1 < text.length() && text.charAt( i + 1 ) == '\'' ) { i++; + segments.add( text.substring( lastOffset, i ) ); + segments.add( null ); + lastOffset = i + 1; } else { @@ -571,11 +719,12 @@ { if ( i != 0 ) // handle { at first character { - segments.put( text.substring( lastOffset, i ), null ); + segments.add( text.substring( lastOffset, i ) ); + segments.add( null ); } lastOffset = i + 1; - braceStack++; } + braceStack++; } break; case '}': @@ -590,12 +739,13 @@ int lastComma = subString.lastIndexOf( "," ); if ( lastComma != -1 ) { - segments.put( subString.substring( 0, lastComma ).trim(), - subString.substring( lastComma + 1 ).trim() ); + segments.add( subString.substring( 0, lastComma ).trim() ); + segments.add( subString.substring( lastComma + 1 ).trim() ); } else { - segments.put( subString.substring( 0, lastComma ).trim(), null ); + segments.add( subString ); + segments.add( null ); } } } @@ -611,7 +761,8 @@ if ( !StringUtils.isEmpty( text.substring( lastOffset, text.length() ) ) ) { - segments.put( text.substring( lastOffset, text.length() ), null ); + segments.add( text.substring( lastOffset, text.length() ) ); + segments.add( null ); } if ( braceStack != 0 ) @@ -619,10 +770,24 @@ throw new IllegalArgumentException( "Unmatched braces in the pattern." ); } - return Collections.unmodifiableMap( segments ); + if ( inQuote ) + { + //throw new IllegalArgumentException( "Unmatched quote in the pattern." ); + //TODO: warning... + } + + return Collections.unmodifiableList( segments ); } + // ---------------------------------------------------------------------- + // Abstract methods + // ---------------------------------------------------------------------- + + /** {...@inheritdoc} */ public abstract String getTitle(); + /** + * Renderer the body content of the report. + */ protected abstract void renderBody(); }