aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/FilterSet.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/FilterSet.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/FilterSet.java654
1 files changed, 654 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/FilterSet.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/FilterSet.java
new file mode 100644
index 00000000..2c1f2e71
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/types/FilterSet.java
@@ -0,0 +1,654 @@
+/*
+ * 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.types;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.VectorSet;
+
+/**
+ * A set of filters to be applied to something.
+ *
+ * A filter set may have begintoken and endtokens defined.
+ *
+ */
+public class FilterSet extends DataType implements Cloneable {
+
+ /**
+ * Individual filter component of filterset.
+ *
+ */
+ public static class Filter {
+ // CheckStyle:VisibilityModifier OFF - bc
+ /** Token which will be replaced in the filter operation. */
+ String token;
+
+ /** The value which will replace the token in the filtering operation. */
+ String value;
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * 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.
+ */
+ public Filter(String token, String value) {
+ setToken(token);
+ setValue(value);
+ }
+
+ /**
+ * No-argument constructor.
+ */
+ public Filter() {
+ }
+
+ /**
+ * Sets the Token attribute of the Filter object.
+ *
+ * @param token The new Token value.
+ */
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ /**
+ * Sets the Value attribute of the Filter object.
+ *
+ * @param value The new Value value.
+ */
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ /**
+ * Gets the Token attribute of the Filter object.
+ *
+ * @return The Token value.
+ */
+ public String getToken() {
+ return token;
+ }
+
+ /**
+ * Gets the Value attribute of the Filter object.
+ *
+ * @return The Value value.
+ */
+ public String getValue() {
+ return value;
+ }
+ }
+
+ /**
+ * The filtersfile nested element.
+ *
+ */
+ public class FiltersFile {
+
+ /**
+ * Constructor for the FiltersFile object.
+ */
+ public FiltersFile() {
+ }
+
+ /**
+ * Sets the file from which filters will be read.
+ *
+ * @param file the file from which filters will be read.
+ */
+ public void setFile(File file) {
+ filtersFiles.add(file);
+ }
+ }
+
+ /**
+ * EnumeratedAttribute to set behavior WRT missing filtersfiles:
+ * "fail" (default), "warn", "ignore".
+ * @since Ant 1.7
+ */
+ public static class OnMissing extends EnumeratedAttribute {
+ private static final String[] VALUES
+ = new String[] {"fail", "warn", "ignore"};
+
+ /** Fail value */
+ public static final OnMissing FAIL = new OnMissing("fail");
+ /** Warn value */
+ public static final OnMissing WARN = new OnMissing("warn");
+ /** Ignore value */
+ public static final OnMissing IGNORE = new OnMissing("ignore");
+
+ private static final int FAIL_INDEX = 0;
+ private static final int WARN_INDEX = 1;
+ private static final int IGNORE_INDEX = 2;
+
+ /**
+ * Default constructor.
+ */
+ public OnMissing() {
+ }
+
+ /**
+ * Convenience constructor.
+ * @param value the value to set.
+ */
+ public OnMissing(String value) {
+ setValue(value);
+ }
+
+ //inherit doc
+ /** {@inheritDoc}. */
+ @Override
+ public String[] getValues() {
+ return VALUES;
+ }
+ }
+
+ /** The default token start string */
+ public static final String DEFAULT_TOKEN_START = "@";
+
+ /** The default token end string */
+ public static final String DEFAULT_TOKEN_END = "@";
+
+ private String startOfToken = DEFAULT_TOKEN_START;
+ private String endOfToken = DEFAULT_TOKEN_END;
+
+ /** Contains a list of parsed tokens */
+ private Vector<String> passedTokens;
+ /** if a duplicate token is found, this is set to true */
+ private boolean duplicateToken = false;
+
+ private boolean recurse = true;
+ private Hashtable<String, String> filterHash = null;
+ private Vector<File> filtersFiles = new Vector<File>();
+ private OnMissing onMissingFiltersFile = OnMissing.FAIL;
+ private boolean readingFiles = false;
+
+ private int recurseDepth = 0;
+
+ /**
+ * List of ordered filters and filter files.
+ */
+ private Vector<Filter> filters = new Vector<Filter>();
+
+ /**
+ * Default constructor.
+ */
+ public FilterSet() {
+ }
+
+ /**
+ * Create a Filterset from another filterset.
+ *
+ * @param filterset the filterset upon which this filterset will be based.
+ */
+ protected FilterSet(FilterSet filterset) {
+ super();
+ @SuppressWarnings("unchecked")
+ Vector<Filter> clone = (Vector<Filter>) filterset.getFilters().clone();
+ this.filters = clone;
+ }
+
+ /**
+ * Get the filters in the filter set.
+ *
+ * @return a Vector of Filter instances.
+ */
+ protected synchronized Vector<Filter> getFilters() {
+ if (isReference()) {
+ return getRef().getFilters();
+ }
+ dieOnCircularReference();
+ //silly hack to avoid stack overflow...
+ if (!readingFiles) {
+ readingFiles = true;
+ final int size = filtersFiles.size();
+ for (int i = 0; i < size; i++) {
+ readFiltersFromFile(filtersFiles.get(i));
+ }
+ filtersFiles.clear();
+ readingFiles = false;
+ }
+ return filters;
+ }
+
+ /**
+ * Get the referenced filter set.
+ *
+ * @return the filterset from the reference.
+ */
+ protected FilterSet getRef() {
+ return getCheckedRef(FilterSet.class, "filterset");
+ }
+
+ /**
+ * Gets the filter hash of the FilterSet.
+ *
+ * @return The hash of the tokens and values for quick lookup.
+ */
+ public synchronized Hashtable<String, String> getFilterHash() {
+ if (isReference()) {
+ return getRef().getFilterHash();
+ }
+ dieOnCircularReference();
+ if (filterHash == null) {
+ filterHash = new Hashtable<String, String>(getFilters().size());
+ for (Enumeration<Filter> e = getFilters().elements(); e.hasMoreElements();) {
+ Filter filter = e.nextElement();
+ filterHash.put(filter.getToken(), filter.getValue());
+ }
+ }
+ return filterHash;
+ }
+
+ /**
+ * Set the file containing the filters for this filterset.
+ *
+ * @param filtersFile sets the filter file from which to read filters
+ * for this filter set.
+ * @throws BuildException if there is an error.
+ */
+ public void setFiltersfile(File filtersFile) throws BuildException {
+ if (isReference()) {
+ throw tooManyAttributes();
+ }
+ filtersFiles.add(filtersFile);
+ }
+
+ /**
+ * Set the string used to id the beginning of a token.
+ *
+ * @param startOfToken The new Begintoken value.
+ */
+ public void setBeginToken(String startOfToken) {
+ if (isReference()) {
+ throw tooManyAttributes();
+ }
+ if (startOfToken == null || "".equals(startOfToken)) {
+ throw new BuildException("beginToken must not be empty");
+ }
+ this.startOfToken = startOfToken;
+ }
+
+ /**
+ * Get the begin token for this filterset.
+ *
+ * @return the filter set's begin token for filtering.
+ */
+ public String getBeginToken() {
+ if (isReference()) {
+ return getRef().getBeginToken();
+ }
+ return startOfToken;
+ }
+
+ /**
+ * Set the string used to id the end of a token.
+ *
+ * @param endOfToken The new Endtoken value.
+ */
+ public void setEndToken(String endOfToken) {
+ if (isReference()) {
+ throw tooManyAttributes();
+ }
+ if (endOfToken == null || "".equals(endOfToken)) {
+ throw new BuildException("endToken must not be empty");
+ }
+ this.endOfToken = endOfToken;
+ }
+
+ /**
+ * Get the end token for this filterset.
+ *
+ * @return the filter set's end token for replacement delimiting.
+ */
+ public String getEndToken() {
+ if (isReference()) {
+ return getRef().getEndToken();
+ }
+ 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 when the file cannot be read.
+ */
+ public synchronized void readFiltersFromFile(File filtersFile) throws BuildException {
+ if (isReference()) {
+ throw tooManyAttributes();
+ }
+ if (!filtersFile.exists()) {
+ handleMissingFile("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;
+ try {
+ Properties props = new Properties();
+ in = new FileInputStream(filtersFile);
+ props.load(in);
+
+ Enumeration<?> e = props.propertyNames();
+ Vector<Filter> filts = getFilters();
+ while (e.hasMoreElements()) {
+ String strPropName = (String) e.nextElement();
+ String strValue = props.getProperty(strPropName);
+ filts.addElement(new Filter(strPropName, strValue));
+ }
+ } catch (Exception ex) {
+ throw new BuildException("Could not read filters from file: "
+ + filtersFile, ex);
+ } finally {
+ FileUtils.close(in);
+ }
+ } else {
+ handleMissingFile(
+ "Must specify a file rather than a directory in "
+ + "the filtersfile attribute:" + filtersFile);
+ }
+ filterHash = null;
+ }
+
+ /**
+ * Does replacement on the given string with token matching.
+ * This uses the defined begintoken and endtoken values which default
+ * to @ for both.
+ * This resets the passedTokens and calls iReplaceTokens to
+ * do the actual replacements.
+ *
+ * @param line The line in which to process embedded tokens.
+ * @return The input string after token replacement.
+ */
+ public synchronized String replaceTokens(String line) {
+ return iReplaceTokens(line);
+ }
+
+ /**
+ * Add a new filter.
+ *
+ * @param filter the filter to be added.
+ */
+ public synchronized void addFilter(Filter filter) {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
+ filters.addElement(filter);
+ filterHash = null;
+ }
+
+ /**
+ * Create a new FiltersFile.
+ *
+ * @return The filtersfile that was created.
+ */
+ public FiltersFile createFiltersfile() {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
+ return new FiltersFile();
+ }
+
+ /**
+ * 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();
+ }
+ addFilter(new Filter(token, value));
+ }
+
+ /**
+ * 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 (Filter filter : filterSet.getFilters()) {
+ addFilter(filter);
+ }
+ }
+
+ /**
+ * Adds the properties provided by the specified PropertySet to this filterset.
+ *
+ * @param propertySet the propertyset to be added to this propertyset
+ */
+ public synchronized void addConfiguredPropertySet(PropertySet propertySet) {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
+ Properties p = propertySet.getProperties();
+ Set<Map.Entry<Object,Object>> entries = p.entrySet();
+ for (Map.Entry<Object, Object> entry : entries) {
+ addFilter(new Filter(String.valueOf(entry.getKey()),
+ String.valueOf(entry.getValue())));
+ }
+ }
+
+ /**
+ * Test to see if this filter set has filters.
+ *
+ * @return Return true if there are filters in this set.
+ */
+ public synchronized boolean hasFilters() {
+ return getFilters().size() > 0;
+ }
+
+ /**
+ * Clone the filterset.
+ *
+ * @return a deep clone of this filterset.
+ *
+ * @throws BuildException if the clone cannot be performed.
+ */
+ @Override
+ public synchronized Object clone() throws BuildException {
+ if (isReference()) {
+ return getRef().clone();
+ }
+ try {
+ FilterSet fs = (FilterSet) super.clone();
+ @SuppressWarnings("unchecked")
+ Vector<Filter> clonedFilters = (Vector<Filter>) getFilters().clone();
+ fs.filters = clonedFilters;
+ fs.setProject(getProject());
+ return fs;
+ } catch (CloneNotSupportedException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * Set the behavior WRT missing filtersfiles.
+ * @param onMissingFiltersFile the OnMissing describing the behavior.
+ */
+ public void setOnMissingFiltersFile(OnMissing onMissingFiltersFile) {
+ this.onMissingFiltersFile = onMissingFiltersFile;
+ }
+
+ /**
+ * Get the onMissingFiltersFile setting.
+ * @return the OnMissing instance.
+ */
+ public OnMissing getOnMissingFiltersFile() {
+ return onMissingFiltersFile;
+ }
+
+ /**
+ * Does replacement on the given string with token matching.
+ * This uses the defined begintoken and endtoken values which default
+ * to @ for both.
+ *
+ * @param line The line to process the tokens in.
+ * @return The string with the tokens replaced.
+ */
+ private synchronized String iReplaceTokens(String line) {
+ String beginToken = getBeginToken();
+ String endToken = getEndToken();
+ int index = line.indexOf(beginToken);
+
+ if (index > -1) {
+ Hashtable<String, String> tokens = getFilterHash();
+ try {
+ StringBuilder b = new StringBuilder();
+ int i = 0;
+ String token = null;
+ String value = null;
+
+ while (index > -1) {
+ //can't have zero-length token
+ int endIndex = line.indexOf(endToken,
+ index + beginToken.length() + 1);
+ if (endIndex == -1) {
+ break;
+ }
+ token
+ = line.substring(index + beginToken.length(), endIndex);
+ b.append(line.substring(i, index));
+ if (tokens.containsKey(token)) {
+ value = tokens.get(token);
+ if (recurse && !value.equals(token)) {
+ // we have another token, let's parse it.
+ value = replaceTokens(value, token);
+ }
+ log("Replacing: " + beginToken + token + endToken
+ + " -> " + value, Project.MSG_VERBOSE);
+ b.append(value);
+ i = index + beginToken.length() + token.length()
+ + endToken.length();
+ } else {
+ // just append first character of beginToken
+ // and search further
+ // we can't skip the complete beginToken since
+ // it may contain the start of another
+ // candidate begin token (Bugzilla 45094)
+ b.append(beginToken.charAt(0));
+ i = index + 1;
+ }
+ index = line.indexOf(beginToken, i);
+ }
+
+ b.append(line.substring(i));
+ return b.toString();
+ } catch (StringIndexOutOfBoundsException e) {
+ return line;
+ }
+ } else {
+ return line;
+ }
+ }
+
+ /**
+ * 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 parent token (= the token it was parsed from).
+ */
+ private synchronized String replaceTokens(String line, String parent)
+ throws BuildException {
+ String beginToken = getBeginToken();
+ String endToken = getEndToken();
+ if (recurseDepth == 0) {
+ passedTokens = new VectorSet<String>();
+ }
+ recurseDepth++;
+ if (passedTokens.contains(parent) && !duplicateToken) {
+ duplicateToken = true;
+ System.out.println(
+ "Infinite loop in tokens. Currently known tokens : "
+ + passedTokens.toString() + "\nProblem token : " + beginToken
+ + parent + endToken + " called from " + beginToken
+ + passedTokens.lastElement().toString() + endToken);
+ recurseDepth--;
+ return parent;
+ }
+ passedTokens.addElement(parent);
+ String value = iReplaceTokens(line);
+ if (value.indexOf(beginToken) == -1 && !duplicateToken
+ && recurseDepth == 1) {
+ passedTokens = null;
+ } else if (duplicateToken) {
+ // should always be the case...
+ if (passedTokens.size() > 0) {
+ value = passedTokens.remove(passedTokens.size() - 1);
+ if (passedTokens.size() == 0) {
+ value = beginToken + value + endToken;
+ duplicateToken = false;
+ }
+ }
+ } else if (passedTokens.size() > 0) {
+ // remove last seen token when crawling out of recursion
+ passedTokens.remove(passedTokens.size() - 1);
+ }
+ recurseDepth--;
+ return value;
+ }
+
+ private void handleMissingFile(String message) {
+ switch (onMissingFiltersFile.getIndex()) {
+ case OnMissing.IGNORE_INDEX:
+ return;
+ case OnMissing.FAIL_INDEX:
+ throw new BuildException(message);
+ case OnMissing.WARN_INDEX:
+ log(message, Project.MSG_WARN);
+ return;
+ default:
+ throw new BuildException("Invalid value for onMissingFiltersFile");
+ }
+ }
+
+}