(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 ); | |||
} | |||
} | |||
} |
@@ -41,6 +41,7 @@ import org.apache.myrmidon.interfaces.role.RoleManager; | |||
import org.apache.myrmidon.interfaces.service.MultiSourceServiceManager; | |||
import org.apache.myrmidon.interfaces.type.TypeFactory; | |||
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.listeners.ProjectListener; | |||
@@ -254,6 +255,7 @@ public class DefaultEmbeddor | |||
createComponent( Deployer.class, PREFIX + "deployer.DefaultDeployer" ); | |||
createComponent( ClassLoaderManager.class, PREFIX + "deployer.DefaultClassLoaderManager" ); | |||
createComponent( Executor.class, PREFIX + "executor.AspectAwareExecutor" ); | |||
createComponent( PropertyResolver.class, PREFIX + "workspace.DefaultPropertyResolver" ); | |||
// Setup the components | |||
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.Resources; | |||
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.service.ServiceException; | |||
import org.apache.avalon.framework.service.ServiceManager; | |||
import org.apache.myrmidon.api.TaskContext; | |||
import org.apache.myrmidon.api.TaskException; | |||
import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||
/** | |||
* Default implementation of TaskContext. | |||
@@ -26,7 +29,7 @@ import org.apache.myrmidon.api.TaskException; | |||
* @version $Revision$ $Date$ | |||
*/ | |||
public class DefaultTaskContext | |||
implements TaskContext | |||
implements TaskContext, Context | |||
{ | |||
private final static Resources REZ = | |||
ResourceManager.getPackageResources( DefaultTaskContext.class ); | |||
@@ -35,6 +38,7 @@ public class DefaultTaskContext | |||
private final TaskContext m_parent; | |||
private ServiceManager m_serviceManager; | |||
private Logger m_logger; | |||
private PropertyResolver m_propertyResolver; | |||
/** | |||
* Constructor that takes both parent context and a service directory. | |||
@@ -55,7 +59,7 @@ public class DefaultTaskContext | |||
*/ | |||
public String getName() | |||
{ | |||
return (String)m_contextData.get( NAME ); | |||
return (String)getProperty( NAME ); | |||
} | |||
/** | |||
@@ -65,7 +69,7 @@ public class DefaultTaskContext | |||
*/ | |||
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 ) | |||
throws TaskException | |||
{ | |||
try | |||
{ | |||
// Lazy lookup of the PropertyResolver | |||
if( m_propertyResolver == null ) | |||
{ | |||
m_propertyResolver = (PropertyResolver)getService( PropertyResolver.class ); | |||
} | |||
final Object object = | |||
PropertyUtil.resolveProperty( value, this, false ); | |||
m_propertyResolver.resolveProperties( value, this ); | |||
if( null == object ) | |||
{ | |||
@@ -161,7 +172,12 @@ public class DefaultTaskContext | |||
*/ | |||
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; | |||
} | |||
/** | |||
* 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. | |||
* | |||
@@ -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}. | |||
#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}. | |||
null-resolved-value.error=Value "{0}" resolved to null. | |||
bad-resolve.error=Unable to resolve value "{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}. | |||
#PropertyUtil | |||
#AbstractPropertyResolver | |||
prop.mismatched-braces.error=Malformed property with mismatched }'s. | |||
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.role.DefaultRoleManager; | |||
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.converter.ConverterRegistry; | |||
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.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||
/** | |||
* A base class for tests for the default components. | |||
@@ -120,6 +122,10 @@ public abstract class AbstractComponentTest | |||
m_serviceManager.put( RoleManager.ROLE, component ); | |||
components.add( component ); | |||
component = new DefaultPropertyResolver(); | |||
m_serviceManager.put( PropertyResolver.ROLE, component ); | |||
components.add( component ); | |||
// Log enable the components | |||
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.role.DefaultRoleManager; | |||
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.converter.ConverterRegistry; | |||
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.TypeException; | |||
import org.apache.myrmidon.interfaces.type.TypeManager; | |||
import org.apache.myrmidon.interfaces.workspace.PropertyResolver; | |||
/** | |||
* A base class for tests for the default components. | |||
@@ -120,6 +122,10 @@ public abstract class AbstractComponentTest | |||
m_serviceManager.put( RoleManager.ROLE, component ); | |||
components.add( component ); | |||
component = new DefaultPropertyResolver(); | |||
m_serviceManager.put( PropertyResolver.ROLE, component ); | |||
components.add( component ); | |||
// Log enable the components | |||
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 ); | |||
} | |||
} | |||
} |