Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 500   Methods: 27
NCLOC: 256   Classes: 3
 
 Source file Conditionals Statements Methods TOTAL
FilterSet.java 65% 82.2% 77.8% 76.9%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 package org.apache.tools.ant.types;
 55   
 
 56   
 // java io classes
 57   
 import java.io.File;
 58   
 import java.io.FileInputStream;
 59   
 import java.io.IOException;
 60   
 import java.util.Enumeration;
 61   
 import java.util.Hashtable;
 62   
 import java.util.Properties;
 63   
 import java.util.Vector;
 64   
 import org.apache.tools.ant.BuildException;
 65   
 import org.apache.tools.ant.Project;
 66   
 
 67   
 
 68   
 /**
 69   
  * A set of filters to be applied to something.
 70   
  *
 71   
  * A filter set may have begintoken and endtokens defined.
 72   
  *
 73   
  * @author     <A href="mailto:gholam@xtra.co.nz">  Michael McCallum  </A>
 74   
  * @author     <A href="mailto:martin@mvdb.net">  Martin van den Bemt </A>
 75   
  */
 76   
 public class FilterSet extends DataType implements Cloneable {
 77   
     
 78   
     /**
 79   
      * Individual filter component of filterset
 80   
      *
 81   
      * @author    Michael McCallum
 82   
      */
 83   
     public static class Filter {
 84   
         /** Token which will be replaced in the filter operation */
 85   
         String token;
 86   
         
 87   
         /** The value which will replace the token in the filtering operation */
 88   
         String value;
 89   
         
 90   
         /**
 91   
          * Constructor for the Filter object
 92   
          *
 93   
          * @param token  The token which will be replaced when filtering
 94   
          * @param value  The value which will replace the token when filtering
 95   
          */
 96  13
         public Filter(String token, String value) {
 97  13
            this.token = token;
 98  13
            this.value = value;
 99   
         }
 100   
         
 101   
         /**
 102   
          * No argument conmstructor
 103   
          */
 104  28
         public Filter() {
 105   
         }
 106   
         
 107   
         /**
 108   
          * Sets the Token attribute of the Filter object
 109   
          *
 110   
          * @param token  The new Token value
 111   
          */
 112  28
         public void setToken(String token) {
 113  28
            this.token = token;
 114   
         }
 115   
         
 116   
         /**
 117   
          * Sets the Value attribute of the Filter object
 118   
          *
 119   
          * @param value  The new Value value
 120   
          */
 121  28
         public void setValue(String value) {
 122  28
            this.value = value;
 123   
         }
 124   
         
 125   
         /**
 126   
          * Gets the Token attribute of the Filter object
 127   
          *
 128   
          * @return   The Token value
 129   
          */
 130  59
         public String getToken() {
 131  59
            return token;
 132   
         }
 133   
         
 134   
         /**
 135   
          * Gets the Value attribute of the Filter object
 136   
          *
 137   
          * @return   The Value value
 138   
          */
 139  59
         public String getValue() {
 140  59
            return value;
 141   
         }
 142   
      }
 143   
     
 144   
     /**
 145   
      * The filtersfile nested element.
 146   
      *
 147   
      * @author    Michael McCallum
 148   
      */
 149   
     public class FiltersFile {
 150   
         
 151   
         /**
 152   
          * Constructor for the Filter object
 153   
          */
 154  0
         public FiltersFile() {
 155   
         }
 156   
         
 157   
         /**
 158   
          * Sets the file from which filters will be read.
 159   
          *
 160   
          * @param file the file from which filters will be read.
 161   
          */
 162  0
         public void setFile(File file) {
 163  0
            readFiltersFromFile(file);
 164   
         }
 165   
     }
 166   
     
 167   
     /** The default token start string */
 168   
     public static final String DEFAULT_TOKEN_START = "@";
 169   
     
 170   
     /** The default token end string */
 171   
     public static final String DEFAULT_TOKEN_END = "@";
 172   
     
 173   
     private String startOfToken = DEFAULT_TOKEN_START;
 174   
     private String endOfToken = DEFAULT_TOKEN_END;
 175   
     
 176   
     /**
 177   
      * List of ordered filters and filter files.
 178   
      */
 179   
     private Vector filters = new Vector();
 180   
     
 181  711
     public FilterSet() {
 182   
     }
 183   
     
 184   
     /**
 185   
      * Create a Filterset from another filterset
 186   
      *
 187   
      * @param filterset the filterset upon which this filterset will be based.
 188   
      */
 189  0
     protected FilterSet(FilterSet filterset) {
 190  0
         super();
 191  0
         this.filters = (Vector) filterset.getFilters().clone();
 192   
     }
 193   
 
 194  99
     protected Vector getFilters() {
 195  99
         if (isReference()) {
 196  27
             return getRef().getFilters();
 197   
         }
 198  72
         return filters;
 199   
     }
 200   
 
 201  93
     protected FilterSet getRef() {
 202  93
         return (FilterSet) getCheckedRef(FilterSet.class, "filterset");
 203   
     }
 204   
     
 205   
     /**
 206   
      * Gets the filter hash of the FilterSet.
 207   
      *
 208   
      * @return   The hash of the tokens and values for quick lookup.
 209   
      */
 210  29
     public Hashtable getFilterHash() {
 211  29
         int filterSize = getFilters().size();
 212  29
         Hashtable filterHash = new Hashtable(filterSize + 1);
 213  29
         for (Enumeration e = getFilters().elements(); e.hasMoreElements();) {
 214  59
            Filter filter = (Filter) e.nextElement();
 215  59
            filterHash.put(filter.getToken(), filter.getValue());
 216   
         }
 217  29
         return filterHash;
 218   
     }
 219   
     
 220   
     /**
 221   
      * set the file containing the filters for this filterset.
 222   
      *
 223   
      * @param filtersFile sets the filter fil to read filters for this filter set from.
 224   
      * @exception BuildException if there is a problem reading the filters
 225   
      */
 226  0
     public void setFiltersfile(File filtersFile) throws BuildException {
 227  0
         if (isReference()) {
 228  0
             throw tooManyAttributes();
 229   
         }
 230  0
         readFiltersFromFile(filtersFile);
 231   
     }
 232   
     
 233   
     /**
 234   
      * The string used to id the beginning of a token.
 235   
      *
 236   
      * @param startOfToken  The new Begintoken value
 237   
      */
 238  8
     public void setBeginToken(String startOfToken) {
 239  8
         if (isReference()) {
 240  0
             throw tooManyAttributes();
 241   
         }
 242  8
         if (startOfToken == null || "".equals(startOfToken)) {
 243  0
             throw new BuildException("beginToken must not be empty");
 244   
         }
 245  8
         this.startOfToken = startOfToken;
 246   
     }
 247   
 
 248  114
     public String getBeginToken() {
 249  114
         if (isReference()) {
 250  37
             return getRef().getBeginToken();
 251   
         }
 252  77
         return startOfToken;
 253   
     }
 254   
     
 255   
     
 256   
     /**
 257   
      * The string used to id the end of a token.
 258   
      *
 259   
      * @param endOfToken  The new Endtoken value
 260   
      */
 261  8
     public void setEndToken(String endOfToken) {
 262  8
         if (isReference()) {
 263  0
             throw tooManyAttributes();
 264   
         }
 265  8
         if (endOfToken == null || "".equals(endOfToken)) {
 266  0
             throw new BuildException("endToken must not be empty");
 267   
         }
 268  8
         this.endOfToken = endOfToken;
 269   
     }
 270   
 
 271  84
     public String getEndToken() {
 272  84
         if (isReference()) {
 273  29
             return getRef().getEndToken();
 274   
         }
 275  55
         return endOfToken;
 276   
     }
 277   
     
 278   
     
 279   
     /**
 280   
      * Read the filters from the given file.
 281   
      *
 282   
      * @param filtersFile         the file from which filters are read
 283   
      * @exception BuildException  Throw a build exception when unable to read the
 284   
      * file.
 285   
      */
 286  1
     public void readFiltersFromFile(File filtersFile) throws BuildException {
 287  1
         if (isReference()) {
 288  0
             throw tooManyAttributes();
 289   
         }
 290   
 
 291  1
         if (filtersFile.isFile()) {
 292  1
            log("Reading filters from " + filtersFile, Project.MSG_VERBOSE);
 293  1
            FileInputStream in = null;
 294  1
            try {
 295  1
               Properties props = new Properties();
 296  1
               in = new FileInputStream(filtersFile);
 297  1
               props.load(in);
 298   
               
 299  1
               Enumeration enum = props.propertyNames();
 300  1
               Vector filters = getFilters();
 301  1
               while (enum.hasMoreElements()) {
 302  1
                  String strPropName = (String) enum.nextElement();
 303  1
                  String strValue = props.getProperty(strPropName);
 304  1
                  filters.addElement(new Filter(strPropName, strValue));
 305   
               }
 306   
            } catch (Exception e) {
 307  0
               throw new BuildException("Could not read filters from file: " 
 308   
                 + filtersFile);
 309   
            } finally {
 310  1
               if (in != null) {
 311  1
                  try {
 312  1
                     in.close();
 313   
                  } catch (IOException ioex) {
 314   
                  }
 315   
               }
 316   
            }
 317   
         } else {
 318  0
            throw new BuildException("Must specify a file not a directory in " 
 319   
             + "the filtersfile attribute:" + filtersFile);
 320   
         }
 321   
     }
 322   
     
 323   
     /**
 324   
      * Does replacement on the given string with token matching.
 325   
      * This uses the defined begintoken and endtoken values which default to @ for both.
 326   
      *
 327   
      * @param line  The line to process the tokens in.
 328   
      * @return      The string with the tokens replaced.
 329   
      */
 330  52
     public String replaceTokens(String line) {
 331  52
         String beginToken = getBeginToken();
 332  52
         String endToken = getEndToken();
 333  52
         int index = line.indexOf(beginToken);
 334   
         
 335  52
         if (index > -1) {
 336  25
             Hashtable tokens = getFilterHash();
 337  25
             try {
 338  25
                 StringBuffer b = new StringBuffer();
 339  25
                 int i = 0;
 340  25
                 String token = null;
 341  25
                 String value = null;
 342   
                 
 343  25
                 do {
 344  29
                     int endIndex = line.indexOf(endToken, 
 345   
                         index + beginToken.length() + 1);
 346  29
                     if (endIndex == -1) {
 347  3
                         break;
 348   
                     }
 349  26
                     token 
 350   
                         = line.substring(index + beginToken.length(), endIndex);
 351  26
                     b.append(line.substring(i, index));
 352  26
                     if (tokens.containsKey(token)) {
 353  23
                         value = (String) tokens.get(token);
 354  23
                         if (!value.equals(token)) {
 355   
                             // we have another token, let's parse it.
 356  23
                             value = replaceTokens(value, token);
 357   
                         }
 358  23
                         log("Replacing: " + beginToken + token + endToken 
 359   
                             + " -> " + value, Project.MSG_VERBOSE);
 360  23
                         b.append(value);
 361  23
                         i = index + beginToken.length() + token.length() 
 362   
                             + endToken.length();
 363   
                     } else {
 364   
                         // just append beginToken and search further
 365  3
                         b.append(beginToken);
 366  3
                         i = index + beginToken.length();
 367   
                     }
 368  ?
                 } while ((index = line.indexOf(beginToken, i)) > -1);
 369   
                 
 370  25
                 b.append(line.substring(i));
 371  25
                 return b.toString();
 372   
             } catch (StringIndexOutOfBoundsException e) {
 373  0
                 return line;
 374   
             }
 375   
         } else {
 376  27
            return line;
 377   
         }
 378   
     }
 379   
     
 380   
     /** Contains a list of parsed tokens */
 381   
     private Vector passedTokens;
 382   
     /** if a ducplicate token is found, this is set to true */
 383   
     private boolean duplicateToken = false;
 384   
     
 385   
     /**
 386   
      * This parses tokens which point to tokens.
 387   
      * It also maintains a list of currently used tokens, so we cannot
 388   
      * get into an infinite loop
 389   
      * @param value the value / token to parse
 390   
      * @param parent the parant token (= the token it was parsed from)
 391   
      */
 392  23
     private String replaceTokens(String line, String parent)
 393   
     throws BuildException
 394   
     {
 395  23
         if (passedTokens == null) {
 396  17
             passedTokens = new Vector();
 397   
         }
 398  23
         if (passedTokens.contains(parent) && !duplicateToken) {
 399  1
             duplicateToken = true;
 400  1
             StringBuffer sb = new StringBuffer();
 401  1
             sb.append("Inifinite loop in tokens. Currently known tokens : ");
 402  1
             sb.append(passedTokens);
 403  1
             sb.append("\nProblem token : "+getBeginToken()+parent+getEndToken());
 404  1
             sb.append(" called from "+getBeginToken()+passedTokens.lastElement());
 405  1
             sb.append(getEndToken());
 406  1
             System.out.println(sb.toString());
 407  1
             return parent;
 408   
         }
 409  22
         passedTokens.addElement(parent);
 410  22
         String value = this.replaceTokens(line);
 411  22
         if (value.indexOf(getBeginToken()) == -1 && !duplicateToken) {
 412  19
             duplicateToken = false;
 413  19
             passedTokens = null;
 414  3
         } else if(duplicateToken) {
 415   
             // should always be the case...
 416  3
             if (passedTokens.size() > 0) {
 417  3
                 value = (String) passedTokens.lastElement();
 418  3
                 passedTokens.removeElementAt(passedTokens.size()-1);
 419  3
                 if (passedTokens.size() == 0) {
 420  1
                     value = getBeginToken()+value+getEndToken();
 421  1
                     duplicateToken = false;
 422   
                 }
 423   
             }
 424   
         }
 425  22
         return value;
 426   
     }
 427   
     
 428   
     /**
 429   
      * Create a new filter
 430   
      *
 431   
      * @param  the filter to be added
 432   
      */
 433  28
     public void addFilter(Filter filter) {
 434  28
         if (isReference()) {
 435  0
             throw noChildrenAllowed();
 436   
         }
 437  28
         filters.addElement(filter);
 438   
     }
 439   
     
 440   
     /**
 441   
      * Create a new FiltersFile
 442   
      *
 443   
      * @return   The filter that was created.
 444   
      */
 445  0
     public FiltersFile createFiltersfile() {
 446  0
         if (isReference()) {
 447  0
             throw noChildrenAllowed();
 448   
         }
 449  0
         return new FiltersFile();
 450   
     }
 451   
     
 452   
     /**
 453   
     * Add a new filter made from the given token and value.
 454   
     *
 455   
     * @param token  The token for the new filter.
 456   
     * @param value  The value for the new filter.
 457   
     */
 458  12
     public void addFilter(String token, String value) {
 459  12
         if (isReference()) {
 460  0
             throw noChildrenAllowed();
 461   
         }
 462  12
         filters.addElement(new Filter(token, value));
 463   
     }
 464   
     
 465   
     /**
 466   
     * Add a Filterset to this filter set
 467   
     *
 468   
     * @param filterSet the filterset to be added to this filterset
 469   
     */
 470  3
     public void addConfiguredFilterSet(FilterSet filterSet) {
 471  3
         if (isReference()) {
 472  0
             throw noChildrenAllowed();
 473   
         }
 474  3
         for (Enumeration e = filterSet.getFilters().elements(); e.hasMoreElements();) {
 475  4
             filters.addElement(e.nextElement());
 476   
         }
 477   
     }
 478   
     
 479   
     /**
 480   
     * Test to see if this filter set it empty.
 481   
     *
 482   
     * @return   Return true if there are filter in this set otherwise false.
 483   
     */
 484  10
     public boolean hasFilters() {
 485  10
         return getFilters().size() > 0;
 486   
     }
 487   
 
 488  0
     public Object clone() throws BuildException {
 489  0
         if (isReference()) {
 490  0
             return new FilterSet(getRef());
 491   
         } else {
 492  0
             return new FilterSet(this);
 493   
         }
 494   
     }
 495   
 
 496   
 }
 497   
  
 498   
 
 499   
 
 500