diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/util')
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 <classpath>} + * 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 <classpath> </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 <classpath> 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 <?xml version='1.0' encoding='UTF-8'?> 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 <, > & ', " 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 <, > & ', " 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("<"); + break; + case '>': + sb.append(">"); + break; + case '\'': + sb.append("'"); + break; + case '\"': + sb.append("""); + break; + case '&': + sb.append("&"); + 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>]]></code> + * marker by replacing that sequence with + * <code>&#x5d;&#x5d;&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>]]></code> + * marker by replacing that sequence with + * <code>&#x5d;&#x5d;&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><a></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(<a>, "b")</pre> + * creates + * <pre> + * <a> + * <b/> + * </a> + * </pre> + * and returns <code><b></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(<a>, "b")</pre> + * creates + * <pre> + * <a>b</a> + * </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(<a>, "b")</pre> + * creates + * <pre> + * <a><[!CDATA[b]]></a> + * </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(<a>, "b", "c")</pre> + * creates + * <pre> + * <a> + * <b>c</b> + * </a> + * </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(<a>, "b", "c")</pre> + * creates + * <pre> + * <a> + * <b><![CDATA[c]]></b> + * </a> + * </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 + * "./" or "../" 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(); + } + + /** + * "Normalize" 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 "normalize" 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 -> *.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 "from" pattern before the *. + */ + protected String fromPrefix = null; + + /** + * Part of "from" pattern after the *. + */ + protected String fromPostfix = null; + + /** + * Length of the prefix ("from" pattern). + */ + protected int prefixLength; + + /** + * Length of the postfix ("from" pattern). + */ + protected int postfixLength; + + /** + * Part of "to" pattern before the *. + */ + protected String toPrefix = null; + + /** + * Part of "to" 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 "from" 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 "to" 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 + * "from" 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 + * "from" 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 + * < 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 && 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 <= 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 "funnel" + * 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 "funnel" 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 "funnel" <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> + * <mapper classname="org.apache.tools.ant.util.PackageNameMapper" + * from="*Test.java" to="${test.data.dir}/TEST-*Test.xml"/> + * </pre> + * + */ +public class PackageNameMapper extends GlobPatternMapper { + /** + * Returns the part of the given string that matches the * in the + * "from" 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 "from" 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 "to" 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 + * "from" 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<-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, <script> 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 -> " \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> + * <mapper classname="org.apache.tools.ant.util.UnPackageNameMapper" + * from="${test.data.dir}/TEST-*Test.xml" to="*Test.java"> + * </pre> + * + * + */ +public class UnPackageNameMapper extends GlobPatternMapper { + /** + * Returns the part of the given string that matches the * in the + * "from" 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 >= 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 <=> 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 + * "root" 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; + } +} |