(One implementation mimics Ant1 behaviour). These are added in the "workspace" packages, since that's where PropertyUtil was. Not sure if this is the right place. * DefaultTaskContext now implements Context interface, used by PropertyResolver. This avoids having the PropertyResolver dependent on TaskContext, avoiding a potential circularity problem. (since TaskContext has a "resolve" method of it's own). * Removed PropertyUtil. * Tests for PropertyResolver implementations. Submitted by Darrell DeBoer [darrell@apache.org] git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271801 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -237,4 +237,4 @@ public class Delete | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| } | |||||
| @@ -958,4 +958,4 @@ public class CBZip2InputStream | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| } | |||||
| @@ -338,4 +338,4 @@ public class TarOutputStream | |||||
| m_buffer.writeRecord( m_recordBuf ); | m_buffer.writeRecord( m_recordBuf ); | ||||
| } | } | ||||
| } | |||||
| } | |||||
| @@ -41,6 +41,7 @@ import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
| import org.apache.myrmidon.interfaces.service.MultiSourceServiceManager; | import org.apache.myrmidon.interfaces.service.MultiSourceServiceManager; | ||||
| import org.apache.myrmidon.interfaces.type.TypeFactory; | import org.apache.myrmidon.interfaces.type.TypeFactory; | ||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | import org.apache.myrmidon.interfaces.type.TypeManager; | ||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| import org.apache.myrmidon.interfaces.workspace.Workspace; | import org.apache.myrmidon.interfaces.workspace.Workspace; | ||||
| import org.apache.myrmidon.listeners.ProjectListener; | import org.apache.myrmidon.listeners.ProjectListener; | ||||
| @@ -254,6 +255,7 @@ public class DefaultEmbeddor | |||||
| createComponent( Deployer.class, PREFIX + "deployer.DefaultDeployer" ); | createComponent( Deployer.class, PREFIX + "deployer.DefaultDeployer" ); | ||||
| createComponent( ClassLoaderManager.class, PREFIX + "deployer.DefaultClassLoaderManager" ); | createComponent( ClassLoaderManager.class, PREFIX + "deployer.DefaultClassLoaderManager" ); | ||||
| createComponent( Executor.class, PREFIX + "executor.AspectAwareExecutor" ); | createComponent( Executor.class, PREFIX + "executor.AspectAwareExecutor" ); | ||||
| createComponent( PropertyResolver.class, PREFIX + "workspace.DefaultPropertyResolver" ); | |||||
| // Setup the components | // Setup the components | ||||
| for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | for( Iterator iterator = m_components.iterator(); iterator.hasNext(); ) | ||||
| @@ -0,0 +1,44 @@ | |||||
| /* | |||||
| * 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.workspace; | |||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.avalon.framework.context.ContextException; | |||||
| /** | |||||
| * A {@link PropertyResolver} implementation which resolves properties | |||||
| * as per Ant1, ignoring undefined properties. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class ClassicPropertyResolver | |||||
| extends DefaultPropertyResolver | |||||
| implements PropertyResolver | |||||
| { | |||||
| /** | |||||
| * Retrieve a value from the specified context using the specified key. | |||||
| * If there is no such value, returns the original property reference. | |||||
| * | |||||
| * @param propertyName the name of the property to retrieve | |||||
| * @param context the set of known properties | |||||
| */ | |||||
| protected Object getPropertyValue( final String propertyName, | |||||
| final Context context ) | |||||
| { | |||||
| try | |||||
| { | |||||
| return context.get( propertyName ); | |||||
| } | |||||
| catch( ContextException e ) | |||||
| { | |||||
| return "${" + propertyName + "}"; | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,255 @@ | |||||
| /* | |||||
| * 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.workspace; | |||||
| 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; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| /** | |||||
| * Base class for PropertyResolver implementations. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultPropertyResolver | |||||
| implements PropertyResolver | |||||
| { | |||||
| private final static Resources REZ = | |||||
| ResourceManager.getPackageResources( DefaultPropertyResolver.class ); | |||||
| /** | |||||
| * Resolve a string property. This evaluates all property | |||||
| * substitutions based on specified context. | |||||
| * | |||||
| * If the content contains a single property reference, then the property value | |||||
| * <code>Object</code> itself is returned. | |||||
| * Otherwise, a <code>String</code> is returned, comprising the supplied | |||||
| * content, with all property references replaced with the result of | |||||
| * <code>toString()</code> called on the property value. | |||||
| * | |||||
| * @param content the property to resolve | |||||
| * @param context the context in which to resolve property | |||||
| * @return the reolved property | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| public Object resolveProperties( final String content, | |||||
| final Context context ) | |||||
| throws TaskException | |||||
| { | |||||
| int start = findNextProperty( content, 0 ); | |||||
| if( -1 == start ) | |||||
| { | |||||
| return content; | |||||
| } | |||||
| int end = findEnding( content, start ); | |||||
| final int length = content.length(); | |||||
| if( 0 == start && end == ( length - 1 ) ) | |||||
| { | |||||
| return getPropertyValue( content.substring( start + 2, end ), | |||||
| context ); | |||||
| } | |||||
| final StringBuffer sb = new StringBuffer( length * 2 ); | |||||
| int lastPlace = 0; | |||||
| while( true ) | |||||
| { | |||||
| final Object propertyValue = | |||||
| getPropertyValue( content.substring( start + 2, end ), | |||||
| context ); | |||||
| sb.append( content.substring( lastPlace, start ) ); | |||||
| sb.append( propertyValue ); | |||||
| lastPlace = end + 1; | |||||
| start = findNextProperty( content, lastPlace ); | |||||
| if( -1 == start ) | |||||
| { | |||||
| break; | |||||
| } | |||||
| end = findEnding( content, start ); | |||||
| } | |||||
| sb.append( content.substring( lastPlace, length ) ); | |||||
| return sb.toString(); | |||||
| } | |||||
| /** | |||||
| * Resolve a string property. This recursively evaluates all property | |||||
| * substitutions based on specified context. | |||||
| * | |||||
| * @param content the property to resolve | |||||
| * @param context the context in which to resolve property | |||||
| * @return the reolved property | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| protected Object recursiveResolveProperty( final String content, | |||||
| final Context context ) | |||||
| throws TaskException | |||||
| { | |||||
| int start = findNextProperty( content, 0 ); | |||||
| if( -1 == start ) | |||||
| { | |||||
| return content; | |||||
| } | |||||
| int end = findNestedEnding( content, start ); | |||||
| final int length = content.length(); | |||||
| if( 0 == start && end == ( length - 1 ) ) | |||||
| { | |||||
| final String propertyName = content.substring( start + 2, end ); | |||||
| final Object key = recursiveResolveProperty( propertyName, context ); | |||||
| return getPropertyValue( key.toString(), context ); | |||||
| } | |||||
| final StringBuffer sb = new StringBuffer( length * 2 ); | |||||
| int lastPlace = 0; | |||||
| while( true ) | |||||
| { | |||||
| final String propertyName = content.substring( start + 2, end ); | |||||
| final Object key = recursiveResolveProperty( propertyName, context ); | |||||
| final Object value = getPropertyValue( key.toString(), context ); | |||||
| sb.append( content.substring( lastPlace, start ) ); | |||||
| sb.append( value ); | |||||
| lastPlace = end + 1; | |||||
| start = findNextProperty( content, lastPlace ); | |||||
| if( -1 == start ) | |||||
| { | |||||
| break; | |||||
| } | |||||
| end = findNestedEnding( content, start ); | |||||
| } | |||||
| sb.append( content.substring( lastPlace, length ) ); | |||||
| return sb.toString(); | |||||
| } | |||||
| /** | |||||
| * Finds the next occurrance of the start of a Property identifier. | |||||
| * @param content the String to search | |||||
| * @param currentPosition start location of the search | |||||
| * @return the position of the next occurrence, or <code>-1</code> if none | |||||
| * was found. | |||||
| */ | |||||
| private int findNextProperty( final String content, final int currentPosition ) | |||||
| { | |||||
| //TODO: Check if it is commented out | |||||
| return content.indexOf( "${", currentPosition ); | |||||
| } | |||||
| /** | |||||
| * Finds the next occurrence of the end of a Property identifier. | |||||
| * @param property the String to search | |||||
| * @param currentPosition start location of the search | |||||
| * @return the position of the next occurrence | |||||
| * @throws TaskException if no end was found | |||||
| */ | |||||
| private int findEnding( final String property, final int currentPosition ) | |||||
| throws TaskException | |||||
| { | |||||
| //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 TaskException( message ); | |||||
| } | |||||
| return index; | |||||
| } | |||||
| /** | |||||
| * Finds the end of the property identifier at the currentPosition, | |||||
| * taking into account nested property identifiers. | |||||
| * @param property the String to search | |||||
| * @param currentPosition location of the property | |||||
| * @return the position of the propery ending. | |||||
| * @throws TaskException if the property is not properly ended. | |||||
| */ | |||||
| private int findNestedEnding( final String property, final int currentPosition ) | |||||
| throws TaskException | |||||
| { | |||||
| 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 TaskException( message ); | |||||
| } | |||||
| /** | |||||
| * Retrieve a value from the specified context using the specified key. | |||||
| * | |||||
| * @param propertyName the key of value in context | |||||
| * @param context the set of known properties | |||||
| * @return the object retrieved from context | |||||
| * @exception TaskException if the property is undefined | |||||
| */ | |||||
| protected Object getPropertyValue( final String propertyName, | |||||
| final Context context ) | |||||
| throws TaskException | |||||
| { | |||||
| try | |||||
| { | |||||
| return context.get( propertyName ); | |||||
| } | |||||
| catch( ContextException e ) | |||||
| { | |||||
| final String message = REZ.getString( "prop.missing-value.error", propertyName ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -13,11 +13,14 @@ import java.util.Map; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | import org.apache.avalon.excalibur.i18n.ResourceManager; | ||||
| import org.apache.avalon.excalibur.i18n.Resources; | import org.apache.avalon.excalibur.i18n.Resources; | ||||
| import org.apache.avalon.excalibur.io.FileUtil; | import org.apache.avalon.excalibur.io.FileUtil; | ||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.avalon.framework.context.ContextException; | |||||
| import org.apache.avalon.framework.logger.Logger; | import org.apache.avalon.framework.logger.Logger; | ||||
| import org.apache.avalon.framework.service.ServiceException; | import org.apache.avalon.framework.service.ServiceException; | ||||
| import org.apache.avalon.framework.service.ServiceManager; | import org.apache.avalon.framework.service.ServiceManager; | ||||
| import org.apache.myrmidon.api.TaskContext; | import org.apache.myrmidon.api.TaskContext; | ||||
| import org.apache.myrmidon.api.TaskException; | import org.apache.myrmidon.api.TaskException; | ||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| /** | /** | ||||
| * Default implementation of TaskContext. | * Default implementation of TaskContext. | ||||
| @@ -26,7 +29,7 @@ import org.apache.myrmidon.api.TaskException; | |||||
| * @version $Revision$ $Date$ | * @version $Revision$ $Date$ | ||||
| */ | */ | ||||
| public class DefaultTaskContext | public class DefaultTaskContext | ||||
| implements TaskContext | |||||
| implements TaskContext, Context | |||||
| { | { | ||||
| private final static Resources REZ = | private final static Resources REZ = | ||||
| ResourceManager.getPackageResources( DefaultTaskContext.class ); | ResourceManager.getPackageResources( DefaultTaskContext.class ); | ||||
| @@ -35,6 +38,7 @@ public class DefaultTaskContext | |||||
| private final TaskContext m_parent; | private final TaskContext m_parent; | ||||
| private ServiceManager m_serviceManager; | private ServiceManager m_serviceManager; | ||||
| private Logger m_logger; | private Logger m_logger; | ||||
| private PropertyResolver m_propertyResolver; | |||||
| /** | /** | ||||
| * Constructor that takes both parent context and a service directory. | * Constructor that takes both parent context and a service directory. | ||||
| @@ -55,7 +59,7 @@ public class DefaultTaskContext | |||||
| */ | */ | ||||
| public String getName() | public String getName() | ||||
| { | { | ||||
| return (String)m_contextData.get( NAME ); | |||||
| return (String)getProperty( NAME ); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -65,7 +69,7 @@ public class DefaultTaskContext | |||||
| */ | */ | ||||
| public File getBaseDirectory() | public File getBaseDirectory() | ||||
| { | { | ||||
| return (File)m_contextData.get( BASE_DIRECTORY ); | |||||
| return (File)getProperty( BASE_DIRECTORY ); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -133,10 +137,17 @@ public class DefaultTaskContext | |||||
| public Object resolveValue( final String value ) | public Object resolveValue( final String value ) | ||||
| throws TaskException | throws TaskException | ||||
| { | { | ||||
| try | try | ||||
| { | { | ||||
| // Lazy lookup of the PropertyResolver | |||||
| if( m_propertyResolver == null ) | |||||
| { | |||||
| m_propertyResolver = (PropertyResolver)getService( PropertyResolver.class ); | |||||
| } | |||||
| final Object object = | final Object object = | ||||
| PropertyUtil.resolveProperty( value, this, false ); | |||||
| m_propertyResolver.resolveProperties( value, this ); | |||||
| if( null == object ) | if( null == object ) | ||||
| { | { | ||||
| @@ -161,7 +172,12 @@ public class DefaultTaskContext | |||||
| */ | */ | ||||
| public Object getProperty( final String name ) | public Object getProperty( final String name ) | ||||
| { | { | ||||
| return m_contextData.get( name ); | |||||
| Object value = m_contextData.get( name ); | |||||
| if( value == null && m_parent != null ) | |||||
| { | |||||
| value = m_parent.getProperty( name ); | |||||
| } | |||||
| return value; | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -332,6 +348,20 @@ public class DefaultTaskContext | |||||
| return context; | return context; | ||||
| } | } | ||||
| /** | |||||
| * Returns a property. | |||||
| */ | |||||
| public Object get( final Object key ) throws ContextException | |||||
| { | |||||
| final Object value = getProperty( (String)key ); | |||||
| if( value == null ) | |||||
| { | |||||
| final String message = REZ.getString( "unknown-property.error", key ); | |||||
| throw new ContextException( message ); | |||||
| } | |||||
| return value; | |||||
| } | |||||
| /** | /** | ||||
| * Make sure property is valid if it is one of the "magic" properties. | * Make sure property is valid if it is one of the "magic" properties. | ||||
| * | * | ||||
| @@ -1,239 +0,0 @@ | |||||
| /* | |||||
| * 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.workspace; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.myrmidon.api.TaskContext; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| /** | |||||
| * Utility class to evaluate properties. | |||||
| * | |||||
| * @author <a href="mailto:peter@apache.org">Peter Donald</a> | |||||
| * @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 TaskException if property is not found | |||||
| * @return the reolved property | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| public static Object resolveProperty( final String property, | |||||
| final TaskContext context, | |||||
| final boolean ignoreUndefined ) | |||||
| throws TaskException | |||||
| { | |||||
| 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 TaskException if property is not found | |||||
| * @return the reolved property | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| public static Object recursiveResolveProperty( final String property, | |||||
| final TaskContext context, | |||||
| final boolean ignoreUndefined ) | |||||
| throws TaskException | |||||
| { | |||||
| 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 TaskException | |||||
| { | |||||
| //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 TaskException( message ); | |||||
| } | |||||
| return index; | |||||
| } | |||||
| private static int findNestedEnding( final String property, final int currentPosition ) | |||||
| throws TaskException | |||||
| { | |||||
| 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 TaskException( 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 | |||||
| * TaskException 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 TaskException if an error occurs | |||||
| */ | |||||
| private static Object resolveValue( final String key, | |||||
| final TaskContext context, | |||||
| final boolean ignoreUndefined ) | |||||
| throws TaskException | |||||
| { | |||||
| final Object value = context.getProperty( key ); | |||||
| if( value != null ) | |||||
| { | |||||
| return value; | |||||
| } | |||||
| if( ignoreUndefined ) | |||||
| { | |||||
| return ""; | |||||
| } | |||||
| final String message = REZ.getString( "prop.missing-value.error", key ); | |||||
| throw new TaskException( message ); | |||||
| } | |||||
| } | |||||
| @@ -11,17 +11,13 @@ exec-target.notice=Executing target {0}. | |||||
| exec-task.notice=Executing task {0}. | exec-task.notice=Executing task {0}. | ||||
| #DefaultTaskContext | #DefaultTaskContext | ||||
| no-version.error=No JavaVersion in Context. | |||||
| no-name.error=No Name in Context. | |||||
| no-dir.error=No Base Directory in Context. | |||||
| no-parent.error=Can't set a property with parent scope when context has no parent. | |||||
| bad-scope.error=Unknown property scope! ({0}). | |||||
| unknown-prop.error=Unknown property {0}. | |||||
| bad-property.error=Property {0} must have a value of type {1}. | bad-property.error=Property {0} must have a value of type {1}. | ||||
| null-resolved-value.error=Value "{0}" resolved to null. | null-resolved-value.error=Value "{0}" resolved to null. | ||||
| bad-resolve.error=Unable to resolve value "{0}". | bad-resolve.error=Unable to resolve value "{0}". | ||||
| bad-find-service.error=Could not find service "{0}". | bad-find-service.error=Could not find service "{0}". | ||||
| bad-service-class.error=Find service "{0}" but it was of type {1} where it was expected to be of type {2}. | bad-service-class.error=Find service "{0}" but it was of type {1} where it was expected to be of type {2}. | ||||
| #PropertyUtil | |||||
| #AbstractPropertyResolver | |||||
| prop.mismatched-braces.error=Malformed property with mismatched }'s. | prop.mismatched-braces.error=Malformed property with mismatched }'s. | ||||
| prop.missing-value.error=Unable to find "{0}" to expand during property resolution. | prop.missing-value.error=Unable to find "{0}" to expand during property resolution. | ||||
| @@ -0,0 +1,38 @@ | |||||
| /* | |||||
| * 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.interfaces.workspace; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| /** | |||||
| * | |||||
| * Provides a service for the resolution of property identifiers within | |||||
| * String content. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public interface PropertyResolver | |||||
| { | |||||
| String ROLE = PropertyResolver.class.getName(); | |||||
| /** | |||||
| * Resolve a string property. This evaluates all property | |||||
| * substitutions based on specified contex. | |||||
| * Rules used for property resolution are implementation dependent. | |||||
| * | |||||
| * @param value the value to resolve, which may contain property identifiers | |||||
| * @param context the set of properties to resolve against. | |||||
| * @return the resolved content | |||||
| * @exception TaskException if an error occurs | |||||
| */ | |||||
| Object resolveProperties( final String value, | |||||
| final Context context ) | |||||
| throws TaskException; | |||||
| } | |||||
| @@ -27,6 +27,7 @@ import org.apache.myrmidon.components.deployer.DefaultDeployer; | |||||
| import org.apache.myrmidon.components.extensions.DefaultExtensionManager; | import org.apache.myrmidon.components.extensions.DefaultExtensionManager; | ||||
| import org.apache.myrmidon.components.role.DefaultRoleManager; | import org.apache.myrmidon.components.role.DefaultRoleManager; | ||||
| import org.apache.myrmidon.components.type.DefaultTypeManager; | import org.apache.myrmidon.components.type.DefaultTypeManager; | ||||
| import org.apache.myrmidon.components.workspace.DefaultPropertyResolver; | |||||
| import org.apache.myrmidon.interfaces.configurer.Configurer; | import org.apache.myrmidon.interfaces.configurer.Configurer; | ||||
| import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | ||||
| import org.apache.myrmidon.interfaces.deployer.Deployer; | import org.apache.myrmidon.interfaces.deployer.Deployer; | ||||
| @@ -36,6 +37,7 @@ import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
| import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | ||||
| import org.apache.myrmidon.interfaces.type.TypeException; | import org.apache.myrmidon.interfaces.type.TypeException; | ||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | import org.apache.myrmidon.interfaces.type.TypeManager; | ||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| /** | /** | ||||
| * A base class for tests for the default components. | * A base class for tests for the default components. | ||||
| @@ -120,6 +122,10 @@ public abstract class AbstractComponentTest | |||||
| m_serviceManager.put( RoleManager.ROLE, component ); | m_serviceManager.put( RoleManager.ROLE, component ); | ||||
| components.add( component ); | components.add( component ); | ||||
| component = new DefaultPropertyResolver(); | |||||
| m_serviceManager.put( PropertyResolver.ROLE, component ); | |||||
| components.add( component ); | |||||
| // Log enable the components | // Log enable the components | ||||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | ||||
| { | { | ||||
| @@ -0,0 +1,41 @@ | |||||
| /* | |||||
| * 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.workspace; | |||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| /** | |||||
| * A test for {@link ClassicPropertyResolver} | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class ClassicPropertyResolverTest | |||||
| extends DefaultPropertyResolverTest | |||||
| { | |||||
| public ClassicPropertyResolverTest( String name ) | |||||
| { | |||||
| super( name ); | |||||
| } | |||||
| protected PropertyResolver createResolver() | |||||
| { | |||||
| return new ClassicPropertyResolver(); | |||||
| } | |||||
| /** | |||||
| * Tests handing undefined property. | |||||
| */ | |||||
| public void testUndefinedProp() throws Exception | |||||
| { | |||||
| String undefinedProp = "undefinedProperty"; | |||||
| final String propRef = "${" + undefinedProp + "}"; | |||||
| doTestResolution( propRef, propRef, m_context ); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,167 @@ | |||||
| /* | |||||
| * 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.workspace; | |||||
| import java.io.File; | |||||
| import java.util.Date; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.components.AbstractComponentTest; | |||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| /** | |||||
| * Functional tests for {@link DefaultPropertyResolver}. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultPropertyResolverTest | |||||
| extends AbstractComponentTest | |||||
| { | |||||
| protected final static Resources REZ | |||||
| = ResourceManager.getPackageResources( DefaultPropertyResolver.class ); | |||||
| protected PropertyResolver m_resolver; | |||||
| protected DefaultTaskContext m_context; | |||||
| public DefaultPropertyResolverTest( String name ) | |||||
| { | |||||
| super( name ); | |||||
| } | |||||
| protected void setUp() throws Exception | |||||
| { | |||||
| super.setUp(); | |||||
| m_resolver = createResolver(); | |||||
| m_context = new DefaultTaskContext( null, getServiceManager(), getLogger() ); | |||||
| m_context.setProperty( "intProp", new Integer( 333 ) ); | |||||
| m_context.setProperty( "stringProp", "String property" ); | |||||
| } | |||||
| protected PropertyResolver createResolver() | |||||
| { | |||||
| return new DefaultPropertyResolver(); | |||||
| } | |||||
| /** | |||||
| * Test property resolution with various different typed properties. | |||||
| */ | |||||
| public void testPropertyTypes() throws Exception | |||||
| { | |||||
| testPropertyValue( new String( "String value" ) ); | |||||
| testPropertyValue( new Date() ); | |||||
| testPropertyValue( new Integer( Integer.MIN_VALUE ) ); | |||||
| testPropertyValue( new Double( 24234.98453 ) ); | |||||
| testPropertyValue( this.getClass() ); | |||||
| testPropertyValue( File.createTempFile( "PropertyResolverTest", null ) ); | |||||
| } | |||||
| /** | |||||
| * Simple tests with property on it's own, and accompanied by text. | |||||
| */ | |||||
| private void testPropertyValue( Object propObject ) | |||||
| throws Exception | |||||
| { | |||||
| m_context.setProperty( "typedProp", propObject ); | |||||
| String propString = propObject.toString(); | |||||
| doTestResolution( "${typedProp}", propObject, m_context ); | |||||
| doTestResolution( "${typedProp} with following text", | |||||
| propString + " with following text", m_context ); | |||||
| doTestResolution( "Preceding text with ${typedProp}", | |||||
| "Preceding text with " + propString, m_context ); | |||||
| } | |||||
| /** | |||||
| * Tests multiple property declarations in a single value. | |||||
| */ | |||||
| public void testMultipleProperties() throws Exception | |||||
| { | |||||
| m_context.setProperty( "prop1", "value1" ); | |||||
| m_context.setProperty( "prop2", "value2" ); | |||||
| m_context.setProperty( "int1", new Integer( 123 ) ); | |||||
| doTestResolution( "${prop1}${prop2}", "value1value2", m_context ); | |||||
| doTestResolution( "${prop1}${prop1}${prop1}", "value1value1value1", m_context ); | |||||
| doTestResolution( "before ${prop2} between ${prop1} after", | |||||
| "before value2 between value1 after", m_context ); | |||||
| doTestResolution( "${prop1}-${int1}-${prop2}", "value1-123-value2", m_context ); | |||||
| } | |||||
| /** | |||||
| * Tests handing undefined property. | |||||
| */ | |||||
| public void testUndefinedProp() throws Exception | |||||
| { | |||||
| String undefinedProp = "undefinedProperty"; | |||||
| doTestFailure( "${" + undefinedProp + "}", | |||||
| REZ.getString( "prop.missing-value.error", undefinedProp ), | |||||
| m_context ); | |||||
| //TODO - "" should be disallowed as a property name | |||||
| doTestFailure( "${}", | |||||
| REZ.getString( "prop.missing-value.error", "" ), | |||||
| m_context ); | |||||
| } | |||||
| /** | |||||
| * Tests illegal property syntax. | |||||
| */ | |||||
| public void testInvalidTypeDeclarations() throws Exception | |||||
| { | |||||
| doTestFailure( "${unclosed", | |||||
| REZ.getString( "prop.mismatched-braces.error" ), | |||||
| m_context ); | |||||
| doTestFailure( "${", | |||||
| REZ.getString( "prop.mismatched-braces.error" ), | |||||
| m_context ); | |||||
| /* TODO - need to handle these cases. */ | |||||
| // testFailure( "${bad${}", "", m_context ); | |||||
| // testFailure( "${ }", "", m_context ); | |||||
| } | |||||
| /** | |||||
| * Resolves the property using the supplied context, and checks the result. | |||||
| */ | |||||
| protected void doTestResolution( String value, | |||||
| Object expected, | |||||
| Context context ) | |||||
| throws Exception | |||||
| { | |||||
| Object resolved = m_resolver.resolveProperties( value, context ); | |||||
| assertEquals( expected, resolved ); | |||||
| } | |||||
| /** | |||||
| * Attempts to resolve the value using the supplied context, expecting to | |||||
| * fail with the supplied error message. | |||||
| */ | |||||
| protected void doTestFailure( String value, | |||||
| String expectedErrorMessage, | |||||
| Context context ) | |||||
| { | |||||
| try | |||||
| { | |||||
| m_resolver.resolveProperties( value, context ); | |||||
| fail( "Unexpected sucess - test should have failed." ); | |||||
| } | |||||
| catch( TaskException e ) | |||||
| { | |||||
| assertSameMessage( expectedErrorMessage, e ); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -27,6 +27,7 @@ import org.apache.myrmidon.components.deployer.DefaultDeployer; | |||||
| import org.apache.myrmidon.components.extensions.DefaultExtensionManager; | import org.apache.myrmidon.components.extensions.DefaultExtensionManager; | ||||
| import org.apache.myrmidon.components.role.DefaultRoleManager; | import org.apache.myrmidon.components.role.DefaultRoleManager; | ||||
| import org.apache.myrmidon.components.type.DefaultTypeManager; | import org.apache.myrmidon.components.type.DefaultTypeManager; | ||||
| import org.apache.myrmidon.components.workspace.DefaultPropertyResolver; | |||||
| import org.apache.myrmidon.interfaces.configurer.Configurer; | import org.apache.myrmidon.interfaces.configurer.Configurer; | ||||
| import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | import org.apache.myrmidon.interfaces.converter.ConverterRegistry; | ||||
| import org.apache.myrmidon.interfaces.deployer.Deployer; | import org.apache.myrmidon.interfaces.deployer.Deployer; | ||||
| @@ -36,6 +37,7 @@ import org.apache.myrmidon.interfaces.role.RoleManager; | |||||
| import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | import org.apache.myrmidon.interfaces.type.DefaultTypeFactory; | ||||
| import org.apache.myrmidon.interfaces.type.TypeException; | import org.apache.myrmidon.interfaces.type.TypeException; | ||||
| import org.apache.myrmidon.interfaces.type.TypeManager; | import org.apache.myrmidon.interfaces.type.TypeManager; | ||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| /** | /** | ||||
| * A base class for tests for the default components. | * A base class for tests for the default components. | ||||
| @@ -120,6 +122,10 @@ public abstract class AbstractComponentTest | |||||
| m_serviceManager.put( RoleManager.ROLE, component ); | m_serviceManager.put( RoleManager.ROLE, component ); | ||||
| components.add( component ); | components.add( component ); | ||||
| component = new DefaultPropertyResolver(); | |||||
| m_serviceManager.put( PropertyResolver.ROLE, component ); | |||||
| components.add( component ); | |||||
| // Log enable the components | // Log enable the components | ||||
| for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | for( Iterator iterator = components.iterator(); iterator.hasNext(); ) | ||||
| { | { | ||||
| @@ -0,0 +1,41 @@ | |||||
| /* | |||||
| * 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.workspace; | |||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| /** | |||||
| * A test for {@link ClassicPropertyResolver} | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class ClassicPropertyResolverTest | |||||
| extends DefaultPropertyResolverTest | |||||
| { | |||||
| public ClassicPropertyResolverTest( String name ) | |||||
| { | |||||
| super( name ); | |||||
| } | |||||
| protected PropertyResolver createResolver() | |||||
| { | |||||
| return new ClassicPropertyResolver(); | |||||
| } | |||||
| /** | |||||
| * Tests handing undefined property. | |||||
| */ | |||||
| public void testUndefinedProp() throws Exception | |||||
| { | |||||
| String undefinedProp = "undefinedProperty"; | |||||
| final String propRef = "${" + undefinedProp + "}"; | |||||
| doTestResolution( propRef, propRef, m_context ); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,167 @@ | |||||
| /* | |||||
| * 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.workspace; | |||||
| import java.io.File; | |||||
| import java.util.Date; | |||||
| import org.apache.avalon.excalibur.i18n.ResourceManager; | |||||
| import org.apache.avalon.excalibur.i18n.Resources; | |||||
| import org.apache.avalon.framework.context.Context; | |||||
| import org.apache.myrmidon.api.TaskException; | |||||
| import org.apache.myrmidon.components.AbstractComponentTest; | |||||
| import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||||
| /** | |||||
| * Functional tests for {@link DefaultPropertyResolver}. | |||||
| * | |||||
| * @author <a href="mailto:darrell@apache.org">Darrell DeBoer</a> | |||||
| * @version $Revision$ $Date$ | |||||
| */ | |||||
| public class DefaultPropertyResolverTest | |||||
| extends AbstractComponentTest | |||||
| { | |||||
| protected final static Resources REZ | |||||
| = ResourceManager.getPackageResources( DefaultPropertyResolver.class ); | |||||
| protected PropertyResolver m_resolver; | |||||
| protected DefaultTaskContext m_context; | |||||
| public DefaultPropertyResolverTest( String name ) | |||||
| { | |||||
| super( name ); | |||||
| } | |||||
| protected void setUp() throws Exception | |||||
| { | |||||
| super.setUp(); | |||||
| m_resolver = createResolver(); | |||||
| m_context = new DefaultTaskContext( null, getServiceManager(), getLogger() ); | |||||
| m_context.setProperty( "intProp", new Integer( 333 ) ); | |||||
| m_context.setProperty( "stringProp", "String property" ); | |||||
| } | |||||
| protected PropertyResolver createResolver() | |||||
| { | |||||
| return new DefaultPropertyResolver(); | |||||
| } | |||||
| /** | |||||
| * Test property resolution with various different typed properties. | |||||
| */ | |||||
| public void testPropertyTypes() throws Exception | |||||
| { | |||||
| testPropertyValue( new String( "String value" ) ); | |||||
| testPropertyValue( new Date() ); | |||||
| testPropertyValue( new Integer( Integer.MIN_VALUE ) ); | |||||
| testPropertyValue( new Double( 24234.98453 ) ); | |||||
| testPropertyValue( this.getClass() ); | |||||
| testPropertyValue( File.createTempFile( "PropertyResolverTest", null ) ); | |||||
| } | |||||
| /** | |||||
| * Simple tests with property on it's own, and accompanied by text. | |||||
| */ | |||||
| private void testPropertyValue( Object propObject ) | |||||
| throws Exception | |||||
| { | |||||
| m_context.setProperty( "typedProp", propObject ); | |||||
| String propString = propObject.toString(); | |||||
| doTestResolution( "${typedProp}", propObject, m_context ); | |||||
| doTestResolution( "${typedProp} with following text", | |||||
| propString + " with following text", m_context ); | |||||
| doTestResolution( "Preceding text with ${typedProp}", | |||||
| "Preceding text with " + propString, m_context ); | |||||
| } | |||||
| /** | |||||
| * Tests multiple property declarations in a single value. | |||||
| */ | |||||
| public void testMultipleProperties() throws Exception | |||||
| { | |||||
| m_context.setProperty( "prop1", "value1" ); | |||||
| m_context.setProperty( "prop2", "value2" ); | |||||
| m_context.setProperty( "int1", new Integer( 123 ) ); | |||||
| doTestResolution( "${prop1}${prop2}", "value1value2", m_context ); | |||||
| doTestResolution( "${prop1}${prop1}${prop1}", "value1value1value1", m_context ); | |||||
| doTestResolution( "before ${prop2} between ${prop1} after", | |||||
| "before value2 between value1 after", m_context ); | |||||
| doTestResolution( "${prop1}-${int1}-${prop2}", "value1-123-value2", m_context ); | |||||
| } | |||||
| /** | |||||
| * Tests handing undefined property. | |||||
| */ | |||||
| public void testUndefinedProp() throws Exception | |||||
| { | |||||
| String undefinedProp = "undefinedProperty"; | |||||
| doTestFailure( "${" + undefinedProp + "}", | |||||
| REZ.getString( "prop.missing-value.error", undefinedProp ), | |||||
| m_context ); | |||||
| //TODO - "" should be disallowed as a property name | |||||
| doTestFailure( "${}", | |||||
| REZ.getString( "prop.missing-value.error", "" ), | |||||
| m_context ); | |||||
| } | |||||
| /** | |||||
| * Tests illegal property syntax. | |||||
| */ | |||||
| public void testInvalidTypeDeclarations() throws Exception | |||||
| { | |||||
| doTestFailure( "${unclosed", | |||||
| REZ.getString( "prop.mismatched-braces.error" ), | |||||
| m_context ); | |||||
| doTestFailure( "${", | |||||
| REZ.getString( "prop.mismatched-braces.error" ), | |||||
| m_context ); | |||||
| /* TODO - need to handle these cases. */ | |||||
| // testFailure( "${bad${}", "", m_context ); | |||||
| // testFailure( "${ }", "", m_context ); | |||||
| } | |||||
| /** | |||||
| * Resolves the property using the supplied context, and checks the result. | |||||
| */ | |||||
| protected void doTestResolution( String value, | |||||
| Object expected, | |||||
| Context context ) | |||||
| throws Exception | |||||
| { | |||||
| Object resolved = m_resolver.resolveProperties( value, context ); | |||||
| assertEquals( expected, resolved ); | |||||
| } | |||||
| /** | |||||
| * Attempts to resolve the value using the supplied context, expecting to | |||||
| * fail with the supplied error message. | |||||
| */ | |||||
| protected void doTestFailure( String value, | |||||
| String expectedErrorMessage, | |||||
| Context context ) | |||||
| { | |||||
| try | |||||
| { | |||||
| m_resolver.resolveProperties( value, context ); | |||||
| fail( "Unexpected sucess - test should have failed." ); | |||||
| } | |||||
| catch( TaskException e ) | |||||
| { | |||||
| assertSameMessage( expectedErrorMessage, e ); | |||||
| } | |||||
| } | |||||
| } | |||||