diff --git a/src/main/org/apache/tools/ant/FileUtils.java b/src/main/org/apache/tools/ant/FileUtils.java
new file mode 100644
index 000000000..66b2f2c27
--- /dev/null
+++ b/src/main/org/apache/tools/ant/FileUtils.java
@@ -0,0 +1,271 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ *
+ * This class also encapsulates methods which allow Files to be refered
+ * to using abstract path names which are translated to native system
+ * file paths at runtime as well as defining various project properties.
+ *
+ * @author duncan@x180.com
+ * @author Conor MacNeill
+ */
+
+public class FileUtils {
+ private static Object lockReflection = new Object();
+ private static java.lang.reflect.Method setLastModified = null;
+
+ /**
+ * Convienence method to copy a file from a source to a destination.
+ * No filtering is performed.
+ *
+ * @throws IOException
+ */
+ public static void copyFile(String sourceFile, String destFile) throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), null, false, false);
+ }
+
+ /**
+ * Convienence method to copy a file from a source to a destination
+ * specifying if token filtering must be used.
+ *
+ * @throws IOException
+ */
+ public static void copyFile(String sourceFile, String destFile, FilterSet filterSet)
+ throws IOException
+ {
+ copyFile(new File(sourceFile), new File(destFile), filterSet, false, false);
+ }
+
+ /**
+ * Convienence 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.
+ *
+ * @throws IOException
+ */
+ public static void copyFile(String sourceFile, String destFile, FilterSet filterSet,
+ boolean overwrite) throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), filterSet,
+ overwrite, false);
+ }
+
+ /**
+ * Convienence 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 destFile
file should be made equal
+ * to the last modified time of sourceFile
.
+ *
+ * @throws IOException
+ */
+ public static void copyFile(String sourceFile, String destFile, FilterSet filterSet,
+ boolean overwrite, boolean preserveLastModified)
+ throws IOException {
+ copyFile(new File(sourceFile), new File(destFile), filterSet,
+ overwrite, preserveLastModified);
+ }
+
+ /**
+ * Convienence method to copy a file from a source to a destination.
+ * No filtering is performed.
+ *
+ * @throws IOException
+ */
+ public static void copyFile(File sourceFile, File destFile) throws IOException {
+ copyFile(sourceFile, destFile, null, false, false);
+ }
+
+ /**
+ * Convienence method to copy a file from a source to a destination
+ * specifying if token filtering must be used.
+ *
+ * @throws IOException
+ */
+ public static void copyFile(File sourceFile, File destFile, FilterSet filterSet)
+ throws IOException {
+ copyFile(sourceFile, destFile, filterSet, false, false);
+ }
+
+ /**
+ * Convienence 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.
+ *
+ * @throws IOException
+ */
+ public static void copyFile(File sourceFile, File destFile, FilterSet filterSet,
+ boolean overwrite) throws IOException {
+ copyFile(sourceFile, destFile, filterSet, overwrite, false);
+ }
+
+ /**
+ * Convienence 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 destFile
file should be made equal
+ * to the last modified time of sourceFile
.
+ *
+ * @throws IOException
+ */
+ public static void copyFile(File sourceFile, File destFile, FilterSet filterSet,
+ boolean overwrite, boolean preserveLastModified)
+ throws IOException {
+
+ if (overwrite || !destFile.exists() ||
+ destFile.lastModified() < sourceFile.lastModified()) {
+
+ if (destFile.exists() && destFile.isFile()) {
+ destFile.delete();
+ }
+
+ // ensure that parent dir of dest file exists!
+ // not using getParentFile method to stay 1.1 compat
+ File parent = new File(destFile.getParent());
+ if (!parent.exists()) {
+ parent.mkdirs();
+ }
+
+ if (filterSet != null) {
+ BufferedReader in = new BufferedReader(new FileReader(sourceFile));
+ BufferedWriter out = new BufferedWriter(new FileWriter(destFile));
+
+ int length;
+ String newline = null;
+ String line = in.readLine();
+ while (line != null) {
+ if (line.length() == 0) {
+ out.newLine();
+ } else {
+ newline = filterSet.replaceTokens(line);
+ out.write(newline);
+ out.newLine();
+ }
+ line = in.readLine();
+ }
+
+ out.close();
+ in.close();
+ } else {
+ FileInputStream in = new FileInputStream(sourceFile);
+ FileOutputStream out = new FileOutputStream(destFile);
+
+ byte[] buffer = new byte[8 * 1024];
+ int count = 0;
+ do {
+ out.write(buffer, 0, count);
+ count = in.read(buffer, 0, buffer.length);
+ } while (count != -1);
+
+ in.close();
+ out.close();
+ }
+
+ if (preserveLastModified) {
+ setFileLastModified(destFile, sourceFile.lastModified());
+ }
+ }
+ }
+
+ /**
+ * Calls File.setLastModified(long time) in a Java 1.1 compatible way.
+ */
+ public static void setFileLastModified(File file, long time) throws BuildException {
+ if (Project.getJavaVersion() == Project.JAVA_1_1) {
+ return;
+ }
+ if (setLastModified == null) {
+ synchronized (lockReflection) {
+ if (setLastModified == null) {
+ try {
+ setLastModified =
+ java.io.File.class.getMethod("setLastModified",
+ new Class[] {Long.TYPE});
+ } catch (NoSuchMethodException nse) {
+ throw new BuildException("File.setlastModified not in JDK > 1.1?",
+ nse);
+ }
+ }
+ }
+ }
+ Long[] times = new Long[1];
+ if (time < 0) {
+ times[0] = new Long(System.currentTimeMillis());
+ } else {
+ times[0] = new Long(time);
+ }
+ try {
+ setLastModified.invoke(file, times);
+ } catch (java.lang.reflect.InvocationTargetException ite) {
+ Throwable nested = ite.getTargetException();
+ throw new BuildException("Exception setting the modification time "
+ + "of " + file, nested);
+ } catch (Throwable other) {
+ throw new BuildException("Exception setting the modification time "
+ + "of " + file, other);
+ }
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/Project.java b/src/main/org/apache/tools/ant/Project.java
index 1039738e6..88ba00e9a 100644
--- a/src/main/org/apache/tools/ant/Project.java
+++ b/src/main/org/apache/tools/ant/Project.java
@@ -58,6 +58,8 @@ import java.io.*;
import java.util.*;
import java.text.*;
+import org.apache.tools.ant.types.FilterSet;
+
/**
* Central representation of an Ant project. This class defines a
* Ant project with all of it's targets and tasks. It also provides
@@ -91,8 +93,8 @@ public class Project {
public static final String JAVA_1_3 = "1.3";
public static final String JAVA_1_4 = "1.4";
- public static final String TOKEN_START = "@";
- public static final String TOKEN_END = "@";
+ public static final String TOKEN_START = FilterSet.DEFAULT_TOKEN_START;
+ public static final String TOKEN_END = FilterSet.DEFAULT_TOKEN_END;
private String name;
@@ -103,14 +105,11 @@ public class Project {
private Hashtable dataClassDefinitions = new Hashtable();
private Hashtable taskClassDefinitions = new Hashtable();
private Hashtable targets = new Hashtable();
- private Hashtable filters = new Hashtable();
+ private FilterSet globalFilterSet = new FilterSet();
private File baseDir;
private Vector listeners = new Vector();
- private static java.lang.reflect.Method setLastModified = null;
- private static Object lockReflection = new Object();
-
/** The system classloader - may be null */
private ClassLoader systemLoader = null;
@@ -254,6 +253,12 @@ public class Project {
fireMessageLogged(target, msg, msgLevel);
}
+
+ public FilterSet getGlobalFilterSet() {
+ return globalFilterSet;
+ }
+
+
public void setProperty(String name, String value) {
// command line properties take precedence
if (null != userProperties.get(name)) {
@@ -315,15 +320,19 @@ public class Project {
return name;
}
+ /** @deprecated */
public void addFilter(String token, String value) {
- if (token == null) return;
- log("Setting token to filter: " + token + " -> "
- + value, MSG_DEBUG);
- this.filters.put(token, value);
+ if (token == null) {
+ return;
+ }
+
+ globalFilterSet.addFilter(new FilterSet.Filter(token, value));
}
+ /** @deprecated */
public Hashtable getFilters() {
- return filters;
+ // we need to build the hashtable dynamically
+ return globalFilterSet.getFilterHash();
}
// match basedir attribute in xml
@@ -505,6 +514,9 @@ public class Project {
} else {
o = ctor.newInstance(new Object[] {this});
}
+ if (o instanceof ProjectComponent) {
+ ((ProjectComponent)o).setProject(this);
+ }
String msg = " +DataType: " + typeName;
log (msg, MSG_DEBUG);
return o;
@@ -674,9 +686,11 @@ public class Project {
* No filtering is performed.
*
* @throws IOException
+ *
+ * @deprecated
*/
public void copyFile(String sourceFile, String destFile) throws IOException {
- copyFile(new File(sourceFile), new File(destFile), false);
+ FileUtils.copyFile(sourceFile, destFile);
}
/**
@@ -686,9 +700,8 @@ public class Project {
* @throws IOException
*/
public void copyFile(String sourceFile, String destFile, boolean filtering)
- throws IOException
- {
- copyFile(new File(sourceFile), new File(destFile), filtering);
+ throws IOException {
+ FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null);
}
/**
@@ -700,8 +713,7 @@ public class Project {
*/
public void copyFile(String sourceFile, String destFile, boolean filtering,
boolean overwrite) throws IOException {
- copyFile(new File(sourceFile), new File(destFile), filtering,
- overwrite);
+ FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null, overwrite);
}
/**
@@ -716,8 +728,8 @@ public class Project {
public void copyFile(String sourceFile, String destFile, boolean filtering,
boolean overwrite, boolean preserveLastModified)
throws IOException {
- copyFile(new File(sourceFile), new File(destFile), filtering,
- overwrite, preserveLastModified);
+ FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null,
+ overwrite, preserveLastModified);
}
/**
@@ -727,7 +739,7 @@ public class Project {
* @throws IOException
*/
public void copyFile(File sourceFile, File destFile) throws IOException {
- copyFile(sourceFile, destFile, false);
+ FileUtils.copyFile(sourceFile, destFile);
}
/**
@@ -738,7 +750,7 @@ public class Project {
*/
public void copyFile(File sourceFile, File destFile, boolean filtering)
throws IOException {
- copyFile(sourceFile, destFile, filtering, false);
+ FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null);
}
/**
@@ -750,7 +762,7 @@ public class Project {
*/
public void copyFile(File sourceFile, File destFile, boolean filtering,
boolean overwrite) throws IOException {
- copyFile(sourceFile, destFile, filtering, overwrite, false);
+ FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null, overwrite);
}
/**
@@ -765,63 +777,8 @@ public class Project {
public void copyFile(File sourceFile, File destFile, boolean filtering,
boolean overwrite, boolean preserveLastModified)
throws IOException {
-
- if (overwrite || !destFile.exists() ||
- destFile.lastModified() < sourceFile.lastModified()) {
-
- if (destFile.exists() && destFile.isFile()) {
- destFile.delete();
- }
-
- log("Copy: " + sourceFile.getAbsolutePath() + " -> "
- + destFile.getAbsolutePath(), MSG_VERBOSE);
-
- // ensure that parent dir of dest file exists!
- // not using getParentFile method to stay 1.1 compat
- File parent = new File(destFile.getParent());
- if (!parent.exists()) {
- parent.mkdirs();
- }
-
- if (filtering) {
- BufferedReader in = new BufferedReader(new FileReader(sourceFile));
- BufferedWriter out = new BufferedWriter(new FileWriter(destFile));
-
- int length;
- String newline = null;
- String line = in.readLine();
- while (line != null) {
- if (line.length() == 0) {
- out.newLine();
- } else {
- newline = replace(line, filters);
- out.write(newline);
- out.newLine();
- }
- line = in.readLine();
- }
-
- out.close();
- in.close();
- } else {
- FileInputStream in = new FileInputStream(sourceFile);
- FileOutputStream out = new FileOutputStream(destFile);
-
- byte[] buffer = new byte[8 * 1024];
- int count = 0;
- do {
- out.write(buffer, 0, count);
- count = in.read(buffer, 0, buffer.length);
- } while (count != -1);
-
- in.close();
- out.close();
- }
-
- if (preserveLastModified) {
- setFileLastModified(destFile, sourceFile.lastModified());
- }
- }
+ FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null,
+ overwrite, preserveLastModified);
}
/**
@@ -833,82 +790,8 @@ public class Project {
+ " in JDK 1.1", Project.MSG_WARN);
return;
}
- if (setLastModified == null) {
- synchronized (lockReflection) {
- if (setLastModified == null) {
- try {
- setLastModified =
- java.io.File.class.getMethod("setLastModified",
- new Class[] {Long.TYPE});
- } catch (NoSuchMethodException nse) {
- throw new BuildException("File.setlastModified not in JDK > 1.1?",
- nse);
- }
- }
- }
- }
- Long[] times = new Long[1];
- if (time < 0) {
- times[0] = new Long(System.currentTimeMillis());
- } else {
- times[0] = new Long(time);
- }
- try {
- log("Setting modification time for " + file, MSG_VERBOSE);
- setLastModified.invoke(file, times);
- } catch (java.lang.reflect.InvocationTargetException ite) {
- Throwable nested = ite.getTargetException();
- throw new BuildException("Exception setting the modification time "
- + "of " + file, nested);
- } catch (Throwable other) {
- throw new BuildException("Exception setting the modification time "
- + "of " + file, other);
- }
- }
-
- /**
- * Does replacement on the given string using the given token table.
- *
- * @returns the string with the token replaced.
- */
- private String replace(String s, Hashtable tokens) {
- int index = s.indexOf(TOKEN_START);
-
- if (index > -1) {
- try {
- StringBuffer b = new StringBuffer();
- int i = 0;
- String token = null;
- String value = null;
-
- do {
- int endIndex = s.indexOf(TOKEN_END,
- index + TOKEN_START.length() + 1);
- if (endIndex == -1) {
- break;
- }
- token = s.substring(index + TOKEN_START.length(), endIndex);
- b.append(s.substring(i, index));
- if (tokens.containsKey(token)) {
- value = (String) tokens.get(token);
- log("Replacing: " + TOKEN_START + token + TOKEN_END + " -> " + value, MSG_VERBOSE);
- b.append(value);
- i = index + TOKEN_START.length() + token.length() + TOKEN_END.length();
- } else {
- // just append TOKEN_START and search further
- b.append(TOKEN_START);
- i = index + TOKEN_START.length();
- }
- } while ((index = s.indexOf(TOKEN_START, i)) > -1);
-
- b.append(s.substring(i));
- return b.toString();
- } catch (StringIndexOutOfBoundsException e) {
- return s;
- }
- } else {
- return s;
- }
+ FileUtils.setFileLastModified(file, time);
+ log("Setting modification time for " + file, MSG_VERBOSE);
}
/**
diff --git a/src/main/org/apache/tools/ant/taskdefs/Copy.java b/src/main/org/apache/tools/ant/taskdefs/Copy.java
index 673ccd00a..1ea6a6e9e 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Copy.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Copy.java
@@ -73,6 +73,7 @@ import java.util.*;
*
* @author Glenn McAllister glennm@ca.ibm.com
* @author Stefan Bodewig
+ * @author Michael McCallum
*/
public class Copy extends Task {
protected File file = null; // the source file
@@ -91,7 +92,8 @@ public class Copy extends Task {
protected Hashtable dirCopyMap = new Hashtable();
protected Mapper mapperElement = null;
-
+ private Vector filterSets = new Vector();
+
/**
* Sets a single source file to copy.
*/
@@ -113,6 +115,15 @@ public class Copy extends Task {
this.destDir = destDir;
}
+ /**
+ * Create a nested filterset
+ */
+ public FilterSet createFilterSet() {
+ FilterSet filterSet = new FilterSet();
+ filterSets.addElement(filterSet);
+ return filterSet;
+ }
+
/**
* Give the copied files the same last modified time as the original files.
*/
@@ -120,6 +131,15 @@ public class Copy extends Task {
preserveLastModified = Project.toBoolean(preserve);
}
+ /**
+ * Get the filtersets being applied to this operation.
+ *
+ * @return a vector of FilterSet objects
+ */
+ protected Vector getFilterSets() {
+ return filterSets;
+ }
+
/**
* Sets filtering.
*/
@@ -338,11 +358,15 @@ public class Copy extends Task {
try {
log("Copying " + fromFile + " to " + toFile, verbosity);
- project.copyFile(fromFile,
- toFile,
- filtering,
- forceOverwrite,
- preserveLastModified);
+ FilterSet executionFilterSet = new FilterSet();
+ if (filtering) {
+ executionFilterSet.addFilterSet(project.getGlobalFilterSet());
+ }
+ for (Enumeration filterEnum = filterSets.elements(); filterEnum.hasMoreElements();) {
+ executionFilterSet.addFilterSet((FilterSet)filterEnum.nextElement());
+ }
+ FileUtils.copyFile(fromFile, toFile, executionFilterSet,
+ forceOverwrite, preserveLastModified);
} catch (IOException ioe) {
String msg = "Failed to copy " + fromFile + " to " + toFile
+ " due to " + ioe.getMessage();
diff --git a/src/main/org/apache/tools/ant/taskdefs/Move.java b/src/main/org/apache/tools/ant/taskdefs/Move.java
index 30504618f..ec3715580 100644
--- a/src/main/org/apache/tools/ant/taskdefs/Move.java
+++ b/src/main/org/apache/tools/ant/taskdefs/Move.java
@@ -100,7 +100,17 @@ public class Move extends Copy {
try {
log("Moving " + fromFile + " to " + toFile, verbosity);
- project.copyFile(fromFile, toFile, filtering, forceOverwrite);
+
+ FilterSet executionFilterSet = new FilterSet();
+ if (filtering) {
+ executionFilterSet.addFilterSet(project.getGlobalFilterSet());
+ }
+ for (Enumeration filterEnum = getFilterSets().elements(); filterEnum.hasMoreElements();) {
+ executionFilterSet.addFilterSet((FilterSet)filterEnum.nextElement());
+ }
+ FileUtils.copyFile(fromFile, toFile, executionFilterSet,
+ forceOverwrite);
+
File f = new File(fromFile);
if (!f.delete()) {
throw new BuildException("Unable to delete file " + f.getAbsolutePath());
diff --git a/src/main/org/apache/tools/ant/types/FilterSet.java b/src/main/org/apache/tools/ant/types/FilterSet.java
new file mode 100644
index 000000000..67ff8d8c0
--- /dev/null
+++ b/src/main/org/apache/tools/ant/types/FilterSet.java
@@ -0,0 +1,417 @@
+/*
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 1999 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution, if
+ * any, must include the following acknowlegement:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowlegement may appear in the software itself,
+ * if and wherever such third-party acknowlegements normally appear.
+ *
+ * 4. The names "The Jakarta Project", "Ant", and "Apache Software
+ * Foundation" must not be used to endorse or promote products derived
+ * from this software without prior written permission. For written
+ * permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ *