Browse Source

Nested file mappers; container mapper.

PR: 26364


git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276223 13f79535-47bb-0310-9956-ffa450edef68
master
Matthew Jason Benson 21 years ago
parent
commit
ce89090b46
6 changed files with 370 additions and 9 deletions
  1. +5
    -0
      WHATSNEW
  2. +100
    -5
      docs/manual/CoreTypes/mapper.html
  3. +51
    -4
      src/main/org/apache/tools/ant/types/Mapper.java
  4. +10
    -0
      src/main/org/apache/tools/ant/types/defaults.properties
  5. +129
    -0
      src/main/org/apache/tools/ant/util/ContainerMapper.java
  6. +75
    -0
      src/testcases/org/apache/tools/ant/types/MapperTest.java

+ 5
- 0
WHATSNEW View File

@@ -41,6 +41,11 @@ Other changes:
a granularity of two seconds). The default remains to round up.
Bugzilla Report 17934.

* Nested file mappers and a container mapper implementation have been
introduced. Additionally, the <mapper> element now accepts "defined"
nested FileNameMapper implementations directly, allowing a usage
comparable to those of <condition>, <filter>, and <selector>.

Changes from Ant 1.6.1 to current Ant 1.6 CVS version
=============================================



+ 100
- 5
docs/manual/CoreTypes/mapper.html View File

@@ -62,6 +62,12 @@ with the following attributes:</p>
implementation.</td>
<td align="center" valign="top">Depends on implementation.</td>
</tr>
<tr>
<td valign="top">chained</td>
<td valign="top">Whether to chain nested <CODE>&lt;mapper&gt;</CODE>s.
<i>Since Ant 1.7</i></td>
<td align="center" valign="top">No, default is <CODE>false</CODE>.</td>
</tr>
</table>
<p>Note that Ant will not automatically convert / or \ characters in
the <code>to</code> and <code>from</code> attributes to the correct
@@ -71,14 +77,30 @@ this separator, use <code>${file.separator}</code> instead.</p>
<p>The classpath can be specified via a nested
<code>&lt;classpath&gt;</code>, as well - that is,
a <a href="../using.html#path">path</a>-like structure.</p>
<p><b>Since Ant 1.7,</b> nested File Mappers can
be supplied via either <CODE>&lt;mapper&gt;</CODE> elements or
<a href="../CoreTasks/typedef.html"><code>&lt;typedef&gt;</code></a>'d
implementations of <CODE>org.apache.tools.ant.util.FileNameMapper</CODE>.
If one or more nested File Mappers are specified using either convention,
only the <i>chained</i> attribute will be considered in the configuration
of the implicitly used <a href="#container-mapper">container mapper</a>.
</p>
<hr/>
<h3>The built-in mapper types are:</h3>
<p>All built-in mappers are case-sensitive.</p>
<p><b>As of Ant 1.7,</b> each of the built-in mapper implementation
types is directly accessible using a specific tagname. This makes it
possible for filename mappers to support attributes in addition to
the generally available <i>to</i> and <i>from</i>.<br/>
The <code>&lt;mapper type|classname=&quot;...&quot;&gt;</code> usage
form remains valid for reasons of backward compatibility.</p>
<h4><a name="identity-mapper">identity</a></h4>
<p>The target file name is identical to the source file name. Both
<code>to</code> and <code>from</code> will be ignored.</p>
<b>Examples:</b>
<blockquote><pre>
&lt;mapper type=&quot;identity&quot;/&gt;
&lt;identitymapper /&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -109,6 +131,7 @@ leading directory information stripped off. Both <code>to</code> and
<b>Examples:</b>
<blockquote><pre>
&lt;mapper type=&quot;flatten&quot;/&gt;
&lt;flattenmapper /&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -138,6 +161,7 @@ leading directory information stripped off. Both <code>to</code> and
<h5>Examples:</h5>
<blockquote><pre>
&lt;mapper type=&quot;merge&quot; to=&quot;archive.tar&quot;/&gt;
&lt;mergemapper to=&quot;archive.tar&quot;/&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -172,6 +196,7 @@ that don't match the <code>from</code> pattern will be ignored.</p>
<b>Examples:</b>
<blockquote><pre>
&lt;mapper type=&quot;glob&quot; from=&quot;*.java&quot; to=&quot;*.java.bak&quot;/&gt;
&lt;globmapper from=&quot;*.java&quot; to=&quot;*.java.bak&quot;/&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -197,6 +222,7 @@ that don't match the <code>from</code> pattern will be ignored.</p>
</table>
<blockquote><pre>
&lt;mapper type=&quot;glob&quot; from=&quot;C*ies&quot; to=&quot;Q*y&quot;/&gt;
&lt;globmapper from=&quot;C*ies&quot; to=&quot;Q*y&quot;/&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -267,6 +293,7 @@ jakarta-ORO and finally try jakarta-regexp.</li>
<b>Examples:</b>
<blockquote><pre>
&lt;mapper type=&quot;regexp&quot; from=&quot;^(.*)\.java$$&quot; to=&quot;\1.java.bak&quot;/&gt;
&lt;regexpmapper from=&quot;^(.*)\.java$$&quot; to=&quot;\1.java.bak&quot;/&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -292,6 +319,7 @@ jakarta-ORO and finally try jakarta-regexp.</li>
</table>
<blockquote><pre>
&lt;mapper type=&quot;regexp&quot; from=&quot;^(.*)/([^/]+)/([^/]*)$$&quot; to=&quot;\1/\2/\2-\3&quot;/&gt;
&lt;regexpmapper from=&quot;^(.*)/([^/]+)/([^/]*)$$&quot; to=&quot;\1/\2/\2-\3&quot;/&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -317,6 +345,7 @@ jakarta-ORO and finally try jakarta-regexp.</li>
</table>
<blockquote><pre>
&lt;mapper type=&quot;regexp&quot; from=&quot;^(.*)\.(.*)$$&quot; to=&quot;\2.\1&quot;/&gt;
&lt;regexpmapper from=&quot;^(.*)\.(.*)$$&quot; to=&quot;\2.\1&quot;/&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -349,8 +378,8 @@ pattern placeholder. This mapper is particularly useful in combination
with <code>&lt;uptodate&gt;</code> and <code>&lt;junit&gt;</code> output.</p>
<b>Example:</b>
<blockquote><pre>
&lt;mapper type="package"
from="*Test.java" to="TEST-*Test.xml"/&gt;
&lt;mapper type="package" from="*Test.java" to="TEST-*Test.xml"/&gt;
&lt;packagemapper from="*Test.java" to="TEST-*Test.xml"/&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -375,8 +404,8 @@ with <code>&lt;uptodate&gt;</code> and <code>&lt;junit&gt;</code> output.</p>
</p>
<b>Example:</b>
<blockquote><pre>
&lt;mapper type="unpackage"
from="TEST-*Test.xml" to="${test.src.dir}/*Test.java"&gt;
&lt;mapper type="unpackage" from="TEST-*Test.xml" to="${test.src.dir}/*Test.java"&gt;
&lt;unpackagemapper from="TEST-*Test.xml" to="${test.src.dir}/*Test.java"&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
@@ -388,7 +417,73 @@ with <code>&lt;uptodate&gt;</code> and <code>&lt;junit&gt;</code> output.</p>
<td valign="top"><code>${test.src.dir}/org/acme/AcmeTest.java</code></td>
</tr>
</table>

<h4><a name="container-mapper">container (since ant 1.7)</a></h4>
<p>This mapper implementation can contain multiple nested mappers,
and can process in one of two modes, controlled by the <i>chained</i>
attribute. In the default mode, file mapping is performed by passing
the source filename to each nested <code>&lt;mapper&gt;</code> in turn,
returning all results. When <i>chained</i> is set to <CODE>true</CODE>,
the source filename will be passed to the first nested mapper, its
results will be passed to the second, and so on. The target filenames
generated by the last nested mapper comprise the ultimate results of the
mapping operation. The <i>to</i> and <i>from</i> attributes are ignored.</p>
<b>Examples:</b>
<blockquote><pre>
&lt;containermapper&gt;
&lt;identitymapper /&gt;
&lt;packagemapper from="*.java" to="*"/&gt;
&lt;/containermapper&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td valign="top"><b>Source file name</b></td>
<td valign="top"><b>Target file names</b></td>
</tr>
<tr>
<td valign="center" rowspan="2"><code>foo/bar/A.java</code></td>
<td valign="top"><code>foo/bar/A.java</code></td>
</tr>
<tr>
<td valign="top"><code>foo.bar.A</code></td>
</tr>
</table>
<blockquote><pre>
&lt;mapper chained=&quot;true&quot;&gt;
&lt;flattenmapper /&gt;
&lt;globmapper from="*" to="new/path/*"/&gt;
&lt;mapper&gt;
&lt;globmapper from="*" to="*1"/&gt;
&lt;globmapper from="*" to="*2"/&gt;
&lt;/mapper&gt;
&lt;/mapper&gt;
</pre></blockquote>
<table border="1" cellpadding="2" cellspacing="0">
<tr>
<td valign="top"><b>Source file name</b></td>
<td valign="top"><b>Target file names</b></td>
</tr>
<tr>
<td valign="center" rowspan="2"><code>foo/bar/A.java</code></td>
<td valign="top"><code>new/path/A.java1</code></td>
</tr>
<tr>
<td valign="top"><code>new/path/A.java2</code></td>
</tr>
<tr>
<td valign="center" rowspan="2"><code>boo/far/B.java</code></td>
<td valign="top"><code>new/path/B.java1</code></td>
</tr>
<tr>
<td valign="top"><code>new/path/B.java2</code></td>
</tr>
</table>
<p>Finally, the container mapper is <b>not</b> built-in in the same sense
as the others. It is available via its own typedef,
<code>&lt;containermapper&gt;</code>, and the use of a common
<code>&lt;mapper&gt;</code> element with nested mappers will, as mentioned
previously, make implicit use of a container mapper. The container
mapper is <b>not</b> available, however (nor does it need to be), using
the common <code>&lt;mapper type=&quot;...&quot;&gt;</code> syntax.</p>
<hr>
<p align="center">Copyright &copy; 2000-2004 The Apache Software Foundation. All rights
Reserved.</p>


+ 51
- 4
src/main/org/apache/tools/ant/types/Mapper.java View File

@@ -23,6 +23,7 @@ import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.util.FileNameMapper;
import org.apache.tools.ant.util.ContainerMapper;

/**
* Element to define a FileNameMapper.
@@ -30,7 +31,9 @@ import org.apache.tools.ant.util.FileNameMapper;
*/
public class Mapper extends DataType implements Cloneable {

protected MapperType type = null;
protected MapperType type = null;
private ContainerMapper container = null;
private Boolean chained = null;

public Mapper(Project p) {
setProject(p);
@@ -48,6 +51,34 @@ public class Mapper extends DataType implements Cloneable {

protected String classname = null;

/**
* Add a nested filename mapper
* @param fileNameMapper the mapper to add
*/
public void add(FileNameMapper fileNameMapper) {
if (container == null) {
container = new ContainerMapper();
}
container.add(fileNameMapper);
}

/**
* Add a Mapper
* @param mapper the mapper to add
*/
public void addConfiguredMapper(Mapper mapper) {
add(mapper.getImplementation());
}
/**
* Set the chained attribute of the nested mapper container
* @param chained the setting for the chained attribute of the
* nested mapper container.
*/
public void setChained(Boolean chained) {
this.chained = chained;
}
/**
* Set the class name of the FileNameMapper to use.
*/
@@ -143,12 +174,28 @@ public class Mapper extends DataType implements Cloneable {
return getRef().getImplementation();
}

if (type == null && classname == null) {
throw new BuildException("one of the attributes type or classname is required");
if (type == null && classname == null && container == null) {
throw new BuildException(
"nested mapper or "
+ "one of the attributes type or classname is required");
}

if (container != null) {
if (type != null || classname != null ||
to != null || from != null) {
throw new BuildException(
"for nested mappers, type, classname, to and from" +
" attributes are not allowed");
}
if (chained != null) {
container.setChained(chained.booleanValue());
}
return container;
}

if (type != null && classname != null) {
throw new BuildException("must not specify both type and classname attribute");
throw new BuildException(
"must not specify both type and classname attribute");
}

try {


+ 10
- 0
src/main/org/apache/tools/ant/types/defaults.properties View File

@@ -7,6 +7,16 @@ filterchain=org.apache.tools.ant.types.FilterChain
filterreader=org.apache.tools.ant.types.AntFilterReader
filterset=org.apache.tools.ant.types.FilterSet
mapper=org.apache.tools.ant.types.Mapper
# different filename mappers
identitymapper=org.apache.tools.ant.util.IdentityMapper
flattenmapper=org.apache.tools.ant.util.FlatFileNameMapper
globmapper=org.apache.tools.ant.util.GlobPatternMapper
mergemapper=org.apache.tools.ant.util.MergingMapper
regexpmapper=org.apache.tools.ant.util.RegexpPatternMapper
packagemapper=org.apache.tools.ant.util.PackageNameMapper
unpackagemapper=org.apache.tools.ant.util.UnPackageNameMapper
containermapper=org.apache.tools.ant.util.ContainerMapper

path=org.apache.tools.ant.types.Path
patternset=org.apache.tools.ant.types.PatternSet
regexp=org.apache.tools.ant.types.RegularExpression


+ 129
- 0
src/main/org/apache/tools/ant/util/ContainerMapper.java View File

@@ -0,0 +1,129 @@
/*
* Copyright 2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

package org.apache.tools.ant.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.tools.ant.types.Mapper;
import org.apache.tools.ant.util.FileNameMapper;

/**
* A filenamemapper that contains other filename mappers.
* The mappers proceeded in a chain or separately.
* @see FileNameMapper
*/

public class ContainerMapper implements FileNameMapper {

private boolean chained = false;
private List mappers = new ArrayList();

/**
* Add a file name mapper.
*
* @param fileNameMapper a file name mapper.
*/
public void add(FileNameMapper fileNameMapper) {
mappers.add(fileNameMapper);
}

/**
* Add a Mapper
* @param mapper the mapper to add
*/
public void addConfiguredMapper(Mapper mapper) {
mappers.add(mapper.getImplementation());
}
/**
* Set the chained attribute.
*
* @param chained if true the mappers are processed in
* a chained fashion. The outputs of
* a mapper are the inputs for the next mapper.
* if false the mappers are processed indepentanly, the
* outputs are combined.
*/
public void setChained(boolean chained) {
this.chained = chained;
}

/**
* This method is ignored, present to fullfill the FileNameMapper
* interface.
* @param ignore this parameter is ignored.
*/
public void setFrom(String ignore) {
}

/**
* This method is ignored, present to fullfill the FileNameMapper
* interface.
* @param ignore this parameter is ignored.
*/
public void setTo(String ignore) {
}

/**
* Map a filename using the list of mappers.
*
* @param sourceFileName The filename to map.
* @return a <code>String[]</code> value or null if there
* are no mappings.
*/
public String[] mapFileName(String sourceFileName) {
List ret = new ArrayList();
if (chained) {
List inputs = new ArrayList();
ret.add(sourceFileName);
for (int i = 0; i < mappers.size(); ++i) {
inputs = ret;
ret = new ArrayList();
FileNameMapper mapper = (FileNameMapper) mappers.get(i);
for (Iterator it = inputs.iterator(); it.hasNext();) {
String[] mapped = mapper.mapFileName(
(String) it.next());
if (mapped != null) {
for (int m = 0; m < mapped.length; ++m) {
ret.add(mapped[m]);
}
}
}
if (ret.size() == 0) {
return null;
}
}
} else {
for (int i = 0; i < mappers.size(); ++i) {
FileNameMapper mapper = (FileNameMapper) mappers.get(i);
String[] mapped = mapper.mapFileName(sourceFileName);
if (mapped != null) {
for (int m = 0; m < mapped.length; ++m) {
ret.add(mapped[m]);
}
}
}
if (ret.size() == 0) {
return null;
}
}
return (String[]) ret.toArray(new String[ret.size()]);
}
}


+ 75
- 0
src/testcases/org/apache/tools/ant/types/MapperTest.java View File

@@ -26,6 +26,8 @@ import junit.framework.TestCase;
import junit.framework.AssertionFailedError;

import java.io.File;
import java.util.List;
import java.util.Arrays;

/**
* JUnit 3 testcases for org.apache.tools.ant.types.Mapper.
@@ -138,6 +140,79 @@ public class MapperTest extends TestCase {
assertEquals("a.class", result[0]);
}

public void testContainer() {
Mapper mapper1 = new Mapper(project);
Mapper.MapperType mt = new Mapper.MapperType();
mt.setValue("glob");
mapper1.setType(mt);
mapper1.setFrom("from*");
mapper1.setTo("to*");

//mix element types
FileNameMapper mapper2 = new FlatFileNameMapper();
FileNameMapper mapper3 = new MergingMapper();
mapper3.setTo("mergefile");

Mapper container = new Mapper(project);
container.addConfiguredMapper(mapper1);
container.add(mapper2);
container.add(mapper3);

FileNameMapper fileNameMapper = container.getImplementation();
String[] targets = fileNameMapper.mapFileName("fromfilename");
assertNotNull("no filenames mapped", targets);
assertEquals("wrong number of filenames mapped", 3, targets.length);
List list = Arrays.asList(targets);
assertTrue("cannot find expected target \"tofilename\"",
list.contains("tofilename"));
assertTrue("cannot find expected target \"fromfilename\"",
list.contains("fromfilename"));
assertTrue("cannot find expected target \"mergefile\"",
list.contains("mergefile"));
}

public void testChainedContainer() {

// a --> b --> c --- def
// \-- ghi

FileNameMapper mapperAB = new GlobPatternMapper();
mapperAB.setFrom("a");
mapperAB.setTo("b");

FileNameMapper mapperBC = new GlobPatternMapper();
mapperBC.setFrom("b");
mapperBC.setTo("c");

Mapper mapperCX = new Mapper(project);

FileNameMapper mapperDEF = new GlobPatternMapper();
mapperDEF.setFrom("c");
mapperDEF.setTo("def");

FileNameMapper mapperGHI = new GlobPatternMapper();
mapperGHI.setFrom("c");
mapperGHI.setTo("ghi");

mapperCX.add(mapperDEF);
mapperCX.add(mapperGHI);

ContainerMapper chained = new ContainerMapper();
chained.setChained(true);
chained.add(mapperAB);
chained.add(mapperBC);
chained.addConfiguredMapper(mapperCX);

String[] targets = chained.mapFileName("a");
assertNotNull("no filenames mapped", targets);
assertEquals("wrong number of filenames mapped", 2, targets.length);
List list = Arrays.asList(targets);
assertTrue("cannot find expected target \"def\"",
list.contains("def"));
assertTrue("cannot find expected target \"ghi\"",
list.contains("ghi"));
}

public void testCopyTaskWithTwoFilesets() {
TaskdefForCopyTest t = new TaskdefForCopyTest("test1");
try {


Loading…
Cancel
Save