git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@292251 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -16,12 +16,16 @@ compatibility.</i></p> | |||||
| <p>Executes a system command. When the <i>os</i> attribute is specified, then | <p>Executes a system command. When the <i>os</i> attribute is specified, then | ||||
| the command is only executed when Ant is run on one of the specified operating | the command is only executed when Ant is run on one of the specified operating | ||||
| systems.</p> | systems.</p> | ||||
| <p>The files and/or directories of a number of | |||||
| <p>The files and/or directories of a number of <a | |||||
| href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
| – including but not restricted to | |||||
| <a href="../CoreTypes/fileset.html">FileSet</a>s, | <a href="../CoreTypes/fileset.html">FileSet</a>s, | ||||
| <a href="../CoreTypes/dirset.html">DirSet</a>s | <a href="../CoreTypes/dirset.html">DirSet</a>s | ||||
| (<em>since Ant 1.6</em>) or | (<em>since Ant 1.6</em>) or | ||||
| <a href="../CoreTypes/filelist.html">FileList</a>s | <a href="../CoreTypes/filelist.html">FileList</a>s | ||||
| (<em>since Ant 1.6</em>) | (<em>since Ant 1.6</em>) | ||||
| – | |||||
| are passed as arguments to the system command.</p> | are passed as arguments to the system command.</p> | ||||
| <p>If you specify a nested <a href="../CoreTypes/mapper.html">mapper</a>, | <p>If you specify a nested <a href="../CoreTypes/mapper.html">mapper</a>, | ||||
| the timestamp of each source file is compared to the timestamp of a | the timestamp of each source file is compared to the timestamp of a | ||||
| @@ -283,6 +287,12 @@ elements to define the files for this task and refer to | |||||
| <p>You can use any number of nested <code><dirset></code> | <p>You can use any number of nested <code><dirset></code> | ||||
| elements to define the directories for this task and refer to | elements to define the directories for this task and refer to | ||||
| <code><dirset></code>s defined elsewhere.</p> | <code><dirset></code>s defined elsewhere.</p> | ||||
| <h4>Any other <a href="../CoreTypes/resources.html#collection">Resource | |||||
| Collection</a></h4> | |||||
| <p><em>since Ant 1.7</em></p> | |||||
| <p>You can use any number of nested resource collections.</p> | |||||
| <h4>mapper</h4> | <h4>mapper</h4> | ||||
| <p>A single <code><mapper></code> specifies the target files relative | <p>A single <code><mapper></code> specifies the target files relative | ||||
| to the <code>dest</code> attribute for dependency checking. If the | to the <code>dest</code> attribute for dependency checking. If the | ||||
| @@ -385,6 +395,17 @@ task. A reference to <code>out</code> is then used as an | |||||
| <code><outputmapper></code> nested in a <code><redirector></code>, which in turn is | <code><outputmapper></code> nested in a <code><redirector></code>, which in turn is | ||||
| nested beneath this <code><apply></code> instance. This allows us to perform | nested beneath this <code><apply></code> instance. This allows us to perform | ||||
| dependency checking against output files--the target files in this case. | dependency checking against output files--the target files in this case. | ||||
| <blockquote><pre> | |||||
| <apply executable="ls" parallel="true" | |||||
| force="true" dest="${basedir}" append="true" type="both"> | |||||
| <path> | |||||
| <pathelement path="${env.PATH}"/> | |||||
| </path> | |||||
| <identitymapper/> | |||||
| </apply> | |||||
| </pre></blockquote> | |||||
| Applies the "ls" executable to all directories in the PATH, effectively | |||||
| listing all executables that are available on the PATH. | |||||
| <hr><p align="center">Copyright © 2000-2005 The Apache Software Foundation. All rights | <hr><p align="center">Copyright © 2000-2005 The Apache Software Foundation. All rights | ||||
| Reserved.</p> | Reserved.</p> | ||||
| @@ -26,6 +26,10 @@ specified using nested <code><fileset></code> or | |||||
| <p>Starting with Ant 1.6, this task also supports nested <a | <p>Starting with Ant 1.6, this task also supports nested <a | ||||
| href="../CoreTypes/filelist.html">filelist</a>s.</p> | href="../CoreTypes/filelist.html">filelist</a>s.</p> | ||||
| <p>Starting with Ant 1.7, this task supports arbitrary <a | |||||
| href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
| as nested elements.</p> | |||||
| <p>By default this task will use a single invocation of the underlying | <p>By default this task will use a single invocation of the underlying | ||||
| chmod command. If you are working on a large number of files this may | chmod command. If you are working on a large number of files this may | ||||
| result in a command line that is too long for your operating system. | result in a command line that is too long for your operating system. | ||||
| @@ -23,6 +23,10 @@ href="../CoreTypes/filelist.html">FileList</a>s can be specified using | |||||
| nested <code><fileset></code>, <code><dirset></code> and | nested <code><fileset></code>, <code><dirset></code> and | ||||
| <code><filelist></code> elements.</p> | <code><filelist></code> elements.</p> | ||||
| <p>Starting with Ant 1.7, this task supports arbitrary <a | |||||
| href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
| as nested elements.</p> | |||||
| <p>By default this task will use a single invocation of the underlying | <p>By default this task will use a single invocation of the underlying | ||||
| attrib command. If you are working on a large number of files this | attrib command. If you are working on a large number of files this | ||||
| may result in a command line that is too long for your operating | may result in a command line that is too long for your operating | ||||
| @@ -23,6 +23,10 @@ href="../CoreTypes/filelist.html">FileList</a>s can be specified using | |||||
| nested <code><fileset></code>, <code><dirset></code> and | nested <code><fileset></code>, <code><dirset></code> and | ||||
| <code><filelist></code> elements.</p> | <code><filelist></code> elements.</p> | ||||
| <p>Starting with Ant 1.7, this task supports arbitrary <a | |||||
| href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
| as nested elements.</p> | |||||
| <p>By default this task will use a single invocation of the underlying | <p>By default this task will use a single invocation of the underlying | ||||
| chgrp command. If you are working on a large number of files this may | chgrp command. If you are working on a large number of files this may | ||||
| result in a command line that is too long for your operating system. | result in a command line that is too long for your operating system. | ||||
| @@ -23,6 +23,9 @@ href="../CoreTypes/filelist.html">FileList</a>s can be specified using | |||||
| nested <code><fileset></code>, <code><dirset></code> and | nested <code><fileset></code>, <code><dirset></code> and | ||||
| <code><filelist></code> elements.</p> | <code><filelist></code> elements.</p> | ||||
| <p>Starting with Ant 1.7, this task supports arbitrary <a | |||||
| href="../CoreTypes/resources.html#collection">Resource Collection</a>s | |||||
| as nested elements.</p> | |||||
| <p>By default this task will use a single invocation of the underlying | <p>By default this task will use a single invocation of the underlying | ||||
| chown command. If you are working on a large number of files this may | chown command. If you are working on a large number of files this may | ||||
| @@ -31,6 +31,17 @@ | |||||
| <isset property="echo.exe.executable"/> | <isset property="echo.exe.executable"/> | ||||
| </or> | </or> | ||||
| </condition> | </condition> | ||||
| <!-- UNIX --> | |||||
| <available file="ls" filepath="${env.PATH}" property="ls.executable"/> | |||||
| <!-- CYGWIN --> | |||||
| <available file="ls.exe" filepath="${env.PATH}" property="ls.exe.executable"/> | |||||
| <condition property="ls.can.run"> | |||||
| <or> | |||||
| <isset property="ls.executable"/> | |||||
| <isset property="ls.exe.executable"/> | |||||
| </or> | |||||
| </condition> | |||||
| </target> | </target> | ||||
| <target name="xyz"> | <target name="xyz"> | ||||
| @@ -394,6 +405,7 @@ | |||||
| <ekko outputproperty="foo" /> | <ekko outputproperty="foo" /> | ||||
| <ekko outputproperty="bar" force="true" /> | <ekko outputproperty="bar" force="true" /> | ||||
| <fail> | <fail> | ||||
| <condition> | <condition> | ||||
| <not> | <not> | ||||
| @@ -428,6 +440,26 @@ | |||||
| </fail> | </fail> | ||||
| </target> | </target> | ||||
| <target name="lsPath" depends="init" if="ls.can.run"> | |||||
| <apply executable="ls" parallel="false" outputproperty="foo" | |||||
| force="true" dest="${basedir}" append="true" type="both"> | |||||
| <path> | |||||
| <pathelement path="${env.PATH}"/> | |||||
| </path> | |||||
| <identitymapper/> | |||||
| </apply> | |||||
| </target> | |||||
| <target name="lsPathParallel" depends="init" if="ls.can.run"> | |||||
| <apply executable="ls" parallel="true" outputproperty="foo" | |||||
| force="true" dest="${basedir}" append="true" type="both"> | |||||
| <path> | |||||
| <pathelement path="${env.PATH}"/> | |||||
| </path> | |||||
| <identitymapper/> | |||||
| </apply> | |||||
| </target> | |||||
| <target name="cleanup"> | <target name="cleanup"> | ||||
| <delete> | <delete> | ||||
| <fileset refid="xyz" /> | <fileset refid="xyz" /> | ||||
| @@ -20,6 +20,7 @@ package org.apache.tools.ant.taskdefs; | |||||
| import java.io.File; | import java.io.File; | ||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.util.Hashtable; | import java.util.Hashtable; | ||||
| import java.util.Iterator; | |||||
| import java.util.Vector; | import java.util.Vector; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.DirectoryScanner; | import org.apache.tools.ant.DirectoryScanner; | ||||
| @@ -31,6 +32,10 @@ import org.apache.tools.ant.types.EnumeratedAttribute; | |||||
| import org.apache.tools.ant.types.FileList; | import org.apache.tools.ant.types.FileList; | ||||
| import org.apache.tools.ant.types.FileSet; | import org.apache.tools.ant.types.FileSet; | ||||
| import org.apache.tools.ant.types.Mapper; | import org.apache.tools.ant.types.Mapper; | ||||
| import org.apache.tools.ant.types.Resource; | |||||
| import org.apache.tools.ant.types.ResourceCollection; | |||||
| import org.apache.tools.ant.types.resources.FileResource; | |||||
| import org.apache.tools.ant.types.resources.Union; | |||||
| import org.apache.tools.ant.util.FileNameMapper; | import org.apache.tools.ant.util.FileNameMapper; | ||||
| import org.apache.tools.ant.util.SourceFileScanner; | import org.apache.tools.ant.util.SourceFileScanner; | ||||
| @@ -43,13 +48,20 @@ import org.apache.tools.ant.util.SourceFileScanner; | |||||
| */ | */ | ||||
| public class ExecuteOn extends ExecTask { | public class ExecuteOn extends ExecTask { | ||||
| // filesets has been protected so we need to keep that even after | |||||
| // switching to resource collections. In fact, they will still | |||||
| // get a different treatment form the other resource collections | |||||
| // even in execute since we have some subtle special features like | |||||
| // switching type to "dir" when we encounter a DirSet that would | |||||
| // be more difficult to achieve otherwise. | |||||
| protected Vector filesets = new Vector(); // contains AbstractFileSet | protected Vector filesets = new Vector(); // contains AbstractFileSet | ||||
| // (both DirSet and FileSet) | // (both DirSet and FileSet) | ||||
| private Vector filelists = new Vector(); | |||||
| private Union resources = new Union(); | |||||
| private boolean relative = false; | private boolean relative = false; | ||||
| private boolean parallel = false; | private boolean parallel = false; | ||||
| private boolean forwardSlash = false; | private boolean forwardSlash = false; | ||||
| protected String type = "file"; | |||||
| protected String type = FileDirBoth.FILE; | |||||
| protected Commandline.Marker srcFilePos = null; | protected Commandline.Marker srcFilePos = null; | ||||
| private boolean skipEmpty = false; | private boolean skipEmpty = false; | ||||
| protected Commandline.Marker targetFilePos = null; | protected Commandline.Marker targetFilePos = null; | ||||
| @@ -91,7 +103,18 @@ public class ExecuteOn extends ExecTask { | |||||
| * @param list the FileList to add. | * @param list the FileList to add. | ||||
| */ | */ | ||||
| public void addFilelist(FileList list) { | public void addFilelist(FileList list) { | ||||
| filelists.addElement(list); | |||||
| add(list); | |||||
| } | |||||
| /** | |||||
| * Add a collection of resources upon which to operate. | |||||
| * @param rc resource collection to add. | |||||
| * @since Ant 1.7 | |||||
| */ | |||||
| public void add(ResourceCollection rc) { | |||||
| if (rc instanceof FileSet) | |||||
| throw new BuildException("Huh?"); | |||||
| resources.add(rc); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -273,8 +296,8 @@ public class ExecuteOn extends ExecTask { | |||||
| log("!! execon is deprecated. Use apply instead. !!"); | log("!! execon is deprecated. Use apply instead. !!"); | ||||
| } | } | ||||
| super.checkConfiguration(); | super.checkConfiguration(); | ||||
| if (filesets.size() == 0 && filelists.size() == 0) { | |||||
| throw new BuildException("no filesets and no filelists specified", | |||||
| if (filesets.size() == 0 && resources.size() == 0) { | |||||
| throw new BuildException("no resources specified", | |||||
| getLocation()); | getLocation()); | ||||
| } | } | ||||
| if (targetFilePos != null && mapperElement == null) { | if (targetFilePos != null && mapperElement == null) { | ||||
| @@ -326,19 +349,19 @@ public class ExecuteOn extends ExecTask { | |||||
| String currentType = type; | String currentType = type; | ||||
| AbstractFileSet fs = (AbstractFileSet) filesets.elementAt(i); | AbstractFileSet fs = (AbstractFileSet) filesets.elementAt(i); | ||||
| if (fs instanceof DirSet) { | if (fs instanceof DirSet) { | ||||
| if (!"dir".equals(type)) { | |||||
| if (!FileDirBoth.DIR.equals(type)) { | |||||
| log("Found a nested dirset but type is " + type + ". " | log("Found a nested dirset but type is " + type + ". " | ||||
| + "Temporarily switching to type=\"dir\" on the" | + "Temporarily switching to type=\"dir\" on the" | ||||
| + " assumption that you really did mean" | + " assumption that you really did mean" | ||||
| + " <dirset> not <fileset>.", Project.MSG_DEBUG); | + " <dirset> not <fileset>.", Project.MSG_DEBUG); | ||||
| currentType = "dir"; | |||||
| currentType = FileDirBoth.DIR; | |||||
| } | } | ||||
| } | } | ||||
| File base = fs.getDir(getProject()); | File base = fs.getDir(getProject()); | ||||
| DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | DirectoryScanner ds = fs.getDirectoryScanner(getProject()); | ||||
| if (!"dir".equals(currentType)) { | |||||
| if (!FileDirBoth.DIR.equals(currentType)) { | |||||
| String[] s = getFiles(base, ds); | String[] s = getFiles(base, ds); | ||||
| for (int j = 0; j < s.length; j++) { | for (int j = 0; j < s.length; j++) { | ||||
| totalFiles++; | totalFiles++; | ||||
| @@ -346,7 +369,7 @@ public class ExecuteOn extends ExecTask { | |||||
| baseDirs.addElement(base); | baseDirs.addElement(base); | ||||
| } | } | ||||
| } | } | ||||
| if (!"file".equals(currentType)) { | |||||
| if (!FileDirBoth.FILE.equals(currentType)) { | |||||
| String[] s = getDirs(base, ds); | String[] s = getDirs(base, ds); | ||||
| for (int j = 0; j < s.length; j++) { | for (int j = 0; j < s.length; j++) { | ||||
| totalDirs++; | totalDirs++; | ||||
| @@ -356,9 +379,9 @@ public class ExecuteOn extends ExecTask { | |||||
| } | } | ||||
| if (fileNames.size() == 0 && skipEmpty) { | if (fileNames.size() == 0 && skipEmpty) { | ||||
| int includedCount | int includedCount | ||||
| = ((!"dir".equals(currentType)) | |||||
| = ((!FileDirBoth.DIR.equals(currentType)) | |||||
| ? ds.getIncludedFilesCount() : 0) | ? ds.getIncludedFilesCount() : 0) | ||||
| + ((!"file".equals(currentType)) | |||||
| + ((!FileDirBoth.FILE.equals(currentType)) | |||||
| ? ds.getIncludedDirsCount() : 0); | ? ds.getIncludedDirsCount() : 0); | ||||
| log("Skipping fileset for directory " + base + ". It is " | log("Skipping fileset for directory " + base + ". It is " | ||||
| @@ -392,68 +415,67 @@ public class ExecuteOn extends ExecTask { | |||||
| baseDirs.removeAllElements(); | baseDirs.removeAllElements(); | ||||
| } | } | ||||
| } | } | ||||
| for (int i = 0; i < filelists.size(); i++) { | |||||
| FileList list = (FileList) filelists.elementAt(i); | |||||
| File base = list.getDir(getProject()); | |||||
| String[] names = getFilesAndDirs(list); | |||||
| for (int j = 0; j < names.length; j++) { | |||||
| File f = new File(base, names[j]); | |||||
| if ((!ignoreMissing) || (f.isFile() && !"dir".equals(type)) | |||||
| || (f.isDirectory() && !"file".equals(type))) { | |||||
| if (ignoreMissing || f.isFile()) { | |||||
| totalFiles++; | |||||
| } else { | |||||
| totalDirs++; | |||||
| } | |||||
| fileNames.addElement(names[j]); | |||||
| baseDirs.addElement(base); | |||||
| } | |||||
| } | |||||
| if (fileNames.size() == 0 && skipEmpty) { | |||||
| DirectoryScanner ds = new DirectoryScanner(); | |||||
| ds.setBasedir(base); | |||||
| ds.setIncludes(list.getFiles(getProject())); | |||||
| ds.scan(); | |||||
| int includedCount | |||||
| = ds.getIncludedFilesCount() + ds.getIncludedDirsCount(); | |||||
| Iterator iter = resources.iterator(); | |||||
| while (iter.hasNext()) { | |||||
| Resource res = (Resource) iter.next(); | |||||
| if (!res.isExists() && ignoreMissing) { | |||||
| continue; | |||||
| } | |||||
| File base = null; | |||||
| String name = res.getName(); | |||||
| if (res instanceof FileResource) { | |||||
| FileResource fr = (FileResource) res; | |||||
| base = fr.getBaseDir(); | |||||
| if (base == null) { | |||||
| name = fr.getFile().getAbsolutePath(); | |||||
| } | |||||
| } | |||||
| if (restrict(new String[] {name}, base).length == 0) { | |||||
| continue; | |||||
| } | |||||
| if ((!res.isDirectory() || !res.isExists()) | |||||
| && !FileDirBoth.DIR.equals(type)) { | |||||
| totalFiles++; | |||||
| } else if (res.isDirectory() && !FileDirBoth.FILE.equals(type)) { | |||||
| totalDirs++; | |||||
| } else { | |||||
| continue; | |||||
| } | |||||
| baseDirs.add(base); | |||||
| fileNames.add(name); | |||||
| log("Skipping filelist for directory " + base + ". It is " | |||||
| + ((includedCount > 0) ? "up to date." : "empty."), | |||||
| Project.MSG_INFO); | |||||
| continue; | |||||
| } | |||||
| if (!parallel) { | if (!parallel) { | ||||
| String[] s = new String[fileNames.size()]; | |||||
| fileNames.copyInto(s); | |||||
| for (int j = 0; j < s.length; j++) { | |||||
| String[] command = getCommandline(s[j], base); | |||||
| log(Commandline.describeCommand(command), | |||||
| Project.MSG_VERBOSE); | |||||
| exe.setCommandline(command); | |||||
| if (redirectorElement != null) { | |||||
| setupRedirector(); | |||||
| redirectorElement.configure(redirector, s[j]); | |||||
| } | |||||
| if (redirectorElement != null || haveExecuted) { | |||||
| // need to reset the stream handler to restart | |||||
| // reading of pipes; | |||||
| // go ahead and do it always w/ nested redirectors | |||||
| exe.setStreamHandler(redirector.createHandler()); | |||||
| } | |||||
| runExecute(exe); | |||||
| haveExecuted = true; | |||||
| } | |||||
| fileNames.removeAllElements(); | |||||
| baseDirs.removeAllElements(); | |||||
| } | |||||
| String[] command = getCommandline(name, base); | |||||
| log(Commandline.describeCommand(command), | |||||
| Project.MSG_VERBOSE); | |||||
| exe.setCommandline(command); | |||||
| if (redirectorElement != null) { | |||||
| setupRedirector(); | |||||
| redirectorElement.configure(redirector, name); | |||||
| } | |||||
| if (redirectorElement != null || haveExecuted) { | |||||
| // need to reset the stream handler to restart | |||||
| // reading of pipes; | |||||
| // go ahead and do it always w/ nested redirectors | |||||
| exe.setStreamHandler(redirector.createHandler()); | |||||
| } | |||||
| runExecute(exe); | |||||
| haveExecuted = true; | |||||
| fileNames.removeAllElements(); | |||||
| baseDirs.removeAllElements(); | |||||
| } | |||||
| } | } | ||||
| if (parallel && (fileNames.size() > 0 || !skipEmpty)) { | if (parallel && (fileNames.size() > 0 || !skipEmpty)) { | ||||
| runParallel(exe, fileNames, baseDirs); | runParallel(exe, fileNames, baseDirs); | ||||
| haveExecuted = true; | haveExecuted = true; | ||||
| } | |||||
| } | |||||
| if (haveExecuted) { | if (haveExecuted) { | ||||
| log("Applied " + cmdl.getExecutable() + " to " | log("Applied " + cmdl.getExecutable() + " to " | ||||
| + totalFiles + " file" | + totalFiles + " file" | ||||
| @@ -697,11 +719,13 @@ public class ExecuteOn extends ExecTask { | |||||
| * for the type attribute. | * for the type attribute. | ||||
| */ | */ | ||||
| public static class FileDirBoth extends EnumeratedAttribute { | public static class FileDirBoth extends EnumeratedAttribute { | ||||
| public static final String FILE = "file"; | |||||
| public static final String DIR = "dir"; | |||||
| /** | /** | ||||
| * @see EnumeratedAttribute#getValues | * @see EnumeratedAttribute#getValues | ||||
| */ | */ | ||||
| public String[] getValues() { | public String[] getValues() { | ||||
| return new String[] {"file", "dir", "both"}; | |||||
| return new String[] {FILE, DIR, "both"}; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| @@ -31,6 +31,7 @@ import java.io.OutputStream; | |||||
| public class ExecuteOnTest extends BuildFileTest { | public class ExecuteOnTest extends BuildFileTest { | ||||
| private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; | private static final String BUILD_PATH = "src/etc/testcases/taskdefs/exec/"; | ||||
| private static final String BUILD_FILE = BUILD_PATH + "apply.xml"; | private static final String BUILD_FILE = BUILD_PATH + "apply.xml"; | ||||
| private static final String LINE_SEP = System.getProperty("line.separator"); | |||||
| public ExecuteOnTest(String name) { | public ExecuteOnTest(String name) { | ||||
| super(name); | super(name); | ||||
| @@ -562,6 +563,26 @@ public class ExecuteOnTest extends BuildFileTest { | |||||
| executeTarget("testNoDest"); | executeTarget("testNoDest"); | ||||
| } | } | ||||
| public void testLsPath() { | |||||
| testLsPath("lsPath"); | |||||
| } | |||||
| public void testLsPathParallel() { | |||||
| testLsPath("lsPathParallel"); | |||||
| } | |||||
| private void testLsPath(String target) { | |||||
| executeTarget(target); | |||||
| if (getProject().getProperty("ls.can.run") == null) { | |||||
| return; | |||||
| } | |||||
| String foo = getProject().getProperty("foo"); | |||||
| assertNotNull(foo); | |||||
| int indNoExt = foo.indexOf("ls" + LINE_SEP); | |||||
| int indExe = foo.indexOf("ls.exe" + LINE_SEP); | |||||
| assertTrue(indNoExt >= 0 || indExe >= 0); | |||||
| } | |||||
| //borrowed from TokenFilterTest | //borrowed from TokenFilterTest | ||||
| private String getFileString(String filename) throws IOException { | private String getFileString(String filename) throws IOException { | ||||
| String result = null; | String result = null; | ||||