mirror of https://github.com/apache/maven.git
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:
parent
19696518b3
commit
694bcf59ab
|
@ -1,42 +1,67 @@
|
||||||
<project>
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
|
||||||
<parent>
|
<!--
|
||||||
<artifactId>maven-reporting</artifactId>
|
/*
|
||||||
<groupId>org.apache.maven.reporting</groupId>
|
* Copyright 2001-2005 The Apache Software Foundation.
|
||||||
<version>2.0-beta-1-SNAPSHOT</version>
|
*
|
||||||
</parent>
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
<artifactId>maven-reporting-api</artifactId>
|
* you may not use this file except in compliance with the License.
|
||||||
<contributors>
|
* You may obtain a copy of the License at
|
||||||
<contributor>
|
*
|
||||||
<name>Vincent Siveton</name>
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
<email>vincent.siveton@gmail.com</email>
|
*
|
||||||
</contributor>
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
</contributors>
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
<dependencies>
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
<dependency>
|
* See the License for the specific language governing permissions and
|
||||||
<groupId>org.apache.maven</groupId>
|
* limitations under the License.
|
||||||
<artifactId>maven-project</artifactId>
|
*/
|
||||||
<version>2.0-beta-1-SNAPSHOT</version>
|
-->
|
||||||
</dependency>
|
|
||||||
<dependency>
|
<project>
|
||||||
<groupId>doxia</groupId>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>doxia-core</artifactId>
|
<parent>
|
||||||
<version>1.0-alpha-4-SNAPSHOT</version>
|
<artifactId>maven-reporting</artifactId>
|
||||||
</dependency>
|
<groupId>org.apache.maven.reporting</groupId>
|
||||||
<dependency>
|
<version>2.0-beta-1-SNAPSHOT</version>
|
||||||
<groupId>org.apache.maven</groupId>
|
</parent>
|
||||||
<artifactId>maven-plugin-api</artifactId>
|
<artifactId>maven-reporting-api</artifactId>
|
||||||
<version>2.0-beta-1-SNAPSHOT</version>
|
<developers>
|
||||||
</dependency>
|
<developer>
|
||||||
<dependency>
|
<id>vsiveton</id>
|
||||||
<groupId>commons-validator</groupId>
|
<name>Vincent Siveton</name>
|
||||||
<artifactId>commons-validator</artifactId>
|
<email>vincent.siveton@gmail.com</email>
|
||||||
<version>1.1.4</version>
|
<roles>
|
||||||
</dependency>
|
<role>Java Developer</role>
|
||||||
<dependency>
|
</roles>
|
||||||
<groupId>oro</groupId>
|
<timezone>-5</timezone>
|
||||||
<artifactId>oro</artifactId>
|
</developer>
|
||||||
<version>2.0.7</version>
|
</developers>
|
||||||
</dependency>
|
<dependencies>
|
||||||
</dependencies>
|
<dependency>
|
||||||
</project>
|
<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>
|
||||||
|
|
|
@ -1,315 +1,592 @@
|
||||||
package org.apache.maven.reporting;
|
package org.apache.maven.reporting;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright 2004-2005 The Apache Software Foundation.
|
* Copyright 2004-2005 The Apache Software Foundation.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* 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
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.apache.commons.validator.EmailValidator;
|
import org.apache.commons.validator.EmailValidator;
|
||||||
import org.apache.commons.validator.UrlValidator;
|
import org.apache.commons.validator.UrlValidator;
|
||||||
import org.codehaus.doxia.sink.Sink;
|
import org.codehaus.doxia.sink.Sink;
|
||||||
|
import org.codehaus.plexus.util.StringUtils;
|
||||||
/**
|
|
||||||
* @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
|
import java.util.Collections;
|
||||||
* @author <a href="evenisse@apache.org">Emmanuel Venisse</a>
|
import java.util.Iterator;
|
||||||
* @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
|
import java.util.LinkedHashMap;
|
||||||
* @version $Id: AbstractMavenReportRenderer.java 163373 2005-02-22 03:37:00Z brett $
|
import java.util.Map;
|
||||||
* @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.
|
import java.util.Properties;
|
||||||
*/
|
|
||||||
public abstract class AbstractMavenReportRenderer
|
/**
|
||||||
implements MavenReportRenderer
|
* An abstract class to manage report generation.
|
||||||
{
|
*
|
||||||
protected Sink sink;
|
* @author <a href="mailto:jason@maven.org">Jason van Zyl</a>
|
||||||
|
* @author <a href="evenisse@apache.org">Emmanuel Venisse</a>
|
||||||
private int section = 0;
|
* @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
|
||||||
|
* @version $Id: AbstractMavenReportRenderer.java 163373 2005-02-22 03:37:00Z brett $
|
||||||
public AbstractMavenReportRenderer( Sink sink )
|
* @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.
|
||||||
{
|
*/
|
||||||
this.sink = sink;
|
public abstract class AbstractMavenReportRenderer
|
||||||
}
|
implements MavenReportRenderer
|
||||||
|
{
|
||||||
public void render()
|
protected Sink sink;
|
||||||
{
|
|
||||||
sink.head();
|
private int section;
|
||||||
|
|
||||||
sink.title();
|
public AbstractMavenReportRenderer( Sink sink )
|
||||||
|
{
|
||||||
sink.text( getTitle() );
|
this.sink = sink;
|
||||||
|
}
|
||||||
sink.title_();
|
|
||||||
|
public void render()
|
||||||
sink.head_();
|
{
|
||||||
|
sink.head();
|
||||||
sink.body();
|
|
||||||
|
sink.title();
|
||||||
renderBody();
|
|
||||||
|
text( getTitle() );
|
||||||
sink.body_();
|
|
||||||
|
sink.title_();
|
||||||
sink.flush();
|
|
||||||
|
sink.head_();
|
||||||
sink.close();
|
|
||||||
}
|
sink.body();
|
||||||
|
|
||||||
protected void startTable()
|
renderBody();
|
||||||
{
|
|
||||||
sink.table();
|
sink.body_();
|
||||||
}
|
|
||||||
|
sink.flush();
|
||||||
protected void endTable()
|
|
||||||
{
|
sink.close();
|
||||||
sink.table_();
|
}
|
||||||
}
|
|
||||||
|
protected void startTable()
|
||||||
protected void startSection( String name )
|
{
|
||||||
{
|
sink.table();
|
||||||
section = section + 1;
|
}
|
||||||
|
|
||||||
switch ( section )
|
protected void endTable()
|
||||||
{
|
{
|
||||||
case 1:
|
sink.table_();
|
||||||
sink.section1();
|
}
|
||||||
sink.sectionTitle1();
|
|
||||||
break;
|
protected void startSection( String name )
|
||||||
case 2:
|
{
|
||||||
sink.section2();
|
section = section + 1;
|
||||||
sink.sectionTitle2();
|
|
||||||
break;
|
switch ( section )
|
||||||
case 3:
|
{
|
||||||
sink.section3();
|
case 1:
|
||||||
sink.sectionTitle3();
|
sink.section1();
|
||||||
break;
|
sink.sectionTitle1();
|
||||||
case 4:
|
break;
|
||||||
sink.section4();
|
case 2:
|
||||||
sink.sectionTitle4();
|
sink.section2();
|
||||||
break;
|
sink.sectionTitle2();
|
||||||
case 5:
|
break;
|
||||||
sink.section5();
|
case 3:
|
||||||
sink.sectionTitle5();
|
sink.section3();
|
||||||
break;
|
sink.sectionTitle3();
|
||||||
|
break;
|
||||||
default:
|
case 4:
|
||||||
// TODO: warning - just don't start a section
|
sink.section4();
|
||||||
break;
|
sink.sectionTitle4();
|
||||||
}
|
break;
|
||||||
|
case 5:
|
||||||
sink.text( name );
|
sink.section5();
|
||||||
|
sink.sectionTitle5();
|
||||||
switch ( section )
|
break;
|
||||||
{
|
|
||||||
case 1:
|
default:
|
||||||
sink.sectionTitle1_();
|
// TODO: warning - just don't start a section
|
||||||
break;
|
break;
|
||||||
case 2:
|
}
|
||||||
sink.sectionTitle2_();
|
|
||||||
break;
|
text( name );
|
||||||
case 3:
|
|
||||||
sink.sectionTitle3_();
|
switch ( section )
|
||||||
break;
|
{
|
||||||
case 4:
|
case 1:
|
||||||
sink.sectionTitle4_();
|
sink.sectionTitle1_();
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 2:
|
||||||
sink.sectionTitle5_();
|
sink.sectionTitle2_();
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
default:
|
sink.sectionTitle3_();
|
||||||
// TODO: warning - just don't start a section
|
break;
|
||||||
break;
|
case 4:
|
||||||
}
|
sink.sectionTitle4_();
|
||||||
}
|
break;
|
||||||
|
case 5:
|
||||||
protected void endSection()
|
sink.sectionTitle5_();
|
||||||
{
|
break;
|
||||||
switch ( section )
|
|
||||||
{
|
default:
|
||||||
case 1:
|
// TODO: warning - just don't start a section
|
||||||
sink.section1_();
|
break;
|
||||||
break;
|
}
|
||||||
case 2:
|
}
|
||||||
sink.section2_();
|
|
||||||
break;
|
protected void endSection()
|
||||||
case 3:
|
{
|
||||||
sink.section3_();
|
switch ( section )
|
||||||
break;
|
{
|
||||||
case 4:
|
case 1:
|
||||||
sink.section4_();
|
sink.section1_();
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 2:
|
||||||
sink.section5_();
|
sink.section2_();
|
||||||
break;
|
break;
|
||||||
|
case 3:
|
||||||
default:
|
sink.section3_();
|
||||||
// TODO: warning - just don't start a section
|
break;
|
||||||
break;
|
case 4:
|
||||||
}
|
sink.section4_();
|
||||||
|
break;
|
||||||
section = section - 1;
|
case 5:
|
||||||
|
sink.section5_();
|
||||||
if ( section < 0 )
|
break;
|
||||||
{
|
|
||||||
throw new IllegalStateException( "Too many closing sections" );
|
default:
|
||||||
}
|
// TODO: warning - just don't start a section
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
protected void tableHeaderCell( String text )
|
|
||||||
{
|
section = section - 1;
|
||||||
sink.tableHeaderCell();
|
|
||||||
|
if ( section < 0 )
|
||||||
sink.text( text );
|
{
|
||||||
|
throw new IllegalStateException( "Too many closing sections" );
|
||||||
sink.tableHeaderCell_();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void tableCell( String text )
|
protected void tableHeaderCell( String text )
|
||||||
{
|
{
|
||||||
sink.tableCell();
|
sink.tableHeaderCell();
|
||||||
|
|
||||||
if ( text != null )
|
text( text );
|
||||||
{
|
|
||||||
sink.text( text );
|
sink.tableHeaderCell_();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
/**
|
||||||
sink.nonBreakingSpace();
|
* Add a cell in a table.
|
||||||
}
|
* <p>The text could be a link patterned text defined by <code>{text, url}</code></p>
|
||||||
|
*
|
||||||
sink.tableCell_();
|
* @param text
|
||||||
}
|
* @see #linkPatternedText(String)
|
||||||
|
*/
|
||||||
/**
|
protected void tableCell( String text )
|
||||||
* Create a cell with a potential link.
|
{
|
||||||
*
|
sink.tableCell();
|
||||||
* @param text the text
|
|
||||||
* @param href the href
|
linkPatternedText( text );
|
||||||
*/
|
|
||||||
protected void tableCellWithLink( String text, String href )
|
sink.tableCell_();
|
||||||
{
|
}
|
||||||
sink.tableCell();
|
|
||||||
|
protected void tableRow( String[] content )
|
||||||
if ( text != null )
|
{
|
||||||
{
|
sink.tableRow();
|
||||||
if ( href != null )
|
|
||||||
{
|
for ( int i = 0; i < content.length; i++ )
|
||||||
String[] schemes = {"http", "https"};
|
{
|
||||||
UrlValidator urlValidator = new UrlValidator( schemes );
|
tableCell( content[i] );
|
||||||
|
}
|
||||||
if ( EmailValidator.getInstance().isValid( href ) )
|
|
||||||
{
|
sink.tableRow_();
|
||||||
link( "mailto:" + href, text );
|
}
|
||||||
}
|
|
||||||
else if ( href.toLowerCase().startsWith( "mailto:" ) )
|
protected void tableHeader( String[] content )
|
||||||
{
|
{
|
||||||
link( href, text );
|
sink.tableRow();
|
||||||
}
|
|
||||||
else if ( urlValidator.isValid( href ) )
|
for ( int i = 0; i < content.length; i++ )
|
||||||
{
|
{
|
||||||
link( href, text );
|
tableHeaderCell( content[i] );
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
sink.tableRow_();
|
||||||
sink.text( text );
|
}
|
||||||
}
|
|
||||||
}
|
protected void tableCaption( String caption )
|
||||||
else
|
{
|
||||||
{
|
sink.tableCaption();
|
||||||
sink.text( text );
|
text( caption );
|
||||||
}
|
sink.tableCaption_();
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
protected void paragraph( String paragraph )
|
||||||
sink.nonBreakingSpace();
|
{
|
||||||
}
|
sink.paragraph();
|
||||||
|
|
||||||
sink.tableCell_();
|
text( paragraph );
|
||||||
}
|
|
||||||
|
sink.paragraph_();
|
||||||
protected void tableRow( String[] content )
|
}
|
||||||
{
|
|
||||||
sink.tableRow();
|
protected void link( String href, String name )
|
||||||
|
{
|
||||||
for ( int i = 0; i < content.length; i++ )
|
sink.link( href );
|
||||||
{
|
|
||||||
tableCell( content[i] );
|
text( name );
|
||||||
}
|
|
||||||
|
sink.link_();
|
||||||
sink.tableRow_();
|
}
|
||||||
}
|
|
||||||
|
/**
|
||||||
/**
|
* Add a new text.
|
||||||
* Create a new row : each cell could have a link.
|
* <p>If text is empty of has a null value, add the "-" charater</p>
|
||||||
* <br>
|
*
|
||||||
* The arrays should have the same size.
|
* @param text a string
|
||||||
*
|
*/
|
||||||
* @param texts an array of text
|
protected void text( String text )
|
||||||
* @param hrefs an array of href
|
{
|
||||||
*/
|
if ( text == null || text.length() == 0 ) // Take care of spaces
|
||||||
protected void tableRowWithLink( String[] texts, String[] hrefs )
|
{
|
||||||
{
|
sink.text( "-" );
|
||||||
if ( hrefs.length != texts.length )
|
}
|
||||||
{
|
else
|
||||||
throw new IllegalArgumentException( "The arrays should have the same size" );
|
{
|
||||||
}
|
sink.text( text );
|
||||||
|
}
|
||||||
sink.tableRow();
|
}
|
||||||
|
|
||||||
for ( int i = 0; i < texts.length; i++ )
|
/**
|
||||||
{
|
* Add a verbatim text.
|
||||||
tableCellWithLink( texts[i], hrefs[i] );
|
*
|
||||||
}
|
* @param text a string
|
||||||
|
* @see #text(String)
|
||||||
sink.tableRow_();
|
*/
|
||||||
}
|
protected void verbatimText( String text )
|
||||||
|
{
|
||||||
protected void tableHeader( String[] content )
|
sink.verbatim( true );
|
||||||
{
|
|
||||||
sink.tableRow();
|
text( text );
|
||||||
|
|
||||||
for ( int i = 0; i < content.length; i++ )
|
sink.verbatim_();
|
||||||
{
|
}
|
||||||
tableHeaderCell( content[i] );
|
|
||||||
}
|
/**
|
||||||
|
* Add a verbatim text with a specific link.
|
||||||
sink.tableRow_();
|
*
|
||||||
}
|
* @param text a string
|
||||||
|
* @param href an href could be null
|
||||||
protected void tableCaption( String caption )
|
* @see #link(String, String)
|
||||||
{
|
*/
|
||||||
sink.tableCaption();
|
protected void verbatimLink( String text, String href )
|
||||||
sink.text( caption );
|
{
|
||||||
sink.tableCaption_();
|
if ( StringUtils.isEmpty( href ) )
|
||||||
}
|
{
|
||||||
|
verbatimText( text );
|
||||||
protected void paragraph( String paragraph )
|
}
|
||||||
{
|
else
|
||||||
sink.paragraph();
|
{
|
||||||
|
sink.verbatim( true );
|
||||||
sink.text( paragraph );
|
|
||||||
|
link( href, text );
|
||||||
sink.paragraph_();
|
|
||||||
}
|
sink.verbatim_();
|
||||||
|
}
|
||||||
protected void link( String href, String name )
|
}
|
||||||
{
|
|
||||||
sink.link( href );
|
/**
|
||||||
|
* Add a Javascript code.
|
||||||
sink.text( name );
|
*
|
||||||
|
* @param jsCode a string of Javascript
|
||||||
sink.link_();
|
*/
|
||||||
}
|
protected void javaScript( String jsCode )
|
||||||
|
{
|
||||||
public abstract String getTitle();
|
sink.rawText( "<script type=\"text/javascript\">\n" + jsCode + "</script>" );
|
||||||
|
}
|
||||||
protected abstract void renderBody();
|
|
||||||
}
|
/**
|
||||||
|
* 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();
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue