aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Base64Converter.java124
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ChainedMapper.java60
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java463
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/CollectionUtils.java278
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/CompositeMapper.java50
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ConcatFileInputStream.java136
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java147
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ContainerMapper.java119
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DOMElementWriter.java640
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DOMUtils.java163
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DateUtils.java301
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DeweyDecimal.java237
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileNameMapper.java60
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileTokenizer.java48
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileUtils.java1722
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FirstMatchMapper.java45
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FlatFileNameMapper.java54
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/GlobPatternMapper.java203
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/IdentityMapper.java52
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/IdentityStack.java130
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/JAXPUtils.java260
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/JavaEnvUtils.java573
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/KeepAliveInputStream.java66
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/KeepAliveOutputStream.java83
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LayoutPreservingProperties.java775
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LazyFileOutputStream.java162
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LazyHashtable.java120
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java161
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineOrientedOutputStream.java158
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineOrientedOutputStreamRedirector.java68
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineTokenizer.java115
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LinkedHashtable.java132
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LoaderUtils.java140
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/MergingMapper.java67
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/OutputStreamFunneler.java176
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/PackageNameMapper.java49
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ProcessUtil.java65
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/PropertyOutputStream.java69
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ProxySetup.java115
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReaderInputStream.java205
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReflectUtil.java212
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReflectWrapper.java99
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/RegexpPatternMapper.java159
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ResourceUtils.java860
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/RetryHandler.java74
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Retryable.java38
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptFixBSFPath.java147
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunner.java27
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java360
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerCreator.java133
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java206
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SourceFileScanner.java173
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SplitClassLoader.java73
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/StringTokenizer.java154
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/StringUtils.java273
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java296
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TaskLogger.java79
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TeeOutputStream.java95
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TimeoutObserver.java37
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Tokenizer.java44
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UUEncoder.java148
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UnPackageNameMapper.java48
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UnicodeUtil.java46
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/VectorSet.java242
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Watchdog.java128
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/WeakishReference.java91
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/WorkerAnt.java172
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/XMLFragment.java155
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/XmlConstants.java65
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java286
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java130
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java144
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java192
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java136
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/facade/FacadeTaskHelper.java165
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/facade/ImplementationSpecificArgument.java61
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/java15/ProxyDiagnostics.java108
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/JavaxScriptRunner.java163
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/NoExitSecurityManager.java51
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java177
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/WeakishReference12.java45
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaOroMatcher.java170
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaOroRegexp.java98
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpMatcher.java161
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpRegexp.java90
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcher.java170
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexp.java105
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Regexp.java50
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpFactory.java85
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpMatcher.java110
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpMatcherFactory.java114
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpUtil.java109
92 files changed, 16145 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Base64Converter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Base64Converter.java
new file mode 100644
index 00000000..5d60a145
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Base64Converter.java
@@ -0,0 +1,124 @@
+/*
+ * 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.util;
+
+/**
+ * BASE 64 encoding of a String or an array of bytes.
+ *
+ * Based on RFC 1421.
+ *
+ **/
+public class Base64Converter {
+
+ private static final int BYTE = 8;
+ private static final int WORD = 16;
+ private static final int BYTE_MASK = 0xFF;
+ private static final int POS_0_MASK = 0x0000003F;
+ private static final int POS_1_MASK = 0x00000FC0;
+ private static final int POS_1_SHIFT = 6;
+ private static final int POS_2_MASK = 0x0003F000;
+ private static final int POS_2_SHIFT = 12;
+ private static final int POS_3_MASK = 0x00FC0000;
+ private static final int POS_3_SHIFT = 18;
+
+
+ private static final char[] ALPHABET = {
+ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', // 0 to 7
+ 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', // 8 to 15
+ 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', // 16 to 23
+ 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', // 24 to 31
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', // 32 to 39
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', // 40 to 47
+ 'w', 'x', 'y', 'z', '0', '1', '2', '3', // 48 to 55
+ '4', '5', '6', '7', '8', '9', '+', '/'}; // 56 to 63
+
+ // CheckStyle:ConstantNameCheck OFF - bc
+ /** Provided for BC purposes */
+ public static final char[] alphabet = ALPHABET;
+ // CheckStyle:ConstantNameCheck ON
+
+
+ /**
+ * Encode a string into base64 encoding.
+ * @param s the string to encode.
+ * @return the encoded string.
+ */
+ public String encode(String s) {
+ return encode(s.getBytes());
+ }
+
+ /**
+ * Encode a byte array into base64 encoding.
+ * @param octetString the byte array to encode.
+ * @return the encoded string.
+ */
+ public String encode(byte[] octetString) {
+ int bits24;
+ int bits6;
+
+ // CheckStyle:MagicNumber OFF
+ char[] out = new char[((octetString.length - 1) / 3 + 1) * 4];
+ // CheckStyle:MagicNumber ON
+ int outIndex = 0;
+ int i = 0;
+
+ // CheckStyle:MagicNumber OFF
+ while ((i + 3) <= octetString.length) {
+ // CheckStyle:MagicNumber ON
+ // store the octets
+ bits24 = (octetString[i++] & BYTE_MASK) << WORD;
+ bits24 |= (octetString[i++] & BYTE_MASK) << BYTE;
+ bits24 |= octetString[i++] & BYTE_MASK;
+
+ bits6 = (bits24 & POS_3_MASK) >> POS_3_SHIFT;
+ out[outIndex++] = ALPHABET[bits6];
+ bits6 = (bits24 & POS_2_MASK) >> POS_2_SHIFT;
+ out[outIndex++] = ALPHABET[bits6];
+ bits6 = (bits24 & POS_1_MASK) >> POS_1_SHIFT;
+ out[outIndex++] = ALPHABET[bits6];
+ bits6 = (bits24 & POS_0_MASK);
+ out[outIndex++] = ALPHABET[bits6];
+ }
+ if (octetString.length - i == 2) {
+ // store the octets
+ bits24 = (octetString[i] & BYTE_MASK) << WORD;
+ bits24 |= (octetString[i + 1] & BYTE_MASK) << BYTE;
+ bits6 = (bits24 & POS_3_MASK) >> POS_3_SHIFT;
+ out[outIndex++] = ALPHABET[bits6];
+ bits6 = (bits24 & POS_2_MASK) >> POS_2_SHIFT;
+ out[outIndex++] = ALPHABET[bits6];
+ bits6 = (bits24 & POS_1_MASK) >> POS_1_SHIFT;
+ out[outIndex++] = ALPHABET[bits6];
+
+ // padding
+ out[outIndex++] = '=';
+ } else if (octetString.length - i == 1) {
+ // store the octets
+ bits24 = (octetString[i] & BYTE_MASK) << WORD;
+ bits6 = (bits24 & POS_3_MASK) >> POS_3_SHIFT;
+ out[outIndex++] = ALPHABET[bits6];
+ bits6 = (bits24 & POS_2_MASK) >> POS_2_SHIFT;
+ out[outIndex++] = ALPHABET[bits6];
+
+ // padding
+ out[outIndex++] = '=';
+ out[outIndex++] = '=';
+ }
+ return new String(out);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ChainedMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ChainedMapper.java
new file mode 100644
index 00000000..635a0538
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ChainedMapper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * A <code>ContainerMapper</code> that chains the results of the first
+ * nested <code>FileNameMapper</code>s into sourcefiles for the second,
+ * the second to the third, and so on, returning the resulting mapped
+ * filenames from the last nested <code>FileNameMapper</code>.
+ */
+public class ChainedMapper extends ContainerMapper {
+
+ /** {@inheritDoc}. */
+ public String[] mapFileName(String sourceFileName) {
+ List inputs = new ArrayList();
+ List results = new ArrayList();
+ results.add(sourceFileName);
+ FileNameMapper mapper = null;
+
+ for (Iterator mIter = getMappers().iterator(); mIter.hasNext();) {
+ mapper = (FileNameMapper) (mIter.next());
+ if (mapper != null) {
+ inputs.clear();
+ inputs.addAll(results);
+ results.clear();
+
+ for (Iterator it = inputs.iterator(); it.hasNext();) {
+ String[] mapped = mapper.mapFileName((String) (it.next()));
+ if (mapped != null) {
+ results.addAll(Arrays.asList(mapped));
+ }
+ }
+ }
+ }
+ return (results.size() == 0) ? null
+ : (String[]) results.toArray(new String[results.size()]);
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java
new file mode 100644
index 00000000..309860e9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ClasspathUtils.java
@@ -0,0 +1,463 @@
+/*
+ * 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.util;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * Offers some helper methods on the Path structure in ant.
+ *
+ * <p>The basic idea behind this utility class is to use it from inside the
+ * different Ant objects (and user defined objects) that need classLoading
+ * for their operation.
+ * Normally those would have a setClasspathRef() {for the @classpathref}
+ * and/or a createClasspath() {for the nested &lt;classpath&gt;}
+ * Typically one would have in your Ant Task or DataType</p>
+ *
+ * <pre><code>
+ * ClasspathUtils.Delegate cpDelegate;
+ *
+ * public void init() {
+ * this.cpDelegate = ClasspathUtils.getDelegate(this);
+ * super.init();
+ * }
+ *
+ * public void setClasspathRef(Reference r) {
+ * this.cpDelegate.setClasspathRef(r);
+ * }
+ *
+ * public Path createClasspath() {
+ * return this.cpDelegate.createClasspath();
+ * }
+ *
+ * public void setClassname(String fqcn) {
+ * this.cpDelegate.setClassname(fqcn);
+ * }
+ * </code></pre>
+ *
+ * <p>At execution time, when you actually need the classloading
+ * you can just:</p>
+ *
+ * <pre><code>
+ * Object o = this.cpDelegate.newInstance();
+ * </code></pre>
+ *
+ * @since Ant 1.6
+ */
+public class ClasspathUtils {
+
+ /**
+ * Name of the magic property that controls classloader reuse in Ant 1.4.
+ */
+ public static final String REUSE_LOADER_REF = MagicNames.REFID_CLASSPATH_REUSE_LOADER;
+
+ /**
+ * Convenience overloaded version of {@link
+ * #getClassLoaderForPath(Project, Reference, boolean)}.
+ *
+ * <p>Assumes the logical 'false' for the reverseLoader.</p>
+ *
+ * @param p the project
+ * @param ref the reference
+ * @return The class loader
+ */
+ public static ClassLoader getClassLoaderForPath(Project p, Reference ref) {
+ return getClassLoaderForPath(p, ref, false);
+ }
+
+ /**
+ * Convenience overloaded version of {@link #getClassLoaderForPath(Project, Path,
+ * String, boolean)}.
+ *
+ * <p>Delegates to the other one after extracting the referenced
+ * Path from the Project. This checks also that the passed
+ * Reference is pointing to a Path all right.</p>
+ * @param p current Ant project
+ * @param ref Reference to Path structure
+ * @param reverseLoader if set to true this new loader will take
+ * precedence over its parent (which is contra the regular
+ * classloader behaviour)
+ * @return The class loader
+ */
+ public static ClassLoader getClassLoaderForPath(
+ Project p, Reference ref, boolean reverseLoader) {
+ String pathId = ref.getRefId();
+ Object path = p.getReference(pathId);
+ if (!(path instanceof Path)) {
+ throw new BuildException("The specified classpathref " + pathId
+ + " does not reference a Path.");
+ }
+ String loaderId = MagicNames.REFID_CLASSPATH_LOADER_PREFIX + pathId;
+ return getClassLoaderForPath(p, (Path) path, loaderId, reverseLoader);
+ }
+
+ /**
+ * Convenience overloaded version of {@link
+ * #getClassLoaderForPath(Project, Path, String, boolean)}.
+ *
+ * <p>Assumes the logical 'false' for the reverseLoader.</p>
+ *
+ * @param p current Ant project
+ * @param path the path
+ * @param loaderId the loader id string
+ * @return The class loader
+ */
+ public static ClassLoader getClassLoaderForPath(Project p, Path path, String loaderId) {
+ return getClassLoaderForPath(p, path, loaderId, false);
+ }
+
+ /**
+ * Convenience overloaded version of {@link
+ * #getClassLoaderForPath(Project, Path, String, boolean, boolean)}.
+ *
+ * <p>Sets value for 'reuseLoader' to true if the magic property
+ * has been set.</p>
+ *
+ * @param p the project
+ * @param path the path
+ * @param loaderId the loader id string
+ * @param reverseLoader if set to true this new loader will take
+ * precedence over its parent (which is contra the regular
+ * classloader behaviour)
+ * @return The class loader
+ */
+ public static ClassLoader getClassLoaderForPath(
+ Project p, Path path, String loaderId, boolean reverseLoader) {
+ return getClassLoaderForPath(p, path, loaderId, reverseLoader, isMagicPropertySet(p));
+ }
+
+ /**
+ * Gets a classloader that loads classes from the classpath
+ * defined in the path argument.
+ *
+ * <p>Based on the setting of the magic property
+ * 'ant.reuse.loader' this will try to reuse the previously
+ * created loader with that id, and of course store it there upon
+ * creation.</p>
+ * @param p Ant Project where the handled components are living in.
+ * @param path Path object to be used as classpath for this classloader
+ * @param loaderId identification for this Loader,
+ * @param reverseLoader if set to true this new loader will take
+ * precedence over its parent (which is contra the regular
+ * classloader behaviour)
+ * @param reuseLoader if true reuse the loader if it is found
+ * @return ClassLoader that uses the Path as its classpath.
+ */
+ public static ClassLoader getClassLoaderForPath(
+ Project p, Path path, String loaderId, boolean reverseLoader, boolean reuseLoader) {
+ ClassLoader cl = null;
+
+ // magic property
+ if (loaderId != null && reuseLoader) {
+ Object reusedLoader = p.getReference(loaderId);
+ if (reusedLoader != null && !(reusedLoader instanceof ClassLoader)) {
+ throw new BuildException("The specified loader id " + loaderId
+ + " does not reference a class loader");
+ }
+ cl = (ClassLoader) reusedLoader;
+ }
+ if (cl == null) {
+ cl = getUniqueClassLoaderForPath(p, path, reverseLoader);
+ if (loaderId != null && reuseLoader) {
+ p.addReference(loaderId, cl);
+ }
+ }
+ return cl;
+ }
+
+ /**
+ * Gets a fresh, different, previously unused classloader that uses the
+ * passed path as its classpath.
+ *
+ * <p>This method completely ignores the ant.reuse.loader magic
+ * property and should be used with caution.</p>
+ * @param p Ant Project where the handled components are living in.
+ * @param path the classpath for this loader
+ * @param reverseLoader if set to true this new loader will take
+ * precedence over its parent (which is contra the regular
+ * classloader behaviour)
+ * @return The fresh, different, previously unused class loader.
+ */
+ public static ClassLoader getUniqueClassLoaderForPath(Project p, Path path,
+ boolean reverseLoader) {
+ AntClassLoader acl = p.createClassLoader(path);
+ if (reverseLoader) {
+ acl.setParentFirst(false);
+ acl.addJavaLibraries();
+ }
+ return acl;
+ }
+
+ /**
+ * Creates a fresh object instance of the specified classname.
+ *
+ * <p> This uses the userDefinedLoader to load the specified class,
+ * and then makes an instance using the default no-argument constructor.
+ * </p>
+ *
+ * @param className the full qualified class name to load.
+ * @param userDefinedLoader the classloader to use.
+ * @return The fresh object instance
+ * @throws BuildException when loading or instantiation failed.
+ */
+ public static Object newInstance(String className, ClassLoader userDefinedLoader) {
+ return newInstance(className, userDefinedLoader, Object.class);
+ }
+
+ /**
+ * Creates a fresh object instance of the specified classname.
+ *
+ * <p> This uses the userDefinedLoader to load the specified class,
+ * and then makes an instance using the default no-argument constructor.
+ * </p>
+ *
+ * @param className the full qualified class name to load.
+ * @param userDefinedLoader the classloader to use.
+ * @param expectedType the Class that the result should be assignment
+ * compatible with. (No ClassCastException will be thrown in case
+ * the result of this method is casted to the expectedType)
+ * @return The fresh object instance
+ * @throws BuildException when loading or instantiation failed.
+ * @since Ant 1.7
+ */
+ public static Object newInstance(String className, ClassLoader userDefinedLoader,
+ Class expectedType) {
+ try {
+ Class clazz = Class.forName(className, true, userDefinedLoader);
+ Object o = clazz.newInstance();
+ if (!expectedType.isInstance(o)) {
+ throw new BuildException("Class of unexpected Type: " + className + " expected :"
+ + expectedType);
+ }
+ return o;
+ } catch (ClassNotFoundException e) {
+ throw new BuildException("Class not found: " + className, e);
+ } catch (InstantiationException e) {
+ throw new BuildException("Could not instantiate " + className
+ + ". Specified class should have a no " + "argument constructor.", e);
+ } catch (IllegalAccessException e) {
+ throw new BuildException("Could not instantiate " + className
+ + ". Specified class should have a " + "public constructor.", e);
+ } catch (LinkageError e) {
+ throw new BuildException("Class " + className
+ + " could not be loaded because of an invalid dependency.", e);
+ }
+ }
+
+ /**
+ * Obtains a delegate that helps out with classic classpath configuration.
+ *
+ * @param component your projectComponent that needs the assistence
+ * @return the helper, delegate.
+ * @see ClasspathUtils.Delegate
+ */
+ public static Delegate getDelegate(ProjectComponent component) {
+ return new Delegate(component);
+ }
+
+ /**
+ * Checks for the magic property that enables class loader reuse
+ * for <taskdef> and <typedef> in Ant 1.5 and earlier.
+ */
+ private static boolean isMagicPropertySet(Project p) {
+ return p.getProperty(REUSE_LOADER_REF) != null;
+ }
+
+ /**
+ * Delegate that helps out any specific ProjectComponent that needs
+ * dynamic classloading.
+ *
+ * <p>Ant ProjectComponents that need a to be able to dynamically load
+ * Classes and instantiate them often expose the following ant syntax
+ * sugar: </p>
+ *
+ * <ul><li> nested &lt;classpath&gt; </li>
+ * <li> attribute @classpathref </li>
+ * <li> attribute @classname </li></ul>
+ *
+ * <p> This class functions as a delegate handling the configuration
+ * issues for this recurring pattern. Its usage pattern, as the name
+ * suggests, is delegation rather than inheritance. </p>
+ *
+ * @since Ant 1.6
+ */
+ public static class Delegate {
+ private final ProjectComponent component;
+ private Path classpath;
+ private String classpathId;
+ private String className;
+ private String loaderId;
+ private boolean reverseLoader = false;
+
+ /**
+ * Construct a Delegate
+ * @param component the ProjectComponent this delegate is for.
+ */
+ Delegate(ProjectComponent component) {
+ this.component = component;
+ }
+
+ /**
+ * This method is a Delegate method handling the @classpath attribute.
+ *
+ * <p>This attribute can set a path to add to the classpath.</p>
+ *
+ * @param classpath the path to use for the classpath.
+ */
+ public void setClasspath(Path classpath) {
+ if (this.classpath == null) {
+ this.classpath = classpath;
+ } else {
+ this.classpath.append(classpath);
+ }
+ }
+
+ /**
+ * Delegate method handling the &lt;classpath&gt; tag.
+ *
+ * <p>This nested path-like structure can set a path to add to the
+ * classpath.</p>
+ *
+ * @return the created path.
+ */
+ public Path createClasspath() {
+ if (this.classpath == null) {
+ this.classpath = new Path(component.getProject());
+ }
+ return this.classpath.createPath();
+ }
+
+ /**
+ * Delegate method handling the @classname attribute.
+ *
+ * <p>This attribute sets the full qualified class name of the class
+ * to load and instantiate.</p>
+ *
+ * @param fcqn the name of the class to load.
+ */
+ public void setClassname(String fcqn) {
+ this.className = fcqn;
+ }
+
+ /**
+ * Delegate method handling the @classpathref attribute.
+ *
+ * <p>This attribute can add a referenced path-like structure to the
+ * classpath.</p>
+ *
+ * @param r the reference to the classpath.
+ */
+ public void setClasspathref(Reference r) {
+ this.classpathId = r.getRefId();
+ createClasspath().setRefid(r);
+ }
+
+ /**
+ * Delegate method handling the @reverseLoader attribute.
+ *
+ * <p>This attribute can set a boolean indicating that the used
+ * classloader should NOT follow the classical parent-first scheme.
+ * </p>
+ *
+ * <p>By default this is supposed to be false.</p>
+ *
+ * <p>Caution: this behaviour is contradictory to the normal way
+ * classloaders work. Do not let your ProjectComponent use it if
+ * you are not really sure.</p>
+ *
+ * @param reverseLoader if true reverse the order of looking up a class.
+ */
+ public void setReverseLoader(boolean reverseLoader) {
+ this.reverseLoader = reverseLoader;
+ }
+
+ /**
+ * Sets the loaderRef.
+ * @param r the reference to the loader.
+ */
+ public void setLoaderRef(Reference r) {
+ this.loaderId = r.getRefId();
+ }
+
+
+ /**
+ * Finds or creates the classloader for this object.
+ * @return The class loader.
+ */
+ public ClassLoader getClassLoader() {
+ return getClassLoaderForPath(getContextProject(), classpath, getClassLoadId(),
+ reverseLoader, loaderId != null || isMagicPropertySet(getContextProject()));
+ }
+
+ /**
+ * The project of the ProjectComponent we are working for.
+ */
+ private Project getContextProject() {
+ return component.getProject();
+ }
+
+ /**
+ * Computes the loaderId based on the configuration of the component.
+ * @return a loader identifier.
+ */
+ public String getClassLoadId() {
+ if (loaderId == null && classpathId != null) {
+ return MagicNames.REFID_CLASSPATH_LOADER_PREFIX + classpathId;
+ } else {
+ return loaderId;
+ }
+ }
+
+ /**
+ * Helper method obtaining a fresh instance of the class specified
+ * in the @classname and using the specified classpath.
+ *
+ * @return the fresh instantiated object.
+ */
+ public Object newInstance() {
+ return ClasspathUtils.newInstance(this.className, getClassLoader());
+ }
+
+ /**
+ * The classpath.
+ * @return the classpath.
+ */
+ public Path getClasspath() {
+ return classpath;
+ }
+
+ /**
+ * Get the reverseLoader setting.
+ * @return true if looking up in reverse order.
+ */
+ public boolean isReverseLoader() {
+ return reverseLoader;
+ }
+
+ //TODO no methods yet for getClassname
+ //TODO no method for newInstance using a reverse-classloader
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/CollectionUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/CollectionUtils.java
new file mode 100644
index 00000000..03c48d93
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/CollectionUtils.java
@@ -0,0 +1,278 @@
+/*
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Vector;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * A set of helper methods related to collection manipulation.
+ *
+ * @since Ant 1.5
+ */
+public class CollectionUtils {
+
+ /**
+ * Collections.emptyList() is Java5+.
+ */
+ @SuppressWarnings("rawtypes")
+ @Deprecated
+ public static final List EMPTY_LIST = Collections.EMPTY_LIST;
+
+ /**
+ * Please use Vector.equals() or List.equals().
+ * @param v1 the first vector.
+ * @param v2 the second vector.
+ * @return true if the vectors are equal.
+ * @since Ant 1.5
+ * @deprecated since 1.6.x.
+ */
+ public static boolean equals(Vector<?> v1, Vector<?> v2) {
+ if (v1 == v2) {
+ return true;
+ }
+
+ if (v1 == null || v2 == null) {
+ return false;
+ }
+
+ return v1.equals(v2);
+ }
+
+ /**
+ * Dictionary does not have an equals.
+ * Please use Map.equals().
+ *
+ * <p>Follows the equals contract of Java 2's Map.</p>
+ * @param d1 the first directory.
+ * @param d2 the second directory.
+ * @return true if the directories are equal.
+ * @since Ant 1.5
+ * @deprecated since 1.6.x.
+ */
+ public static boolean equals(Dictionary<?, ?> d1, Dictionary<?, ?> d2) {
+ if (d1 == d2) {
+ return true;
+ }
+
+ if (d1 == null || d2 == null) {
+ return false;
+ }
+
+ if (d1.size() != d2.size()) {
+ return false;
+ }
+
+ Enumeration<?> e1 = d1.keys();
+ while (e1.hasMoreElements()) {
+ Object key = e1.nextElement();
+ Object value1 = d1.get(key);
+ Object value2 = d2.get(key);
+ if (value2 == null || !value1.equals(value2)) {
+ return false;
+ }
+ }
+
+ // don't need the opposite check as the Dictionaries have the
+ // same size, so we've also covered all keys of d2 already.
+
+ return true;
+ }
+
+ /**
+ * Creates a comma separated list of all values held in the given
+ * collection.
+ *
+ * @param c collection to transform
+ * @return string representation of the collection
+ * @since Ant 1.8.0
+ */
+ public static String flattenToString(Collection<?> c) {
+ final StringBuilder sb = new StringBuilder();
+ for (Object o : c) {
+ if (sb.length() != 0) {
+ sb.append(",");
+ }
+ sb.append(o);
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Dictionary does not know the putAll method. Please use Map.putAll().
+ * @param m1 the to directory.
+ * @param m2 the from directory.
+ * @param <K> type of the key
+ * @param <V> type of the value
+ * @since Ant 1.6
+ * @deprecated since 1.6.x.
+ */
+ public static <K, V> void putAll(Dictionary<? super K, ? super V> m1, Dictionary<? extends K, ? extends V> m2) {
+ for (Enumeration<? extends K> it = m2.keys(); it.hasMoreElements();) {
+ K key = it.nextElement();
+ m1.put(key, m2.get(key));
+ }
+ }
+
+ /**
+ * An empty enumeration.
+ * @since Ant 1.6
+ */
+ public static final class EmptyEnumeration<E> implements Enumeration<E> {
+ /** Constructor for the EmptyEnumeration */
+ public EmptyEnumeration() {
+ }
+
+ /**
+ * @return false always.
+ */
+ public boolean hasMoreElements() {
+ return false;
+ }
+
+ /**
+ * @return nothing.
+ * @throws NoSuchElementException always.
+ */
+ public E nextElement() throws NoSuchElementException {
+ throw new NoSuchElementException();
+ }
+ }
+
+ /**
+ * Append one enumeration to another.
+ * Elements are evaluated lazily.
+ * @param e1 the first enumeration.
+ * @param e2 the subsequent enumeration.
+ * @param <E> element type
+ * @return an enumeration representing e1 followed by e2.
+ * @since Ant 1.6.3
+ */
+ public static <E> Enumeration<E> append(Enumeration<E> e1, Enumeration<E> e2) {
+ return new CompoundEnumeration<E>(e1, e2);
+ }
+
+ /**
+ * Adapt the specified Iterator to the Enumeration interface.
+ * @param iter the Iterator to adapt.
+ * @param <E> element type
+ * @return an Enumeration.
+ */
+ public static <E> Enumeration<E> asEnumeration(final Iterator<E> iter) {
+ return new Enumeration<E>() {
+ public boolean hasMoreElements() {
+ return iter.hasNext();
+ }
+ public E nextElement() {
+ return iter.next();
+ }
+ };
+ }
+
+ /**
+ * Adapt the specified Enumeration to the Iterator interface.
+ * @param e the Enumeration to adapt.
+ * @param <E> element type
+ * @return an Iterator.
+ */
+ public static <E> Iterator<E> asIterator(final Enumeration<E> e) {
+ return new Iterator<E>() {
+ public boolean hasNext() {
+ return e.hasMoreElements();
+ }
+ public E next() {
+ return e.nextElement();
+ }
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ /**
+ * Returns a collection containing all elements of the iterator.
+ *
+ * @param iter the Iterator to convert
+ * @param <T> element type
+ * @return the collection
+ * @since Ant 1.8.0
+ */
+ public static <T> Collection<T> asCollection(final Iterator<? extends T> iter) {
+ List<T> l = new ArrayList<T>();
+ while (iter.hasNext()) {
+ l.add(iter.next());
+ }
+ return l;
+ }
+
+ private static final class CompoundEnumeration<E> implements Enumeration<E> {
+
+ private final Enumeration<E> e1, e2;
+
+ public CompoundEnumeration(Enumeration<E> e1, Enumeration<E> e2) {
+ this.e1 = e1;
+ this.e2 = e2;
+ }
+
+ public boolean hasMoreElements() {
+ return e1.hasMoreElements() || e2.hasMoreElements();
+ }
+
+ public E nextElement() throws NoSuchElementException {
+ if (e1.hasMoreElements()) {
+ return e1.nextElement();
+ } else {
+ return e2.nextElement();
+ }
+ }
+
+ }
+
+ /**
+ * Counts how often the given Object occurs in the given
+ * collection using equals() for comparison.
+ *
+ * @param c collection in which to search
+ * @param o object to search
+ * @return frequency
+ * @since Ant 1.8.0
+ */
+ public static int frequency(Collection<?> c, Object o) {
+ // same as Collections.frequency introduced with JDK 1.5
+ int freq = 0;
+ if (c != null) {
+ for (Iterator<?> i = c.iterator(); i.hasNext();) {
+ Object test = i.next();
+ if (o == null ? test == null : o.equals(test)) {
+ freq++;
+ }
+ }
+ }
+ return freq;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/CompositeMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/CompositeMapper.java
new file mode 100644
index 00000000..d04a5fc9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/CompositeMapper.java
@@ -0,0 +1,50 @@
+/*
+ * 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.util;
+
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+
+/**
+ * A <code>ContainerMapper</code> that unites the results of its constituent
+ * <code>FileNameMapper</code>s into a single set of result filenames.
+ */
+public class CompositeMapper extends ContainerMapper {
+
+ /** {@inheritDoc}. */
+ public String[] mapFileName(String sourceFileName) {
+ LinkedHashSet results = new LinkedHashSet();
+
+ FileNameMapper mapper = null;
+ for (Iterator mIter = getMappers().iterator(); mIter.hasNext();) {
+ mapper = (FileNameMapper) (mIter.next());
+ if (mapper != null) {
+ String[] mapped = mapper.mapFileName(sourceFileName);
+ if (mapped != null) {
+ for (int i = 0; i < mapped.length; i++) {
+ results.add(mapped[i]);
+ }
+ }
+ }
+ }
+ return (results.size() == 0) ? null
+ : (String[]) results.toArray(new String[results.size()]);
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ConcatFileInputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ConcatFileInputStream.java
new file mode 100644
index 00000000..22dcb7fb
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ConcatFileInputStream.java
@@ -0,0 +1,136 @@
+/*
+ * 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.util;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Task;
+
+/**
+ * Special <code>InputStream</code> that will
+ * concatenate the contents of an array of files.
+ */
+public class ConcatFileInputStream extends InputStream {
+
+ private static final int EOF = -1;
+ private int currentIndex = -1;
+ private boolean eof = false;
+ private File[] file;
+ private InputStream currentStream;
+ private ProjectComponent managingPc;
+
+ /**
+ * Construct a new <code>ConcatFileInputStream</code>
+ * with the specified <code>File[]</code>.
+ * @param file <code>File[]</code>.
+ * @throws IOException if I/O errors occur.
+ */
+ public ConcatFileInputStream(File[] file) throws IOException {
+ this.file = file;
+ }
+
+ /**
+ * Close the stream.
+ * @throws IOException if there is an error.
+ */
+ public void close() throws IOException {
+ closeCurrent();
+ eof = true;
+ }
+
+ /**
+ * Read a byte.
+ * @return the byte (0 - 255) or -1 if this is the end of the stream.
+ * @throws IOException if there is an error.
+ */
+ public int read() throws IOException {
+ int result = readCurrent();
+ if (result == EOF && !eof) {
+ openFile(++currentIndex);
+ result = readCurrent();
+ }
+ return result;
+ }
+
+ /**
+ * Set a managing <code>Task</code> for
+ * this <code>ConcatFileInputStream</code>.
+ * @param task the managing <code>Task</code>.
+ */
+ public void setManagingTask(Task task) {
+ setManagingComponent(task);
+ }
+
+ /**
+ * Set a managing <code>Task</code> for
+ * this <code>ConcatFileInputStream</code>.
+ * @param pc the managing <code>Task</code>.
+ */
+ public void setManagingComponent(ProjectComponent pc) {
+ this.managingPc = pc;
+ }
+
+ /**
+ * Log a message with the specified logging level.
+ * @param message the <code>String</code> message.
+ * @param loglevel the <code>int</code> logging level.
+ */
+ public void log(String message, int loglevel) {
+ if (managingPc != null) {
+ managingPc.log(message, loglevel);
+ } else {
+ if (loglevel > Project.MSG_WARN) {
+ System.out.println(message);
+ } else {
+ System.err.println(message);
+ }
+ }
+ }
+
+ private int readCurrent() throws IOException {
+ return (eof || currentStream == null) ? EOF : currentStream.read();
+ }
+
+ private void openFile(int index) throws IOException {
+ closeCurrent();
+ if (file != null && index < file.length) {
+ log("Opening " + file[index], Project.MSG_VERBOSE);
+ try {
+ currentStream = new BufferedInputStream(
+ new FileInputStream(file[index]));
+ } catch (IOException eyeOhEx) {
+ log("Failed to open " + file[index], Project.MSG_ERR);
+ throw eyeOhEx;
+ }
+ } else {
+ eof = true;
+ }
+ }
+
+ private void closeCurrent() {
+ FileUtils.close(currentStream);
+ currentStream = null;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java
new file mode 100644
index 00000000..7bae58e5
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ConcatResourceInputStream.java
@@ -0,0 +1,147 @@
+/*
+ * 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.util;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * Special <code>InputStream</code> that will
+ * concatenate the contents of Resources from a single ResourceCollection.
+ * @since Ant 1.7
+ */
+public class ConcatResourceInputStream extends InputStream {
+
+ private static final int EOF = -1;
+ private boolean eof = false;
+ private Iterator<Resource> iter;
+ private InputStream currentStream;
+ private ProjectComponent managingPc;
+ private boolean ignoreErrors = false;
+
+ /**
+ * Construct a new ConcatResourceInputStream
+ * for the specified ResourceCollection.
+ * @param rc the ResourceCollection to combine.
+ */
+ public ConcatResourceInputStream(ResourceCollection rc) {
+ iter = rc.iterator();
+ }
+
+ /**
+ * Set whether this ConcatResourceInputStream ignores errors.
+ * @param b whether to ignore errors.
+ */
+ public void setIgnoreErrors(boolean b) {
+ ignoreErrors = b;
+ }
+
+ /**
+ * Find out whether this ConcatResourceInputStream ignores errors.
+ * @return boolean ignore-errors flag.
+ */
+ public boolean isIgnoreErrors() {
+ return ignoreErrors;
+ }
+
+ /**
+ * Close the stream.
+ * @throws IOException if there is an error.
+ */
+ public void close() throws IOException {
+ closeCurrent();
+ eof = true;
+ }
+
+ /**
+ * Read a byte.
+ * @return the byte (0 - 255) or -1 if this is the end of the stream.
+ * @throws IOException if there is an error.
+ */
+ public int read() throws IOException {
+ if (eof) {
+ return EOF;
+ }
+ int result = readCurrent();
+ if (result == EOF) {
+ nextResource();
+ result = readCurrent();
+ }
+ return result;
+ }
+
+ /**
+ * Set a managing <code>ProjectComponent</code> for
+ * this <code>ConcatResourceInputStream</code>.
+ * @param pc the managing <code>ProjectComponent</code>.
+ */
+ public void setManagingComponent(ProjectComponent pc) {
+ this.managingPc = pc;
+ }
+
+ /**
+ * Log a message with the specified logging level.
+ * @param message the <code>String</code> message.
+ * @param loglevel the <code>int</code> logging level.
+ */
+ public void log(String message, int loglevel) {
+ if (managingPc != null) {
+ managingPc.log(message, loglevel);
+ } else {
+ (loglevel > Project.MSG_WARN ? System.out : System.err).println(message);
+ }
+ }
+
+ private int readCurrent() throws IOException {
+ return eof || currentStream == null ? EOF : currentStream.read();
+ }
+
+ private void nextResource() throws IOException {
+ closeCurrent();
+ while (iter.hasNext()) {
+ Resource r = (Resource) iter.next();
+ if (!r.isExists()) {
+ continue;
+ }
+ log("Concating " + r.toLongString(), Project.MSG_VERBOSE);
+ try {
+ currentStream = new BufferedInputStream(r.getInputStream());
+ return;
+ } catch (IOException eyeOhEx) {
+ if (!ignoreErrors) {
+ log("Failed to get input stream for " + r, Project.MSG_ERR);
+ throw eyeOhEx;
+ }
+ }
+ }
+ eof = true;
+ }
+
+ private void closeCurrent() {
+ FileUtils.close(currentStream);
+ currentStream = null;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ContainerMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ContainerMapper.java
new file mode 100644
index 00000000..990ee148
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ContainerMapper.java
@@ -0,0 +1,119 @@
+/*
+ * 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.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tools.ant.types.Mapper;
+
+/**
+ * A <code>FileNameMapper</code> that contains
+ * other <code>FileNameMapper</code>s.
+ * @see FileNameMapper
+ */
+public abstract class ContainerMapper implements FileNameMapper {
+
+ private List mappers = new ArrayList();
+
+ /**
+ * Add a <code>Mapper</code>.
+ * @param mapper the <code>Mapper</code> to add.
+ */
+ public void addConfiguredMapper(Mapper mapper) {
+ add(mapper.getImplementation());
+ }
+
+ /**
+ * An add configured version of the add method.
+ * This class used to contain an add method and an
+ * addConfiguredMapper method. Dur to ordering,
+ * the add method was always called first. This
+ * addConfigured method has been added to allow
+ * chaining to work correctly.
+ * @param fileNameMapper a <code>FileNameMapper</code>.
+ */
+ public void addConfigured(FileNameMapper fileNameMapper) {
+ add(fileNameMapper);
+ }
+
+ /**
+ * Add a <code>FileNameMapper</code>.
+ * @param fileNameMapper a <code>FileNameMapper</code>.
+ * @throws IllegalArgumentException if attempting to add this
+ * <code>ContainerMapper</code> to itself, or if the specified
+ * <code>FileNameMapper</code> is itself a <code>ContainerMapper</code>
+ * that contains this <code>ContainerMapper</code>.
+ */
+ public synchronized void add(FileNameMapper fileNameMapper) {
+ if (this == fileNameMapper
+ || (fileNameMapper instanceof ContainerMapper
+ && ((ContainerMapper) fileNameMapper).contains(this))) {
+ throw new IllegalArgumentException(
+ "Circular mapper containment condition detected");
+ } else {
+ mappers.add(fileNameMapper);
+ }
+ }
+
+ /**
+ * Return <code>true</code> if this <code>ContainerMapper</code> or any of
+ * its sub-elements contains the specified <code>FileNameMapper</code>.
+ * @param fileNameMapper the <code>FileNameMapper</code> to search for.
+ * @return <code>boolean</code>.
+ */
+ protected synchronized boolean contains(FileNameMapper fileNameMapper) {
+ boolean foundit = false;
+ for (Iterator iter = mappers.iterator(); iter.hasNext() && !foundit;) {
+ FileNameMapper next = (FileNameMapper) (iter.next());
+ foundit = (next == fileNameMapper
+ || (next instanceof ContainerMapper
+ && ((ContainerMapper) next).contains(fileNameMapper)));
+ }
+ return foundit;
+ }
+
+ /**
+ * Get the <code>List</code> of <code>FileNameMapper</code>s.
+ * @return <code>List</code>.
+ */
+ public synchronized List getMappers() {
+ return Collections.unmodifiableList(mappers);
+ }
+
+ /**
+ * Empty implementation.
+ * @param ignore ignored.
+ */
+ public void setFrom(String ignore) {
+ //Empty
+ }
+
+ /**
+ * Empty implementation.
+ * @param ignore ignored.
+ */
+ public void setTo(String ignore) {
+ //Empty
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DOMElementWriter.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DOMElementWriter.java
new file mode 100644
index 00000000..14cbaee2
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DOMElementWriter.java
@@ -0,0 +1,640 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.w3c.dom.Text;
+
+/**
+ * Writes a DOM tree to a given Writer.
+ * warning: this utility currently does not declare XML Namespaces.
+ * <p>Utility class used by {@link org.apache.tools.ant.XmlLogger
+ * XmlLogger} and
+ * org.apache.tools.ant.taskdefs.optional.junit.XMLJUnitResultFormatter
+ * XMLJUnitResultFormatter}.</p>
+ *
+ */
+public class DOMElementWriter {
+
+ private static final int HEX = 16;
+
+ private static final String[] WS_ENTITIES = new String['\r' - '\t' + 1];
+ static {
+ for (int i = '\t'; i < '\r' + 1; i++) {
+ WS_ENTITIES[i - '\t'] = "&#x" + Integer.toHexString(i) + ";";
+ }
+ }
+
+ /** prefix for generated prefixes */
+ private static final String NS = "ns";
+
+ /** xml declaration is on by default */
+ private boolean xmlDeclaration = true;
+
+ /**
+ * XML Namespaces are ignored by default.
+ */
+ private XmlNamespacePolicy namespacePolicy = XmlNamespacePolicy.IGNORE;
+
+ /**
+ * Map (URI to prefix) of known namespaces.
+ */
+ private HashMap nsPrefixMap = new HashMap();
+
+ /**
+ * Number of generated prefix to use next.
+ */
+ private int nextPrefix = 0;
+
+ /**
+ * Map (Element to URI) of namespaces defined on a given element.
+ */
+ private HashMap nsURIByElement = new HashMap();
+
+ /**
+ * Whether namespaces should be ignored for elements and attributes.
+ *
+ * @since Ant 1.7
+ */
+ public static class XmlNamespacePolicy {
+ private boolean qualifyElements;
+ private boolean qualifyAttributes;
+
+ /**
+ * Ignores namespaces for elements and attributes, the default.
+ */
+ public static final XmlNamespacePolicy IGNORE =
+ new XmlNamespacePolicy(false, false);
+
+ /**
+ * Ignores namespaces for attributes.
+ */
+ public static final XmlNamespacePolicy ONLY_QUALIFY_ELEMENTS =
+ new XmlNamespacePolicy(true, false);
+
+ /**
+ * Qualifies namespaces for elements and attributes.
+ */
+ public static final XmlNamespacePolicy QUALIFY_ALL =
+ new XmlNamespacePolicy(true, true);
+
+ /**
+ * @param qualifyElements whether to qualify elements
+ * @param qualifyAttributes whether to qualify elements
+ */
+ public XmlNamespacePolicy(boolean qualifyElements,
+ boolean qualifyAttributes) {
+ this.qualifyElements = qualifyElements;
+ this.qualifyAttributes = qualifyAttributes;
+ }
+ }
+
+ /**
+ * Create an element writer.
+ * The ?xml? declaration will be included, namespaces ignored.
+ */
+ public DOMElementWriter() {
+ }
+
+ /**
+ * Create an element writer
+ * XML namespaces will be ignored.
+ * @param xmlDeclaration flag to indicate whether the ?xml? declaration
+ * should be included.
+ * @since Ant1.7
+ */
+ public DOMElementWriter(boolean xmlDeclaration) {
+ this(xmlDeclaration, XmlNamespacePolicy.IGNORE);
+ }
+
+ /**
+ * Create an element writer
+ * XML namespaces will be ignored.
+ * @param xmlDeclaration flag to indicate whether the ?xml? declaration
+ * should be included.
+ * @param namespacePolicy the policy to use.
+ * @since Ant1.7
+ */
+ public DOMElementWriter(boolean xmlDeclaration,
+ XmlNamespacePolicy namespacePolicy) {
+ this.xmlDeclaration = xmlDeclaration;
+ this.namespacePolicy = namespacePolicy;
+ }
+
+ private static String lSep = System.getProperty("line.separator");
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ /**
+ * Don't try to be too smart but at least recognize the predefined
+ * entities.
+ */
+ protected String[] knownEntities = {"gt", "amp", "lt", "apos", "quot"};
+ // CheckStyle:VisibilityModifier ON
+
+
+ /**
+ * Writes a DOM tree to a stream in UTF8 encoding. Note that
+ * it prepends the &lt;?xml version='1.0' encoding='UTF-8'?&gt; if
+ * the xmlDeclaration field is true.
+ * The indent number is set to 0 and a 2-space indent.
+ * @param root the root element of the DOM tree.
+ * @param out the outputstream to write to.
+ * @throws IOException if an error happens while writing to the stream.
+ */
+ public void write(Element root, OutputStream out) throws IOException {
+ Writer wri = new OutputStreamWriter(out, "UTF8");
+ writeXMLDeclaration(wri);
+ write(root, wri, 0, " ");
+ wri.flush();
+ }
+
+ /**
+ * Writes the XML declaration if xmlDeclaration is true.
+ * @param wri the writer to write to.
+ * @throws IOException if there is an error.
+ * @since Ant 1.7.0
+ */
+ public void writeXMLDeclaration(Writer wri) throws IOException {
+ if (xmlDeclaration) {
+ wri.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+ }
+ }
+
+ /**
+ * Writes a DOM tree to a stream.
+ *
+ * @param element the Root DOM element of the tree
+ * @param out where to send the output
+ * @param indent number of
+ * @param indentWith string that should be used to indent the
+ * corresponding tag.
+ * @throws IOException if an error happens while writing to the stream.
+ */
+ public void write(Element element, Writer out, int indent,
+ String indentWith)
+ throws IOException {
+
+ // Write child elements and text
+ NodeList children = element.getChildNodes();
+ boolean hasChildren = (children.getLength() > 0);
+ boolean hasChildElements = false;
+ openElement(element, out, indent, indentWith, hasChildren);
+
+ if (hasChildren) {
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+
+ switch (child.getNodeType()) {
+
+ case Node.ELEMENT_NODE:
+ hasChildElements = true;
+ if (i == 0) {
+ out.write(lSep);
+ }
+ write((Element) child, out, indent + 1, indentWith);
+ break;
+
+ case Node.TEXT_NODE:
+ out.write(encode(child.getNodeValue()));
+ break;
+
+ case Node.COMMENT_NODE:
+ out.write("<!--");
+ out.write(encode(child.getNodeValue()));
+ out.write("-->");
+ break;
+
+ case Node.CDATA_SECTION_NODE:
+ out.write("<![CDATA[");
+ encodedata(out, ((Text) child).getData());
+ out.write("]]>");
+ break;
+
+ case Node.ENTITY_REFERENCE_NODE:
+ out.write('&');
+ out.write(child.getNodeName());
+ out.write(';');
+ break;
+
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ out.write("<?");
+ out.write(child.getNodeName());
+ String data = child.getNodeValue();
+ if (data != null && data.length() > 0) {
+ out.write(' ');
+ out.write(data);
+ }
+ out.write("?>");
+ break;
+ default:
+ // Do nothing
+ }
+ }
+ closeElement(element, out, indent, indentWith, hasChildElements);
+ }
+ }
+
+ /**
+ * Writes the opening tag - including all attributes -
+ * corresponding to a DOM element.
+ *
+ * @param element the DOM element to write
+ * @param out where to send the output
+ * @param indent number of
+ * @param indentWith string that should be used to indent the
+ * corresponding tag.
+ * @throws IOException if an error happens while writing to the stream.
+ */
+ public void openElement(Element element, Writer out, int indent,
+ String indentWith)
+ throws IOException {
+ openElement(element, out, indent, indentWith, true);
+ }
+
+ /**
+ * Writes the opening tag - including all attributes -
+ * corresponding to a DOM element.
+ *
+ * @param element the DOM element to write
+ * @param out where to send the output
+ * @param indent number of
+ * @param indentWith string that should be used to indent the
+ * corresponding tag.
+ * @param hasChildren whether this element has children.
+ * @throws IOException if an error happens while writing to the stream.
+ * @since Ant 1.7
+ */
+ public void openElement(Element element, Writer out, int indent,
+ String indentWith, boolean hasChildren)
+ throws IOException {
+ // Write indent characters
+ for (int i = 0; i < indent; i++) {
+ out.write(indentWith);
+ }
+
+ // Write element
+ out.write("<");
+ if (namespacePolicy.qualifyElements) {
+ String uri = getNamespaceURI(element);
+ String prefix = (String) nsPrefixMap.get(uri);
+ if (prefix == null) {
+ if (nsPrefixMap.isEmpty()) {
+ // steal default namespace
+ prefix = "";
+ } else {
+ prefix = NS + (nextPrefix++);
+ }
+ nsPrefixMap.put(uri, prefix);
+ addNSDefinition(element, uri);
+ }
+ if (!"".equals(prefix)) {
+ out.write(prefix);
+ out.write(":");
+ }
+ }
+ out.write(element.getTagName());
+
+ // Write attributes
+ NamedNodeMap attrs = element.getAttributes();
+ for (int i = 0; i < attrs.getLength(); i++) {
+ Attr attr = (Attr) attrs.item(i);
+ out.write(" ");
+ if (namespacePolicy.qualifyAttributes) {
+ String uri = getNamespaceURI(attr);
+ String prefix = (String) nsPrefixMap.get(uri);
+ if (prefix == null) {
+ prefix = NS + (nextPrefix++);
+ nsPrefixMap.put(uri, prefix);
+ addNSDefinition(element, uri);
+ }
+ out.write(prefix);
+ out.write(":");
+ }
+ out.write(attr.getName());
+ out.write("=\"");
+ out.write(encodeAttributeValue(attr.getValue()));
+ out.write("\"");
+ }
+
+ // write namespace declarations
+ ArrayList al = (ArrayList) nsURIByElement.get(element);
+ if (al != null) {
+ Iterator iter = al.iterator();
+ while (iter.hasNext()) {
+ String uri = (String) iter.next();
+ String prefix = (String) nsPrefixMap.get(uri);
+ out.write(" xmlns");
+ if (!"".equals(prefix)) {
+ out.write(":");
+ out.write(prefix);
+ }
+ out.write("=\"");
+ out.write(uri);
+ out.write("\"");
+ }
+ }
+
+ if (hasChildren) {
+ out.write(">");
+ } else {
+ removeNSDefinitions(element);
+ out.write(" />");
+ out.write(lSep);
+ out.flush();
+ }
+ }
+
+ /**
+ * Writes a DOM tree to a stream.
+ *
+ * @param element the Root DOM element of the tree
+ * @param out where to send the output
+ * @param indent number of
+ * @param indentWith string that should be used to indent the
+ * corresponding tag.
+ * @param hasChildren if true indent.
+ * @throws IOException if an error happens while writing to the stream.
+ */
+ public void closeElement(Element element, Writer out, int indent,
+ String indentWith, boolean hasChildren)
+ throws IOException {
+ // If we had child elements, we need to indent before we close
+ // the element, otherwise we're on the same line and don't need
+ // to indent
+ if (hasChildren) {
+ for (int i = 0; i < indent; i++) {
+ out.write(indentWith);
+ }
+ }
+
+ // Write element close
+ out.write("</");
+ if (namespacePolicy.qualifyElements) {
+ String uri = getNamespaceURI(element);
+ String prefix = (String) nsPrefixMap.get(uri);
+ if (prefix != null && !"".equals(prefix)) {
+ out.write(prefix);
+ out.write(":");
+ }
+ removeNSDefinitions(element);
+ }
+ out.write(element.getTagName());
+ out.write(">");
+ out.write(lSep);
+ out.flush();
+ }
+
+ /**
+ * Escape &lt;, &gt; &amp; &apos;, &quot; as their entities and
+ * drop characters that are illegal in XML documents.
+ * @param value the string to encode.
+ * @return the encoded string.
+ */
+ public String encode(String value) {
+ return encode(value, false);
+ }
+
+ /**
+ * Escape &lt;, &gt; &amp; &apos;, &quot; as their entities, \n,
+ * \r and \t as numeric entities and drop characters that are
+ * illegal in XML documents.
+ * @param value the string to encode.
+ * @return the encoded string.
+ */
+ public String encodeAttributeValue(String value) {
+ return encode(value, true);
+ }
+
+ private String encode(final String value, final boolean encodeWhitespace) {
+ final int len = value.length();
+ final StringBuffer sb = new StringBuffer(len);
+ for (int i = 0; i < len; i++) {
+ final char c = value.charAt(i);
+ switch (c) {
+ case '<':
+ sb.append("&lt;");
+ break;
+ case '>':
+ sb.append("&gt;");
+ break;
+ case '\'':
+ sb.append("&apos;");
+ break;
+ case '\"':
+ sb.append("&quot;");
+ break;
+ case '&':
+ sb.append("&amp;");
+ break;
+ case '\r':
+ case '\n':
+ case '\t':
+ if (encodeWhitespace) {
+ sb.append(WS_ENTITIES[c - '\t']);
+ } else {
+ sb.append(c);
+ }
+ break;
+ default:
+ if (isLegalCharacter(c)) {
+ sb.append(c);
+ }
+ break;
+ }
+ }
+ return sb.substring(0);
+ }
+
+ /**
+ * Drop characters that are illegal in XML documents.
+ *
+ * <p>Also ensure that we are not including an <code>]]&gt;</code>
+ * marker by replacing that sequence with
+ * <code>&amp;#x5d;&amp;#x5d;&amp;gt;</code>.</p>
+ *
+ * <p>See XML 1.0 2.2 <a
+ * href="http://www.w3.org/TR/1998/REC-xml-19980210#charsets">
+ * http://www.w3.org/TR/1998/REC-xml-19980210#charsets</a> and
+ * 2.7 <a
+ * href="http://www.w3.org/TR/1998/REC-xml-19980210#sec-cdata-sect">http://www.w3.org/TR/1998/REC-xml-19980210#sec-cdata-sect</a>.</p>
+ * @param value the value to be encoded.
+ * @return the encoded value.
+ */
+ public String encodedata(final String value) {
+ final StringWriter out = new StringWriter();
+ try {
+ encodedata(out, value);
+ } catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ return out.toString();
+ }
+
+ /**
+ * Drop characters that are illegal in XML documents and write the
+ * rest to the given writer.
+ *
+ * <p>Also ensure that we are not including an <code>]]&gt;</code>
+ * marker by replacing that sequence with
+ * <code>&amp;#x5d;&amp;#x5d;&amp;gt;</code>.</p>
+ *
+ * <p>See XML 1.0 2.2 <a
+ * href="http://www.w3.org/TR/1998/REC-xml-19980210#charsets">
+ * http://www.w3.org/TR/1998/REC-xml-19980210#charsets</a> and
+ * 2.7 <a
+ * href="http://www.w3.org/TR/1998/REC-xml-19980210#sec-cdata-sect">http://www.w3.org/TR/1998/REC-xml-19980210#sec-cdata-sect</a>.</p>
+ * @param value the value to be encoded.
+ * @param out where to write the encoded data to.
+ */
+ public void encodedata(final Writer out, final String value) throws IOException {
+ final int len = value.length();
+ int prevEnd = 0, cdataEndPos = value.indexOf("]]>");
+ while (prevEnd < len) {
+ final int end = (cdataEndPos < 0 ? len : cdataEndPos);
+ // Write out stretches of legal characters in the range [prevEnd, end).
+ for (int prevLegalCharPos = prevEnd; prevLegalCharPos < end;/*empty*/) {
+ int illegalCharPos;
+ for (illegalCharPos = prevLegalCharPos; true; ++illegalCharPos) {
+ if (illegalCharPos >= end
+ || !isLegalCharacter(value.charAt(illegalCharPos))) {
+ break;
+ }
+ }
+ out.write(value, prevLegalCharPos, illegalCharPos - prevLegalCharPos);
+ prevLegalCharPos = illegalCharPos + 1;
+ }
+
+ if (cdataEndPos >= 0) {
+ out.write("]]]]><![CDATA[>");
+ prevEnd = cdataEndPos + 3;
+ cdataEndPos = value.indexOf("]]>", prevEnd);
+ } else {
+ prevEnd = end;
+ }
+ }
+ }
+
+ /**
+ * Is the given argument a character or entity reference?
+ * @param ent the value to be checked.
+ * @return true if it is an entity.
+ */
+ public boolean isReference(String ent) {
+ if (!(ent.charAt(0) == '&') || !ent.endsWith(";")) {
+ return false;
+ }
+
+ if (ent.charAt(1) == '#') {
+ if (ent.charAt(2) == 'x') {
+ try {
+ // CheckStyle:MagicNumber OFF
+ Integer.parseInt(ent.substring(3, ent.length() - 1), HEX);
+ // CheckStyle:MagicNumber ON
+ return true;
+ } catch (NumberFormatException nfe) {
+ return false;
+ }
+ } else {
+ try {
+ Integer.parseInt(ent.substring(2, ent.length() - 1));
+ return true;
+ } catch (NumberFormatException nfe) {
+ return false;
+ }
+ }
+ }
+
+ String name = ent.substring(1, ent.length() - 1);
+ for (int i = 0; i < knownEntities.length; i++) {
+ if (name.equals(knownEntities[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Is the given character allowed inside an XML document?
+ *
+ * <p>See XML 1.0 2.2 <a
+ * href="http://www.w3.org/TR/1998/REC-xml-19980210#charsets">
+ * http://www.w3.org/TR/1998/REC-xml-19980210#charsets</a>.</p>
+ * @param c the character to test.
+ * @return true if the character is allowed.
+ * @since 1.10, Ant 1.5
+ */
+ public boolean isLegalCharacter(final char c) {
+ // CheckStyle:MagicNumber OFF
+ if (c == 0x9 || c == 0xA || c == 0xD) {
+ return true;
+ } else if (c < 0x20) {
+ return false;
+ } else if (c <= 0xD7FF) {
+ return true;
+ } else if (c < 0xE000) {
+ return false;
+ } else if (c <= 0xFFFD) {
+ return true;
+ }
+ // CheckStyle:MagicNumber ON
+ return false;
+ }
+
+ private void removeNSDefinitions(Element element) {
+ ArrayList al = (ArrayList) nsURIByElement.get(element);
+ if (al != null) {
+ Iterator iter = al.iterator();
+ while (iter.hasNext()) {
+ nsPrefixMap.remove(iter.next());
+ }
+ nsURIByElement.remove(element);
+ }
+ }
+
+ private void addNSDefinition(Element element, String uri) {
+ ArrayList al = (ArrayList) nsURIByElement.get(element);
+ if (al == null) {
+ al = new ArrayList();
+ nsURIByElement.put(element, al);
+ }
+ al.add(uri);
+ }
+
+ private static String getNamespaceURI(Node n) {
+ String uri = n.getNamespaceURI();
+ if (uri == null) {
+ // FIXME: Is "No Namespace is Empty Namespace" really OK?
+ uri = "";
+ }
+ return uri;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DOMUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DOMUtils.java
new file mode 100644
index 00000000..db00213d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DOMUtils.java
@@ -0,0 +1,163 @@
+/*
+ * 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.util;
+
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Text;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * Some utility methods for common tasks when building DOM trees in memory.
+ *
+ * <p>In this documentation <code>&lt;a&gt;</code> means an {@link
+ * org.w3c.dom.Element Element} instance with name <code>a</code>.</p>
+ *
+ * @since Ant 1.6.3
+ */
+public class DOMUtils {
+
+ /**
+ * Get a new Document instance,
+ * @return the document.
+ * @since Ant 1.6.3
+ */
+ public static Document newDocument() {
+ return JAXPUtils.getDocumentBuilder().newDocument();
+ }
+
+ /**
+ * Creates a named Element and appends it to the given element,
+ * returns it.
+ *
+ * <p>This means
+ * <pre>createChildElement(&lt;a&gt;, "b")</pre>
+ * creates
+ * <pre>
+ * &lt;a&gt;
+ * &lt;b/&gt;
+ * &lt;/a&gt;
+ * </pre>
+ * and returns <code>&lt;b&gt;</code>.
+ *
+ * @param parent element that will receive the new element as child.
+ * @param name name of the new element.
+ * @return the new element.
+ *
+ * @since Ant 1.6.3
+ */
+ public static Element createChildElement(Element parent, String name) {
+ Document doc = parent.getOwnerDocument();
+ Element e = doc.createElement(name);
+ parent.appendChild(e);
+ return e;
+ }
+
+ /**
+ * Adds nested text.
+ *
+ * <p>This means
+ * <pre>appendText(&lt;a&gt;, "b")</pre>
+ * creates
+ * <pre>
+ * &lt;a&gt;b&lt;/a&gt;
+ * </pre>
+ *
+ * @param parent element that will receive the new element as child.
+ * @param content text content.
+ *
+ * @since Ant 1.6.3
+ */
+ public static void appendText(Element parent, String content) {
+ Document doc = parent.getOwnerDocument();
+ Text t = doc.createTextNode(content);
+ parent.appendChild(t);
+ }
+
+ /**
+ * Adds a nested CDATA section.
+ *
+ * <p>This means
+ * <pre>appendCDATA(&lt;a&gt;, "b")</pre>
+ * creates
+ * <pre>
+ * &lt;a&gt;&lt;[!CDATA[b]]&gt;&lt;/a&gt;
+ * </pre>
+ *
+ * @param parent element that will receive the new element as child.
+ * @param content text content.
+ *
+ * @since Ant 1.6.3
+ */
+ public static void appendCDATA(Element parent, String content) {
+ Document doc = parent.getOwnerDocument();
+ CDATASection c = doc.createCDATASection(content);
+ parent.appendChild(c);
+ }
+
+ /**
+ * Adds nested text in a new child element.
+ *
+ * <p>This means
+ * <pre>appendTextElement(&lt;a&gt;, "b", "c")</pre>
+ * creates
+ * <pre>
+ * &lt;a&gt;
+ * &lt;b&gt;c&lt;/b&gt;
+ * &lt;/a&gt;
+ * </pre>
+ *
+ * @param parent element that will receive the new element as child.
+ * @param name of the child element.
+ * @param content text content.
+ *
+ * @since Ant 1.6.3
+ */
+ public static void appendTextElement(Element parent, String name,
+ String content) {
+ Element e = createChildElement(parent, name);
+ appendText(e, content);
+ }
+
+ /**
+ * Adds a nested CDATA section in a new child element.
+ *
+ * <p>This means
+ * <pre>appendCDATAElement(&lt;a&gt;, "b", "c")</pre>
+ * creates
+ * <pre>
+ * &lt;a&gt;
+ * &lt;b&gt;&lt;![CDATA[c]]&gt;&lt;/b&gt;
+ * &lt;/a&gt;
+ * </pre>
+ *
+ * @param parent element that will receive the new element as child.
+ * @param name of the child element.
+ * @param content text content.
+ *
+ * @since Ant 1.6.3
+ */
+ public static void appendCDATAElement(Element parent, String name,
+ String content) {
+ Element e = createChildElement(parent, name);
+ appendCDATA(e, content);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DateUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DateUtils.java
new file mode 100644
index 00000000..9ce737b0
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DateUtils.java
@@ -0,0 +1,301 @@
+/*
+ * 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.util;
+
+import java.text.ChoiceFormat;
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.TimeZone;
+
+/**
+ * Helper methods to deal with date/time formatting with a specific
+ * defined format (<a href="http://www.w3.org/TR/NOTE-datetime">ISO8601</a>)
+ * or a plurialization correct elapsed time in minutes and seconds.
+ *
+ * @since Ant 1.5
+ *
+ */
+public final class DateUtils {
+
+ private static final int ONE_SECOND = 1000;
+ private static final int ONE_MINUTE = 60;
+ private static final int ONE_HOUR = 60;
+ private static final int TEN = 10;
+ /**
+ * ISO8601-like pattern for date-time. It does not support timezone.
+ * <tt>yyyy-MM-ddTHH:mm:ss</tt>
+ */
+ public static final String ISO8601_DATETIME_PATTERN
+ = "yyyy-MM-dd'T'HH:mm:ss";
+
+ /**
+ * ISO8601-like pattern for date. <tt>yyyy-MM-dd</tt>
+ */
+ public static final String ISO8601_DATE_PATTERN
+ = "yyyy-MM-dd";
+
+ /**
+ * ISO8601-like pattern for time. <tt>HH:mm:ss</tt>
+ */
+ public static final String ISO8601_TIME_PATTERN
+ = "HH:mm:ss";
+
+ /**
+ * Format used for SMTP (and probably other) Date headers.
+ * @deprecated DateFormat is not thread safe, and we cannot guarantee that
+ * some other code is using the format in parallel.
+ * Deprecated since ant 1.8
+ */
+ public static final DateFormat DATE_HEADER_FORMAT
+ = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ", Locale.US);
+
+ private static final DateFormat DATE_HEADER_FORMAT_INT
+ = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss ", Locale.US);
+
+
+// code from Magesh moved from DefaultLogger and slightly modified
+ private static final MessageFormat MINUTE_SECONDS
+ = new MessageFormat("{0}{1}");
+
+ private static final double[] LIMITS = {0, 1, 2};
+
+ private static final String[] MINUTES_PART = {"", "1 minute ", "{0,number,###############} minutes "};
+
+ private static final String[] SECONDS_PART = {"0 seconds", "1 second", "{1,number} seconds"};
+
+ private static final ChoiceFormat MINUTES_FORMAT =
+ new ChoiceFormat(LIMITS, MINUTES_PART);
+
+ private static final ChoiceFormat SECONDS_FORMAT =
+ new ChoiceFormat(LIMITS, SECONDS_PART);
+
+ static {
+ MINUTE_SECONDS.setFormat(0, MINUTES_FORMAT);
+ MINUTE_SECONDS.setFormat(1, SECONDS_FORMAT);
+ }
+
+ /** private constructor */
+ private DateUtils() {
+ }
+
+
+ /**
+ * Format a date/time into a specific pattern.
+ * @param date the date to format expressed in milliseconds.
+ * @param pattern the pattern to use to format the date.
+ * @return the formatted date.
+ */
+ public static String format(long date, String pattern) {
+ return format(new Date(date), pattern);
+ }
+
+
+ /**
+ * Format a date/time into a specific pattern.
+ * @param date the date to format expressed in milliseconds.
+ * @param pattern the pattern to use to format the date.
+ * @return the formatted date.
+ */
+ public static String format(Date date, String pattern) {
+ DateFormat df = createDateFormat(pattern);
+ return df.format(date);
+ }
+
+
+ /**
+ * Format an elapsed time into a plurialization correct string.
+ * It is limited only to report elapsed time in minutes and
+ * seconds and has the following behavior.
+ * <ul>
+ * <li>minutes are not displayed when 0. (ie: "45 seconds")</li>
+ * <li>seconds are always displayed in plural form (ie "0 seconds" or
+ * "10 seconds") except for 1 (ie "1 second")</li>
+ * </ul>
+ * @param millis the elapsed time to report in milliseconds.
+ * @return the formatted text in minutes/seconds.
+ */
+ public static String formatElapsedTime(long millis) {
+ long seconds = millis / ONE_SECOND;
+ long minutes = seconds / ONE_MINUTE;
+ Object[] args = {new Long(minutes), new Long(seconds % ONE_MINUTE)};
+ return MINUTE_SECONDS.format(args);
+ }
+
+ /**
+ * return a lenient date format set to GMT time zone.
+ * @param pattern the pattern used for date/time formatting.
+ * @return the configured format for this pattern.
+ */
+ private static DateFormat createDateFormat(String pattern) {
+ SimpleDateFormat sdf = new SimpleDateFormat(pattern);
+ TimeZone gmt = TimeZone.getTimeZone("GMT");
+ sdf.setTimeZone(gmt);
+ sdf.setLenient(true);
+ return sdf;
+ }
+
+ /**
+ * Calculate the phase of the moon for a given date.
+ *
+ * <p>Code heavily influenced by hacklib.c in <a
+ * href="http://www.nethack.org/">Nethack</a></p>
+ *
+ * <p>The Algorithm:
+ *
+ * <pre>
+ * moon period = 29.53058 days ~= 30, year = 365.2422 days
+ *
+ * days moon phase advances on first day of year compared to preceding year
+ * = 365.2422 - 12*29.53058 ~= 11
+ *
+ * years in Metonic cycle (time until same phases fall on the same days of
+ * the month) = 18.6 ~= 19
+ *
+ * moon phase on first day of year (epact) ~= (11*(year%19) + 18) % 30
+ * (18 as initial condition for 1900)
+ *
+ * current phase in days = first day phase + days elapsed in year
+ *
+ * 6 moons ~= 177 days
+ * 177 ~= 8 reported phases * 22
+ * + 11/22 for rounding
+ * </pre>
+ *
+ * @param cal the calendar.
+ *
+ * @return The phase of the moon as a number between 0 and 7 with
+ * 0 meaning new moon and 4 meaning full moon.
+ *
+ * @since 1.2, Ant 1.5
+ */
+ public static int getPhaseOfMoon(Calendar cal) {
+ // CheckStyle:MagicNumber OFF
+ int dayOfTheYear = cal.get(Calendar.DAY_OF_YEAR);
+ int yearInMetonicCycle = ((cal.get(Calendar.YEAR) - 1900) % 19) + 1;
+ int epact = (11 * yearInMetonicCycle + 18) % 30;
+ if ((epact == 25 && yearInMetonicCycle > 11) || epact == 24) {
+ epact++;
+ }
+ return (((((dayOfTheYear + epact) * 6) + 11) % 177) / 22) & 7;
+ // CheckStyle:MagicNumber ON
+ }
+
+ /**
+ * Returns the current Date in a format suitable for a SMTP date
+ * header.
+ * @return the current date.
+ * @since Ant 1.5.2
+ */
+ public static String getDateForHeader() {
+ Calendar cal = Calendar.getInstance();
+ TimeZone tz = cal.getTimeZone();
+ int offset = tz.getOffset(cal.get(Calendar.ERA),
+ cal.get(Calendar.YEAR),
+ cal.get(Calendar.MONTH),
+ cal.get(Calendar.DAY_OF_MONTH),
+ cal.get(Calendar.DAY_OF_WEEK),
+ cal.get(Calendar.MILLISECOND));
+ StringBuffer tzMarker = new StringBuffer(offset < 0 ? "-" : "+");
+ offset = Math.abs(offset);
+ int hours = offset / (ONE_HOUR * ONE_MINUTE * ONE_SECOND);
+ int minutes = offset / (ONE_MINUTE * ONE_SECOND) - ONE_HOUR * hours;
+ if (hours < TEN) {
+ tzMarker.append("0");
+ }
+ tzMarker.append(hours);
+ if (minutes < TEN) {
+ tzMarker.append("0");
+ }
+ tzMarker.append(minutes);
+ synchronized (DATE_HEADER_FORMAT_INT) {
+ return DATE_HEADER_FORMAT_INT.format(cal.getTime()) + tzMarker.toString();
+ }
+ }
+
+ /**
+ * Parses the string in a format suitable for a SMTP date header.
+ *
+ * @param datestr string to be parsed
+ *
+ * @return a java.util.Date object as parsed by the format.
+ * @exception ParseException if the supplied string cannot be parsed by
+ * this pattern.
+ * @since Ant 1.8.0
+ */
+ public static Date parseDateFromHeader(String datestr) throws ParseException {
+ synchronized (DATE_HEADER_FORMAT_INT) {
+ return DATE_HEADER_FORMAT_INT.parse(datestr);
+ }
+ }
+
+ /**
+ * Parse a string as a datetime using the ISO8601_DATETIME format which is
+ * <code>yyyy-MM-dd'T'HH:mm:ss</code>
+ *
+ * @param datestr string to be parsed
+ *
+ * @return a java.util.Date object as parsed by the format.
+ * @exception ParseException if the supplied string cannot be parsed by
+ * this pattern.
+ * @since Ant 1.6
+ */
+ public static Date parseIso8601DateTime(String datestr)
+ throws ParseException {
+ return new SimpleDateFormat(ISO8601_DATETIME_PATTERN).parse(datestr);
+ }
+
+ /**
+ * Parse a string as a date using the ISO8601_DATE format which is
+ * <code>yyyy-MM-dd</code>
+ *
+ * @param datestr string to be parsed
+ *
+ * @return a java.util.Date object as parsed by the format.
+ * @exception ParseException if the supplied string cannot be parsed by
+ * this pattern.
+ * @since Ant 1.6
+ */
+ public static Date parseIso8601Date(String datestr) throws ParseException {
+ return new SimpleDateFormat(ISO8601_DATE_PATTERN).parse(datestr);
+ }
+
+ /**
+ * Parse a string as a date using the either the ISO8601_DATETIME
+ * or ISO8601_DATE formats.
+ *
+ * @param datestr string to be parsed
+ *
+ * @return a java.util.Date object as parsed by the formats.
+ * @exception ParseException if the supplied string cannot be parsed by
+ * either of these patterns.
+ * @since Ant 1.6
+ */
+ public static Date parseIso8601DateTimeOrDate(String datestr)
+ throws ParseException {
+ try {
+ return parseIso8601DateTime(datestr);
+ } catch (ParseException px) {
+ return parseIso8601Date(datestr);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DeweyDecimal.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DeweyDecimal.java
new file mode 100644
index 00000000..003f1406
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/DeweyDecimal.java
@@ -0,0 +1,237 @@
+/*
+ * 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.util;
+
+import java.util.StringTokenizer;
+
+/**
+ * Utility class to contain version numbers in "Dewey Decimal"
+ * syntax. Numbers in the "Dewey Decimal" syntax consist of positive
+ * decimal integers separated by periods ".". For example, "2.0" or
+ * "1.2.3.4.5.6.7". This allows an extensible number to be used to
+ * represent major, minor, micro, etc versions. The version number
+ * must begin with a number.
+ *
+ */
+public class DeweyDecimal implements Comparable<DeweyDecimal> {
+
+ /** Array of components that make up DeweyDecimal */
+ private final int[] components;
+
+ /**
+ * Construct a DeweyDecimal from an array of integer components.
+ *
+ * @param components an array of integer components.
+ */
+ public DeweyDecimal(final int[] components) {
+ this.components = new int[components.length];
+ System.arraycopy(components, 0, this.components, 0, components.length);
+ }
+
+ /**
+ * Construct a DeweyDecimal from string in DeweyDecimal format.
+ *
+ * @param string the string in dewey decimal format
+ * @exception NumberFormatException if string is malformed
+ */
+ public DeweyDecimal(final String string)
+ throws NumberFormatException {
+ final StringTokenizer tokenizer = new StringTokenizer(string, ".", true);
+ final int size = tokenizer.countTokens();
+
+ components = new int[ (size + 1) / 2 ];
+
+ for (int i = 0; i < components.length; i++) {
+ final String component = tokenizer.nextToken();
+ if (component.length() == 0) {
+ throw new NumberFormatException("Empty component in string");
+ }
+
+ components[ i ] = Integer.parseInt(component);
+
+ //Strip '.' token
+ if (tokenizer.hasMoreTokens()) {
+ tokenizer.nextToken();
+
+ //If it ended in a dot, throw an exception
+ if (!tokenizer.hasMoreTokens()) {
+ throw new NumberFormatException("DeweyDecimal ended in a '.'");
+ }
+ }
+ }
+ }
+
+ /**
+ * Return number of components in <code>DeweyDecimal</code>.
+ *
+ * @return the number of components in dewey decimal
+ */
+ public int getSize() {
+ return components.length;
+ }
+
+ /**
+ * Return the component at specified index.
+ *
+ * @param index the index of components
+ * @return the value of component at index
+ */
+ public int get(final int index) {
+ return components[ index ];
+ }
+
+ /**
+ * Return <code>true</code> if this <code>DeweyDecimal</code> is
+ * equal to the other <code>DeweyDecimal</code>.
+ *
+ * @param other the other DeweyDecimal
+ * @return true if equal to other DeweyDecimal, false otherwise
+ */
+ public boolean isEqual(final DeweyDecimal other) {
+ final int max = Math.max(other.components.length, components.length);
+
+ for (int i = 0; i < max; i++) {
+ final int component1 = (i < components.length) ? components[ i ] : 0;
+ final int component2 = (i < other.components.length) ? other.components[ i ] : 0;
+
+ if (component2 != component1) {
+ return false;
+ }
+ }
+
+ return true; // Exact match
+ }
+
+ /**
+ * Return <code>true</code> if this <code>DeweyDecimal</code> is
+ * less than the other <code>DeweyDecimal</code>.
+ *
+ * @param other the other DeweyDecimal
+ * @return true if less than other DeweyDecimal, false otherwise
+ */
+ public boolean isLessThan(final DeweyDecimal other) {
+ return !isGreaterThanOrEqual(other);
+ }
+
+ /**
+ * Return <code>true</code> if this <code>DeweyDecimal</code> is
+ * less than or equal to the other <code>DeweyDecimal</code>.
+ *
+ * @param other the other DeweyDecimal
+ * @return true if less than or equal to other DeweyDecimal, false otherwise
+ */
+ public boolean isLessThanOrEqual(final DeweyDecimal other) {
+ return !isGreaterThan(other);
+ }
+
+ /**
+ * Return <code>true</code> if this <code>DeweyDecimal</code> is
+ * greater than the other <code>DeweyDecimal</code>.
+ *
+ * @param other the other DeweyDecimal
+ * @return true if greater than other DeweyDecimal, false otherwise
+ */
+ public boolean isGreaterThan(final DeweyDecimal other) {
+ final int max = Math.max(other.components.length, components.length);
+
+ for (int i = 0; i < max; i++) {
+ final int component1 = (i < components.length) ? components[ i ] : 0;
+ final int component2 = (i < other.components.length) ? other.components[ i ] : 0;
+
+ if (component2 > component1) {
+ return false;
+ }
+ if (component2 < component1) {
+ return true;
+ }
+ }
+
+ return false; // Exact match
+ }
+
+ /**
+ * Return <code>true</code> if this <code>DeweyDecimal</code> is
+ * greater than or equal to the other <code>DeweyDecimal</code>.
+ *
+ * @param other the other DeweyDecimal
+ * @return true if greater than or equal to other DeweyDecimal, false otherwise
+ */
+ public boolean isGreaterThanOrEqual(final DeweyDecimal other) {
+ final int max = Math.max(other.components.length, components.length);
+
+ for (int i = 0; i < max; i++) {
+ final int component1 = (i < components.length) ? components[ i ] : 0;
+ final int component2 = (i < other.components.length) ? other.components[ i ] : 0;
+
+ if (component2 > component1) {
+ return false;
+ }
+ if (component2 < component1) {
+ return true;
+ }
+ }
+
+ return true; // Exact match
+ }
+
+ /**
+ * Return string representation of <code>DeweyDecimal</code>.
+ *
+ * @return the string representation of DeweyDecimal.
+ */
+ @Override public String toString() {
+ final StringBuffer sb = new StringBuffer();
+
+ for (int i = 0; i < components.length; i++) {
+ if (i != 0) {
+ sb.append('.');
+ }
+ sb.append(components[ i ]);
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Compares this DeweyDecimal with another one.
+ *
+ * @param other another DeweyDecimal to compare with
+ * @return result
+ * @see java.lang.Comparable#compareTo(Object)
+ */
+ public int compareTo(DeweyDecimal other) {
+ final int max = Math.max(other.components.length, components.length);
+ for (int i = 0; i < max; i++) {
+ final int component1 = (i < components.length) ? components[ i ] : 0;
+ final int component2 = (i < other.components.length) ? other.components[ i ] : 0;
+ if (component1 != component2) {
+ return component1 - component2;
+ }
+ }
+ return 0;
+ }
+
+ @Override public int hashCode() {
+ return toString().hashCode();
+ }
+
+ @Override public boolean equals(Object o) {
+ return o instanceof DeweyDecimal && isEqual((DeweyDecimal) o);
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileNameMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileNameMapper.java
new file mode 100644
index 00000000..bbd82614
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileNameMapper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.util;
+
+/**
+ * Interface to be used by SourceFileScanner.
+ *
+ * <p>Used to find the name of the target file(s) corresponding to a
+ * source file.</p>
+ *
+ * <p>The rule by which the file names are transformed is specified
+ * via the setFrom and setTo methods. The exact meaning of these is
+ * implementation dependent.</p>
+ *
+ */
+public interface FileNameMapper {
+
+ /**
+ * Sets the from part of the transformation rule.
+ * @param from a string.
+ */
+ void setFrom(String from);
+
+ /**
+ * Sets the to part of the transformation rule.
+ * @param to a string.
+ */
+ void setTo(String to);
+
+ /**
+ * Returns an array containing the target filename(s) for the
+ * given source file.
+ *
+ * <p>if the given rule doesn't apply to the source file,
+ * implementation must return null. SourceFileScanner will then
+ * omit the source file in question.</p>
+ *
+ * @param sourceFileName the name of the source file relative to
+ * some given basedirectory.
+ * @return an array of strings if the rule applies to the source file, or
+ * null if it does not.
+ */
+ String[] mapFileName(String sourceFileName);
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileTokenizer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileTokenizer.java
new file mode 100644
index 00000000..2807aa42
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileTokenizer.java
@@ -0,0 +1,48 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Class to read the complete input into a string.
+ * @since Ant 1.7
+ */
+public class FileTokenizer extends ProjectComponent implements Tokenizer {
+
+ /**
+ * Get the complete input as a string
+ * @param in the reader object
+ * @return the complete input
+ * @throws IOException if error reading
+ */
+ public String getToken(Reader in) throws IOException {
+ return FileUtils.readFully(in);
+ }
+
+ /**
+ * Return the intra-token string
+ * @return an empty string always
+ */
+ public String getPostToken() {
+ return "";
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileUtils.java
new file mode 100644
index 00000000..bcef5ecf
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FileUtils.java
@@ -0,0 +1,1722 @@
+/*
+ * 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.util;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.Writer;
+import java.net.HttpURLConnection;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.nio.channels.Channel;
+import java.text.DecimalFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Random;
+import java.util.Stack;
+import java.util.StringTokenizer;
+import java.util.Vector;
+import java.util.jar.JarFile;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.PathTokenizer;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.launch.Locator;
+import org.apache.tools.ant.taskdefs.condition.Os;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.resources.FileResource;
+
+/**
+ * This class also encapsulates methods which allow Files to be
+ * referred to using abstract path names which are translated to native
+ * system file paths at runtime as well as copying files or setting
+ * their last modification time.
+ *
+ */
+public class FileUtils {
+ private static final int DELETE_RETRY_SLEEP_MILLIS = 10;
+ private static final int EXPAND_SPACE = 50;
+ private static final FileUtils PRIMARY_INSTANCE = new FileUtils();
+
+ //get some non-crypto-grade randomness from various places.
+ private static Random rand = new Random(System.currentTimeMillis()
+ + Runtime.getRuntime().freeMemory());
+
+ private static final boolean ON_NETWARE = Os.isFamily("netware");
+ private static final boolean ON_DOS = Os.isFamily("dos");
+ private static final boolean ON_WIN9X = Os.isFamily("win9x");
+ private static final boolean ON_WINDOWS = Os.isFamily("windows");
+
+ static final int BUF_SIZE = 8192;
+
+
+ /**
+ * The granularity of timestamps under FAT.
+ */
+ public static final long FAT_FILE_TIMESTAMP_GRANULARITY = 2000;
+
+ /**
+ * The granularity of timestamps under Unix.
+ */
+ public static final long UNIX_FILE_TIMESTAMP_GRANULARITY = 1000;
+
+ /**
+ * The granularity of timestamps under the NT File System.
+ * NTFS has a granularity of 100 nanoseconds, which is less
+ * than 1 millisecond, so we round this up to 1 millisecond.
+ */
+ public static final long NTFS_FILE_TIMESTAMP_GRANULARITY = 1;
+
+ /**
+ * A one item cache for fromUri.
+ * fromUri is called for each element when parseing ant build
+ * files. It is a costly operation. This just caches the result
+ * of the last call.
+ */
+ private Object cacheFromUriLock = new Object();
+ private String cacheFromUriRequest = null;
+ private String cacheFromUriResponse = null;
+
+ /**
+ * Factory method.
+ *
+ * @return a new instance of FileUtils.
+ * @deprecated since 1.7.
+ * Use getFileUtils instead,
+ * FileUtils do not have state.
+ */
+ public static FileUtils newFileUtils() {
+ return new FileUtils();
+ }
+
+ /**
+ * Method to retrieve The FileUtils, which is shared by all users of this
+ * method.
+ * @return an instance of FileUtils.
+ * @since Ant 1.6.3
+ */
+ public static FileUtils getFileUtils() {
+ return PRIMARY_INSTANCE;
+ }
+
+ /**
+ * Empty constructor.
+ */
+ protected FileUtils() {
+ }
+
+ /**
+ * Get the URL for a file taking into account # characters.
+ *
+ * @param file the file whose URL representation is required.
+ * @return The FileURL value.
+ * @throws MalformedURLException if the URL representation cannot be
+ * formed.
+ */
+ public URL getFileURL(File file) throws MalformedURLException {
+ return new URL(file.toURI().toASCIIString());
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a destination.
+ * No filtering is performed.
+ *
+ * @param sourceFile Name of file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile Name of file to copy to.
+ * Must not be <code>null</code>.
+ *
+ * @throws IOException if the copying fails.
+ */
+ public void copyFile(String sourceFile, String destFile) throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), null, false, false);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a destination
+ * specifying if token filtering must be used.
+ *
+ * @param sourceFile Name of file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile Name of file to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ *
+ * @throws IOException if the copying fails.
+ */
+ public void copyFile(String sourceFile, String destFile, FilterSetCollection filters)
+ throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), filters, false, false);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a destination specifying if token
+ * filtering must be used and if source files may overwrite newer destination files.
+ *
+ * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
+ * @param destFile Name of file to copy to. Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param overwrite Whether or not the destination file should be overwritten if it already
+ * exists.
+ *
+ * @throws IOException if the copying fails.
+ */
+ public void copyFile(String sourceFile, String destFile, FilterSetCollection filters,
+ boolean overwrite) throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), filters, overwrite, false);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a destination
+ * specifying if token
+ * filtering must be used, if source files may overwrite newer destination
+ * files and the last
+ * modified time of <code>destFile</code> file should be made equal to
+ * the last modified time
+ * of <code>sourceFile</code>.
+ *
+ * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
+ * @param destFile Name of file to copy to. Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param overwrite Whether or not the destination file should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the resulting file
+ * should be set to that of the source file.
+ *
+ * @throws IOException if the copying fails.
+ */
+ public void copyFile(String sourceFile, String destFile,
+ FilterSetCollection filters,
+ boolean overwrite, boolean preserveLastModified)
+ throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), filters, overwrite,
+ preserveLastModified);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a destination specifying if token
+ * filtering must be used, if source files may overwrite newer destination files and the last
+ * modified time of <code>destFile</code> file should be made equal to the last modified time
+ * of <code>sourceFile</code>.
+ *
+ * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
+ * @param destFile Name of file to copy to. Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param overwrite Whether or not the destination file should be overwritten if it already
+ * exists.
+ * @param preserveLastModified Whether or not the last modified time of the resulting file
+ * should be set to that of the source file.
+ * @param encoding the encoding used to read and write the files.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.5
+ */
+ public void copyFile(String sourceFile, String destFile,
+ FilterSetCollection filters, boolean overwrite,
+ boolean preserveLastModified, String encoding) throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), filters,
+ overwrite, preserveLastModified, encoding);
+ }
+
+ // CheckStyle:ParameterNumberCheck OFF - bc
+ /**
+ * Convenience method to copy a file from a source to a
+ * destination specifying if token filtering must be used, if
+ * filter chains must be used, if source files may overwrite
+ * newer destination files and the last modified time of
+ * <code>destFile</code> file should be made equal
+ * to the last modified time of <code>sourceFile</code>.
+ *
+ * @param sourceFile Name of file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile Name of file to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param filterChains filterChains to apply during the copy.
+ * @param overwrite Whether or not the destination file should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the resulting file should be set to that
+ * of the source file.
+ * @param encoding the encoding used to read and write the files.
+ * @param project the project instance.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.5
+ */
+ public void copyFile(String sourceFile, String destFile,
+ FilterSetCollection filters, Vector filterChains,
+ boolean overwrite, boolean preserveLastModified,
+ String encoding, Project project) throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), filters, filterChains, overwrite,
+ preserveLastModified, encoding, project);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a destination specifying if token
+ * filtering must be used, if filter chains must be used, if source files may overwrite newer
+ * destination files and the last modified time of <code>destFile</code> file should be made
+ * equal to the last modified time of <code>sourceFile</code>.
+ *
+ * @param sourceFile Name of file to copy from. Must not be <code>null</code>.
+ * @param destFile Name of file to copy to. Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param filterChains filterChains to apply during the copy.
+ * @param overwrite Whether or not the destination file should be overwritten if it already
+ * exists.
+ * @param preserveLastModified Whether or not the last modified time of the resulting file
+ * should be set to that of the source file.
+ * @param inputEncoding the encoding used to read the files.
+ * @param outputEncoding the encoding used to write the files.
+ * @param project the project instance.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.6
+ */
+ public void copyFile(String sourceFile, String destFile,
+ FilterSetCollection filters, Vector filterChains,
+ boolean overwrite, boolean preserveLastModified,
+ String inputEncoding, String outputEncoding,
+ Project project) throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), filters, filterChains, overwrite,
+ preserveLastModified, inputEncoding, outputEncoding, project);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a destination. No filtering is performed.
+ *
+ * @param sourceFile the file to copy from. Must not be <code>null</code>.
+ * @param destFile the file to copy to. Must not be <code>null</code>.
+ *
+ * @throws IOException if the copying fails.
+ */
+ public void copyFile(File sourceFile, File destFile) throws IOException {
+ copyFile(sourceFile, destFile, null, false, false);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a destination
+ * specifying if token filtering must be used.
+ *
+ * @param sourceFile the file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile the file to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ *
+ * @throws IOException if the copying fails.
+ */
+ public void copyFile(File sourceFile, File destFile, FilterSetCollection filters)
+ throws IOException {
+ copyFile(sourceFile, destFile, filters, false, false);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a
+ * destination specifying if token filtering must be used and if
+ * source files may overwrite newer destination files.
+ *
+ * @param sourceFile the file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile the file to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param overwrite Whether or not the destination file should be
+ * overwritten if it already exists.
+ *
+ * @throws IOException if the copying fails.
+ */
+ public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
+ boolean overwrite) throws IOException {
+ copyFile(sourceFile, destFile, filters, overwrite, false);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a
+ * destination specifying if token filtering must be used, if
+ * source files may overwrite newer destination files and the
+ * last modified time of <code>destFile</code> file should be made equal
+ * to the last modified time of <code>sourceFile</code>.
+ *
+ * @param sourceFile the file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile the file to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param overwrite Whether or not the destination file should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the resulting file should be set to that
+ * of the source file.
+ *
+ * @throws IOException if the copying fails.
+ */
+ public void copyFile(File sourceFile, File destFile, FilterSetCollection filters,
+ boolean overwrite, boolean preserveLastModified) throws IOException {
+ copyFile(sourceFile, destFile, filters, overwrite, preserveLastModified, null);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a destination specifying if token
+ * filtering must be used, if source files may overwrite newer destination files, the last
+ * modified time of <code>destFile</code> file should be made equal to the last modified time
+ * of <code>sourceFile</code> and which character encoding to assume.
+ *
+ * @param sourceFile the file to copy from. Must not be <code>null</code>.
+ * @param destFile the file to copy to. Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param overwrite Whether or not the destination file should be overwritten if it already
+ * exists.
+ * @param preserveLastModified Whether or not the last modified time of the resulting file
+ * should be set to that of the source file.
+ * @param encoding the encoding used to read and write the files.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.5
+ */
+ public void copyFile(File sourceFile, File destFile,
+ FilterSetCollection filters, boolean overwrite,
+ boolean preserveLastModified, String encoding) throws IOException {
+ copyFile(sourceFile, destFile, filters, null, overwrite,
+ preserveLastModified, encoding, null);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a
+ * destination specifying if token filtering must be used, if
+ * filter chains must be used, if source files may overwrite
+ * newer destination files and the last modified time of
+ * <code>destFile</code> file should be made equal
+ * to the last modified time of <code>sourceFile</code>.
+ *
+ * @param sourceFile the file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile the file to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param filterChains filterChains to apply during the copy.
+ * @param overwrite Whether or not the destination file should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the resulting file should be set to that
+ * of the source file.
+ * @param encoding the encoding used to read and write the files.
+ * @param project the project instance.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.5
+ */
+ public void copyFile(File sourceFile, File destFile,
+ FilterSetCollection filters, Vector filterChains,
+ boolean overwrite, boolean preserveLastModified,
+ String encoding, Project project) throws IOException {
+ copyFile(sourceFile, destFile, filters, filterChains,
+ overwrite, preserveLastModified, encoding, encoding, project);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a
+ * destination specifying if token filtering must be used, if
+ * filter chains must be used, if source files may overwrite
+ * newer destination files and the last modified time of
+ * <code>destFile</code> file should be made equal
+ * to the last modified time of <code>sourceFile</code>.
+ *
+ * @param sourceFile the file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile the file to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param filterChains filterChains to apply during the copy.
+ * @param overwrite Whether or not the destination file should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the resulting file should be set to that
+ * of the source file.
+ * @param inputEncoding the encoding used to read the files.
+ * @param outputEncoding the encoding used to write the files.
+ * @param project the project instance.
+ *
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.6
+ */
+ public void copyFile(File sourceFile, File destFile,
+ FilterSetCollection filters, Vector filterChains,
+ boolean overwrite, boolean preserveLastModified,
+ String inputEncoding, String outputEncoding,
+ Project project) throws IOException {
+ copyFile(sourceFile, destFile, filters, filterChains, overwrite, preserveLastModified,
+ false, inputEncoding, outputEncoding, project);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a
+ * destination specifying if token filtering must be used, if
+ * filter chains must be used, if source files may overwrite
+ * newer destination files and the last modified time of
+ * <code>destFile</code> file should be made equal
+ * to the last modified time of <code>sourceFile</code>.
+ *
+ * @param sourceFile the file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile the file to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param filterChains filterChains to apply during the copy.
+ * @param overwrite Whether or not the destination file should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the resulting file should be set to that
+ * of the source file.
+ * @param append whether to append to the destination file.
+ * @param inputEncoding the encoding used to read the files.
+ * @param outputEncoding the encoding used to write the files.
+ * @param project the project instance.
+ *
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.8
+ */
+ public void copyFile(File sourceFile, File destFile,
+ FilterSetCollection filters, Vector filterChains,
+ boolean overwrite, boolean preserveLastModified,
+ boolean append,
+ String inputEncoding, String outputEncoding,
+ Project project) throws IOException {
+ copyFile(sourceFile, destFile, filters, filterChains, overwrite,
+ preserveLastModified, append, inputEncoding, outputEncoding,
+ project, /* force: */ false);
+ }
+
+ /**
+ * Convenience method to copy a file from a source to a
+ * destination specifying if token filtering must be used, if
+ * filter chains must be used, if source files may overwrite
+ * newer destination files and the last modified time of
+ * <code>destFile</code> file should be made equal
+ * to the last modified time of <code>sourceFile</code>.
+ *
+ * @param sourceFile the file to copy from.
+ * Must not be <code>null</code>.
+ * @param destFile the file to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param filterChains filterChains to apply during the copy.
+ * @param overwrite Whether or not the destination file should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the resulting file should be set to that
+ * of the source file.
+ * @param append whether to append to the destination file.
+ * @param inputEncoding the encoding used to read the files.
+ * @param outputEncoding the encoding used to write the files.
+ * @param project the project instance.
+ * @param force whether to overwrite read-only destination files.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.8.2
+ */
+ public void copyFile(File sourceFile, File destFile,
+ FilterSetCollection filters, Vector filterChains,
+ boolean overwrite, boolean preserveLastModified,
+ boolean append,
+ String inputEncoding, String outputEncoding,
+ Project project, boolean force) throws IOException {
+ ResourceUtils.copyResource(new FileResource(sourceFile),
+ new FileResource(destFile),
+ filters, filterChains, overwrite,
+ preserveLastModified, append, inputEncoding,
+ outputEncoding, project, force);
+ }
+
+ // CheckStyle:ParameterNumberCheck ON
+
+ /**
+ * Calls File.setLastModified(long time). Originally written to
+ * to dynamically bind to that call on Java1.2+.
+ *
+ * @param file the file whose modified time is to be set
+ * @param time the time to which the last modified time is to be set.
+ * if this is -1, the current time is used.
+ */
+ public void setFileLastModified(File file, long time) {
+ ResourceUtils.setLastModified(new FileResource(file), time);
+ }
+
+ /**
+ * Interpret the filename as a file relative to the given file
+ * unless the filename already represents an absolute filename.
+ * Differs from <code>new File(file, filename)</code> in that
+ * the resulting File's path will always be a normalized,
+ * absolute pathname. Also, if it is determined that
+ * <code>filename</code> is context-relative, <code>file</code>
+ * will be discarded and the reference will be resolved using
+ * available context/state information about the filesystem.
+ *
+ * @param file the "reference" file for relative paths. This
+ * instance must be an absolute file and must not contain
+ * &quot;./&quot; or &quot;../&quot; sequences (same for \ instead
+ * of /). If it is null, this call is equivalent to
+ * <code>new java.io.File(filename).getAbsoluteFile()</code>.
+ *
+ * @param filename a file name.
+ *
+ * @return an absolute file.
+ * @throws java.lang.NullPointerException if filename is null.
+ */
+ public File resolveFile(File file, String filename) {
+ if (!isAbsolutePath(filename)) {
+ char sep = File.separatorChar;
+ filename = filename.replace('/', sep).replace('\\', sep);
+ if (isContextRelativePath(filename)) {
+ file = null;
+ // on cygwin, our current directory can be a UNC;
+ // assume user.dir is absolute or all hell breaks loose...
+ String udir = System.getProperty("user.dir");
+ if (filename.charAt(0) == sep && udir.charAt(0) == sep) {
+ filename = dissect(udir)[0] + filename.substring(1);
+ }
+ }
+ filename = new File(file, filename).getAbsolutePath();
+ }
+ return normalize(filename);
+ }
+
+ /**
+ * On DOS and NetWare, the evaluation of certain file
+ * specifications is context-dependent. These are filenames
+ * beginning with a single separator (relative to current root directory)
+ * and filenames with a drive specification and no intervening separator
+ * (relative to current directory of the specified root).
+ * @param filename the filename to evaluate.
+ * @return true if the filename is relative to system context.
+ * @throws java.lang.NullPointerException if filename is null.
+ * @since Ant 1.7
+ */
+ public static boolean isContextRelativePath(String filename) {
+ if (!(ON_DOS || ON_NETWARE) || filename.length() == 0) {
+ return false;
+ }
+ char sep = File.separatorChar;
+ filename = filename.replace('/', sep).replace('\\', sep);
+ char c = filename.charAt(0);
+ int len = filename.length();
+ return (c == sep && (len == 1 || filename.charAt(1) != sep))
+ || (Character.isLetter(c) && len > 1
+ && filename.charAt(1) == ':'
+ && (len == 2 || filename.charAt(2) != sep));
+ }
+
+ /**
+ * Verifies that the specified filename represents an absolute path.
+ * Differs from new java.io.File("filename").isAbsolute() in that a path
+ * beginning with a double file separator--signifying a Windows UNC--must
+ * at minimum match "\\a\b" to be considered an absolute path.
+ * @param filename the filename to be checked.
+ * @return true if the filename represents an absolute path.
+ * @throws java.lang.NullPointerException if filename is null.
+ * @since Ant 1.6.3
+ */
+ public static boolean isAbsolutePath(String filename) {
+ int len = filename.length();
+ if (len == 0) {
+ return false;
+ }
+ char sep = File.separatorChar;
+ filename = filename.replace('/', sep).replace('\\', sep);
+ char c = filename.charAt(0);
+ if (!(ON_DOS || ON_NETWARE)) {
+ return (c == sep);
+ }
+ if (c == sep) {
+ // CheckStyle:MagicNumber OFF
+ if (!(ON_DOS && len > 4 && filename.charAt(1) == sep)) {
+ return false;
+ }
+ // CheckStyle:MagicNumber ON
+ int nextsep = filename.indexOf(sep, 2);
+ return nextsep > 2 && nextsep + 1 < len;
+ }
+ int colon = filename.indexOf(':');
+ return (Character.isLetter(c) && colon == 1
+ && filename.length() > 2 && filename.charAt(2) == sep)
+ || (ON_NETWARE && colon > 0);
+ }
+
+ /**
+ * Translate a path into its native (platform specific) format.
+ * <p>
+ * This method uses PathTokenizer to separate the input path
+ * into its components. This handles DOS style paths in a relatively
+ * sensible way. The file separators are then converted to their platform
+ * specific versions.
+ *
+ * @param toProcess The path to be translated.
+ * May be <code>null</code>.
+ *
+ * @return the native version of the specified path or
+ * an empty string if the path is <code>null</code> or empty.
+ *
+ * @since ant 1.7
+ * @see PathTokenizer
+ */
+ public static String translatePath(String toProcess) {
+ if (toProcess == null || toProcess.length() == 0) {
+ return "";
+ }
+ StringBuffer path = new StringBuffer(toProcess.length() + EXPAND_SPACE);
+ PathTokenizer tokenizer = new PathTokenizer(toProcess);
+ while (tokenizer.hasMoreTokens()) {
+ String pathComponent = tokenizer.nextToken();
+ pathComponent = pathComponent.replace('/', File.separatorChar);
+ pathComponent = pathComponent.replace('\\', File.separatorChar);
+ if (path.length() != 0) {
+ path.append(File.pathSeparatorChar);
+ }
+ path.append(pathComponent);
+ }
+ return path.toString();
+ }
+
+ /**
+ * &quot;Normalize&quot; the given absolute path.
+ *
+ * <p>This includes:
+ * <ul>
+ * <li>Uppercase the drive letter if there is one.</li>
+ * <li>Remove redundant slashes after the drive spec.</li>
+ * <li>Resolve all ./, .\, ../ and ..\ sequences.</li>
+ * <li>DOS style paths that start with a drive letter will have
+ * \ as the separator.</li>
+ * </ul>
+ * Unlike {@link File#getCanonicalPath()} this method
+ * specifically does not resolve symbolic links.
+ *
+ * @param path the path to be normalized.
+ * @return the normalized version of the path.
+ *
+ * @throws java.lang.NullPointerException if path is null.
+ */
+ public File normalize(final String path) {
+ Stack s = new Stack();
+ String[] dissect = dissect(path);
+ s.push(dissect[0]);
+
+ StringTokenizer tok = new StringTokenizer(dissect[1], File.separator);
+ while (tok.hasMoreTokens()) {
+ String thisToken = tok.nextToken();
+ if (".".equals(thisToken)) {
+ continue;
+ }
+ if ("..".equals(thisToken)) {
+ if (s.size() < 2) {
+ // Cannot resolve it, so skip it.
+ return new File(path);
+ }
+ s.pop();
+ } else { // plain component
+ s.push(thisToken);
+ }
+ }
+ StringBuffer sb = new StringBuffer();
+ final int size = s.size();
+ for (int i = 0; i < size; i++) {
+ if (i > 1) {
+ // not before the filesystem root and not after it, since root
+ // already contains one
+ sb.append(File.separatorChar);
+ }
+ sb.append(s.elementAt(i));
+ }
+ return new File(sb.toString());
+ }
+
+ /**
+ * Dissect the specified absolute path.
+ * @param path the path to dissect.
+ * @return String[] {root, remaining path}.
+ * @throws java.lang.NullPointerException if path is null.
+ * @since Ant 1.7
+ */
+ public String[] dissect(String path) {
+ char sep = File.separatorChar;
+ path = path.replace('/', sep).replace('\\', sep);
+
+ // make sure we are dealing with an absolute path
+ if (!isAbsolutePath(path)) {
+ throw new BuildException(path + " is not an absolute path");
+ }
+ String root = null;
+ int colon = path.indexOf(':');
+ if (colon > 0 && (ON_DOS || ON_NETWARE)) {
+
+ int next = colon + 1;
+ root = path.substring(0, next);
+ char[] ca = path.toCharArray();
+ root += sep;
+ //remove the initial separator; the root has it.
+ next = (ca[next] == sep) ? next + 1 : next;
+
+ StringBuffer sbPath = new StringBuffer();
+ // Eliminate consecutive slashes after the drive spec:
+ for (int i = next; i < ca.length; i++) {
+ if (ca[i] != sep || ca[i - 1] != sep) {
+ sbPath.append(ca[i]);
+ }
+ }
+ path = sbPath.toString();
+ } else if (path.length() > 1 && path.charAt(1) == sep) {
+ // UNC drive
+ int nextsep = path.indexOf(sep, 2);
+ nextsep = path.indexOf(sep, nextsep + 1);
+ root = (nextsep > 2) ? path.substring(0, nextsep + 1) : path;
+ path = path.substring(root.length());
+ } else {
+ root = File.separator;
+ path = path.substring(1);
+ }
+ return new String[] {root, path};
+ }
+
+ /**
+ * Returns a VMS String representation of a <code>File</code> object.
+ * This is useful since the JVM by default internally converts VMS paths
+ * to Unix style.
+ * The returned String is always an absolute path.
+ *
+ * @param f The <code>File</code> to get the VMS path for.
+ * @return The absolute VMS path to <code>f</code>.
+ */
+ public String toVMSPath(File f) {
+ // format: "DEVICE:[DIR.SUBDIR]FILE"
+ String osPath;
+ String path = normalize(f.getAbsolutePath()).getPath();
+ String name = f.getName();
+ boolean isAbsolute = path.charAt(0) == File.separatorChar;
+ // treat directories specified using .DIR syntax as files
+ // CheckStyle:MagicNumber OFF
+ boolean isDirectory = f.isDirectory()
+ && !name.regionMatches(true, name.length() - 4, ".DIR", 0, 4);
+ // CheckStyle:MagicNumber ON
+ String device = null;
+ StringBuffer directory = null;
+ String file = null;
+
+ int index = 0;
+
+ if (isAbsolute) {
+ index = path.indexOf(File.separatorChar, 1);
+ if (index == -1) {
+ return path.substring(1) + ":[000000]";
+ }
+ device = path.substring(1, index++);
+ }
+ if (isDirectory) {
+ directory = new StringBuffer(path.substring(index).replace(File.separatorChar, '.'));
+ } else {
+ int dirEnd = path.lastIndexOf(File.separatorChar, path.length());
+ if (dirEnd == -1 || dirEnd < index) {
+ file = path.substring(index);
+ } else {
+ directory = new StringBuffer(path.substring(index, dirEnd).
+ replace(File.separatorChar, '.'));
+ index = dirEnd + 1;
+ if (path.length() > index) {
+ file = path.substring(index);
+ }
+ }
+ }
+ if (!isAbsolute && directory != null) {
+ directory.insert(0, '.');
+ }
+ osPath = ((device != null) ? device + ":" : "")
+ + ((directory != null) ? "[" + directory + "]" : "")
+ + ((file != null) ? file : "");
+ return osPath;
+ }
+
+ /**
+ * Create a File object for a temporary file in a given directory. Without
+ * actually creating the file.
+ *
+ * <p>
+ * The file denoted by the returned abstract pathname did not exist before
+ * this method was invoked, any subsequent invocation of this method will
+ * yield a different file name.
+ * </p>
+ * <p>
+ * The filename is prefixNNNNNsuffix where NNNN is a random number.
+ * </p>
+ *
+ * @param prefix
+ * prefix before the random number.
+ * @param suffix
+ * file extension; include the '.'.
+ * @param parentDir
+ * Directory to create the temporary file in; java.io.tmpdir used
+ * if not specified.
+ *
+ * @deprecated since ant 1.7.1 use createTempFile(String, String, File,
+ * boolean, boolean) instead.
+ * @return a File reference to the new, nonexistent temporary file.
+ */
+ public File createTempFile(String prefix, String suffix, File parentDir) {
+ return createTempFile(prefix, suffix, parentDir, false, false);
+ }
+
+ private static final String NULL_PLACEHOLDER = "null";
+
+ /**
+ * Create a temporary file in a given directory.
+ *
+ * <p>The file denoted by the returned abstract pathname did not
+ * exist before this method was invoked, any subsequent invocation
+ * of this method will yield a different file name.</p>
+ *
+ * @param prefix prefix before the random number.
+ * @param suffix file extension; include the '.'.
+ * @param parentDir Directory to create the temporary file in;
+ * java.io.tmpdir used if not specified.
+ * @param deleteOnExit whether to set the tempfile for deletion on
+ * normal VM exit.
+ * @param createFile true if the file must actually be created. If false
+ * chances exist that a file with the same name is created in the time
+ * between invoking this method and the moment the file is actually created.
+ * If possible set to true.
+ *
+ * @return a File reference to the new temporary file.
+ * @since Ant 1.7.1
+ */
+ public File createTempFile(String prefix, String suffix, File parentDir,
+ boolean deleteOnExit, boolean createFile) {
+ File result = null;
+ String parent = (parentDir == null)
+ ? System.getProperty("java.io.tmpdir")
+ : parentDir.getPath();
+ if (prefix == null) {
+ prefix = NULL_PLACEHOLDER;
+ }
+ if (suffix == null) {
+ suffix = NULL_PLACEHOLDER;
+ }
+
+ if (createFile) {
+ try {
+ result = File.createTempFile(prefix, suffix, new File(parent));
+ } catch (IOException e) {
+ throw new BuildException("Could not create tempfile in "
+ + parent, e);
+ }
+ } else {
+ DecimalFormat fmt = new DecimalFormat("#####");
+ synchronized (rand) {
+ do {
+ result = new File(parent, prefix
+ + fmt.format(rand.nextInt(Integer.MAX_VALUE)) + suffix);
+ } while (result.exists());
+ }
+ }
+
+ if (deleteOnExit) {
+ result.deleteOnExit();
+ }
+ return result;
+ }
+
+ /**
+ * Create a File object for a temporary file in a given directory. Without
+ * actually creating the file.
+ *
+ * <p>
+ * The file denoted by the returned abstract pathname did not exist before
+ * this method was invoked, any subsequent invocation of this method will
+ * yield a different file name.
+ * </p>
+ * <p>
+ * The filename is prefixNNNNNsuffix where NNNN is a random number.
+ * </p>
+ *
+ * @param prefix
+ * prefix before the random number.
+ * @param suffix
+ * file extension; include the '.'.
+ * @param parentDir
+ * Directory to create the temporary file in; java.io.tmpdir used
+ * if not specified.
+ * @param deleteOnExit
+ * whether to set the tempfile for deletion on normal VM exit.
+ *
+ * @deprecated since ant 1.7.1 use createTempFile(String, String, File,
+ * boolean, boolean) instead.
+ * @return a File reference to the new, nonexistent temporary file.
+ */
+ public File createTempFile(String prefix, String suffix,
+ File parentDir, boolean deleteOnExit) {
+ return createTempFile(prefix, suffix, parentDir, deleteOnExit, false);
+ }
+
+ /**
+ * Compares the contents of two files.
+ *
+ * @param f1 the file whose content is to be compared.
+ * @param f2 the other file whose content is to be compared.
+ *
+ * @return true if the content of the files is the same.
+ *
+ * @throws IOException if the files cannot be read.
+ */
+ public boolean contentEquals(File f1, File f2) throws IOException {
+ return contentEquals(f1, f2, false);
+ }
+
+ /**
+ * Compares the contents of two files.
+ *
+ * @param f1 the file whose content is to be compared.
+ * @param f2 the other file whose content is to be compared.
+ * @param textfile true if the file is to be treated as a text file and
+ * differences in kind of line break are to be ignored.
+ *
+ * @return true if the content of the files is the same.
+ *
+ * @throws IOException if the files cannot be read.
+ * @since Ant 1.6.3
+ */
+ public boolean contentEquals(File f1, File f2, boolean textfile) throws IOException {
+ return ResourceUtils.contentEquals(new FileResource(f1), new FileResource(f2), textfile);
+ }
+
+ /**
+ * This was originally an emulation of {@link File#getParentFile} for JDK 1.1, but it is now
+ * implemented using that method (Ant 1.6.3 onwards).
+ *
+ * @param f the file whose parent is required.
+ * @return the given file's parent, or null if the file does not have a parent.
+ * @since 1.10
+ * @deprecated since 1.7. Just use {@link File#getParentFile} directly.
+ */
+ public File getParentFile(File f) {
+ return (f == null) ? null : f.getParentFile();
+ }
+
+ /**
+ * Read from reader till EOF.
+ * @param rdr the reader from which to read.
+ * @return the contents read out of the given reader.
+ *
+ * @throws IOException if the contents could not be read out from the
+ * reader.
+ */
+ public static String readFully(Reader rdr) throws IOException {
+ return readFully(rdr, BUF_SIZE);
+ }
+
+ /**
+ * Read from reader till EOF.
+ *
+ * @param rdr the reader from which to read.
+ * @param bufferSize the buffer size to use when reading.
+ *
+ * @return the contents read out of the given reader.
+ *
+ * @throws IOException if the contents could not be read out from the
+ * reader.
+ */
+ public static String readFully(Reader rdr, int bufferSize)
+ throws IOException {
+ if (bufferSize <= 0) {
+ throw new IllegalArgumentException("Buffer size must be greater "
+ + "than 0");
+ }
+ final char[] buffer = new char[bufferSize];
+ int bufferLength = 0;
+ StringBuffer textBuffer = null;
+ while (bufferLength != -1) {
+ bufferLength = rdr.read(buffer);
+ if (bufferLength > 0) {
+ textBuffer = (textBuffer == null) ? new StringBuffer() : textBuffer;
+ textBuffer.append(new String(buffer, 0, bufferLength));
+ }
+ }
+ return (textBuffer == null) ? null : textBuffer.toString();
+ }
+
+ /**
+ * Safe read fully - do not return a null for an empty reader.
+ * @param reader the input to read from.
+ * @return the string.
+ * @throws IOException if unable to read from reader.
+ * @since Ant 1.7.1
+ */
+ public static String safeReadFully(Reader reader) throws IOException {
+ String ret = readFully(reader);
+ return ret == null ? "" : ret;
+ }
+
+ /**
+ * This was originally an emulation of File.createNewFile for JDK 1.1,
+ * but it is now implemented using that method (Ant 1.6.3 onwards).
+ *
+ * <p>This method has historically <strong>not</strong> guaranteed that the
+ * operation was atomic. In its current implementation it is.
+ *
+ * @param f the file to be created.
+ * @return true if the file did not exist already.
+ * @throws IOException on error.
+ * @since Ant 1.5
+ */
+ public boolean createNewFile(File f) throws IOException {
+ return f.createNewFile();
+ }
+
+ /**
+ * Create a new file, optionally creating parent directories.
+ *
+ * @param f the file to be created.
+ * @param mkdirs <code>boolean</code> whether to create parent directories.
+ * @return true if the file did not exist already.
+ * @throws IOException on error.
+ * @since Ant 1.6.3
+ */
+ public boolean createNewFile(File f, boolean mkdirs) throws IOException {
+ File parent = f.getParentFile();
+ if (mkdirs && !(parent.exists())) {
+ parent.mkdirs();
+ }
+ return f.createNewFile();
+ }
+
+ /**
+ * Checks whether a given file is a symbolic link.
+ *
+ * <p>It doesn't really test for symbolic links but whether the
+ * canonical and absolute paths of the file are identical--this
+ * may lead to false positives on some platforms.</p>
+ *
+ * @param parent the parent directory of the file to test
+ * @param name the name of the file to test.
+ *
+ * @return true if the file is a symbolic link.
+ * @throws IOException on error.
+ * @since Ant 1.5
+ * @deprecated use SymbolicLinkUtils instead
+ */
+ public boolean isSymbolicLink(File parent, String name)
+ throws IOException {
+ SymbolicLinkUtils u = SymbolicLinkUtils.getSymbolicLinkUtils();
+ if (parent == null) {
+ return u.isSymbolicLink(name);
+ }
+ return u.isSymbolicLink(parent, name);
+ }
+
+ /**
+ * Removes a leading path from a second path.
+ *
+ * @param leading The leading path, must not be null, must be absolute.
+ * @param path The path to remove from, must not be null, must be absolute.
+ *
+ * @return path's normalized absolute if it doesn't start with
+ * leading; path's path with leading's path removed otherwise.
+ *
+ * @since Ant 1.5
+ */
+ public String removeLeadingPath(File leading, File path) {
+ String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
+ String p = normalize(path.getAbsolutePath()).getAbsolutePath();
+ if (l.equals(p)) {
+ return "";
+ }
+ // ensure that l ends with a /
+ // so we never think /foo was a parent directory of /foobar
+ if (!l.endsWith(File.separator)) {
+ l += File.separator;
+ }
+ return (p.startsWith(l)) ? p.substring(l.length()) : p;
+ }
+
+ /**
+ * Learn whether one path "leads" another.
+ * @param leading The leading path, must not be null, must be absolute.
+ * @param path The path to remove from, must not be null, must be absolute.
+ * @return true if path starts with leading; false otherwise.
+ * @since Ant 1.7
+ */
+ public boolean isLeadingPath(File leading, File path) {
+ String l = normalize(leading.getAbsolutePath()).getAbsolutePath();
+ String p = normalize(path.getAbsolutePath()).getAbsolutePath();
+ if (l.equals(p)) {
+ return true;
+ }
+ // ensure that l ends with a /
+ // so we never think /foo was a parent directory of /foobar
+ if (!l.endsWith(File.separator)) {
+ l += File.separator;
+ }
+ return p.startsWith(l);
+ }
+
+ /**
+ * Constructs a <code>file:</code> URI that represents the
+ * external form of the given pathname.
+ *
+ * <p>Will be an absolute URI if the given path is absolute.</p>
+ *
+ * <p>This code encodes non ASCII characters too.</p>
+ *
+ * <p>The coding of the output is the same as what File.toURI().toASCIIString() produces</p>
+ *
+ * See <a href="http://www.w3.org/TR/xml11/#dt-sysid">dt-sysid</a>
+ * which makes some mention of how
+ * characters not supported by URI Reference syntax should be escaped.
+ *
+ * @param path the path in the local file system.
+ * @return the URI version of the local path.
+ * @since Ant 1.6
+ */
+ public String toURI(String path) {
+ return new File(path).toURI().toASCIIString();
+ }
+
+ /**
+ * Constructs a file path from a <code>file:</code> URI.
+ *
+ * <p>Will be an absolute path if the given URI is absolute.</p>
+ *
+ * <p>Swallows '%' that are not followed by two characters,
+ * doesn't deal with non-ASCII characters.</p>
+ *
+ * @param uri the URI designating a file in the local filesystem.
+ * @return the local file system path for the file.
+ * @since Ant 1.6
+ */
+ public String fromURI(String uri) {
+ synchronized (cacheFromUriLock) {
+ if (uri.equals(cacheFromUriRequest)) {
+ return cacheFromUriResponse;
+ }
+ String path = Locator.fromURI(uri);
+ String ret = isAbsolutePath(path) ? normalize(path).getAbsolutePath() : path;
+ cacheFromUriRequest = uri;
+ cacheFromUriResponse = ret;
+ return ret;
+ }
+ }
+
+ /**
+ * Compares two filenames.
+ *
+ * <p>Unlike java.io.File#equals this method will try to compare
+ * the absolute paths and &quot;normalize&quot; the filenames
+ * before comparing them.</p>
+ *
+ * @param f1 the file whose name is to be compared.
+ * @param f2 the other file whose name is to be compared.
+ *
+ * @return true if the file are for the same file.
+ *
+ * @since Ant 1.5.3
+ */
+ public boolean fileNameEquals(File f1, File f2) {
+ return normalize(f1.getAbsolutePath()).getAbsolutePath().equals(
+ normalize(f2.getAbsolutePath()).getAbsolutePath());
+ }
+
+ /**
+ * Are the two File instances pointing to the same object on the
+ * file system?
+ * @since Ant 1.8.2
+ */
+ public boolean areSame(File f1, File f2) throws IOException {
+ if (f1 == null && f2 == null) {
+ return true;
+ }
+ if (f1 == null || f2 == null) {
+ return false;
+ }
+ File f1Normalized = normalize(f1.getAbsolutePath());
+ File f2Normalized = normalize(f2.getAbsolutePath());
+ return f1Normalized.equals(f2Normalized)
+ || f1Normalized.getCanonicalFile().equals(f2Normalized
+ .getCanonicalFile());
+ }
+
+ /**
+ * Renames a file, even if that involves crossing file system boundaries.
+ *
+ * <p>This will remove <code>to</code> (if it exists), ensure that
+ * <code>to</code>'s parent directory exists and move
+ * <code>from</code>, which involves deleting <code>from</code> as
+ * well.</p>
+ *
+ * @param from the file to move.
+ * @param to the new file name.
+ *
+ * @throws IOException if anything bad happens during this
+ * process. Note that <code>to</code> may have been deleted
+ * already when this happens.
+ *
+ * @since Ant 1.6
+ */
+ public void rename(File from, File to) throws IOException {
+ // identical logic lives in Move.renameFile():
+ from = normalize(from.getAbsolutePath()).getCanonicalFile();
+ to = normalize(to.getAbsolutePath());
+ if (!from.exists()) {
+ System.err.println("Cannot rename nonexistent file " + from);
+ return;
+ }
+ if (from.getAbsolutePath().equals(to.getAbsolutePath())) {
+ System.err.println("Rename of " + from + " to " + to + " is a no-op.");
+ return;
+ }
+ if (to.exists() && !(areSame(from, to) || tryHardToDelete(to))) {
+ throw new IOException("Failed to delete " + to + " while trying to rename " + from);
+ }
+ File parent = to.getParentFile();
+ if (parent != null && !parent.isDirectory()
+ && !(parent.mkdirs() || parent.isDirectory())) {
+ throw new IOException("Failed to create directory " + parent
+ + " while trying to rename " + from);
+ }
+ if (!from.renameTo(to)) {
+ copyFile(from, to);
+ if (!tryHardToDelete(from)) {
+ throw new IOException("Failed to delete " + from + " while trying to rename it.");
+ }
+ }
+ }
+
+ /**
+ * Get the granularity of file timestamps. The choice is made based on OS, which is
+ * incorrect--it should really be by filesystem. We do not have an easy way to probe for file
+ * systems, however, so this heuristic gives us a decent default.
+ *
+ * @return the difference, in milliseconds, which two file timestamps must have in order for the
+ * two files to be considered to have different timestamps.
+ */
+ public long getFileTimestampGranularity() {
+ if (ON_WIN9X) {
+ return FAT_FILE_TIMESTAMP_GRANULARITY;
+ }
+ if (ON_WINDOWS) {
+ return NTFS_FILE_TIMESTAMP_GRANULARITY;
+ }
+ if (ON_DOS) {
+ return FAT_FILE_TIMESTAMP_GRANULARITY;
+ }
+ return UNIX_FILE_TIMESTAMP_GRANULARITY;
+ }
+
+ /**
+ * test whether a file or directory exists, with an error in the
+ * upper/lower case spelling of the name.
+ * Using this method is only interesting on case insensitive file systems
+ * (Windows).<br>
+ * It will return true only if 3 conditions are met :
+ * <br>
+ * <ul>
+ * <li>operating system is case insensitive</li>
+ * <li>file exists</li>
+ * <li>actual name from directory reading is different from the
+ * supplied argument</li>
+ * </ul>
+ * <br>
+ * the purpose is to identify files or directories on case-insensitive
+ * filesystems whose case is not what is expected.<br>
+ * Possibly to rename them afterwards to the desired upper/lowercase
+ * combination.
+ *
+ * @param localFile file to test
+ * @return true if the file exists and the case of the actual file
+ * is not the case of the parameter
+ * @since Ant 1.7.1
+ */
+ public boolean hasErrorInCase(File localFile) {
+ localFile = normalize(localFile.getAbsolutePath());
+ if (!localFile.exists()) {
+ return false;
+ }
+ final String localFileName = localFile.getName();
+ FilenameFilter ff = new FilenameFilter () {
+ public boolean accept(File dir, String name) {
+ return name.equalsIgnoreCase(localFileName) && (!name.equals(localFileName));
+ }
+ };
+ String[] names = localFile.getParentFile().list(ff);
+ return names != null && names.length == 1;
+ }
+
+ /**
+ * Returns true if the source is older than the dest.
+ * If the dest file does not exist, then the test returns false; it is
+ * implicitly not up do date.
+ * @param source source file (should be the older).
+ * @param dest dest file (should be the newer).
+ * @param granularity an offset added to the source time.
+ * @return true if the source is older than the dest after accounting
+ * for granularity.
+ * @since Ant 1.6.3
+ */
+ public boolean isUpToDate(File source, File dest, long granularity) {
+ //do a check for the destination file existing
+ if (!dest.exists()) {
+ //if it does not, then the file is not up to date.
+ return false;
+ }
+ long sourceTime = source.lastModified();
+ long destTime = dest.lastModified();
+ return isUpToDate(sourceTime, destTime, granularity);
+ }
+
+ /**
+ * Returns true if the source is older than the dest.
+ * @param source source file (should be the older).
+ * @param dest dest file (should be the newer).
+ * @return true if the source is older than the dest, taking the granularity into account.
+ * @since Ant 1.6.3
+ */
+ public boolean isUpToDate(File source, File dest) {
+ return isUpToDate(source, dest, getFileTimestampGranularity());
+ }
+
+ /**
+ * Compare two timestamps for being up to date using
+ * the specified granularity.
+ *
+ * @param sourceTime timestamp of source file.
+ * @param destTime timestamp of dest file.
+ * @param granularity os/filesys granularity.
+ * @return true if the dest file is considered up to date.
+ */
+ public boolean isUpToDate(long sourceTime, long destTime, long granularity) {
+ return destTime != -1 && destTime >= sourceTime + granularity;
+ }
+
+ /**
+ * Compare two timestamps for being up to date using the
+ * current granularity.
+ *
+ * @param sourceTime timestamp of source file.
+ * @param destTime timestamp of dest file.
+ * @return true if the dest file is considered up to date.
+ */
+ public boolean isUpToDate(long sourceTime, long destTime) {
+ return isUpToDate(sourceTime, destTime, getFileTimestampGranularity());
+ }
+
+ /**
+ * Close a Writer without throwing any exception if something went wrong.
+ * Do not attempt to close it if the argument is null.
+ * @param device output writer, can be null.
+ */
+ public static void close(Writer device) {
+ if (null != device) {
+ try {
+ device.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Close a Reader without throwing any exception if something went wrong.
+ * Do not attempt to close it if the argument is null.
+ *
+ * @param device Reader, can be null.
+ */
+ public static void close(Reader device) {
+ if (null != device) {
+ try {
+ device.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Close a stream without throwing any exception if something went wrong.
+ * Do not attempt to close it if the argument is null.
+ *
+ * @param device stream, can be null.
+ */
+ public static void close(OutputStream device) {
+ if (null != device) {
+ try {
+ device.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Close a stream without throwing any exception if something went wrong.
+ * Do not attempt to close it if the argument is null.
+ *
+ * @param device stream, can be null.
+ */
+ public static void close(InputStream device) {
+ if (null != device) {
+ try {
+ device.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Close a Channel without throwing any exception if something went wrong.
+ * Do not attempt to close it if the argument is null.
+ *
+ * @param device channel, can be null.
+ * @since Ant 1.8.0
+ */
+ public static void close(Channel device) {
+ if (null != device) {
+ try {
+ device.close();
+ } catch (IOException e) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Closes an URLConnection if its concrete implementation provides
+ * a way to close it that Ant knows of.
+ *
+ * @param conn connection, can be null
+ * @since Ant 1.8.0
+ */
+ public static void close(URLConnection conn) {
+ if (conn != null) {
+ try {
+ if (conn instanceof JarURLConnection) {
+ JarURLConnection juc = (JarURLConnection) conn;
+ JarFile jf = juc.getJarFile();
+ jf.close();
+ jf = null;
+ } else if (conn instanceof HttpURLConnection) {
+ ((HttpURLConnection) conn).disconnect();
+ }
+ } catch (IOException exc) {
+ //ignore
+ }
+ }
+ }
+
+ /**
+ * Delete the file with {@link File#delete()} if the argument is not null.
+ * Do nothing on a null argument.
+ * @param file file to delete.
+ */
+ public static void delete(File file) {
+ if (file != null) {
+ file.delete();
+ }
+ }
+
+ /**
+ * Accommodate Windows bug encountered in both Sun and IBM JDKs.
+ * Others possible. If the delete does not work, call System.gc(),
+ * wait a little and try again.
+ *
+ * @return whether deletion was successful
+ * @since Ant 1.8.0
+ */
+ public boolean tryHardToDelete(File f) {
+ return tryHardToDelete(f, ON_WINDOWS);
+ }
+
+ /**
+ * If delete does not work, call System.gc() if asked to, wait a
+ * little and try again.
+ *
+ * @return whether deletion was successful
+ * @since Ant 1.8.3
+ */
+ public boolean tryHardToDelete(File f, boolean runGC) {
+ if (!f.delete()) {
+ if (runGC) {
+ System.gc();
+ }
+ try {
+ Thread.sleep(DELETE_RETRY_SLEEP_MILLIS);
+ } catch (InterruptedException ex) {
+ // Ignore Exception
+ }
+ return f.delete();
+ }
+ return true;
+ }
+
+ /**
+ * Calculates the relative path between two files.
+ * <p>
+ * Implementation note:<br>This function may throw an IOException if an I/O error occurs
+ * because its use of the canonical pathname may require filesystem queries.
+ * </p>
+ *
+ * @param fromFile the <code>File</code> to calculate the path from
+ * @param toFile the <code>File</code> to calculate the path to
+ * @return the relative path between the files
+ * @throws Exception for undocumented reasons
+ * @see File#getCanonicalPath()
+ *
+ * @since Ant 1.7
+ */
+ public static String getRelativePath(File fromFile, File toFile) throws Exception {
+ String fromPath = fromFile.getCanonicalPath();
+ String toPath = toFile.getCanonicalPath();
+
+ // build the path stack info to compare
+ String[] fromPathStack = getPathStack(fromPath);
+ String[] toPathStack = getPathStack(toPath);
+
+ if (0 < toPathStack.length && 0 < fromPathStack.length) {
+ if (!fromPathStack[0].equals(toPathStack[0])) {
+ // not the same device (would be "" on Linux/Unix)
+
+ return getPath(Arrays.asList(toPathStack));
+ }
+ } else {
+ // no comparison possible
+ return getPath(Arrays.asList(toPathStack));
+ }
+
+ int minLength = Math.min(fromPathStack.length, toPathStack.length);
+ int same = 1; // Used outside the for loop
+
+ // get index of parts which are equal
+ for (;
+ same < minLength && fromPathStack[same].equals(toPathStack[same]);
+ same++) {
+ // Do nothing
+ }
+
+ List relativePathStack = new ArrayList();
+
+ // if "from" part is longer, fill it up with ".."
+ // to reach path which is equal to both paths
+ for (int i = same; i < fromPathStack.length; i++) {
+ relativePathStack.add("..");
+ }
+
+ // fill it up path with parts which were not equal
+ for (int i = same; i < toPathStack.length; i++) {
+ relativePathStack.add(toPathStack[i]);
+ }
+
+ return getPath(relativePathStack);
+ }
+
+ /**
+ * Gets all names of the path as an array of <code>String</code>s.
+ *
+ * @param path to get names from
+ * @return <code>String</code>s, never <code>null</code>
+ *
+ * @since Ant 1.7
+ */
+ public static String[] getPathStack(String path) {
+ String normalizedPath = path.replace(File.separatorChar, '/');
+
+ return normalizedPath.split("/");
+ }
+
+ /**
+ * Gets path from a <code>List</code> of <code>String</code>s.
+ *
+ * @param pathStack <code>List</code> of <code>String</code>s to be concatenated as a path.
+ * @return <code>String</code>, never <code>null</code>
+ *
+ * @since Ant 1.7
+ */
+ public static String getPath(List pathStack) {
+ // can safely use '/' because Windows understands '/' as separator
+ return getPath(pathStack, '/');
+ }
+
+ /**
+ * Gets path from a <code>List</code> of <code>String</code>s.
+ *
+ * @param pathStack <code>List</code> of <code>String</code>s to be concated as a path.
+ * @param separatorChar <code>char</code> to be used as separator between names in path
+ * @return <code>String</code>, never <code>null</code>
+ *
+ * @since Ant 1.7
+ */
+ public static String getPath(final List pathStack, final char separatorChar) {
+ final StringBuffer buffer = new StringBuffer();
+
+ final Iterator iter = pathStack.iterator();
+ if (iter.hasNext()) {
+ buffer.append(iter.next());
+ }
+ while (iter.hasNext()) {
+ buffer.append(separatorChar);
+ buffer.append(iter.next());
+ }
+ return buffer.toString();
+ }
+
+ /**
+ * Get the default encoding.
+ * This is done by opening an InputStreamReader on
+ * a dummy InputStream and getting the encoding.
+ * Could use System.getProperty("file.encoding"), but cannot
+ * see where this is documented.
+ * @return the default file encoding.
+ */
+ public String getDefaultEncoding() {
+ InputStreamReader is = new InputStreamReader(
+ new InputStream() {
+ public int read() {
+ return -1;
+ }
+ });
+ try {
+ return is.getEncoding();
+ } finally {
+ close(is);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FirstMatchMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FirstMatchMapper.java
new file mode 100644
index 00000000..b0e47f29
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FirstMatchMapper.java
@@ -0,0 +1,45 @@
+/*
+ * 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.util;
+
+import java.util.Iterator;
+
+/**
+ * A <code>ContainerMapper</code> that returns the results of its
+ * first constituent <code>FileNameMapper</code>s that matches.
+ *
+ * @since Ant 1.8.0
+ */
+public class FirstMatchMapper extends ContainerMapper {
+
+ /** {@inheritDoc}. */
+ public String[] mapFileName(String sourceFileName) {
+ for (Iterator iter = getMappers().iterator(); iter.hasNext();) {
+ FileNameMapper mapper = (FileNameMapper) iter.next();
+ if (mapper != null) {
+ String[] mapped = mapper.mapFileName(sourceFileName);
+ if (mapped != null) {
+ return mapped;
+ }
+ }
+ }
+ return null;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FlatFileNameMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FlatFileNameMapper.java
new file mode 100644
index 00000000..420ccc6c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/FlatFileNameMapper.java
@@ -0,0 +1,54 @@
+/*
+ * 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.util;
+
+/**
+ * Implementation of FileNameMapper that always returns the source
+ * file name without any leading directory information.
+ *
+ * <p>This is the default FileNameMapper for the copy and move
+ * tasks if the flatten attribute has been set.</p>
+ *
+ */
+public class FlatFileNameMapper implements FileNameMapper {
+
+ /**
+ * Ignored.
+ * @param from ignored.
+ */
+ public void setFrom(String from) {
+ }
+
+ /**
+ * Ignored.
+ * @param to ignored.
+ */
+ public void setTo(String to) {
+ }
+
+ /**
+ * Returns an one-element array containing the source file name
+ * without any leading directory information.
+ * @param sourceFileName the name to map.
+ * @return the file name in a one-element array.
+ */
+ public String[] mapFileName(String sourceFileName) {
+ return new String[] {new java.io.File(sourceFileName).getName()};
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/GlobPatternMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/GlobPatternMapper.java
new file mode 100644
index 00000000..da2a0f16
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/GlobPatternMapper.java
@@ -0,0 +1,203 @@
+/*
+ * 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.util;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Implementation of FileNameMapper that does simple wildcard pattern
+ * replacements.
+ *
+ * <p>This does simple translations like *.foo -&gt; *.bar where the
+ * prefix to .foo will be left unchanged. It only handles a single *
+ * character, use regular expressions for more complicated
+ * situations.</p>
+ *
+ * <p>This is one of the more useful Mappers, it is used by javac for
+ * example.</p>
+ *
+ */
+public class GlobPatternMapper implements FileNameMapper {
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ /**
+ * Part of &quot;from&quot; pattern before the *.
+ */
+ protected String fromPrefix = null;
+
+ /**
+ * Part of &quot;from&quot; pattern after the *.
+ */
+ protected String fromPostfix = null;
+
+ /**
+ * Length of the prefix (&quot;from&quot; pattern).
+ */
+ protected int prefixLength;
+
+ /**
+ * Length of the postfix (&quot;from&quot; pattern).
+ */
+ protected int postfixLength;
+
+ /**
+ * Part of &quot;to&quot; pattern before the *.
+ */
+ protected String toPrefix = null;
+
+ /**
+ * Part of &quot;to&quot; pattern after the *.
+ */
+ protected String toPostfix = null;
+
+ // CheckStyle:VisibilityModifier ON
+
+ private boolean fromContainsStar = false;
+ private boolean toContainsStar = false;
+ private boolean handleDirSep = false;
+ private boolean caseSensitive = true;
+
+ /**
+ * Attribute specifying whether to ignore the difference
+ * between / and \ (the two common directory characters).
+ * @param handleDirSep a boolean, default is false.
+ * @since Ant 1.6.3
+ */
+ public void setHandleDirSep(boolean handleDirSep) {
+ this.handleDirSep = handleDirSep;
+ }
+
+ /**
+ * Attribute specifying whether to ignore the difference
+ * between / and \ (the two common directory characters).
+ * @since Ant 1.8.3
+ */
+ public boolean getHandleDirSep() {
+ return handleDirSep;
+ }
+
+ /**
+ * Attribute specifying whether to ignore the case difference
+ * in the names.
+ *
+ * @param caseSensitive a boolean, default is false.
+ * @since Ant 1.6.3
+ */
+ public void setCaseSensitive(boolean caseSensitive) {
+ this.caseSensitive = caseSensitive;
+ }
+
+ /**
+ * Sets the &quot;from&quot; pattern. Required.
+ * @param from a string
+ */
+ public void setFrom(String from) {
+ if (from != null) {
+ int index = from.lastIndexOf("*");
+ if (index == -1) {
+ fromPrefix = from;
+ fromPostfix = "";
+ } else {
+ fromPrefix = from.substring(0, index);
+ fromPostfix = from.substring(index + 1);
+ fromContainsStar = true;
+ }
+ prefixLength = fromPrefix.length();
+ postfixLength = fromPostfix.length();
+ } else {
+ throw new BuildException("this mapper requires a 'from' attribute");
+ }
+ }
+
+ /**
+ * Sets the &quot;to&quot; pattern. Required.
+ * @param to a string
+ */
+ public void setTo(String to) {
+ if (to != null) {
+ int index = to.lastIndexOf("*");
+ if (index == -1) {
+ toPrefix = to;
+ toPostfix = "";
+ } else {
+ toPrefix = to.substring(0, index);
+ toPostfix = to.substring(index + 1);
+ toContainsStar = true;
+ }
+ } else {
+ throw new BuildException("this mapper requires a 'to' attribute");
+ }
+ }
+
+ /**
+ * Returns null if the source file name doesn't match the
+ * &quot;from&quot; pattern, an one-element array containing the
+ * translated file otherwise.
+ * @param sourceFileName the filename to map
+ * @return a list of converted filenames
+ */
+ public String[] mapFileName(String sourceFileName) {
+ String modName = modifyName(sourceFileName);
+ if (fromPrefix == null
+ || (sourceFileName.length() < (prefixLength + postfixLength))
+ || (!fromContainsStar
+ && !modName.equals(modifyName(fromPrefix))
+ )
+ || (fromContainsStar
+ && (!modName.startsWith(modifyName(fromPrefix))
+ || !modName.endsWith(modifyName(fromPostfix)))
+ )
+ ) {
+ return null;
+ }
+ return new String[] {toPrefix
+ + (toContainsStar
+ ? extractVariablePart(sourceFileName)
+ + toPostfix
+ : "")};
+ }
+
+ /**
+ * Returns the part of the given string that matches the * in the
+ * &quot;from&quot; pattern.
+ * @param name the source file name
+ * @return the variable part of the name
+ */
+ protected String extractVariablePart(String name) {
+ return name.substring(prefixLength,
+ name.length() - postfixLength);
+ }
+
+ /**
+ * modify string based on dir char mapping and case sensitivity
+ * @param name the name to convert
+ * @return the converted name
+ */
+ private String modifyName(String name) {
+ if (!caseSensitive) {
+ name = name.toLowerCase();
+ }
+ if (handleDirSep) {
+ if (name.indexOf('\\') != -1) {
+ name = name.replace('\\', '/');
+ }
+ }
+ return name;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/IdentityMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/IdentityMapper.java
new file mode 100644
index 00000000..22c6c7ea
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/IdentityMapper.java
@@ -0,0 +1,52 @@
+/*
+ * 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.util;
+
+/**
+ * Implementation of FileNameMapper that always returns the source file name.
+ *
+ * <p>This is the default FileNameMapper for the copy and move
+ * tasks.</p>
+ *
+ */
+public class IdentityMapper implements FileNameMapper {
+
+ /**
+ * Ignored.
+ * @param from ignored.
+ */
+ public void setFrom(String from) {
+ }
+
+ /**
+ * Ignored.
+ * @param to ignored.
+ */
+ public void setTo(String to) {
+ }
+
+ /**
+ * Returns an one-element array containing the source file name.
+ * @param sourceFileName the name to map.
+ * @return the source filename in a one-element array.
+ */
+ public String[] mapFileName(String sourceFileName) {
+ return new String[] {sourceFileName};
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/IdentityStack.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/IdentityStack.java
new file mode 100644
index 00000000..ac806d78
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/IdentityStack.java
@@ -0,0 +1,130 @@
+/*
+ * 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.util;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.IdentityHashMap;
+import java.util.Set;
+import java.util.Stack;
+
+/**
+ * Identity Stack.
+ * @since Ant 1.7
+ */
+public class IdentityStack<E> extends Stack<E> {
+
+ private static final long serialVersionUID = -5555522620060077046L;
+
+ /**
+ * Get an IdentityStack containing the contents of the specified Stack.
+ * @param s the Stack to copy; ignored if null.
+ * @return an IdentityStack instance.
+ */
+ public static <E> IdentityStack<E> getInstance(Stack<E> s) {
+ if (s instanceof IdentityStack) {
+ return (IdentityStack<E>) s;
+ }
+ IdentityStack<E> result = new IdentityStack<E>();
+ if (s != null) {
+ result.addAll(s);
+ }
+ return result;
+ }
+
+ /**
+ * Default constructor.
+ */
+ public IdentityStack() {
+ }
+
+ /**
+ * Construct a new IdentityStack with the specified Object
+ * as the bottom element.
+ * @param o the bottom element.
+ */
+ public IdentityStack(E o) {
+ super();
+ push(o);
+ }
+
+ /**
+ * Override methods that use <code>.equals()</code> comparisons on elements.
+ * @param o the Object to search for.
+ * @return true if the stack contains the object.
+ * @see java.util.Vector#contains(Object)
+ */
+ public synchronized boolean contains(Object o) {
+ return indexOf(o) >= 0;
+ }
+
+ /**
+ * Override methods that use <code>.equals()</code> comparisons on elements.
+ * @param o the Object to search for.
+ * @param pos the position from which to search.
+ * @return the position of the object, -1 if not found.
+ * @see java.util.Vector#indexOf(Object, int)
+ */
+ public synchronized int indexOf(Object o, int pos) {
+ final int size = size();
+ for (int i = pos; i < size; i++) {
+ if (get(i) == o) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Override methods that use <code>.equals()</code> comparisons on elements.
+ * @param o the Object to search for.
+ * @param pos the position from which to search (backward).
+ * @return the position of the object, -1 if not found.
+ * @see java.util.Vector#indexOf(Object, int)
+ */
+ public synchronized int lastIndexOf(Object o, int pos) {
+ for (int i = pos; i >= 0; i--) {
+ if (get(i) == o) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ public synchronized boolean removeAll(Collection<?> c) {
+ if (!(c instanceof Set)) {
+ c = new HashSet(c);
+ }
+ return super.removeAll(c);
+ }
+
+ public synchronized boolean retainAll(Collection c) {
+ if (!(c instanceof Set)) {
+ c = new HashSet(c);
+ }
+ return super.retainAll(c);
+ }
+
+ public synchronized boolean containsAll(Collection<?> c) {
+ IdentityHashMap map = new IdentityHashMap();
+ for (Object e : this) {
+ map.put(e, Boolean.TRUE);
+ }
+ return map.keySet().containsAll(c);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/JAXPUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/JAXPUtils.java
new file mode 100644
index 00000000..76460ae2
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/JAXPUtils.java
@@ -0,0 +1,260 @@
+/*
+ * 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.util;
+
+import java.io.File;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+
+import org.apache.tools.ant.BuildException;
+import org.xml.sax.Parser;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * Collection of helper methods that retrieve a ParserFactory or
+ * Parsers and Readers.
+ *
+ * <p>This class will create only a single factory instance.</p>
+ *
+ * @since Ant 1.5
+ */
+public class JAXPUtils {
+
+ /**
+ * Helper for systemId.
+ *
+ * @since Ant 1.6
+ */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /**
+ * Parser factory to use to create parsers.
+ * @see #getParserFactory
+ *
+ * @since Ant 1.5
+ */
+ private static SAXParserFactory parserFactory = null;
+
+ /**
+ * Parser Factory to create Namespace aware parsers.
+ *
+ * @since Ant 1.6
+ */
+ private static SAXParserFactory nsParserFactory = null;
+
+ /**
+ * Parser factory to use to create document builders.
+ *
+ * @since Ant 1.6
+ */
+ private static DocumentBuilderFactory builderFactory = null;
+
+ /**
+ * Returns the parser factory to use. Only one parser factory is
+ * ever created by this method and is then cached for future use.
+ *
+ * @return a SAXParserFactory to use.
+ * @throws BuildException on error.
+ *
+ * @since Ant 1.5
+ */
+ public static synchronized SAXParserFactory getParserFactory()
+ throws BuildException {
+
+ if (parserFactory == null) {
+ parserFactory = newParserFactory();
+ }
+ return parserFactory;
+ }
+
+ /**
+ * Returns the parser factory to use to create namespace aware parsers.
+ *
+ * @return a SAXParserFactory to use which supports manufacture of
+ * namespace aware parsers.
+ * @throws BuildException on error.
+ *
+ * @since Ant 1.6
+ */
+ public static synchronized SAXParserFactory getNSParserFactory()
+ throws BuildException {
+
+ if (nsParserFactory == null) {
+ nsParserFactory = newParserFactory();
+ nsParserFactory.setNamespaceAware(true);
+ }
+ return nsParserFactory;
+ }
+
+ /**
+ * Returns a new parser factory instance.
+ *
+ * @return the parser factory.
+ * @throws BuildException on error.
+ * @since Ant 1.5
+ */
+ public static SAXParserFactory newParserFactory() throws BuildException {
+
+ try {
+ return SAXParserFactory.newInstance();
+ } catch (FactoryConfigurationError e) {
+ throw new BuildException("XML parser factory has not been "
+ + "configured correctly: "
+ + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Returns a newly created SAX 1 Parser, using the default parser
+ * factory.
+ *
+ * @return a SAX 1 Parser.
+ * @throws BuildException on error.
+ * @see #getParserFactory
+ * @since Ant 1.5
+ */
+ public static Parser getParser() throws BuildException {
+ try {
+ return newSAXParser(getParserFactory()).getParser();
+ } catch (SAXException e) {
+ throw convertToBuildException(e);
+ }
+ }
+
+ /**
+ * Returns a newly created SAX 2 XMLReader, using the default parser
+ * factory.
+ *
+ * @return a SAX 2 XMLReader.
+ * @throws BuildException on error.
+ * @see #getParserFactory
+ * @since Ant 1.5
+ */
+ public static XMLReader getXMLReader() throws BuildException {
+ try {
+ return newSAXParser(getParserFactory()).getXMLReader();
+ } catch (SAXException e) {
+ throw convertToBuildException(e);
+ }
+ }
+
+ /**
+ * Returns a newly created SAX 2 XMLReader, which is namespace aware
+ *
+ * @return a SAX 2 XMLReader.
+ * @throws BuildException on error.
+ * @see #getParserFactory
+ * @since Ant 1.6
+ */
+ public static XMLReader getNamespaceXMLReader() throws BuildException {
+ try {
+ return newSAXParser(getNSParserFactory()).getXMLReader();
+ } catch (SAXException e) {
+ throw convertToBuildException(e);
+ }
+ }
+
+ /**
+ * This is a best attempt to provide a URL.toExternalForm() from
+ * a file URL. Some parsers like Crimson choke on uri that are made of
+ * backslashed paths (ie windows) as it is does not conform
+ * URI specifications.
+ * @param file the file to create the system id from.
+ * @return the systemid corresponding to the given file.
+ * @since Ant 1.5.2
+ */
+ public static String getSystemId(File file) {
+ return FILE_UTILS.toURI(file.getAbsolutePath());
+ }
+
+ /**
+ * Returns a newly created DocumentBuilder.
+ *
+ * @return a DocumentBuilder.
+ * @throws BuildException on error.
+ * @since Ant 1.6
+ */
+ public static DocumentBuilder getDocumentBuilder() throws BuildException {
+ try {
+ return getDocumentBuilderFactory().newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * @return a new SAXParser instance as helper for getParser and
+ * getXMLReader.
+ *
+ * @since Ant 1.5
+ */
+ private static SAXParser newSAXParser(SAXParserFactory factory)
+ throws BuildException {
+ try {
+ return factory.newSAXParser();
+ } catch (ParserConfigurationException e) {
+ throw new BuildException("Cannot create parser for the given "
+ + "configuration: " + e.getMessage(), e);
+ } catch (SAXException e) {
+ throw convertToBuildException(e);
+ }
+ }
+
+ /**
+ * Translate a SAXException into a BuildException
+ *
+ * @since Ant 1.5
+ */
+ private static BuildException convertToBuildException(SAXException e) {
+ Exception nested = e.getException();
+ if (nested != null) {
+ return new BuildException(nested);
+ } else {
+ return new BuildException(e);
+ }
+ }
+
+ /**
+ * Obtains the default builder factory if not already.
+ *
+ * @since Ant 1.6
+ */
+ private static synchronized
+ DocumentBuilderFactory getDocumentBuilderFactory()
+ throws BuildException {
+ if (builderFactory == null) {
+ try {
+ builderFactory = DocumentBuilderFactory.newInstance();
+ } catch (FactoryConfigurationError e) {
+ throw new BuildException("Document builder factory has not "
+ + "been configured correctly: "
+ + e.getMessage(), e);
+ }
+ }
+ return builderFactory;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/JavaEnvUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/JavaEnvUtils.java
new file mode 100644
index 00000000..df778208
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/JavaEnvUtils.java
@@ -0,0 +1,573 @@
+/*
+ * 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.util;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Vector;
+
+import org.apache.tools.ant.taskdefs.condition.Os;
+
+/**
+ * A set of helper methods related to locating executables or checking
+ * conditions of a given Java installation.
+ *
+ * @since Ant 1.5
+ */
+public final class JavaEnvUtils {
+
+ private JavaEnvUtils() {
+ }
+
+ /** Are we on a DOS-based system */
+ private static final boolean IS_DOS = Os.isFamily("dos");
+ /** Are we on Novell NetWare */
+ private static final boolean IS_NETWARE = Os.isName("netware");
+ /** Are we on AIX */
+ private static final boolean IS_AIX = Os.isName("aix");
+
+ /** shortcut for System.getProperty("java.home") */
+ private static final String JAVA_HOME = System.getProperty("java.home");
+
+ /** FileUtils instance for path normalization */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /** Version of currently running VM. */
+ private static String javaVersion;
+
+ /** floating version of the JVM */
+ private static int javaVersionNumber;
+
+ /** Version constant for Java 1.0 */
+ public static final String JAVA_1_0 = "1.0";
+ /** Number Version constant for Java 1.0 */
+ public static final int VERSION_1_0 = 10;
+
+ /** Version constant for Java 1.1 */
+ public static final String JAVA_1_1 = "1.1";
+ /** Number Version constant for Java 1.1 */
+ public static final int VERSION_1_1 = 11;
+
+ /** Version constant for Java 1.2 */
+ public static final String JAVA_1_2 = "1.2";
+ /** Number Version constant for Java 1.2 */
+ public static final int VERSION_1_2 = 12;
+
+ /** Version constant for Java 1.3 */
+ public static final String JAVA_1_3 = "1.3";
+ /** Number Version constant for Java 1.3 */
+ public static final int VERSION_1_3 = 13;
+
+ /** Version constant for Java 1.4 */
+ public static final String JAVA_1_4 = "1.4";
+ /** Number Version constant for Java 1.4 */
+ public static final int VERSION_1_4 = 14;
+
+ /** Version constant for Java 1.5 */
+ public static final String JAVA_1_5 = "1.5";
+ /** Number Version constant for Java 1.5 */
+ public static final int VERSION_1_5 = 15;
+
+ /** Version constant for Java 1.6 */
+ public static final String JAVA_1_6 = "1.6";
+ /** Number Version constant for Java 1.6 */
+ public static final int VERSION_1_6 = 16;
+
+ /** Version constant for Java 1.7 */
+ public static final String JAVA_1_7 = "1.7";
+ /** Number Version constant for Java 1.7 */
+ public static final int VERSION_1_7 = 17;
+
+ /** Version constant for Java 1.8 */
+ public static final String JAVA_1_8 = "1.8";
+ /** Number Version constant for Java 1.8 */
+ public static final int VERSION_1_8 = 18;
+
+ /** Version constant for Java 1.9 */
+ public static final String JAVA_1_9 = "1.9";
+ /** Number Version constant for Java 1.9 */
+ public static final int VERSION_1_9 = 19;
+
+ /** Whether this is the Kaffe VM */
+ private static boolean kaffeDetected;
+
+ /** Wheter this is a GNU Classpath based VM */
+ private static boolean classpathDetected;
+
+ /** Whether this is the GNU VM (gcj/gij) */
+ private static boolean gijDetected;
+
+ /** Whether this is Apache Harmony */
+ private static boolean harmonyDetected;
+
+ /** array of packages in the runtime */
+ private static Vector<String> jrePackages;
+
+
+ static {
+
+ // Determine the Java version by looking at available classes
+ // java.net.Proxy was introduced in JDK 1.5
+ // java.lang.CharSequence was introduced in JDK 1.4
+ // java.lang.StrictMath was introduced in JDK 1.3
+ // java.lang.ThreadLocal was introduced in JDK 1.2
+ // java.lang.Void was introduced in JDK 1.1
+ // Count up version until a NoClassDefFoundError ends the try
+
+ try {
+ javaVersion = JAVA_1_0;
+ javaVersionNumber = VERSION_1_0;
+ Class.forName("java.lang.Void");
+ javaVersion = JAVA_1_1;
+ javaVersionNumber++;
+ Class.forName("java.lang.ThreadLocal");
+ javaVersion = JAVA_1_2;
+ javaVersionNumber++;
+ Class.forName("java.lang.StrictMath");
+ javaVersion = JAVA_1_3;
+ javaVersionNumber++;
+ Class.forName("java.lang.CharSequence");
+ javaVersion = JAVA_1_4;
+ javaVersionNumber++;
+ Class.forName("java.net.Proxy");
+ javaVersion = JAVA_1_5;
+ javaVersionNumber++;
+ Class.forName("java.net.CookieStore");
+ javaVersion = JAVA_1_6;
+ javaVersionNumber++;
+ Class.forName("java.nio.file.FileSystem");
+ javaVersion = JAVA_1_7;
+ javaVersionNumber++;
+ Class.forName("java.lang.reflect.Executable");
+ javaVersion = JAVA_1_8;
+ javaVersionNumber++;
+ checkForJava9();
+ javaVersion = JAVA_1_9;
+ javaVersionNumber++;
+ } catch (Throwable t) {
+ // swallow as we've hit the max class version that
+ // we have
+ }
+ kaffeDetected = false;
+ try {
+ Class.forName("kaffe.util.NotImplemented");
+ kaffeDetected = true;
+ } catch (Throwable t) {
+ // swallow as this simply doesn't seem to be Kaffe
+ }
+ classpathDetected = false;
+ try {
+ Class.forName("gnu.classpath.Configuration");
+ classpathDetected = true;
+ } catch (Throwable t) {
+ // swallow as this simply doesn't seem to be GNU classpath based.
+ }
+ gijDetected = false;
+ try {
+ Class.forName("gnu.gcj.Core");
+ gijDetected = true;
+ } catch (Throwable t) {
+ // swallow as this simply doesn't seem to be gcj/gij
+ }
+ harmonyDetected = false;
+ try {
+ Class.forName("org.apache.harmony.luni.util.Base64");
+ harmonyDetected = true;
+ } catch (Throwable t) {
+ // swallow as this simply doesn't seem to be Apache Harmony
+ }
+ }
+
+ /**
+ * Returns the version of Java this class is running under.
+ * @return the version of Java as a String, e.g. "1.6"
+ */
+ public static String getJavaVersion() {
+ return javaVersion;
+ }
+
+
+ /**
+ * Checks for a give Java 9 runtime.
+ * At the time of writing the actual version of the JDK was 1.9.0_b06.
+ * Searching for new classes gave no hits, so we need another aproach.
+ * Searching for changes (grep -r -i -n "@since 1.9" .) in the sources gave
+ * only one hit: a new constant in the class SourceVersion.
+ * So we have to check that ...
+ *
+ * @throws Exception if we can't load the class or don't find the new constant.
+ * This is the behavior when searching for new features on older versions.
+ * @since Ant 1.9.4
+ */
+ private static void checkForJava9() throws Exception {
+ Class<?> clazz = Class.forName("javax.lang.model.SourceVersion");
+ clazz.getDeclaredField("RELEASE_9");
+ }
+
+
+ /**
+ * Returns the version of Java this class is running under.
+ * This number can be used for comparisons; it will always be
+ * @return the version of Java as a number 10x the major/minor,
+ * e.g Java1.5 has a value of 15
+ */
+ public static int getJavaVersionNumber() {
+ return javaVersionNumber;
+ }
+
+ /**
+ * Compares the current Java version to the passed in String -
+ * assumes the argument is one of the constants defined in this
+ * class.
+ * Note that Ant now requires JDK 1.5+ so {@link #JAVA_1_0} through
+ * {@link #JAVA_1_4} need no longer be tested for.
+ * @param version the version to check against the current version.
+ * @return true if the version of Java is the same as the given version.
+ * @since Ant 1.5
+ */
+ public static boolean isJavaVersion(String version) {
+ return javaVersion.equals(version);
+ }
+
+ /**
+ * Compares the current Java version to the passed in String -
+ * assumes the argument is one of the constants defined in this
+ * class.
+ * Note that Ant now requires JDK 1.5+ so {@link #JAVA_1_0} through
+ * {@link #JAVA_1_4} need no longer be tested for.
+ * @param version the version to check against the current version.
+ * @return true if the version of Java is the same or higher than the
+ * given version.
+ * @since Ant 1.7
+ */
+ public static boolean isAtLeastJavaVersion(String version) {
+ return javaVersion.compareTo(version) >= 0;
+ }
+
+ /**
+ * Checks whether the current Java VM is Kaffe.
+ * @return true if the current Java VM is Kaffe.
+ * @since Ant 1.6.3
+ * @see <a href="http://www.kaffe.org/">http://www.kaffe.org/</a>
+ */
+ public static boolean isKaffe() {
+ return kaffeDetected;
+ }
+
+ /**
+ * Checks whether the current Java VM is GNU Classpath
+ * @since Ant 1.9.1
+ * @return true if the version of Java is GNU Classpath
+ */
+ public static boolean isClasspathBased() {
+ return classpathDetected;
+ }
+
+ /**
+ * Checks whether the current Java VM is the GNU interpreter gij
+ * or we are running in a gcj precompiled binary.
+ * @since Ant 1.8.2
+ * @return true if the current Java VM is gcj/gij.
+ */
+ public static boolean isGij() {
+ return gijDetected;
+ }
+
+ /**
+ * Checks whether the current VM is Apache Harmony.
+ * @since Ant 1.8.2
+ * @return true if the current VM is Apache Harmony.
+ */
+ public static boolean isApacheHarmony() {
+ return harmonyDetected;
+ }
+
+ /**
+ * Finds an executable that is part of a JRE installation based on
+ * the java.home system property.
+ *
+ * <p><code>java</code>, <code>keytool</code>,
+ * <code>policytool</code>, <code>orbd</code>, <code>rmid</code>,
+ * <code>rmiregistry</code>, <code>servertool</code> and
+ * <code>tnameserv</code> are JRE executables on Sun based
+ * JRE's.</p>
+ *
+ * <p>You typically find them in <code>JAVA_HOME/jre/bin</code> if
+ * <code>JAVA_HOME</code> points to your JDK installation. JDK
+ * &lt; 1.2 has them in the same directory as the JDK
+ * executables.</p>
+ * @param command the java executable to find.
+ * @return the path to the command.
+ * @since Ant 1.5
+ */
+ public static String getJreExecutable(String command) {
+ if (IS_NETWARE) {
+ // Extrapolating from:
+ // "NetWare may have a "java" in that directory, but 99% of
+ // the time, you don't want to execute it" -- Jeff Tulley
+ // <JTULLEY@novell.com>
+ return command;
+ }
+
+ File jExecutable = null;
+
+ if (IS_AIX) {
+ // On IBM's JDK 1.2 the directory layout is different, 1.3 follows
+ // Sun's layout.
+ jExecutable = findInDir(JAVA_HOME + "/sh", command);
+ }
+
+ if (jExecutable == null) {
+ jExecutable = findInDir(JAVA_HOME + "/bin", command);
+ }
+
+ if (jExecutable != null) {
+ return jExecutable.getAbsolutePath();
+ } else {
+ // Unfortunately on Windows java.home doesn't always refer
+ // to the correct location, so we need to fall back to
+ // assuming java is somewhere on the PATH.
+ return addExtension(command);
+ }
+ }
+
+ /**
+ * Finds an executable that is part of a JDK installation based on
+ * the java.home system property.
+ *
+ * <p>You typically find them in <code>JAVA_HOME/bin</code> if
+ * <code>JAVA_HOME</code> points to your JDK installation.</p>
+ * @param command the java executable to find.
+ * @return the path to the command.
+ * @since Ant 1.5
+ */
+ public static String getJdkExecutable(String command) {
+ if (IS_NETWARE) {
+ // Extrapolating from:
+ // "NetWare may have a "java" in that directory, but 99% of
+ // the time, you don't want to execute it" -- Jeff Tulley
+ // <JTULLEY@novell.com>
+ return command;
+ }
+
+ File jExecutable = null;
+
+ if (IS_AIX) {
+ // On IBM's JDK 1.2 the directory layout is different, 1.3 follows
+ // Sun's layout.
+ jExecutable = findInDir(JAVA_HOME + "/../sh", command);
+ }
+
+ if (jExecutable == null) {
+ jExecutable = findInDir(JAVA_HOME + "/../bin", command);
+ }
+
+ if (jExecutable != null) {
+ return jExecutable.getAbsolutePath();
+ } else {
+ // fall back to JRE bin directory, also catches JDK 1.0 and 1.1
+ // where java.home points to the root of the JDK and Mac OS X where
+ // the whole directory layout is different from Sun's
+ // and also catches JDK 1.9 (and probably later) which
+ // merged JDK and JRE dirs
+ return getJreExecutable(command);
+ }
+ }
+
+ /**
+ * Adds a system specific extension to the name of an executable.
+ *
+ * @since Ant 1.5
+ */
+ private static String addExtension(String command) {
+ // This is the most common extension case - exe for windows and OS/2,
+ // nothing for *nix.
+ return command + (IS_DOS ? ".exe" : "");
+ }
+
+ /**
+ * Look for an executable in a given directory.
+ *
+ * @return null if the executable cannot be found.
+ */
+ private static File findInDir(String dirName, String commandName) {
+ File dir = FILE_UTILS.normalize(dirName);
+ File executable = null;
+ if (dir.exists()) {
+ executable = new File(dir, addExtension(commandName));
+ if (!executable.exists()) {
+ executable = null;
+ }
+ }
+ return executable;
+ }
+
+ /**
+ * demand creation of the package list.
+ * When you add a new package, add a new test below.
+ */
+
+ private static void buildJrePackages() {
+ jrePackages = new Vector<String>();
+ switch(javaVersionNumber) {
+ case VERSION_1_9:
+ case VERSION_1_8:
+ case VERSION_1_7:
+ case VERSION_1_6:
+ case VERSION_1_5:
+ //In Java1.5, the apache stuff moved.
+ jrePackages.addElement("com.sun.org.apache");
+ //fall through.
+ case VERSION_1_4:
+ if (javaVersionNumber == VERSION_1_4) {
+ jrePackages.addElement("org.apache.crimson");
+ jrePackages.addElement("org.apache.xalan");
+ jrePackages.addElement("org.apache.xml");
+ jrePackages.addElement("org.apache.xpath");
+ }
+ jrePackages.addElement("org.ietf.jgss");
+ jrePackages.addElement("org.w3c.dom");
+ jrePackages.addElement("org.xml.sax");
+ // fall through
+ case VERSION_1_3:
+ jrePackages.addElement("org.omg");
+ jrePackages.addElement("com.sun.corba");
+ jrePackages.addElement("com.sun.jndi");
+ jrePackages.addElement("com.sun.media");
+ jrePackages.addElement("com.sun.naming");
+ jrePackages.addElement("com.sun.org.omg");
+ jrePackages.addElement("com.sun.rmi");
+ jrePackages.addElement("sunw.io");
+ jrePackages.addElement("sunw.util");
+ // fall through
+ case VERSION_1_2:
+ jrePackages.addElement("com.sun.java");
+ jrePackages.addElement("com.sun.image");
+ // are there any here that we forgot?
+ // fall through
+ case VERSION_1_1:
+ default:
+ //things like sun.reflection, sun.misc, sun.net
+ jrePackages.addElement("sun");
+ jrePackages.addElement("java");
+ jrePackages.addElement("javax");
+ break;
+ }
+ }
+
+ /**
+ * Testing helper method; kept here for unification of changes.
+ * @return a list of test classes depending on the java version.
+ */
+ public static Vector<String> getJrePackageTestCases() {
+ Vector<String> tests = new Vector<String>();
+ tests.addElement("java.lang.Object");
+ switch(javaVersionNumber) {
+ case VERSION_1_9:
+ case VERSION_1_8:
+ case VERSION_1_7:
+ case VERSION_1_6:
+ case VERSION_1_5:
+ tests.addElement(
+ "com.sun.org.apache.xerces.internal.jaxp.datatype.DatatypeFactoryImpl ");
+ // Fall through
+ case VERSION_1_4:
+ tests.addElement("sun.audio.AudioPlayer");
+ if (javaVersionNumber == VERSION_1_4) {
+ // only for 1.4, not for higher versions which fall through
+ tests.addElement("org.apache.crimson.parser.ContentModel");
+ tests.addElement("org.apache.xalan.processor.ProcessorImport");
+ tests.addElement("org.apache.xml.utils.URI");
+ tests.addElement("org.apache.xpath.XPathFactory");
+ }
+ tests.addElement("org.ietf.jgss.Oid");
+ tests.addElement("org.w3c.dom.Attr");
+ tests.addElement("org.xml.sax.XMLReader");
+ // fall through
+ case VERSION_1_3:
+ tests.addElement("org.omg.CORBA.Any");
+ tests.addElement("com.sun.corba.se.internal.corba.AnyImpl");
+ tests.addElement("com.sun.jndi.ldap.LdapURL");
+ tests.addElement("com.sun.media.sound.Printer");
+ tests.addElement("com.sun.naming.internal.VersionHelper");
+ tests.addElement("com.sun.org.omg.CORBA.Initializer");
+ tests.addElement("sunw.io.Serializable");
+ tests.addElement("sunw.util.EventListener");
+ // fall through
+ case VERSION_1_2:
+ tests.addElement("javax.accessibility.Accessible");
+ tests.addElement("sun.misc.BASE64Encoder");
+ tests.addElement("com.sun.image.codec.jpeg.JPEGCodec");
+ // fall through
+ case VERSION_1_1:
+ default:
+ //things like sun.reflection, sun.misc, sun.net
+ tests.addElement("sun.reflect.SerializationConstructorAccessorImpl");
+ tests.addElement("sun.net.www.http.HttpClient");
+ tests.addElement("sun.audio.AudioPlayer");
+ break;
+ }
+ return tests;
+ }
+ /**
+ * get a vector of strings of packages built into
+ * that platforms runtime jar(s)
+ * @return list of packages.
+ */
+ public static Vector<String> getJrePackages() {
+ if (jrePackages == null) {
+ buildJrePackages();
+ }
+ return jrePackages;
+ }
+
+ /**
+ *
+ * Writes the command into a temporary DCL script and returns the
+ * corresponding File object.
+ * It is the job of the caller to delete the file on exit.
+ * @param cmd the command.
+ * @return the file containing the command.
+ * @throws IOException if there is an error writing to the file.
+ */
+ public static File createVmsJavaOptionFile(String[] cmd)
+ throws IOException {
+ File script = FILE_UTILS.createTempFile("ANT", ".JAVA_OPTS", null, false, true);
+ BufferedWriter out = null;
+ try {
+ out = new BufferedWriter(new FileWriter(script));
+ for (int i = 0; i < cmd.length; i++) {
+ out.write(cmd[i]);
+ out.newLine();
+ }
+ } finally {
+ FileUtils.close(out);
+ }
+ return script;
+ }
+
+ /**
+ * Return the value of ${java.home}
+ * @return the java home value.
+ */
+ public static String getJavaHome() {
+ return JAVA_HOME;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/KeepAliveInputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/KeepAliveInputStream.java
new file mode 100644
index 00000000..debde59a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/KeepAliveInputStream.java
@@ -0,0 +1,66 @@
+/*
+ * 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.util;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Class that can be used to wrap <tt>System.in</tt>
+ * without getting anxious about any client closing the stream.
+ *
+ * <p>
+ * In code-language it means that it is not necessary to do:
+ * <pre>
+ * if (out != System.in) {
+ * in.close();
+ * }
+ * </pre>
+ *
+ * @since Ant 1.6
+ */
+public class KeepAliveInputStream extends FilterInputStream {
+
+ /**
+ * Constructor of KeepAliveInputStream.
+ *
+ * @param in an InputStream value, it should be standard input.
+ */
+ public KeepAliveInputStream(InputStream in) {
+ super(in);
+ }
+
+ /**
+ * This method does nothing.
+ * @throws IOException as we are overriding FilterInputStream.
+ */
+ public void close() throws IOException {
+ // do not close the stream
+ }
+
+ /**
+ * Convenience factory method that returns a non-closing
+ * InputStream around System.in.
+ *
+ * @since Ant 1.8.0
+ */
+ public static InputStream wrapSystemIn() {
+ return new KeepAliveInputStream(System.in);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/KeepAliveOutputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/KeepAliveOutputStream.java
new file mode 100644
index 00000000..27f3d7e4
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/KeepAliveOutputStream.java
@@ -0,0 +1,83 @@
+/*
+ * 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.util;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * Class that can be used to wrap <tt>System.out</tt> and <tt>System.err</tt>
+ * without getting anxious about any client closing the stream.
+ *
+ * <p>
+ * In code-language it means that it is not necessary to do:
+ * <pre>
+ * if (out != System.out &amp;&amp; out != System.err) {
+ * out.close();
+ * }
+ * </pre>
+ *
+ */
+public class KeepAliveOutputStream extends FilterOutputStream {
+
+ /**
+ * Constructor of KeepAliveOutputStream.
+ *
+ * @param out an OutputStream value, it should be standard output.
+ */
+ public KeepAliveOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ /**
+ * This method does nothing.
+ * @throws IOException as we are overriding FilterOutputStream.
+ */
+ public void close() throws IOException {
+ // do not close the stream
+ }
+
+ /**
+ * Convenience factory method that returns a non-closing
+ * PrintStream around System.out.
+ *
+ * @since Ant 1.8.0
+ */
+ public static PrintStream wrapSystemOut() {
+ return wrap(System.out);
+ }
+
+ /**
+ * Convenience factory method that returns a non-closing
+ * PrintStream around System.err.
+ *
+ * @since Ant 1.8.0
+ */
+ public static PrintStream wrapSystemErr() {
+ return wrap(System.err);
+ }
+
+ /**
+ * @since Ant 1.8.0
+ */
+ private static PrintStream wrap(PrintStream ps) {
+ return new PrintStream(new KeepAliveOutputStream(ps));
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LayoutPreservingProperties.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LayoutPreservingProperties.java
new file mode 100644
index 00000000..aed6f371
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LayoutPreservingProperties.java
@@ -0,0 +1,775 @@
+/*
+ * 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.util;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+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.PrintStream;
+import java.io.PushbackReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Properties;
+
+/**
+ * <p>A Properties collection which preserves comments and whitespace
+ * present in the input stream from which it was loaded.</p>
+ * <p>The class defers the usual work of the <a href="http://java.sun.com/j2se/1.3/docs/api/java/util/Properties.html">java.util.Properties</a>
+ * class to there, but it also keeps track of the contents of the
+ * input stream from which it was loaded (if applicable), so that it can
+ * write out the properties in as close a form as possible to the input.</p>
+ * <p>If no changes occur to property values, the output should be the same
+ * as the input, except for the leading date stamp, as normal for a
+ * properties file. Properties added are appended to the file. Properties
+ * whose values are changed are changed in place. Properties that are
+ * removed are excised. If the <code>removeComments</code> flag is set,
+ * then the comments immediately preceding the property are also removed.</p>
+ * <p>If a second set of properties is loaded into an existing set, the
+ * lines of the second set are added to the end. Note however, that if a
+ * property already stored is present in a stream subsequently loaded, then
+ * that property is removed before the new value is set. For example,
+ * consider the file</p>
+ * <pre> # the first line
+ * alpha=one
+ *
+ * # the second line
+ * beta=two</pre>
+ * <p>This file is loaded, and then the following is also loaded into the
+ * same <code>LayoutPreservingProperties</code> object</p>
+ * <pre> # association
+ * beta=band
+ *
+ * # and finally
+ * gamma=rays</pre>
+ * <p>The resulting collection sequence of logical lines depends on whether
+ * or not <code>removeComments</code> was set at the time the second stream
+ * is loaded. If it is set, then the resulting list of lines is</p>
+ * <pre> # the first line
+ * alpha=one
+ *
+ * # association
+ * beta=band
+ *
+ * # and finally
+ * gamma=rays</pre>
+ * <p>If the flag is not set, then the comment "the second line" is retained,
+ * although the key-value pair <code>beta=two</code> is removed.</p>
+ */
+public class LayoutPreservingProperties extends Properties {
+ private String LS = StringUtils.LINE_SEP;
+
+ /**
+ * Logical lines have escaping and line continuation taken care
+ * of. Comments and blank lines are logical lines; they are not
+ * removed.
+ */
+ private ArrayList logicalLines = new ArrayList();
+
+ /**
+ * Position in the <code>logicalLines</code> list, keyed by property name.
+ */
+ private HashMap keyedPairLines = new HashMap();
+
+ /**
+ * Flag to indicate that, when we remove a property from the file, we
+ * also want to remove the comments that precede it.
+ */
+ private boolean removeComments;
+
+ /**
+ * Create a new, empty, Properties collection, with no defaults.
+ */
+ public LayoutPreservingProperties() {
+ super();
+ }
+
+ /**
+ * Create a new, empty, Properties collection, with the specified defaults.
+ * @param defaults the default property values
+ */
+ public LayoutPreservingProperties(final Properties defaults) {
+ super(defaults);
+ }
+
+ /**
+ * Returns <code>true</code> if comments are removed along with
+ * properties, or <code>false</code> otherwise. If
+ * <code>true</code>, then when a property is removed, the comment
+ * preceding it in the original file is removed also.
+ * @return <code>true</code> if leading comments are removed when
+ * a property is removed; <code>false</code> otherwise
+ */
+ public boolean isRemoveComments() {
+ return removeComments;
+ }
+
+ /**
+ * Sets the behaviour for comments accompanying properties that
+ * are being removed. If <code>true</code>, then when a property
+ * is removed, the comment preceding it in the original file is
+ * removed also.
+ * @param val <code>true</code> if leading comments are to be
+ * removed when a property is removed; <code>false</code>
+ * otherwise
+ */
+ public void setRemoveComments(final boolean val) {
+ removeComments = val;
+ }
+
+ @Override
+ public void load(final InputStream inStream) throws IOException {
+ final String s = readLines(inStream);
+ final byte[] ba = s.getBytes(ResourceUtils.ISO_8859_1);
+ final ByteArrayInputStream bais = new ByteArrayInputStream(ba);
+ super.load(bais);
+ }
+
+ @Override
+ public Object put(final Object key, final Object value) throws NullPointerException {
+ final Object obj = super.put(key, value);
+ // the above call will have failed if key or value are null
+ innerSetProperty(key.toString(), value.toString());
+ return obj;
+ }
+
+ @Override
+ public Object setProperty(final String key, final String value)
+ throws NullPointerException {
+ final Object obj = super.setProperty(key, value);
+ // the above call will have failed if key or value are null
+ innerSetProperty(key, value);
+ return obj;
+ }
+
+ /**
+ * Store a new key-value pair, or add a new one. The normal
+ * functionality is taken care of by the superclass in the call to
+ * {@link #setProperty}; this method takes care of this classes
+ * extensions.
+ * @param key the key of the property to be stored
+ * @param value the value to be stored
+ */
+ private void innerSetProperty(String key, String value) {
+ value = escapeValue(value);
+
+ if (keyedPairLines.containsKey(key)) {
+ final Integer i = (Integer) keyedPairLines.get(key);
+ final Pair p = (Pair) logicalLines.get(i.intValue());
+ p.setValue(value);
+ } else {
+ key = escapeName(key);
+ final Pair p = new Pair(key, value);
+ p.setNew(true);
+ keyedPairLines.put(key, new Integer(logicalLines.size()));
+ logicalLines.add(p);
+ }
+ }
+
+ @Override
+ public void clear() {
+ super.clear();
+ keyedPairLines.clear();
+ logicalLines.clear();
+ }
+
+ @Override
+ public Object remove(final Object key) {
+ final Object obj = super.remove(key);
+ final Integer i = (Integer) keyedPairLines.remove(key);
+ if (null != i) {
+ if (removeComments) {
+ removeCommentsEndingAt(i.intValue());
+ }
+ logicalLines.set(i.intValue(), null);
+ }
+ return obj;
+ }
+
+ @Override
+ public Object clone() {
+ final LayoutPreservingProperties dolly =
+ (LayoutPreservingProperties) super.clone();
+ dolly.keyedPairLines = (HashMap) this.keyedPairLines.clone();
+ dolly.logicalLines = (ArrayList) this.logicalLines.clone();
+ final int size = dolly.logicalLines.size();
+ for (int j = 0; j < size; j++) {
+ final LogicalLine line = (LogicalLine) dolly.logicalLines.get(j);
+ if (line instanceof Pair) {
+ final Pair p = (Pair) line;
+ dolly.logicalLines.set(j, p.clone());
+ }
+ // no reason to clone other lines are they are immutable
+ }
+ return dolly;
+ }
+
+ /**
+ * Echo the lines of the properties (including blanks and comments) to the
+ * stream.
+ * @param out the stream to write to
+ */
+ public void listLines(final PrintStream out) {
+ out.println("-- logical lines --");
+ final Iterator i = logicalLines.iterator();
+ while (i.hasNext()) {
+ final LogicalLine line = (LogicalLine) i.next();
+ if (line instanceof Blank) {
+ out.println("blank: \"" + line + "\"");
+ } else if (line instanceof Comment) {
+ out.println("comment: \"" + line + "\"");
+ } else if (line instanceof Pair) {
+ out.println("pair: \"" + line + "\"");
+ }
+ }
+ }
+
+ /**
+ * Save the properties to a file.
+ * @param dest the file to write to
+ */
+ public void saveAs(final File dest) throws IOException {
+ final FileOutputStream fos = new FileOutputStream(dest);
+ store(fos, null);
+ fos.close();
+ }
+
+ @Override
+ public void store(final OutputStream out, final String header) throws IOException {
+ final OutputStreamWriter osw = new OutputStreamWriter(out, ResourceUtils.ISO_8859_1);
+
+ int skipLines = 0;
+ final int totalLines = logicalLines.size();
+
+ if (header != null) {
+ osw.write("#" + header + LS);
+ if (totalLines > 0
+ && logicalLines.get(0) instanceof Comment
+ && header.equals(logicalLines.get(0).toString().substring(1))) {
+ skipLines = 1;
+ }
+ }
+
+ // we may be updatiung a file written by this class, replace
+ // the date comment instead of adding a new one and preserving
+ // the one written last time
+ if (totalLines > skipLines
+ && logicalLines.get(skipLines) instanceof Comment) {
+ try {
+ DateUtils.parseDateFromHeader(logicalLines
+ .get(skipLines)
+ .toString().substring(1));
+ skipLines++;
+ } catch (final java.text.ParseException pe) {
+ // not an existing date comment
+ }
+ }
+ osw.write("#" + DateUtils.getDateForHeader() + LS);
+
+ boolean writtenSep = false;
+ for (final Iterator i = logicalLines.subList(skipLines, totalLines).iterator();
+ i.hasNext();) {
+ final LogicalLine line = (LogicalLine) i.next();
+ if (line instanceof Pair) {
+ if (((Pair)line).isNew()) {
+ if (!writtenSep) {
+ osw.write(LS);
+ writtenSep = true;
+ }
+ }
+ osw.write(line.toString() + LS);
+ } else if (line != null) {
+ osw.write(line.toString() + LS);
+ }
+ }
+ osw.close();
+ }
+
+ /**
+ * Reads a properties file into an internally maintained
+ * collection of logical lines (possibly spanning physcial lines),
+ * which make up the comments, blank lines and properties of the
+ * file.
+ * @param is the stream from which to read the data
+ */
+ private String readLines(final InputStream is) throws IOException {
+ final InputStreamReader isr = new InputStreamReader(is, ResourceUtils.ISO_8859_1);
+ final PushbackReader pbr = new PushbackReader(isr, 1);
+
+ if (logicalLines.size() > 0) {
+ // we add a blank line for spacing
+ logicalLines.add(new Blank());
+ }
+
+ String s = readFirstLine(pbr);
+ final BufferedReader br = new BufferedReader(pbr);
+
+ boolean continuation = false;
+ boolean comment = false;
+ final StringBuffer fileBuffer = new StringBuffer();
+ final StringBuffer logicalLineBuffer = new StringBuffer();
+ while (s != null) {
+ fileBuffer.append(s).append(LS);
+
+ if (continuation) {
+ // put in the line feed that was removed
+ s = "\n" + s;
+ } else {
+ // could be a comment, if first non-whitespace is a # or !
+ comment = s.matches("^( |\t|\f)*(#|!).*");
+ }
+
+ // continuation if not a comment and the line ends is an
+ // odd number of backslashes
+ if (!comment) {
+ continuation = requiresContinuation(s);
+ }
+
+ logicalLineBuffer.append(s);
+
+ if (!continuation) {
+ LogicalLine line = null;
+ if (comment) {
+ line = new Comment(logicalLineBuffer.toString());
+ } else if (logicalLineBuffer.toString().trim().length() == 0) {
+ line = new Blank();
+ } else {
+ line = new Pair(logicalLineBuffer.toString());
+ final String key = unescape(((Pair)line).getName());
+ if (keyedPairLines.containsKey(key)) {
+ // this key is already present, so we remove it and add
+ // the new one
+ remove(key);
+ }
+ keyedPairLines.put(key, new Integer(logicalLines.size()));
+ }
+ logicalLines.add(line);
+ logicalLineBuffer.setLength(0);
+ }
+ s = br.readLine();
+ }
+ return fileBuffer.toString();
+ }
+
+ /**
+ * Reads the first line and determines the EOL-style of the file
+ * (relies on the style to be consistent, of course).
+ *
+ * <p>Sets LS as a side-effect.</p>
+ *
+ * @return the first line without any line separator, leaves the
+ * reader positioned after the first line separator
+ *
+ * @since Ant 1.8.2
+ */
+ private String readFirstLine(final PushbackReader r) throws IOException {
+ final StringBuffer sb = new StringBuffer(80);
+ int ch = r.read();
+ boolean hasCR = false;
+ // when reaching EOF before the first EOL, assume native line
+ // feeds
+ LS = StringUtils.LINE_SEP;
+
+ while (ch >= 0) {
+ if (hasCR && ch != '\n') {
+ // line feed is sole CR
+ r.unread(ch);
+ break;
+ }
+
+ if (ch == '\r') {
+ LS = "\r";
+ hasCR = true;
+ } else if (ch == '\n') {
+ LS = hasCR ? "\r\n" : "\n";
+ break;
+ } else {
+ sb.append((char) ch);
+ }
+ ch = r.read();
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns <code>true</code> if the line represented by
+ * <code>s</code> is to be continued on the next line of the file,
+ * or <code>false</code> otherwise.
+ * @param s the contents of the line to examine
+ * @return <code>true</code> if the line is to be continued,
+ * <code>false</code> otherwise
+ */
+ private boolean requiresContinuation(final String s) {
+ final char[] ca = s.toCharArray();
+ int i = ca.length - 1;
+ while (i > 0 && ca[i] == '\\') {
+ i--;
+ }
+ // trailing backslashes
+ final int tb = ca.length - i - 1;
+ return tb % 2 == 1;
+ }
+
+ /**
+ * Unescape the string according to the rules for a Properites
+ * file, as laid out in the docs for <a
+ * href="http://java.sun.com/j2se/1.3/docs/api/java/util/Properties.html">java.util.Properties</a>.
+ * @param s the string to unescape (coming from the source file)
+ * @return the unescaped string
+ */
+ private String unescape(final String s) {
+ /*
+ * The following combinations are converted:
+ * \n newline
+ * \r carraige return
+ * \f form feed
+ * \t tab
+ * \\ backslash
+ * \u0000 unicode character
+ * Any other slash is ignored, so
+ * \b becomes 'b'.
+ */
+
+ final char[] ch = new char[s.length() + 1];
+ s.getChars(0, s.length(), ch, 0);
+ ch[s.length()] = '\n';
+ final StringBuffer buffy = new StringBuffer(s.length());
+ for (int i = 0; i < ch.length; i++) {
+ char c = ch[i];
+ if (c == '\n') {
+ // we have hit out end-of-string marker
+ break;
+ } else if (c == '\\') {
+ // possibly an escape sequence
+ c = ch[++i];
+ if (c == 'n') {
+ buffy.append('\n');
+ } else if (c == 'r') {
+ buffy.append('\r');
+ } else if (c == 'f') {
+ buffy.append('\f');
+ } else if (c == 't') {
+ buffy.append('\t');
+ } else if (c == 'u') {
+ // handle unicode escapes
+ c = unescapeUnicode(ch, i+1);
+ i += 4;
+ buffy.append(c);
+ } else {
+ buffy.append(c);
+ }
+ } else {
+ buffy.append(c);
+ }
+ }
+ return buffy.toString();
+ }
+
+ /**
+ * Retrieve the unicode character whose code is listed at position
+ * <code>i</code> in the character array <code>ch</code>.
+ * @param ch the character array containing the unicode character code
+ * @return the character extracted
+ */
+ private char unescapeUnicode(final char[] ch, final int i) {
+ final String s = new String(ch, i, 4);
+ return (char) Integer.parseInt(s, 16);
+ }
+
+ /**
+ * Escape the string <code>s</code> according to the rules in the
+ * docs for <a
+ * href="http://java.sun.com/j2se/1.3/docs/api/java/util/Properties.html">java.util.Properties</a>.
+ * @param s the string to escape
+ * @return the escaped string
+ */
+ private String escapeValue(final String s) {
+ return escape(s, false);
+ }
+
+ /**
+ * Escape the string <code>s</code> according to the rules in the
+ * docs for <a
+ * href="http://java.sun.com/j2se/1.3/docs/api/java/util/Properties.html">java.util.Properties</a>.
+ * This method escapes all the whitespace, not just the stuff at
+ * the beginning.
+ * @param s the string to escape
+ * @return the escaped string
+ */
+ private String escapeName(final String s) {
+ return escape(s, true);
+ }
+
+ /**
+ * Escape the string <code>s</code> according to the rules in the
+ * docs for <a
+ * href="http://java.sun.com/j2se/1.3/docs/api/java/util/Properties.html">java.util.Properties</a>.
+ * @param s the string to escape
+ * @param escapeAllSpaces if <code>true</code> the method escapes
+ * all the spaces, if <code>false</code>, it escapes only the
+ * leading whitespace
+ * @return the escaped string
+ */
+ private String escape(final String s, final boolean escapeAllSpaces) {
+ if (s == null) {
+ return null;
+ }
+
+ final char[] ch = new char[s.length()];
+ s.getChars(0, s.length(), ch, 0);
+ final String forEscaping = "\t\f\r\n\\:=#!";
+ final String escaped = "tfrn\\:=#!";
+ final StringBuffer buffy = new StringBuffer(s.length());
+ boolean leadingSpace = true;
+ for (int i = 0; i < ch.length; i++) {
+ final char c = ch[i];
+ if (c == ' ') {
+ if (escapeAllSpaces || leadingSpace) {
+ buffy.append("\\");
+ }
+ } else {
+ leadingSpace = false;
+ }
+ final int p = forEscaping.indexOf(c);
+ if (p != -1) {
+ buffy.append("\\").append(escaped.substring(p,p+1));
+ } else if (c < 0x0020 || c > 0x007e) {
+ buffy.append(escapeUnicode(c));
+ } else {
+ buffy.append(c);
+ }
+ }
+ return buffy.toString();
+ }
+
+ /**
+ * Return the unicode escape sequence for a character, in the form
+ * \u005CuNNNN.
+ * @param ch the character to encode
+ * @return the unicode escape sequence
+ */
+ private String escapeUnicode(final char ch) {
+ return "\\" + UnicodeUtil.EscapeUnicode(ch);
+ }
+
+ /**
+ * Remove the comments in the leading up the {@link logicalLines}
+ * list leading up to line <code>pos</code>.
+ * @param pos the line number to which the comments lead
+ */
+ private void removeCommentsEndingAt(int pos) {
+ /* We want to remove comments preceding this position. Step
+ * back counting blank lines (call this range B1) until we hit
+ * something non-blank. If what we hit is not a comment, then
+ * exit. If what we hit is a comment, then step back counting
+ * comment lines (call this range C1). Nullify lines in C1 and
+ * B1.
+ */
+
+ final int end = pos - 1;
+
+ // step pos back until it hits something non-blank
+ for (pos = end; pos > 0; pos--) {
+ if (!(logicalLines.get(pos) instanceof Blank)) {
+ break;
+ }
+ }
+
+ // if the thing it hits is not a comment, then we have nothing
+ // to remove
+ if (!(logicalLines.get(pos) instanceof Comment)) {
+ return;
+ }
+
+ // step back until we hit the start of the comment
+ for (; pos >= 0; pos--) {
+ if (!(logicalLines.get(pos) instanceof Comment)) {
+ break;
+ }
+ }
+
+ // now we want to delete from pos+1 to end
+ for (pos++; pos <= end; pos++) {
+ logicalLines.set(pos, null);
+ }
+ }
+
+ /**
+ * A logical line of the properties input stream.
+ */
+ private abstract static class LogicalLine {
+ private String text;
+
+ public LogicalLine(final String text) {
+ this.text = text;
+ }
+
+ public void setText(final String text) {
+ this.text = text;
+ }
+
+ @Override
+ public String toString() {
+ return text;
+ }
+ }
+
+ /**
+ * A blank line of the input stream.
+ */
+ private static class Blank extends LogicalLine {
+ public Blank() {
+ super("");
+ }
+ }
+
+ /**
+ * A comment line of the input stream.
+ */
+ private class Comment extends LogicalLine {
+ public Comment(final String text) {
+ super(text);
+ }
+ }
+
+ /**
+ * A key-value pair from the input stream. This may span more than
+ * one physical line, but it is constitutes as a single logical
+ * line.
+ */
+ private static class Pair extends LogicalLine implements Cloneable {
+ private String name;
+ private String value;
+ private boolean added;
+
+ public Pair(final String text) {
+ super(text);
+ parsePair(text);
+ }
+
+ public Pair(final String name, final String value) {
+ this(name + "=" + value);
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(final String value) {
+ this.value = value;
+ setText(name + "=" + value);
+ }
+
+ public boolean isNew() {
+ return added;
+ }
+
+ public void setNew(final boolean val) {
+ added = val;
+ }
+
+ @Override
+ public Object clone() {
+ Object dolly = null;
+ try {
+ dolly = super.clone();
+ } catch (final CloneNotSupportedException e) {
+ // should be fine
+ e.printStackTrace();
+ }
+ return dolly;
+ }
+
+ private void parsePair(final String text) {
+ // need to find first non-escaped '=', ':', '\t' or ' '.
+ final int pos = findFirstSeparator(text);
+ if (pos == -1) {
+ // trim leading whitespace only
+ name = text;
+ value = null;
+ } else {
+ name = text.substring(0, pos);
+ value = text.substring(pos+1, text.length());
+ }
+ // trim leading whitespace only
+ name = stripStart(name, " \t\f");
+ }
+
+ private String stripStart(final String s, final String chars) {
+ if (s == null) {
+ return null;
+ }
+
+ int i = 0;
+ for (;i < s.length(); i++) {
+ if (chars.indexOf(s.charAt(i)) == -1) {
+ break;
+ }
+ }
+ if (i == s.length()) {
+ return "";
+ }
+ return s.substring(i);
+ }
+
+ private int findFirstSeparator(String s) {
+ // Replace double backslashes with underscores so that they don't
+ // confuse us looking for '\t' or '\=', for example, but they also
+ // don't change the position of other characters
+ s = s.replaceAll("\\\\\\\\", "__");
+
+ // Replace single backslashes followed by separators, so we don't
+ // pick them up
+ s = s.replaceAll("\\\\=", "__");
+ s = s.replaceAll("\\\\:", "__");
+ s = s.replaceAll("\\\\ ", "__");
+ s = s.replaceAll("\\\\t", "__");
+
+ // Now only the unescaped separators are left
+ return indexOfAny(s, " :=\t");
+ }
+
+ private int indexOfAny(final String s, final String chars) {
+ if (s == null || chars == null) {
+ return -1;
+ }
+
+ int p = s.length() + 1;
+ for (int i = 0; i < chars.length(); i++) {
+ final int x = s.indexOf(chars.charAt(i));
+ if (x != -1 && x < p) {
+ p = x;
+ }
+ }
+ if (p == s.length() + 1) {
+ return -1;
+ }
+ return p;
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LazyFileOutputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LazyFileOutputStream.java
new file mode 100644
index 00000000..7e5bf786
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LazyFileOutputStream.java
@@ -0,0 +1,162 @@
+/*
+ * 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.util;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Class that delays opening the output file until the first bytes
+ * shall be written or the method {@link #open open} has been invoked
+ * explicitly.
+ *
+ * @since Ant 1.6
+ */
+public class LazyFileOutputStream extends OutputStream {
+
+ private FileOutputStream fos;
+ private File file;
+ private boolean append;
+ private boolean alwaysCreate;
+ private boolean opened = false;
+ private boolean closed = false;
+
+ /**
+ * Creates a stream that will eventually write to the file with
+ * the given name and replace it.
+ * @param name the filename.
+ */
+ public LazyFileOutputStream(String name) {
+ this(name, false);
+ }
+
+ /**
+ * Creates a stream that will eventually write to the file with
+ * the given name and optionally append to instead of replacing
+ * it.
+ * @param name the filename.
+ * @param append if true append rather than replace.
+ */
+ public LazyFileOutputStream(String name, boolean append) {
+ this(new File(name), append);
+ }
+
+ /**
+ * Creates a stream that will eventually write to the file with
+ * the given name and replace it.
+ * @param f the file to create.
+ */
+ public LazyFileOutputStream(File f) {
+ this(f, false);
+ }
+
+ /**
+ * Creates a stream that will eventually write to the file with
+ * the given name and optionally append to instead of replacing
+ * it.
+ * @param file the file to create.
+ * @param append if true append rather than replace.
+ */
+ public LazyFileOutputStream(File file, boolean append) {
+ this(file, append, false);
+ }
+
+ /**
+ * Creates a stream that will eventually write to the file with
+ * the given name, optionally append to instead of replacing
+ * it, and optionally always create a file (even if zero length).
+ * @param file the file to create.
+ * @param append if true append rather than replace.
+ * @param alwaysCreate if true create the file even if nothing to write.
+ */
+ public LazyFileOutputStream(File file, boolean append,
+ boolean alwaysCreate) {
+ this.file = file;
+ this.append = append;
+ this.alwaysCreate = alwaysCreate;
+ }
+
+ /**
+ * Explicitly open the file for writing.
+ *
+ * <p>Returns silently if the file has already been opened.</p>
+ * @throws IOException if there is an error.
+ */
+ public void open() throws IOException {
+ ensureOpened();
+ }
+
+ /**
+ * Close the file.
+ * @throws IOException if there is an error.
+ */
+ public synchronized void close() throws IOException {
+ if (alwaysCreate && !closed) {
+ ensureOpened();
+ }
+ if (opened) {
+ fos.close();
+ }
+ closed = true;
+ }
+
+ /**
+ * Delegates to the three-arg version.
+ * @param b the bytearray to write.
+ * @throws IOException if there is a problem.
+ */
+ public void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ /**
+ * Write part of a byte array.
+ * @param b the byte array.
+ * @param offset write from this index.
+ * @param len the number of bytes to write.
+ * @throws IOException if there is a problem.
+ */
+ public synchronized void write(byte[] b, int offset, int len)
+ throws IOException {
+ ensureOpened();
+ fos.write(b, offset, len);
+ }
+
+ /**
+ * Write a byte.
+ * @param b the byte to write.
+ * @throws IOException if there is a problem.
+ */
+ public synchronized void write(int b) throws IOException {
+ ensureOpened();
+ fos.write(b);
+ }
+
+ private synchronized void ensureOpened() throws IOException {
+ if (closed) {
+ throw new IOException(file + " has already been closed.");
+ }
+
+ if (!opened) {
+ fos = new FileOutputStream(file.getAbsolutePath(), append);
+ opened = true;
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LazyHashtable.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LazyHashtable.java
new file mode 100644
index 00000000..1df953cf
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LazyHashtable.java
@@ -0,0 +1,120 @@
+/*
+ * 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.util;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/** Hashtable implementation that allows delayed construction
+ * of expensive objects
+ *
+ * All operations that need access to the full list of objects
+ * will call initAll() first. Get and put are cheap.
+ *
+ * @since Ant 1.6
+ */
+public class LazyHashtable extends Hashtable {
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected boolean initAllDone = false;
+ // CheckStyle:VisibilityModifier OFF - bc
+
+ /** No arg constructor. */
+ public LazyHashtable() {
+ super();
+ }
+
+ /** Used to be part of init. It must be done once - but
+ * we delay it until we do need _all_ tasks. Otherwise we
+ * just get the tasks that we need, and avoid costly init.
+ */
+ protected void initAll() {
+ if (initAllDone) {
+ return;
+ }
+ initAllDone = true;
+ }
+
+
+ /**
+ * Get a enumeration over the elements.
+ * @return an enumeration.
+ */
+ public Enumeration elements() {
+ initAll();
+ return super.elements();
+ }
+
+ /**
+ * Check if the table is empty.
+ * @return true if it is.
+ */
+ public boolean isEmpty() {
+ initAll();
+ return super.isEmpty();
+ }
+
+ /**
+ * Get the size of the table.
+ * @return the size.
+ */
+ public int size() {
+ initAll();
+ return super.size();
+ }
+
+ /**
+ * Check if the table contains a particular value.
+ * @param value the value to look for.
+ * @return true if the table contains the value.
+ */
+ public boolean contains(Object value) {
+ initAll();
+ return super.contains(value);
+ }
+
+ /**
+ * Check if the table contains a particular key.
+ * @param value the key to look for.
+ * @return true if the table contains key.
+ */
+ public boolean containsKey(Object value) {
+ initAll();
+ return super.containsKey(value);
+ }
+
+ /**
+ * Delegates to {@link #contains contains}.
+ * @param value the value to look for.
+ * @return true if the table contains the value.
+ */
+ public boolean containsValue(Object value) {
+ return contains(value);
+ }
+
+ /**
+ * Get an enumeration over the keys.
+ * @return an enumeration.
+ */
+ public Enumeration keys() {
+ initAll();
+ return super.keys();
+ }
+
+ // TODO Unfortunately JDK1.2 adds entrySet(), keySet(), values() -
+ // implementing this requires a small hack, we can add it later.
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java
new file mode 100644
index 00000000..00819128
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LeadPipeInputStream.java
@@ -0,0 +1,161 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.Task;
+
+/**
+ * Special <code>PipedInputStream</code> that will not die
+ * when the writing <code>Thread</code> is no longer alive.
+ * @since Ant 1.6.2
+ */
+public class LeadPipeInputStream extends PipedInputStream {
+ private static final int BYTE_MASK = 0xFF;
+ private ProjectComponent managingPc;
+
+ /**
+ * Construct a new <code>LeadPipeInputStream</code>.
+ */
+ public LeadPipeInputStream() {
+ super();
+ }
+
+ /**
+ * Construct a new <code>LeadPipeInputStream</code>
+ * with the specified buffer size.
+ * @param size the size of the circular buffer.
+ */
+ public LeadPipeInputStream(int size) {
+ super();
+ setBufferSize(size);
+ }
+
+ /**
+ * Construct a new <code>LeadPipeInputStream</code> to pull
+ * from the specified <code>PipedOutputStream</code>.
+ * @param src the <code>PipedOutputStream</code> source.
+ * @throws IOException if unable to construct the stream.
+ */
+ public LeadPipeInputStream(PipedOutputStream src) throws IOException {
+ super(src);
+ }
+
+ /**
+ * Construct a new <code>LeadPipeInputStream</code> to pull
+ * from the specified <code>PipedOutputStream</code>, using a
+ * circular buffer of the specified size.
+ * @param src the <code>PipedOutputStream</code> source.
+ * @param size the size of the circular buffer.
+ * @throws IOException if there is an error.
+ */
+ public LeadPipeInputStream(PipedOutputStream src, int size) throws IOException {
+ super(src);
+ setBufferSize(size);
+ }
+
+ //inherit doc
+ /**
+ * Read a byte from the stream.
+ * @return the byte (0 to 255) or -1 if there are no more.
+ * @throws IOException if there is an error.
+ */
+ public synchronized int read() throws IOException {
+ int result = -1;
+ try {
+ result = super.read();
+ } catch (IOException eyeOhEx) {
+ String msg = eyeOhEx.getMessage();
+ if ("write end dead".equalsIgnoreCase(msg)
+ || "pipe broken".equalsIgnoreCase(msg)) {
+ if (super.in > 0 && super.out < super.buffer.length
+ && super.out > super.in) {
+ result = super.buffer[super.out++] & BYTE_MASK;
+ }
+ } else {
+ log("error at LeadPipeInputStream.read(): " + msg,
+ Project.MSG_INFO);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Set the size of the buffer.
+ * @param size the new buffer size. Ignored if &lt;= current size.
+ */
+ public synchronized void setBufferSize(int size) {
+ if (size > buffer.length) {
+ byte[] newBuffer = new byte[size];
+ if (in >= 0) {
+ if (in > out) {
+ System.arraycopy(buffer, out, newBuffer, out, in - out);
+ } else {
+ int outlen = buffer.length - out;
+ System.arraycopy(buffer, out, newBuffer, 0, outlen);
+ System.arraycopy(buffer, 0, newBuffer, outlen, in);
+ in += outlen;
+ out = 0;
+ }
+ }
+ buffer = newBuffer;
+ }
+ }
+
+ /**
+ * Set a managing <code>Task</code> for
+ * this <code>LeadPipeInputStream</code>.
+ * @param task the managing <code>Task</code>.
+ */
+ public void setManagingTask(Task task) {
+ setManagingComponent(task);
+ }
+
+ /**
+ * Set a managing <code>ProjectComponent</code> for
+ * this <code>LeadPipeInputStream</code>.
+ * @param pc the managing <code>ProjectComponent</code>.
+ */
+ public void setManagingComponent(ProjectComponent pc) {
+ this.managingPc = pc;
+ }
+
+ /**
+ * Log a message with the specified logging level.
+ * @param message the <code>String</code> message.
+ * @param loglevel the <code>int</code> logging level.
+ */
+ public void log(String message, int loglevel) {
+ if (managingPc != null) {
+ managingPc.log(message, loglevel);
+ } else {
+ if (loglevel > Project.MSG_WARN) {
+ System.out.println(message);
+ } else {
+ System.err.println(message);
+ }
+ }
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineOrientedOutputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineOrientedOutputStream.java
new file mode 100644
index 00000000..073a89f1
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineOrientedOutputStream.java
@@ -0,0 +1,158 @@
+/*
+ * 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.util;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Invokes {@link #processLine processLine} whenever a full line has
+ * been written to this stream.
+ *
+ * <p>Tries to be smart about line separators.</p>
+ */
+public abstract class LineOrientedOutputStream extends OutputStream {
+
+ /** Initial buffer size. */
+ private static final int INITIAL_SIZE = 132;
+
+ /** Carriage return */
+ private static final int CR = 0x0d;
+
+ /** Linefeed */
+ private static final int LF = 0x0a;
+
+ private ByteArrayOutputStream buffer
+ = new ByteArrayOutputStream(INITIAL_SIZE);
+ private boolean skip = false;
+
+ /**
+ * Write the data to the buffer and flush the buffer, if a line
+ * separator is detected.
+ *
+ * @param cc data to log (byte).
+ * @throws IOException if there is an error.
+ */
+ @Override
+ public final void write(int cc) throws IOException {
+ final byte c = (byte) cc;
+ if ((c == LF) || (c == CR)) {
+ if (!skip) {
+ processBuffer();
+ }
+ } else {
+ buffer.write(cc);
+ }
+ skip = (c == CR);
+ }
+
+ /**
+ * Flush this log stream
+ * @throws IOException if there is an error.
+ */
+ @Override
+ public void flush() throws IOException {
+ }
+
+ /**
+ * Converts the buffer to a byte[] and sends it to
+ * <code>processLine</code>
+ * @throws IOException if there is an error.
+ */
+ protected void processBuffer() throws IOException {
+ try {
+ processLine(buffer.toByteArray());
+ } finally {
+ buffer.reset();
+ }
+ }
+
+ /**
+ * Processes a line.
+ *
+ * @param line the line to log.
+ * @throws IOException if there is an error.
+ */
+ protected abstract void processLine(String line) throws IOException;
+
+ /**
+ * Processes a line.
+ *
+ * <p>This implementations invokes the string-arg version
+ * converting the byte array using the default encoding.
+ * Subclasses are encouraged to override this method (and provide
+ * a dummy implementation of the String-arg version) so they don't
+ * interfere with the encoding of the underlying stream.</p>
+ *
+ * @param line the line to log.
+ * @throws IOException if there is an error.
+ * @since Ant 1.8.3
+ */
+ protected void processLine(byte[] line) throws IOException {
+ processLine(new String(line));
+ }
+
+ /**
+ * Writes all remaining
+ * @throws IOException if there is an error.
+ */
+ @Override
+ public void close() throws IOException {
+ if (buffer.size() > 0) {
+ processBuffer();
+ }
+ super.close();
+ }
+
+ /**
+ * Write a block of characters to the output stream
+ *
+ * @param b the array containing the data
+ * @param off the offset into the array where data starts
+ * @param len the length of block
+ *
+ * @throws IOException if the data cannot be written into the stream.
+ */
+ @Override
+ public final void write(byte[] b, int off, int len) throws IOException {
+ // find the line breaks and pass other chars through in blocks
+ int offset = off;
+ int blockStartOffset = offset;
+ int remaining = len;
+ while (remaining > 0) {
+ while (remaining > 0 && b[offset] != LF && b[offset] != CR) {
+ offset++;
+ remaining--;
+ }
+ // either end of buffer or a line separator char
+ int blockLength = offset - blockStartOffset;
+ if (blockLength > 0) {
+ buffer.write(b, blockStartOffset, blockLength);
+ }
+ while (remaining > 0 && (b[offset] == LF || b[offset] == CR)) {
+ write(b[offset]);
+ offset++;
+ remaining--;
+ }
+ blockStartOffset = offset;
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineOrientedOutputStreamRedirector.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineOrientedOutputStreamRedirector.java
new file mode 100644
index 00000000..48bad5cc
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineOrientedOutputStreamRedirector.java
@@ -0,0 +1,68 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Output stream which buffer and redirect a stream line by line.
+ * <p>
+ * If the source stream doesn't end with a end of line, one will be added. This
+ * is particularly useful in combination with the OutputStreamFunneler so each
+ * funneled stream get its line.
+ *
+ * @since Ant 1.8.3
+ */
+public class LineOrientedOutputStreamRedirector
+ extends LineOrientedOutputStream {
+
+ private OutputStream stream;
+
+ // these should be in the ASCII range and hopefully are single bytes
+ // (for LF and CR respectively) for any encoding thrown at this class
+ private static final byte[] EOL =
+ System.getProperty("line.separator").getBytes();
+
+ public LineOrientedOutputStreamRedirector(OutputStream stream) {
+ this.stream = stream;
+ }
+
+ @Override
+ protected void processLine(byte[] b) throws IOException {
+ stream.write(b);
+ stream.write(EOL);
+ }
+
+ @Override
+ protected void processLine(String line) throws IOException {
+ stream.write((line + System.getProperty("line.separator")).getBytes());
+ }
+
+ @Override
+ public void close() throws IOException {
+ super.close();
+ stream.close();
+ }
+
+ @Override
+ public void flush() throws IOException {
+ super.flush();
+ stream.flush();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineTokenizer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineTokenizer.java
new file mode 100644
index 00000000..778606dd
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LineTokenizer.java
@@ -0,0 +1,115 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * class to tokenize the input as lines separated
+ * by \r (mac style), \r\n (dos/windows style) or \n (unix style)
+ * @since Ant 1.6
+ */
+public class LineTokenizer extends ProjectComponent
+ implements Tokenizer {
+ private static final int NOT_A_CHAR = -2;
+ private String lineEnd = "";
+ private int pushed = NOT_A_CHAR;
+ private boolean includeDelims = false;
+
+ /**
+ * attribute includedelims - whether to include
+ * the line ending with the line, or to return
+ * it in the posttoken
+ * default false
+ * @param includeDelims if true include /r and /n in the line
+ */
+
+ public void setIncludeDelims(boolean includeDelims) {
+ this.includeDelims = includeDelims;
+ }
+
+ /**
+ * get the next line from the input
+ *
+ * @param in the input reader
+ * @return the line excluding /r or /n, unless includedelims is set
+ * @exception IOException if an error occurs reading
+ */
+ public String getToken(Reader in) throws IOException {
+ int ch = -1;
+ if (pushed != NOT_A_CHAR) {
+ ch = pushed;
+ pushed = NOT_A_CHAR;
+ } else {
+ ch = in.read();
+ }
+ if (ch == -1) {
+ return null;
+ }
+
+ lineEnd = "";
+ StringBuffer line = new StringBuffer();
+
+ int state = 0;
+ while (ch != -1) {
+ if (state == 0) {
+ if (ch == '\r') {
+ state = 1;
+ } else if (ch == '\n') {
+ lineEnd = "\n";
+ break;
+ } else {
+ line.append((char) ch);
+ }
+ } else {
+ state = 0;
+ if (ch == '\n') {
+ lineEnd = "\r\n";
+ } else {
+ pushed = ch;
+ lineEnd = "\r";
+ }
+ break;
+ }
+ ch = in.read();
+ }
+ if (ch == -1 && state == 1) {
+ lineEnd = "\r";
+ }
+
+ if (includeDelims) {
+ line.append(lineEnd);
+ }
+ return line.toString();
+ }
+
+ /**
+ * @return the line ending character(s) for the current line
+ */
+ public String getPostToken() {
+ if (includeDelims) {
+ return "";
+ }
+ return lineEnd;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LinkedHashtable.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LinkedHashtable.java
new file mode 100644
index 00000000..73fc83c6
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LinkedHashtable.java
@@ -0,0 +1,132 @@
+/*
+ * 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.util;
+
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Subclass of Hashtable that wraps a LinkedHashMap to provide
+ * predictable iteration order.
+ *
+ * <p>This is not a general purpose class but has been written because
+ * the protected members of {@link org.apache.tools.ant.taskdefs.Copy
+ * Copy} prohibited later revisions from using a more predictable
+ * collection.</p>
+ *
+ * <p>Methods are synchronized to keep Hashtable's contract.</p>
+ *
+ * @since Ant 1.8.2
+ */
+public class LinkedHashtable<K, V> extends Hashtable<K, V> {
+ private static final long serialVersionUID = 1L;
+
+ private final LinkedHashMap<K, V> map;
+
+ public LinkedHashtable() {
+ map = new LinkedHashMap<K, V>();
+ }
+
+ public LinkedHashtable(int initialCapacity) {
+ map = new LinkedHashMap<K, V>(initialCapacity);
+ }
+
+ public LinkedHashtable(int initialCapacity, float loadFactor) {
+ map = new LinkedHashMap<K, V>(initialCapacity, loadFactor);
+ }
+
+ public LinkedHashtable(Map<K, V> m) {
+ map = new LinkedHashMap<K, V>(m);
+ }
+
+ public synchronized void clear() {
+ map.clear();
+ }
+
+ public boolean contains(Object value) {
+ return containsKey(value);
+ }
+
+ public synchronized boolean containsKey(Object value) {
+ return map.containsKey(value);
+ }
+
+ public synchronized boolean containsValue(Object value) {
+ return map.containsValue(value);
+ }
+
+ public Enumeration<V> elements() {
+ return CollectionUtils.asEnumeration(values().iterator());
+ }
+
+ public synchronized Set<Map.Entry<K, V>> entrySet() {
+ return map.entrySet();
+ }
+
+ public synchronized boolean equals(Object o) {
+ return map.equals(o);
+ }
+
+ public synchronized V get(Object k) {
+ return map.get(k);
+ }
+
+ public synchronized int hashCode() {
+ return map.hashCode();
+ }
+
+ public synchronized boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ public Enumeration<K> keys() {
+ return CollectionUtils.asEnumeration(keySet().iterator());
+ }
+
+ public synchronized Set<K> keySet() {
+ return map.keySet();
+ }
+
+ public synchronized V put(K k, V v) {
+ return map.put(k, v);
+ }
+
+ public synchronized void putAll(Map<? extends K, ? extends V> m) {
+ map.putAll(m);
+ }
+
+ public synchronized V remove(Object k) {
+ return map.remove(k);
+ }
+
+ public synchronized int size() {
+ return map.size();
+ }
+
+ public synchronized String toString() {
+ return map.toString();
+ }
+
+ public synchronized Collection<V> values() {
+ return map.values();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LoaderUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LoaderUtils.java
new file mode 100644
index 00000000..e0514f65
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/LoaderUtils.java
@@ -0,0 +1,140 @@
+/*
+ * 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.util;
+
+import java.io.File;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.launch.Locator;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * ClassLoader utility methods
+ *
+ */
+public class LoaderUtils {
+
+ /** Utilities used for file operations */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /**
+ * Set the context classloader
+ *
+ * @param loader the ClassLoader to be used as the context class loader
+ * on the current thread.
+ */
+ public static void setContextClassLoader(ClassLoader loader) {
+ Thread currentThread = Thread.currentThread();
+ currentThread.setContextClassLoader(loader);
+ }
+
+
+ /**
+ * JDK1.1 compatible access to set the context class loader.
+ *
+ * @return the ClassLoader instance being used as the context
+ * classloader on the current thread. Returns null on JDK 1.1
+ */
+ public static ClassLoader getContextClassLoader() {
+ Thread currentThread = Thread.currentThread();
+ return currentThread.getContextClassLoader();
+ }
+
+ /**
+ * Indicates if the context class loader methods are available
+ *
+ * @return true if the get and set methods dealing with the context
+ * classloader are available.
+ */
+ public static boolean isContextLoaderAvailable() {
+ return true;
+ }
+
+ /**
+ * Normalize a source location
+ *
+ * @param source the source location to be normalized.
+ *
+ * @return the normalized source location.
+ */
+ private static File normalizeSource(File source) {
+ if (source != null) {
+ try {
+ source = FILE_UTILS.normalize(source.getAbsolutePath());
+ } catch (BuildException e) {
+ // relative path
+ }
+ }
+
+ return source;
+ }
+
+ /**
+ * Find the directory or jar file the class has been loaded from.
+ *
+ * @param c the class whose location is required.
+ * @return the file or jar with the class or null if we cannot
+ * determine the location.
+ *
+ * @since Ant 1.6
+ */
+ public static File getClassSource(Class c) {
+ return normalizeSource(Locator.getClassSource(c));
+ }
+
+ /**
+ * Find the directory or a give resource has been loaded from.
+ *
+ * @param c the classloader to be consulted for the source
+ * @param resource the resource whose location is required.
+ *
+ * @return the file with the resource source or null if
+ * we cannot determine the location.
+ *
+ * @since Ant 1.6
+ */
+ public static File getResourceSource(ClassLoader c, String resource) {
+ if (c == null) {
+ c = LoaderUtils.class.getClassLoader();
+ }
+ return normalizeSource(Locator.getResourceSource(c, resource));
+ }
+
+ /**
+ * Return the resource name of a class name.
+ * @param className the name of the class to convert.
+ * @return the corresponding resource name.
+ * @since Ant 1.7.0.
+ */
+ public static String classNameToResource(String className) {
+ return className.replace('.', '/') + ".class";
+ }
+
+ /**
+ * Check if a classloader has a classname resource.
+ * @param loader the classloader to look it.
+ * @param className the name of the class to look for.
+ * @return true if the classexists, false otherwise
+ * @since Ant 1.7.0.
+ */
+ public static boolean classExists(ClassLoader loader, String className) {
+ return loader.getResource(classNameToResource(className)) != null;
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/MergingMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/MergingMapper.java
new file mode 100644
index 00000000..7f158dbf
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/MergingMapper.java
@@ -0,0 +1,67 @@
+/*
+ * 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.util;
+
+/**
+ * Implementation of FileNameMapper that always returns the same
+ * target file name.
+ *
+ * <p>This is the default FileNameMapper for the archiving tasks and
+ * uptodate.</p>
+ *
+ */
+public class MergingMapper implements FileNameMapper {
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected String[] mergedFile = null;
+ // CheckStyle:VisibilityModifier ON
+
+ public MergingMapper() {}
+
+ /**
+ * @since Ant 1.8.0
+ */
+ public MergingMapper(String to) {
+ setTo(to);
+ }
+
+ /**
+ * Ignored.
+ * @param from ignored.
+ */
+ public void setFrom(String from) {
+ }
+
+ /**
+ * Sets the name of the merged file.
+ * @param to the name of the merged file.
+ */
+ public void setTo(String to) {
+ mergedFile = new String[] {to};
+ }
+
+ /**
+ * Returns an one-element array containing the file name set via setTo.
+ * @param sourceFileName ignored.
+ * @return a one-element array containing the merged filename.
+ */
+ public String[] mapFileName(String sourceFileName) {
+ return mergedFile;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/OutputStreamFunneler.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/OutputStreamFunneler.java
new file mode 100644
index 00000000..6694c3f0
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/OutputStreamFunneler.java
@@ -0,0 +1,176 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Manages a set of <code>OutputStream</code>s to
+ * write to a single underlying stream, which is
+ * closed only when the last &quot;funnel&quot;
+ * has been closed.
+ */
+public class OutputStreamFunneler {
+
+ /**
+ * Default timeout.
+ * @see #setTimeout(long)
+ */
+ public static final long DEFAULT_TIMEOUT_MILLIS = 1000;
+
+ private final class Funnel extends OutputStream {
+ private boolean closed = false;
+
+ private Funnel() {
+ synchronized (OutputStreamFunneler.this) {
+ ++count;
+ }
+ }
+
+ public void flush() throws IOException {
+ synchronized (OutputStreamFunneler.this) {
+ dieIfClosed();
+ out.flush();
+ }
+ }
+
+ public void write(int b) throws IOException {
+ synchronized (OutputStreamFunneler.this) {
+ dieIfClosed();
+ out.write(b);
+ }
+ }
+
+ public void write(byte[] b) throws IOException {
+ synchronized (OutputStreamFunneler.this) {
+ dieIfClosed();
+ out.write(b);
+ }
+ }
+
+ public void write(byte[] b, int off, int len) throws IOException {
+ synchronized (OutputStreamFunneler.this) {
+ dieIfClosed();
+ out.write(b, off, len);
+ }
+ }
+
+ public void close() throws IOException {
+ release(this);
+ }
+ }
+
+ private OutputStream out;
+ private int count = 0;
+ private boolean closed;
+ private long timeoutMillis;
+
+ /**
+ * Create a new <code>OutputStreamFunneler</code> for
+ * the specified <code>OutputStream</code>.
+ * @param out <code>OutputStream</code>.
+ */
+ public OutputStreamFunneler(OutputStream out) {
+ this(out, DEFAULT_TIMEOUT_MILLIS);
+ }
+
+ /**
+ * Create a new <code>OutputStreamFunneler</code> for
+ * the specified <code>OutputStream</code>, with the
+ * specified timeout value.
+ * @param out <code>OutputStream</code>.
+ * @param timeoutMillis <code>long</code>.
+ * @see #setTimeout(long)
+ */
+ public OutputStreamFunneler(OutputStream out, long timeoutMillis) {
+ if (out == null) {
+ throw new IllegalArgumentException(
+ "OutputStreamFunneler.<init>: out == null");
+ }
+ this.out = out;
+ this.closed = false; //as far as we know
+ setTimeout(timeoutMillis);
+ }
+
+ /**
+ * Set the timeout for this <code>OutputStreamFunneler</code>.
+ * This is the maximum time that may elapse between the closure
+ * of the last &quot;funnel&quot; and the next call to
+ * <code>getOutputStream()</code> without closing the
+ * underlying stream.
+ * @param timeoutMillis <code>long</code> timeout value.
+ */
+ public synchronized void setTimeout(long timeoutMillis) {
+ this.timeoutMillis = timeoutMillis;
+ }
+
+ /**
+ * Get a &quot;funnel&quot; <code>OutputStream</code> instance to
+ * write to this <code>OutputStreamFunneler</code>'s underlying
+ * <code>OutputStream</code>.
+ * @return <code>OutputStream</code>.
+ * @throws IOException if unable to create the funnel.
+ */
+ public synchronized OutputStream getFunnelInstance()
+ throws IOException {
+ dieIfClosed();
+ try {
+ return new Funnel();
+ } finally {
+ notifyAll();
+ }
+ }
+
+ private synchronized void release(Funnel funnel) throws IOException {
+ //ignore release of an already-closed funnel
+ if (!funnel.closed) {
+ try {
+ if (timeoutMillis > 0) {
+ try {
+ wait(timeoutMillis);
+ } catch (InterruptedException eyeEx) {
+ //ignore
+ }
+ }
+ if (--count == 0) {
+ close();
+ }
+ } finally {
+ funnel.closed = true;
+ }
+ }
+ }
+
+ private synchronized void close() throws IOException {
+ try {
+ dieIfClosed();
+ out.close();
+ } finally {
+ closed = true;
+ }
+ }
+
+ private synchronized void dieIfClosed() throws IOException {
+ if (closed) {
+ throw new IOException("The funneled OutputStream has been closed.");
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/PackageNameMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/PackageNameMapper.java
new file mode 100644
index 00000000..30256670
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/PackageNameMapper.java
@@ -0,0 +1,49 @@
+/*
+ * 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.util;
+
+import java.io.File;
+
+/**
+ * Maps directory name matches into a dotted package name. This is
+ * useful for matching JUnit test cases against their XML formatter
+ * results.
+ * <pre>
+ * &lt;mapper classname="org.apache.tools.ant.util.PackageNameMapper"
+ * from="*Test.java" to="${test.data.dir}/TEST-*Test.xml"/&gt;
+ * </pre>
+ *
+ */
+public class PackageNameMapper extends GlobPatternMapper {
+ /**
+ * Returns the part of the given string that matches the * in the
+ * &quot;from&quot; pattern replacing file separators with dots
+ *
+ *@param name Source filename
+ *@return Replaced variable part
+ */
+ protected String extractVariablePart(String name) {
+ String var = name.substring(prefixLength,
+ name.length() - postfixLength);
+ if (getHandleDirSep()) {
+ var = var.replace('/', '.').replace('\\', '.');
+ }
+ return var.replace(File.separatorChar, '.');
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ProcessUtil.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ProcessUtil.java
new file mode 100644
index 00000000..f6e71b12
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ProcessUtil.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util;
+
+import java.lang.management.ManagementFactory;
+
+/**
+ * Process Utilities
+ * @since Ant 1.9.4
+ */
+public class ProcessUtil {
+
+ private ProcessUtil() {
+ }
+
+ /**
+ * provide id of the current process
+ * @param fallback
+ * @return current process id
+ */
+ public static String getProcessId(final String fallback) {
+ // Note: may fail in some JVM implementations
+ // therefore fallback has to be provided
+
+ // something like '<pid>@<hostname>', at least in SUN / Oracle JVMs
+ final String jvmName = ManagementFactory.getRuntimeMXBean().getName();
+ final int index = jvmName.indexOf('@');
+
+ if (index < 1) {
+ // part before '@' empty (index = 0) / '@' not found (index = -1)
+ return fallback;
+ }
+
+ try {
+ return Long.toString(Long.parseLong(jvmName.substring(0, index)));
+ } catch (NumberFormatException e) {
+ // ignore
+ }
+ return fallback;
+ }
+
+ public static void main(String [] args) {
+ System.out.println(getProcessId("<PID>"));
+ try {
+ Thread.sleep(120000);
+ } catch (Exception exc) {
+ // ignore
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/PropertyOutputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/PropertyOutputStream.java
new file mode 100644
index 00000000..59a1b7e8
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/PropertyOutputStream.java
@@ -0,0 +1,69 @@
+/*
+ * 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.util;
+
+import java.io.ByteArrayOutputStream;
+
+import org.apache.tools.ant.Project;
+
+/**
+ * Exception thrown when an attempt is made to get an OutputStream
+ * from an immutable Resource.
+ * @since Ant 1.7
+ */
+public class PropertyOutputStream extends ByteArrayOutputStream {
+ private Project project;
+ private String property;
+ private boolean trim;
+
+ /**
+ * Construct a new PropertyOutputStream for the specified Project
+ * and property name, trimming the property value.
+ * @param p the associated Ant Project.
+ * @param s the String property name.
+ */
+ public PropertyOutputStream(Project p, String s) {
+ this(p, s, true);
+ }
+
+ /**
+ * Construct a new PropertyOutputStream for
+ * the specified Project, property name, and trim mode.
+ * @param p the associated Ant Project.
+ * @param s the String property name.
+ * @param b the boolean trim mode.
+ */
+ public PropertyOutputStream(Project p, String s, boolean b) {
+ project = p;
+ property = s;
+ trim = b;
+ }
+
+ /**
+ * Close the PropertyOutputStream, storing the property.
+ */
+ public void close() {
+ if (project != null && property != null) {
+ String s = new String(toByteArray());
+ project.setNewProperty(property, trim ? s.trim() : s);
+ }
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ProxySetup.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ProxySetup.java
new file mode 100644
index 00000000..f077f87c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ProxySetup.java
@@ -0,0 +1,115 @@
+/*
+ * 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.util;
+
+import org.apache.tools.ant.Project;
+
+/**
+ * Code to do proxy setup. This is just factored out of the main system just to
+ * keep everything else less convoluted.
+ * @since Ant1.7
+ */
+
+public class ProxySetup {
+
+ /**
+ * owner project; used for logging and extracting properties
+ */
+ private Project owner;
+
+ /**
+ * Java1.5 property that enables use of system proxies.
+ */
+ public static final String USE_SYSTEM_PROXIES = "java.net.useSystemProxies";
+ /** the http proxyhost property */
+ public static final String HTTP_PROXY_HOST = "http.proxyHost";
+ /** the http proxyport property */
+ public static final String HTTP_PROXY_PORT = "http.proxyPort";
+ /** the https proxyhost property */
+ public static final String HTTPS_PROXY_HOST = "https.proxyHost";
+ /** the https proxyport property */
+ public static final String HTTPS_PROXY_PORT = "https.proxyPort";
+ /** the ftp proxyhost property */
+ public static final String FTP_PROXY_HOST = "ftp.proxyHost";
+ /** the ftp proxyport property */
+ public static final String FTP_PROXY_PORT = "ftp.proxyPort";
+ /** the ftp proxyport property */
+ public static final String HTTP_NON_PROXY_HOSTS = "http.nonProxyHosts";
+ /** the http hosts not to be proxied property */
+ public static final String HTTPS_NON_PROXY_HOSTS = "https.nonProxyHosts";
+ /** the ftp hosts not to be proxied property */
+ public static final String FTP_NON_PROXY_HOSTS = "ftp.nonProxyHosts";
+ /** the http proxy username property */
+ public static final String HTTP_PROXY_USERNAME = "http.proxyUser";
+ /** the http proxy password property */
+ public static final String HTTP_PROXY_PASSWORD = "http.proxyPassword";
+ /** the socks proxy host property */
+ public static final String SOCKS_PROXY_HOST = "socksProxyHost";
+ /** the socks proxy port property */
+ public static final String SOCKS_PROXY_PORT = "socksProxyPort";
+ /** the socks proxy username property */
+ public static final String SOCKS_PROXY_USERNAME = "java.net.socks.username";
+ /** the socks proxy password property */
+ public static final String SOCKS_PROXY_PASSWORD = "java.net.socks.password";
+
+ /**
+ * create a proxy setup class bound to this project
+ * @param owner the project that owns this setup.
+ */
+ public ProxySetup(Project owner) {
+ this.owner = owner;
+ }
+
+ /**
+ * Get the current system property settings
+ * @return current value; null for none or no access
+ */
+ public static String getSystemProxySetting() {
+ try {
+ return System.getProperty(USE_SYSTEM_PROXIES);
+ } catch (SecurityException e) {
+ //if you cannot read it, you won't be able to write it either
+ return null;
+ }
+ }
+
+ /**
+ * turn proxies on;
+ * if the proxy key is already set to some value: leave alone.
+ * if an ant property of the value {@link #USE_SYSTEM_PROXIES}
+ * is set, use that instead. Else set to "true".
+ */
+ public void enableProxies() {
+ if (!(getSystemProxySetting() != null)) {
+ String proxies = owner.getProperty(USE_SYSTEM_PROXIES);
+ if (proxies == null || Project.toBoolean(proxies)) {
+ proxies = "true";
+ }
+ String message = "setting " + USE_SYSTEM_PROXIES + " to " + proxies;
+ try {
+ owner.log(message, Project.MSG_DEBUG);
+ System.setProperty(USE_SYSTEM_PROXIES, proxies);
+ } catch (SecurityException e) {
+ //log security exceptions and continue; it aint that
+ //important and may be quite common running Ant embedded.
+ owner.log("Security Exception when " + message);
+ }
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReaderInputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReaderInputStream.java
new file mode 100644
index 00000000..620af8d5
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReaderInputStream.java
@@ -0,0 +1,205 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+
+/**
+ * Adapts a <code>Reader</code> as an <code>InputStream</code>.
+ * Adapted from <code>StringInputStream</code>.
+ *
+ */
+public class ReaderInputStream extends InputStream {
+ private static final int BYTE_MASK = 0xFF;
+
+ /** Source Reader */
+ private Reader in;
+
+ private String encoding = System.getProperty("file.encoding");
+
+ private byte[] slack;
+
+ private int begin;
+
+ /**
+ * Construct a <code>ReaderInputStream</code>
+ * for the specified <code>Reader</code>.
+ *
+ * @param reader <code>Reader</code>. Must not be <code>null</code>.
+ */
+ public ReaderInputStream(Reader reader) {
+ in = reader;
+ }
+
+ /**
+ * Construct a <code>ReaderInputStream</code>
+ * for the specified <code>Reader</code>,
+ * with the specified encoding.
+ *
+ * @param reader non-null <code>Reader</code>.
+ * @param encoding non-null <code>String</code> encoding.
+ */
+ public ReaderInputStream(Reader reader, String encoding) {
+ this(reader);
+ if (encoding == null) {
+ throw new IllegalArgumentException("encoding must not be null");
+ } else {
+ this.encoding = encoding;
+ }
+ }
+
+ /**
+ * Reads from the <code>Reader</code>, returning the same value.
+ *
+ * @return the value of the next character in the <code>Reader</code>.
+ *
+ * @exception IOException if the original <code>Reader</code> fails to be read
+ */
+ public synchronized int read() throws IOException {
+ if (in == null) {
+ throw new IOException("Stream Closed");
+ }
+
+ byte result;
+ if (slack != null && begin < slack.length) {
+ result = slack[begin];
+ if (++begin == slack.length) {
+ slack = null;
+ }
+ } else {
+ byte[] buf = new byte[1];
+ if (read(buf, 0, 1) <= 0) {
+ return -1;
+ } else {
+ result = buf[0];
+ }
+ }
+ return result & BYTE_MASK;
+ }
+
+ /**
+ * Reads from the <code>Reader</code> into a byte array
+ *
+ * @param b the byte array to read into
+ * @param off the offset in the byte array
+ * @param len the length in the byte array to fill
+ * @return the actual number read into the byte array, -1 at
+ * the end of the stream
+ * @exception IOException if an error occurs
+ */
+ public synchronized int read(byte[] b, int off, int len)
+ throws IOException {
+ if (in == null) {
+ throw new IOException("Stream Closed");
+ }
+ if (len == 0) {
+ return 0;
+ }
+ while (slack == null) {
+ char[] buf = new char[len]; // might read too much
+ int n = in.read(buf);
+ if (n == -1) {
+ return -1;
+ }
+ if (n > 0) {
+ slack = new String(buf, 0, n).getBytes(encoding);
+ begin = 0;
+ }
+ }
+
+ if (len > slack.length - begin) {
+ len = slack.length - begin;
+ }
+
+ System.arraycopy(slack, begin, b, off, len);
+
+ begin += len;
+ if (begin >= slack.length) {
+ slack = null;
+ }
+
+ return len;
+ }
+
+ /**
+ * Marks the read limit of the Reader.
+ *
+ * @param limit the maximum limit of bytes that can be read before the
+ * mark position becomes invalid
+ */
+ public synchronized void mark(final int limit) {
+ try {
+ in.mark(limit);
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe.getMessage());
+ }
+ }
+
+
+ /**
+ * @return the current number of bytes ready for reading
+ * @exception IOException if an error occurs
+ */
+ public synchronized int available() throws IOException {
+ if (in == null) {
+ throw new IOException("Stream Closed");
+ }
+ if (slack != null) {
+ return slack.length - begin;
+ }
+ if (in.ready()) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * @return false - mark is not supported
+ */
+ public boolean markSupported () {
+ return false; // would be imprecise
+ }
+
+ /**
+ * Resets the Reader.
+ *
+ * @exception IOException if the Reader fails to be reset
+ */
+ public synchronized void reset() throws IOException {
+ if (in == null) {
+ throw new IOException("Stream Closed");
+ }
+ slack = null;
+ in.reset();
+ }
+
+ /**
+ * Closes the Reader.
+ *
+ * @exception IOException if the original Reader fails to be closed
+ */
+ public synchronized void close() throws IOException {
+ if (in != null) {
+ in.close();
+ slack = null;
+ in = null;
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReflectUtil.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReflectUtil.java
new file mode 100644
index 00000000..88b7911e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReflectUtil.java
@@ -0,0 +1,212 @@
+/*
+ * 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.util;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Utility class to handle reflection on java objects.
+ * The class contains static methods to call reflection
+ * methods, catch any exceptions, converting them
+ * to BuildExceptions.
+ */
+// CheckStyle:FinalClassCheck OFF - backward compatible
+public class ReflectUtil {
+
+ /** private constructor */
+ private ReflectUtil() {
+ }
+
+ /**
+ * Create an instance of a class using the constructor matching
+ * the given arguments.
+ * @since Ant 1.8.0
+ */
+ public static <T> T newInstance(Class<T> ofClass,
+ Class<?>[] argTypes,
+ Object[] args) {
+ try {
+ Constructor<T> con = ofClass.getConstructor(argTypes);
+ return con.newInstance(args);
+ } catch (Exception t) {
+ throwBuildException(t);
+ return null; // NotReached
+ }
+ }
+
+ /**
+ * Call a method on the object with no parameters.
+ * @param obj the object to invoke the method on.
+ * @param methodName the name of the method to call
+ * @return the object returned by the method
+ */
+ public static Object invoke(Object obj, String methodName) {
+ try {
+ Method method;
+ method = obj.getClass().getMethod(
+ methodName, (Class[]) null);
+ return method.invoke(obj, (Object[]) null);
+ } catch (Exception t) {
+ throwBuildException(t);
+ return null; // NotReached
+ }
+ }
+
+ /**
+ * Call a method on the object with no parameters.
+ * Note: Unlike the invoke method above, this
+ * calls class or static methods, not instance methods.
+ * @param obj the object to invoke the method on.
+ * @param methodName the name of the method to call
+ * @return the object returned by the method
+ */
+ public static Object invokeStatic(Object obj, String methodName) {
+ try {
+ Method method;
+ method = ((Class<?>) obj).getMethod(
+ methodName, (Class[]) null);
+ return method.invoke(obj, (Object[]) null);
+ } catch (Exception t) {
+ throwBuildException(t);
+ return null; // NotReached
+ }
+ }
+
+ /**
+ * Call a method on the object with one argument.
+ * @param obj the object to invoke the method on.
+ * @param methodName the name of the method to call
+ * @param argType the type of argument.
+ * @param arg the value of the argument.
+ * @return the object returned by the method
+ */
+ public static Object invoke(
+ Object obj, String methodName, Class<?> argType, Object arg) {
+ try {
+ Method method;
+ method = obj.getClass().getMethod(
+ methodName, new Class[] {argType});
+ return method.invoke(obj, new Object[] {arg});
+ } catch (Exception t) {
+ throwBuildException(t);
+ return null; // NotReached
+ }
+ }
+
+ /**
+ * Call a method on the object with two argument.
+ * @param obj the object to invoke the method on.
+ * @param methodName the name of the method to call
+ * @param argType1 the type of the first argument.
+ * @param arg1 the value of the first argument.
+ * @param argType2 the type of the second argument.
+ * @param arg2 the value of the second argument.
+ * @return the object returned by the method
+ */
+ public static Object invoke(
+ Object obj, String methodName, Class<?> argType1, Object arg1,
+ Class<?> argType2, Object arg2) {
+ try {
+ Method method;
+ method = obj.getClass().getMethod(
+ methodName, new Class[] {argType1, argType2});
+ return method.invoke(obj, new Object[] {arg1, arg2});
+ } catch (Exception t) {
+ throwBuildException(t);
+ return null; // NotReached
+ }
+ }
+
+ /**
+ * Get the value of a field in an object.
+ * @param obj the object to look at.
+ * @param fieldName the name of the field in the object.
+ * @return the value of the field.
+ * @throws BuildException if there is an error.
+ */
+ public static Object getField(Object obj, String fieldName)
+ throws BuildException {
+ try {
+ Field field = obj.getClass().getDeclaredField(fieldName);
+ field.setAccessible(true);
+ return field.get(obj);
+ } catch (Exception t) {
+ throwBuildException(t);
+ return null; // NotReached
+ }
+ }
+
+ /**
+ * A method to convert an invocationTargetException to
+ * a buildexception and throw it.
+ * @param t the invocation target exception.
+ * @throws BuildException the converted exception.
+ */
+ public static void throwBuildException(Exception t)
+ throws BuildException {
+ throw toBuildException(t);
+ }
+
+ /**
+ * A method to convert an invocationTargetException to
+ * a buildexception.
+ * @param t the invocation target exception.
+ * @return the converted exception.
+ * @since ant 1.7.1
+ */
+ public static BuildException toBuildException(Exception t) {
+ if (t instanceof InvocationTargetException) {
+ Throwable t2 = ((InvocationTargetException) t)
+ .getTargetException();
+ if (t2 instanceof BuildException) {
+ return (BuildException) t2;
+ }
+ return new BuildException(t2);
+ } else {
+ return new BuildException(t);
+ }
+ }
+
+ /**
+ * A method to test if an object responds to a given
+ * message (method call)
+ * @param o the object
+ * @param methodName the method to check for
+ * @return true if the object has the method.
+ * @throws BuildException if there is a problem.
+ */
+ public static boolean respondsTo(Object o, String methodName)
+ throws BuildException {
+ try {
+ Method[] methods = o.getClass().getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].getName().equals(methodName)) {
+ return true;
+ }
+ }
+ return false;
+ } catch (Exception t) {
+ throw toBuildException(t);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReflectWrapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReflectWrapper.java
new file mode 100644
index 00000000..e34363ea
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ReflectWrapper.java
@@ -0,0 +1,99 @@
+/*
+ * 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.util;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * Utility class to handle reflection on java objects.
+ * The class is a holder class for an object and
+ * uses java reflection to call methods on the objects.
+ * If things go wrong, BuildExceptions are thrown.
+ */
+
+public class ReflectWrapper {
+ private Object obj;
+ /**
+ * Construct a wrapped object using the no arg constructor.
+ * @param loader the classloader to use to construct the class.
+ * @param name the classname of the object to construct.
+ */
+ public ReflectWrapper(ClassLoader loader, String name) {
+ try {
+ Class clazz;
+ clazz = Class.forName(name, true, loader);
+ Constructor constructor;
+ constructor = clazz.getConstructor((Class[]) null);
+ obj = constructor.newInstance((Object[]) null);
+ } catch (Exception t) {
+ ReflectUtil.throwBuildException(t);
+ }
+ }
+
+ /**
+ * Constructor using a passed in object.
+ * @param obj the object to wrap.
+ */
+ public ReflectWrapper(Object obj) {
+ this.obj = obj;
+ }
+
+ /**
+ * @return the wrapped object.
+ */
+ public Object getObject() {
+ return obj;
+ }
+
+ /**
+ * Call a method on the object with no parameters.
+ * @param methodName the name of the method to call
+ * @return the object returned by the method
+ */
+ public Object invoke(String methodName) {
+ return ReflectUtil.invoke(obj, methodName);
+ }
+
+ /**
+ * Call a method on the object with one argument.
+ * @param methodName the name of the method to call
+ * @param argType the type of argument.
+ * @param arg the value of the argument.
+ * @return the object returned by the method
+ */
+ public Object invoke(
+ String methodName, Class argType, Object arg) {
+ return ReflectUtil.invoke(obj, methodName, argType, arg);
+ }
+
+ /**
+ * Call a method on the object with one argument.
+ * @param methodName the name of the method to call
+ * @param argType1 the type of the first argument.
+ * @param arg1 the value of the first argument.
+ * @param argType2 the type of the second argument.
+ * @param arg2 the value of the second argument.
+ * @return the object returned by the method
+ */
+ public Object invoke(
+ String methodName, Class argType1, Object arg1,
+ Class argType2, Object arg2) {
+ return ReflectUtil.invoke(
+ obj, methodName, argType1, arg1, argType2, arg2);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/RegexpPatternMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/RegexpPatternMapper.java
new file mode 100644
index 00000000..fa620d9a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/RegexpPatternMapper.java
@@ -0,0 +1,159 @@
+/*
+ * 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.util;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.regexp.RegexpMatcher;
+import org.apache.tools.ant.util.regexp.RegexpMatcherFactory;
+import org.apache.tools.ant.util.regexp.RegexpUtil;
+
+/**
+ * Implementation of FileNameMapper that does regular expression
+ * replacements.
+ *
+ */
+public class RegexpPatternMapper implements FileNameMapper {
+
+ private static final int DECIMAL = 10;
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected RegexpMatcher reg = null;
+ protected char[] to = null;
+ protected StringBuffer result = new StringBuffer();
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Constructor for RegexpPatternMapper.
+ * @throws BuildException on error.
+ */
+ public RegexpPatternMapper() throws BuildException {
+ reg = (new RegexpMatcherFactory()).newRegexpMatcher();
+ }
+
+ private boolean handleDirSep = false;
+ private int regexpOptions = 0;
+
+ /**
+ * Attribute specifying whether to ignore the difference
+ * between / and \ (the two common directory characters).
+ * @param handleDirSep a boolean, default is false.
+ * @since Ant 1.6.3
+ */
+ public void setHandleDirSep(boolean handleDirSep) {
+ this.handleDirSep = handleDirSep;
+ }
+
+ /**
+ * Attribute specifying whether to ignore the case difference
+ * in the names.
+ *
+ * @param caseSensitive a boolean, default is false.
+ * @since Ant 1.6.3
+ */
+ public void setCaseSensitive(boolean caseSensitive) {
+ regexpOptions = RegexpUtil.asOptions(caseSensitive);
+ }
+
+ /**
+ * Sets the &quot;from&quot; pattern. Required.
+ * @param from the from pattern.
+ * @throws BuildException on error.
+ */
+ public void setFrom(String from) throws BuildException {
+ if (from != null) {
+ try {
+ reg.setPattern(from);
+ } catch (NoClassDefFoundError e) {
+ // depending on the implementation the actual RE won't
+ // get instantiated in the constructor.
+ throw new BuildException("Cannot load regular expression matcher",
+ e);
+ }
+ } else {
+ throw new BuildException("this mapper requires a 'from' attribute");
+ }
+ }
+
+ /**
+ * Sets the &quot;to&quot; pattern. Required.
+ * @param to the to pattern.
+ * @throws BuildException on error.
+ */
+ public void setTo(String to) {
+ if (to != null) {
+ this.to = to.toCharArray();
+ } else {
+ throw new BuildException("this mapper requires a 'to' attribute");
+ }
+ }
+
+ /**
+ * Returns null if the source file name doesn't match the
+ * &quot;from&quot; pattern, an one-element array containing the
+ * translated file otherwise.
+ * @param sourceFileName the source file name
+ * @return a one-element array containing the translated file or
+ * null if the to pattern did not match
+ */
+ public String[] mapFileName(String sourceFileName) {
+ if (handleDirSep) {
+ if (sourceFileName.indexOf("\\") != -1) {
+ sourceFileName = sourceFileName.replace('\\', '/');
+ }
+ }
+ if (reg == null || to == null
+ || !reg.matches(sourceFileName, regexpOptions)) {
+ return null;
+ }
+ return new String[] {replaceReferences(sourceFileName)};
+ }
+
+ /**
+ * Replace all backreferences in the to pattern with the matched
+ * groups of the source.
+ * @param source the source file name.
+ * @return the translated file name.
+ */
+ protected String replaceReferences(String source) {
+ Vector v = reg.getGroups(source, regexpOptions);
+
+ result.setLength(0);
+ for (int i = 0; i < to.length; i++) {
+ if (to[i] == '\\') {
+ if (++i < to.length) {
+ int value = Character.digit(to[i], DECIMAL);
+ if (value > -1) {
+ result.append((String) v.elementAt(value));
+ } else {
+ result.append(to[i]);
+ }
+ } else {
+ // TODO - should throw an exception instead?
+ result.append('\\');
+ }
+ } else {
+ result.append(to[i]);
+ }
+ }
+ return result.substring(0);
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ResourceUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ResourceUtils.java
new file mode 100644
index 00000000..6397f714
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ResourceUtils.java
@@ -0,0 +1,860 @@
+/*
+ * 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.util;
+
+import java.io.BufferedInputStream;
+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.nio.channels.FileChannel;
+import java.util.Arrays;
+import java.util.Vector;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.filters.util.ChainReaderHelper;
+import org.apache.tools.ant.types.FilterSetCollection;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.ResourceFactory;
+import org.apache.tools.ant.types.TimeComparison;
+import org.apache.tools.ant.types.resources.Appendable;
+import org.apache.tools.ant.types.resources.FileProvider;
+import org.apache.tools.ant.types.resources.FileResource;
+import org.apache.tools.ant.types.resources.Resources;
+import org.apache.tools.ant.types.resources.Restrict;
+import org.apache.tools.ant.types.resources.StringResource;
+import org.apache.tools.ant.types.resources.Touchable;
+import org.apache.tools.ant.types.resources.Union;
+import org.apache.tools.ant.types.resources.selectors.Date;
+import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
+import org.apache.tools.ant.types.selectors.SelectorUtils;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/**
+ * This class provides utility methods to process Resources.
+ *
+ * @since Ant 1.5.2
+ */
+public class ResourceUtils {
+
+ /** Utilities used for file operations */
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /**
+ * Name of charset "ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1".
+ *
+ * @since Ant 1.8.1
+ */
+ public static final String ISO_8859_1 = "ISO-8859-1";
+
+ private static final long MAX_IO_CHUNK_SIZE = 16*1024*1024; // 16 MB
+
+ /**
+ * Tells which source files should be reprocessed based on the
+ * last modification date of target files.
+ * @param logTo where to send (more or less) interesting output.
+ * @param source array of resources bearing relative path and last
+ * modification date.
+ * @param mapper filename mapper indicating how to find the target
+ * files.
+ * @param targets object able to map as a resource a relative path
+ * at <b>destination</b>.
+ * @return array containing the source files which need to be
+ * copied or processed, because the targets are out of date or do
+ * not exist.
+ */
+ public static Resource[] selectOutOfDateSources(final ProjectComponent logTo,
+ final Resource[] source,
+ final FileNameMapper mapper,
+ final ResourceFactory targets) {
+ return selectOutOfDateSources(logTo, source, mapper, targets,
+ FILE_UTILS.getFileTimestampGranularity());
+ }
+
+ /**
+ * Tells which source files should be reprocessed based on the
+ * last modification date of target files.
+ * @param logTo where to send (more or less) interesting output.
+ * @param source array of resources bearing relative path and last
+ * modification date.
+ * @param mapper filename mapper indicating how to find the target
+ * files.
+ * @param targets object able to map as a resource a relative path
+ * at <b>destination</b>.
+ * @param granularity The number of milliseconds leeway to give
+ * before deciding a target is out of date.
+ * @return array containing the source files which need to be
+ * copied or processed, because the targets are out of date or do
+ * not exist.
+ * @since Ant 1.6.2
+ */
+ public static Resource[] selectOutOfDateSources(final ProjectComponent logTo,
+ final Resource[] source,
+ final FileNameMapper mapper,
+ final ResourceFactory targets,
+ final long granularity) {
+ final Union u = new Union();
+ u.addAll(Arrays.asList(source));
+ final ResourceCollection rc
+ = selectOutOfDateSources(logTo, u, mapper, targets, granularity);
+ return rc.size() == 0 ? new Resource[0] : ((Union) rc).listResources();
+ }
+
+ /**
+ * Tells which sources should be reprocessed based on the
+ * last modification date of targets.
+ * @param logTo where to send (more or less) interesting output.
+ * @param source ResourceCollection.
+ * @param mapper filename mapper indicating how to find the target Resources.
+ * @param targets object able to map a relative path as a Resource.
+ * @param granularity The number of milliseconds leeway to give
+ * before deciding a target is out of date.
+ * @return ResourceCollection.
+ * @since Ant 1.7
+ */
+ public static ResourceCollection selectOutOfDateSources(final ProjectComponent logTo,
+ final ResourceCollection source,
+ final FileNameMapper mapper,
+ final ResourceFactory targets,
+ final long granularity) {
+ logFuture(logTo, source, granularity);
+ final ResourceSelectorProvider p =
+ new ResourceSelectorProvider() {
+ public ResourceSelector
+ getTargetSelectorForSource(final Resource sr) {
+ return new ResourceSelector() {
+ public boolean isSelected(final Resource target) {
+ /* Extra I/O, probably wasted:
+ if (target.isDirectory()) {
+ return false;
+ }
+ */
+ return SelectorUtils.isOutOfDate(sr, target,
+ granularity);
+ }
+ };
+ }
+ };
+ return selectSources(logTo, source, mapper, targets, p);
+ }
+
+ /**
+ * Tells which sources should be reprocessed because the given
+ * selector selects at least one target.
+ *
+ * @param logTo where to send (more or less) interesting output.
+ * @param source ResourceCollection.
+ * @param mapper filename mapper indicating how to find the target Resources.
+ * @param targets object able to map a relative path as a Resource.
+ * @param selector returns a selector that is applied to target
+ * files. If it selects at least one target the source will be
+ * added to the returned collection.
+ * @return ResourceCollection.
+ * @since Ant 1.8.0
+ */
+ public static ResourceCollection selectSources(final ProjectComponent logTo,
+ ResourceCollection source,
+ final FileNameMapper mapper,
+ final ResourceFactory targets,
+ final ResourceSelectorProvider selector) {
+ if (source.size() == 0) {
+ logTo.log("No sources found.", Project.MSG_VERBOSE);
+ return Resources.NONE;
+ }
+ source = Union.getInstance(source);
+
+ final Union result = new Union();
+ for (final Resource sr : source) {
+ String srName = sr.getName();
+ srName = srName == null
+ ? srName : srName.replace('/', File.separatorChar);
+
+ String[] targetnames = null;
+ try {
+ targetnames = mapper.mapFileName(srName);
+ } catch (final Exception e) {
+ logTo.log("Caught " + e + " mapping resource " + sr,
+ Project.MSG_VERBOSE);
+ }
+ if (targetnames == null || targetnames.length == 0) {
+ logTo.log(sr + " skipped - don\'t know how to handle it",
+ Project.MSG_VERBOSE);
+ continue;
+ }
+ for (int i = 0; i < targetnames.length; i++) {
+ if (targetnames[i] == null) {
+ targetnames[i] = "(no name)";
+ }
+ }
+ final Union targetColl = new Union();
+ for (int i = 0; i < targetnames.length; i++) {
+ targetColl.add(targets.getResource(
+ targetnames[i].replace(File.separatorChar, '/')));
+ }
+ //find the out-of-date targets:
+ final Restrict r = new Restrict();
+ r.add(selector.getTargetSelectorForSource(sr));
+ r.add(targetColl);
+ if (r.size() > 0) {
+ result.add(sr);
+ final Resource t = r.iterator().next();
+ logTo.log(sr.getName() + " added as " + t.getName()
+ + (t.isExists() ? " is outdated." : " doesn\'t exist."),
+ Project.MSG_VERBOSE);
+ continue;
+ }
+ //log uptodateness of all targets:
+ logTo.log(sr.getName()
+ + " omitted as " + targetColl.toString()
+ + (targetColl.size() == 1 ? " is" : " are ")
+ + " up to date.", Project.MSG_VERBOSE);
+ }
+ return result;
+ }
+
+ /**
+ * Convenience method to copy content from one Resource to another.
+ * No filtering is performed.
+ *
+ * @param source the Resource to copy from.
+ * Must not be <code>null</code>.
+ * @param dest the Resource to copy to.
+ * Must not be <code>null</code>.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.7
+ */
+ public static void copyResource(final Resource source, final Resource dest) throws IOException {
+ copyResource(source, dest, null);
+ }
+
+ /**
+ * Convenience method to copy content from one Resource to another.
+ * No filtering is performed.
+ *
+ * @param source the Resource to copy from.
+ * Must not be <code>null</code>.
+ * @param dest the Resource to copy to.
+ * Must not be <code>null</code>.
+ * @param project the project instance.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.7
+ */
+ public static void copyResource(final Resource source, final Resource dest, final Project project)
+ throws IOException {
+ copyResource(source, dest, null, null, false,
+ false, null, null, project);
+ }
+
+ // CheckStyle:ParameterNumberCheck OFF - bc
+ /**
+ * Convenience method to copy content from one Resource to another
+ * specifying whether token filtering must be used, whether filter chains
+ * must be used, whether newer destination files may be overwritten and
+ * whether the last modified time of <code>dest</code> file should be made
+ * equal to the last modified time of <code>source</code>.
+ *
+ * @param source the Resource to copy from.
+ * Must not be <code>null</code>.
+ * @param dest the Resource to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param filterChains filterChains to apply during the copy.
+ * @param overwrite Whether or not the destination Resource should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the destination Resource should be set to that
+ * of the source.
+ * @param inputEncoding the encoding used to read the files.
+ * @param outputEncoding the encoding used to write the files.
+ * @param project the project instance.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.7
+ */
+ public static void copyResource(final Resource source, final Resource dest,
+ final FilterSetCollection filters, final Vector filterChains,
+ final boolean overwrite, final boolean preserveLastModified,
+ final String inputEncoding, final String outputEncoding,
+ final Project project)
+ throws IOException {
+ copyResource(source, dest, filters, filterChains, overwrite, preserveLastModified, false, inputEncoding, outputEncoding, project);
+ }
+
+ // CheckStyle:ParameterNumberCheck OFF - bc
+ /**
+ * Convenience method to copy content from one Resource to another
+ * specifying whether token filtering must be used, whether filter chains
+ * must be used, whether newer destination files may be overwritten and
+ * whether the last modified time of <code>dest</code> file should be made
+ * equal to the last modified time of <code>source</code>.
+ *
+ * @param source the Resource to copy from.
+ * Must not be <code>null</code>.
+ * @param dest the Resource to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param filterChains filterChains to apply during the copy.
+ * @param overwrite Whether or not the destination Resource should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the destination Resource should be set to that
+ * of the source.
+ * @param append Whether to append to an Appendable Resource.
+ * @param inputEncoding the encoding used to read the files.
+ * @param outputEncoding the encoding used to write the files.
+ * @param project the project instance.
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.8
+ */
+ public static void copyResource(final Resource source, final Resource dest,
+ final FilterSetCollection filters, final Vector filterChains,
+ final boolean overwrite, final boolean preserveLastModified,
+ final boolean append,
+ final String inputEncoding, final String outputEncoding,
+ final Project project)
+ throws IOException {
+ copyResource(source, dest, filters, filterChains, overwrite,
+ preserveLastModified, append, inputEncoding,
+ outputEncoding, project, /* force: */ false);
+ }
+
+ /**
+ * Convenience method to copy content from one Resource to another
+ * specifying whether token filtering must be used, whether filter chains
+ * must be used, whether newer destination files may be overwritten and
+ * whether the last modified time of <code>dest</code> file should be made
+ * equal to the last modified time of <code>source</code>.
+ *
+ * @param source the Resource to copy from.
+ * Must not be <code>null</code>.
+ * @param dest the Resource to copy to.
+ * Must not be <code>null</code>.
+ * @param filters the collection of filters to apply to this copy.
+ * @param filterChains filterChains to apply during the copy.
+ * @param overwrite Whether or not the destination Resource should be
+ * overwritten if it already exists.
+ * @param preserveLastModified Whether or not the last modified time of
+ * the destination Resource should be set to that
+ * of the source.
+ * @param append Whether to append to an Appendable Resource.
+ * @param inputEncoding the encoding used to read the files.
+ * @param outputEncoding the encoding used to write the files.
+ * @param project the project instance.
+ * @param force whether read-only target files will be overwritten
+ *
+ * @throws IOException if the copying fails.
+ *
+ * @since Ant 1.8.2
+ */
+ public static void copyResource(final Resource source, final Resource dest,
+ final FilterSetCollection filters, final Vector filterChains,
+ final boolean overwrite, final boolean preserveLastModified,
+ final boolean append,
+ final String inputEncoding, final String outputEncoding,
+ final Project project, final boolean force)
+ throws IOException {
+ if (!(overwrite || SelectorUtils.isOutOfDate(source, dest, FileUtils.getFileUtils()
+ .getFileTimestampGranularity()))) {
+ return;
+ }
+ final boolean filterSetsAvailable = (filters != null
+ && filters.hasFilters());
+ final boolean filterChainsAvailable = (filterChains != null
+ && filterChains.size() > 0);
+ String effectiveInputEncoding = null;
+ if (source instanceof StringResource) {
+ effectiveInputEncoding = ((StringResource) source).getEncoding();
+ } else {
+ effectiveInputEncoding = inputEncoding;
+ }
+ File destFile = null;
+ if (dest.as(FileProvider.class) != null) {
+ destFile = dest.as(FileProvider.class).getFile();
+ }
+ if (destFile != null && destFile.isFile() && !destFile.canWrite()) {
+ if (!force) {
+ throw new ReadOnlyTargetFileException(destFile);
+ } else if (!FILE_UTILS.tryHardToDelete(destFile)) {
+ throw new IOException("failed to delete read-only "
+ + "destination file " + destFile);
+ }
+ }
+
+ if (filterSetsAvailable) {
+ copyWithFilterSets(source, dest, filters, filterChains,
+ filterChainsAvailable, append,
+ effectiveInputEncoding, outputEncoding,
+ project);
+ } else if (filterChainsAvailable
+ || (effectiveInputEncoding != null
+ && !effectiveInputEncoding.equals(outputEncoding))
+ || (effectiveInputEncoding == null && outputEncoding != null)) {
+ copyWithFilterChainsOrTranscoding(source, dest, filterChains,
+ filterChainsAvailable, append,
+ effectiveInputEncoding,
+ outputEncoding, project);
+ } else {
+ boolean copied = false;
+ if (source.as(FileProvider.class) != null
+ && destFile != null && !append) {
+ final File sourceFile =
+ source.as(FileProvider.class).getFile();
+ try {
+ copyUsingFileChannels(sourceFile, destFile);
+ copied = true;
+ } catch (final IOException ex) {
+ String msg = "Attempt to copy " + sourceFile
+ + " to " + destFile + " using NIO Channels"
+ + " failed due to '" + ex.getMessage()
+ + "'. Falling back to streams.";
+ if (project != null) {
+ project.log(msg, Project.MSG_WARN);
+ } else {
+ System.err.println(msg);
+ }
+ }
+ }
+ if (!copied) {
+ copyUsingStreams(source, dest, append, project);
+ }
+ }
+ if (preserveLastModified) {
+ final Touchable t = dest.as(Touchable.class);
+ if (t != null) {
+ setLastModified(t, source.getLastModified());
+ }
+ }
+ }
+ // CheckStyle:ParameterNumberCheck ON
+
+ /**
+ * Set the last modified time of an object implementing
+ * org.apache.tools.ant.types.resources.Touchable .
+ *
+ * @param t the Touchable whose modified time is to be set.
+ * @param time the time to which the last modified time is to be set.
+ * if this is -1, the current time is used.
+ * @since Ant 1.7
+ */
+ public static void setLastModified(final Touchable t, final long time) {
+ t.touch((time < 0) ? System.currentTimeMillis() : time);
+ }
+
+ /**
+ * Compares the contents of two Resources.
+ *
+ * @param r1 the Resource whose content is to be compared.
+ * @param r2 the other Resource whose content is to be compared.
+ * @param text true if the content is to be treated as text and
+ * differences in kind of line break are to be ignored.
+ *
+ * @return true if the content of the Resources is the same.
+ *
+ * @throws IOException if the Resources cannot be read.
+ * @since Ant 1.7
+ */
+ public static boolean contentEquals(final Resource r1, final Resource r2, final boolean text) throws IOException {
+ if (r1.isExists() != r2.isExists()) {
+ return false;
+ }
+ if (!r1.isExists()) {
+ // two not existing files are equal
+ return true;
+ }
+ // should the following two be switched? If r1 and r2 refer to the same file,
+ // isn't their content equal regardless of whether that file is a directory?
+ if (r1.isDirectory() || r2.isDirectory()) {
+ // don't want to compare directory contents for now
+ return false;
+ }
+ if (r1.equals(r2)) {
+ return true;
+ }
+ if (!text) {
+ final long s1 = r1.getSize();
+ final long s2 = r2.getSize();
+ if (s1 != Resource.UNKNOWN_SIZE && s2 != Resource.UNKNOWN_SIZE
+ && s1 != s2) {
+ return false;
+ }
+ }
+ return compareContent(r1, r2, text) == 0;
+ }
+
+ /**
+ * Compare the content of two Resources. A nonexistent Resource's
+ * content is "less than" that of an existing Resource; a directory-type
+ * Resource's content is "less than" that of a file-type Resource.
+ * @param r1 the Resource whose content is to be compared.
+ * @param r2 the other Resource whose content is to be compared.
+ * @param text true if the content is to be treated as text and
+ * differences in kind of line break are to be ignored.
+ * @return a negative integer, zero, or a positive integer as the first
+ * argument is less than, equal to, or greater than the second.
+ * @throws IOException if the Resources cannot be read.
+ * @since Ant 1.7
+ */
+ public static int compareContent(final Resource r1, final Resource r2, final boolean text) throws IOException {
+ if (r1.equals(r2)) {
+ return 0;
+ }
+ final boolean e1 = r1.isExists();
+ final boolean e2 = r2.isExists();
+ if (!(e1 || e2)) {
+ return 0;
+ }
+ if (e1 != e2) {
+ return e1 ? 1 : -1;
+ }
+ final boolean d1 = r1.isDirectory();
+ final boolean d2 = r2.isDirectory();
+ if (d1 && d2) {
+ return 0;
+ }
+ if (d1 || d2) {
+ return d1 ? -1 : 1;
+ }
+ return text ? textCompare(r1, r2) : binaryCompare(r1, r2);
+ }
+
+ /**
+ * Convenience method to turn any fileProvider into a basic
+ * FileResource with the file's immediate parent as the basedir,
+ * for tasks that need one.
+ * @param fileProvider input
+ * @return fileProvider if it is a FileResource instance, or a new
+ * FileResource with fileProvider's file.
+ * @since Ant 1.8
+ */
+ public static FileResource asFileResource(final FileProvider fileProvider) {
+ if (fileProvider instanceof FileResource || fileProvider == null) {
+ return (FileResource) fileProvider;
+ }
+ final FileResource result = new FileResource(fileProvider.getFile());
+ result.setProject(Project.getProject(fileProvider));
+ return result;
+ }
+
+ /**
+ * Binary compares the contents of two Resources.
+ * <p>
+ * simple but sub-optimal comparison algorithm. written for working
+ * rather than fast. Better would be a block read into buffers followed
+ * by long comparisons apart from the final 1-7 bytes.
+ * </p>
+ *
+ * @param r1 the Resource whose content is to be compared.
+ * @param r2 the other Resource whose content is to be compared.
+ * @return a negative integer, zero, or a positive integer as the first
+ * argument is less than, equal to, or greater than the second.
+ * @throws IOException if the Resources cannot be read.
+ * @since Ant 1.7
+ */
+ private static int binaryCompare(final Resource r1, final Resource r2) throws IOException {
+ InputStream in1 = null;
+ InputStream in2 = null;
+ try {
+ in1 = new BufferedInputStream(r1.getInputStream());
+ in2 = new BufferedInputStream(r2.getInputStream());
+
+ for (int b1 = in1.read(); b1 != -1; b1 = in1.read()) {
+ final int b2 = in2.read();
+ if (b1 != b2) {
+ return b1 > b2 ? 1 : -1;
+ }
+ }
+ return in2.read() == -1 ? 0 : -1;
+ } finally {
+ FileUtils.close(in1);
+ FileUtils.close(in2);
+ }
+ }
+
+ /**
+ * Text compares the contents of two Resources.
+ * Ignores different kinds of line endings.
+ * @param r1 the Resource whose content is to be compared.
+ * @param r2 the other Resource whose content is to be compared.
+ * @return a negative integer, zero, or a positive integer as the first
+ * argument is less than, equal to, or greater than the second.
+ * @throws IOException if the Resources cannot be read.
+ * @since Ant 1.7
+ */
+ private static int textCompare(final Resource r1, final Resource r2) throws IOException {
+ BufferedReader in1 = null;
+ BufferedReader in2 = null;
+ try {
+ in1 = new BufferedReader(new InputStreamReader(r1.getInputStream()));
+ in2 = new BufferedReader(new InputStreamReader(r2.getInputStream()));
+
+ String expected = in1.readLine();
+ while (expected != null) {
+ final String actual = in2.readLine();
+ if (!expected.equals(actual)) {
+ if (actual == null) {
+ return 1;
+ }
+ return expected.compareTo(actual);
+ }
+ expected = in1.readLine();
+ }
+ return in2.readLine() == null ? 0 : -1;
+ } finally {
+ FileUtils.close(in1);
+ FileUtils.close(in2);
+ }
+ }
+
+ /**
+ * Log which Resources (if any) have been modified in the future.
+ * @param logTo the ProjectComponent to do the logging.
+ * @param rc the collection of Resources to check.
+ * @param granularity the timestamp granularity to use.
+ * @since Ant 1.7
+ */
+ private static void logFuture(final ProjectComponent logTo,
+ final ResourceCollection rc, final long granularity) {
+ final long now = System.currentTimeMillis() + granularity;
+ final Date sel = new Date();
+ sel.setMillis(now);
+ sel.setWhen(TimeComparison.AFTER);
+ final Restrict future = new Restrict();
+ future.add(sel);
+ future.add(rc);
+ for (final Resource r : future) {
+ logTo.log("Warning: " + r.getName() + " modified in the future.", Project.MSG_WARN);
+ }
+ }
+
+ private static void copyWithFilterSets(final Resource source, final Resource dest,
+ final FilterSetCollection filters,
+ final Vector filterChains,
+ final boolean filterChainsAvailable,
+ final boolean append, final String inputEncoding,
+ final String outputEncoding,
+ final Project project)
+ throws IOException {
+ BufferedReader in = null;
+ BufferedWriter out = null;
+ try {
+ InputStreamReader isr = null;
+ if (inputEncoding == null) {
+ isr = new InputStreamReader(source.getInputStream());
+ } else {
+ isr = new InputStreamReader(source.getInputStream(),
+ inputEncoding);
+ }
+ in = new BufferedReader(isr);
+ final OutputStream os = getOutputStream(dest, append, project);
+ OutputStreamWriter osw;
+ if (outputEncoding == null) {
+ osw = new OutputStreamWriter(os);
+ } else {
+ osw = new OutputStreamWriter(os, outputEncoding);
+ }
+ out = new BufferedWriter(osw);
+ if (filterChainsAvailable) {
+ final ChainReaderHelper crh = new ChainReaderHelper();
+ crh.setBufferSize(FileUtils.BUF_SIZE);
+ crh.setPrimaryReader(in);
+ crh.setFilterChains(filterChains);
+ crh.setProject(project);
+ final Reader rdr = crh.getAssembledReader();
+ in = new BufferedReader(rdr);
+ }
+ final LineTokenizer lineTokenizer = new LineTokenizer();
+ lineTokenizer.setIncludeDelims(true);
+ String newline = null;
+ String line = lineTokenizer.getToken(in);
+ while (line != null) {
+ if (line.length() == 0) {
+ // this should not happen, because the lines are
+ // returned with the end of line delimiter
+ out.newLine();
+ } else {
+ newline = filters.replaceTokens(line);
+ out.write(newline);
+ }
+ line = lineTokenizer.getToken(in);
+ }
+ } finally {
+ FileUtils.close(out);
+ FileUtils.close(in);
+ }
+ }
+
+ private static void copyWithFilterChainsOrTranscoding(final Resource source,
+ final Resource dest,
+ final Vector filterChains,
+ final boolean filterChainsAvailable,
+ final boolean append,
+ final String inputEncoding,
+ final String outputEncoding,
+ final Project project)
+ throws IOException {
+ BufferedReader in = null;
+ BufferedWriter out = null;
+ try {
+ InputStreamReader isr = null;
+ if (inputEncoding == null) {
+ isr = new InputStreamReader(source.getInputStream());
+ } else {
+ isr = new InputStreamReader(source.getInputStream(),
+ inputEncoding);
+ }
+ in = new BufferedReader(isr);
+ final OutputStream os = getOutputStream(dest, append, project);
+ OutputStreamWriter osw;
+ if (outputEncoding == null) {
+ osw = new OutputStreamWriter(os);
+ } else {
+ osw = new OutputStreamWriter(os, outputEncoding);
+ }
+ out = new BufferedWriter(osw);
+ if (filterChainsAvailable) {
+ final ChainReaderHelper crh = new ChainReaderHelper();
+ crh.setBufferSize(FileUtils.BUF_SIZE);
+ crh.setPrimaryReader(in);
+ crh.setFilterChains(filterChains);
+ crh.setProject(project);
+ final Reader rdr = crh.getAssembledReader();
+ in = new BufferedReader(rdr);
+ }
+ final char[] buffer = new char[FileUtils.BUF_SIZE];
+ while (true) {
+ final int nRead = in.read(buffer, 0, buffer.length);
+ if (nRead == -1) {
+ break;
+ }
+ out.write(buffer, 0, nRead);
+ }
+ } finally {
+ FileUtils.close(out);
+ FileUtils.close(in);
+ }
+ }
+
+ private static void copyUsingFileChannels(final File sourceFile,
+ final File destFile)
+ throws IOException {
+
+ final File parent = destFile.getParentFile();
+ if (parent != null && !parent.isDirectory()
+ && !(parent.mkdirs() || parent.isDirectory())) {
+ throw new IOException("failed to create the parent directory"
+ + " for " + destFile);
+ }
+
+ FileInputStream in = null;
+ FileOutputStream out = null;
+ FileChannel srcChannel = null;
+ FileChannel destChannel = null;
+
+ try {
+ in = new FileInputStream(sourceFile);
+ out = new FileOutputStream(destFile);
+
+ srcChannel = in.getChannel();
+ destChannel = out.getChannel();
+
+ long position = 0;
+ final long count = srcChannel.size();
+ while (position < count) {
+ final long chunk = Math.min(MAX_IO_CHUNK_SIZE, count - position);
+ position +=
+ destChannel.transferFrom(srcChannel, position, chunk);
+ }
+ } finally {
+ FileUtils.close(srcChannel);
+ FileUtils.close(destChannel);
+ FileUtils.close(out);
+ FileUtils.close(in);
+ }
+ }
+
+ private static void copyUsingStreams(final Resource source, final Resource dest,
+ final boolean append, final Project project)
+ throws IOException {
+ InputStream in = null;
+ OutputStream out = null;
+ try {
+ in = source.getInputStream();
+ out = getOutputStream(dest, append, project);
+
+ final byte[] buffer = new byte[FileUtils.BUF_SIZE];
+ int count = 0;
+ do {
+ out.write(buffer, 0, count);
+ count = in.read(buffer, 0, buffer.length);
+ } while (count != -1);
+ } finally {
+ FileUtils.close(out);
+ FileUtils.close(in);
+ }
+ }
+
+ private static OutputStream getOutputStream(final Resource resource, final boolean append, final Project project)
+ throws IOException {
+ if (append) {
+ final Appendable a = resource.as(Appendable.class);
+ if (a != null) {
+ return a.getAppendOutputStream();
+ }
+ String msg = "Appendable OutputStream not available for non-appendable resource "
+ + resource + "; using plain OutputStream";
+ if (project != null) {
+ project.log(msg, Project.MSG_VERBOSE);
+ } else {
+ System.out.println(msg);
+ }
+ }
+ return resource.getOutputStream();
+ }
+
+ public interface ResourceSelectorProvider {
+ ResourceSelector getTargetSelectorForSource(Resource source);
+ }
+
+ /**
+ * @since Ant 1.9.4
+ */
+ public static class ReadOnlyTargetFileException extends IOException {
+ private static final long serialVersionUID = 1L;
+
+ public ReadOnlyTargetFileException(final File destFile) {
+ super("can't write to read-only destination file " + destFile);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/RetryHandler.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/RetryHandler.java
new file mode 100644
index 00000000..dd62bc27
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/RetryHandler.java
@@ -0,0 +1,74 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * A simple utility class to take a piece of code (that implements
+ * <code>Retryable</code> interface) and executes that with possibility to
+ * retry the execution in case of IOException.
+ */
+public class RetryHandler {
+
+ private int retriesAllowed = 0;
+ private Task task;
+
+ /**
+ * Create a new RetryingHandler.
+ *
+ * @param retriesAllowed how many times to retry
+ * @param task the Ant task that is is executed from, used for logging only
+ */
+ public RetryHandler(int retriesAllowed, Task task) {
+ this.retriesAllowed = retriesAllowed;
+ this.task = task;
+ }
+
+ /**
+ * Execute the <code>Retryable</code> code with specified number of retries.
+ *
+ * @param exe the code to execute
+ * @param desc some descriptive text for this piece of code, used for logging
+ * @throws IOException if the number of retries has exceeded the allowed limit
+ */
+ public void execute(Retryable exe, String desc) throws IOException {
+ int retries = 0;
+ while (true) {
+ try {
+ exe.execute();
+ break;
+ } catch (IOException e) {
+ retries++;
+ if (retries > this.retriesAllowed && this.retriesAllowed > -1) {
+ task.log("try #" + retries + ": IO error ("
+ + desc + "), number of maximum retries reached ("
+ + this.retriesAllowed + "), giving up", Project.MSG_WARN);
+ throw e;
+ } else {
+ task.log("try #" + retries + ": IO error (" + desc
+ + "), retrying", Project.MSG_WARN);
+ }
+ }
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Retryable.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Retryable.java
new file mode 100644
index 00000000..537244a1
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Retryable.java
@@ -0,0 +1,38 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+
+
+/**
+ * Simple interface for executing a piece of code. Used for writing anonymous inner
+ * classes in FTP task for retry-on-IOException behaviour.
+ *
+ * @see RetryHandler
+ */
+public interface Retryable {
+ /** The value to use to never give up. */
+ int RETRY_FOREVER = -1;
+ /**
+ * Called to execute the code.
+ * @throws IOException if there is a problem.
+ */
+ void execute() throws IOException;
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptFixBSFPath.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptFixBSFPath.java
new file mode 100644
index 00000000..ca76e56b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptFixBSFPath.java
@@ -0,0 +1,147 @@
+/*
+ * 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.util;
+
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * A class to modify a classloader to
+ * support BSF language support.
+ */
+public class ScriptFixBSFPath {
+ private static final String UTIL_OPTIONAL_PACKAGE
+ = "org.apache.tools.ant.util.optional";
+
+ private static final String BSF_PACKAGE = "org.apache.bsf";
+ private static final String BSF_MANAGER = BSF_PACKAGE + ".BSFManager";
+ private static final String BSF_SCRIPT_RUNNER
+ = UTIL_OPTIONAL_PACKAGE + ".ScriptRunner";
+
+ /**
+ * The following are languages that have
+ * scripting engines embedded in bsf.jar.
+ * The array is converted to a map of
+ * languagename->classname.
+ */
+ private static final String[] BSF_LANGUAGES =
+ new String[] {
+ "js", "org.mozilla.javascript.Scriptable",
+ "javascript", "org.mozilla.javascript.Scriptable",
+ "jacl", "tcl.lang.Interp",
+ "netrexx", "netrexx.lang.Rexx",
+ "nrx", "netrexx.lang.Rexx",
+ "jython", "org.python.core.Py",
+ "py", "org.python.core.Py",
+ "xslt", "org.apache.xpath.objects.XObject"};
+
+ /** A map of languages for which the engine in located in bsf */
+ private static final Map BSF_LANGUAGE_MAP = new HashMap();
+ static {
+ for (int i = 0; i < BSF_LANGUAGES.length; i = i + 2) {
+ BSF_LANGUAGE_MAP.put(BSF_LANGUAGES[i], BSF_LANGUAGES[i + 1]);
+ }
+ }
+
+ private File getClassSource(ClassLoader loader, String className) {
+ return LoaderUtils.getResourceSource(
+ loader,
+ LoaderUtils.classNameToResource(className));
+ }
+
+ private File getClassSource(String className) {
+ return getClassSource(getClass().getClassLoader(), className);
+ }
+
+ /**
+ * Check if need to mess about with the classloader.
+ * The class loader will need to be modified for two
+ * reasons:
+ * <ol>
+ * <li>language is at a higher level than bsf for engines in bsf,
+ * move bsf.
+ * </li>
+ * <li>bsf is at a higher level than oata.util.optional.ScriptRunner
+ * </li>
+ * </ol>
+ *
+ * Assume a simple model for the loader:
+ * thisloader&lt;-customloader
+ * or
+ * thisloader
+ *
+ * @param loader the classloader to fix.
+ * @param language the language to use.
+ */
+ public void fixClassLoader(ClassLoader loader, String language) {
+ if (loader == getClass().getClassLoader()
+ || !(loader instanceof AntClassLoader)) {
+ return;
+ }
+ ClassLoader myLoader = getClass().getClassLoader();
+ AntClassLoader fixLoader = (AntClassLoader) loader;
+
+ // Check for location of bsf in this classloader
+ File bsfSource = getClassSource(BSF_MANAGER);
+
+ // If bsf is not in the classloader for this, need to move
+ // runner.
+ boolean needMoveRunner = (bsfSource == null);
+
+ // Check for location of language
+ String languageClassName = (String) BSF_LANGUAGE_MAP.get(language);
+
+ // Check if need to need to move bsf
+ boolean needMoveBsf =
+ bsfSource != null
+ && languageClassName != null
+ && !LoaderUtils.classExists(myLoader, languageClassName)
+ && LoaderUtils.classExists(loader, languageClassName);
+
+ // Update need to move runner
+ needMoveRunner = needMoveRunner || needMoveBsf;
+
+ // Check if bsf in place
+ if (bsfSource == null) {
+ bsfSource = getClassSource(loader, BSF_MANAGER);
+ }
+
+ if (bsfSource == null) {
+ throw new BuildException(
+ "Unable to find BSF classes for scripting");
+ }
+
+ if (needMoveBsf) {
+ fixLoader.addPathComponent(bsfSource);
+ fixLoader.addLoaderPackageRoot(BSF_PACKAGE);
+ }
+
+ if (needMoveRunner) {
+ fixLoader.addPathComponent(
+ LoaderUtils.getResourceSource(
+ fixLoader,
+ LoaderUtils.classNameToResource(BSF_SCRIPT_RUNNER)));
+ fixLoader.addLoaderPackageRoot(UTIL_OPTIONAL_PACKAGE);
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunner.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunner.java
new file mode 100644
index 00000000..735e5555
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunner.java
@@ -0,0 +1,27 @@
+/*
+ * 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.util;
+
+/**
+ * This class is here for backwards compatibility.
+ * @deprecated Implementation moved to another location. Use
+ * that org.apache.tools.ant.types.optional.ScriptRunner instead.
+ */
+public class ScriptRunner
+ extends org.apache.tools.ant.util.optional.ScriptRunner {
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java
new file mode 100644
index 00000000..b8aa01a8
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerBase.java
@@ -0,0 +1,360 @@
+/*
+ * 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.util;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceCollection;
+
+/**
+ * This is a common abstract base case for script runners.
+ * These classes need to implement executeScript, evaluateScript
+ * and supportsLanguage.
+ * @since Ant 1.7.0
+ */
+public abstract class ScriptRunnerBase {
+ /** Whether to keep the engine between calls to execute/eval */
+ private boolean keepEngine = false;
+
+ /** Script language */
+ private String language;
+
+ /** Script content */
+ private String script = "";
+
+ /** Project this runner is used in */
+ private Project project;
+
+ /** Classloader to be used when running the script. */
+ private ClassLoader scriptLoader;
+
+ /** Beans to be provided to the script */
+ private Map beans = new HashMap();
+
+ /**
+ * Add a list of named objects to the list to be exported to the script
+ *
+ * @param dictionary a map of objects to be placed into the script context
+ * indexed by String names.
+ */
+ public void addBeans(Map dictionary) {
+ for (Iterator i = dictionary.keySet().iterator(); i.hasNext();) {
+ String key = (String) i.next();
+ try {
+ Object val = dictionary.get(key);
+ addBean(key, val);
+ } catch (BuildException ex) {
+ // The key is in the dictionary but cannot be retrieved
+ // This is usually due references that refer to tasks
+ // that have not been taskdefed in the current run.
+ // Ignore
+ }
+ }
+ }
+
+ /**
+ * Add a single object into the script context.
+ *
+ * @param key the name in the context this object is to stored under.
+ * @param bean the object to be stored in the script context.
+ */
+ public void addBean(String key, Object bean) {
+ boolean isValid = key.length() > 0
+ && Character.isJavaIdentifierStart(key.charAt(0));
+
+ for (int i = 1; isValid && i < key.length(); i++) {
+ isValid = Character.isJavaIdentifierPart(key.charAt(i));
+ }
+
+ if (isValid) {
+ beans.put(key, bean);
+ }
+ }
+
+ /**
+ * Get the beans used for the script.
+ * @return the map of beans.
+ */
+ protected Map getBeans() {
+ return beans;
+ }
+
+ /**
+ * Do the work.
+ * @param execName the name that will be passed to BSF for this script
+ * execution.
+ */
+ public abstract void executeScript(String execName);
+
+ /**
+ * Evaluate the script.
+ * @param execName the name that will be passed to the
+ * scripting engine for this script execution.
+ * @return the result of evaluating the script.
+ */
+ public abstract Object evaluateScript(String execName);
+
+ /**
+ * Check if a script engine can be created for
+ * this language.
+ * @return true if a script engine can be created, false
+ * otherwise.
+ */
+ public abstract boolean supportsLanguage();
+
+ /**
+ * Get the name of the manager prefix used for this
+ * scriptrunner.
+ * @return the prefix string.
+ */
+ public abstract String getManagerName();
+
+ /**
+ * Defines the language (required).
+ * @param language the scripting language name for the script.
+ */
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ /**
+ * Get the script language
+ * @return the script language
+ */
+ public String getLanguage() {
+ return language;
+ }
+
+ /**
+ * Set the script classloader.
+ * @param classLoader the classloader to use.
+ */
+ public void setScriptClassLoader(ClassLoader classLoader) {
+ this.scriptLoader = classLoader;
+ }
+
+ /**
+ * Get the classloader used to load the script engine.
+ * @return the classloader.
+ */
+ protected ClassLoader getScriptClassLoader() {
+ return scriptLoader;
+ }
+
+ /**
+ * Whether to keep the script engine between calls.
+ * @param keepEngine if true, keep the engine.
+ */
+ public void setKeepEngine(boolean keepEngine) {
+ this.keepEngine = keepEngine;
+ }
+
+ /**
+ * Get the keep engine attribute.
+ * @return the attribute.
+ */
+ public boolean getKeepEngine() {
+ return keepEngine;
+ }
+
+ /**
+ * Load the script from an external file; optional.
+ * @param file the file containing the script source.
+ */
+ public void setSrc(File file) {
+ String filename = file.getPath();
+ if (!file.exists()) {
+ throw new BuildException("file " + filename + " not found.");
+ }
+ try {
+ readSource(new FileReader(file), filename);
+ } catch (FileNotFoundException e) {
+ //this can only happen if the file got deleted a short moment ago
+ throw new BuildException("file " + filename + " not found.");
+ }
+ }
+
+ /**
+ * Read some source in from the given reader
+ * @param reader the reader; this is closed afterwards.
+ * @param name the name to use in error messages
+ */
+ private void readSource(Reader reader, String name) {
+ BufferedReader in = null;
+ try {
+ in = new BufferedReader(reader);
+ script += FileUtils.safeReadFully(in);
+ } catch (IOException ex) {
+ throw new BuildException("Failed to read " + name, ex);
+ } finally {
+ FileUtils.close(in);
+ }
+ }
+
+
+ /**
+ * Add a resource to the source list.
+ * @since Ant 1.7.1
+ * @param sourceResource the resource to load
+ * @throws BuildException if the resource cannot be read
+ */
+ public void loadResource(Resource sourceResource) {
+ String name = sourceResource.toLongString();
+ InputStream in = null;
+ try {
+ in = sourceResource.getInputStream();
+ } catch (IOException e) {
+ throw new BuildException("Failed to open " + name, e);
+ } catch (UnsupportedOperationException e) {
+ throw new BuildException(
+ "Failed to open " + name + " -it is not readable", e);
+ }
+ readSource(new InputStreamReader(in), name);
+ }
+
+ /**
+ * Add all resources in a resource collection to the source list.
+ * @since Ant 1.7.1
+ * @param collection the resource to load
+ * @throws BuildException if a resource cannot be read
+ */
+ public void loadResources(ResourceCollection collection) {
+ for (Resource resource : collection) {
+ loadResource(resource);
+ }
+ }
+
+ /**
+ * Set the script text. Properties in the text are not expanded!
+ *
+ * @param text a component of the script text to be added.
+ */
+ public void addText(String text) {
+ script += text;
+ }
+
+ /**
+ * Get the current script text content.
+ * @return the script text.
+ */
+ public String getScript() {
+ return script;
+ }
+
+ /**
+ * Clear the current script text content.
+ */
+ public void clearScript() {
+ this.script = "";
+ }
+
+ /**
+ * Set the project for this runner.
+ * @param project the project.
+ */
+ public void setProject(Project project) {
+ this.project = project;
+ }
+
+ /**
+ * Get the project for this runner.
+ * @return the project.
+ */
+ public Project getProject() {
+ return project;
+ }
+
+ /**
+ * Bind the runner to a project component.
+ * Properties, targets and references are all added as beans;
+ * project is bound to project, and self to the component.
+ * @param component to become <code>self</code>
+ */
+ public void bindToComponent(ProjectComponent component) {
+ project = component.getProject();
+ addBeans(project.getProperties());
+ addBeans(project.getUserProperties());
+ addBeans(project.getCopyOfTargets());
+ addBeans(project.getCopyOfReferences());
+ addBean("project", project);
+ addBean("self", component);
+ }
+
+ /**
+ * Bind the runner to a project component.
+ * The project and self are the only beans set.
+ * @param component to become <code>self</code>
+ */
+ public void bindToComponentMinimum(ProjectComponent component) {
+ project = component.getProject();
+ addBean("project", project);
+ addBean("self", component);
+ }
+
+ /**
+ * Check if the language attribute is set.
+ * @throws BuildException if it is not.
+ */
+ protected void checkLanguage() {
+ if (language == null) {
+ throw new BuildException(
+ "script language must be specified");
+ }
+ }
+
+ /**
+ * Replace the current context classloader with the
+ * script context classloader.
+ * @return the current context classloader.
+ */
+ protected ClassLoader replaceContextLoader() {
+ ClassLoader origContextClassLoader =
+ Thread.currentThread().getContextClassLoader();
+ if (getScriptClassLoader() == null) {
+ setScriptClassLoader(getClass().getClassLoader());
+ }
+ Thread.currentThread().setContextClassLoader(getScriptClassLoader());
+ return origContextClassLoader;
+ }
+
+ /**
+ * Restore the context loader with the original context classloader.
+ *
+ * script context loader.
+ * @param origLoader the original context classloader.
+ */
+ protected void restoreContextLoader(ClassLoader origLoader) {
+ Thread.currentThread().setContextClassLoader(
+ origLoader);
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerCreator.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerCreator.java
new file mode 100644
index 00000000..77e9ee73
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerCreator.java
@@ -0,0 +1,133 @@
+/*
+ * 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.util;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+
+/**
+ * This is a helper class used by ScriptRunnerHelper to
+ * create a ScriptRunner based on a classloader and on a language.
+ */
+public class ScriptRunnerCreator {
+ private static final String AUTO = "auto";
+ private static final String OATAU = "org.apache.tools.ant.util";
+ private static final String UTIL_OPT = OATAU + ".optional";
+
+ private static final String BSF = "bsf";
+ private static final String BSF_PACK = "org.apache.bsf";
+ private static final String BSF_MANAGER = BSF_PACK + ".BSFManager";
+ private static final String BSF_RUNNER = UTIL_OPT + ".ScriptRunner";
+
+ private static final String JAVAX = "javax";
+ private static final String JAVAX_MANAGER = "javax.script.ScriptEngineManager";
+ private static final String JAVAX_RUNNER = UTIL_OPT + ".JavaxScriptRunner";
+
+ private Project project;
+ private String manager;
+ private String language;
+ private ClassLoader scriptLoader = null;
+
+ /**
+ * Constructor for creator.
+ * @param project the current project.
+ */
+ public ScriptRunnerCreator(Project project) {
+ this.project = project;
+ }
+
+ /**
+ * Create a ScriptRunner.
+ * @param manager the script manager ("auto" | "bsf" | "javax")
+ * @param language the language.
+ * @param classLoader the classloader to use
+ * @return the created script runner.
+ * @throws BuildException if unable to create the ScriptRunner.
+ */
+ public synchronized ScriptRunnerBase createRunner(
+ String manager, String language, ClassLoader classLoader) {
+ this.manager = manager;
+ this.language = language;
+ this.scriptLoader = classLoader;
+
+ if (language == null) {
+ throw new BuildException("script language must be specified");
+ }
+ if (!manager.equals(AUTO) && !manager.equals(JAVAX) && !manager.equals(BSF)) {
+ throw new BuildException("Unsupported language prefix " + manager);
+ }
+
+ // Check for bsf first then javax
+ // This version does not check if the scriptManager
+ // supports the language.
+
+ ScriptRunnerBase ret = null;
+ ret = createRunner(BSF, BSF_MANAGER, BSF_RUNNER);
+ if (ret == null) {
+ ret = createRunner(JAVAX, JAVAX_MANAGER, JAVAX_RUNNER);
+ }
+ if (ret != null) {
+ return ret;
+ }
+ if (JAVAX.equals(manager)) {
+ throw new BuildException(
+ "Unable to load the script engine manager " + "(" + JAVAX_MANAGER + ")");
+ }
+ if (BSF.equals(manager)) {
+ throw new BuildException(
+ "Unable to load the BSF script engine manager " + "(" + BSF_MANAGER + ")");
+ }
+ throw new BuildException("Unable to load a script engine manager "
+ + "(" + BSF_MANAGER + " or " + JAVAX_MANAGER + ")");
+ }
+
+ /**
+ * Create a script runner if the scriptManager matches the passed
+ * in manager.
+ * This checks if the script manager exists in the scriptLoader
+ * classloader and if so it creates and returns the script runner.
+ * @param checkManager check if the manager matchs this value.
+ * @param managerClass the name of the script manager class.
+ * @param runnerClass the name of ant's script runner for this manager.
+ * @return the script runner class.
+ * @throws BuildException if there is a problem creating the runner class.
+ */
+ private ScriptRunnerBase createRunner(
+ String checkManager, String managerClass, String runnerClass) {
+ ScriptRunnerBase runner = null;
+ if (!manager.equals(AUTO) && !manager.equals(checkManager)) {
+ return null;
+ }
+ if (scriptLoader.getResource(LoaderUtils.classNameToResource(managerClass)) == null) {
+ return null;
+ }
+ if (managerClass.equals(BSF_MANAGER)) {
+ new ScriptFixBSFPath().fixClassLoader(scriptLoader, language);
+ }
+ try {
+ runner = (ScriptRunnerBase) Class.forName(
+ runnerClass, true, scriptLoader).newInstance();
+ runner.setProject(project);
+ } catch (Exception ex) {
+ throw ReflectUtil.toBuildException(ex);
+ }
+ runner.setLanguage(language);
+ runner.setScriptClassLoader(scriptLoader);
+ return runner;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java
new file mode 100644
index 00000000..9e814d96
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/ScriptRunnerHelper.java
@@ -0,0 +1,206 @@
+/*
+ * 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.util;
+
+import java.io.File;
+
+import org.apache.tools.ant.ProjectComponent;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.Reference;
+import org.apache.tools.ant.types.ResourceCollection;
+import org.apache.tools.ant.types.resources.Union;
+
+/**
+ * A class to help in creating, setting and getting script runners.
+ */
+public class ScriptRunnerHelper {
+ private ClasspathUtils.Delegate cpDelegate = null;
+ private File srcFile;
+ private String manager = "auto";
+ private String language;
+ private String text;
+ private boolean setBeans = true;
+ private ProjectComponent projectComponent;
+ private ClassLoader scriptLoader = null;
+ private Union resources = new Union();
+
+ /**
+ * Set the project component associated with this helper.
+ * @param component the project component that owns this helper.
+ */
+ public void setProjectComponent(ProjectComponent component) {
+ this.projectComponent = component;
+ }
+
+ /**
+ * Create and set text on a script.
+ * @return the created or reused script runner.
+ */
+ public ScriptRunnerBase getScriptRunner() {
+ ScriptRunnerBase runner = getRunner();
+ if (srcFile != null) {
+ runner.setSrc(srcFile);
+ }
+ if (text != null) {
+ runner.addText(text);
+ }
+ if (resources != null) {
+ runner.loadResources(resources);
+ }
+ if (setBeans) {
+ runner.bindToComponent(projectComponent);
+ } else {
+ runner.bindToComponentMinimum(projectComponent);
+ }
+ return runner;
+ }
+
+ /**
+ * Classpath to be used when searching for classes and resources.
+ *
+ * @return an empty Path instance to be configured by Ant.
+ */
+ public Path createClasspath() {
+ return getClassPathDelegate().createClasspath();
+ }
+
+ /**
+ * Set the classpath to be used when searching for classes and resources.
+ *
+ * @param classpath an Ant Path object containing the search path.
+ */
+ public void setClasspath(Path classpath) {
+ getClassPathDelegate().setClasspath(classpath);
+ }
+
+ /**
+ * Set the classpath by reference.
+ *
+ * @param r a Reference to a Path instance to be used as the classpath
+ * value.
+ */
+ public void setClasspathRef(Reference r) {
+ getClassPathDelegate().setClasspathref(r);
+ }
+
+ /**
+ * Load the script from an external file ; optional.
+ *
+ * @param file the file containing the script source.
+ */
+ public void setSrc(File file) {
+ this.srcFile = file;
+ }
+
+ /**
+ * Add script text.
+ *
+ * @param text a component of the script text to be added.
+ */
+ public void addText(String text) {
+ this.text = text;
+ }
+
+ /**
+ * Defines the script manager - defaults to "auto".
+ *
+ * @param manager the scripting manager - "bsf" or "javax" or "auto"
+ */
+ public void setManager(String manager) {
+ this.manager = manager;
+ }
+
+ /**
+ * Defines the language (required).
+ *
+ * @param language the scripting language name for the script.
+ */
+ public void setLanguage(String language) {
+ this.language = language;
+ }
+
+ /**
+ * Get the language.
+ * @return the scripting language.
+ */
+ public String getLanguage() {
+ return language;
+ }
+
+ /**
+ * Set the setbeans attribute.
+ * If this is true, &lt;script&gt; will create variables in the
+ * script instance for all
+ * properties, targets and references of the current project.
+ * It this is false, only the project and self variables will
+ * be set.
+ * The default is true.
+ * @param setBeans the value to set.
+ */
+ public void setSetBeans(boolean setBeans) {
+ this.setBeans = setBeans;
+ }
+
+ /**
+ * Used when called by scriptdef.
+ * @param loader the loader used by scriptdef.
+ */
+ public void setClassLoader(ClassLoader loader) {
+ scriptLoader = loader;
+ }
+
+ private synchronized ClassLoader generateClassLoader() {
+ if (scriptLoader != null) {
+ return scriptLoader;
+ }
+ if (cpDelegate == null) {
+ scriptLoader = getClass().getClassLoader();
+ return scriptLoader;
+ }
+ scriptLoader = cpDelegate.getClassLoader();
+ return scriptLoader;
+ }
+
+ private ClasspathUtils.Delegate getClassPathDelegate() {
+ if (cpDelegate == null) {
+ if (projectComponent == null) {
+ throw new IllegalStateException("Can't access classpath without a project component");
+ }
+ cpDelegate = ClasspathUtils.getDelegate(projectComponent);
+ }
+ return cpDelegate;
+ }
+
+ /**
+ * Get a script runner.
+ */
+ private ScriptRunnerBase getRunner() {
+ return new ScriptRunnerCreator(projectComponent.getProject()).createRunner(
+ manager, language, generateClassLoader());
+ }
+
+ /**
+ * Add any source resource.
+ *
+ * @param resource source of script
+ * @since Ant 1.7.1
+ */
+ public void add(ResourceCollection resource) {
+ resources.add(resource);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SourceFileScanner.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SourceFileScanner.java
new file mode 100644
index 00000000..c79f0347
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SourceFileScanner.java
@@ -0,0 +1,173 @@
+/*
+ * 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.util;
+
+import java.io.File;
+import java.util.Vector;
+
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.types.Resource;
+import org.apache.tools.ant.types.ResourceFactory;
+import org.apache.tools.ant.types.resources.FileResource;
+
+/**
+ * Utility class that collects the functionality of the various
+ * scanDir methods that have been scattered in several tasks before.
+ *
+ * <p>The only method returns an array of source files. The array is a
+ * subset of the files given as a parameter and holds only those that
+ * are newer than their corresponding target files.</p>
+ *
+ */
+public class SourceFileScanner implements ResourceFactory {
+
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected Task task;
+ // CheckStyle:VisibilityModifier ON
+
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+ private File destDir; // base directory of the fileset
+
+ /**
+ * Construct a new SourceFileScanner.
+ * @param task The task we should log messages through.
+ */
+ public SourceFileScanner(Task task) {
+ this.task = task;
+ }
+
+ /**
+ * Restrict the given set of files to those that are newer than
+ * their corresponding target files.
+ *
+ * @param files the original set of files.
+ * @param srcDir all files are relative to this directory.
+ * @param destDir target files live here. if null file names
+ * returned by the mapper are assumed to be absolute.
+ * @param mapper knows how to construct a target file names from
+ * source file names.
+ * @return an array of filenames.
+ */
+ public String[] restrict(String[] files, File srcDir, File destDir,
+ FileNameMapper mapper) {
+ return restrict(files, srcDir, destDir, mapper,
+ FILE_UTILS.getFileTimestampGranularity());
+ }
+
+ /**
+ * Restrict the given set of files to those that are newer than
+ * their corresponding target files.
+ *
+ * @param files the original set of files.
+ * @param srcDir all files are relative to this directory.
+ * @param destDir target files live here. If null file names
+ * returned by the mapper are assumed to be absolute.
+ * @param mapper knows how to construct a target file names from
+ * source file names.
+ * @param granularity The number of milliseconds leeway to give
+ * before deciding a target is out of date.
+ * @return an array of filenames.
+ *
+ * @since Ant 1.6.2
+ */
+ public String[] restrict(String[] files, File srcDir, File destDir,
+ FileNameMapper mapper, long granularity) {
+ // record destdir for later use in getResource
+ this.destDir = destDir;
+ Vector v = new Vector();
+ for (int i = 0; i < files.length; i++) {
+ final String name = files[i];
+ v.addElement(new FileResource(srcDir, name) {
+ public String getName() {
+ return name;
+ }
+ });
+ }
+ Resource[] sourceresources = new Resource[v.size()];
+ v.copyInto(sourceresources);
+
+ // build the list of sources which are out of date with
+ // respect to the target
+ Resource[] outofdate =
+ ResourceUtils.selectOutOfDateSources(task, sourceresources,
+ mapper, this, granularity);
+ String[] result = new String[outofdate.length];
+ for (int counter = 0; counter < outofdate.length; counter++) {
+ result[counter] = outofdate[counter].getName();
+ }
+ return result;
+ }
+
+ /**
+ * Convenience layer on top of restrict that returns the source
+ * files as File objects (containing absolute paths if srcDir is
+ * absolute).
+ * @param files the original set of files.
+ * @param srcDir all files are relative to this directory.
+ * @param destDir target files live here. If null file names
+ * returned by the mapper are assumed to be absolute.
+ * @param mapper knows how to construct a target file names from
+ * source file names.
+ * @return an array of files.
+ */
+ public File[] restrictAsFiles(String[] files, File srcDir, File destDir,
+ FileNameMapper mapper) {
+ return restrictAsFiles(files, srcDir, destDir, mapper,
+ FILE_UTILS.getFileTimestampGranularity());
+ }
+
+ /**
+ * Convenience layer on top of restrict that returns the source
+ * files as File objects (containing absolute paths if srcDir is
+ * absolute).
+ *
+ * @param files the original set of files.
+ * @param srcDir all files are relative to this directory.
+ * @param destDir target files live here. If null file names
+ * returned by the mapper are assumed to be absolute.
+ * @param mapper knows how to construct a target file names from
+ * source file names.
+ * @param granularity The number of milliseconds leeway to give
+ * before deciding a target is out of date.
+ * @return an array of files.
+ * @since Ant 1.6.2
+ */
+ public File[] restrictAsFiles(String[] files, File srcDir, File destDir,
+ FileNameMapper mapper, long granularity) {
+ String[] res = restrict(files, srcDir, destDir, mapper, granularity);
+ File[] result = new File[res.length];
+ for (int i = 0; i < res.length; i++) {
+ result[i] = new File(srcDir, res[i]);
+ }
+ return result;
+ }
+
+ /**
+ * Returns resource information for a file at destination.
+ * @param name relative path of file at destination.
+ * @return data concerning a file whose relative path to destDir is name.
+ *
+ * @since Ant 1.5.2
+ */
+ public Resource getResource(String name) {
+ return new FileResource(destDir, name);
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SplitClassLoader.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SplitClassLoader.java
new file mode 100644
index 00000000..f48d3d3e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SplitClassLoader.java
@@ -0,0 +1,73 @@
+/*
+ * 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.util;
+
+import org.apache.tools.ant.AntClassLoader;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Specialized classloader for tasks that need finer grained control
+ * over which classes are to be loaded via Ant's classloader and which
+ * should not even if they are available.
+ */
+public final class SplitClassLoader extends AntClassLoader {
+
+ private final String[] splitClasses;
+
+ /**
+ * @param splitClasses classes contained herin will not be loaded
+ * via Ant's classloader
+ */
+ public SplitClassLoader(ClassLoader parent, Path path, Project project,
+ String[] splitClasses) {
+ super(parent, project, path, true);
+ this.splitClasses = splitClasses;
+ }
+
+ // forceLoadClass is not convenient here since it would not
+ // properly deal with inner classes of these classes.
+ protected synchronized Class loadClass(String classname, boolean resolve)
+ throws ClassNotFoundException {
+ Class theClass = findLoadedClass(classname);
+ if (theClass != null) {
+ return theClass;
+ }
+ if (isSplit(classname)) {
+ theClass = findClass(classname);
+ if (resolve) {
+ resolveClass(theClass);
+ }
+ return theClass;
+ } else {
+ return super.loadClass(classname, resolve);
+ }
+ }
+
+ private boolean isSplit(String classname) {
+ String simplename = classname.substring(classname.lastIndexOf('.') + 1);
+ for (int i = 0; i < splitClasses.length; i++) {
+ if (simplename.equals(splitClasses[i])
+ || simplename.startsWith(splitClasses[i] + '$')) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/StringTokenizer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/StringTokenizer.java
new file mode 100644
index 00000000..7addf310
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/StringTokenizer.java
@@ -0,0 +1,154 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.Reader;
+
+import org.apache.tools.ant.ProjectComponent;
+
+/**
+ * Class to tokenize the input as areas separated
+ * by white space, or by a specified list of
+ * delim characters. Behaves like java.util.StringTokenizer.
+ * If the stream starts with delim characters, the first
+ * token will be an empty string (unless the treat delims
+ * as tokens flag is set).
+ * @since Ant 1.7
+ */
+public class StringTokenizer extends ProjectComponent implements Tokenizer {
+ private static final int NOT_A_CHAR = -2;
+ private String intraString = "";
+ private int pushed = NOT_A_CHAR;
+ private char[] delims = null;
+ private boolean delimsAreTokens = false;
+ private boolean suppressDelims = false;
+ private boolean includeDelims = false;
+
+ /**
+ * attribute delims - the delimiter characters
+ * @param delims a string containing the delimiter characters
+ */
+ public void setDelims(String delims) {
+ this.delims = StringUtils.resolveBackSlash(delims).toCharArray();
+ }
+
+ /**
+ * attribute delimsaretokens - treat delimiters as
+ * separate tokens.
+ * @param delimsAreTokens true if delimiters are to be separate
+ */
+
+ public void setDelimsAreTokens(boolean delimsAreTokens) {
+ this.delimsAreTokens = delimsAreTokens;
+ }
+ /**
+ * attribute suppressdelims - suppress delimiters.
+ * default - false
+ * @param suppressDelims if true do not report delimiters
+ */
+ public void setSuppressDelims(boolean suppressDelims) {
+ this.suppressDelims = suppressDelims;
+ }
+
+ /**
+ * attribute includedelims - treat delimiters as part
+ * of the token.
+ * default - false
+ * @param includeDelims if true add delimiters to the token
+ */
+ public void setIncludeDelims(boolean includeDelims) {
+ this.includeDelims = includeDelims;
+ }
+
+ /**
+ * find and return the next token
+ *
+ * @param in the input stream
+ * @return the token
+ * @exception IOException if an error occurs reading
+ */
+ public String getToken(Reader in) throws IOException {
+ int ch = -1;
+ if (pushed != NOT_A_CHAR) {
+ ch = pushed;
+ pushed = NOT_A_CHAR;
+ } else {
+ ch = in.read();
+ }
+ if (ch == -1) {
+ return null;
+ }
+ boolean inToken = true;
+ intraString = "";
+ StringBuffer word = new StringBuffer();
+ StringBuffer padding = new StringBuffer();
+ while (ch != -1) {
+ char c = (char) ch;
+ boolean isDelim = isDelim(c);
+ if (inToken) {
+ if (isDelim) {
+ if (delimsAreTokens) {
+ if (word.length() == 0) {
+ word.append(c);
+ } else {
+ pushed = ch;
+ }
+ break;
+ }
+ padding.append(c);
+ inToken = false;
+ } else {
+ word.append(c);
+ }
+ } else {
+ if (isDelim) {
+ padding.append(c);
+ } else {
+ pushed = ch;
+ break;
+ }
+ }
+ ch = in.read();
+ }
+ intraString = padding.toString();
+ if (includeDelims) {
+ word.append(intraString);
+ }
+ return word.toString();
+ }
+
+ /**
+ * @return the intratoken string
+ */
+ public String getPostToken() {
+ return suppressDelims || includeDelims ? "" : intraString;
+ }
+
+ private boolean isDelim(char ch) {
+ if (delims == null) {
+ return Character.isWhitespace(ch);
+ }
+ for (int i = 0; i < delims.length; ++i) {
+ if (delims[i] == ch) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/StringUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/StringUtils.java
new file mode 100644
index 00000000..626fb224
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/StringUtils.java
@@ -0,0 +1,273 @@
+/*
+ * 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.util;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * A set of helper methods related to string manipulation.
+ *
+ */
+public final class StringUtils {
+ private static final long KILOBYTE = 1024;
+ private static final long MEGABYTE = KILOBYTE * 1024;
+ private static final long GIGABYTE = MEGABYTE * 1024;
+ private static final long TERABYTE = GIGABYTE * 1024;
+ private static final long PETABYTE = TERABYTE * 1024;
+
+ /**
+ * constructor to stop anyone instantiating the class
+ */
+ private StringUtils() {
+ }
+
+ /** the line separator for this OS */
+ public static final String LINE_SEP = System.getProperty("line.separator");
+
+ /**
+ * Splits up a string into a list of lines. It is equivalent
+ * to <tt>split(data, '\n')</tt>.
+ * @param data the string to split up into lines.
+ * @return the list of lines available in the string.
+ */
+ public static Vector<String> lineSplit(String data) {
+ return split(data, '\n');
+ }
+
+ /**
+ * Splits up a string where elements are separated by a specific
+ * character and return all elements.
+ * @param data the string to split up.
+ * @param ch the separator character.
+ * @return the list of elements.
+ */
+ public static Vector<String> split(String data, int ch) {
+ Vector<String> elems = new Vector<String>();
+ int pos = -1;
+ int i = 0;
+ while ((pos = data.indexOf(ch, i)) != -1) {
+ String elem = data.substring(i, pos);
+ elems.addElement(elem);
+ i = pos + 1;
+ }
+ elems.addElement(data.substring(i));
+ return elems;
+ }
+
+ /**
+ * Replace occurrences into a string.
+ * @param data the string to replace occurrences into
+ * @param from the occurrence to replace.
+ * @param to the occurrence to be used as a replacement.
+ * @return the new string with replaced occurrences.
+ * @deprecated Use {@link String#replace(CharSequence, CharSequence)} now.
+ */
+ public static String replace(String data, String from, String to) {
+ return data.replace(from, to);
+ }
+
+ /**
+ * Convenient method to retrieve the full stacktrace from a given exception.
+ * @param t the exception to get the stacktrace from.
+ * @return the stacktrace from the given exception.
+ */
+ public static String getStackTrace(Throwable t) {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw, true);
+ t.printStackTrace(pw);
+ pw.flush();
+ pw.close();
+ return sw.toString();
+ }
+
+ /**
+ * Checks that a string buffer ends up with a given string. It may sound
+ * trivial with the existing
+ * JDK API but the various implementation among JDKs can make those
+ * methods extremely resource intensive
+ * and perform poorly due to massive memory allocation and copying. See
+ * @param buffer the buffer to perform the check on
+ * @param suffix the suffix
+ * @return <code>true</code> if the character sequence represented by the
+ * argument is a suffix of the character sequence represented by
+ * the StringBuffer object; <code>false</code> otherwise. Note that the
+ * result will be <code>true</code> if the argument is the
+ * empty string.
+ */
+ public static boolean endsWith(StringBuffer buffer, String suffix) {
+ if (suffix.length() > buffer.length()) {
+ return false;
+ }
+ // this loop is done on purpose to avoid memory allocation performance
+ // problems on various JDKs
+ // StringBuffer.lastIndexOf() was introduced in jdk 1.4 and
+ // implementation is ok though does allocation/copying
+ // StringBuffer.toString().endsWith() does massive memory
+ // allocation/copying on JDK 1.5
+ // See http://issues.apache.org/bugzilla/show_bug.cgi?id=37169
+ int endIndex = suffix.length() - 1;
+ int bufferIndex = buffer.length() - 1;
+ while (endIndex >= 0) {
+ if (buffer.charAt(bufferIndex) != suffix.charAt(endIndex)) {
+ return false;
+ }
+ bufferIndex--;
+ endIndex--;
+ }
+ return true;
+ }
+
+ /**
+ * xml does not do "c" like interpretation of strings.
+ * i.e. \n\r\t etc.
+ * this method processes \n, \r, \t, \f, \\
+ * also subs \s -&gt; " \n\r\t\f"
+ * a trailing '\' will be ignored
+ *
+ * @param input raw string with possible embedded '\'s
+ * @return converted string
+ * @since Ant 1.7
+ */
+ public static String resolveBackSlash(String input) {
+ StringBuffer b = new StringBuffer();
+ boolean backSlashSeen = false;
+ for (int i = 0; i < input.length(); ++i) {
+ char c = input.charAt(i);
+ if (!backSlashSeen) {
+ if (c == '\\') {
+ backSlashSeen = true;
+ } else {
+ b.append(c);
+ }
+ } else {
+ switch (c) {
+ case '\\':
+ b.append((char) '\\');
+ break;
+ case 'n':
+ b.append((char) '\n');
+ break;
+ case 'r':
+ b.append((char) '\r');
+ break;
+ case 't':
+ b.append((char) '\t');
+ break;
+ case 'f':
+ b.append((char) '\f');
+ break;
+ case 's':
+ b.append(" \t\n\r\f");
+ break;
+ default:
+ b.append(c);
+ }
+ backSlashSeen = false;
+ }
+ }
+ return b.toString();
+ }
+
+ /**
+ * Takes a human readable size representation eg 10K
+ * a long value. Doesn't support 1.1K or other rational values.
+ * @param humanSize the amount as a human readable string.
+ * @return a long value representation
+ * @throws Exception if there is a problem.
+ * @since Ant 1.7
+ */
+ public static long parseHumanSizes(String humanSize) throws Exception {
+ long factor = 1L;
+ char s = humanSize.charAt(0);
+ switch (s) {
+ case '+':
+ humanSize = humanSize.substring(1);
+ break;
+ case '-':
+ factor = -1L;
+ humanSize = humanSize.substring(1);
+ break;
+ default:
+ break;
+ }
+ //last character isn't a digit
+ char c = humanSize.charAt(humanSize.length() - 1);
+ if (!Character.isDigit(c)) {
+ int trim = 1;
+ switch (c) {
+ case 'K':
+ factor *= KILOBYTE;
+ break;
+ case 'M':
+ factor *= MEGABYTE;
+ break;
+ case 'G':
+ factor *= GIGABYTE;
+ break;
+ case 'T':
+ factor *= TERABYTE;
+ break;
+ case 'P':
+ factor *= PETABYTE;
+ break;
+ default:
+ trim = 0;
+ }
+ humanSize = humanSize.substring(0, humanSize.length() - trim);
+ }
+ try {
+ return factor * Long.parseLong(humanSize);
+ } catch (NumberFormatException e) {
+ throw new BuildException("Failed to parse \"" + humanSize + "\"", e);
+ }
+ }
+
+ /**
+ * Removes the suffix from a given string, if the string contains
+ * that suffix.
+ * @param string String for check
+ * @param suffix Suffix to remove
+ * @return the <i>string</i> with the <i>suffix</i>
+ */
+ public static String removeSuffix(String string, String suffix) {
+ if (string.endsWith(suffix)) {
+ return string.substring(0, string.length() - suffix.length());
+ } else {
+ return string;
+ }
+ }
+
+ /**
+ * Removes the prefix from a given string, if the string contains
+ * that prefix.
+ * @param string String for check
+ * @param prefix Prefix to remove
+ * @return the <i>string</i> with the <i>prefix</i>
+ */
+ public static String removePrefix(String string, String prefix) {
+ if (string.startsWith(prefix)) {
+ return string.substring(prefix.length());
+ } else {
+ return string;
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java
new file mode 100644
index 00000000..3bc9918e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/SymbolicLinkUtils.java
@@ -0,0 +1,296 @@
+/*
+ * 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.util;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+import org.apache.tools.ant.taskdefs.Execute;
+
+/**
+ * Contains methods related to symbolic links - or what Ant thinks is
+ * a symbolic link based on the absent support for them in Java.
+ *
+ * @since Ant 1.8.0
+ */
+public class SymbolicLinkUtils {
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ /**
+ * Shared instance.
+ */
+ private static final SymbolicLinkUtils PRIMARY_INSTANCE =
+ new SymbolicLinkUtils();
+
+ /**
+ * Method to retrieve The SymbolicLinkUtils, which is shared by
+ * all users of this method.
+ * @return an instance of SymbolicLinkUtils.
+ */
+ public static SymbolicLinkUtils getSymbolicLinkUtils() {
+ // keep the door open for Java X.Y specific subclass if symbolic
+ // links ever become supported in the classlib
+ return PRIMARY_INSTANCE;
+ }
+
+ /**
+ * Empty constructor.
+ */
+ protected SymbolicLinkUtils() {
+ }
+
+ /**
+ * Checks whether a given file is a symbolic link.
+ *
+ * <p>It doesn't really test for symbolic links but whether the
+ * canonical and absolute paths of the file are identical--this
+ * may lead to false positives on some platforms.</p>
+ *
+ * @param file the file to test. Must not be null.
+ *
+ * @return true if the file is a symbolic link.
+ * @throws IOException on error.
+ */
+ public boolean isSymbolicLink(final File file) throws IOException {
+ return isSymbolicLink(file.getParentFile(), file.getName());
+ }
+
+ /**
+ * Checks whether a given file is a symbolic link.
+ *
+ * <p>It doesn't really test for symbolic links but whether the
+ * canonical and absolute paths of the file are identical--this
+ * may lead to false positives on some platforms.</p>
+ *
+ * @param name the name of the file to test.
+ *
+ * @return true if the file is a symbolic link.
+ * @throws IOException on error.
+ */
+ public boolean isSymbolicLink(final String name) throws IOException {
+ return isSymbolicLink(new File(name));
+ }
+
+ /**
+ * Checks whether a given file is a symbolic link.
+ *
+ * <p>It doesn't really test for symbolic links but whether the
+ * canonical and absolute paths of the file are identical--this
+ * may lead to false positives on some platforms.</p>
+ *
+ * @param parent the parent directory of the file to test
+ * @param name the name of the file to test.
+ *
+ * @return true if the file is a symbolic link.
+ * @throws IOException on error.
+ */
+ public boolean isSymbolicLink(final File parent, final String name)
+ throws IOException {
+ final File toTest = parent != null
+ ? new File(parent.getCanonicalPath(), name)
+ : new File(name);
+ return !toTest.getAbsolutePath().equals(toTest.getCanonicalPath());
+ }
+
+ /**
+ * Checks whether a given file is a broken symbolic link.
+ *
+ * <p>It doesn't really test for symbolic links but whether Java
+ * reports that the File doesn't exist but its parent's child list
+ * contains it--this may lead to false positives on some
+ * platforms.</p>
+ *
+ * <p>Note that #isSymbolicLink returns false if this method
+ * returns true since Java won't produce a canonical name
+ * different from the abolute one if the link is broken.</p>
+ *
+ * @param name the name of the file to test.
+ *
+ * @return true if the file is a broken symbolic link.
+ * @throws IOException on error.
+ */
+ public boolean isDanglingSymbolicLink(final String name) throws IOException {
+ return isDanglingSymbolicLink(new File(name));
+ }
+
+ /**
+ * Checks whether a given file is a broken symbolic link.
+ *
+ * <p>It doesn't really test for symbolic links but whether Java
+ * reports that the File doesn't exist but its parent's child list
+ * contains it--this may lead to false positives on some
+ * platforms.</p>
+ *
+ * <p>Note that #isSymbolicLink returns false if this method
+ * returns true since Java won't produce a canonical name
+ * different from the abolute one if the link is broken.</p>
+ *
+ * @param file the file to test.
+ *
+ * @return true if the file is a broken symbolic link.
+ * @throws IOException on error.
+ */
+ public boolean isDanglingSymbolicLink(final File file) throws IOException {
+ return isDanglingSymbolicLink(file.getParentFile(), file.getName());
+ }
+
+ /**
+ * Checks whether a given file is a broken symbolic link.
+ *
+ * <p>It doesn't really test for symbolic links but whether Java
+ * reports that the File doesn't exist but its parent's child list
+ * contains it--this may lead to false positives on some
+ * platforms.</p>
+ *
+ * <p>Note that #isSymbolicLink returns false if this method
+ * returns true since Java won't produce a canonical name
+ * different from the abolute one if the link is broken.</p>
+ *
+ * @param parent the parent directory of the file to test
+ * @param name the name of the file to test.
+ *
+ * @return true if the file is a broken symbolic link.
+ * @throws IOException on error.
+ */
+ public boolean isDanglingSymbolicLink(final File parent, final String name)
+ throws IOException {
+ final File f = new File(parent, name);
+ if (!f.exists()) {
+ final String localName = f.getName();
+ final String[] c = parent.list(new FilenameFilter() {
+ public boolean accept(final File d, final String n) {
+ return localName.equals(n);
+ }
+ });
+ return c != null && c.length > 0;
+ }
+ return false;
+ }
+
+ /**
+ * Delete a symlink (without deleting the associated resource).
+ *
+ * <p>This is a utility method that removes a unix symlink without
+ * removing the resource that the symlink points to. If it is
+ * accidentally invoked on a real file, the real file will not be
+ * harmed, but silently ignored.</p>
+ *
+ * <p>Normally this method works by
+ * getting the canonical path of the link, using the canonical path to
+ * rename the resource (breaking the link) and then deleting the link.
+ * The resource is then returned to its original name inside a finally
+ * block to ensure that the resource is unharmed even in the event of
+ * an exception.</p>
+ *
+ * <p>There may be cases where the algorithm described above doesn't work,
+ * in that case the method tries to use the native "rm" command on
+ * the symlink instead.</p>
+ *
+ * @param link A <code>File</code> object of the symlink to delete.
+ * @param task An Ant Task required if "rm" needs to be invoked.
+ *
+ * @throws IOException If calls to <code>File.rename</code>,
+ * <code>File.delete</code> or <code>File.getCanonicalPath</code>
+ * fail.
+ * @throws BuildException if the execution of "rm" failed.
+ */
+ public void deleteSymbolicLink(File link, final Task task)
+ throws IOException {
+ if (isDanglingSymbolicLink(link)) {
+ if (!link.delete()) {
+ throw new IOException("failed to remove dangling symbolic link "
+ + link);
+ }
+ return;
+ }
+
+ if (!isSymbolicLink(link)) {
+ // plain file, not a link
+ return;
+ }
+
+ if (!link.exists()) {
+ throw new FileNotFoundException("No such symbolic link: " + link);
+ }
+
+ // find the resource of the existing link:
+ final File target = link.getCanonicalFile();
+
+ // no reason to try the renaming algorithm if we aren't allowed to
+ // write to the target's parent directory. Let's hope that
+ // File.canWrite works on all platforms.
+
+ if (task == null || target.getParentFile().canWrite()) {
+
+ // rename the resource, thus breaking the link:
+ final File temp = FILE_UTILS.createTempFile("symlink", ".tmp",
+ target.getParentFile(), false,
+ false);
+
+ if (FILE_UTILS.isLeadingPath(target, link)) {
+ // link points to a parent directory, renaming the parent
+ // will rename the file
+ link = new File(temp,
+ FILE_UTILS.removeLeadingPath(target, link));
+ }
+
+ boolean renamedTarget = false;
+ try {
+ try {
+ FILE_UTILS.rename(target, temp);
+ renamedTarget = true;
+ } catch (final IOException e) {
+ throw new IOException("Couldn't rename resource when "
+ + "attempting to delete '" + link
+ + "'. Reason: " + e.getMessage());
+ }
+ // delete the (now) broken link:
+ if (!link.delete()) {
+ throw new IOException("Couldn't delete symlink: "
+ + link
+ + " (was it a real file? is this "
+ + "not a UNIX system?)");
+ }
+ } finally {
+ if (renamedTarget) {
+ // return the resource to its original name:
+ try {
+ FILE_UTILS.rename(temp, target);
+ } catch (final IOException e) {
+ throw new IOException("Couldn't return resource "
+ + temp
+ + " to its original name: "
+ + target.getAbsolutePath()
+ + ". Reason: " + e.getMessage()
+ + "\n THE RESOURCE'S NAME ON DISK"
+ + " HAS BEEN CHANGED BY THIS"
+ + " ERROR!\n");
+ }
+ }
+ }
+ } else {
+ Execute.runCommand(task,
+ new String[] {"rm", link.getAbsolutePath()});
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TaskLogger.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TaskLogger.java
new file mode 100644
index 00000000..9ce5c512
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TaskLogger.java
@@ -0,0 +1,79 @@
+/*
+ * 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.util;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.Task;
+
+/**
+ * A facade that makes logging nicer to use.
+ */
+public final class TaskLogger {
+ /**
+ * Task to use to do logging.
+ */
+ private Task task;
+
+ /**
+ * Constructor for the TaskLogger
+ * @param task the task
+ */
+ public TaskLogger(final Task task) {
+ this.task = task;
+ }
+
+ /**
+ * Log a message with <code>MSG_INFO</code> priority
+ * @param message the message to log
+ */
+ public void info(final String message) {
+ task.log(message, Project.MSG_INFO);
+ }
+
+ /**
+ * Log a message with <code>MSG_ERR</code> priority
+ * @param message the message to log
+ */
+ public void error(final String message) {
+ task.log(message, Project.MSG_ERR);
+ }
+
+ /**
+ * Log a message with <code>MSG_WARN</code> priority
+ * @param message the message to log
+ */
+ public void warning(final String message) {
+ task.log(message, Project.MSG_WARN);
+ }
+
+ /**
+ * Log a message with <code>MSG_VERBOSE</code> priority
+ * @param message the message to log
+ */
+ public void verbose(final String message) {
+ task.log(message, Project.MSG_VERBOSE);
+ }
+
+ /**
+ * Log a message with <code>MSG_DEBUG</code> priority
+ * @param message the message to log
+ */
+ public void debug(final String message) {
+ task.log(message, Project.MSG_DEBUG);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TeeOutputStream.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TeeOutputStream.java
new file mode 100644
index 00000000..eb8da3fa
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TeeOutputStream.java
@@ -0,0 +1,95 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * A simple T-piece to replicate an output stream into two separate streams
+ *
+ */
+public class TeeOutputStream extends OutputStream {
+ private OutputStream left;
+ private OutputStream right;
+
+ /**
+ * Constructor for TeeOutputStream.
+ * @param left one of the output streams.
+ * @param right the other output stream.
+ */
+ public TeeOutputStream(OutputStream left, OutputStream right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ /**
+ * Close both output streams.
+ * @throws IOException on error.
+ */
+ public void close() throws IOException {
+ try {
+ left.close();
+ } finally {
+ right.close();
+ }
+ }
+
+ /**
+ * Flush both output streams.
+ * @throws IOException on error
+ */
+ public void flush() throws IOException {
+ left.flush();
+ right.flush();
+ }
+
+ /**
+ * Write a byte array to both output streams.
+ * @param b an array of bytes.
+ * @throws IOException on error.
+ */
+ public void write(byte[] b) throws IOException {
+ left.write(b);
+ right.write(b);
+ }
+
+ /**
+ * Write a byte array to both output streams.
+ * @param b the data.
+ * @param off the start offset in the data.
+ * @param len the number of bytes to write.
+ * @throws IOException on error.
+ */
+ public void write(byte[] b, int off, int len) throws IOException {
+ left.write(b, off, len);
+ right.write(b, off, len);
+ }
+
+ /**
+ * Write a byte to both output streams.
+ * @param b the byte to write.
+ * @throws IOException on error.
+ */
+ public void write(int b) throws IOException {
+ left.write(b);
+ right.write(b);
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TimeoutObserver.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TimeoutObserver.java
new file mode 100644
index 00000000..ba2e0c76
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/TimeoutObserver.java
@@ -0,0 +1,37 @@
+/*
+ * 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.util;
+
+/**
+ * Interface for classes that want to be notified by Watchdog.
+ *
+ * @since Ant 1.5
+ *
+ * @see org.apache.tools.ant.util.Watchdog
+ *
+ */
+public interface TimeoutObserver {
+
+ /**
+ * Called when the watchdow times out.
+ *
+ * @param w the watchdog that timed out.
+ */
+ void timeoutOccured(Watchdog w);
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Tokenizer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Tokenizer.java
new file mode 100644
index 00000000..25f89650
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Tokenizer.java
@@ -0,0 +1,44 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.Reader;
+
+/**
+ * input stream tokenizers implement this interface
+ *
+ * @version Ant 1.6
+ */
+public interface Tokenizer {
+ /**
+ * get the next token from the input stream
+ * @param in the input stream
+ * @return the next token, or null for the end
+ * of the stream
+ * @throws IOException if an error occurs
+ */
+ String getToken(Reader in) throws IOException;
+
+ /**
+ * return the string between tokens, after the
+ * previous token.
+ * @return the intra-token string
+ */
+ String getPostToken();
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UUEncoder.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UUEncoder.java
new file mode 100644
index 00000000..77e1bee1
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UUEncoder.java
@@ -0,0 +1,148 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintStream;
+
+/**
+ * UUEncoding of an input stream placed into an outputstream.
+ * This class is meant to be a drop in replacement for
+ * sun.misc.UUEncoder, which was previously used by Ant.
+ * The uuencode algorithm code has been copied from the
+ * geronimo project.
+ **/
+
+public class UUEncoder {
+ protected static final int DEFAULT_MODE = 644;
+ private static final int MAX_CHARS_PER_LINE = 45;
+ private static final int INPUT_BUFFER_SIZE = MAX_CHARS_PER_LINE * 100;
+ private OutputStream out;
+ private String name;
+
+ /**
+ * Constructor specifying a name for the encoded buffer, begin
+ * line will be:
+ * <pre>
+ * begin 644 [NAME]
+ * </pre>
+ * @param name the name of the encoded buffer.
+ */
+ public UUEncoder(String name) {
+ this.name = name;
+ }
+
+ /**
+ * UUEncode bytes from the input stream, and write them as text characters
+ * to the output stream. This method will run until it exhausts the
+ * input stream.
+ * @param is the input stream.
+ * @param out the output stream.
+ * @throws IOException if there is an error.
+ */
+ public void encode(InputStream is, OutputStream out)
+ throws IOException {
+ this.out = out;
+ encodeBegin();
+ byte[] buffer = new byte[INPUT_BUFFER_SIZE];
+ int count;
+ while ((count = is.read(buffer, 0, buffer.length)) != -1) {
+ int pos = 0;
+ while (count > 0) {
+ int num = count > MAX_CHARS_PER_LINE
+ ? MAX_CHARS_PER_LINE
+ : count;
+ encodeLine(buffer, pos, num, out);
+ pos += num;
+ count -= num;
+ }
+ }
+ out.flush();
+ encodeEnd();
+ }
+
+ /**
+ * Encode a string to the output.
+ */
+ private void encodeString(String n) throws IOException {
+ PrintStream writer = new PrintStream(out);
+ writer.print(n);
+ writer.flush();
+ }
+
+ private void encodeBegin() throws IOException {
+ encodeString("begin " + DEFAULT_MODE + " " + name + "\n");
+ }
+
+ private void encodeEnd() throws IOException {
+ encodeString(" \nend\n");
+ }
+
+ /**
+ * Encode a single line of data (less than or equal to 45 characters).
+ *
+ * @param data The array of byte data.
+ * @param off The starting offset within the data.
+ * @param length Length of the data to encode.
+ * @param out The output stream the encoded data is written to.
+ *
+ * @exception IOException
+ */
+ private void encodeLine(
+ byte[] data, int offset, int length, OutputStream out)
+ throws IOException {
+ // write out the number of characters encoded in this line.
+ // CheckStyle:MagicNumber OFF
+ out.write((byte) ((length & 0x3F) + ' '));
+ // CheckStyle:MagicNumber ON
+ byte a;
+ byte b;
+ byte c;
+
+ for (int i = 0; i < length;) {
+ // set the padding defaults
+ b = 1;
+ c = 1;
+ // get the next 3 bytes (if we have them)
+ a = data[offset + i++];
+ if (i < length) {
+ b = data[offset + i++];
+ if (i < length) {
+ c = data[offset + i++];
+ }
+ }
+
+ // CheckStyle:MagicNumber OFF
+ byte d1 = (byte) (((a >>> 2) & 0x3F) + ' ');
+ byte d2 = (byte) ((((a << 4) & 0x30) | ((b >>> 4) & 0x0F)) + ' ');
+ byte d3 = (byte) ((((b << 2) & 0x3C) | ((c >>> 6) & 0x3)) + ' ');
+ byte d4 = (byte) ((c & 0x3F) + ' ');
+ // CheckStyle:MagicNumber ON
+
+ out.write(d1);
+ out.write(d2);
+ out.write(d3);
+ out.write(d4);
+ }
+
+ // terminate with a linefeed alone
+ out.write('\n');
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UnPackageNameMapper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UnPackageNameMapper.java
new file mode 100644
index 00000000..1777279d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UnPackageNameMapper.java
@@ -0,0 +1,48 @@
+/*
+ * 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.util;
+
+import java.io.File;
+
+/**
+ * Maps dotted package name matches to a directory name.
+ * This is the inverse of the package mapper.
+ * This is useful for matching XML formatter results against their JUnit test
+ * cases.
+ * <pre>
+ * &lt;mapper classname="org.apache.tools.ant.util.UnPackageNameMapper"
+ * from="${test.data.dir}/TEST-*Test.xml" to="*Test.java"&gt;
+ * </pre>
+ *
+ *
+ */
+public class UnPackageNameMapper extends GlobPatternMapper {
+ /**
+ * Returns the part of the given string that matches the * in the
+ * &quot;from&quot; pattern replacing dots with file separators
+ *
+ *@param name Source filename
+ *@return Replaced variable part
+ */
+ protected String extractVariablePart(String name) {
+ String var = name.substring(prefixLength,
+ name.length() - postfixLength);
+ return var.replace('.', File.separatorChar);
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UnicodeUtil.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UnicodeUtil.java
new file mode 100644
index 00000000..d3e5eec3
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/UnicodeUtil.java
@@ -0,0 +1,46 @@
+/*
+ * 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.util;
+
+/**
+ * Contains one helper method to create a backslash u escape
+ *
+ * @since Ant 1.8.3
+ */
+public class UnicodeUtil {
+
+ private UnicodeUtil() {
+ }
+
+ /**
+ * returns the unicode representation of a char without the leading backslash
+ * @param ch
+ * @return unicode representation of a char for property files
+ */
+ public static StringBuffer EscapeUnicode(char ch) {
+ StringBuffer unicodeBuf = new StringBuffer("u0000");
+ String s = Integer.toHexString(ch);
+ //replace the last 0s by the chars contained in s
+ for (int i = 0; i < s.length(); i++) {
+ unicodeBuf.setCharAt(unicodeBuf.length()
+ - s.length() + i,
+ s.charAt(i));
+ }
+ return unicodeBuf;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/VectorSet.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/VectorSet.java
new file mode 100644
index 00000000..db13129d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/VectorSet.java
@@ -0,0 +1,242 @@
+/*
+ * 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.util;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import java.util.Vector;
+
+/**
+ * Subclass of Vector that won't store duplicate entries and shows
+ * HashSet's constant time performance characteristics for the
+ * contains method.
+ *
+ * <p>This is not a general purpose class but has been written because
+ * the protected members of {@link
+ * org.apache.tools.ant.DirectoryScanner DirectoryScanner} prohibited
+ * later revisions from using a more efficient collection.</p>
+ *
+ * <p>Methods are synchronized to keep Vector's contract.</p>
+ *
+ * @since Ant 1.8.0
+ */
+public final class VectorSet<E> extends Vector<E> {
+ private static final long serialVersionUID = 1L;
+
+ private final HashSet<E> set = new HashSet<E>();
+
+ public VectorSet() { super(); }
+
+ public VectorSet(int initialCapacity) { super(initialCapacity); }
+
+ public VectorSet(int initialCapacity, int capacityIncrement) {
+ super(initialCapacity, capacityIncrement);
+ }
+
+ public VectorSet(Collection<? extends E> c) {
+ if (c != null) {
+ for (E e : c) {
+ add(e);
+ }
+ }
+ }
+
+ public synchronized boolean add(E o) {
+ if (!set.contains(o)) {
+ doAdd(size(), o);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * This implementation may not add the element at the given index
+ * if it is already contained in the collection.
+ */
+ public void add(int index, E o) {
+ doAdd(index, o);
+ }
+
+ private synchronized void doAdd(int index, E o) {
+ // Vector.add seems to delegate to insertElementAt, but this
+ // is not documented so we may better implement it ourselves
+ if (set.add(o)) {
+ int count = size();
+ ensureCapacity(count + 1);
+ if (index != count) {
+ System.arraycopy(elementData, index, elementData, index + 1,
+ count - index);
+ }
+ elementData[index] = o;
+ elementCount++;
+ }
+ }
+
+ public synchronized void addElement(E o) {
+ doAdd(size(), o);
+ }
+
+ public synchronized boolean addAll(Collection<? extends E> c) {
+ boolean changed = false;
+ for (E e : c) {
+ changed |= add(e);
+ }
+ return changed;
+ }
+
+ /**
+ * This implementation may not add all elements at the given index
+ * if any of them are already contained in the collection.
+ */
+ public synchronized boolean addAll(int index, Collection<? extends E> c) {
+ LinkedList toAdd = new LinkedList();
+ for (E e : c) {
+ if (set.add(e)) {
+ toAdd.add(e);
+ }
+ }
+ if (toAdd.isEmpty()) {
+ return false;
+ }
+ int count = size();
+ ensureCapacity(count + toAdd.size());
+ if (index != count) {
+ System.arraycopy(elementData, index, elementData, index + toAdd.size(),
+ count - index);
+ }
+ for (Object o : toAdd) {
+ elementData[index++] = o;
+ }
+ elementCount += toAdd.size();
+ return true;
+ }
+
+ public synchronized void clear() {
+ super.clear();
+ set.clear();
+ }
+
+ public Object clone() {
+ @SuppressWarnings("unchecked")
+ final VectorSet<E> vs = (VectorSet<E>) super.clone();
+ vs.set.addAll(set);
+ return vs;
+ }
+
+ public synchronized boolean contains(Object o) {
+ return set.contains(o);
+ }
+
+ public synchronized boolean containsAll(Collection<?> c) {
+ return set.containsAll(c);
+ }
+
+ public void insertElementAt(E o, int index) {
+ doAdd(index, o);
+ }
+
+ public synchronized E remove(int index) {
+ E o = get(index);
+ remove(o);
+ return o;
+ }
+
+ public boolean remove(Object o) {
+ return doRemove(o);
+ }
+
+ private synchronized boolean doRemove(Object o) {
+ // again, remove seems to delegate to removeElement, but we
+ // shouldn't trust it
+ if (set.remove(o)) {
+ int index = indexOf(o);
+ if (index < elementData.length - 1) {
+ System.arraycopy(elementData, index + 1, elementData, index,
+ elementData.length - index - 1);
+ }
+ elementCount--;
+ return true;
+ }
+ return false;
+ }
+
+ public synchronized boolean removeAll(Collection<?> c) {
+ boolean changed = false;
+ for (Object o : c) {
+ changed |= remove(o);
+ }
+ return changed;
+ }
+
+ public synchronized void removeAllElements() {
+ set.clear();
+ super.removeAllElements();
+ }
+
+ public boolean removeElement(Object o) {
+ return doRemove(o);
+ }
+
+ public synchronized void removeElementAt(int index) {
+ remove(get(index));
+ }
+
+ public synchronized void removeRange(final int fromIndex, int toIndex) {
+ while (toIndex > fromIndex) {
+ remove(--toIndex);
+ }
+ }
+
+ public synchronized boolean retainAll(Collection<?> c) {
+ if (!(c instanceof Set)) {
+ c = new HashSet<Object>(c);
+ }
+ LinkedList<E> l = new LinkedList<E>();
+ for (E o : this) {
+ if (!c.contains(o)) {
+ l.addLast(o);
+ }
+ }
+ if (!l.isEmpty()) {
+ removeAll(l);
+ return true;
+ }
+ return false;
+ }
+
+ public synchronized E set(int index, E o) {
+ E orig = get(index);
+ if (set.add(o)) {
+ elementData[index] = o;
+ set.remove(orig);
+ } else {
+ int oldIndexOfO = indexOf(o);
+ remove(o);
+ remove(orig);
+ add(oldIndexOfO > index ? index : index - 1, o);
+ }
+ return orig;
+ }
+
+ public void setElementAt(E o, int index) {
+ set(index, o);
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Watchdog.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Watchdog.java
new file mode 100644
index 00000000..318b5264
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/Watchdog.java
@@ -0,0 +1,128 @@
+/*
+ * 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.util;
+
+import java.util.Enumeration;
+import java.util.Vector;
+
+/**
+ * Generalization of <code>ExecuteWatchdog</code>
+ *
+ * @since Ant 1.5
+ *
+ * @see org.apache.tools.ant.taskdefs.ExecuteWatchdog
+ *
+ */
+public class Watchdog implements Runnable {
+
+ private Vector observers = new Vector(1);
+ private long timeout = -1;
+ /**
+ * marked as volatile to stop the compiler caching values or (in java1.5+,
+ * reordering access)
+ */
+ private volatile boolean stopped = false;
+ /**
+ * Error string.
+ * {@value}
+ */
+ public static final String ERROR_INVALID_TIMEOUT = "timeout less than 1.";
+
+ /**
+ * Constructor for Watchdog.
+ * @param timeout the timeout to use in milliseconds (must be &gt;= 1).
+ */
+ public Watchdog(long timeout) {
+ if (timeout < 1) {
+ throw new IllegalArgumentException(ERROR_INVALID_TIMEOUT);
+ }
+ this.timeout = timeout;
+ }
+
+ /**
+ * Add a timeout observer.
+ * @param to the timeout observer to add.
+ */
+ public void addTimeoutObserver(TimeoutObserver to) {
+ //no need to synchronize, as Vector is always synchronized
+ observers.addElement(to);
+ }
+
+ /**
+ * Remove a timeout observer.
+ * @param to the timeout observer to remove.
+ */
+ public void removeTimeoutObserver(TimeoutObserver to) {
+ //no need to synchronize, as Vector is always synchronized
+ observers.removeElement(to);
+ }
+
+ /**
+ * Inform the observers that a timeout has occurred.
+ * This happens in the watchdog thread.
+ */
+ protected final void fireTimeoutOccured() {
+ Enumeration e = observers.elements();
+ while (e.hasMoreElements()) {
+ ((TimeoutObserver) e.nextElement()).timeoutOccured(this);
+ }
+ }
+
+ /**
+ * Start the watch dog.
+ */
+ public synchronized void start() {
+ stopped = false;
+ Thread t = new Thread(this, "WATCHDOG");
+ t.setDaemon(true);
+ t.start();
+ }
+
+ /**
+ * Stop the watch dog.
+ */
+ public synchronized void stop() {
+ stopped = true;
+ notifyAll();
+ }
+
+ /**
+ * The run method of the watch dog thread.
+ * This simply does a wait for the timeout time, and
+ * if the stop flag has not been set when the wait has returned or
+ * has been interrupted, the watch dog listeners are informed.
+ */
+ public synchronized void run() {
+ long now = System.currentTimeMillis();
+ final long until = now + timeout;
+
+ try {
+ while (!stopped && until > now) {
+ wait(until - now);
+ now = System.currentTimeMillis();
+ }
+ } catch (InterruptedException e) {
+ // Ignore exception
+ }
+ if (!stopped) {
+ fireTimeoutOccured();
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/WeakishReference.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/WeakishReference.java
new file mode 100644
index 00000000..92f322fb
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/WeakishReference.java
@@ -0,0 +1,91 @@
+/*
+ * 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.util;
+
+
+import java.lang.ref.WeakReference;
+
+/**
+ * These classes are part of some code to reduce memory leaks by only
+ * retaining weak references to things
+ * on Java1.2+, and yet still work (with leaky hard references) on Java1.1.
+ * Now that Ant is 1.2+ only,
+ * life is simpler and none of the classes are needed any more.
+ *
+ * They are only retained in case a third-party task uses them
+ * @since ant1.6
+ * @see org.apache.tools.ant.util.optional.WeakishReference12
+ * @deprecated deprecated 1.7; will be removed in Ant1.8
+ * Just use {@link java.lang.ref.WeakReference} directly.
+ */
+public class WeakishReference {
+
+
+ private WeakReference weakref;
+
+ /**
+ * create a new soft reference, which is bound to a
+ * Weak reference inside
+ *
+ * @param reference
+ * @see java.lang.ref.WeakReference
+ */
+ WeakishReference(Object reference) {
+ this.weakref = new WeakReference(reference);
+ }
+
+ /**
+ * Returns this reference object's referent. If this reference object has
+ * been cleared, then this method returns <code>null</code>.
+ *
+ * @return The object to which this reference refers, or
+ * <code>null</code> if this reference object has been cleared.
+ */
+ public Object get() {
+ return weakref.get();
+ }
+
+ /**
+ * create the appropriate type of reference for the java version
+ * @param object the object that the reference will refer to.
+ * @return reference to the Object.
+ */
+ public static WeakishReference createReference(Object object) {
+ return new WeakishReference(object);
+ }
+
+
+ /**
+ * This was a hard reference for Java 1.1. Since Ant1.7,
+ * @deprecated since 1.7.
+ * Hopefully nobody is using this.
+ */
+ public static class HardReference extends WeakishReference {
+
+ /**
+ * constructor.
+ * @param object the object that the reference will refer to.
+ */
+ public HardReference(Object object) {
+ super(object);
+ }
+
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/WorkerAnt.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/WorkerAnt.java
new file mode 100644
index 00000000..288d74dd
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/WorkerAnt.java
@@ -0,0 +1,172 @@
+/*
+ * 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.util;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Task;
+
+/**
+ * A worker ant executes a single task in a background thread.
+ * After the run, any exception thrown is turned into a buildexception, which can be
+ * rethrown, the finished attribute is set, then notifyAll() is called,
+ * so that anyone waiting on the same notify object gets woken up.
+ * <p>
+ * This class is effectively a superset of
+ * {@link org.apache.tools.ant.taskdefs.Parallel.TaskRunnable}
+ *
+ * @since Ant 1.8
+ */
+
+public class WorkerAnt extends Thread {
+
+ private Task task;
+ private Object notify;
+ private volatile boolean finished = false;
+ private volatile BuildException buildException;
+ private volatile Throwable exception;
+
+ /**
+ * Error message if invoked with no task
+ */
+ public static final String ERROR_NO_TASK = "No task defined";
+
+
+ /**
+ * Create the worker.
+ * <p>
+ * This does not start the thread, merely configures it.
+ * @param task the task
+ * @param notify what to notify
+ */
+ public WorkerAnt(Task task, Object notify) {
+ this.task = task;
+ this.notify = notify != null ? notify : this;
+ }
+
+ /**
+ * Create the worker, using the worker as the notification point.
+ * <p>
+ * This does not start the thread, merely configures it.
+ * @param task the task
+ */
+ public WorkerAnt(Task task) {
+ this(task, null);
+ }
+
+ /**
+ * Get any build exception.
+ * This would seem to be oversynchronised, but know that Java pre-1.5 can
+ * reorder volatile access.
+ * The synchronized attribute is to force an ordering.
+ *
+ * @return the exception or null
+ */
+ public synchronized BuildException getBuildException() {
+ return buildException;
+ }
+
+ /**
+ * Get whatever was thrown, which may or may not be a buildException.
+ * Assertion: getException() instanceof BuildException &lt;=&gt; getBuildException()==getException()
+ * @return the exception.
+ */
+ public synchronized Throwable getException() {
+ return exception;
+ }
+
+
+ /**
+ * Get the task
+ * @return the task
+ */
+ public Task getTask() {
+ return task;
+ }
+
+
+ /**
+ * Query the task/thread for being finished.
+ * This would seem to be oversynchronised, but know that Java pre-1.5 can
+ * reorder volatile access.
+ * The synchronized attribute is to force an ordering.
+ * @return true if the task is finished.
+ */
+ public synchronized boolean isFinished() {
+ return finished;
+ }
+
+ /**
+ * Block on the notify object and so wait until the thread is finished.
+ * @param timeout timeout in milliseconds
+ * @throws InterruptedException if the execution was interrupted
+ */
+ public void waitUntilFinished(long timeout) throws InterruptedException {
+ synchronized (notify) {
+ if (!finished) {
+ notify.wait(timeout);
+ }
+ }
+ }
+
+ /**
+ * Raise an exception if one was caught
+ *
+ * @throws BuildException if one has been picked up
+ */
+ public void rethrowAnyBuildException() {
+ BuildException ex = getBuildException();
+ if (ex != null) {
+ throw ex;
+ }
+ }
+
+
+ /**
+ * Handle a caught exception, by recording it and possibly wrapping it
+ * in a BuildException for later rethrowing.
+ * @param thrown what was caught earlier
+ */
+ private synchronized void caught(Throwable thrown) {
+ exception = thrown;
+ buildException = (thrown instanceof BuildException)
+ ? (BuildException) thrown
+ : new BuildException(thrown);
+ }
+
+ /**
+ * Run the task, which is skipped if null.
+ * When invoked again, the task is re-run.
+ */
+ public void run() {
+ try {
+ if (task != null) {
+ task.execute();
+ }
+ } catch (Throwable thrown) {
+ caught(thrown);
+ } finally {
+ synchronized (notify) {
+ finished = true;
+ //reset the task.
+ //wake up our owner, if it is waiting
+ notify.notifyAll();
+ }
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/XMLFragment.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/XMLFragment.java
new file mode 100644
index 00000000..36a6158e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/XMLFragment.java
@@ -0,0 +1,155 @@
+/*
+ * 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.util;
+
+import org.apache.tools.ant.DynamicConfiguratorNS;
+import org.apache.tools.ant.DynamicElementNS;
+import org.apache.tools.ant.ProjectComponent;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentFragment;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+
+/**
+ * Use this class as a nested element if you want to get a literal DOM
+ * fragment of something nested into your task/type.
+ *
+ * <p>This is useful for tasks that want to deal with the "real" XML
+ * from the build file instead of objects.</p>
+ *
+ * <p>Code heavily influenced by code written by Dominique Devienne.</p>
+ *
+ * @since Ant 1.7
+ */
+public class XMLFragment extends ProjectComponent implements DynamicElementNS {
+
+ private Document doc;
+ private DocumentFragment fragment;
+
+ /**
+ * Constructor for XMLFragment object.
+ */
+ public XMLFragment() {
+ doc = JAXPUtils.getDocumentBuilder().newDocument();
+ fragment = doc.createDocumentFragment();
+ }
+
+ /**
+ * @return the DocumentFragment that corresponds to the nested
+ * structure.
+ */
+ public DocumentFragment getFragment() {
+ return fragment;
+ }
+
+ /**
+ * Add nested text, expanding properties as we go
+ * @param s the text to add
+ */
+ public void addText(String s) {
+ addText(fragment, s);
+ }
+
+ /**
+ * Creates a nested element.
+ * @param uri the uri of the nested element
+ * @param name the localname of the nested element
+ * @param qName the qualified name of the nested element
+ * @return an object that the element is applied to
+ */
+ public Object createDynamicElement(String uri, String name, String qName) {
+ Element e = null;
+ if (uri.equals("")) {
+ e = doc.createElement(name);
+ } else {
+ e = doc.createElementNS(uri, qName);
+ }
+ fragment.appendChild(e);
+ return new Child(e);
+ }
+
+ /**
+ * Add text to a node.
+ * @param n node
+ * @param s value
+ */
+ private void addText(Node n, String s) {
+ s = getProject().replaceProperties(s);
+ //only text nodes that are non null after property expansion are added
+ if (s != null && !s.trim().equals("")) {
+ Text t = doc.createTextNode(s.trim());
+ n.appendChild(t);
+ }
+ }
+
+ /**
+ * An object to handle (recursively) nested elements.
+ */
+ public class Child implements DynamicConfiguratorNS {
+ private Element e;
+
+ Child(Element e) {
+ this.e = e;
+ }
+
+ /**
+ * Add nested text.
+ * @param s the text to add
+ */
+ public void addText(String s) {
+ XMLFragment.this.addText(e, s);
+ }
+
+ /**
+ * Sets the attribute
+ * @param uri the uri of the attribute
+ * @param name the localname of the attribute
+ * @param qName the qualified name of the attribute
+ * @param value the value of the attribute
+ */
+ public void setDynamicAttribute(
+ String uri, String name, String qName, String value) {
+ if (uri.equals("")) {
+ e.setAttribute(name, value);
+ } else {
+ e.setAttributeNS(uri, qName, value);
+ }
+ }
+
+ /**
+ * Creates a nested element.
+ * @param uri the uri of the nested element
+ * @param name the localname of the nested element
+ * @param qName the qualified name of the nested element
+ * @return an object that the element is applied to
+ */
+ public Object createDynamicElement(String uri, String name, String qName) {
+ Element e2 = null;
+ if (uri.equals("")) {
+ e2 = doc.createElement(name);
+ } else {
+ e2 = doc.createElementNS(uri, qName);
+ }
+ e.appendChild(e2);
+ return new Child(e2);
+ }
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/XmlConstants.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/XmlConstants.java
new file mode 100644
index 00000000..d8eaa02e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/XmlConstants.java
@@ -0,0 +1,65 @@
+/*
+ * 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.util;
+
+/**
+ * XML Parser constants, all kept in one place for ease of reuse
+ * @see <a href="http://xml.apache.org/xerces-j/features.html">Xerces features</a>
+ * @see <a href="http://xml.apache.org/xerces-j/properties.html">Xerces properties</a>
+ * @see <a href=
+ * "http://www.saxproject.org/apidoc/org/xml/sax/package-summary.html#package_description"
+ * >SAX.</a>
+ */
+
+public class XmlConstants {
+
+ private XmlConstants() {
+ }
+
+ /** property for location of xml schema */
+ public static final String PROPERTY_SCHEMA_LOCATION =
+ "http://apache.org/xml/properties/schema/external-schemaLocation";
+ /** property for location of no-name schema */
+ public static final String PROPERTY_NO_NAMESPACE_SCHEMA_LOCATION =
+ "http://apache.org/xml/properties/schema/external-noNamespaceSchemaLocation";
+ /** property for full validation */
+ public static final String FEATURE_XSD_FULL_VALIDATION =
+ "http://apache.org/xml/features/validation/schema-full-checking";
+ /** property for xsd */
+ public static final String FEATURE_XSD = "http://apache.org/xml/features/validation/schema";
+
+ /** property for validation */
+ public static final String FEATURE_VALIDATION = "http://xml.org/sax/features/validation";
+ /** property for namespace support */
+ public static final String FEATURE_NAMESPACES = "http://xml.org/sax/features/namespaces";
+ /** property for schema language */
+ public static final String FEATURE_JAXP12_SCHEMA_LANGUAGE =
+ "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+ /** property for schema source */
+ public static final String FEATURE_JAXP12_SCHEMA_SOURCE =
+ "http://java.sun.com/xml/jaxp/properties/schemaSource";
+ /** the namespace for XML schema */
+ public static final String URI_XSD =
+ "http://www.w3.org/2001/XMLSchema";
+ /** the sax external entities feature */
+ public static final String FEATURE_EXTERNAL_ENTITIES =
+ "http://xml.org/sax/features/external-general-entities";
+ /** the apache.org/xml disallow doctype decl feature */
+ public static final String FEATURE_DISALLOW_DTD =
+ "http://apache.org/xml/features/disallow-doctype-decl";
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java
new file mode 100644
index 00000000..5c95d75b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/AbstractAnalyzer.java
@@ -0,0 +1,286 @@
+/*
+ * 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.util.depend;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Vector;
+import java.util.zip.ZipFile;
+
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.util.VectorSet;
+
+/**
+ * An abstract implementation of the analyzer interface providing support
+ * for the bulk of interface methods.
+ *
+ */
+public abstract class AbstractAnalyzer implements DependencyAnalyzer {
+ /** Maximum number of loops for looking for indirect dependencies. */
+ public static final int MAX_LOOPS = 1000;
+
+ /** The source path for the source files */
+ private Path sourcePath = new Path(null);
+
+ /** The classpath containg dirs and jars of class files */
+ private Path classPath = new Path(null);
+
+ /** The list of root classes */
+ private final Vector<String> rootClasses = new VectorSet<String>();
+
+ /** true if dependencies have been determined */
+ private boolean determined = false;
+
+ /** the list of File objects that the root classes depend upon */
+ private Vector<File> fileDependencies;
+ /** the list of java classes the root classes depend upon */
+ private Vector<String> classDependencies;
+
+ /** true if indirect dependencies should be gathered */
+ private boolean closure = true;
+
+ /** Setup the analyzer */
+ protected AbstractAnalyzer() {
+ reset();
+ }
+
+ /**
+ * Set the closure flag. If this flag is true the analyzer will traverse
+ * all class relationships until it has collected the entire set of
+ * direct and indirect dependencies
+ *
+ * @param closure true if dependencies should be traversed to determine
+ * indirect dependencies.
+ */
+ public void setClosure(boolean closure) {
+ this.closure = closure;
+ }
+
+ /**
+ * Get the list of files in the file system upon which the root classes
+ * depend. The files will be either the classfiles or jar files upon
+ * which the root classes depend.
+ *
+ * @return an enumeration of File instances.
+ */
+ public Enumeration<File> getFileDependencies() {
+ if (!supportsFileDependencies()) {
+ throw new RuntimeException("File dependencies are not supported "
+ + "by this analyzer");
+ }
+ if (!determined) {
+ determineDependencies(fileDependencies, classDependencies);
+ }
+ return fileDependencies.elements();
+ }
+
+ /**
+ * Get the list of classes upon which root classes depend. This is a
+ * list of Java classnames in dot notation.
+ *
+ * @return an enumeration of Strings, each being the name of a Java
+ * class in dot notation.
+ */
+ public Enumeration<String> getClassDependencies() {
+ if (!determined) {
+ determineDependencies(fileDependencies, classDependencies);
+ }
+ return classDependencies.elements();
+ }
+
+ /**
+ * Get the file that contains the class definition
+ *
+ * @param classname the name of the required class
+ * @return the file instance, zip or class, containing the
+ * class or null if the class could not be found.
+ * @exception IOException if the files in the classpath cannot be read.
+ */
+ public File getClassContainer(String classname) throws IOException {
+ String classLocation = classname.replace('.', '/') + ".class";
+ // we look through the classpath elements. If the element is a dir
+ // we look for the file. IF it is a zip, we look for the zip entry
+ return getResourceContainer(classLocation, classPath.list());
+ }
+
+ /**
+ * Get the file that contains the class source.
+ *
+ * @param classname the name of the required class
+ * @return the file instance, zip or java, containing the
+ * source or null if the source for the class could not be found.
+ * @exception IOException if the files in the sourcepath cannot be read.
+ */
+ public File getSourceContainer(String classname) throws IOException {
+ String sourceLocation = classname.replace('.', '/') + ".java";
+
+ // we look through the source path elements. If the element is a dir
+ // we look for the file. If it is a zip, we look for the zip entry.
+ // This isn't normal for source paths but we get it for free
+ return getResourceContainer(sourceLocation, sourcePath.list());
+ }
+
+ /**
+ * Add a source path to the source path used by this analyzer. The
+ * elements in the given path contain the source files for the classes
+ * being analyzed. Not all analyzers will use this information.
+ *
+ * @param sourcePath The Path instance specifying the source path
+ * elements.
+ */
+ public void addSourcePath(Path sourcePath) {
+ if (sourcePath == null) {
+ return;
+ }
+ this.sourcePath.append(sourcePath);
+ this.sourcePath.setProject(sourcePath.getProject());
+ }
+
+ /**
+ * Add a classpath to the classpath being used by the analyzer. The
+ * classpath contains the binary classfiles for the classes being
+ * analyzed The elements may either be the directories or jar files.Not
+ * all analyzers will use this information.
+ *
+ * @param classPath the Path instance specifying the classpath elements
+ */
+ public void addClassPath(Path classPath) {
+ if (classPath == null) {
+ return;
+ }
+
+ this.classPath.append(classPath);
+ this.classPath.setProject(classPath.getProject());
+ }
+
+ /**
+ * Add a root class. The root classes are used to drive the
+ * determination of dependency information. The analyzer will start at
+ * the root classes and add dependencies from there.
+ *
+ * @param className the name of the class in Java dot notation.
+ */
+ public void addRootClass(String className) {
+ if (className == null) {
+ return;
+ }
+ if (!rootClasses.contains(className)) {
+ rootClasses.addElement(className);
+ }
+ }
+
+ /**
+ * Configure an aspect of the analyzer. The set of aspects that are
+ * supported is specific to each analyzer instance.
+ *
+ * @param name the name of the aspect being configured
+ * @param info the configuration info.
+ */
+ public void config(String name, Object info) {
+ // do nothing by default
+ }
+
+ /**
+ * Reset the dependency list. This will reset the determined
+ * dependencies and the also list of root classes.
+ */
+ public void reset() {
+ rootClasses.removeAllElements();
+ determined = false;
+ fileDependencies = new Vector<File>();
+ classDependencies = new Vector<String>();
+ }
+
+ /**
+ * Get an enumeration of the root classes
+ *
+ * @return an enumeration of Strings, each of which is a class name
+ * for a root class.
+ */
+ protected Enumeration<String> getRootClasses() {
+ return rootClasses.elements();
+ }
+
+ /**
+ * Indicate if the analyzer is required to follow
+ * indirect class relationships.
+ *
+ * @return true if indirect relationships should be followed.
+ */
+ protected boolean isClosureRequired() {
+ return closure;
+ }
+
+ /**
+ * Determine the dependencies of the current set of root classes
+ *
+ * @param files a vector into which Files upon which the root classes
+ * depend should be placed.
+ * @param classes a vector of Strings into which the names of classes
+ * upon which the root classes depend should be placed.
+ */
+ protected abstract void determineDependencies(Vector<File> files, Vector<String> classes);
+
+ /**
+ * Indicate if the particular subclass supports file dependency
+ * information.
+ *
+ * @return true if file dependencies are supported.
+ */
+ protected abstract boolean supportsFileDependencies();
+
+ /**
+ * Get the file that contains the resource
+ *
+ * @param resourceLocation the name of the required resource.
+ * @param paths the paths which will be searched for the resource.
+ * @return the file instance, zip or class, containing the
+ * class or null if the class could not be found.
+ * @exception IOException if the files in the given paths cannot be read.
+ */
+ private File getResourceContainer(String resourceLocation, String[] paths)
+ throws IOException {
+ for (int i = 0; i < paths.length; ++i) {
+ File element = new File(paths[i]);
+ if (!element.exists()) {
+ continue;
+ }
+ if (element.isDirectory()) {
+ File resource = new File(element, resourceLocation);
+ if (resource.exists()) {
+ return resource;
+ }
+ } else {
+ // must be a zip of some sort
+ ZipFile zipFile = null;
+ try {
+ zipFile = new ZipFile(element);
+ if (zipFile.getEntry(resourceLocation) != null) {
+ return element;
+ }
+ } finally {
+ if (zipFile != null) {
+ zipFile.close();
+ }
+ }
+ }
+ }
+ return null;
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java
new file mode 100644
index 00000000..1415e2e4
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/DependencyAnalyzer.java
@@ -0,0 +1,130 @@
+/*
+ * 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.util.depend;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+
+import org.apache.tools.ant.types.Path;
+
+/**
+ * A dependency analyzer analyzes dependencies between Java classes to
+ * determine the minimal set of classes which are required by a set of
+ * &quot;root&quot; classes. Different implementations of this interface can
+ * use different strategies and libraries to determine the required set. For
+ * example, some analyzers will use class files while others might use
+ * source files. Analyzer specific configuration is catered for through a
+ * generic configure method
+ *
+ */
+public interface DependencyAnalyzer {
+ /**
+ * Add a source path to the source path used by this analyzer. The
+ * elements in the given path contain the source files for the classes
+ * being analyzed. Not all analyzers will use this information.
+ *
+ * @param sourcePath The Path instance specifying the source path
+ * elements.
+ */
+ void addSourcePath(Path sourcePath);
+
+ /**
+ * Add a classpath to the classpath being used by the analyzer. The
+ * classpath contains the binary classfiles for the classes being
+ * analyzed The elements may either be the directories or jar files.Not
+ * all analyzers will use this information.
+ *
+ * @param classpath the Path instance specifying the classpath elements
+ */
+ void addClassPath(Path classpath);
+
+ /**
+ * Add a root class. The root classes are used to drive the
+ * determination of dependency information. The analyzer will start at
+ * the root classes and add dependencies from there.
+ *
+ * @param classname the name of the class in Java dot notation.
+ */
+ void addRootClass(String classname);
+
+ /**
+ * Get the list of files in the file system upon which the root classes
+ * depend. The files will be either the classfiles or jar files upon
+ * which the root classes depend.
+ *
+ * @return an enumeration of File instances.
+ */
+ Enumeration<File> getFileDependencies();
+
+ /**
+ * Get the list of classes upon which root classes depend. This is a
+ * list of Java classnames in dot notation.
+ *
+ * @return an enumeration of Strings, each being the name of a Java
+ * class in dot notation.
+ */
+ Enumeration<String> getClassDependencies();
+
+
+ /**
+ * Reset the dependency list. This will reset the determined
+ * dependencies and the also list of root classes.
+ */
+ void reset();
+
+ /**
+ * Configure an aspect of the analyzer. The set of aspects that are
+ * supported is specific to each analyzer instance.
+ *
+ * @param name the name of the aspect being configured
+ * @param info the configuration information.
+ */
+ void config(String name, Object info);
+
+ /**
+ * Set the closure flag. If this flag is true the analyzer will traverse
+ * all class relationships until it has collected the entire set of
+ * direct and indirect dependencies
+ *
+ * @param closure true if dependencies should be traversed to determine
+ * indirect dependencies.
+ */
+ void setClosure(boolean closure);
+
+
+ /**
+ * Get the file that contains the class definition
+ *
+ * @param classname the name of the required class
+ * @return the file instance, zip or class, containing the
+ * class or null if the class could not be found.
+ * @exception IOException if the files in the classpath cannot be read.
+ */
+ File getClassContainer(String classname) throws IOException;
+
+ /**
+ * Get the file that contains the class source.
+ *
+ * @param classname the name of the required class
+ * @return the file instance, zip or java, containing the
+ * source or null if the source for the class could not be found.
+ * @exception IOException if the files in the sourcepath cannot be read.
+ */
+ File getSourceContainer(String classname) throws IOException;
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java
new file mode 100644
index 00000000..2bd2a6cf
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/AncestorAnalyzer.java
@@ -0,0 +1,144 @@
+/*
+ * 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.util.depend.bcel;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.depend.AbstractAnalyzer;
+
+/**
+ * A dependency analyzer which returns superclass and superinterface
+ * dependencies.
+ *
+ */
+public class AncestorAnalyzer extends AbstractAnalyzer {
+
+ /**
+ * Default constructor
+ *
+ * Causes the BCEL classes to load to ensure BCEL dependencies can
+ * be satisfied
+ */
+ public AncestorAnalyzer() {
+ // force BCEL classes to load now
+ try {
+ new ClassParser("force");
+ } catch (Exception e) {
+ // all released versions of BCEL may throw an IOException
+ // here, but BCEL's trunk does no longer declare to do so
+ if (!(e instanceof IOException)) {
+ throw new BuildException(e);
+ }
+ // ignore IOException like we've always done
+ }
+ }
+
+ /**
+ * Determine the dependencies of the configured root classes.
+ *
+ * @param files a vector to be populated with the files which contain
+ * the dependency classes
+ * @param classes a vector to be populated with the names of the
+ * dependency classes.
+ */
+ protected void determineDependencies(Vector<File> files, Vector<String> classes) {
+ // we get the root classes and build up a set of
+ // classes upon which they depend
+ Hashtable<String, String> dependencies = new Hashtable<String, String>();
+ Hashtable<File, File> containers = new Hashtable<File, File>();
+ Hashtable<String, String> toAnalyze = new Hashtable<String, String>();
+ Hashtable<String, String> nextAnalyze = new Hashtable<String, String>();
+
+ for (Enumeration<String> e = getRootClasses(); e.hasMoreElements();) {
+ String classname = e.nextElement();
+ toAnalyze.put(classname, classname);
+ }
+
+ int count = 0;
+ int maxCount = isClosureRequired() ? MAX_LOOPS : 2;
+ while (toAnalyze.size() != 0 && count++ < maxCount) {
+ nextAnalyze.clear();
+ for (String classname : toAnalyze.keySet()) {
+ dependencies.put(classname, classname);
+ try {
+ File container = getClassContainer(classname);
+ if (container == null) {
+ continue;
+ }
+ containers.put(container, container);
+
+ ClassParser parser = null;
+ if (container.getName().endsWith(".class")) {
+ parser = new ClassParser(container.getPath());
+ } else {
+ parser = new ClassParser(container.getPath(),
+ classname.replace('.', '/') + ".class");
+ }
+
+ JavaClass javaClass = parser.parse();
+ String[] interfaces = javaClass.getInterfaceNames();
+ for (int i = 0; i < interfaces.length; ++i) {
+ String interfaceName = interfaces[i];
+ if (!dependencies.containsKey(interfaceName)) {
+ nextAnalyze.put(interfaceName, interfaceName);
+ }
+ }
+
+ if (javaClass.isClass()) {
+ String superClass = javaClass.getSuperclassName();
+ if (!dependencies.containsKey(superClass)) {
+ nextAnalyze.put(superClass, superClass);
+ }
+ }
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ Hashtable<String, String> temp = toAnalyze;
+ toAnalyze = nextAnalyze;
+ nextAnalyze = temp;
+ }
+
+ files.removeAllElements();
+ for (File f : containers.keySet()) {
+ files.add(f);
+ }
+
+ classes.removeAllElements();
+ for (String dependency : dependencies.keySet()) {
+ classes.add(dependency);
+ }
+ }
+
+ /**
+ * Indicate if this analyzer can determine dependent files.
+ *
+ * @return true if the analyzer provides dependency file information.
+ */
+ protected boolean supportsFileDependencies() {
+ return true;
+ }
+
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java
new file mode 100644
index 00000000..d31d4534
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/DependencyVisitor.java
@@ -0,0 +1,192 @@
+/*
+ * 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.util.depend.bcel;
+
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+
+import org.apache.bcel.classfile.ConstantClass;
+import org.apache.bcel.classfile.ConstantNameAndType;
+import org.apache.bcel.classfile.ConstantPool;
+import org.apache.bcel.classfile.EmptyVisitor;
+import org.apache.bcel.classfile.Field;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.bcel.classfile.Method;
+
+/**
+ * A BCEL visitor implementation to collect class dependency information
+ *
+ */
+public class DependencyVisitor extends EmptyVisitor {
+ /** The collected dependencies */
+ private final Hashtable<String, String> dependencies = new Hashtable<String, String>();
+ /**
+ * The current class's constant pool - used to determine class names
+ * from class references.
+ */
+ private ConstantPool constantPool;
+
+ /**
+ * Get the dependencies collected by this visitor
+ *
+ * @return a Enumeration of classnames, being the classes upon which the
+ * visited classes depend.
+ */
+ public Enumeration<String> getDependencies() {
+ return dependencies.keys();
+ }
+
+ /** Clear the current set of collected dependencies. */
+ public void clearDependencies() {
+ dependencies.clear();
+ }
+
+ /**
+ * Visit the constant pool of a class
+ *
+ * @param constantPool the constant pool of the class being visited.
+ */
+ public void visitConstantPool(final ConstantPool constantPool) {
+ this.constantPool = constantPool;
+ }
+
+ /**
+ * Visit a class reference
+ *
+ * @param constantClass the constantClass entry for the class reference
+ */
+ public void visitConstantClass(final ConstantClass constantClass) {
+ final String classname
+ = constantClass.getConstantValue(constantPool).toString();
+ addSlashClass(classname);
+ }
+
+ /**
+ * Visit a name and type ref
+ *
+ * Look for class references in this
+ *
+ * @param obj the name and type reference being visited.
+ */
+ public void visitConstantNameAndType(final ConstantNameAndType obj) {
+ final String name = obj.getName(constantPool);
+ if (obj.getSignature(constantPool).equals("Ljava/lang/Class;")
+ && name.startsWith("class$")) {
+ String classname
+ = name.substring("class$".length()).replace('$', '.');
+ // does the class have a package structure
+ final int index = classname.lastIndexOf(".");
+ if (index > 0) {
+ char start;
+ // check if the package structure is more than 1 level deep
+ final int index2 = classname.lastIndexOf(".", index - 1);
+ if (index2 != -1) {
+ // class name has more than 1 package level 'com.company.Class'
+ start = classname.charAt(index2 + 1);
+ } else {
+ // class name has only 1 package level 'package.Class'
+ start = classname.charAt(0);
+ }
+ // Check to see if it's an inner class 'com.company.Class$Inner'
+ // CheckStyle:MagicNumber OFF
+ if ((start > 0x40) && (start < 0x5B)) {
+ // first letter of the previous segment of the class name 'Class'
+ // is upper case ascii. so according to the spec it's an inner class
+ classname = classname.substring(0, index) + "$"
+ + classname.substring(index + 1);
+ addClass(classname);
+ } else {
+ // Add the class in dotted notation 'com.company.Class'
+ addClass(classname);
+ }
+ // CheckStyle:MagicNumber ON
+ } else {
+ // Add a class with no package 'Class'
+ addClass(classname);
+ }
+ }
+ }
+
+ /**
+ * Visit a field of the class.
+ *
+ * @param field the field being visited
+ */
+ public void visitField(final Field field) {
+ addClasses(field.getSignature());
+ }
+
+ /**
+ * Visit a Java class
+ *
+ * @param javaClass the class being visited.
+ */
+ public void visitJavaClass(final JavaClass javaClass) {
+ addClass(javaClass.getClassName());
+ }
+
+ /**
+ * Visit a method of the current class
+ *
+ * @param method the method being visited.
+ */
+ public void visitMethod(final Method method) {
+ final String signature = method.getSignature();
+ final int pos = signature.indexOf(")");
+ addClasses(signature.substring(1, pos));
+ addClasses(signature.substring(pos + 1));
+ }
+
+ /**
+ * Add a classname to the list of dependency classes
+ *
+ * @param classname the class to be added to the list of dependencies.
+ */
+ void addClass(final String classname) {
+ dependencies.put(classname, classname);
+ }
+
+ /**
+ * Add all the classes from a descriptor string.
+ *
+ * @param string the descriptor string, being descriptors separated by
+ * ';' characters.
+ */
+ private void addClasses(final String string) {
+ final StringTokenizer tokens = new StringTokenizer(string, ";");
+ while (tokens.hasMoreTokens()) {
+ final String descriptor = tokens.nextToken();
+ final int pos = descriptor.indexOf('L');
+ if (pos != -1) {
+ addSlashClass(descriptor.substring(pos + 1));
+ }
+ }
+ }
+
+ /**
+ * Adds a class name in slash format
+ * (for example org/apache/tools/ant/Main).
+ *
+ * @param classname the class name in slash format
+ */
+ private void addSlashClass(final String classname) {
+ addClass(classname.replace('/', '.'));
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java
new file mode 100644
index 00000000..f270fd48
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/depend/bcel/FullAnalyzer.java
@@ -0,0 +1,136 @@
+/*
+ * 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.util.depend.bcel;
+import java.io.File;
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+import org.apache.bcel.classfile.ClassParser;
+import org.apache.bcel.classfile.DescendingVisitor;
+import org.apache.bcel.classfile.JavaClass;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.depend.AbstractAnalyzer;
+
+/**
+ * An analyzer capable fo traversing all class - class relationships.
+ *
+ */
+public class FullAnalyzer extends AbstractAnalyzer {
+ /**
+ * Default constructor
+ *
+ * Causes the BCEL classes to load to ensure BCEL dependencies can
+ * be satisfied
+ */
+ public FullAnalyzer() {
+ // force BCEL classes to load now
+ try {
+ new ClassParser("force");
+ } catch (Exception e) {
+ // all released versions of BCEL may throw an IOException
+ // here, but BCEL's trunk does no longer declare to do so
+ if (!(e instanceof IOException)) {
+ throw new BuildException(e);
+ }
+ // ignore IOException like we've always done
+ }
+ }
+
+ /**
+ * Determine the dependencies of the configured root classes.
+ *
+ * @param files a vector to be populated with the files which contain
+ * the dependency classes
+ * @param classes a vector to be populated with the names of the
+ * dependency classes.
+ */
+ protected void determineDependencies(Vector<File> files, Vector<String> classes) {
+ // we get the root classes and build up a set of
+ // classes upon which they depend
+ Hashtable<String, String> dependencies = new Hashtable<String, String>();
+ Hashtable<File, File> containers = new Hashtable<File, File>();
+ Hashtable<String, String> toAnalyze = new Hashtable<String, String>();
+ for (Enumeration<String> e = getRootClasses(); e.hasMoreElements();) {
+ String classname = e.nextElement();
+ toAnalyze.put(classname, classname);
+ }
+
+ int count = 0;
+ int maxCount = isClosureRequired() ? MAX_LOOPS : 2;
+ while (toAnalyze.size() != 0 && count++ < maxCount) {
+ DependencyVisitor dependencyVisitor = new DependencyVisitor();
+ for (String classname : toAnalyze.keySet()) {
+ dependencies.put(classname, classname);
+ try {
+ File container = getClassContainer(classname);
+ if (container == null) {
+ continue;
+ }
+ containers.put(container, container);
+
+ ClassParser parser = null;
+ if (container.getName().endsWith(".class")) {
+ parser = new ClassParser(container.getPath());
+ } else {
+ parser = new ClassParser(container.getPath(),
+ classname.replace('.', '/') + ".class");
+ }
+
+ JavaClass javaClass = parser.parse();
+ DescendingVisitor traverser
+ = new DescendingVisitor(javaClass, dependencyVisitor);
+ traverser.visit();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+
+ toAnalyze.clear();
+
+ // now recover all the dependencies collected and add to the list.
+ Enumeration<String> depsEnum = dependencyVisitor.getDependencies();
+ while (depsEnum.hasMoreElements()) {
+ String className = depsEnum.nextElement();
+ if (!dependencies.containsKey(className)) {
+ toAnalyze.put(className, className);
+ }
+ }
+ }
+
+ files.removeAllElements();
+ for (File f : containers.keySet()) {
+ files.add(f);
+ }
+
+ classes.removeAllElements();
+ for (String dependency : dependencies.keySet()) {
+ classes.add(dependency);
+ }
+ }
+
+ /**
+ * Indicate if this analyzer can determine dependent files.
+ *
+ * @return true if the analyzer provides dependency file information.
+ */
+ protected boolean supportsFileDependencies() {
+ return true;
+ }
+}
+
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/facade/FacadeTaskHelper.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/facade/FacadeTaskHelper.java
new file mode 100644
index 00000000..4fb4341b
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/facade/FacadeTaskHelper.java
@@ -0,0 +1,165 @@
+/*
+ * 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.util.facade;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.types.Path;
+
+/**
+ * Helper class for facade implementations - encapsulates treatment of
+ * explicit implementation choices, magic properties and
+ * implementation specific command line arguments.
+ *
+ *
+ * @since Ant 1.5
+ */
+public class FacadeTaskHelper {
+
+ /**
+ * Command line arguments.
+ */
+ private List<ImplementationSpecificArgument> args = new ArrayList<ImplementationSpecificArgument>();
+
+ /**
+ * The explicitly chosen implementation.
+ */
+ private String userChoice;
+
+ /**
+ * The magic property to consult.
+ */
+ private String magicValue;
+
+ /**
+ * The default value.
+ */
+ private String defaultValue;
+
+ /**
+ * User specified path used as classpath when loading the implementation.
+ */
+ private Path implementationClasspath;
+
+ /**
+ * @param defaultValue The default value for the implementation.
+ * Must not be null.
+ */
+ public FacadeTaskHelper(String defaultValue) {
+ this(defaultValue, null);
+ }
+
+ /**
+ * @param defaultValue The default value for the implementation.
+ * Must not be null.
+ * @param magicValue the value of a magic property that may hold a user.
+ * choice. May be null.
+ */
+ public FacadeTaskHelper(String defaultValue, String magicValue) {
+ this.defaultValue = defaultValue;
+ this.magicValue = magicValue;
+ }
+
+ /**
+ * Used to set the value of the magic property.
+ * @param magicValue the value of a magic property that may hold a user.
+ */
+ public void setMagicValue(String magicValue) {
+ this.magicValue = magicValue;
+ }
+
+ /**
+ * Used for explicit user choices.
+ * @param userChoice the explicitly chosen implementation.
+ */
+ public void setImplementation(String userChoice) {
+ this.userChoice = userChoice;
+ }
+
+ /**
+ * Retrieves the implementation.
+ * @return the implementation.
+ */
+ public String getImplementation() {
+ return userChoice != null ? userChoice
+ : (magicValue != null ? magicValue
+ : defaultValue);
+ }
+
+ /**
+ * Retrieves the explicit user choice.
+ * @return the explicit user choice.
+ */
+ public String getExplicitChoice() {
+ return userChoice;
+ }
+
+ /**
+ * Command line argument.
+ * @param arg an argument to add.
+ */
+ public void addImplementationArgument(ImplementationSpecificArgument arg) {
+ args.add(arg);
+ }
+
+ /**
+ * Retrieves the command line arguments enabled for the current
+ * facade implementation.
+ * @return an array of command line arguments.
+ */
+ public String[] getArgs() {
+ List<String> tmp = new ArrayList<String>(args.size());
+ for (ImplementationSpecificArgument arg : args) {
+ String[] curr = arg.getParts(getImplementation());
+ if (curr != null) {
+ for (int i = 0; i < curr.length; i++) {
+ tmp.add(curr[i]);
+ }
+ }
+ }
+ String[] res = new String[tmp.size()];
+ return (String[]) tmp.toArray(res);
+ }
+
+ /**
+ * Tests whether the implementation has been chosen by the user
+ * (either via a magic property or explicitly.
+ * @return true if magic or user choice has be set.
+ * @since Ant 1.5.2
+ */
+ public boolean hasBeenSet() {
+ return userChoice != null || magicValue != null;
+ }
+
+ /**
+ * The classpath to use when loading the implementation.
+ *
+ * @param project the current project
+ * @return a Path instance that may be appended to
+ * @since Ant 1.8.0
+ */
+ public Path getImplementationClasspath(Project project) {
+ if (implementationClasspath == null) {
+ implementationClasspath = new Path(project);
+ }
+ return implementationClasspath;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/facade/ImplementationSpecificArgument.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/facade/ImplementationSpecificArgument.java
new file mode 100644
index 00000000..ba7f14a0
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/facade/ImplementationSpecificArgument.java
@@ -0,0 +1,61 @@
+/*
+ * 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.util.facade;
+
+import org.apache.tools.ant.types.Commandline;
+
+/**
+ * Extension of Commandline.Argument with a new attribute that chooses
+ * a specific implementation of the facade.
+ *
+ *
+ * @since Ant 1.5
+ */
+public class ImplementationSpecificArgument extends Commandline.Argument {
+ private String impl;
+
+ /** Constructor for ImplementationSpecificArgument. */
+ public ImplementationSpecificArgument() {
+ super();
+ }
+
+ /**
+ * Set the implementation this argument is for.
+ * @param impl the implementation this command line argument is for.
+ */
+ public void setImplementation(String impl) {
+ this.impl = impl;
+ }
+
+ /**
+ * Return the parts this Argument consists of, if the
+ * implementation matches the chosen implementation.
+ * @see org.apache.tools.ant.types.Commandline.Argument#getParts()
+ * @param chosenImpl the implementation to check against.
+ * @return the parts if the implementation matches or an zero length
+ * array if not.
+ */
+ public final String[] getParts(String chosenImpl) {
+ if (impl == null || impl.equals(chosenImpl)) {
+ return super.getParts();
+ } else {
+ return new String[0];
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/java15/ProxyDiagnostics.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/java15/ProxyDiagnostics.java
new file mode 100644
index 00000000..bd2e7cac
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/java15/ProxyDiagnostics.java
@@ -0,0 +1,108 @@
+/*
+ * 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.util.java15;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * This class exists to create a string that tells diagnostics about the current
+ * state of proxy diagnostics.
+ * It does this in its toString operator.
+ * Java1.5+ is needed to compile this class; its interface is classic typeless
+ * Java.
+ * @since Ant 1.7
+ */
+public class ProxyDiagnostics {
+
+ private String destination;
+
+ private URI destURI;
+
+ /** {@value} */
+ public static final String DEFAULT_DESTINATION = "http://ant.apache.org/";
+
+ /**
+ * create a diagnostics binding for a specific URI
+ * @param destination dest to bind to
+ * @throws BuildException if the URI is malformed.
+ */
+ public ProxyDiagnostics(String destination) {
+ this.destination = destination;
+ try {
+ this.destURI = new URI(destination);
+ } catch (URISyntaxException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * create a proxy diagnostics tool bound to
+ * {@link #DEFAULT_DESTINATION}
+ */
+ public ProxyDiagnostics() {
+ this(DEFAULT_DESTINATION);
+ }
+
+ /**
+ * Get the diagnostics for proxy information.
+ * @return the information.
+ */
+ public String toString() {
+ ProxySelector selector = ProxySelector.getDefault();
+ List list = selector.select(destURI);
+ StringBuffer result = new StringBuffer();
+ Iterator proxies = list.listIterator();
+ while (proxies.hasNext()) {
+ Proxy proxy = (Proxy) proxies.next();
+ SocketAddress address = proxy.address();
+ if (address == null) {
+ result.append("Direct connection\n");
+ } else {
+ result.append(proxy.toString());
+ if (address instanceof InetSocketAddress) {
+ InetSocketAddress ina = (InetSocketAddress) address;
+ result.append(' ');
+ result.append(ina.getHostName());
+ result.append(':');
+ result.append(ina.getPort());
+ if (ina.isUnresolved()) {
+ result.append(" [unresolved]");
+ } else {
+ InetAddress addr = ina.getAddress();
+ result.append(" [");
+ result.append(addr.getHostAddress());
+ result.append(']');
+ }
+ }
+ result.append('\n');
+ }
+ }
+ return result.toString();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/JavaxScriptRunner.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/JavaxScriptRunner.java
new file mode 100644
index 00000000..a24537ac
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/JavaxScriptRunner.java
@@ -0,0 +1,163 @@
+/*
+ * 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.util.optional;
+
+import java.util.Iterator;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.util.ReflectWrapper;
+import org.apache.tools.ant.util.ScriptRunnerBase;
+
+/**
+ * This class is used to run scripts using JSR 223.
+ * @since Ant 1.7.0
+ */
+public class JavaxScriptRunner extends ScriptRunnerBase {
+ private ReflectWrapper engine;
+
+ /**
+ * Get the name of the manager prefix.
+ * @return "javax"
+ */
+ public String getManagerName() {
+ return "javax";
+ }
+
+ /** {@inheritDoc}. */
+ public boolean supportsLanguage() {
+ if (engine != null) {
+ return true;
+ }
+ checkLanguage();
+ ClassLoader origLoader = replaceContextLoader();
+ try {
+ return createEngine() != null;
+ } catch (Exception ex) {
+ return false;
+ } finally {
+ restoreContextLoader(origLoader);
+ }
+ }
+
+ /**
+ * Do the work to run the script.
+ *
+ * @param execName the name that will be passed to the
+ * scripting engine for this script execution.
+ *
+ * @exception BuildException if something goes wrong executing the script.
+ */
+ public void executeScript(String execName) throws BuildException {
+ evaluateScript(execName);
+ }
+
+ /**
+ * Do the work to eval the script.
+ *
+ * @param execName the name that will be passed to the
+ * scripting engine for this script execution.
+ * @return the result of the evaluation
+ * @exception BuildException if something goes wrong executing the script.
+ */
+ public Object evaluateScript(String execName) throws BuildException {
+ checkLanguage();
+ ClassLoader origLoader = replaceContextLoader();
+ try {
+ ReflectWrapper engine = createEngine();
+ if (engine == null) {
+ throw new BuildException(
+ "Unable to create javax script engine for "
+ + getLanguage());
+ }
+ for (Iterator i = getBeans().keySet().iterator(); i.hasNext();) {
+ String key = (String) i.next();
+ Object value = getBeans().get(key);
+ if ("FX".equalsIgnoreCase(getLanguage())) {
+ engine.invoke(
+ "put", String.class, key
+ + ":" + value.getClass().getName(),
+ Object.class, value);
+ } else {
+ engine.invoke(
+ "put", String.class, key,
+ Object.class, value);
+ }
+ }
+ // execute the script
+ return engine.invoke("eval", String.class, getScript());
+ } catch (BuildException be) {
+ //catch and rethrow build exceptions
+
+ // this may be a BuildException wrapping a ScriptException
+ // deeply wrapping yet another BuildException - for
+ // example because of self.fail() - see
+ // https://issues.apache.org/bugzilla/show_bug.cgi?id=47509
+ throw unwrap(be);
+ } catch (Exception be) {
+ //any other exception? Get its cause
+ Throwable t = be;
+ Throwable te = be.getCause();
+ if (te != null) {
+ if (te instanceof BuildException) {
+ throw (BuildException) te;
+ } else {
+ t = te;
+ }
+ }
+ throw new BuildException(t);
+ } finally {
+ restoreContextLoader(origLoader);
+ }
+ }
+
+ private ReflectWrapper createEngine() throws Exception {
+ if (engine != null) {
+ return engine;
+ }
+ ReflectWrapper manager = new ReflectWrapper(
+ getClass().getClassLoader(), "javax.script.ScriptEngineManager");
+ Object e = manager.invoke(
+ "getEngineByName", String.class, getLanguage());
+ if (e == null) {
+ return null;
+ }
+ ReflectWrapper ret = new ReflectWrapper(e);
+ if (getKeepEngine()) {
+ this.engine = ret;
+ }
+ return ret;
+ }
+
+ /**
+ * Traverse a Throwable's cause(s) and return the BuildException
+ * most deeply nested into it - if any.
+ */
+ private static BuildException unwrap(Throwable t) {
+ BuildException deepest =
+ t instanceof BuildException ? (BuildException) t : null;
+ Throwable current = t;
+ while (current.getCause() != null) {
+ current = current.getCause();
+ if (current instanceof BuildException) {
+ deepest = (BuildException) current;
+ }
+ }
+ return deepest;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/NoExitSecurityManager.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/NoExitSecurityManager.java
new file mode 100644
index 00000000..e704ab29
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/NoExitSecurityManager.java
@@ -0,0 +1,51 @@
+/*
+ * 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.util.optional;
+
+import java.security.Permission;
+
+import org.apache.tools.ant.ExitException;
+
+/**
+ * This is intended as a replacement for the default system manager.
+ * The goal is to intercept System.exit calls and make it throw an
+ * exception instead so that a System.exit in a task does not
+ * fully terminate Ant.
+ *
+ * @see ExitException
+ */
+public class NoExitSecurityManager extends SecurityManager {
+
+ /**
+ * Override SecurityManager#checkExit.
+ * This throws an ExitException(status) exception.
+ * @param status the exit status
+ */
+ public void checkExit(int status) {
+ throw new ExitException(status);
+ }
+
+ /**
+ * Override SecurityManager#checkPermission.
+ * This does nothing.
+ * @param perm the requested permission.
+ */
+ public void checkPermission(Permission perm) {
+ // no permission here
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java
new file mode 100644
index 00000000..0f4cd1f9
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/ScriptRunner.java
@@ -0,0 +1,177 @@
+/*
+ * 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.util.optional;
+
+import java.util.Hashtable;
+import java.util.Iterator;
+
+import org.apache.bsf.BSFEngine;
+import org.apache.bsf.BSFException;
+import org.apache.bsf.BSFManager;
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.ReflectUtil;
+import org.apache.tools.ant.util.ScriptRunnerBase;
+
+/**
+ * This class is used to run BSF scripts
+ *
+ */
+public class ScriptRunner extends ScriptRunnerBase {
+ // Register Groovy ourselves, since BSF did not
+ // natively support it in versions previous to 1.2.4.
+ static {
+ BSFManager.registerScriptingEngine(
+ "groovy",
+ "org.codehaus.groovy.bsf.GroovyEngine",
+ new String[] {"groovy", "gy"});
+ }
+
+ private BSFEngine engine;
+ private BSFManager manager;
+
+ /**
+ * Get the name of the manager prefix.
+ * @return "bsf"
+ */
+ public String getManagerName() {
+ return "bsf";
+ }
+
+ /**
+ * Check if bsf supports the language.
+ * @return true if bsf can create an engine for this language.
+ */
+ public boolean supportsLanguage() {
+ Hashtable table = (Hashtable) ReflectUtil.getField(
+ new BSFManager(), "registeredEngines");
+ String engineClassName = (String) table.get(getLanguage());
+ if (engineClassName == null) {
+ getProject().log(
+ "This is no BSF engine class for language '"
+ + getLanguage() + "'",
+ Project.MSG_VERBOSE);
+ return false;
+ }
+ try {
+ getScriptClassLoader().loadClass(engineClassName);
+ return true;
+ } catch (Throwable ex) {
+ getProject().log(
+ "unable to create BSF engine class for language '"
+ + getLanguage() + "'",
+ ex,
+ Project.MSG_VERBOSE);
+ return false;
+ }
+ }
+
+ /**
+ * Do the work.
+ *
+ * @param execName the name that will be passed to BSF for this script execution.
+ * @exception BuildException if something goes wrong executing the script.
+ */
+ public void executeScript(String execName) throws BuildException {
+ checkLanguage();
+ ClassLoader origLoader = replaceContextLoader();
+ try {
+ BSFManager m = createManager();
+ declareBeans(m);
+ // execute the script
+ if (engine == null) {
+ m.exec(getLanguage(), execName, 0, 0, getScript());
+ } else {
+ engine.exec(execName, 0, 0, getScript());
+ }
+ } catch (BSFException be) {
+ throw getBuildException(be);
+ } finally {
+ restoreContextLoader(origLoader);
+ }
+ }
+
+ /**
+ * Evaluate the script.
+ *
+ * @param execName the name that will be passed to BSF for this script execution.
+ * @return the result of the evaluation
+ * @exception BuildException if something goes wrong executing the script.
+ */
+ public Object evaluateScript(String execName) throws BuildException {
+ checkLanguage();
+ ClassLoader origLoader = replaceContextLoader();
+ try {
+ BSFManager m = createManager();
+ declareBeans(m);
+ // execute the script
+ if (engine == null) {
+ return m.eval(getLanguage(), execName, 0, 0, getScript());
+ }
+ return engine.eval(execName, 0, 0, getScript());
+ } catch (BSFException be) {
+ throw getBuildException(be);
+ } finally {
+ restoreContextLoader(origLoader);
+ }
+ }
+
+ /**
+ * Get/create a BuildException from a BSFException.
+ * @param be BSFException to convert.
+ * @return BuildException the converted exception.
+ */
+ private BuildException getBuildException(BSFException be) {
+ Throwable t = be;
+ Throwable te = be.getTargetException();
+ if (te instanceof BuildException) {
+ return (BuildException) te;
+ }
+ return new BuildException(te == null ? t : te);
+ }
+
+ private void declareBeans(BSFManager m) throws BSFException {
+ for (Iterator i = getBeans().keySet().iterator(); i.hasNext();) {
+ String key = (String) i.next();
+ Object value = getBeans().get(key);
+ if (value != null) {
+ m.declareBean(key, value, value.getClass());
+ } else {
+ // BSF uses a hashtable to store values
+ // so cannot declareBean with a null value
+ // So need to remove any bean of this name as
+ // that bean should not be visible
+ m.undeclareBean(key);
+ }
+ }
+ }
+
+ private BSFManager createManager() throws BSFException {
+ if (manager != null) {
+ return manager;
+ }
+ BSFManager m = new BSFManager();
+ m.setClassLoader(getScriptClassLoader());
+ if (getKeepEngine()) {
+ BSFEngine e = manager.loadScriptingEngine(getLanguage());
+ this.manager = m;
+ this.engine = e;
+ }
+ return m;
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/WeakishReference12.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/WeakishReference12.java
new file mode 100644
index 00000000..4cd12788
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/optional/WeakishReference12.java
@@ -0,0 +1,45 @@
+/*
+ * 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.util.optional;
+
+import org.apache.tools.ant.util.WeakishReference;
+
+/**
+ * This is a reference that really is is Weak, as it uses the
+ * appropriate java.lang.ref class.
+ * @deprecated since 1.7.
+ * Just use {@link java.lang.ref.WeakReference} directly.
+ * Note that in ant1.7 is parent was changed to extend HardReference.
+ * This is because the latter has access to the (package scoped)
+ * WeakishReference(Object) constructor, and both that and this are thin
+ * facades on the underlying no-longer-abstract base class.
+ */
+public class WeakishReference12 extends WeakishReference.HardReference {
+
+
+ /**
+ * create a new soft reference, which is bound to a
+ * Weak reference inside
+ * @param reference the object to reference.
+ * @see java.lang.ref.WeakReference
+ */
+ public WeakishReference12(Object reference) {
+ super(reference);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaOroMatcher.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaOroMatcher.java
new file mode 100644
index 00000000..5c43376c
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaOroMatcher.java
@@ -0,0 +1,170 @@
+/*
+ * 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.util.regexp;
+
+import java.util.Vector;
+
+import org.apache.oro.text.regex.MatchResult;
+import org.apache.oro.text.regex.Pattern;
+import org.apache.oro.text.regex.Perl5Compiler;
+import org.apache.oro.text.regex.Perl5Matcher;
+import org.apache.tools.ant.BuildException;
+
+
+/**
+ * Implementation of RegexpMatcher for Jakarta-ORO.
+ *
+ */
+public class JakartaOroMatcher implements RegexpMatcher {
+
+ private String pattern;
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected final Perl5Compiler compiler = new Perl5Compiler();
+ protected final Perl5Matcher matcher = new Perl5Matcher();
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Constructor for JakartaOroMatcher.
+ */
+ public JakartaOroMatcher() {
+ }
+
+ /**
+ * Set the regexp pattern from the String description.
+ * @param pattern the pattern to match
+ */
+ public void setPattern(final String pattern) {
+ this.pattern = pattern;
+ }
+
+ /**
+ * Get a String representation of the regexp pattern
+ * @return the pattern
+ */
+ public String getPattern() {
+ return this.pattern;
+ }
+
+ /**
+ * Get a compiled representation of the regexp pattern
+ * @param options the options
+ * @return the compiled pattern
+ * @throws BuildException on error
+ */
+ protected Pattern getCompiledPattern(final int options)
+ throws BuildException {
+ try {
+ // compute the compiler options based on the input options first
+ final Pattern p = compiler.compile(pattern, getCompilerOptions(options));
+ return p;
+ } catch (final Exception e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * Does the given argument match the pattern using default options?
+ * @param argument the string to match against
+ * @return true if the pattern matches
+ * @throws BuildException on error
+ */
+ public boolean matches(final String argument) throws BuildException {
+ return matches(argument, MATCH_DEFAULT);
+ }
+
+ /**
+ * Does the given argument match the pattern?
+ * @param input the string to match against
+ * @param options the regex options to use
+ * @return true if the pattern matches
+ * @throws BuildException on error
+ */
+ public boolean matches(final String input, final int options)
+ throws BuildException {
+ final Pattern p = getCompiledPattern(options);
+ return matcher.contains(input, p);
+ }
+
+ /**
+ * Returns a Vector of matched groups found in the argument
+ * using default options.
+ *
+ * <p>Group 0 will be the full match, the rest are the
+ * parenthesized subexpressions</p>.
+ *
+ * @param argument the string to match against
+ * @return the vector of groups
+ * @throws BuildException on error
+ */
+ public Vector getGroups(final String argument) throws BuildException {
+ return getGroups(argument, MATCH_DEFAULT);
+ }
+
+ /**
+ * Returns a Vector of matched groups found in the argument.
+ *
+ * <p>Group 0 will be the full match, the rest are the
+ * parenthesized subexpressions</p>.
+ *
+ * @param input the string to match against
+ * @param options the regex options to use
+ * @return the vector of groups
+ * @throws BuildException on error
+ */
+ public Vector getGroups(final String input, final int options)
+ throws BuildException {
+ if (!matches(input, options)) {
+ return null;
+ }
+ final Vector v = new Vector();
+ final MatchResult mr = matcher.getMatch();
+ final int cnt = mr.groups();
+ for (int i = 0; i < cnt; i++) {
+ String match = mr.group(i);
+ // treat non-matching groups as empty matches
+ if (match == null) {
+ match = "";
+ }
+ v.addElement(match);
+ }
+ return v;
+ }
+
+ /**
+ * Convert the generic options to the regex compiler specific options.
+ * @param options the generic options
+ * @return the specific options
+ */
+ protected int getCompilerOptions(final int options) {
+ int cOptions = Perl5Compiler.DEFAULT_MASK;
+
+ if (RegexpUtil.hasFlag(options, MATCH_CASE_INSENSITIVE)) {
+ cOptions |= Perl5Compiler.CASE_INSENSITIVE_MASK;
+ }
+ if (RegexpUtil.hasFlag(options, MATCH_MULTILINE)) {
+ cOptions |= Perl5Compiler.MULTILINE_MASK;
+ }
+ if (RegexpUtil.hasFlag(options, MATCH_SINGLELINE)) {
+ cOptions |= Perl5Compiler.SINGLELINE_MASK;
+ }
+
+ return cOptions;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaOroRegexp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaOroRegexp.java
new file mode 100644
index 00000000..529a78ae
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaOroRegexp.java
@@ -0,0 +1,98 @@
+/*
+ * 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.util.regexp;
+
+import org.apache.oro.text.regex.Perl5Substitution;
+import org.apache.oro.text.regex.Substitution;
+import org.apache.oro.text.regex.Util;
+import org.apache.tools.ant.BuildException;
+
+/***
+ * Regular expression implementation using the Jakarta Oro package
+ */
+public class JakartaOroRegexp extends JakartaOroMatcher implements Regexp {
+
+ private static final int DECIMAL = 10;
+
+ /** Constructor for JakartaOroRegexp */
+ public JakartaOroRegexp() {
+ super();
+ }
+
+ /**
+ * Perform a substitution on the regular expression.
+ * @param input The string to substitute on
+ * @param argument The string which defines the substitution
+ * @param options The list of options for the match and replace.
+ * @return the result of the operation
+ * @throws BuildException on error
+ */
+ public String substitute(final String input, final String argument, final int options)
+ throws BuildException {
+ // translate \1 to $1 so that the Perl5Substitution will work
+ final StringBuffer subst = new StringBuffer();
+ for (int i = 0; i < argument.length(); i++) {
+ char c = argument.charAt(i);
+ if (c == '$') {
+ subst.append('\\');
+ subst.append('$');
+ } else if (c == '\\') {
+ if (++i < argument.length()) {
+ c = argument.charAt(i);
+ final int value = Character.digit(c, DECIMAL);
+ if (value > -1) {
+ subst.append("$").append(value);
+ } else {
+ subst.append(c);
+ }
+ } else {
+ // TODO - should throw an exception instead?
+ subst.append('\\');
+ }
+ } else {
+ subst.append(c);
+ }
+ }
+
+ // Do the substitution
+ final Substitution s =
+ new Perl5Substitution(subst.toString(),
+ Perl5Substitution.INTERPOLATE_ALL);
+ return Util.substitute(matcher,
+ getCompiledPattern(options),
+ s,
+ input,
+ getSubsOptions(options));
+ }
+
+ /**
+ * Convert ant regexp substitution option to oro options.
+ *
+ * @param options the ant regexp options
+ * @return the oro substition options
+ */
+ protected int getSubsOptions(final int options) {
+ final boolean replaceAll = RegexpUtil.hasFlag(options, REPLACE_ALL);
+ int subsOptions = 1;
+ if (replaceAll) {
+ subsOptions = Util.SUBSTITUTE_ALL;
+ }
+ return subsOptions;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpMatcher.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpMatcher.java
new file mode 100644
index 00000000..3e14415d
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpMatcher.java
@@ -0,0 +1,161 @@
+/*
+ * 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.util.regexp;
+
+import java.util.Vector;
+import org.apache.regexp.RE;
+import org.apache.regexp.RESyntaxException;
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Implementation of RegexpMatcher for Jakarta-Regexp.
+ *
+ */
+public class JakartaRegexpMatcher implements RegexpMatcher {
+
+ private String pattern;
+
+ /**
+ * Set the regexp pattern from the String description.
+ * @param pattern the pattern to match
+ */
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+ /**
+ * Get a String representation of the regexp pattern
+ * @return the pattern
+ */
+ public String getPattern() {
+ return pattern;
+ }
+
+ /**
+ * Compile the pattern.
+ *
+ * @param options the ant regexp options
+ * @return a compiled pattern
+ * @exception BuildException if an error occurs
+ */
+ protected RE getCompiledPattern(int options)
+ throws BuildException {
+ int cOptions = getCompilerOptions(options);
+ try {
+ RE reg = new RE(pattern);
+ reg.setMatchFlags(cOptions);
+ return reg;
+ } catch (RESyntaxException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * Does the given argument match the pattern?
+ * @param argument the string to match against
+ * @return true if the pattern matches
+ * @throws BuildException on error
+ */
+ public boolean matches(String argument) throws BuildException {
+ return matches(argument, MATCH_DEFAULT);
+ }
+
+ /**
+ * Does the given argument match the pattern?
+ * @param input the string to match against
+ * @param options the regex options to use
+ * @return true if the pattern matches
+ * @throws BuildException on error
+ */
+ public boolean matches(String input, int options)
+ throws BuildException {
+ return matches(input, getCompiledPattern(options));
+ }
+
+ private boolean matches(String input, RE reg) {
+ return reg.match(input);
+ }
+
+ /**
+ * Returns a Vector of matched groups found in the argument
+ * using default options.
+ *
+ * <p>Group 0 will be the full match, the rest are the
+ * parenthesized subexpressions</p>.
+ *
+ * @param argument the string to match against
+ * @return the vector of groups
+ * @throws BuildException on error
+ */
+ public Vector getGroups(String argument) throws BuildException {
+ return getGroups(argument, MATCH_DEFAULT);
+ }
+
+ /**
+ * Returns a Vector of matched groups found in the argument.
+ *
+ * <p>Group 0 will be the full match, the rest are the
+ * parenthesized subexpressions</p>.
+ *
+ * @param input the string to match against
+ * @param options the regex options to use
+ * @return the vector of groups
+ * @throws BuildException on error
+ */
+ public Vector getGroups(String input, int options)
+ throws BuildException {
+ RE reg = getCompiledPattern(options);
+ if (!matches(input, reg)) {
+ return null;
+ }
+ Vector v = new Vector();
+ int cnt = reg.getParenCount();
+ for (int i = 0; i < cnt; i++) {
+ String match = reg.getParen(i);
+ // treat non-matching groups as empty matches
+ if (match == null) {
+ match = "";
+ }
+ v.addElement(match);
+ }
+ return v;
+ }
+
+ /**
+ * Convert the generic options to the regex compiler specific options.
+ * @param options the generic options
+ * @return the specific options
+ */
+ protected int getCompilerOptions(int options) {
+ int cOptions = RE.MATCH_NORMAL;
+
+ if (RegexpUtil.hasFlag(options, MATCH_CASE_INSENSITIVE)) {
+ cOptions |= RE.MATCH_CASEINDEPENDENT;
+ }
+ if (RegexpUtil.hasFlag(options, MATCH_MULTILINE)) {
+ cOptions |= RE.MATCH_MULTILINE;
+ }
+ if (RegexpUtil.hasFlag(options, MATCH_SINGLELINE)) {
+ cOptions |= RE.MATCH_SINGLELINE;
+ }
+
+ return cOptions;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpRegexp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpRegexp.java
new file mode 100644
index 00000000..865f424a
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/JakartaRegexpRegexp.java
@@ -0,0 +1,90 @@
+/*
+ * 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.util.regexp;
+
+import java.util.Vector;
+import org.apache.regexp.RE;
+import org.apache.tools.ant.BuildException;
+
+/***
+ * Regular expression implementation using the Jakarta Regexp package
+ */
+public class JakartaRegexpRegexp extends JakartaRegexpMatcher
+ implements Regexp {
+
+ private static final int DECIMAL = 10;
+
+ /** Constructor for JakartaRegexpRegexp */
+ public JakartaRegexpRegexp() {
+ super();
+ }
+
+ /**
+ * Convert ant regexp substitution option to apache regex options.
+ *
+ * @param options the ant regexp options
+ * @return the apache regex substition options
+ */
+ protected int getSubsOptions(int options) {
+ int subsOptions = RE.REPLACE_FIRSTONLY;
+ if (RegexpUtil.hasFlag(options, REPLACE_ALL)) {
+ subsOptions = RE.REPLACE_ALL;
+ }
+ return subsOptions;
+ }
+
+ /**
+ * Perform a substitution on the regular expression.
+ * @param input The string to substitute on
+ * @param argument The string which defines the substitution
+ * @param options The list of options for the match and replace.
+ * @return the result of the operation
+ * @throws BuildException on error
+ */
+ public String substitute(String input, String argument, int options)
+ throws BuildException {
+ Vector v = getGroups(input, options);
+
+ // replace \1 with the corresponding group
+ StringBuffer result = new StringBuffer();
+ for (int i = 0; i < argument.length(); i++) {
+ char c = argument.charAt(i);
+ if (c == '\\') {
+ if (++i < argument.length()) {
+ c = argument.charAt(i);
+ int value = Character.digit(c, DECIMAL);
+ if (value > -1) {
+ result.append((String) v.elementAt(value));
+ } else {
+ result.append(c);
+ }
+ } else {
+ // TODO - should throw an exception instead?
+ result.append('\\');
+ }
+ } else {
+ result.append(c);
+ }
+ }
+ argument = result.toString();
+
+ RE reg = getCompiledPattern(options);
+ int sOptions = getSubsOptions(options);
+ return reg.subst(input, argument, sOptions);
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcher.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcher.java
new file mode 100644
index 00000000..8c241d4e
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpMatcher.java
@@ -0,0 +1,170 @@
+/*
+ * 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.util.regexp;
+
+import java.util.Vector;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Implementation of RegexpMatcher for the built-in regexp matcher of
+ * JDK 1.4. UNIX_LINES option is enabled as a default.
+ *
+ */
+public class Jdk14RegexpMatcher implements RegexpMatcher {
+
+ private String pattern;
+
+ /** Constructor for JakartaOroRegexp */
+ public Jdk14RegexpMatcher() {
+ }
+
+ /**
+ * Set the regexp pattern from the String description.
+ * @param pattern the pattern to match
+ */
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+ /**
+ * Get a String representation of the regexp pattern
+ * @return the pattern
+ * @throws BuildException on error
+ */
+ public String getPattern() {
+ return pattern;
+ }
+
+ /**
+ * Get a compiled representation of the regexp pattern
+ * @param options the options
+ * @return the compiled pattern
+ * @throws BuildException on error
+ */
+ protected Pattern getCompiledPattern(int options)
+ throws BuildException {
+ int cOptions = getCompilerOptions(options);
+ try {
+ Pattern p = Pattern.compile(this.pattern, cOptions);
+ return p;
+ } catch (PatternSyntaxException e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * Does the given argument match the pattern using default options?
+ * @param argument the string to match against
+ * @return true if the pattern matches
+ * @throws BuildException on error
+ */
+ public boolean matches(String argument) throws BuildException {
+ return matches(argument, MATCH_DEFAULT);
+ }
+
+ /**
+ * Does the given argument match the pattern?
+ * @param input the string to match against
+ * @param options the regex options to use
+ * @return true if the pattern matches
+ * @throws BuildException on error
+ */
+ public boolean matches(String input, int options)
+ throws BuildException {
+ try {
+ Pattern p = getCompiledPattern(options);
+ return p.matcher(input).find();
+ } catch (Exception e) {
+ throw new BuildException(e);
+ }
+ }
+
+ /**
+ * Returns a Vector of matched groups found in the argument
+ * using default options.
+ *
+ * <p>Group 0 will be the full match, the rest are the
+ * parenthesized subexpressions</p>.
+ *
+ * @param argument the string to match against
+ * @return the vector of groups
+ * @throws BuildException on error
+ */
+ public Vector getGroups(String argument) throws BuildException {
+ return getGroups(argument, MATCH_DEFAULT);
+ }
+
+ /**
+ * Returns a Vector of matched groups found in the argument.
+ *
+ * <p>Group 0 will be the full match, the rest are the
+ * parenthesized subexpressions</p>.
+ *
+ * @param input the string to match against
+ * @param options the regex options to use
+ * @return the vector of groups
+ * @throws BuildException on error
+ */
+ public Vector getGroups(String input, int options)
+ throws BuildException {
+ Pattern p = getCompiledPattern(options);
+ Matcher matcher = p.matcher(input);
+ if (!matcher.find()) {
+ return null;
+ }
+ Vector v = new Vector();
+ int cnt = matcher.groupCount();
+ for (int i = 0; i <= cnt; i++) {
+ String match = matcher.group(i);
+ // treat non-matching groups as empty matches
+ if (match == null) {
+ match = "";
+ }
+ v.addElement(match);
+ }
+ return v;
+ }
+
+ /**
+ * Convert the generic options to the regex compiler specific options.
+ * @param options the generic options
+ * @return the specific options
+ */
+ protected int getCompilerOptions(int options) {
+ // be strict about line separator
+ int cOptions = Pattern.UNIX_LINES;
+
+ if (RegexpUtil.hasFlag(options, MATCH_CASE_INSENSITIVE)) {
+ cOptions |= Pattern.CASE_INSENSITIVE;
+ }
+ if (RegexpUtil.hasFlag(options, MATCH_MULTILINE)) {
+ cOptions |= Pattern.MULTILINE;
+ }
+ if (RegexpUtil.hasFlag(options, MATCH_SINGLELINE)) {
+ cOptions |= Pattern.DOTALL;
+ }
+
+ return cOptions;
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexp.java
new file mode 100644
index 00000000..3ca80706
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Jdk14RegexpRegexp.java
@@ -0,0 +1,105 @@
+/*
+ * 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.util.regexp;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.tools.ant.BuildException;
+
+/***
+ * Regular expression implementation using the JDK 1.4 regular expression package
+ */
+public class Jdk14RegexpRegexp extends Jdk14RegexpMatcher implements Regexp {
+
+ private static final int DECIMAL = 10;
+
+ /** Constructor for Jdk14RegexpRegexp */
+ public Jdk14RegexpRegexp() {
+ super();
+ }
+
+ /**
+ * Convert ant regexp substitution option to jdk1.4 options.
+ *
+ * @param options the ant regexp options
+ * @return the jdk14 substition options
+ */
+ protected int getSubsOptions(int options) {
+ int subsOptions = REPLACE_FIRST;
+ if (RegexpUtil.hasFlag(options, REPLACE_ALL)) {
+ subsOptions = REPLACE_ALL;
+ }
+ return subsOptions;
+ }
+
+ /**
+ * Perform a substitution on the regular expression.
+ * @param input The string to substitute on
+ * @param argument The string which defines the substitution
+ * @param options The list of options for the match and replace.
+ * @return the result of the operation
+ * @throws BuildException on error
+ */
+ public String substitute(String input, String argument, int options)
+ throws BuildException {
+ // translate \1 to $(1) so that the Matcher will work
+ StringBuffer subst = new StringBuffer();
+ for (int i = 0; i < argument.length(); i++) {
+ char c = argument.charAt(i);
+ if (c == '$') {
+ subst.append('\\');
+ subst.append('$');
+ } else if (c == '\\') {
+ if (++i < argument.length()) {
+ c = argument.charAt(i);
+ int value = Character.digit(c, DECIMAL);
+ if (value > -1) {
+ subst.append("$").append(value);
+ } else {
+ subst.append(c);
+ }
+ } else {
+ // TODO - should throw an exception instead?
+ subst.append('\\');
+ }
+ } else {
+ subst.append(c);
+ }
+ }
+ argument = subst.toString();
+
+ int sOptions = getSubsOptions(options);
+ Pattern p = getCompiledPattern(options);
+ StringBuffer sb = new StringBuffer();
+
+ Matcher m = p.matcher(input);
+ if (RegexpUtil.hasFlag(sOptions, REPLACE_ALL)) {
+ sb.append(m.replaceAll(argument));
+ } else {
+ boolean res = m.find();
+ if (res) {
+ m.appendReplacement(sb, argument);
+ m.appendTail(sb);
+ } else {
+ sb.append(input);
+ }
+ }
+ return sb.toString();
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Regexp.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Regexp.java
new file mode 100644
index 00000000..1c7816a1
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/Regexp.java
@@ -0,0 +1,50 @@
+/*
+ * 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.util.regexp;
+
+import org.apache.tools.ant.BuildException;
+
+/***
+ * Interface which represents a regular expression, and the operations
+ * that can be performed on it.
+ *
+ */
+public interface Regexp extends RegexpMatcher {
+
+ /**
+ * Replace only the first occurrence of the regular expression
+ */
+ int REPLACE_FIRST = 0x00000001;
+
+ /**
+ * Replace all occurrences of the regular expression
+ */
+ int REPLACE_ALL = 0x00000010;
+
+ /**
+ * Perform a substitution on the regular expression.
+ * @param input The string to substitute on
+ * @param argument The string which defines the substitution
+ * @param options The list of options for the match and replace. See the
+ * MATCH_ and REPLACE_ constants above.
+ * @return the result of the operation
+ * @throws BuildException on error
+ */
+ String substitute(String input, String argument, int options)
+ throws BuildException;
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpFactory.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpFactory.java
new file mode 100644
index 00000000..7077a216
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpFactory.java
@@ -0,0 +1,85 @@
+/*
+ * 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.util.regexp;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.ClasspathUtils;
+
+/***
+ * Regular expression factory, which will create Regexp objects. The
+ * actual implementation class depends on the System or Ant Property:
+ * <code>ant.regexp.regexpimpl</code>.
+ *
+ */
+public class RegexpFactory extends RegexpMatcherFactory {
+
+ /** Constructor for RegexpFactory */
+ public RegexpFactory() {
+ }
+
+ /***
+ * Create a new regular expression matcher instance.
+ * @return the matcher instance
+ * @throws BuildException on error
+ */
+ public Regexp newRegexp() throws BuildException {
+ return newRegexp(null);
+ }
+
+ /***
+ * Create a new regular expression matcher instance.
+ *
+ * @param p Project whose ant.regexp.regexpimpl property will be used.
+ * @return the matcher instance
+ * @throws BuildException on error
+ */
+ public Regexp newRegexp(Project p) throws BuildException {
+ String systemDefault = null;
+ if (p == null) {
+ systemDefault = System.getProperty(MagicNames.REGEXP_IMPL);
+ } else {
+ systemDefault = p.getProperty(MagicNames.REGEXP_IMPL);
+ }
+
+ if (systemDefault != null) {
+ return createRegexpInstance(systemDefault);
+ // TODO should we silently catch possible exceptions and try to
+ // load a different implementation?
+ }
+
+ return new Jdk14RegexpRegexp();
+ }
+
+ /**
+ * Wrapper over RegexpMatcherFactory.createInstance that ensures that
+ * we are dealing with a Regexp implementation.
+ * @param classname the name of the class to use.
+ * @return the instance.
+ * @throws BuildException if there is a problem.
+ * @since 1.3
+ *
+ * @see RegexpMatcherFactory#createInstance(String)
+ */
+ protected Regexp createRegexpInstance(String classname) throws BuildException {
+ return (Regexp) ClasspathUtils.newInstance(classname, RegexpFactory.class.getClassLoader(),
+ Regexp.class);
+ }
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpMatcher.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpMatcher.java
new file mode 100644
index 00000000..7938d8be
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpMatcher.java
@@ -0,0 +1,110 @@
+/*
+ * 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.util.regexp;
+
+import java.util.Vector;
+
+import org.apache.tools.ant.BuildException;
+
+/**
+ * Interface describing a regular expression matcher.
+ *
+ */
+public interface RegexpMatcher {
+
+ /***
+ * Default Mask (case insensitive, neither multiline nor
+ * singleline specified).
+ */
+ int MATCH_DEFAULT = 0x00000000;
+
+ /***
+ * Perform a case insensitive match
+ */
+ int MATCH_CASE_INSENSITIVE = 0x00000100;
+
+ /***
+ * Treat the input as a multiline input
+ */
+ int MATCH_MULTILINE = 0x00001000;
+
+ /***
+ * Treat the input as singleline input ('.' matches newline)
+ */
+ int MATCH_SINGLELINE = 0x00010000;
+
+
+ /**
+ * Set the regexp pattern from the String description.
+ * @param pattern the pattern to match
+ * @throws BuildException on error
+ */
+ void setPattern(String pattern) throws BuildException;
+
+ /**
+ * Get a String representation of the regexp pattern
+ * @return the pattern
+ * @throws BuildException on error
+ */
+ String getPattern() throws BuildException;
+
+ /**
+ * Does the given argument match the pattern?
+ * @param argument the string to match against
+ * @return true if the pattern matches
+ * @throws BuildException on error
+ */
+ boolean matches(String argument) throws BuildException;
+
+ /**
+ * Returns a Vector of matched groups found in the argument
+ * using default options.
+ *
+ * <p>Group 0 will be the full match, the rest are the
+ * parenthesized subexpressions</p>.
+ *
+ * @param argument the string to match against
+ * @return the vector of groups
+ * @throws BuildException on error
+ */
+ Vector getGroups(String argument) throws BuildException;
+
+ /***
+ * Does this regular expression match the input, given
+ * certain options
+ * @param input The string to check for a match
+ * @param options The list of options for the match. See the
+ * MATCH_ constants above.
+ * @return true if the pattern matches
+ * @throws BuildException on error
+ */
+ boolean matches(String input, int options) throws BuildException;
+
+ /***
+ * Get the match groups from this regular expression. The return
+ * type of the elements is always String.
+ * @param input The string to check for a match
+ * @param options The list of options for the match. See the
+ * MATCH_ constants above.
+ * @return the vector of groups
+ * @throws BuildException on error
+ */
+ Vector getGroups(String input, int options) throws BuildException;
+
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpMatcherFactory.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpMatcherFactory.java
new file mode 100644
index 00000000..a0a8a155
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpMatcherFactory.java
@@ -0,0 +1,114 @@
+/*
+ * 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.util.regexp;
+
+import org.apache.tools.ant.BuildException;
+import org.apache.tools.ant.MagicNames;
+import org.apache.tools.ant.Project;
+import org.apache.tools.ant.util.ClasspathUtils;
+
+/**
+ * Simple Factory Class that produces an implementation of RegexpMatcher based on the system
+ * property <code>ant.regexp.regexpimpl</code> and the classes available.
+ *
+ * <p>
+ * In a more general framework this class would be abstract and have a static newInstance method.
+ * </p>
+ *
+ */
+public class RegexpMatcherFactory {
+
+ /** Constructor for RegexpMatcherFactory. */
+ public RegexpMatcherFactory() {
+ }
+
+ /***
+ * Create a new regular expression instance.
+ * @return the matcher
+ * @throws BuildException on error
+ */
+ public RegexpMatcher newRegexpMatcher() throws BuildException {
+ return newRegexpMatcher(null);
+ }
+
+ /***
+ * Create a new regular expression instance.
+ *
+ * @param p Project whose ant.regexp.regexpimpl property will be used.
+ * @return the matcher
+ * @throws BuildException on error
+ */
+ public RegexpMatcher newRegexpMatcher(Project p) throws BuildException {
+ String systemDefault = null;
+ if (p == null) {
+ systemDefault = System.getProperty(MagicNames.REGEXP_IMPL);
+ } else {
+ systemDefault = p.getProperty(MagicNames.REGEXP_IMPL);
+ }
+
+ if (systemDefault != null) {
+ return createInstance(systemDefault);
+ // TODO should we silently catch possible exceptions and try to
+ // load a different implementation?
+ }
+
+ return new Jdk14RegexpMatcher();
+ }
+
+ /**
+ * Create an instance of a matcher from a classname.
+ *
+ * @param className a <code>String</code> value
+ * @return a <code>RegexpMatcher</code> value
+ * @exception BuildException if an error occurs
+ */
+ protected RegexpMatcher createInstance(String className) throws BuildException {
+ return (RegexpMatcher) ClasspathUtils.newInstance(className, RegexpMatcherFactory.class
+ .getClassLoader(), RegexpMatcher.class);
+ }
+
+ /**
+ * Test if a particular class is available to be used.
+ *
+ * @param className a <code>String</code> value
+ * @exception BuildException if an error occurs
+ */
+ protected void testAvailability(String className) throws BuildException {
+ try {
+ Class.forName(className);
+ } catch (Throwable t) {
+ throw new BuildException(t);
+ }
+ }
+
+ /**
+ * Checks if a RegExp-Matcher is available.
+ * @param project The project to check for (may be <code>null</code>)
+ * @return <code>true</code> if available otherwise <code>false</code>
+ */
+ public static boolean regexpMatcherPresent(Project project) {
+ try {
+ // The factory throws a BuildException if no usable matcher
+ // cannot be instantiated. We dont need the matcher itself here.
+ new RegexpMatcherFactory().newRegexpMatcher(project);
+ return true;
+ } catch (Throwable ex) {
+ return false;
+ }
+ }
+}
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpUtil.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpUtil.java
new file mode 100644
index 00000000..ebd85fab
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util/regexp/RegexpUtil.java
@@ -0,0 +1,109 @@
+/*
+ * 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.util.regexp;
+
+// CheckStyle:HideUtilityClassConstructorCheck OFF - bc
+
+/***
+ * Regular expression utilities class which handles flag operations.
+ *
+ */
+public class RegexpUtil {
+
+ /**
+ * Check the options has a particular flag set.
+ *
+ * @param options an <code>int</code> value
+ * @param flag an <code>int</code> value
+ * @return true if the flag is set
+ */
+ public static boolean hasFlag(int options, int flag) {
+ return ((options & flag) > 0);
+ }
+
+ /**
+ * Remove a particular flag from an int value contains the option flags.
+ *
+ * @param options an <code>int</code> value
+ * @param flag an <code>int</code> value
+ * @return the options with the flag unset
+ */
+ public static int removeFlag(int options, int flag) {
+ return (options & (0xFFFFFFFF - flag));
+ }
+
+ /**
+ * convert regex option flag characters to regex options
+ * <dl>
+ * <li>g - Regexp.REPLACE_ALL</li>
+ * <li>i - RegexpMatcher.MATCH_CASE_INSENSITIVE</li>
+ * <li>m - RegexpMatcher.MATCH_MULTILINE</li>
+ * <li>s - RegexpMatcher.MATCH_SINGLELINE</li>
+ * </dl>
+ * @param flags the string containing the flags
+ * @return the Regexp option bits
+ * @since Ant 1.8.2
+ */
+ public static int asOptions(String flags) {
+ int options = RegexpMatcher.MATCH_DEFAULT;
+ if (flags != null) {
+ options = asOptions(flags.indexOf('i') == -1,
+ flags.indexOf('m') != -1,
+ flags.indexOf('s') != -1);
+ if (flags.indexOf('g') != -1) {
+ options |= Regexp.REPLACE_ALL;
+ }
+ }
+ return options;
+ }
+
+ /**
+ * Convert flag to regex options.
+ *
+ * @param caseSensitive opposite of RegexpMatcher.MATCH_CASE_INSENSITIVE
+ * @return the Regexp option bits
+ * @since Ant 1.8.2
+ */
+ public static int asOptions(boolean caseSensitive) {
+ return asOptions(caseSensitive, false, false);
+ }
+
+ /**
+ * Convert flags to regex options.
+ *
+ * @param caseSensitive opposite of RegexpMatcher.MATCH_CASE_INSENSITIVE
+ * @param multiLine RegexpMatcher.MATCH_MULTILINE
+ * @param singleLine RegexpMatcher.MATCH_SINGLELINE
+ * @return the Regexp option bits
+ * @since Ant 1.8.2
+ */
+ public static int asOptions(boolean caseSensitive, boolean multiLine,
+ boolean singleLine) {
+ int options = RegexpMatcher.MATCH_DEFAULT;
+ if (!caseSensitive) {
+ options = options | RegexpMatcher.MATCH_CASE_INSENSITIVE;
+ }
+ if (multiLine) {
+ options = options | RegexpMatcher.MATCH_MULTILINE;
+ }
+ if (singleLine) {
+ options = options | RegexpMatcher.MATCH_SINGLELINE;
+ }
+ return options;
+ }
+}