Browse Source

Add multimapping to the copy and move task

Some slight changes from the orignal patch - rename
of ignoremultiplemapping to enablemultiplemapping and
some checkstyle changes
PR: 21320
Obtained from: Evan Easton


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274923 13f79535-47bb-0310-9956-ffa450edef68
master
Peter Reilly 22 years ago
parent
commit
99067d0607
6 changed files with 527 additions and 115 deletions
  1. +17
    -0
      docs/manual/CoreTasks/copy.html
  2. +10
    -0
      docs/manual/CoreTasks/move.html
  3. +175
    -0
      src/etc/testcases/taskdefs/multimap.xml
  4. +91
    -46
      src/main/org/apache/tools/ant/taskdefs/Copy.java
  5. +120
    -69
      src/main/org/apache/tools/ant/taskdefs/Move.java
  6. +114
    -0
      src/testcases/org/apache/tools/ant/taskdefs/MultiMapTest.java

+ 17
- 0
docs/manual/CoreTasks/copy.html View File

@@ -118,6 +118,23 @@ operation as <a href="../CoreTypes/filterset.html">filtersets</a>
<td align="center">No - defaults to the value of the encoding
attribute if given or the default JVM encoding otherwise.</td>
</tr>
<tr>
<td valign="top">outputencoding</td>
<td valign="top">The encoding to use when writing the files.
<em>since Ant 1.6</em>.</td>
<td align="center">No - defaults to the value of the encoding
attribute if given or the default JVM encoding otherwise.</td>
</tr>
<tr>
<td valign="top">enablemultiplemapping</td>
<td valign="top">
If true the task will process to all the mappings for a
given source path. If false the task will only process
the first file or directory. This attribute is only relevant
if there is a mapper subelement.
<em>since Ant 1.6</em>.</td>
<td align="center">No - defaults to false.</td>
</tr>
</table>
<h3>Parameters specified as nested elements</h3>



+ 10
- 0
docs/manual/CoreTasks/move.html View File

@@ -103,6 +103,16 @@ to move to the <var>todir</var> directory.</p>
<td align="center">No - defaults to the value of the encoding
attribute if given or the default JVM encoding otherwise.</td>
</tr>
<tr>
<td valign="top">enablemultiplemapping</td>
<td valign="top">
If true the task will process to all the mappings for a
given source path. If false the task will only process
the first file or directory. This attribute is only relevant
if there is a mapper subelement.
<em>since Ant 1.6</em>.</td>
<td align="center">No - defaults to false.</td>
</tr>
</table>
<h3>Parameters specified as nested elements</h3>
<h4>mapper</h4>


+ 175
- 0
src/etc/testcases/taskdefs/multimap.xml View File

@@ -0,0 +1,175 @@
<?xml version="1.0"?>
<project name="test" basedir=".">
<path id="testclasses">
<pathelement location="../../../../build/testcases" />
<pathelement path="${java.class.path}" />
</path>

<mapper id="testmapper"
classname="org.apache.tools.ant.taskdefs.MultiMapTest$TestMapper"
classpathref="testclasses"/>

<property name="map.ext" value=".copy2"/>
<property name="rootScratchDir" value="test_multi_mapper_scratch_area"/>
<property name="baseScratchSrc" value="${rootScratchDir}/src"/>

<target name="setup">
<delete dir="${baseScratchSrc}"/>
<mkdir dir="${baseScratchSrc}"/>
<delete dir="${baseScratchDest}"/>
<mkdir dir="${baseScratchDest}"/>
<touch file="${baseScratchSrc}/somefile.txt"/>
</target>

<!-- test simple single file to multiple file move -->
<target name="multicopy" depends="setup">
<copy todir="${baseScratchDest}" enablemultiplemappings="true">
<fileset dir="${baseScratchSrc}" includes="somefile.txt"/>
<mapper refid="testmapper"/>
</copy>
<condition property="multicopy.outcome">
<and>
<available file="${baseScratchDest}/somefile.txt"/>
<available file="${baseScratchDest}/somefile.txt${map.ext}"/>
</and>
</condition>
<fail unless="multicopy.outcome">multicopy failed</fail>
</target>

<target name="multimove" depends="setup">
<move todir="${baseScratchDest}" enablemultiplemappings="true">
<fileset dir="${baseScratchSrc}" includes="somefile.txt"/>
<mapper refid="testmapper"/>
</move>
<condition property="test2.outcome">
<and>
<available file="${baseScratchDest}/somefile.txt"/>
<available file="${baseScratchDest}/somefile.txt${map.ext}"/>
<not>
<available file="${baseScratchSrc}/somefile.txt"/>
</not>
<not>
<available file="${baseScratchSrc}/somefile.txt${map.ext}"/>
</not>
</and>
</condition>
<fail unless="test2.outcome">mulitmove failed</fail>
</target>
<!--
test traditional single file to single file copy explicitly telling
task to ignore multiple mappings
-->

<target name="singlecopy" depends="setup">
<copy todir="${baseScratchDest}" enablemultiplemappings="false">
<fileset dir="${baseScratchSrc}" includes="somefile.txt"/>
<mapper refid="testmapper"/>
</copy>
<condition property="singlecopy.outcome">
<and>
<available file="${baseScratchDest}/somefile.txt"/>
<not>
<available file="${baseScratchDest}/somefile.txt${map.ext}"/>
</not>
<available file="${baseScratchSrc}/somefile.txt"/>
</and>
</condition>
<fail unless="singlecopy.outcome">singlecopy failed</fail>
</target>

<target name="singlemove" depends="setup">
<move todir="${baseScratchDest}" enablemultiplemappings="false">
<fileset dir="${baseScratchSrc}" includes="somefile.txt"/>
<mapper refid="testmapper"/>
</move>
<condition property="singlemove.outcome">
<and>
<available file="${baseScratchDest}/somefile.txt"/>
<not>
<available file="${baseScratchDest}/somefile.txt${map.ext}"/>
</not>
<not>
<available file="${baseScratchSrc}/somefile.txt"/>
</not>
</and>
</condition>
<fail unless="singlemove.outcome">singlemove failed</fail>
</target>

<!-- test dir w/ file + empty dir multimap copy -->
<target name="copywithempty">
<delete dir="${baseScratchSrc}"/>
<mkdir dir="${baseScratchSrc}/dirwithfile"/>
<mkdir dir="${baseScratchSrc}/emptydir"/>
<touch file="${baseScratchSrc}/dirwithfile/somefile.txt"/>

<delete dir="${baseScratchDest}"/>
<mkdir dir="${baseScratchDest}"/>

<copy todir="${baseScratchDest}" enablemultiplemappings="true">
<fileset dir="${baseScratchSrc}" includes="**/*"/>
<mapper refid="testmapper"/>
</copy>
<condition property="copywithempty.outcome">
<and>
<available file="${baseScratchDest}/dirwithfile"/>
<available file="${baseScratchDest}/dirwithfile${map.ext}"/>
<available file="${baseScratchDest}/dirwithfile/somefile.txt"/>
<available file="${baseScratchDest}/dirwithfile/somefile.txt${map.ext}"/>
<not>
<available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt"/>
</not>
<not>
<available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt${map.ext}"/>
</not>
<available file="${baseScratchDest}/emptydir"/>
<available file="${baseScratchDest}/emptydir${map.ext}"/>
</and>
</condition>
<fail unless="copywithempty.outcome">copywithempty failed</fail>
</target>
<!-- test dir w/ file + empty dir multimap move -->
<target name="movewithempty">
<delete dir="${baseScratchSrc}"/>
<mkdir dir="${baseScratchSrc}/dirwithfile"/>
<mkdir dir="${baseScratchSrc}/emptydir"/>
<touch file="${baseScratchSrc}/dirwithfile/somefile.txt"/>

<delete dir="${baseScratchDest}"/>
<mkdir dir="${baseScratchDest}"/>

<move todir="${baseScratchDest}" enablemultiplemappings="true">
<fileset dir="${baseScratchSrc}" includes="**/*"/>
<mapper refid="testmapper"/>
</move>
<condition property="movewithempty.outcome">
<and>
<available file="${baseScratchDest}/dirwithfile"/>
<available file="${baseScratchDest}/dirwithfile${map.ext}"/>
<available file="${baseScratchDest}/dirwithfile/somefile.txt"/>
<available file="${baseScratchDest}/dirwithfile/somefile.txt${map.ext}"/>
<not>
<available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt"/>
</not>
<not>
<available file="${baseScratchDest}/dirwithfile${map.ext}/somefile.txt${map.ext}"/>
</not>
<available file="${baseScratchDest}/emptydir"/>
<available file="${baseScratchDest}/emptydir${map.ext}"/>
<not>
<available file="${baseScratchSrc}/dirwithfile"/>
</not>
<not>
<available file="${baseScratchSrc}/emptydir"/>
</not>
</and>
</condition>
<fail unless="movewithempty.outcome">movewithempty failed</fail>
</target>

<target name="cleanup">
<delete dir="${rootScratchDir}"/>
</target>

</project>

+ 91
- 46
src/main/org/apache/tools/ant/taskdefs/Copy.java View File

@@ -102,6 +102,7 @@ public class Copy extends Task {
protected File destDir = null; // the destination directory
protected Vector filesets = new Vector();

private boolean enableMultipleMappings = false;
protected boolean filtering = false;
protected boolean preserveLastModified = false;
protected boolean forceOverwrite = false;
@@ -259,6 +260,28 @@ public class Copy extends Task {
this.includeEmpty = includeEmpty;
}

/**
* Attribute to handle mappers that return multiple
* mappings for a given source path.
* @param enableMultipleMappings If true the task will
* copy to all the mappings for a given source path, if
* false, only the first file or directory is
* processed.
* By default, this setting is false to provide backward
* compatibility with earlier releases.
* @since 1.6
*/
public void setEnableMultipleMappings(boolean enableMultipleMappings) {
this.enableMultipleMappings = enableMultipleMappings;
}

/**
* @return the value of the enableMultipleMapping attribute
*/
public boolean isEnableMultipleMapping() {
return enableMultipleMappings;
}
/**
* If false, note errors to the output but keep going.
* @param failonerror true or false
@@ -354,7 +377,7 @@ public class Copy extends Task {
if (forceOverwrite || !destFile.exists()
|| (file.lastModified() > destFile.lastModified())) {
fileCopyMap.put(file.getAbsolutePath(),
destFile.getAbsolutePath());
new String[] {destFile.getAbsolutePath()});
} else {
log(file + " omitted as " + destFile
+ " is up to date.", Project.MSG_VERBOSE);
@@ -528,8 +551,20 @@ public class Copy extends Task {

for (int i = 0; i < toCopy.length; i++) {
File src = new File(fromDir, toCopy[i]);
File dest = new File(toDir, mapper.mapFileName(toCopy[i])[0]);
map.put(src.getAbsolutePath(), dest.getAbsolutePath());

String[] mappedFiles = mapper.mapFileName(toCopy[i]);

if (!enableMultipleMappings) {
map.put(src.getAbsolutePath(),
new String[] {new File(toDir, mappedFiles[0]).getAbsolutePath()});
} else {
// reuse the array created by the mapper
for (int k = 0; k < mappedFiles.length; k++) {
mappedFiles[k] = new File(toDir, mappedFiles[k]).getAbsolutePath();
}

map.put(src.getAbsolutePath(), mappedFiles);
}
}
}

@@ -546,64 +581,74 @@ public class Copy extends Task {
Enumeration e = fileCopyMap.keys();
while (e.hasMoreElements()) {
String fromFile = (String) e.nextElement();
String toFile = (String) fileCopyMap.get(fromFile);

if (fromFile.equals(toFile)) {
log("Skipping self-copy of " + fromFile, verbosity);
continue;
}
String[] toFiles = (String[]) fileCopyMap.get(fromFile);

try {
log("Copying " + fromFile + " to " + toFile, verbosity);
for (int i = 0; i < toFiles.length; i++) {
String toFile = toFiles[i];

FilterSetCollection executionFilters =
new FilterSetCollection();
if (filtering) {
executionFilters
.addFilterSet(getProject().getGlobalFilterSet());
}
for (Enumeration filterEnum = filterSets.elements();
filterEnum.hasMoreElements();) {
executionFilters
.addFilterSet((FilterSet) filterEnum.nextElement());
if (fromFile.equals(toFile)) {
log("Skipping self-copy of " + fromFile, verbosity);
continue;
}
fileUtils.copyFile(fromFile, toFile, executionFilters,
filterChains, forceOverwrite,
preserveLastModified, inputEncoding,
outputEncoding, getProject());
} catch (IOException ioe) {
String msg = "Failed to copy " + fromFile + " to " + toFile
+ " due to " + ioe.getMessage();
File targetFile = new File(toFile);
if (targetFile.exists() && !targetFile.delete()) {
msg += " and I couldn't delete the corrupt " + toFile;

try {
log("Copying " + fromFile + " to " + toFile, verbosity);

FilterSetCollection executionFilters =
new FilterSetCollection();
if (filtering) {
executionFilters
.addFilterSet(getProject().getGlobalFilterSet());
}
for (Enumeration filterEnum = filterSets.elements();
filterEnum.hasMoreElements();) {
executionFilters
.addFilterSet((FilterSet) filterEnum.nextElement());
}
fileUtils.copyFile(fromFile, toFile, executionFilters,
filterChains, forceOverwrite,
preserveLastModified, inputEncoding,
outputEncoding, getProject());
} catch (IOException ioe) {
String msg = "Failed to copy " + fromFile + " to " + toFile
+ " due to " + ioe.getMessage();
File targetFile = new File(toFile);
if (targetFile.exists() && !targetFile.delete()) {
msg += " and I couldn't delete the corrupt " + toFile;
}
throw new BuildException(msg, ioe, getLocation());
}
throw new BuildException(msg, ioe, getLocation());
}
}
}

if (includeEmpty) {
Enumeration e = dirCopyMap.elements();
int count = 0;
int createCount = 0;
while (e.hasMoreElements()) {
File d = new File((String) e.nextElement());
if (!d.exists()) {
if (!d.mkdirs()) {
log("Unable to create directory "
+ d.getAbsolutePath(), Project.MSG_ERR);
} else {
count++;
String[] dirs = (String[]) e.nextElement();
for (int i = 0; i < dirs.length; i++) {
File d = new File(dirs[i]);
if (!d.exists()) {
if (!d.mkdirs()) {
log("Unable to create directory "
+ d.getAbsolutePath(), Project.MSG_ERR);
} else {
createCount++;
}
}
}
}

if (count > 0) {
log("Copied " + count + " empty director"
+ (count == 1 ? "y" : "ies")
+ " to " + destDir.getAbsolutePath());
if (createCount > 0) {
log("Copied " + dirCopyMap.size()
+ " empty director"
+ (dirCopyMap.size() == 1 ? "y" : "ies")
+ " to " + createCount
+ " empty director"
+ (createCount == 1 ? "y" : "ies") + " under "
+ destDir.getAbsolutePath());
}
}
}

}


+ 120
- 69
src/main/org/apache/tools/ant/taskdefs/Move.java View File

@@ -125,67 +125,29 @@ public class Move extends Copy {
Enumeration e = fileCopyMap.keys();
while (e.hasMoreElements()) {
String fromFile = (String) e.nextElement();
String toFile = (String) fileCopyMap.get(fromFile);

if (fromFile.equals(toFile)) {
log("Skipping self-move of " + fromFile, verbosity);
continue;
}

boolean moved = false;
File f = new File(fromFile);
boolean selfMove = false;
if (f.exists()) { //Is this file still available to be moved?
File d = new File(toFile);

try {
log("Attempting to rename: " + fromFile
+ " to " + toFile, verbosity);
moved = renameFile(f, d, filtering, forceOverwrite);
} catch (IOException ioe) {
String msg = "Failed to rename " + fromFile
+ " to " + toFile
+ " due to " + ioe.getMessage();
throw new BuildException(msg, ioe, getLocation());
}
String[] toFiles = (String[]) fileCopyMap.get(fromFile);
for (int i = 0; i < toFiles.length; i++) {
String toFile = (String) toFiles[i];

if (!moved) {
try {
log("Moving " + fromFile + " to " + toFile,
verbosity);
if (fromFile.equals(toFile)) {
log("Skipping self-move of " + fromFile, verbosity);
selfMove = true;

FilterSetCollection executionFilters =
new FilterSetCollection();
if (filtering) {
executionFilters
.addFilterSet(getProject().getGlobalFilterSet());
}
for (Enumeration filterEnum =
getFilterSets().elements();
filterEnum.hasMoreElements();) {
executionFilters
.addFilterSet((FilterSet) filterEnum
.nextElement());
}
getFileUtils().copyFile(f, d, executionFilters,
getFilterChains(),
forceOverwrite,
getPreserveLastModified(),
getEncoding(),
getOutputEncoding(),
getProject());

f = new File(fromFile);
if (!f.delete()) {
throw new BuildException("Unable to delete "
+ "file "
+ f.getAbsolutePath());
}
} catch (IOException ioe) {
String msg = "Failed to copy " + fromFile + " to "
+ toFile
+ " due to " + ioe.getMessage();
throw new BuildException(msg, ioe, getLocation());
// if this is the last time through the loop then
// move will not occur, but that's what we want
continue;
}
File d = new File(toFile);
if ((i + 1) == toFiles.length && !selfMove) {
// Only try to move if this is the last mapped file
// and one of the mappings isn't to itself
moveFile(f, d, filtering, forceOverwrite);
} else {
copyFile(f, d, filtering, forceOverwrite);
}
}
}
@@ -194,32 +156,121 @@ public class Move extends Copy {

if (includeEmpty) {
Enumeration e = dirCopyMap.keys();
int count = 0;
int createCount = 0;
while (e.hasMoreElements()) {
String fromDirName = (String) e.nextElement();
String toDirName = (String) dirCopyMap.get(fromDirName);
File fromDir = new File(fromDirName);
File toDir = new File(toDirName);
if (!toDir.exists()) {
if (!toDir.mkdirs()) {
log("Unable to create directory "
+ toDirName, Project.MSG_ERR);
} else {
count++;
String[] toDirNames = (String[]) dirCopyMap.get(fromDirName);
boolean selfMove = false;
for (int i = 0; i < toDirNames.length; i++) {

if (fromDirName.equals(toDirNames[i])) {
log("Skipping self-move of " + fromDirName, verbosity);
selfMove = true;
continue;
}

File d = new File(toDirNames[i]);
if (!d.exists()) {
if (!d.mkdirs()) {
log("Unable to create directory "
+ d.getAbsolutePath(), Project.MSG_ERR);
} else {
createCount++;
}
}
}
if (okToDelete(fromDir)) {

File fromDir = new File(fromDirName);
if (!selfMove && okToDelete(fromDir)) {
deleteDir(fromDir);
}

}

if (count > 0) {
log("Moved " + count + " empty directories to "
if (createCount > 0) {
log("Moved " + dirCopyMap.size()
+ " empty director"
+ (dirCopyMap.size()== 1 ? "y" : "ies")
+ " to " + createCount
+ " empty director"
+ (createCount == 1 ? "y" : "ies") + " under "
+ destDir.getAbsolutePath());
}
}
}

/**
* Try to move the file via a rename, but if this fails or filtering
* is enabled, copy the file then delete the sourceFile.
*/
private void moveFile(File fromFile, File toFile,
boolean filtering, boolean overwrite) {
boolean moved = false;
try {
log("Attempting to rename: " + fromFile
+ " to " + toFile, verbosity);
moved = renameFile(fromFile, toFile, filtering, forceOverwrite);
} catch (IOException ioe) {
String msg = "Failed to rename " + fromFile
+ " to " + toFile
+ " due to " + ioe.getMessage();
throw new BuildException(msg, ioe, getLocation());
}

if (!moved) {
copyFile(fromFile, toFile, filtering, overwrite);
if (!fromFile.delete()) {
throw new BuildException("Unable to delete "
+ "file "
+ fromFile.getAbsolutePath());
}
}
}

/**
* Copy fromFile to toFile.
* @param fromFile
* @param toFile
* @param filtering
* @param overwrite
*/
private void copyFile(File fromFile, File toFile,
boolean filtering, boolean overwrite) {
try {
log("Copying " + fromFile + " to " + toFile,
verbosity);

FilterSetCollection executionFilters =
new FilterSetCollection();
if (filtering) {
executionFilters
.addFilterSet(getProject().getGlobalFilterSet());
}
for (Enumeration filterEnum =
getFilterSets().elements();
filterEnum.hasMoreElements();) {
executionFilters
.addFilterSet((FilterSet) filterEnum
.nextElement());
}

getFileUtils().copyFile(fromFile, toFile, executionFilters,
getFilterChains(),
forceOverwrite,
getPreserveLastModified(),
getEncoding(),
getOutputEncoding(),
getProject());

} catch (IOException ioe) {
String msg = "Failed to copy " + fromFile
+ " to " + toFile
+ " due to " + ioe.getMessage();
throw new BuildException(msg, ioe, getLocation());
}
}


/**
* Its only ok to delete a directory tree if there are
* no files in it.


+ 114
- 0
src/testcases/org/apache/tools/ant/taskdefs/MultiMapTest.java View File

@@ -0,0 +1,114 @@
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2003 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 "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.taskdefs;

import java.lang.reflect.Method;

import org.apache.tools.ant.BuildFileTest;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.util.FileNameMapper;


/**
* @author Peter Reilly
*/
public class MultiMapTest extends BuildFileTest {
public MultiMapTest(String name) {
super(name);
}
public void setUp() {
configureProject("src/etc/testcases/taskdefs/multimap.xml");
}

public void tearDown() {
executeTarget("cleanup");
}
public void testMultiCopy() {
executeTarget("multicopy");
}
public void testMultiMove() {
executeTarget("multimove");
}
public void testSingleCopy() {
executeTarget("singlecopy");
}
public void testSingleMove() {
executeTarget("singlemove");
}
public void testCopyWithEmpty() {
executeTarget("copywithempty");
}

public void testMoveWithEmpty() {
executeTarget("movewithempty");
}
public static class TestMapper implements FileNameMapper {
public TestMapper() {}
public void setFrom(String from) {}
public void setTo(String to) {}
public String[] mapFileName(final String source_file_name) {
return new String[] {
source_file_name, source_file_name+".copy2" };
}
}
}

Loading…
Cancel
Save