patch from PR1545. There is also more to come. PR: 1545 Submitted by: Michael McCallum <gholam@xtra.co.nz> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269459 13f79535-47bb-0310-9956-ffa450edef68master
@@ -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 | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.ant; | |||
import java.io.*; | |||
import java.util.*; | |||
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 | |||
* the mechanism to kick off a build using a particular target name. | |||
* <p> | |||
* 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 <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||
*/ | |||
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 <code>destFile</code> file should be made equal | |||
* to the last modified time of <code>sourceFile</code>. | |||
* | |||
* @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 <code>destFile</code> file should be made equal | |||
* to the last modified time of <code>sourceFile</code>. | |||
* | |||
* @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); | |||
} | |||
} | |||
} | |||
@@ -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); | |||
} | |||
/** | |||
@@ -73,6 +73,7 @@ import java.util.*; | |||
* | |||
* @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com</a> | |||
* @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | |||
* @author <A href="gholam@xtra.co.nz">Michael McCallum</A> | |||
*/ | |||
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(); | |||
@@ -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()); | |||
@@ -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 | |||
* <http://www.apache.org/>. | |||
*/ | |||
package org.apache.tools.ant.types; | |||
// java io classes | |||
import java.io.File; | |||
import java.io.FileInputStream; | |||
import java.io.IOException; | |||
// java util classes | |||
import java.util.Enumeration; | |||
import java.util.Hashtable; | |||
import java.util.Properties; | |||
import java.util.Vector; | |||
// ant classes | |||
import org.apache.tools.ant.BuildException; | |||
import org.apache.tools.ant.Project; | |||
import org.apache.tools.ant.Task; | |||
/** | |||
* A set of filters to be applied to something. | |||
* | |||
* A filter set may have starttoken and endtokens defined. | |||
* | |||
* @author <A href="mailto:gholam@xtra.co.nz"> Michael McCallum </A> | |||
* @created 14 March 2001 | |||
*/ | |||
public class FilterSet extends DataType { | |||
/** | |||
* Individual filter component of filterset | |||
* | |||
* @author Michael McCallum | |||
* @created 14 March 2001 | |||
*/ | |||
public static class Filter { | |||
/** Token which will be replaced in the filter operation */ | |||
String token; | |||
/** The value which will replace the token in the filtering operation */ | |||
String value; | |||
/** | |||
* Constructor for the Filter object | |||
* | |||
* @param token The token which will be replaced when filtering | |||
* @param value The value which will replace the token when filtering | |||
*/ | |||
public Filter(String token, String value) { | |||
this.token = token; | |||
this.value = value; | |||
} | |||
/** | |||
* No argument conmstructor | |||
*/ | |||
public Filter() { | |||
} | |||
/** | |||
* Sets the Token attribute of the Filter object | |||
* | |||
* @param token The new Token value | |||
*/ | |||
public void setToken( String token ) { | |||
this.token = token; | |||
} | |||
/** | |||
* Sets the Value attribute of the Filter object | |||
* | |||
* @param value The new Value value | |||
*/ | |||
public void setValue( String value ) { | |||
this.value = value; | |||
} | |||
/** | |||
* Gets the Token attribute of the Filter object | |||
* | |||
* @return The Token value | |||
*/ | |||
public String getToken() { | |||
return token; | |||
} | |||
/** | |||
* Gets the Value attribute of the Filter object | |||
* | |||
* @return The Value value | |||
*/ | |||
public String getValue() { | |||
return value; | |||
} | |||
} | |||
/** | |||
* The filtersfile nested element. | |||
* | |||
* @author Michael McCallum | |||
* @created Thursday, April 19, 2001 | |||
*/ | |||
public class FiltersFile { | |||
/** | |||
* Constructor for the Filter object | |||
*/ | |||
public FiltersFile() { | |||
} | |||
/** | |||
* Sets the file from which filters will be read. | |||
* | |||
* @param file the file from which filters will be read. | |||
*/ | |||
public void setFile(File file) { | |||
readFiltersFromFile(file); | |||
} | |||
} | |||
/** The default token start string */ | |||
public static final String DEFAULT_TOKEN_START = "@"; | |||
/** The default token end string */ | |||
public static final String DEFAULT_TOKEN_END = "@"; | |||
private String startOftoken = DEFAULT_TOKEN_START; | |||
private String endOftoken = DEFAULT_TOKEN_END; | |||
/** | |||
* List of ordered filters and filter files. | |||
*/ | |||
private Vector filters = new Vector(); | |||
public FilterSet() { | |||
} | |||
/** | |||
* Create a Filterset from another filterset | |||
* | |||
* @param filterset the filterset upon which this filterset will be based. | |||
*/ | |||
protected FilterSet(FilterSet filterset) { | |||
super(); | |||
this.filters = (Vector)filterset.getFilters().clone(); | |||
} | |||
protected Vector getFilters() { | |||
if (isReference()) { | |||
return getRef().getFilters(); | |||
} | |||
return filters; | |||
} | |||
protected FilterSet getRef() { | |||
return (FilterSet)getCheckedRef(FilterSet.class, "filterset"); | |||
} | |||
/** | |||
* Gets the filter hash of the FilterSet. | |||
* | |||
* @return The hash of the tokens and values for quick lookup. | |||
*/ | |||
public Hashtable getFilterHash() { | |||
int filterSize = getFilters().size(); | |||
Hashtable filterHash = new Hashtable(filterSize); | |||
for (Enumeration e = getFilters().elements(); e.hasMoreElements();) { | |||
Filter filter = (Filter) e.nextElement(); | |||
filterHash.put(filter.getToken(), filter.getValue()); | |||
} | |||
return filterHash; | |||
} | |||
/** | |||
* set the file containing the filters for this filterset. | |||
* | |||
* @param filtersFile sets the filter fil to read filters for this filter set from. | |||
* @exception BuildException if there is a problem reading the filters | |||
*/ | |||
public void setFiltersfile(File filtersFile) throws BuildException { | |||
if (isReference()) { | |||
throw tooManyAttributes(); | |||
} | |||
readFiltersFromFile(filtersFile); | |||
} | |||
/** | |||
* The string used to id the beginning of a token. | |||
* | |||
* @param startOfToken The new Begintoken value | |||
*/ | |||
public void setBeginToken(String startOfToken) { | |||
if (isReference()) { | |||
throw tooManyAttributes(); | |||
} | |||
startOftoken = startOfToken; | |||
} | |||
/** | |||
* The string used to id the end of a token. | |||
* | |||
* @param endOfToken The new Endtoken value | |||
*/ | |||
public void setEndToken( String endOfToken ) { | |||
if (isReference()) { | |||
throw tooManyAttributes(); | |||
} | |||
endOftoken = endOfToken; | |||
} | |||
/** | |||
* Read the filters from the given file. | |||
* | |||
* @param filtersFile the file from which filters are read | |||
* @exception BuildException Throw a build exception when unable to read the | |||
* file. | |||
*/ | |||
public void readFiltersFromFile(File filtersFile) throws BuildException { | |||
if (filtersFile.isFile()) { | |||
log("Reading filters from " + filtersFile, Project.MSG_VERBOSE ); | |||
FileInputStream in = null; | |||
try { | |||
Properties props = new Properties(); | |||
in = new FileInputStream(filtersFile); | |||
props.load(in); | |||
Enumeration enum = props.propertyNames(); | |||
Vector filters = getFilters(); | |||
while (enum.hasMoreElements()) { | |||
String strPropName = (String) enum.nextElement(); | |||
String strValue = props.getProperty(strPropName); | |||
filters.addElement(new Filter(strPropName, strValue)); | |||
} | |||
} | |||
catch (Exception e) { | |||
throw new BuildException( "Could not read filters from file: " + filtersFile ); | |||
} | |||
finally { | |||
if ( in != null ) { | |||
try { | |||
in.close(); | |||
} | |||
catch (IOException ioex) { | |||
} | |||
} | |||
} | |||
} | |||
else { | |||
throw new BuildException( "Must specify a file not a directory in the filtersfile attribute:" + filtersFile ); | |||
} | |||
} | |||
/** | |||
* Does replacement on the given string with token matching. | |||
* This uses the defined starttoken and endtoken values which default to @ for both. | |||
* | |||
* @param line The line to process the tokens in. | |||
* @return The string with the tokens replaced. | |||
*/ | |||
public String replaceTokens(String line) { | |||
int index = line.indexOf(startOftoken); | |||
if (index > -1) { | |||
Hashtable tokens = getFilterHash(); | |||
try { | |||
StringBuffer b = new StringBuffer(); | |||
int i = 0; | |||
String token = null; | |||
String value = null; | |||
do { | |||
int endIndex = line.indexOf(endOftoken, index + startOftoken.length() + 1 ); | |||
if (endIndex == -1) { | |||
break; | |||
} | |||
token = line.substring(index + startOftoken.length(), endIndex ); | |||
b.append(line.substring(i, index)); | |||
if (tokens.containsKey(token)) { | |||
value = (String)tokens.get(token); | |||
log( "Replacing: " + startOftoken + token + endOftoken + " -> " + value, Project.MSG_VERBOSE ); | |||
b.append(value); | |||
i = index + startOftoken.length() + token.length() + endOftoken.length(); | |||
} | |||
else { | |||
// just append startOftoken and search further | |||
b.append(startOftoken); | |||
i = index + startOftoken.length(); | |||
} | |||
} while ((index = line.indexOf( startOftoken, i )) > -1 ); | |||
b.append(line.substring(i)); | |||
return b.toString(); | |||
} | |||
catch (StringIndexOutOfBoundsException e) { | |||
return line; | |||
} | |||
} | |||
else { | |||
return line; | |||
} | |||
} | |||
/** | |||
* Create a new filter | |||
* | |||
* @param the filter to be added | |||
*/ | |||
public void addFilter(Filter filter) { | |||
if (isReference()) { | |||
throw noChildrenAllowed(); | |||
} | |||
filters.addElement(filter); | |||
} | |||
/** | |||
* Create a new FiltersFile | |||
* | |||
* @return The filter that was created. | |||
*/ | |||
public FiltersFile createFiltersfile() { | |||
if (isReference()) { | |||
throw noChildrenAllowed(); | |||
} | |||
return new FiltersFile(); | |||
} | |||
/** | |||
* Add a new filter made from the given token and value. | |||
* | |||
* @param token The token for the new filter. | |||
* @param value The value for the new filter. | |||
*/ | |||
public void addFilter(String token, String value) { | |||
if (isReference()) { | |||
throw noChildrenAllowed(); | |||
} | |||
filters.addElement(new Filter(token, value)); | |||
} | |||
/** | |||
* Add a Filterset to this filter set | |||
* | |||
* @param filterSet the filterset to be added to this filterset | |||
*/ | |||
public void addFilterSet(FilterSet filterSet) { | |||
if (isReference()) { | |||
throw noChildrenAllowed(); | |||
} | |||
for (Enumeration e = filterSet.getFilters().elements(); e.hasMoreElements();) { | |||
filters.addElement((Filter)e.nextElement()); | |||
} | |||
} | |||
/** | |||
* Test to see if this filter set it empty. | |||
* | |||
* @return Return true if there are filter in this set otherwise false. | |||
*/ | |||
public boolean hasFilters() { | |||
return getFilters().size() > 0; | |||
} | |||
} | |||
@@ -2,3 +2,5 @@ path=org.apache.tools.ant.types.Path | |||
fileset=org.apache.tools.ant.types.FileSet | |||
patternset=org.apache.tools.ant.types.PatternSet | |||
mapper=org.apache.tools.ant.types.Mapper | |||
filterset=org.apache.tools.ant.types.FilterSet | |||