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 );
        }
 
        /**

Reply via email to