Attached is a patch (let me know if I should submit this through the issue
tracker instead) to fix up the dereferencePropeties piece. I "borrowed"
some code from Ant's codebase to do the string substitutions as its fairly
involved (and obviously works just fine for Ant).
One thing I added was a call to dereferenceProperties where one was missing:
if( param_name == null && param_num == -1 )
return dereferenceProperties( value );
Ara made it sound like this was intentionally not dereferencing properties,
but I can't quite understand why it should not. It seems like it should
substitute properties for all tags like this:
@bla ${some.prop}
@bla "${some.prop}"
@bla msg="${some.prop}"
My patch takes care of substituting all properties, not just one. If you
literally want it to say "${some.prop}" in the output, you can do the Ant
trick of doubling the $... "$${some.prop}". Or if there is no matching
property then no substitution is done. And unlike Ant, if you specify this:
"${some.prop" and leave off the closing curly bracket it will simply return
"${some.prop" unexpanded and no error (Ant throws a BuildException for such
cases).
I think having these property substitutions is very slick and powerful. I
sure hope this patch gets applied!
Erik
cvs -q diff -u core/src/xdoclet/DocletContext.java
core/src/xdoclet/XDocletTagSupport.java
Index: core/src/xdoclet/DocletContext.java
===================================================================
RCS file: /cvsroot/xdoclet/xdoclet/core/src/xdoclet/DocletContext.java,v
retrieving revision 1.10
diff -u -r1.10 DocletContext.java
--- core/src/xdoclet/DocletContext.java 22 Jan 2002 16:02:09 -0000 1.10
+++ core/src/xdoclet/DocletContext.java 4 Mar 2002 21:21:50 -0000
@@ -6,6 +6,7 @@
import java.util.Set;
import java.util.Iterator;
import java.util.Map;
+import java.util.Collections;
import java.io.IOException;
/**
@@ -96,6 +97,11 @@
public String getProperty( String name )
{
return ( String ) properties.get( name );
+ }
+
+ public Map getProperties()
+ {
+ return Collections.unmodifiableMap( properties );
}
public Object getConfigParam( String name )
Index: core/src/xdoclet/XDocletTagSupport.java
===================================================================
RCS file: /cvsroot/xdoclet/xdoclet/core/src/xdoclet/XDocletTagSupport.java,v
retrieving revision 1.23
diff -u -r1.23 XDocletTagSupport.java
--- core/src/xdoclet/XDocletTagSupport.java 1 Mar 2002 12:07:36 -0000 1.23
+++ core/src/xdoclet/XDocletTagSupport.java 4 Mar 2002 21:21:53 -0000
@@ -2,6 +2,10 @@
import java.util.Properties;
import java.util.StringTokenizer;
+import java.util.Hashtable;
+import java.util.Vector;
+import java.util.Enumeration;
+import java.util.Map;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.FieldDoc;
@@ -52,6 +56,7 @@
* @param param_num
* @return The parameter value; null if not found
* @exception XDocletException
+ * @todo refactor this method! its a mess. :)
*/
public static String getParameterValue( ClassDoc clazz, String value, String
param_name, int param_num ) throws XDocletException
{
@@ -66,7 +71,7 @@
}
if( param_name == null && param_num == -1 )
- return value;
+ return dereferenceProperties( value );
String attr_name = "";
String attr_value = "";
@@ -77,7 +82,7 @@
{
i = TemplateEngine.skipWhitespace( value, i );
- //explicitly to handle the tailing white spaces
+ //explicitly to handle the trailing white spaces
if( i >= value.length() )
break;
@@ -106,9 +111,9 @@
if( params_parsed == 0 &&
value.trim().endsWith( "\"" ) )
{
- String trimed_value = value.trim();
+ String trimmed_value = value.trim();
- return dereferenceProperty(
trimed_value.substring( 1, trimed_value.length() - 1 ) );
+ return dereferenceProperties(
+trimmed_value.substring( 1, trimmed_value.length() - 1 ) );
//return the whole line minus
start/end " signs as the parameter
}
else
@@ -129,9 +134,9 @@
value = value.trim();
if( value.startsWith( "\"" ) &&
value.startsWith( "\"" ) )
- return dereferenceProperty(
value.substring( 1, value.length() - 1 ) );
+ return dereferenceProperties(
+value.substring( 1, value.length() - 1 ) );
- return dereferenceProperty( value );
+ return dereferenceProperties( value );
//return the whole line as the
parameter
}
else
@@ -210,7 +215,7 @@
new String[]{clazz.qualifiedName(), value} ) );
if( param_name != null && attr_name.equalsIgnoreCase(
param_name ) )
- return dereferenceProperty( attr_value );
+ return dereferenceProperties( attr_value );
else
{
params_parsed++;
@@ -399,6 +404,117 @@
}
/**
+ * Replaces <code>${xxx}</code> style constructions in the given value with the
+ * string value of the corresponding data types. NOTE: This method was taken
+ * directly from Ant's source code (org.apache.tools.ant.ProjectHelper) and
+ * modified slightly to use a Map instead of a Hashtable.
+ *
+ * @param value The string to be scanned for property references. May be
+ * <code>null</code>, in which case this method returns immediately with
+ * no effect.
+ * @param keys Mapping (String to String) of property names to their values.
+ * Must not be <code>null</code>.
+ * @return the original string with the properties replaced, or
+<code>null</code>
+ * if the original string is <code>null</code>.
+ */
+ public static String replaceProperties( String value, Map keys )
+ {
+ if( value == null )
+ {
+ return null;
+ }
+
+ Vector fragments = new Vector();
+ Vector propertyRefs = new Vector();
+
+ parsePropertyString( value, fragments, propertyRefs );
+
+ StringBuffer sb = new StringBuffer();
+ Enumeration i = fragments.elements();
+ Enumeration j = propertyRefs.elements();
+
+ while( i.hasMoreElements() )
+ {
+ String fragment = ( String ) i.nextElement();
+
+ if( fragment == null )
+ {
+ String propertyName = ( String ) j.nextElement();
+
+ fragment = ( keys.containsKey( propertyName ) ) ? (
+String ) keys.get( propertyName )
+ : "${" + propertyName + "}";
+ }
+ sb.append( fragment );
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Parses a string containing <code>${xxx}</code> style property references
+ * into two lists. The first list is a collection of text fragments, while the
+ * other is a set of string property names. <code>null</code> entries in the
+ * first list indicate a property reference from the second list. NOTE: This
+ * method was taken directly from Ant's source code
+ * (org.apache.tools.ant.ProjectHelper) with the BuildException throwing
+ * removed.
+ *
+ * @param value Text to parse. Must not be <code>null</code>.
+ * @param fragments List to add text fragments to. Must not be
+<code>null</code>
+ * .
+ * @param propertyRefs List to add property names to. Must not be
+<code>null</code>
+ * .
+ */
+ public static void parsePropertyString( String value, Vector fragments, Vector
+propertyRefs )
+ {
+ int prev = 0;
+ int pos;
+
+ while( ( pos = value.indexOf( "$", prev ) ) >= 0 )
+ {
+ if( pos > 0 )
+ {
+ fragments.addElement( value.substring( prev, pos ) );
+ }
+
+ if( pos == ( value.length() - 1 ) )
+ {
+ fragments.addElement( "$" );
+ prev = pos + 1;
+ }
+ else if( value.charAt( pos + 1 ) != '{' )
+ {
+ fragments.addElement( value.substring( pos + 1, pos +
+2 ) );
+ prev = pos + 2;
+ }
+ else
+ {
+ int endName = value.indexOf( '}', pos );
+
+ if( endName < 0 )
+ {
+ // In Ant this is a BuildException condition
+as its an
+ // incomplete property reference. Here we'll
+leave it
+ // in the output string
+ fragments.addElement( value.substring( pos ) );
+ return;
+ }
+
+ String propertyName = value.substring( pos + 2,
+endName );
+
+ fragments.addElement( null );
+ propertyRefs.addElement( propertyName );
+ prev = endName + 1;
+ }
+ }
+
+ if( prev < value.length() )
+ {
+ fragments.addElement( value.substring( prev ) );
+ }
+ }
+
+ /**
* @return the context object casted to DocletContext
*/
protected static DocletContext getDocletContext()
@@ -792,32 +908,17 @@
}
/**
- * Check to see if the value passed is the name of an ant property. If so
- * return the value of the ant property, otherwise return the value as passed
- * in.
+ * Replace properties in a string. Properties are in the form ${prop.name} and
+ * the replace properties are obtained from the DocletContext.
*
- * @param property The String to check for a property. Will be in the form of
- * ${property.name} if it is (ie the first two, and last character will be
- * stripped).
- * @return The value of the property, or the value passed if the value
- * is not a property.
+ * @param value The string to check for properties.
+ * @return The value replaced with any property substitutions
*/
- private static String dereferenceProperty( String property )
+ private static String dereferenceProperties( String value )
{
- if( property.length() < 4 || !property.substring( 0, 2 ).equals( "${"
) )
- {
- // is either less than 4 long, or doesn't start with ${
- // therefore not a property
-
- return property;
- }
-
- String propertyName = property.substring( 2, property.length() - 1 );
- String propertyValue = DocletContext.getInstance().getProperty(
propertyName );
-
- // check to see if the property has a value.
+ Map properties = DocletContext.getInstance().getProperties();
- return ( propertyValue != null ) ? propertyValue : propertyName;
+ return replaceProperties( value, properties );
}
/**