/*
* This program is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software
* Foundation.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html
* or from the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved.
*/
package org.pentaho.reporting.engine.classic.core.modules.parser.base;
import java.awt.Color;
import java.awt.Stroke;
import java.util.StringTokenizer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.pentaho.reporting.engine.classic.core.ClassicEngineBoot;
import org.pentaho.reporting.engine.classic.core.ElementAlignment;
import org.pentaho.reporting.engine.classic.core.style.VerticalTextAlign;
import org.pentaho.reporting.engine.classic.core.util.StrokeUtility;
import org.pentaho.reporting.engine.classic.core.util.beans.ColorValueConverter;
import org.pentaho.reporting.libraries.base.util.StringUtils;
import org.pentaho.reporting.libraries.xmlns.common.ParserUtil;
import org.pentaho.reporting.libraries.xmlns.parser.ParseException;
import org.pentaho.reporting.libraries.xmlns.parser.RootXmlReadHandler;
import org.xml.sax.Locator;
/**
* A helper class to make parsing the xml files a lot easier.
*
* @author Thomas Morgner
*/
public final class ReportParserUtil {
public static final String INCLUDE_PARSING_KEY = "::Include-parser";
public static final Object INCLUDE_PARSING_VALUE = Boolean.TRUE;
public static final String HELPER_OBJ_REPORT_NAME = "::Report";
public static final String HELPER_OBJ_LEGACY_STYLES = "::Legacy-Styles";
private static final Log logger = LogFactory.getLog( ReportParserUtil.class );
private static boolean strictParsing;
static {
strictParsing =
"true".equals( ClassicEngineBoot.getInstance().getGlobalConfig().getConfigProperty(
"org.pentaho.reporting.engine.classic.core.modules.parser.base.StrictParseMode" ) );
}
/**
* DefaultConstructor.
*/
private ReportParserUtil() {
}
/**
* Checks whether this report is a included report and not the main report definition.
*
* @param rootXmlReadHandler
* the root handler that provides access to the properties.
* @return true, if the report is included, false otherwise.
*/
public static boolean isIncluded( final RootXmlReadHandler rootXmlReadHandler ) {
return INCLUDE_PARSING_VALUE.equals( rootXmlReadHandler.getHelperObject( INCLUDE_PARSING_KEY ) );
}
/**
* Parses a vertical alignment value.
*
* @param value
* the text to parse.
* @param locator
* the locator provides the current parse position for meaningful error messages.
* @return the element alignment.
* @throws ParseException
* if the alignment value is not recognised.
*/
public static ElementAlignment parseVerticalElementAlignment( String value, final Locator locator )
throws ParseException {
if ( value == null ) {
return null;
}
// todo: Remove me
value = value.toLowerCase();
if ( "top".equals( value ) ) {
return ElementAlignment.TOP;
}
if ( "middle".equals( value ) ) {
return ElementAlignment.MIDDLE;
}
if ( "bottom".equals( value ) ) {
return ElementAlignment.BOTTOM;
}
if ( strictParsing ) {
throw new ParseException( "Invalid vertical alignment", locator );
}
if ( locator == null ) {
logger.warn( "Invalid value encountered for vertical alignment attribute." );
} else {
logger.warn( "Invalid value encountered for vertical alignment attribute. [Line: " + locator.getLineNumber()
+ " Column: " + locator.getColumnNumber() + "]" );
}
return ElementAlignment.TOP;
}
/**
* Parses a horizontal alignment value.
*
* @param value
* the text to parse.
* @param locator
* the locator provides the current parse position for meaningful error messages.
* @return the element alignment.
* @throws ParseException
* if a parse error occured.
*/
public static ElementAlignment parseHorizontalElementAlignment( String value, final Locator locator )
throws ParseException {
if ( value == null ) {
return null;
}
// todo: remove me
value = value.toLowerCase();
if ( "left".equals( value ) ) {
return ElementAlignment.LEFT;
}
if ( "center".equals( value ) ) {
return ElementAlignment.CENTER;
}
if ( "right".equals( value ) ) {
return ElementAlignment.RIGHT;
}
if ( "justify".equals( value ) ) {
return ElementAlignment.JUSTIFY;
}
if ( strictParsing ) {
throw new ParseException( "Invalid horizontal alignment", locator );
}
if ( locator == null ) {
logger.warn( "Invalid value encountered for horizontal alignment attribute." );
} else {
logger.warn( "Invalid value encountered for horizontal alignment attribute. [Line: " + locator.getLineNumber()
+ " Column: " + locator.getColumnNumber() + "]" );
}
return ElementAlignment.LEFT;
}
/**
* Reads an attribute as float and returns <code>def</code> if that fails.
*
* @param value
* the attribute value.
* @param locator
* the locator provides the current parse position for meaningful error messages.
* @return the float value.
* @throws ParseException
* if an parse error occured.
*/
public static Float parseFloat( final String value, final Locator locator ) throws ParseException {
if ( value == null ) {
return null;
}
try {
return new Float( value );
} catch ( Exception ex ) {
throw new ParseException( "Failed to parse value", locator );
}
}
public static Boolean parseBoolean( final String value, final Locator locator ) throws ParseException {
if ( value == null ) {
return null;
}
if ( "true".equals( value ) ) {
return Boolean.TRUE;
} else if ( "false".equals( value ) ) {
return Boolean.FALSE;
} else {
if ( strictParsing ) {
throw new ParseException( "Failed to parse value", locator );
}
if ( locator == null ) {
logger.warn( "Invalid value encountered for boolean attribute." );
} else {
logger.warn( "Invalid value encountered for boolean attribute. [Line: " + locator.getLineNumber() + " Column: "
+ locator.getColumnNumber() + "]" );
}
return Boolean.FALSE;
}
}
/**
* Reads an attribute as float and returns <code>def</code> if that fails.
*
* @param value
* the attribute value.
* @param locator
* the locator provides the current parse position for meaningful error messages.
* @return the float value.
* @throws ParseException
* if an parse error occured.
*/
public static Integer parseInteger( final String value, final Locator locator ) throws ParseException {
if ( value == null ) {
return null;
}
try {
return new Integer( value );
} catch ( Exception ex ) {
throw new ParseException( "Failed to parse value", locator );
}
}
/**
* Parses a color entry. If the entry is in hexadecimal or ocal notation, the color is created using Color.decode().
* If the string denotes a constant name of on of the color constants defined in java.awt.Color, this constant is
* used.
* <p/>
* As fallback the color black is returned if no color can be parsed.
*
* @param color
* the color (as a string).
* @return the paint.
*/
public static Color parseColor( final String color ) {
return parseColor( color, Color.black );
}
/**
* Parses a color entry. If the entry is in hexadecimal or octal notation, the color is created using Color.decode().
* If the string denotes a constant name of one of the color constants defined in java.awt.Color, this constant is
* used.
* <p/>
* As fallback the supplied default value is returned if no color can be parsed.
*
* @param color
* the color (as a string).
* @param defaultValue
* the default value (returned if no color can be parsed).
* @return the paint.
*/
public static Color parseColor( final String color, final Color defaultValue ) {
if ( color == null ) {
return defaultValue;
}
try {
// get color by hex or octal value
return (Color) new ColorValueConverter().toPropertyValue( color );
} catch ( Exception nfe ) {
return defaultValue;
}
}
/**
* Parses a position of an element. If a relative postion is given, the returnvalue is a negative number between 0 and
* -100.
*
* @param value
* the value.
* @param exceptionMessage
* the exception message.
* @param locator
* the locator provides the current parse position for meaningful error messages.
* @return the float value.
* @throws ParseException
* if there is a problem parsing the string.
*/
public static float parseRelativeFloat( final String value, final String exceptionMessage, final Locator locator )
throws ParseException {
if ( value == null ) {
throw new ParseException( exceptionMessage, locator );
}
if ( "auto".equalsIgnoreCase( value ) ) {
return Long.MIN_VALUE;
}
final String tvalue = value.trim();
if ( tvalue.length() > 0 && tvalue.charAt( tvalue.length() - 1 ) == '%' ) {
final String number = tvalue.substring( 0, tvalue.length() - 1 );
return ParserUtil.parseFloat( number, exceptionMessage, locator ) * -1.0f;
} else {
return ParserUtil.parseFloat( tvalue, exceptionMessage, locator );
}
}
public static Stroke parseStroke( final String strokeStyle, final float weight ) {
// "dashed | solid | dotted | dot-dot-dash | dot-dash"
if ( "dashed".equalsIgnoreCase( strokeStyle ) ) {
return StrokeUtility.createStroke( StrokeUtility.STROKE_DASHED, weight );
} else if ( "dotted".equalsIgnoreCase( strokeStyle ) ) {
return StrokeUtility.createStroke( StrokeUtility.STROKE_DOTTED, weight );
} else if ( "dot-dot-dash".equalsIgnoreCase( strokeStyle ) ) {
return StrokeUtility.createStroke( StrokeUtility.STROKE_DOT_DOT_DASH, weight );
} else if ( "dot-dash".equalsIgnoreCase( strokeStyle ) ) {
return StrokeUtility.createStroke( StrokeUtility.STROKE_DOT_DASH, weight );
} else {
return StrokeUtility.createStroke( StrokeUtility.STROKE_SOLID, weight );
}
}
public static VerticalTextAlign parseVerticalTextElementAlignment( final String value, final Locator locator )
throws ParseException {
if ( value == null ) {
return null;
}
if ( "top".equals( value ) ) {
return VerticalTextAlign.TOP;
}
if ( "middle".equals( value ) ) {
return VerticalTextAlign.MIDDLE;
}
if ( "bottom".equals( value ) ) {
return VerticalTextAlign.BOTTOM;
}
if ( "baseline".equals( value ) ) {
return VerticalTextAlign.BASELINE;
}
if ( "central".equals( value ) ) {
return VerticalTextAlign.CENTRAL;
}
if ( "sub".equals( value ) ) {
return VerticalTextAlign.SUB;
}
if ( "super".equals( value ) ) {
return VerticalTextAlign.SUPER;
}
if ( "text-bottom".equals( value ) ) {
return VerticalTextAlign.TEXT_BOTTOM;
}
if ( "text-top".equals( value ) ) {
return VerticalTextAlign.TEXT_TOP;
}
if ( "use-script".equals( value ) ) {
return VerticalTextAlign.USE_SCRIPT;
}
throw new ParseException( "Invalid vertical alignment", locator );
}
public static int parseVersion( final String s ) {
if ( StringUtils.isEmpty( s ) ) {
return -1;
}
try {
final StringTokenizer strtok = new StringTokenizer( s, "." );
int version = 0;
while ( strtok.hasMoreElements() ) {
final String token = strtok.nextToken();
final int i = Integer.parseInt( token );
version = version * 1000 + i;
}
return version;
} catch ( Exception e ) {
return -1;
}
}
}