Hi everyone, I made a patch, so FilterSet allows nested tokens. A short example. If you currently have these token/value pairs = @[EMAIL PROTECTED]/usr/local @[EMAIL PROTECTED]@root@/test.txt
If you call @test-path@ from your file, it will not resolve the @root@ anymore, which can be very annoying .. Since you can also get into an infinite loop, by using the eg the values @[EMAIL PROTECTED]@path@ @[EMAIL PROTECTED]@root@ I made some extra code to handle this, so it will just parse in the @path@ (if you called that from the file to be filtered) and I will write a message to System.out with the reason it could parse it (log doesn't seem to get passed back to console, so I used this). There is only one problem : it is not backward compatible, since the old way is to ignore the nested ifs and just put the value there. Since I don't know any use cases myself where you want the token to be unresolved if you put a value there, I will leave the decision to put this in to the committers ;)) Attached is the change in documtation and FilterSet.java (in one diff, from the root of the jakarta-ant module) and a seperate testcase called FilterSetRecursiveTest.java. Don't know if the name is correct (nested could be better), but it is easy to rename ;). I ran the FilterSetTest separately and it passes.. Have fun with it ;) Mvgr, Martin
/* * The Apache Software License, Version 1.1 * * Copyright (c) 2000-2001 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Ant", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. */ package org.apache.tools.ant.types; import junit.framework.TestCase; /** * This will test the recursive FilterSet. * Which means that if the filter value @test@ contains another filter * value, it will actually resolve. * It also contains test to see what happens when the resolving occurs * in an infinite loop. * * @author <a href="mailto:[EMAIL PROTECTED]">Martin van den Bemt</a> */ public class FilterSetRecursiveTest extends TestCase { /** * Constructor for FilterSetRecursiveTest. * @param arg0 */ public FilterSetRecursiveTest(String arg0) { super(arg0); } public static void main(String[] args) { junit.textui.TestRunner.run(FilterSetRecursiveTest.class); } /** * The actual recursive test * The endresult should be it works */ public void testRecursive() { System.out.println("testRecursive"); String result = "it works line"; String line="@test@ line"; FilterSet fs = new FilterSet(); fs.addFilter("test", "@test1@"); fs.addFilter("test1","@test2@"); fs.addFilter("test2", "it works"); fs.setBeginToken("@"); fs.setEndToken("@"); assertEquals(result, fs.replaceTokens(line)); } /** * Tests having a inifinite loop */ public void testInfinite() { System.out.println("testInfinite"); String result = "@test@ line testvalue"; String line = "@test@ line @test3@"; FilterSet fs = new FilterSet(); fs.addFilter("test", "@test1@"); fs.addFilter("test1","@test2@"); fs.addFilter("test2", "@test@"); fs.addFilter("test3", "testvalue"); fs.setBeginToken("@"); fs.setEndToken("@"); assertEquals(result, fs.replaceTokens(line)); } }
Index: docs/manual/CoreTypes/filterset.html =================================================================== RCS file: /home/cvspublic/jakarta-ant/docs/manual/CoreTypes/filterset.html,v retrieving revision 1.6 diff -u -r1.6 filterset.html --- docs/manual/CoreTypes/filterset.html 25 Mar 2002 20:21:11 -0000 1.6 +++ docs/manual/CoreTypes/filterset.html 20 May 2002 15:18:49 -0000 @@ -19,6 +19,7 @@ <code>endtoken</code> attributes to define what to match.</p> <p>Filtersets are used for doing replacements in tasks such as <code><copy></code>, etc.</p> +<p>Nested filters are possible and a message will be given in case a value in a filter chain is called for a second time and thus causing an infinite loop. The originating token will be passed back when an infinite loop occurs. <H2>Filterset</H2> Index: src/main/org/apache/tools/ant/types/FilterSet.java =================================================================== RCS file: /home/cvspublic/jakarta-ant/src/main/org/apache/tools/ant/types/FilterSet.java,v retrieving revision 1.13 diff -u -r1.13 FilterSet.java --- src/main/org/apache/tools/ant/types/FilterSet.java 15 Apr 2002 14:56:34 -0000 1.13 +++ src/main/org/apache/tools/ant/types/FilterSet.java 20 May 2002 15:20:38 -0000 @@ -75,6 +75,7 @@ * A filter set may have begintoken and endtokens defined. * * @author <A href="mailto:[EMAIL PROTECTED]"> Michael McCallum </A> + * @author <A href="mailto:[EMAIL PROTECTED]"> Martin van den Bemt </A> */ public class FilterSet extends DataType implements Cloneable { @@ -356,6 +357,10 @@ value = (String) tokens.get(token); log("Replacing: " + beginToken + token + endToken + " -> " + value, Project.MSG_VERBOSE); + if (!value.equals(token)) { + // we have another token, let's parse it. + value = replaceTokens(value, token); + } b.append(value); i = index + beginToken.length() + token.length() + endToken.length(); @@ -374,6 +379,54 @@ } else { return line; } + } + + /** 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 value the value / token to parse + * @param parent the parant token (= the token it was parsed from) + */ + private String replaceTokens(String line, String parent) + throws BuildException + { + if (passedTokens == null) { + passedTokens = new Vector(); + } + if (passedTokens.contains(parent) && !duplicateToken) { + duplicateToken = true; + StringBuffer sb = new StringBuffer(); + sb.append("Inifinite 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()); + return parent; + } + passedTokens.addElement(parent); + String value = this.replaceTokens(line); + if (value.indexOf(getBeginToken()) == -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); + if (passedTokens.size() == 0) { + value = getBeginToken()+value+getEndToken(); + duplicateToken = false; + } + } + } + return value; } /**
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
