Clover coverage report - ConfigKit - 1.2
Coverage timestamp: Wed Dec 3 2003 14:29:16 EST
file stats: LOC: 257   Methods: 8
NCLOC: 143   Classes: 1
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
PropertyExpander.java 100% 100% 100% 100%
coverage
 1   
 /*
 2   
  * Copyright (C) The Spice Group. All rights reserved.
 3   
  *
 4   
  * This software is published under the terms of the Spice
 5   
  * Software License version 1.1, a copy of which has been included
 6   
  * with this distribution in the LICENSE.txt file.
 7   
  */
 8   
 package org.codehaus.spice.configkit;
 9   
 
 10   
 import java.util.Iterator;
 11   
 import java.util.Map;
 12   
 import java.util.Properties;
 13   
 import org.w3c.dom.Attr;
 14   
 import org.w3c.dom.Element;
 15   
 import org.w3c.dom.NamedNodeMap;
 16   
 import org.w3c.dom.Node;
 17   
 import org.w3c.dom.NodeList;
 18   
 import org.w3c.dom.Text;
 19   
 
 20   
 /**
 21   
  * This is a utility class designed for expanding propertys in configuration
 22   
  * files. Propertys are stored in Map objects and any section that begins with
 23   
  * "${" and ends with "}" will have inner name replaced with property value from
 24   
  * map.
 25   
  *
 26   
  * @author Peter Donald
 27   
  * @version $Revision: 1.1 $ $Date: 2003/12/03 03:19:28 $
 28   
  */
 29   
 public final class PropertyExpander
 30   
 {
 31   
     /**
 32   
      * Flag indicating that undefined propertys should be not be replaced. ie
 33   
      * "${myUnresolvedProperty}"
 34   
      */
 35   
     public static final int LEAVE_UNDEFINED = 1;
 36   
 
 37   
     /**
 38   
      * Flag indicating that undefined propertys should cause an exception to be
 39   
      * thrown.
 40   
      */
 41   
     public static final int EXCEPT_ON_UNDEFINED = 2;
 42   
 
 43   
     /**
 44   
      * Flag indicating that undefined propertys should be replaced with a empty
 45   
      * string "".
 46   
      */
 47   
     public static final int EMPTY_ON_UNDEFINED = 3;
 48   
 
 49   
     /**
 50   
      * The flag for behaviour when undefined property is encountered. Must be
 51   
      * one of the *_UNDEFINED propertys.
 52   
      */
 53   
     private final int m_onUndefined;
 54   
 
 55   
     /**
 56   
      * Create property expander with EXCEPT_ON_UNDEFINED policy for undefined
 57   
      * propertys.
 58   
      */
 59  3
     public PropertyExpander()
 60   
     {
 61  3
         this( EXCEPT_ON_UNDEFINED );
 62   
     }
 63   
 
 64   
     /**
 65   
      * Create property expander with specified policy for undefined propertys.
 66   
      *
 67   
      * @param onUndefined the flag indicating behaviour when undefined property
 68   
      * is encountered. Must be one of the *_UNDEFINED constants.
 69   
      */
 70  9
     public PropertyExpander( final int onUndefined )
 71   
     {
 72  9
         m_onUndefined = onUndefined;
 73   
     }
 74   
 
 75   
     /**
 76   
      * Expand all propertys in the input Properties object.
 77   
      *
 78   
      * @param input the Properties object to resolve
 79   
      * @param data the data that holds property values
 80   
      * @throws Exception if an error occurs
 81   
      */
 82  1
     public Properties expandValues( final Properties input, final Map data )
 83   
         throws Exception
 84   
     {
 85  1
         final Properties result = new Properties();
 86  1
         final Iterator iterator = input.keySet().iterator();
 87  1
         while( iterator.hasNext() )
 88   
         {
 89  2
             final String key = (String)iterator.next();
 90  2
             final String value = input.getProperty( key );
 91  2
             final String newKey = expandValues( key, data );
 92  2
             final String newValue = expandValues( value, data );
 93  2
             result.setProperty( newKey, newValue );
 94   
         }
 95  1
         return result;
 96   
     }
 97   
 
 98   
     /**
 99   
      * Expand all propertys in the input XML attributes and text contents.
 100   
      *
 101   
      * @param input the DOM element to resolve
 102   
      * @param data the data that holds property values
 103   
      * @throws Exception if an error occurs
 104   
      */
 105  2
     public void expandValues( final Element input, final Map data )
 106   
         throws Exception
 107   
     {
 108  2
         final NamedNodeMap attributes = input.getAttributes();
 109  2
         final int attributeCount = attributes.getLength();
 110  2
         for( int i = 0; i < attributeCount; i++ )
 111   
         {
 112  2
             final Attr attr = (Attr)attributes.item( i );
 113  2
             final String value = attr.getValue();
 114  2
             final String newValue = expandValues( value, data );
 115  2
             attr.setValue( newValue );
 116   
         }
 117  2
         final NodeList nodes = input.getChildNodes();
 118  2
         final int childCount = nodes.getLength();
 119  2
         for( int i = 0; i < childCount; i++ )
 120   
         {
 121  4
             final Node node = nodes.item( i );
 122  4
             if( node instanceof Element )
 123   
             {
 124  1
                 expandValues( (Element)node, data );
 125   
             }
 126  3
             else if( node instanceof Text )
 127   
             {
 128  2
                 final Text text = (Text)node;
 129  2
                 final String content = text.getData();
 130  2
                 final String newContent = expandValues( content, data );
 131  2
                 text.setData( newContent );
 132   
             }
 133   
         }
 134   
     }
 135   
 
 136   
     /**
 137   
      * Expand all propertys in input string.
 138   
      *
 139   
      * @param input the string to resolve
 140   
      * @param data the data that holds property values
 141   
      * @return the resolved string
 142   
      * @throws Exception if an error occurs
 143   
      */
 144  19
     public String expandValues( final String input, final Map data )
 145   
         throws Exception
 146   
     {
 147  19
         int start = findBeginning( input, 0 );
 148  19
         if( -1 == start )
 149   
         {
 150  3
             return input;
 151   
         }
 152   
 
 153  16
         int end = findEnding( input, start );
 154   
 
 155  15
         final int length = input.length();
 156  15
         if( 0 == start && end == ( length - 1 ) )
 157   
         {
 158  9
             return getValue( input.substring( start + 2, end ),
 159   
                              data );
 160   
         }
 161   
 
 162  6
         final StringBuffer sb = new StringBuffer( length * 2 );
 163  6
         int lastPlace = 0;
 164   
 
 165  6
         while( true )
 166   
         {
 167  9
             final String value =
 168   
                 getValue( input.substring( start + 2, end ), data );
 169   
 
 170  9
             sb.append( input.substring( lastPlace, start ) );
 171  9
             sb.append( value );
 172   
 
 173  9
             lastPlace = end + 1;
 174   
 
 175  9
             start = findBeginning( input, lastPlace );
 176  9
             if( -1 == start )
 177   
             {
 178  6
                 break;
 179   
             }
 180   
 
 181  3
             end = findEnding( input, start );
 182   
         }
 183   
 
 184  6
         sb.append( input.substring( lastPlace, length ) );
 185   
 
 186  6
         return sb.toString();
 187   
     }
 188   
 
 189   
     /**
 190   
      * Helper method to find the start of a input definition.
 191   
      *
 192   
      * @param input the input string
 193   
      * @param index the current index into input
 194   
      * @return the index of start of property definition
 195   
      */
 196  28
     private int findBeginning( final String input, final int index )
 197   
     {
 198  28
         return input.indexOf( "${", index );
 199   
     }
 200   
 
 201   
     /**
 202   
      * Helper method to find the end of a property definition.
 203   
      *
 204   
      * @param input the input string
 205   
      * @param index the current index into input
 206   
      * @return the index of end of property definition
 207   
      * @throws Exception if unable to locate end of property
 208   
      */
 209  19
     private int findEnding( final String input, final int index )
 210   
         throws Exception
 211   
     {
 212  19
         final int end = input.indexOf( '}', index );
 213  19
         if( -1 == end )
 214   
         {
 215  1
             final String message = "Malformed input with mismatched }'s";
 216  1
             throw new Exception( message );
 217   
         }
 218   
 
 219  18
         return end;
 220   
     }
 221   
 
 222   
     /**
 223   
      * Return value from data map. If null is retrieved from data map then
 224   
      * behave as defined by {@link #m_onUndefined} flag.
 225   
      *
 226   
      * @param key the key of value in data
 227   
      * @param data the data map
 228   
      * @return the stringized value of value in map
 229   
      * @throws Exception if an error occurs
 230   
      */
 231  18
     private String getValue( final String key, final Map data )
 232   
         throws Exception
 233   
     {
 234  18
         final Object value = data.get( key );
 235  18
         if( null == value )
 236   
         {
 237  3
             if( LEAVE_UNDEFINED == m_onUndefined )
 238   
             {
 239  1
                 return "${" + key + "}";
 240   
             }
 241  2
             else if( EMPTY_ON_UNDEFINED == m_onUndefined )
 242   
             {
 243  1
                 return "";
 244   
             }
 245   
             else// if( EXCEPT_ON_UNDEFINED == m_onUndefined )
 246   
             {
 247  1
                 final String message = "Unable to find " +
 248   
                     key +
 249   
                     " to expand during property resolution.";
 250  1
                 throw new Exception( message );
 251   
             }
 252   
         }
 253   
 
 254  15
         return String.valueOf( value );
 255   
     }
 256   
 }
 257