aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Replace.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Replace.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Replace.java955
1 files changed, 955 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Replace.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Replace.java
new file mode 100644
index 00000000..9aa9fe8e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Replace.java
@@ -0,0 +1,955 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.tools.ant.taskdefs;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Properties;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.DirectoryScanner;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.FileProvider;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Replaces all occurrences of one or more string tokens with given
+ * values in the indicated files. Each value can be either a string
+ * or the value of a property available in a designated property file.
+ * If you want to replace a text that crosses line boundaries, you
+ * must use a nested <code>&lt;replacetoken&gt;</code> element.
+ *
+ * @since Ant 1.1
+ *
+ * @ant.task category="filesystem"
+ */
+public class Replace extends MatchingTask {
+
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ private File sourceFile = null;
+ private NestedString token = null;
+ private NestedString value = new NestedString();
+
+ private Resource propertyResource = null;
+ private Resource replaceFilterResource = null;
+ private Properties properties = null;
+ private ArrayList replacefilters = new ArrayList();
+
+ private File dir = null;
+
+ private int fileCount;
+ private int replaceCount;
+ private boolean summary = false;
+
+ /** The encoding used to read and write files - if null, uses default */
+ private String encoding = null;
+
+ private Union resources;
+
+ private boolean preserveLastModified = false;
+ private boolean failOnNoReplacements = false;
+
+ /**
+ * An inline string to use as the replacement text.
+ */
+ public class NestedString {
+
+ private boolean expandProperties = false;
+ private StringBuffer buf = new StringBuffer();
+
+ /**
+ * Whether properties should be expanded in nested test.
+ *
+ * <p>If you use this class via its Java interface the text
+ * you add via {@link #addText addText} has most likely been
+ * expanded already so you do <b>not</b> want to set this to
+ * true.</p>
+ *
+ * @since Ant 1.8.0
+ */
+ public void setExpandProperties(boolean b) {
+ expandProperties = b;
+ }
+
+ /**
+ * The text of the element.
+ *
+ * @param val the string to add
+ */
+ public void addText(String val) {
+ buf.append(val);
+ }
+
+ /**
+ * @return the text
+ */
+ public String getText() {
+ String s = buf.toString();
+ return expandProperties ? getProject().replaceProperties(s) : s;
+ }
+ }
+
+ /**
+ * A filter to apply.
+ */
+ public class Replacefilter {
+ private NestedString token;
+ private NestedString value;
+ private String replaceValue;
+ private String property;
+
+ private StringBuffer inputBuffer;
+ private StringBuffer outputBuffer = new StringBuffer();
+
+ /**
+ * Validate the filter's configuration.
+ * @throws BuildException if any part is invalid.
+ */
+ public void validate() throws BuildException {
+ //Validate mandatory attributes
+ if (token == null) {
+ String message = "token is a mandatory for replacefilter.";
+ throw new BuildException(message);
+ }
+
+ if ("".equals(token.getText())) {
+ String message = "The token must not be an empty "
+ + "string.";
+ throw new BuildException(message);
+ }
+
+ //value and property are mutually exclusive attributes
+ if ((value != null) && (property != null)) {
+ String message = "Either value or property "
+ + "can be specified, but a replacefilter "
+ + "element cannot have both.";
+ throw new BuildException(message);
+ }
+
+ if ((property != null)) {
+ //the property attribute must have access to a property file
+ if (propertyResource == null) {
+ String message = "The replacefilter's property attribute "
+ + "can only be used with the replacetask's "
+ + "propertyFile/Resource attribute.";
+ throw new BuildException(message);
+ }
+
+ //Make sure property exists in property file
+ if (properties == null
+ || properties.getProperty(property) == null) {
+ String message = "property \"" + property
+ + "\" was not found in " + propertyResource.getName();
+ throw new BuildException(message);
+ }
+ }
+
+ replaceValue = getReplaceValue();
+ }
+
+ /**
+ * Get the replacement value for this filter token.
+ * @return the replacement value
+ */
+ public String getReplaceValue() {
+ if (property != null) {
+ return properties.getProperty(property);
+ } else if (value != null) {
+ return value.getText();
+ } else if (Replace.this.value != null) {
+ return Replace.this.value.getText();
+ } else {
+ //Default is empty string
+ return "";
+ }
+ }
+
+ /**
+ * Set the token to replace.
+ * @param t <code>String</code> token.
+ */
+ public void setToken(String t) {
+ createReplaceToken().addText(t);
+ }
+
+ /**
+ * Get the string to search for.
+ * @return current <code>String</code> token.
+ */
+ public String getToken() {
+ return token.getText();
+ }
+
+ /**
+ * The replacement string; required if <code>property</code>
+ * is not set.
+ * @param value <code>String</code> value to replace.
+ */
+ public void setValue(String value) {
+ createReplaceValue().addText(value);
+ }
+
+ /**
+ * Get replacement <code>String</code>.
+ * @return replacement or null.
+ */
+ public String getValue() {
+ return value.getText();
+ }
+
+ /**
+ * Set the name of the property whose value is to serve as
+ * the replacement value; required if <code>value</code> is not set.
+ * @param property property name.
+ */
+ public void setProperty(String property) {
+ this.property = property;
+ }
+
+ /**
+ * Get the name of the property whose value is to serve as
+ * the replacement value.
+ * @return property or null.
+ */
+ public String getProperty() {
+ return property;
+ }
+
+ /**
+ * Create a token to filter as the text of a nested element.
+ * @return nested token <code>NestedString</code> to configure.
+ * @since Ant 1.8.0
+ */
+ public NestedString createReplaceToken() {
+ if (token == null) {
+ token = new NestedString();
+ }
+ return token;
+ }
+
+ /**
+ * Create a string to replace the token as the text of a nested element.
+ * @return replacement value <code>NestedString</code> to configure.
+ * @since Ant 1.8.0
+ */
+ public NestedString createReplaceValue() {
+ if (value == null) {
+ value = new NestedString();
+ }
+ return value;
+ }
+
+ /**
+ * Retrieves the output buffer of this filter. The filter guarantees
+ * that data is only appended to the end of this StringBuffer.
+ * @return The StringBuffer containing the output of this filter.
+ */
+ StringBuffer getOutputBuffer() {
+ return outputBuffer;
+ }
+
+ /**
+ * Sets the input buffer for this filter.
+ * The filter expects from the component providing the input that data
+ * is only added by that component to the end of this StringBuffer.
+ * This StringBuffer will be modified by this filter, and expects that
+ * another component will only apped to this StringBuffer.
+ * @param input The input for this filter.
+ */
+ void setInputBuffer(StringBuffer input) {
+ inputBuffer = input;
+ }
+
+ /**
+ * Processes the buffer as far as possible. Takes into account that
+ * appended data may make it possible to replace the end of the already
+ * received data, when the token is split over the "old" and the "new"
+ * part.
+ * @return true if some data has been made available in the
+ * output buffer.
+ */
+ boolean process() {
+ String t = getToken();
+ if (inputBuffer.length() > t.length()) {
+ int pos = replace();
+ pos = Math.max((inputBuffer.length() - t.length()), pos);
+ outputBuffer.append(inputBuffer.substring(0, pos));
+ inputBuffer.delete(0, pos);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Processes the buffer to the end. Does not take into account that
+ * appended data may make it possible to replace the end of the already
+ * received data.
+ */
+ void flush() {
+ replace();
+ outputBuffer.append(inputBuffer);
+ inputBuffer.delete(0, inputBuffer.length());
+ }
+
+ /**
+ * Performs the replace operation.
+ * @return The position of the last character that was inserted as
+ * replacement.
+ */
+ private int replace() {
+ String t = getToken();
+ int found = inputBuffer.indexOf(t);
+ int pos = -1;
+ final int tokenLength = t.length();
+ final int replaceValueLength = replaceValue.length();
+ while (found >= 0) {
+ inputBuffer.replace(found, found + tokenLength, replaceValue);
+ pos = found + replaceValueLength;
+ found = inputBuffer.indexOf(t, pos);
+ ++replaceCount;
+ }
+ return pos;
+ }
+ }
+
+ /**
+ * Class reading a file in small chunks, and presenting these chunks in
+ * a StringBuffer. Compatible with the Replacefilter.
+ * @since 1.7
+ */
+ private class FileInput /* JDK 5: implements Closeable */ {
+ private StringBuffer outputBuffer;
+ private final InputStream is;
+ private Reader reader;
+ private char[] buffer;
+ private static final int BUFF_SIZE = 4096;
+
+ /**
+ * Constructs the input component. Opens the file for reading.
+ * @param source The file to read from.
+ * @throws IOException When the file cannot be read from.
+ */
+ FileInput(File source) throws IOException {
+ outputBuffer = new StringBuffer();
+ buffer = new char[BUFF_SIZE];
+ is = new FileInputStream(source);
+ try {
+ reader = new BufferedReader(encoding != null ? new InputStreamReader(is, encoding) : new InputStreamReader(is));
+ } finally {
+ if (reader == null) {
+ is.close();
+ }
+ }
+ }
+
+ /**
+ * Retrieves the output buffer of this filter. The component guarantees
+ * that data is only appended to the end of this StringBuffer.
+ * @return The StringBuffer containing the output of this filter.
+ */
+ StringBuffer getOutputBuffer() {
+ return outputBuffer;
+ }
+
+ /**
+ * Reads some data from the file.
+ * @return true when the end of the file has not been reached.
+ * @throws IOException When the file cannot be read from.
+ */
+ boolean readChunk() throws IOException {
+ int bufferLength = 0;
+ bufferLength = reader.read(buffer);
+ if (bufferLength < 0) {
+ return false;
+ }
+ outputBuffer.append(new String(buffer, 0, bufferLength));
+ return true;
+ }
+
+ /**
+ * Closes the file.
+ * @throws IOException When the file cannot be closed.
+ */
+ public void close() throws IOException {
+ is.close();
+ }
+
+ }
+
+ /**
+ * Component writing a file in chunks, taking the chunks from the
+ * Replacefilter.
+ * @since 1.7
+ */
+ private class FileOutput /* JDK 5: implements Closeable */ {
+ private StringBuffer inputBuffer;
+ private final OutputStream os;
+ private Writer writer;
+
+ /**
+ * Constructs the output component. Opens the file for writing.
+ * @param out The file to read to.
+ * @throws IOException When the file cannot be read from.
+ */
+ FileOutput(File out) throws IOException {
+ os = new FileOutputStream(out);
+ try {
+ writer = new BufferedWriter(encoding != null ? new OutputStreamWriter(os, encoding) : new OutputStreamWriter(os));
+ } finally {
+ if (writer == null) {
+ os.close();
+ }
+ }
+ }
+
+ /**
+ * Sets the input buffer for this component.
+ * The filter expects from the component providing the input that data
+ * is only added by that component to the end of this StringBuffer.
+ * This StringBuffer will be modified by this filter, and expects that
+ * another component will only append to this StringBuffer.
+ * @param input The input for this filter.
+ */
+ void setInputBuffer(StringBuffer input) {
+ inputBuffer = input;
+ }
+
+ /**
+ * Writes the buffer as far as possible.
+ * @return false to be inline with the Replacefilter.
+ * (Yes defining an interface crossed my mind, but would publish the
+ * internal behavior.)
+ * @throws IOException when the output cannot be written.
+ */
+ boolean process() throws IOException {
+ writer.write(inputBuffer.toString());
+ inputBuffer.delete(0, inputBuffer.length());
+ return false;
+ }
+
+ /**
+ * Processes the buffer to the end.
+ * @throws IOException when the output cannot be flushed.
+ */
+ void flush() throws IOException {
+ process();
+ writer.flush();
+ }
+
+ /**
+ * Closes the file.
+ * @throws IOException When the file cannot be closed.
+ */
+ public void close() throws IOException {
+ os.close();
+ }
+
+ }
+
+ /**
+ * Do the execution.
+ * @throws BuildException if we can't build
+ */
+ public void execute() throws BuildException {
+
+ ArrayList savedFilters = (ArrayList) replacefilters.clone();
+ Properties savedProperties =
+ properties == null ? null : (Properties) properties.clone();
+
+ if (token != null) {
+ // line separators in values and tokens are "\n"
+ // in order to compare with the file contents, replace them
+ // as needed
+ StringBuffer val = new StringBuffer(value.getText());
+ stringReplace(val, "\r\n", "\n");
+ stringReplace(val, "\n", StringUtils.LINE_SEP);
+ StringBuffer tok = new StringBuffer(token.getText());
+ stringReplace(tok, "\r\n", "\n");
+ stringReplace(tok, "\n", StringUtils.LINE_SEP);
+ Replacefilter firstFilter = createPrimaryfilter();
+ firstFilter.setToken(tok.toString());
+ firstFilter.setValue(val.toString());
+ }
+
+ try {
+ if (replaceFilterResource != null) {
+ Properties props = getProperties(replaceFilterResource);
+ Iterator e = props.keySet().iterator();
+ while (e.hasNext()) {
+ String tok = e.next().toString();
+ Replacefilter replaceFilter = createReplacefilter();
+ replaceFilter.setToken(tok);
+ replaceFilter.setValue(props.getProperty(tok));
+ }
+ }
+
+ validateAttributes();
+
+ if (propertyResource != null) {
+ properties = getProperties(propertyResource);
+ }
+
+ validateReplacefilters();
+ fileCount = 0;
+ replaceCount = 0;
+
+ if (sourceFile != null) {
+ processFile(sourceFile);
+ }
+
+ if (dir != null) {
+ DirectoryScanner ds = super.getDirectoryScanner(dir);
+ String[] srcs = ds.getIncludedFiles();
+
+ for (int i = 0; i < srcs.length; i++) {
+ File file = new File(dir, srcs[i]);
+ processFile(file);
+ }
+ }
+
+ if (resources != null) {
+ for (Resource r : resources) {
+ FileProvider fp =
+ r.as(FileProvider.class);
+ processFile(fp.getFile());
+ }
+ }
+
+ if (summary) {
+ log("Replaced " + replaceCount + " occurrences in "
+ + fileCount + " files.", Project.MSG_INFO);
+ }
+ if (failOnNoReplacements && replaceCount == 0) {
+ throw new BuildException("didn't replace anything");
+ }
+ } finally {
+ replacefilters = savedFilters;
+ properties = savedProperties;
+ } // end of finally
+
+ }
+
+ /**
+ * Validate attributes provided for this task in .xml build file.
+ *
+ * @exception BuildException if any supplied attribute is invalid or any
+ * mandatory attribute is missing.
+ */
+ public void validateAttributes() throws BuildException {
+ if (sourceFile == null && dir == null && resources == null) {
+ String message = "Either the file or the dir attribute "
+ + "or nested resources must be specified";
+ throw new BuildException(message, getLocation());
+ }
+ if (propertyResource != null && !propertyResource.isExists()) {
+ String message = "Property file " + propertyResource.getName()
+ + " does not exist.";
+ throw new BuildException(message, getLocation());
+ }
+ if (token == null && replacefilters.size() == 0) {
+ String message = "Either token or a nested replacefilter "
+ + "must be specified";
+ throw new BuildException(message, getLocation());
+ }
+ if (token != null && "".equals(token.getText())) {
+ String message = "The token attribute must not be an empty string.";
+ throw new BuildException(message, getLocation());
+ }
+ }
+
+ /**
+ * Validate nested elements.
+ *
+ * @exception BuildException if any supplied attribute is invalid or any
+ * mandatory attribute is missing.
+ */
+ public void validateReplacefilters()
+ throws BuildException {
+ final int size = replacefilters.size();
+ for (int i = 0; i < size; i++) {
+ Replacefilter element =
+ (Replacefilter) replacefilters.get(i);
+ element.validate();
+ }
+ }
+
+ /**
+ * Load a properties file.
+ * @param propertyFile the file to load the properties from.
+ * @return loaded <code>Properties</code> object.
+ * @throws BuildException if the file could not be found or read.
+ */
+ public Properties getProperties(File propertyFile) throws BuildException {
+ return getProperties(new FileResource(getProject(), propertyFile));
+ }
+
+ /**
+ * Load a properties resource.
+ * @param propertyResource the resource to load the properties from.
+ * @return loaded <code>Properties</code> object.
+ * @throws BuildException if the resource could not be found or read.
+ * @since Ant 1.8.0
+ */
+ public Properties getProperties(Resource propertyResource)
+ throws BuildException {
+ Properties props = new Properties();
+
+ InputStream in = null;
+ try {
+ in = propertyResource.getInputStream();
+ props.load(in);
+ } catch (IOException e) {
+ String message = "Property resource (" + propertyResource.getName()
+ + ") cannot be loaded.";
+ throw new BuildException(message);
+ } finally {
+ FileUtils.close(in);
+ }
+
+ return props;
+ }
+
+ /**
+ * Perform the replacement on the given file.
+ *
+ * The replacement is performed on a temporary file which then
+ * replaces the original file.
+ *
+ * @param src the source <code>File</code>.
+ */
+ private void processFile(File src) throws BuildException {
+ if (!src.exists()) {
+ throw new BuildException("Replace: source file " + src.getPath()
+ + " doesn't exist", getLocation());
+ }
+
+ int repCountStart = replaceCount;
+ logFilterChain(src.getPath());
+
+ try {
+ File temp = FILE_UTILS.createTempFile("rep", ".tmp",
+ src.getParentFile(), false, true);
+ try {
+ FileInput in = new FileInput(src);
+ try {
+ FileOutput out = new FileOutput(temp);
+ try {
+ out.setInputBuffer(buildFilterChain(in.getOutputBuffer()));
+
+ while (in.readChunk()) {
+ if (processFilterChain()) {
+ out.process();
+ }
+ }
+
+ flushFilterChain();
+
+ out.flush();
+ } finally {
+ out.close();
+ }
+ } finally {
+ in.close();
+ }
+ boolean changes = (replaceCount != repCountStart);
+ if (changes) {
+ fileCount++;
+ long origLastModified = src.lastModified();
+ FILE_UTILS.rename(temp, src);
+ if (preserveLastModified) {
+ FILE_UTILS.setFileLastModified(src, origLastModified);
+ }
+ }
+ } finally {
+ if (temp.isFile() && !temp.delete()) {
+ temp.deleteOnExit();
+ }
+ }
+ } catch (IOException ioe) {
+ throw new BuildException("IOException in " + src + " - "
+ + ioe.getClass().getName() + ":"
+ + ioe.getMessage(), ioe, getLocation());
+ }
+ }
+
+ /**
+ * Flushes all filters.
+ */
+ private void flushFilterChain() {
+ final int size = replacefilters.size();
+ for (int i = 0; i < size; i++) {
+ Replacefilter filter = (Replacefilter) replacefilters.get(i);
+ filter.flush();
+ }
+ }
+
+ /**
+ * Performs the normal processing of the filters.
+ * @return true if the filter chain produced new output.
+ */
+ private boolean processFilterChain() {
+ final int size = replacefilters.size();
+ for (int i = 0; i < size; i++) {
+ Replacefilter filter = (Replacefilter) replacefilters.get(i);
+ if (!filter.process()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Creates the chain of filters to operate.
+ * @param inputBuffer <code>StringBuffer</code> containing the input for the
+ * first filter.
+ * @return <code>StringBuffer</code> containing the output of the last filter.
+ */
+ private StringBuffer buildFilterChain(StringBuffer inputBuffer) {
+ StringBuffer buf = inputBuffer;
+ final int size = replacefilters.size();
+ for (int i = 0; i < size; i++) {
+ Replacefilter filter = (Replacefilter) replacefilters.get(i);
+ filter.setInputBuffer(buf);
+ buf = filter.getOutputBuffer();
+ }
+ return buf;
+ }
+
+ /**
+ * Logs the chain of filters to operate on the file.
+ * @param filename <code>String</code>.
+ */
+ private void logFilterChain(String filename) {
+ final int size = replacefilters.size();
+ for (int i = 0; i < size; i++) {
+ Replacefilter filter = (Replacefilter) replacefilters.get(i);
+ log("Replacing in " + filename + ": " + filter.getToken()
+ + " --> " + filter.getReplaceValue(), Project.MSG_VERBOSE);
+ }
+ }
+ /**
+ * Set the source file; required unless <code>dir</code> is set.
+ * @param file source <code>File</code>.
+ */
+ public void setFile(File file) {
+ this.sourceFile = file;
+ }
+
+ /**
+ * Indicates whether a summary of the replace operation should be
+ * produced, detailing how many token occurrences and files were
+ * processed; optional, default=<code>false</code>.
+ *
+ * @param summary <code>boolean</code> whether a summary of the
+ * replace operation should be logged.
+ */
+ public void setSummary(boolean summary) {
+ this.summary = summary;
+ }
+
+
+ /**
+ * Sets the name of a property file containing filters; optional.
+ * Each property will be treated as a replacefilter where token is the name
+ * of the property and value is the value of the property.
+ * @param replaceFilterFile <code>File</code> to load.
+ */
+ public void setReplaceFilterFile(File replaceFilterFile) {
+ setReplaceFilterResource(new FileResource(getProject(),
+ replaceFilterFile));
+ }
+
+ /**
+ * Sets the name of a resource containing filters; optional.
+ * Each property will be treated as a replacefilter where token is the name
+ * of the property and value is the value of the property.
+ * @param replaceFilter <code>Resource</code> to load.
+ * @since Ant 1.8.0
+ */
+ public void setReplaceFilterResource(Resource replaceFilter) {
+ this.replaceFilterResource = replaceFilter;
+ }
+
+ /**
+ * The base directory to use when replacing a token in multiple files;
+ * required if <code>file</code> is not defined.
+ * @param dir <code>File</code> representing the base directory.
+ */
+ public void setDir(File dir) {
+ this.dir = dir;
+ }
+
+ /**
+ * Set the string token to replace; required unless a nested
+ * <code>replacetoken</code> element or the
+ * <code>replacefilterresource</code> attribute is used.
+ * @param token token <code>String</code>.
+ */
+ public void setToken(String token) {
+ createReplaceToken().addText(token);
+ }
+
+ /**
+ * Set the string value to use as token replacement;
+ * optional, default is the empty string "".
+ * @param value replacement value.
+ */
+ public void setValue(String value) {
+ createReplaceValue().addText(value);
+ }
+
+ /**
+ * Set the file encoding to use on the files read and written by the task;
+ * optional, defaults to default JVM encoding.
+ *
+ * @param encoding the encoding to use on the files.
+ */
+ public void setEncoding(String encoding) {
+ this.encoding = encoding;
+ }
+
+ /**
+ * Create a token to filter as the text of a nested element.
+ * @return nested token <code>NestedString</code> to configure.
+ */
+ public NestedString createReplaceToken() {
+ if (token == null) {
+ token = new NestedString();
+ }
+ return token;
+ }
+
+ /**
+ * Create a string to replace the token as the text of a nested element.
+ * @return replacement value <code>NestedString</code> to configure.
+ */
+ public NestedString createReplaceValue() {
+ return value;
+ }
+
+ /**
+ * The name of a property file from which properties specified using nested
+ * <code>&lt;replacefilter&gt;</code> elements are drawn; required only if
+ * the <i>property</i> attribute of <code>&lt;replacefilter&gt;</code> is used.
+ * @param propertyFile <code>File</code> to load.
+ */
+ public void setPropertyFile(File propertyFile) {
+ setPropertyResource(new FileResource(propertyFile));
+ }
+
+ /**
+ * A resource from which properties specified using nested
+ * <code>&lt;replacefilter&gt;</code> elements are drawn; required
+ * only if the <i>property</i> attribute of
+ * <code>&lt;replacefilter&gt;</code> is used.
+ * @param propertyResource <code>Resource</code> to load.
+ *
+ * @since Ant 1.8.0
+ */
+ public void setPropertyResource(Resource propertyResource) {
+ this.propertyResource = propertyResource;
+ }
+
+ /**
+ * Add a nested &lt;replacefilter&gt; element.
+ * @return a nested <code>Replacefilter</code> object to be configured.
+ */
+ public Replacefilter createReplacefilter() {
+ Replacefilter filter = new Replacefilter();
+ replacefilters.add(filter);
+ return filter;
+ }
+
+ /**
+ * Support arbitrary file system based resource collections.
+ *
+ * @since Ant 1.8.0
+ */
+ public void addConfigured(ResourceCollection rc) {
+ if (!rc.isFilesystemOnly()) {
+ throw new BuildException("only filesystem resources are supported");
+ }
+ if (resources == null) {
+ resources = new Union();
+ }
+ resources.add(rc);
+ }
+
+ /**
+ * Whether the file timestamp shall be preserved even if the file
+ * is modified.
+ *
+ * @since Ant 1.8.0
+ */
+ public void setPreserveLastModified(boolean b) {
+ preserveLastModified = b;
+ }
+
+ /**
+ * Whether the build should fail if nothing has been replaced.
+ *
+ * @since Ant 1.8.0
+ */
+ public void setFailOnNoReplacements(boolean b) {
+ failOnNoReplacements = b;
+ }
+
+ /**
+ * Adds the token and value as first &lt;replacefilter&gt; element.
+ * The token and value are always processed first.
+ * @return a nested <code>Replacefilter</code> object to be configured.
+ */
+ private Replacefilter createPrimaryfilter() {
+ Replacefilter filter = new Replacefilter();
+ replacefilters.add(0, filter);
+ return filter;
+ }
+
+ /**
+ * Replace occurrences of str1 in StringBuffer str with str2.
+ */
+ private void stringReplace(StringBuffer str, String str1, String str2) {
+ int found = str.indexOf(str1);
+ final int str1Length = str1.length();
+ final int str2Length = str2.length();
+ while (found >= 0) {
+ str.replace(found, found + str1Length, str2);
+ found = str.indexOf(str1, found + str2Length);
+ }
+ }
+
+}