mbenson 2005/02/03 11:18:07 Modified: . WHATSNEW src/main/org/apache/tools/ant/types FilterSet.java src/testcases/org/apache/tools/ant/types FilterSetTest.java docs/manual/CoreTypes filterset.html Log: Add recurse attribute to filterset. Revision Changes Path 1.740 +3 -0 ant/WHATSNEW Index: WHATSNEW =================================================================== RCS file: /home/cvs/ant/WHATSNEW,v retrieving revision 1.739 retrieving revision 1.740 diff -u -r1.739 -r1.740 --- WHATSNEW 2 Feb 2005 23:55:49 -0000 1.739 +++ WHATSNEW 3 Feb 2005 19:18:06 -0000 1.740 @@ -205,6 +205,9 @@ * <native2ascii> now also supports Kaffe's version. +* Recursive token expansion in a filterset can now be disabled by + setting its recurse attribute to false. + Fixed bugs: ----------- 1.31 +116 -105 ant/src/main/org/apache/tools/ant/types/FilterSet.java Index: FilterSet.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/types/FilterSet.java,v retrieving revision 1.30 retrieving revision 1.31 diff -u -r1.30 -r1.31 --- FilterSet.java 12 Nov 2004 15:15:22 -0000 1.30 +++ FilterSet.java 3 Feb 2005 19:18:07 -0000 1.31 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2004 The Apache Software Foundation + * Copyright 2001-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,6 @@ */ package org.apache.tools.ant.types; -// java io classes import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -24,10 +23,10 @@ import java.util.Hashtable; import java.util.Properties; import java.util.Vector; + import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; - /** * A set of filters to be applied to something. * @@ -37,64 +36,64 @@ public class FilterSet extends DataType implements Cloneable { /** - * Individual filter component of filterset + * Individual filter component of filterset. * */ public static class Filter { - /** Token which will be replaced in the filter operation */ + /** Token which will be replaced in the filter operation. */ String token; - /** The value which will replace the token in the filtering operation */ + /** The value which will replace the token in the filtering operation. */ String value; /** - * Constructor for the Filter object + * Constructor for the Filter object. * - * @param token The token which will be replaced when filtering - * @param value The value which will replace the token when filtering + * @param token The token which will be replaced when filtering. + * @param value The value which will replace the token when filtering. */ public Filter(String token, String value) { - this.token = token; - this.value = value; + setToken(token); + setValue(value); } /** - * No argument conmstructor + * No-argument conmstructor. */ public Filter() { } /** - * Sets the Token attribute of the Filter object + * Sets the Token attribute of the Filter object. * - * @param token The new Token value + * @param token The new Token value. */ public void setToken(String token) { this.token = token; } /** - * Sets the Value attribute of the Filter object + * Sets the Value attribute of the Filter object. * - * @param value The new Value value + * @param value The new Value value. */ public void setValue(String value) { this.value = value; } /** - * Gets the Token attribute of the Filter object + * Gets the Token attribute of the Filter object. * - * @return The Token value + * @return The Token value. */ public String getToken() { return token; } /** - * Gets the Value attribute of the Filter object + * Gets the Value attribute of the Filter object. * - * @return The Value value + * @return The Value value. */ public String getValue() { return value; @@ -108,7 +107,7 @@ public class FiltersFile { /** - * Constructor for the Filter object + * Constructor for the FiltersFile object. */ public FiltersFile() { } @@ -132,19 +131,27 @@ private String startOfToken = DEFAULT_TOKEN_START; private String endOfToken = DEFAULT_TOKEN_END; + /** Contains a list of parsed tokens */ + private Vector passedTokens; + /** if a duplicate token is found, this is set to true */ + private boolean duplicateToken = false; + + private boolean recurse = true; + private Hashtable filterHash = null; + /** * List of ordered filters and filter files. */ private Vector filters = new Vector(); /** - * Default constructor + * Default constructor. */ public FilterSet() { } /** - * Create a Filterset from another filterset + * Create a Filterset from another filterset. * * @param filterset the filterset upon which this filterset will be based. */ @@ -154,11 +161,11 @@ } /** - * Get the filters in the filter set + * Get the filters in the filter set. * - * @return a Vector of Filter instances + * @return a Vector of Filter instances. */ - protected Vector getFilters() { + protected synchronized Vector getFilters() { if (isReference()) { return getRef().getFilters(); } @@ -166,7 +173,7 @@ } /** - * Get the referred filter set + * Get the referenced filter set. * * @return the filterset from the reference. */ @@ -179,21 +186,23 @@ * * @return The hash of the tokens and values for quick lookup. */ - public Hashtable getFilterHash() { - int filterSize = getFilters().size(); - Hashtable filterHash = new Hashtable(filterSize + 1); - for (Enumeration e = getFilters().elements(); e.hasMoreElements();) { - Filter filter = (Filter) e.nextElement(); - filterHash.put(filter.getToken(), filter.getValue()); + public synchronized Hashtable getFilterHash() { + if (filterHash == null) { + filterHash = new Hashtable(getFilters().size()); + for (Enumeration e = getFilters().elements(); e.hasMoreElements();) { + Filter filter = (Filter) e.nextElement(); + filterHash.put(filter.getToken(), filter.getValue()); + } } return filterHash; } /** - * set the file containing the filters for this filterset. + * Set the file containing the filters for this filterset. * - * @param filtersFile sets the filter fil to read filters for this filter set from. - * @exception BuildException if there is a problem reading the filters + * @param filtersFile sets the filter file from which to read filters + * for this filter set. + * @exception BuildException if there is a problem reading the filters. */ public void setFiltersfile(File filtersFile) throws BuildException { if (isReference()) { @@ -203,9 +212,9 @@ } /** - * The string used to id the beginning of a token. + * Set the string used to id the beginning of a token. * - * @param startOfToken The new Begintoken value + * @param startOfToken The new Begintoken value. */ public void setBeginToken(String startOfToken) { if (isReference()) { @@ -218,9 +227,9 @@ } /** - * Get the begin token for this filterset + * Get the begin token for this filterset. * - * @return the filter set's begin token for filtering + * @return the filter set's begin token for filtering. */ public String getBeginToken() { if (isReference()) { @@ -229,11 +238,10 @@ return startOfToken; } - /** - * The string used to id the end of a token. + * Set the string used to id the end of a token. * - * @param endOfToken The new Endtoken value + * @param endOfToken The new Endtoken value. */ public void setEndToken(String endOfToken) { if (isReference()) { @@ -246,9 +254,9 @@ } /** - * Get the end token for this filterset + * Get the end token for this filterset. * - * @return the filter set's end token for replacement delimiting + * @return the filter set's end token for replacement delimiting. */ public String getEndToken() { if (isReference()) { @@ -257,24 +265,36 @@ return endOfToken; } + /** + * Set whether recursive token expansion is enabled. + * @param recurse <code>boolean</code> whether to recurse. + */ + public void setRecurse(boolean recurse) { + this.recurse = recurse; + } + + /** + * Get whether recursive token expansion is enabled. + * @return <code>boolean</code> whether enabled. + */ + public boolean isRecurse() { + return recurse; + } /** * Read the filters from the given file. * - * @param filtersFile the file from which filters are read - * @exception BuildException Throw a build exception when unable to read the - * file. + * @param filtersFile the file from which filters are read. + * @exception BuildException when the file cannot be read. */ - public void readFiltersFromFile(File filtersFile) throws BuildException { + public synchronized void readFiltersFromFile(File filtersFile) throws BuildException { if (isReference()) { throw tooManyAttributes(); } - if (!filtersFile.exists()) { throw new BuildException("Could not read filters from file " + filtersFile + " as it doesn't exist."); } - if (filtersFile.isFile()) { log("Reading filters from " + filtersFile, Project.MSG_VERBOSE); FileInputStream in = null; @@ -315,10 +335,10 @@ * This resets the passedTokens and calls iReplaceTokens to * do the actual replacements. * - * @param line The line to process the tokens in. - * @return The string with the tokens replaced. + * @param line The line in which to process embedded tokens. + * @return The input string after token replacement. */ - public String replaceTokens(String line) { + public synchronized String replaceTokens(String line) { passedTokens = null; // reset for new line return iReplaceTokens(line); } @@ -331,7 +351,7 @@ * @param line The line to process the tokens in. * @return The string with the tokens replaced. */ - private String iReplaceTokens(String line) { + private synchronized String iReplaceTokens(String line) { String beginToken = getBeginToken(); String endToken = getEndToken(); int index = line.indexOf(beginToken); @@ -345,6 +365,7 @@ String value = null; do { + //can't have zero-length token int endIndex = line.indexOf(endToken, index + beginToken.length() + 1); if (endIndex == -1) { @@ -355,7 +376,7 @@ b.append(line.substring(i, index)); if (tokens.containsKey(token)) { value = (String) tokens.get(token); - if (!value.equals(token)) { + if (recurse && !value.equals(token)) { // we have another token, let's parse it. value = replaceTokens(value, token); } @@ -381,48 +402,40 @@ } } - /** Contains a list of parsed tokens */ - private Vector passedTokens; - /** if a ducplicate token is found, this is set to true */ - private boolean duplicateToken = false; - /** * This parses tokens which point to tokens. * It also maintains a list of currently used tokens, so we cannot - * get into an infinite loop - * @param line the value / token to parse - * @param parent the parant token (= the token it was parsed from) + * get into an infinite loop. + * @param line the value / token to parse. + * @param parent the parent token (= the token it was parsed from). */ - private String replaceTokens(String line, String parent) + private synchronized String replaceTokens(String line, String parent) throws BuildException { + String beginToken = getBeginToken(); + String endToken = getEndToken(); if (passedTokens == null) { passedTokens = new Vector(); } if (passedTokens.contains(parent) && !duplicateToken) { duplicateToken = true; - StringBuffer sb = new StringBuffer(); - sb.append("Infinite loop in tokens. Currently known tokens : "); - sb.append(passedTokens); - sb.append("\nProblem token : " + getBeginToken() + parent - + getEndToken()); - sb.append(" called from " + getBeginToken() - + passedTokens.lastElement()); - sb.append(getEndToken()); - System.out.println(sb.toString()); + System.out.println( + "Infinite loop in tokens. Currently known tokens : " + + passedTokens.toString() + "\nProblem token : " + beginToken + + parent + endToken + " called from " + beginToken + + passedTokens.lastElement().toString() + endToken); return parent; } passedTokens.addElement(parent); String value = iReplaceTokens(line); - if (value.indexOf(getBeginToken()) == -1 && !duplicateToken) { + if (value.indexOf(beginToken) == -1 && !duplicateToken) { duplicateToken = false; passedTokens = null; } else if (duplicateToken) { // should always be the case... if (passedTokens.size() > 0) { - value = (String) passedTokens.lastElement(); - passedTokens.removeElementAt(passedTokens.size() - 1); + value = (String) passedTokens.remove(passedTokens.size() - 1); if (passedTokens.size() == 0) { - value = getBeginToken() + value + getEndToken(); + value = beginToken + value + endToken; duplicateToken = false; } } @@ -431,21 +444,22 @@ } /** - * Create a new filter + * Add a new filter. * - * @param filter the filter to be added + * @param filter the filter to be added. */ - public void addFilter(Filter filter) { + public synchronized void addFilter(Filter filter) { if (isReference()) { throw noChildrenAllowed(); } filters.addElement(filter); + filterHash = null; } /** - * Create a new FiltersFile + * Create a new FiltersFile. * - * @return The filter that was created. + * @return The filtersfile that was created. */ public FiltersFile createFiltersfile() { if (isReference()) { @@ -455,49 +469,49 @@ } /** - * Add a new filter made from the given token and value. - * - * @param token The token for the new filter. - * @param value The value for the new filter. - */ - public void addFilter(String token, String value) { + * Add a new filter made from the given token and value. + * + * @param token The token for the new filter. + * @param value The value for the new filter. + */ + public synchronized void addFilter(String token, String value) { if (isReference()) { throw noChildrenAllowed(); } - filters.addElement(new Filter(token, value)); + addFilter(new Filter(token, value)); } /** - * Add a Filterset to this filter set - * - * @param filterSet the filterset to be added to this filterset - */ - public void addConfiguredFilterSet(FilterSet filterSet) { + * Add a Filterset to this filter set. + * + * @param filterSet the filterset to be added to this filterset + */ + public synchronized void addConfiguredFilterSet(FilterSet filterSet) { if (isReference()) { throw noChildrenAllowed(); } for (Enumeration e = filterSet.getFilters().elements(); e.hasMoreElements();) { - filters.addElement(e.nextElement()); + addFilter((Filter) e.nextElement()); } } /** - * Test to see if this filter set it empty. + * Test to see if this filter set has filters. * - * @return Return true if there are filter in this set otherwise false. + * @return Return true if there are filters in this set. */ - public boolean hasFilters() { + public synchronized boolean hasFilters() { return getFilters().size() > 0; } /** - * clone the filterset + * Clone the filterset. * - * @return a deep clone of this filterset + * @return a deep clone of this filterset. * * @throws BuildException if the clone cannot be performed. */ - public Object clone() throws BuildException { + public synchronized Object clone() throws BuildException { if (isReference()) { return ((FilterSet) getRef()).clone(); } else { @@ -511,8 +525,5 @@ } } } - } - - 1.15 +18 -1 ant/src/testcases/org/apache/tools/ant/types/FilterSetTest.java Index: FilterSetTest.java =================================================================== RCS file: /home/cvs/ant/src/testcases/org/apache/tools/ant/types/FilterSetTest.java,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- FilterSetTest.java 7 Dec 2004 09:10:38 -0000 1.14 +++ FilterSetTest.java 3 Feb 2005 19:18:07 -0000 1.15 @@ -1,5 +1,5 @@ /* - * Copyright 2001-2002,2004 The Apache Software Foundation + * Copyright 2001-2002, 2004-2005 The Apache Software Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -99,6 +99,23 @@ assertEquals(result, fs.replaceTokens(line)); } + /** + * Test to see what happens when the resolving occurs in + * what would be an infinite loop, but with recursion disabled. + */ + public void testRecursionDisabled() { + String result = "@test1@ line testvalue"; + String line = "@test@ line @test2@"; + FilterSet fs = new FilterSet(); + fs.addFilter("test", "@test1@"); + fs.addFilter("test1","@test@"); + fs.addFilter("test2", "testvalue"); + fs.setBeginToken("@"); + fs.setEndToken("@"); + fs.setRecurse(false); + assertEquals(result, fs.replaceTokens(line)); + } + public void testNestedFilterSets() { executeTarget("test-nested-filtersets"); 1.15 +86 -79 ant/docs/manual/CoreTypes/filterset.html Index: filterset.html =================================================================== RCS file: /home/cvs/ant/docs/manual/CoreTypes/filterset.html,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- filterset.html 9 Feb 2004 21:50:07 -0000 1.14 +++ filterset.html 3 Feb 2005 19:18:07 -0000 1.15 @@ -1,19 +1,19 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> -<HTML> -<HEAD> - <TITLE>FilterSet Type</TITLE> -</HEAD> +<html> +<head> + <title>FilterSet Type</title> +</head> -<BODY> -<H2><A name="filterset">FilterSet</A></H2> +<body> +<h2><a name="filterset">FilterSet</a></h2> -<P>FilterSets are groups of filters. Filters can be defined as token-value +<p>FilterSets are groups of filters. Filters can be defined as token-value pairs or be read in from a file. FilterSets can appear inside tasks that support this -feature or at the same level as <CODE><target></CODE> - i.e., as +feature or at the same level as <code><target></code> - i.e., as children of -<CODE><project></CODE>.</P> +<code><project></code>.</p> <p>FilterSets support the <code>id</code> and <code>refid</code> attributes. You can define a FilterSet with an <code>id</code> @@ -35,92 +35,99 @@ you should ensure that the set of files being filtered are all text files. </p> -<H2>Filterset</H2> +<h2>Filterset</h2> -<TABLE cellSpacing=0 cellPadding=2 border=1> - <TR> - <TD vAlign=top><B>Attribute</B></TD> - <TD vAlign=top><B>Description</B></TD> - <TD vAlign=top><B>Default</B></TD> - <TD vAlign=top align="center"><B>Required</B></TD> - </TR> - <TR> - <TD vAlign=top>begintoken</TD> - <TD vAlign=top>The string marking the beginning of a token (eg., - <code>@DATE@</code>).</TD> - <TD vAlign=top>@</TD> - <TD vAlign=top align="center">No</TD> - </TR> - <TR> - <TD vAlign=top>endtoken</TD> - <TD vAlign=top>The string marking the end of a token (eg., - <code>@DATE@</code>).</TD> - <TD vAlign=top>@</TD> - <TD vAlign=top align="center">No</TD> - </TR> -</TABLE> - -<H2>Filter</H2> -<TABLE cellSpacing=0 cellPadding=2 border=1> - <TR> - <TD vAlign=top><B>Attribute</B></TD> - <TD vAlign=top><B>Description</B></TD> - <TD vAlign=top align="center"><B>Required</B></TD> - </TR> - <TR> - <TD vAlign=top>token</TD> - <TD vAlign=top>The token to replace (eg., <code>@DATE@</code>)</TD> - <TD vAlign=top align="center">Yes</TD> - </TR> - <TR> - <TD vAlign=top>value</TD> - <TD vAlign=top>The value to replace it with - (eg., <code>Thursday, April 26, 2001</code>).</TD> - <TD vAlign=top align="center">Yes</TD> - </TR> -</TABLE> - -<H2>Filtersfile</H2> -<TABLE cellSpacing=0 cellPadding=2 border=1> - <TR> - <TD vAlign=top><B>Attribute</B></TD> - <TD vAlign=top><B>Description</B></TD> - <TD vAlign=top align="center"><B>Required</B></TD> - </TR> - <TR> - <TD vAlign=top>file</TD> - <TD vAlign=top>A properties file of - name-value pairs from which to load the tokens.</TD> - <TD vAlign=top align="center">Yes</TD> - </TR> -</TABLE> +<table cellSpacing=0 cellPadding=2 border=1> + <tr> + <td vAlign=top><b>Attribute</b></td> + <td vAlign=top><b>Description</b></td> + <td vAlign=top><b>Default</b></td> + <td vAlign=top align="center"><b>Required</b></td> + </tr> + <tr> + <td vAlign=top>begintoken</td> + <td vAlign=top>The string marking the beginning of a token (eg., + <code>@DATE@</code>).</td> + <td vAlign=top>@</td> + <td vAlign=top align="center">No</td> + </tr> + <tr> + <td vAlign=top>endtoken</td> + <td vAlign=top>The string marking the end of a token (eg., + <code>@DATE@</code>).</td> + <td vAlign=top>@</td> + <td vAlign=top align="center">No</td> + </tr> + <tr> + <td vAlign=top>recurse</td> + <td vAlign=top>Indicates whether the replacement text of tokens + should be searched for more tokens. <b>Since Ant 1.6.3</b></td> + <td vAlign=top><i>true</i></td> + <td vAlign=top align="center">No</td> + </tr> +</table> + +<h2>Filter</h2> +<table cellSpacing=0 cellPadding=2 border=1> + <tr> + <td vAlign=top><b>Attribute</b></td> + <td vAlign=top><b>Description</b></td> + <td vAlign=top align="center"><b>Required</b></td> + </tr> + <tr> + <td vAlign=top>token</td> + <td vAlign=top>The token to replace (eg., <code>@DATE@</code>)</td> + <td vAlign=top align="center">Yes</td> + </tr> + <tr> + <td vAlign=top>value</td> + <td vAlign=top>The value to replace it with + (eg., <code>Thursday, April 26, 2001</code>).</td> + <td vAlign=top align="center">Yes</td> + </tr> +</table> + +<h2>Filtersfile</h2> +<table cellSpacing=0 cellPadding=2 border=1> + <tr> + <td vAlign=top><b>Attribute</b></td> + <td vAlign=top><b>Description</b></td> + <td vAlign=top align="center"><b>Required</b></td> + </tr> + <tr> + <td vAlign=top>file</td> + <td vAlign=top>A properties file of + name-value pairs from which to load the tokens.</td> + <td vAlign=top align="center">Yes</td> + </tr> +</table> -<H4>Examples</H4> +<h4>Examples</h4> <p>You are copying the <code>version.txt</code> file to the <code>dist</code> directory from the <code>build</code> directory but wish to replace the token <code>@DATE@</code> with today's date.</p> -<BLOCKQUOTE><PRE> +<blockquote><pre> <copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt"> <filterset> <filter token="DATE" value="${TODAY}"/> </filterset> </copy> -</PRE></BLOCKQUOTE> +</pre></blockquote> <p>You are copying the <code>version.txt</code> file to the <code>dist</code> directory from the build directory but wish to replace the token <code>%DATE*</code> with today's date.</p> -<BLOCKQUOTE><PRE> +<blockquote><pre> <copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt"> <filterset begintoken="%" endtoken="*"> <filter token="DATE" value="${TODAY}"/> </filterset> </copy> -</PRE></BLOCKQUOTE> +</pre></blockquote> <p>Copy all the docs but change all dates and appropriate notices as stored in a file.</p> -<BLOCKQUOTE><PRE> +<blockquote><pre> <copy toDir="${dist.dir}/docs"> <fileset dir="${build.dir}/docs"> <include name="**/*.html"> @@ -129,10 +136,10 @@ <filtersfile file="${user.dir}/dist.properties"/> </filterset> </copy> -</PRE></BLOCKQUOTE> +</pre></blockquote> <p>Define a FilterSet and reference it later.</p> -<BLOCKQUOTE><PRE> +<blockquote><pre> <filterset id="myFilterSet" begintoken="%" endtoken="*"> <filter token="DATE" value="${TODAY}"/> </filterset> @@ -140,8 +147,8 @@ <copy file="${build.dir}/version.txt" toFile="${dist.dir}/version.txt"> <filterset refid="myFilterSet"/> </copy> -</PRE></BLOCKQUOTE> -<HR> +</pre></blockquote> +<hr> -<P align=center>Copyright © 2001-2004 The Apache Software Foundation. -All rights Reserved.</P></BODY></HTML> +<p align=center>Copyright © 2001-2005 The Apache Software Foundation. +All rights Reserved.</p></body></html>
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]