diff --git a/WHATSNEW b/WHATSNEW
index 0facf307f..d5c527822 100644
--- a/WHATSNEW
+++ b/WHATSNEW
@@ -604,6 +604,10 @@ Other changes:
used to checkout/list files based on a date instead of a label.
Bugzilla Report 20578.
+* New filter . Adds the content of file at the beginning
+ or end of a file. Discussion started at
+ http://marc.theaimsgroup.com/?l=ant-user&m=106336791228585&w=2
+
Changes from Ant 1.5.3 to Ant 1.5.4
===================================
diff --git a/src/etc/testcases/filters/concat.xml b/src/etc/testcases/filters/concat.xml
new file mode 100644
index 000000000..d631fd674
--- /dev/null
+++ b/src/etc/testcases/filters/concat.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/org/apache/tools/ant/filters/ConcatFilter.java b/src/main/org/apache/tools/ant/filters/ConcatFilter.java
new file mode 100644
index 000000000..c50e47967
--- /dev/null
+++ b/src/main/org/apache/tools/ant/filters/ConcatFilter.java
@@ -0,0 +1,246 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 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 "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 apache@apache.org.
+ *
+ * 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
+ * .
+ */
+package org.apache.tools.ant.filters;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import org.apache.tools.ant.types.Parameter;
+
+/**
+ * Concats a file before and/or after the file.
+ *
+ * Example:
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ * Copies all java sources from src to build and adds the
+ * content of apache-license-java.txt add the beginning of each
+ * file.
+ *
+ * @since 1.6
+ * @version 2003-09-17
+ * @author Jan Matèrne
+ */
+public final class ConcatFilter extends BaseParamFilterReader
+ implements ChainableReader {
+
+ /** File to add before the content. */
+ private File before;
+
+ /** File to add after the content. */
+ private File after;
+
+ /** Reader for before-file. */
+ private Reader beforeReader = new EmptyReader();
+
+ /** Reader for after-file. */
+ private Reader afterReader = new EmptyReader();
+
+ /**
+ * Constructor for "dummy" instances.
+ *
+ * @see BaseFilterReader#BaseFilterReader()
+ */
+ public ConcatFilter() {
+ super();
+ }
+
+ /**
+ * Creates a new filtered reader.
+ *
+ * @param in A Reader object providing the underlying stream.
+ * Must not be null
.
+ */
+ public ConcatFilter(final Reader in) {
+ super(in);
+ }
+
+ /**
+ * Returns the next character in the filtered stream. If the desired
+ * number of lines have already been read, the resulting stream is
+ * effectively at an end. Otherwise, the next character from the
+ * underlying stream is read and returned.
+ *
+ * @return the next character in the resulting stream, or -1
+ * if the end of the resulting stream has been reached
+ *
+ * @exception IOException if the underlying stream throws an IOException
+ * during reading
+ */
+ public int read() throws IOException {
+ // do the "singleton" initialization
+ if (!getInitialized()) {
+ initialize();
+ setInitialized(true);
+ }
+
+ int ch = -1;
+
+ // The readers return -1 if they end. So simply read the "before"
+ // after that the "content" and at the end the "after" file.
+ ch = beforeReader.read();
+ if (ch == -1) {
+ ch = super.read();
+ }
+ if (ch == -1) {
+ ch = afterReader.read();
+ }
+
+ return ch;
+ }
+
+ /**
+ * Sets before attribute.
+ * @param before new value
+ */
+ public void setBefore(final File before) {
+ this.before = before;
+ }
+
+ /**
+ * Returns before attribute.
+ * @return before attribute
+ */
+ public File getBefore() {
+ return before;
+ }
+
+ /**
+ * Sets after attribute.
+ * @param after new value
+ */
+ public void setAfter(final File after) {
+ this.after = after;
+ }
+
+ /**
+ * Returns after attribute.
+ * @return after attribute
+ */
+ public File getAfter() {
+ return after;
+ }
+
+ /**
+ * Creates a new ConcatReader using the passed in
+ * Reader for instantiation.
+ *
+ * @param rdr A Reader object providing the underlying stream.
+ * Must not be null
.
+ *
+ * @return a new filter based on this configuration, but filtering
+ * the specified reader
+ */
+ public Reader chain(final Reader rdr) {
+ ConcatFilter newFilter = new ConcatFilter(rdr);
+ newFilter.setBefore(getBefore());
+ newFilter.setAfter(getAfter());
+ // Usually the initialized is set to true. But here it must not.
+ // Because the before and after readers have to be instantiated
+ // on runtime
+ //newFilter.setInitialized(true);
+ return newFilter;
+ }
+
+ /**
+ * Scans the parameters list for the "lines" parameter and uses
+ * it to set the number of lines to be returned in the filtered stream.
+ * also scan for skip parameter.
+ */
+ private void initialize() throws IOException {
+ // get parameters
+ Parameter[] params = getParameters();
+ if (params != null) {
+ for (int i = 0; i < params.length; i++) {
+ if ("before".equals(params[i].getName())) {
+ setBefore(new File(params[i].getValue()));
+ continue;
+ }
+ if ("after".equals(params[i].getName())) {
+ setAfter(new File(params[i].getValue()));
+ continue;
+ }
+ }
+ }
+ if (before != null) {
+ if (!before.isAbsolute()) {
+ before = new File(getProject().getBaseDir(), before.getPath());
+ }
+ beforeReader = new BufferedReader(new FileReader(before));
+ }
+ if (after != null) {
+ if (!after.isAbsolute()) {
+ after = new File(getProject().getBaseDir(), after.getPath());
+ }
+ afterReader = new BufferedReader(new FileReader(after));
+ }
+ }
+
+ /**
+ * Reader which is always at the end of file.
+ * Used for easier algorithm (polymorphism instead if-cascades).
+ */
+ private class EmptyReader extends Reader {
+ public int read(char[] ch, int i1, int i2) { return -1; }
+ public void close() { }
+ }
+
+}
\ No newline at end of file
diff --git a/src/testcases/org/apache/tools/ant/filters/ConcatFilterTest.java b/src/testcases/org/apache/tools/ant/filters/ConcatFilterTest.java
new file mode 100644
index 000000000..15d7be6b1
--- /dev/null
+++ b/src/testcases/org/apache/tools/ant/filters/ConcatFilterTest.java
@@ -0,0 +1,195 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2003 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 "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 apache@apache.org.
+ *
+ * 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
+ * .
+ */
+
+package org.apache.tools.ant.filters;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildFileTest;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * JUnit Testcases for ConcatReader
+ * @author Jan Matèrne
+ */
+public class ConcatFilterTest extends BuildFileTest {
+
+ private static FileUtils fu = FileUtils.newFileUtils();
+ private static final String lSep = System.getProperty("line.separator");
+
+ private static final String FILE_BEGINNING_WITH =
+ "this-should-be-the-first-line" + lSep
+ + "Line 1" + lSep
+ + "Line 2" + lSep
+ + "Line 3" + lSep
+ + "Line 4" + lSep
+ ;
+
+ private static final String FILE_BEGINNING =
+ "Line 1" + lSep
+ + "Line 2" + lSep
+ + "Line 3" + lSep
+ + "Line 4" + lSep
+ + "Line 5" + lSep
+ ;
+
+ private static final String FILE_ENDING_WITH =
+ "Line 57" + lSep
+ + "Line 58" + lSep
+ + "Line 59" + lSep
+ + "Line 60" + lSep
+ + "this-should-be-the-last-line" + lSep
+ ;
+
+ private static final String FILE_ENDING =
+ "Line 56" + lSep
+ + "Line 57" + lSep
+ + "Line 58" + lSep
+ + "Line 59" + lSep
+ + "Line 60" + lSep
+ ;
+
+
+ public ConcatFilterTest(String name) {
+ super(name);
+ }
+
+ public void setUp() {
+ configureProject("src/etc/testcases/filters/concat.xml");
+ }
+
+ public void tearDown() {
+ // I dont know why - but on my machine I always get a
+ // "Unable to delete file ...result\after.txt" (or before.txt)
+ // from Delete.removeDir(Delete.java:612).
+ // Win2000, JDK 1.4.1_02
+ // A before doesn´t work. From 10ms to 3000ms.
+ // I modified the taskdefs.Delete.DELETE_RETRY_SLEEP_MILLIS
+ // from 10 up to 2000 ms, but no success.
+ // So I give up - and hope for a suggestion from another one.
+ // But this shouldn´t let the testcases fail, so I do the cleanup
+ // inside a try-block
+ // Jan
+ try {
+ executeTarget("cleanup");
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void testFilterReaderNoArgs() throws IOException {
+ executeTarget("testFilterReaderNoArgs");
+ File expected = getProject().resolveFile("input/concatfilter.test");
+ File result = getProject().resolveFile("result/concat.filterReaderNoArgs.test");
+ assertTrue("testFilterReaderNoArgs: Result not like expected", fu.contentEquals(expected, result));
+ }
+
+ public void testFilterReaderBefore() throws IOException {
+ executeTarget("testFilterReaderBefore");
+ File resultFile = getProject().resolveFile("result/concat.filterReaderBefore.test");
+ String resultContent = fu.readFully(new java.io.FileReader(resultFile));
+ assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING_WITH));
+ assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING));
+ }
+
+ public void testFilterReaderAfter() throws IOException {
+ executeTarget("testFilterReaderAfter");
+ File resultFile = getProject().resolveFile("result/concat.filterReaderAfter.test");
+ String resultContent = fu.readFully(new java.io.FileReader(resultFile));
+ assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING));
+ assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING_WITH));
+ }
+
+ public void testFilterReaderBeforeAfter() throws IOException {
+ executeTarget("testFilterReaderBeforeAfter");
+ File resultFile = getProject().resolveFile("result/concat.filterReaderBeforeAfter.test");
+ String resultContent = fu.readFully(new java.io.FileReader(resultFile));
+ assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING_WITH));
+ assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING_WITH));
+ }
+
+ public void testConcatFilter() throws IOException {
+ executeTarget("testConcatFilter");
+ File resultFile = getProject().resolveFile("result/concat.concatfilter.test");
+ String resultContent = fu.readFully(new java.io.FileReader(resultFile));
+ assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING));
+ assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING));
+ }
+
+ public void testConcatFilterBefore() throws IOException {
+ executeTarget("testConcatFilterBefore");
+ File resultFile = getProject().resolveFile("result/concat.concatfilterBefore.test");
+ String resultContent = fu.readFully(new java.io.FileReader(resultFile));
+ assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING_WITH));
+ assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING));
+ }
+
+ public void testConcatFilterAfter() throws IOException {
+ executeTarget("testConcatFilterAfter");
+ File resultFile = getProject().resolveFile("result/concat.concatfilterAfter.test");
+ String resultContent = fu.readFully(new java.io.FileReader(resultFile));
+ assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING));
+ assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING_WITH));
+ }
+
+ public void testConcatFilterBeforeAfter() throws IOException {
+ executeTarget("testConcatFilterBeforeAfter");
+ File resultFile = getProject().resolveFile("result/concat.concatfilterBeforeAfter.test");
+ String resultContent = fu.readFully(new java.io.FileReader(resultFile));
+ assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING_WITH));
+ assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING_WITH));
+ }
+
+}
\ No newline at end of file