diff --git a/proposal/myrmidon/src/java/org/apache/antlib/file/Delete.java b/proposal/myrmidon/src/java/org/apache/antlib/file/Delete.java
index 25187ec10..23baba5b4 100644
--- a/proposal/myrmidon/src/java/org/apache/antlib/file/Delete.java
+++ b/proposal/myrmidon/src/java/org/apache/antlib/file/Delete.java
@@ -237,4 +237,4 @@ public class Delete
}
}
}
-}
\ No newline at end of file
+}
diff --git a/proposal/myrmidon/src/java/org/apache/aut/bzip2/CBZip2InputStream.java b/proposal/myrmidon/src/java/org/apache/aut/bzip2/CBZip2InputStream.java
index f9582c492..4836549f7 100644
--- a/proposal/myrmidon/src/java/org/apache/aut/bzip2/CBZip2InputStream.java
+++ b/proposal/myrmidon/src/java/org/apache/aut/bzip2/CBZip2InputStream.java
@@ -958,4 +958,4 @@ public class CBZip2InputStream
}
}
}
-}
\ No newline at end of file
+}
diff --git a/proposal/myrmidon/src/java/org/apache/aut/tar/TarOutputStream.java b/proposal/myrmidon/src/java/org/apache/aut/tar/TarOutputStream.java
index 2b78ae49d..a338919bc 100644
--- a/proposal/myrmidon/src/java/org/apache/aut/tar/TarOutputStream.java
+++ b/proposal/myrmidon/src/java/org/apache/aut/tar/TarOutputStream.java
@@ -338,4 +338,4 @@ public class TarOutputStream
m_buffer.writeRecord( m_recordBuf );
}
-}
\ No newline at end of file
+}
diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java
index 1882401c2..476969f8b 100644
--- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java
+++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/embeddor/DefaultEmbeddor.java
@@ -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(); )
diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ClassicPropertyResolver.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ClassicPropertyResolver.java
new file mode 100644
index 000000000..2b9b384c3
--- /dev/null
+++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/ClassicPropertyResolver.java
@@ -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 Darrell DeBoer
+ * @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 + "}";
+ }
+ }
+}
diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultPropertyResolver.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultPropertyResolver.java
new file mode 100644
index 000000000..d75e3e805
--- /dev/null
+++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultPropertyResolver.java
@@ -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 Peter Donald
+ * @author Darrell DeBoer
+ * @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
+ * Object
itself is returned.
+ * Otherwise, a String
is returned, comprising the supplied
+ * content, with all property references replaced with the result of
+ * toString()
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 -1
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 );
+ }
+ }
+}
+
diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java
index d1d033755..5224a34aa 100644
--- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java
+++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/DefaultTaskContext.java
@@ -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.
*
diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/PropertyUtil.java b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/PropertyUtil.java
deleted file mode 100644
index 6b6b25322..000000000
--- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/PropertyUtil.java
+++ /dev/null
@@ -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 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 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 );
- }
-}
-
diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties
index 582395c6b..c2db45564 100644
--- a/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties
+++ b/proposal/myrmidon/src/java/org/apache/myrmidon/components/workspace/Resources.properties
@@ -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.
diff --git a/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/workspace/PropertyResolver.java b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/workspace/PropertyResolver.java
new file mode 100644
index 000000000..4da9ad1fe
--- /dev/null
+++ b/proposal/myrmidon/src/java/org/apache/myrmidon/interfaces/workspace/PropertyResolver.java
@@ -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 Darrell DeBoer
+ * @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;
+}
diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java
index c6a3052fb..3a49f0fb6 100644
--- a/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java
+++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/AbstractComponentTest.java
@@ -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(); )
{
diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java
new file mode 100644
index 000000000..514b4e11e
--- /dev/null
+++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java
@@ -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 Darrell DeBoer
+ * @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 );
+ }
+}
diff --git a/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java b/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java
new file mode 100644
index 000000000..1657b5339
--- /dev/null
+++ b/proposal/myrmidon/src/test/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java
@@ -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 Darrell DeBoer
+ * @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 );
+ }
+ }
+}
diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java
index c6a3052fb..3a49f0fb6 100644
--- a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java
+++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/AbstractComponentTest.java
@@ -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(); )
{
diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java
new file mode 100644
index 000000000..514b4e11e
--- /dev/null
+++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/ClassicPropertyResolverTest.java
@@ -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 Darrell DeBoer
+ * @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 );
+ }
+}
diff --git a/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java
new file mode 100644
index 000000000..1657b5339
--- /dev/null
+++ b/proposal/myrmidon/src/testcases/org/apache/myrmidon/components/workspace/DefaultPropertyResolverTest.java
@@ -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 Darrell DeBoer
+ * @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 );
+ }
+ }
+}