Submitted by: Vincent Siveton

Reviewed by:  Brett Porter
reporting fixes

git-svn-id: https://svn.apache.org/repos/asf/maven/components/trunk@219820 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Brett Leslie Porter 2005-07-20 00:08:27 +00:00
parent 19696518b3
commit 694bcf59ab
2 changed files with 659 additions and 357 deletions

View File

@ -1,42 +1,67 @@
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>maven-reporting</artifactId>
<groupId>org.apache.maven.reporting</groupId>
<version>2.0-beta-1-SNAPSHOT</version>
</parent>
<artifactId>maven-reporting-api</artifactId>
<contributors>
<contributor>
<name>Vincent Siveton</name>
<email>vincent.siveton@gmail.com</email>
</contributor>
</contributors>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.0-beta-1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>doxia</groupId>
<artifactId>doxia-core</artifactId>
<version>1.0-alpha-4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0-beta-1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
<version>2.0.7</version>
</dependency>
</dependencies>
</project>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!--
/*
* Copyright 2001-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-->
<project>
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>maven-reporting</artifactId>
<groupId>org.apache.maven.reporting</groupId>
<version>2.0-beta-1-SNAPSHOT</version>
</parent>
<artifactId>maven-reporting-api</artifactId>
<developers>
<developer>
<id>vsiveton</id>
<name>Vincent Siveton</name>
<email>vincent.siveton@gmail.com</email>
<roles>
<role>Java Developer</role>
</roles>
<timezone>-5</timezone>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-project</artifactId>
<version>2.0-beta-1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>doxia</groupId>
<artifactId>doxia-core</artifactId>
<version>1.0-alpha-4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
<version>2.0-beta-1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
<version>2.0.7</version>
</dependency>
</dependencies>
</project>

View File

@ -1,315 +1,592 @@
package org.apache.maven.reporting;
/*
* Copyright 2004-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.commons.validator.EmailValidator;
import org.apache.commons.validator.UrlValidator;
import org.codehaus.doxia.sink.Sink;
/**
* @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
* @author <a href="evenisse@apache.org">Emmanuel Venisse</a>
* @author <a href="mailto:vincent.siveton@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.
*/
public abstract class AbstractMavenReportRenderer
implements MavenReportRenderer
{
protected Sink sink;
private int section = 0;
public AbstractMavenReportRenderer( Sink sink )
{
this.sink = sink;
}
public void render()
{
sink.head();
sink.title();
sink.text( getTitle() );
sink.title_();
sink.head_();
sink.body();
renderBody();
sink.body_();
sink.flush();
sink.close();
}
protected void startTable()
{
sink.table();
}
protected void endTable()
{
sink.table_();
}
protected void startSection( String name )
{
section = section + 1;
switch ( section )
{
case 1:
sink.section1();
sink.sectionTitle1();
break;
case 2:
sink.section2();
sink.sectionTitle2();
break;
case 3:
sink.section3();
sink.sectionTitle3();
break;
case 4:
sink.section4();
sink.sectionTitle4();
break;
case 5:
sink.section5();
sink.sectionTitle5();
break;
default:
// TODO: warning - just don't start a section
break;
}
sink.text( name );
switch ( section )
{
case 1:
sink.sectionTitle1_();
break;
case 2:
sink.sectionTitle2_();
break;
case 3:
sink.sectionTitle3_();
break;
case 4:
sink.sectionTitle4_();
break;
case 5:
sink.sectionTitle5_();
break;
default:
// TODO: warning - just don't start a section
break;
}
}
protected void endSection()
{
switch ( section )
{
case 1:
sink.section1_();
break;
case 2:
sink.section2_();
break;
case 3:
sink.section3_();
break;
case 4:
sink.section4_();
break;
case 5:
sink.section5_();
break;
default:
// TODO: warning - just don't start a section
break;
}
section = section - 1;
if ( section < 0 )
{
throw new IllegalStateException( "Too many closing sections" );
}
}
protected void tableHeaderCell( String text )
{
sink.tableHeaderCell();
sink.text( text );
sink.tableHeaderCell_();
}
protected void tableCell( String text )
{
sink.tableCell();
if ( text != null )
{
sink.text( text );
}
else
{
sink.nonBreakingSpace();
}
sink.tableCell_();
}
/**
* Create a cell with a potential link.
*
* @param text the text
* @param href the href
*/
protected void tableCellWithLink( String text, String href )
{
sink.tableCell();
if ( text != null )
{
if ( href != null )
{
String[] schemes = {"http", "https"};
UrlValidator urlValidator = new UrlValidator( schemes );
if ( EmailValidator.getInstance().isValid( href ) )
{
link( "mailto:" + href, text );
}
else if ( href.toLowerCase().startsWith( "mailto:" ) )
{
link( href, text );
}
else if ( urlValidator.isValid( href ) )
{
link( href, text );
}
else
{
sink.text( text );
}
}
else
{
sink.text( text );
}
}
else
{
sink.nonBreakingSpace();
}
sink.tableCell_();
}
protected void tableRow( String[] content )
{
sink.tableRow();
for ( int i = 0; i < content.length; i++ )
{
tableCell( content[i] );
}
sink.tableRow_();
}
/**
* Create a new row : each cell could have a link.
* <br>
* The arrays should have the same size.
*
* @param texts an array of text
* @param hrefs an array of href
*/
protected void tableRowWithLink( String[] texts, String[] hrefs )
{
if ( hrefs.length != texts.length )
{
throw new IllegalArgumentException( "The arrays should have the same size" );
}
sink.tableRow();
for ( int i = 0; i < texts.length; i++ )
{
tableCellWithLink( texts[i], hrefs[i] );
}
sink.tableRow_();
}
protected void tableHeader( String[] content )
{
sink.tableRow();
for ( int i = 0; i < content.length; i++ )
{
tableHeaderCell( content[i] );
}
sink.tableRow_();
}
protected void tableCaption( String caption )
{
sink.tableCaption();
sink.text( caption );
sink.tableCaption_();
}
protected void paragraph( String paragraph )
{
sink.paragraph();
sink.text( paragraph );
sink.paragraph_();
}
protected void link( String href, String name )
{
sink.link( href );
sink.text( name );
sink.link_();
}
public abstract String getTitle();
protected abstract void renderBody();
}
package org.apache.maven.reporting;
/*
* Copyright 2004-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import org.apache.commons.validator.EmailValidator;
import org.apache.commons.validator.UrlValidator;
import org.codehaus.doxia.sink.Sink;
import org.codehaus.plexus.util.StringUtils;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
/**
* An abstract class to manage report generation.
*
* @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
* @author <a href="evenisse@apache.org">Emmanuel Venisse</a>
* @author <a href="mailto:vincent.siveton@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.
*/
public abstract class AbstractMavenReportRenderer
implements MavenReportRenderer
{
protected Sink sink;
private int section;
public AbstractMavenReportRenderer( Sink sink )
{
this.sink = sink;
}
public void render()
{
sink.head();
sink.title();
text( getTitle() );
sink.title_();
sink.head_();
sink.body();
renderBody();
sink.body_();
sink.flush();
sink.close();
}
protected void startTable()
{
sink.table();
}
protected void endTable()
{
sink.table_();
}
protected void startSection( String name )
{
section = section + 1;
switch ( section )
{
case 1:
sink.section1();
sink.sectionTitle1();
break;
case 2:
sink.section2();
sink.sectionTitle2();
break;
case 3:
sink.section3();
sink.sectionTitle3();
break;
case 4:
sink.section4();
sink.sectionTitle4();
break;
case 5:
sink.section5();
sink.sectionTitle5();
break;
default:
// TODO: warning - just don't start a section
break;
}
text( name );
switch ( section )
{
case 1:
sink.sectionTitle1_();
break;
case 2:
sink.sectionTitle2_();
break;
case 3:
sink.sectionTitle3_();
break;
case 4:
sink.sectionTitle4_();
break;
case 5:
sink.sectionTitle5_();
break;
default:
// TODO: warning - just don't start a section
break;
}
}
protected void endSection()
{
switch ( section )
{
case 1:
sink.section1_();
break;
case 2:
sink.section2_();
break;
case 3:
sink.section3_();
break;
case 4:
sink.section4_();
break;
case 5:
sink.section5_();
break;
default:
// TODO: warning - just don't start a section
break;
}
section = section - 1;
if ( section < 0 )
{
throw new IllegalStateException( "Too many closing sections" );
}
}
protected void tableHeaderCell( String text )
{
sink.tableHeaderCell();
text( text );
sink.tableHeaderCell_();
}
/**
* Add a cell in a table.
* <p>The text could be a link patterned text defined by <code>{text, url}</code></p>
*
* @param text
* @see #linkPatternedText(String)
*/
protected void tableCell( String text )
{
sink.tableCell();
linkPatternedText( text );
sink.tableCell_();
}
protected void tableRow( String[] content )
{
sink.tableRow();
for ( int i = 0; i < content.length; i++ )
{
tableCell( content[i] );
}
sink.tableRow_();
}
protected void tableHeader( String[] content )
{
sink.tableRow();
for ( int i = 0; i < content.length; i++ )
{
tableHeaderCell( content[i] );
}
sink.tableRow_();
}
protected void tableCaption( String caption )
{
sink.tableCaption();
text( caption );
sink.tableCaption_();
}
protected void paragraph( String paragraph )
{
sink.paragraph();
text( paragraph );
sink.paragraph_();
}
protected void link( String href, String name )
{
sink.link( href );
text( name );
sink.link_();
}
/**
* Add a new text.
* <p>If text is empty of has a null value, add the "-" charater</p>
*
* @param text a string
*/
protected void text( String text )
{
if ( text == null || text.length() == 0 ) // Take care of spaces
{
sink.text( "-" );
}
else
{
sink.text( text );
}
}
/**
* Add a verbatim text.
*
* @param text a string
* @see #text(String)
*/
protected void verbatimText( String text )
{
sink.verbatim( true );
text( text );
sink.verbatim_();
}
/**
* Add a verbatim text with a specific link.
*
* @param text a string
* @param href an href could be null
* @see #link(String, String)
*/
protected void verbatimLink( String text, String href )
{
if ( StringUtils.isEmpty( href ) )
{
verbatimText( text );
}
else
{
sink.verbatim( true );
link( href, text );
sink.verbatim_();
}
}
/**
* Add a Javascript code.
*
* @param jsCode a string of Javascript
*/
protected void javaScript( String jsCode )
{
sink.rawText( "<script type=\"text/javascript\">\n" + jsCode + "</script>" );
}
/**
* Add a text with links inside.
* <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 #applyPattern(String)
*/
public void linkPatternedText( String text )
{
if ( StringUtils.isEmpty( text ) )
{
text( text );
}
else
{
Map segments = applyPattern( text );
if ( segments == null )
{
text( text );
}
else
{
for ( Iterator it = segments.entrySet().iterator(); it.hasNext(); )
{
Map.Entry entry = (Map.Entry) it.next();
String name = (String) entry.getKey();
String href = (String) entry.getValue();
if ( href == null )
{
text( name );
}
else
{
if ( getValidHref( href ) != null )
{
link( getValidHref( href ), name );
}
else
{
text( text );
}
}
}
}
}
}
/**
* Create a link pattern text defined by <code>{text, url}</code>.
* <p>This created pattern could be used by the method <code>linkPatternedText(String)</code> to
* handle a text with link.</p>
*
* @param text
* @param href
* @return a link pattern
* @see #linkPatternedText(String)
*/
protected static String createLinkPatternedText( String text, String href )
{
if ( text == null )
{
return text;
}
if ( href == null )
{
return text;
}
StringBuffer sb = new StringBuffer();
sb.append( "{" ).append( text ).append( ", " ).append( href ).append( "}" );
return sb.toString();
}
/**
* Convenience method to display a <code>Properties</code> object comma separated.
*
* @param props
* @return the properties object as comma separated String
*/
protected static String propertiesToString( Properties props )
{
StringBuffer sb = new StringBuffer();
if ( props == null || props.isEmpty() )
{
return sb.toString();
}
for ( Iterator i = props.keySet().iterator(); i.hasNext(); )
{
String key = (String) i.next();
sb.append( key ).append( "=" ).append( props.get( key ) );
if ( i.hasNext() )
{
sb.append( ", " );
}
}
return sb.toString();
}
/**
* Return a valid href.
* <p>A valid href could start by <code>mailto:</code></p>.
*
* @param href an href
* @return a valid href or null if the href is not valid.
*/
private static String getValidHref( String href )
{
href = href.trim();
String[] schemes = {"http", "https"};
UrlValidator urlValidator = new UrlValidator( schemes );
if ( EmailValidator.getInstance().isValid( href ) )
{
return "mailto:" + href;
}
else if ( href.toLowerCase().startsWith( "mailto:" ) )
{
return href;
}
else if ( urlValidator.isValid( href ) )
{
return href;
}
else
{
// TODO Waiting for new release of Validator
// http://issues.apache.org/bugzilla/show_bug.cgi?id=30686
String hrefTmp;
if ( !href.trim().endsWith( "/" ) )
{
hrefTmp = href + "/index.html";
}
else
{
hrefTmp = href + "index.html";
}
if ( urlValidator.isValid( hrefTmp ) )
{
return href;
}
return null;
}
}
/**
* The method parses a text an apply the given pattern <code>{text, url}</code> to create
* a map of text/href.
*
* @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 )
{
if ( StringUtils.isEmpty( text ) )
{
return null;
}
// Map defined by key/value name/href
// If href == null, it means
Map segments = new LinkedHashMap();
// TODO Special case http://jira.codehaus.org/browse/MEV-40
if ( text.indexOf( "${" ) != -1 )
{
int lastComma = text.lastIndexOf( "," );
int lastSemi = text.lastIndexOf( "}" );
if ( lastComma != -1 && lastSemi != -1 )
{
segments.put( text.substring( lastComma + 1, lastSemi ).trim(), null );
}
else
{
segments.put( text, null );
}
return segments;
}
boolean inQuote = false;
int braceStack = 0;
int lastOffset = 0;
for ( int i = 0; i < text.length(); i++ )
{
char ch = text.charAt( i );
if ( ch == '\'' && !inQuote )
{
// handle: ''
if ( i + 1 < text.length() && text.charAt( i + 1 ) == '\'' )
{
i++;
}
else
{
inQuote = true;
}
}
else
{
switch ( ch )
{
case '{':
if ( !inQuote )
{
if ( braceStack == 0 )
{
if ( i != 0 ) // handle { at first character
{
segments.put( text.substring( lastOffset, i ), null );
}
lastOffset = i + 1;
braceStack++;
}
}
break;
case '}':
if ( !inQuote )
{
braceStack--;
if ( braceStack == 0 )
{
String subString = text.substring( lastOffset, i );
lastOffset = i + 1;
int lastComma = subString.lastIndexOf( "," );
if ( lastComma != -1 )
{
segments.put( subString.substring( 0, lastComma ).trim(),
subString.substring( lastComma + 1 ).trim() );
}
else
{
segments.put( subString.substring( 0, lastComma ).trim(), null );
}
}
}
break;
case '\'':
inQuote = false;
break;
default:
break;
}
}
}
if ( !StringUtils.isEmpty( text.substring( lastOffset, text.length() ) ) )
{
segments.put( text.substring( lastOffset, text.length() ), null );
}
if ( braceStack != 0 )
{
throw new IllegalArgumentException( "Unmatched braces in the pattern." );
}
return Collections.unmodifiableMap( segments );
}
public abstract String getTitle();
protected abstract void renderBody();
}