From 1b7d8d44fd80e84057b44965db5a9b39eb72545d Mon Sep 17 00:00:00 2001 From: Peter Donald Date: Thu, 21 Feb 2002 09:33:29 +0000 Subject: [PATCH] Add a PropertyUtil class that doesn't need avalons Context git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271471 13f79535-47bb-0310-9956-ffa450edef68 --- .../configurer/PropertyException.java | 37 +++ .../components/configurer/PropertyUtil.java | 245 ++++++++++++++++++ 2 files changed, 282 insertions(+) create mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyException.java create mode 100644 proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyUtil.java diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyException.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyException.java new file mode 100644 index 000000000..4c041f8b2 --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyException.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.myrmidon.components.configurer; + +/** + * Exception thrown when evaluating a property. + * + * @author Peter Donald + * @version $Revision$ $Date$ + */ +public class PropertyException + extends Exception +{ + /** + * Basic constructor for exception that does not specify a message + */ + public PropertyException() + { + this( "" ); + } + + /** + * Basic constructor with a message + * + * @param message the message + */ + public PropertyException( final String message ) + { + super( message ); + } +} + diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyUtil.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyUtil.java new file mode 100644 index 000000000..1c10f658f --- /dev/null +++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/configurer/PropertyUtil.java @@ -0,0 +1,245 @@ +/* + * Copyright (C) The Apache Software Foundation. All rights reserved. + * + * This software is published under the terms of the Apache Software License + * version 1.1, a copy of which has been included with this distribution in + * the LICENSE.txt file. + */ +package org.apache.myrmidon.components.configurer; + +import org.apache.avalon.excalibur.i18n.ResourceManager; +import org.apache.avalon.excalibur.i18n.Resources; +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.context.ContextException; + +/** + * Utility class to evaluate propertys. + * + * @author Peter Donald + * @version $Revision$ $Date$ + */ +public final class PropertyUtil +{ + private final static Resources REZ = + ResourceManager.getPackageResources( PropertyUtil.class ); + + private PropertyUtil() + { + } + + /** + * Resolve a string property. This evaluates all property + * substitutions based on specified context. + * + * @param property the property to resolve + * @param context the context in which to resolve property + * @param ignoreUndefined if false will throw an PropertyException if property is not found + * @return the reolved property + * @exception PropertyException if an error occurs + */ + public static Object resolveProperty( final String property, + final Context context, + final boolean ignoreUndefined ) + throws PropertyException + { + int start = findBeginning( property, 0 ); + if( -1 == start ) + { + return property; + } + + int end = findEnding( property, start ); + + final int length = property.length(); + + if( 0 == start && end == ( length - 1 ) ) + { + return resolveValue( property.substring( start + 2, end ), + context, + ignoreUndefined ); + } + + final StringBuffer sb = new StringBuffer( length * 2 ); + int lastPlace = 0; + + while( true ) + { + final Object value = + resolveValue( property.substring( start + 2, end ), + context, + ignoreUndefined ); + + sb.append( property.substring( lastPlace, start ) ); + sb.append( value ); + + lastPlace = end + 1; + + start = findBeginning( property, lastPlace ); + if( -1 == start ) + { + break; + } + + end = findEnding( property, start ); + } + + sb.append( property.substring( lastPlace, length ) ); + + return sb.toString(); + } + + /** + * Resolve a string property. This recursively evaluates all property + * substitutions based on specified context. + * + * @param property the property to resolve + * @param context the context in which to resolve property + * @param ignoreUndefined if false will throw an PropertyException if property is not found + * @return the reolved property + * @exception PropertyException if an error occurs + */ + public static Object recursiveResolveProperty( final String property, + final Context context, + final boolean ignoreUndefined ) + throws PropertyException + { + int start = findBeginning( property, 0 ); + if( -1 == start ) + { + return property; + } + + int end = findNestedEnding( property, start ); + + final int length = property.length(); + + if( 0 == start && end == ( length - 1 ) ) + { + final String propertyName = property.substring( start + 2, end ); + final Object key = recursiveResolveProperty( propertyName, context, ignoreUndefined ); + return resolveValue( key.toString(), context, ignoreUndefined ); + } + + final StringBuffer sb = new StringBuffer( length * 2 ); + + int lastPlace = 0; + + while( true ) + { + final String propertyName = property.substring( start + 2, end ); + final Object key = recursiveResolveProperty( propertyName, context, ignoreUndefined ); + final Object value = resolveValue( key.toString(), context, ignoreUndefined ); + + sb.append( property.substring( lastPlace, start ) ); + sb.append( value ); + + lastPlace = end + 1; + + start = findBeginning( property, lastPlace ); + if( -1 == start ) + { + break; + } + + end = findNestedEnding( property, start ); + } + + sb.append( property.substring( lastPlace, length ) ); + + return sb.toString(); + } + + private static int findBeginning( final String property, final int currentPosition ) + { + //TODO: Check if it is commented out + return property.indexOf( "${", currentPosition ); + } + + private static int findEnding( final String property, final int currentPosition ) + throws PropertyException + { + //TODO: Check if it is commented out + final int index = property.indexOf( '}', currentPosition ); + if( -1 == index ) + { + final String message = REZ.getString( "prop.mismatched-braces.error" ); + throw new PropertyException( message ); + } + + return index; + } + + private static int findNestedEnding( final String property, final int currentPosition ) + throws PropertyException + { + final int length = property.length(); + final int start = currentPosition + 2; + + int weight = 1; + for( int i = start; ( weight > 0 ) && ( i < length ); i++ ) + { + final char ch = property.charAt( i ); + switch( ch ) + { + case '}': + //TODO: Check if it is commented out + weight--; + if( weight == 0 ) + { + return i; + } + break; + + case '$': + { + //TODO: Check if it is commented out + final int next = i + 1; + if( next < length && '{' == property.charAt( next ) ) + { + weight++; + } + } + break; + } + } + + final String message = REZ.getString( "prop.mismatched-braces.error" ); + throw new PropertyException( message ); + } + + /** + * Retrieve a value from the specified context using the specified key. + * If there is no such value and ignoreUndefined is not false then a + * PropertyException is generated. + * + * @param key the key of value in context + * @param context the Context + * @param ignoreUndefined true if undefined variables are ignored + * @return the object retrieved from context + * @exception PropertyException if an error occurs + */ + private static Object resolveValue( final String key, + final Context context, + final boolean ignoreUndefined ) + throws PropertyException + { + try + { + return context.get( key ); + } + catch( final ContextException ce ) + { + if( ignoreUndefined ) + { + return ""; + } + else + { + final String message = + REZ.getString( "prop.missing-value.error", key ); + throw new PropertyException( message ); + } + } + } +} +