From 2ead66e52c56fbc1a59789187ddba634ebe4ae2d Mon Sep 17 00:00:00 2001
From: Matthew Jason Benson
<mapper>
s.
- Since Ant 1.7false
.Note that Ant will not automatically convert / or \ characters in
the to
and from
attributes to the correct
@@ -77,18 +71,17 @@ this separator, use ${file.separator}
instead.
The classpath can be specified via a nested
<classpath>
, as well - that is,
a path-like structure.
Since Ant 1.7, nested File Mappers can +
Since Ant 1.6.2, nested File Mappers can
be supplied via either <mapper>
elements or
<typedef>
'd
implementations of org.apache.tools.ant.util.FileNameMapper
.
-If one or more nested File Mappers are specified using either convention,
-only the chained attribute will be considered in the configuration
-of the implicitly used container mapper.
+If nested File Mappers are specified by either means, the mapper will be
+implicitly configured as a composite mapper.
All built-in mappers are case-sensitive.
-As of Ant 1.7, each of the built-in mapper implementation +
As of Ant 1.6.2, 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 to and from.
@@ -395,7 +388,7 @@ with <uptodate>
and <junit>
output.
This mapper is the inverse of the package mapper.
It replaces the dots in a package name with directory separators. This
is useful for matching XML formatter results against their JUnit test
@@ -417,22 +410,17 @@ with <uptodate>
and <junit>
output.
${test.src.dir}/org/acme/AcmeTest.java
This mapper implementation can contain multiple nested mappers,
- and can process in one of two modes, controlled by the chained
- attribute. In the default mode, file mapping is performed by passing
- the source filename to each nested <mapper>
in turn,
- returning all results. When chained is set to true
,
- 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 to and from attributes are ignored.
This mapper implementation can contain multiple nested mappers.
+ File mapping is performed by passing the source filename to each nested
+ <mapper>
in turn, returning all results.
+ The to and from attributes are ignored.
-<containermapper> +<compositemapper> <identitymapper /> <packagemapper from="*.java" to="*"/> -</containermapper> +</compositemapper>
foo.bar.A |
The composite mapper has no corresponding
+ <mapper type>
attribute.
+
This mapper implementation can contain multiple nested mappers. + File mapping is performed by passing the source filename to the first + nested mapper, its results to the second, and so on. The target filenames + generated by the last nested mapper comprise the ultimate results of the + mapping operation. The to and from attributes are ignored.
+Examples:-<mapper chained="true"> +<chainedmapper> <flattenmapper /> <globmapper from="*" to="new/path/*"/> <mapper> <globmapper from="*" to="*1"/> <globmapper from="*" to="*2"/> </mapper> -</mapper> +</chainedmapper>
new/path/B.java2 |
Finally, the container mapper is not built-in in the same sense
- as the others. It is available via its own typedef,
- <containermapper>
, and the use of a common
- <mapper>
element with nested mappers will, as mentioned
- previously, make implicit use of a container mapper. The container
- mapper is not available, however (nor does it need to be), using
- the common <mapper type="...">
syntax.
The chained mapper has no corresponding
+ <mapper type>
attribute.
+
Copyright © 2000-2004 The Apache Software Foundation. All rights Reserved.
diff --git a/src/main/org/apache/tools/ant/types/Mapper.java b/src/main/org/apache/tools/ant/types/Mapper.java index f77746d54..64c5cae5e 100644 --- a/src/main/org/apache/tools/ant/types/Mapper.java +++ b/src/main/org/apache/tools/ant/types/Mapper.java @@ -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.CompositeMapper; import org.apache.tools.ant.util.ContainerMapper; /** @@ -31,16 +32,25 @@ import org.apache.tools.ant.util.ContainerMapper; */ public class Mapper extends DataType implements Cloneable { - protected MapperType type = null; - private ContainerMapper container = null; - private Boolean chained = null; + protected MapperType type = null; + protected String classname = null; + protected Path classpath = null; + protected String from = null; + protected String to = null; + + private ContainerMapper container = null; + /** + * Construct a newMapper
element.
+ * @param p the owning Ant Project
.
+ */
public Mapper(Project p) {
setProject(p);
}
/**
- * Set the type of FileNameMapper to use.
+ * Set the type of FileNameMapper
to use.
+ * @param type the MapperType
enumerated attribute.
*/
public void setType(MapperType type) {
if (isReference()) {
@@ -49,15 +59,26 @@ public class Mapper extends DataType implements Cloneable {
this.type = type;
}
- protected String classname = null;
-
/**
- * Add a nested filename mapper
- * @param fileNameMapper the mapper to add
+ * Add a nested FileNameMapper
.
+ * @param fileNameMapper the FileNameMapper
to add.
*/
public void add(FileNameMapper fileNameMapper) {
+ if (isReference()) {
+ throw noChildrenAllowed();
+ }
if (container == null) {
- container = new ContainerMapper();
+ if (type == null && classname == null) {
+ container = new CompositeMapper();
+ } else {
+ FileNameMapper m = getImplementation();
+ if (m instanceof ContainerMapper) {
+ container = (ContainerMapper)m;
+ } else {
+ throw new BuildException(String.valueOf(m)
+ + " mapper implementation does not support nested mappers!");
+ }
+ }
}
container.add(fileNameMapper);
}
@@ -69,16 +90,7 @@ public class Mapper extends DataType implements Cloneable {
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.
*/
@@ -89,8 +101,6 @@ public class Mapper extends DataType implements Cloneable {
this.classname = classname;
}
- protected Path classpath = null;
-
/**
* Set the classpath to load the FileNameMapper through (attribute).
*/
@@ -129,8 +139,6 @@ public class Mapper extends DataType implements Cloneable {
createClasspath().setRefid(r);
}
- protected String from = null;
-
/**
* Set the argument to FileNameMapper.setFrom
*/
@@ -141,8 +149,6 @@ public class Mapper extends DataType implements Cloneable {
this.from = from;
}
- protected String to = null;
-
/**
* Set the argument to FileNameMapper.setTo
*/
@@ -181,15 +187,6 @@ public class Mapper extends DataType implements Cloneable {
}
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;
}
@@ -199,37 +196,41 @@ public class Mapper extends DataType implements Cloneable {
}
try {
- if (type != null) {
- classname = type.getImplementation();
- }
-
- Class c = null;
- if (classpath == null) {
- c = Class.forName(classname);
- } else {
- AntClassLoader al = getProject().createClassLoader(classpath);
- c = Class.forName(classname, true, al);
- }
-
- FileNameMapper m = (FileNameMapper) c.newInstance();
+ FileNameMapper m
+ = (FileNameMapper)(getImplementationClass().newInstance());
final Project project = getProject();
if (project != null) {
project.setProjectReference(m);
}
m.setFrom(from);
m.setTo(to);
+
return m;
} catch (BuildException be) {
throw be;
} catch (Throwable t) {
throw new BuildException(t);
- } finally {
- if (type != null) {
- classname = null;
- }
}
}
+ /**
+ * Gets the Class object associated with the mapper implementation.
+ * @return Class
.
+ */
+ protected Class getImplementationClass() throws ClassNotFoundException {
+
+ String classname = this.classname;
+ if (type != null) {
+ classname = type.getImplementation();
+ }
+
+ ClassLoader loader = (classpath == null)
+ ? getClass().getClassLoader()
+ : getProject().createClassLoader(classpath);
+
+ return Class.forName(classname, true, loader);
+ }
+
/**
* Performs the check for circular references and returns the
* referenced Mapper.
diff --git a/src/main/org/apache/tools/ant/types/defaults.properties b/src/main/org/apache/tools/ant/types/defaults.properties
index bd1006d6f..55f1e96e5 100644
--- a/src/main/org/apache/tools/ant/types/defaults.properties
+++ b/src/main/org/apache/tools/ant/types/defaults.properties
@@ -16,7 +16,8 @@ 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
+compositemapper=org.apache.tools.ant.util.CompositeMapper
+chainedmapper=org.apache.tools.ant.util.ChainedMapper
path=org.apache.tools.ant.types.Path
patternset=org.apache.tools.ant.types.PatternSet
diff --git a/src/main/org/apache/tools/ant/util/ChainedMapper.java b/src/main/org/apache/tools/ant/util/ChainedMapper.java
new file mode 100755
index 000000000..7d52fd4c6
--- /dev/null
+++ b/src/main/org/apache/tools/ant/util/ChainedMapper.java
@@ -0,0 +1,60 @@
+/*
+ * 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.List;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.ArrayList;
+import org.apache.tools.ant.types.Mapper;
+
+/**
+ * A ContainerMapper
that chains the results of the first
+ * nested FileNameMapper
s into sourcefiles for the second,
+ * the second to the third, and so on, returning the resulting mapped
+ * filenames from the last nested FileNameMapper
.
+ */
+public class ChainedMapper extends ContainerMapper {
+
+ //inherit doc
+ public String[] mapFileName(String sourceFileName) {
+ List inputs = new ArrayList();
+ List results = new ArrayList();
+ results.add(sourceFileName);
+ FileNameMapper mapper = null;
+
+ for (Iterator mIter = getMappers().iterator(); mIter.hasNext();) {
+ mapper = (FileNameMapper)(mIter.next());
+ if (mapper != null) {
+ inputs.clear();
+ inputs.addAll(results);
+ results.clear();
+
+ for (Iterator it = inputs.iterator(); it.hasNext();) {
+ String[] mapped = mapper.mapFileName((String)(it.next()));
+ if (mapped != null) {
+ results.addAll(Arrays.asList(mapped));
+ }
+ }
+ }
+ }
+ return (results.size() == 0) ? null
+ : (String[]) results.toArray(new String[results.size()]);
+ }
+}
+
diff --git a/src/main/org/apache/tools/ant/util/CompositeMapper.java b/src/main/org/apache/tools/ant/util/CompositeMapper.java
new file mode 100755
index 000000000..3b30fe5b3
--- /dev/null
+++ b/src/main/org/apache/tools/ant/util/CompositeMapper.java
@@ -0,0 +1,48 @@
+/*
+ * 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.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+
+/**
+ * A ContainerMapper
that unites the results of its constituent
+ * FileNameMapper
s into a single set of result filenames.
+ */
+public class CompositeMapper extends ContainerMapper {
+
+ //inherit doc
+ public String[] mapFileName(String sourceFileName) {
+ HashSet results = new HashSet();
+
+ FileNameMapper mapper = null;
+ for (Iterator mIter = getMappers().iterator(); mIter.hasNext();) {
+ mapper = (FileNameMapper)(mIter.next());
+ if (mapper != null) {
+ String[] mapped = mapper.mapFileName(sourceFileName);
+ if (mapped != null) {
+ results.addAll(Arrays.asList(mapped));
+ }
+ }
+ }
+ return (results.size() == 0) ? null
+ : (String[]) results.toArray(new String[results.size()]);
+ }
+
+}
+
diff --git a/src/main/org/apache/tools/ant/util/ContainerMapper.java b/src/main/org/apache/tools/ant/util/ContainerMapper.java
index 9c6bdf37f..8731ae5e6 100755
--- a/src/main/org/apache/tools/ant/util/ContainerMapper.java
+++ b/src/main/org/apache/tools/ant/util/ContainerMapper.java
@@ -17,112 +17,84 @@
package org.apache.tools.ant.util;
-import java.util.ArrayList;
-import java.util.Iterator;
import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Collections;
import org.apache.tools.ant.types.Mapper;
/**
- * A filenamemapper that contains other filename mappers.
- * The mappers proceeded in a chain or separately.
+ * A FileNameMapper
that contains
+ * other FileNameMapper
s.
* @see FileNameMapper
*/
+public abstract class ContainerMapper implements 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.
+ * Add a Mapper
.
+ * @param mapper the Mapper
to add.
*/
- public void add(FileNameMapper fileNameMapper) {
- mappers.add(fileNameMapper);
+ public void addConfiguredMapper(Mapper mapper) {
+ add(mapper.getImplementation());
}
/**
- * Add a Mapper
- * @param mapper the mapper to add
+ * Add a FileNameMapper
.
+ * @param fileNameMapper a FileNameMapper
.
+ * @throws IllegalArgumentException
if attempting to add this
+ * ContainerMapper
to itself, or if the specified
+ * FileNameMapper
is itself a ContainerMapper
+ * that contains this ContainerMapper
.
*/
- public void addConfiguredMapper(Mapper mapper) {
- mappers.add(mapper.getImplementation());
+ public synchronized void add(FileNameMapper fileNameMapper) {
+ if (this == fileNameMapper
+ || (fileNameMapper instanceof ContainerMapper
+ && ((ContainerMapper)fileNameMapper).contains(this))) {
+ throw new IllegalArgumentException(
+ "Circular mapper containment condition detected");
+ } else {
+ mappers.add(fileNameMapper);
+ }
}
/**
- * 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.
+ * Return true
if this ContainerMapper
or any of
+ * its sub-elements contains the specified FileNameMapper
.
+ * @param fileNameMapper the FileNameMapper
to search for.
+ * @return boolean
.
*/
- public void setChained(boolean chained) {
- this.chained = chained;
+ protected synchronized boolean contains(FileNameMapper fileNameMapper) {
+ boolean foundit = false;
+ for (Iterator iter = mappers.iterator(); iter.hasNext() && !foundit;) {
+ FileNameMapper next = (FileNameMapper)(iter.next());
+ foundit|= (next == fileNameMapper
+ || (next instanceof ContainerMapper
+ && ((ContainerMapper)next).contains(fileNameMapper)));
+ }
+ return foundit;
}
/**
- * This method is ignored, present to fullfill the FileNameMapper
- * interface.
- * @param ignore this parameter is ignored.
+ * Get the List
of FileNameMapper
s.
+ * @return List
.
*/
- public void setFrom(String ignore) {
+ public synchronized List getMappers() {
+ return Collections.unmodifiableList(mappers);
}
/**
- * This method is ignored, present to fullfill the FileNameMapper
- * interface.
- * @param ignore this parameter is ignored.
+ * Empty implementation.
*/
- public void setTo(String ignore) {
+ public void setFrom(String ignore) {
}
/**
- * Map a filename using the list of mappers.
- *
- * @param sourceFileName The filename to map.
- * @return a String[]
value or null if there
- * are no mappings.
+ * Empty implementation.
*/
- 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()]);
+ public void setTo(String ignore) {
}
+
}
diff --git a/src/testcases/org/apache/tools/ant/types/MapperTest.java b/src/testcases/org/apache/tools/ant/types/MapperTest.java
index 1f46384fe..d377275c4 100644
--- a/src/testcases/org/apache/tools/ant/types/MapperTest.java
+++ b/src/testcases/org/apache/tools/ant/types/MapperTest.java
@@ -140,7 +140,7 @@ public class MapperTest extends TestCase {
assertEquals("a.class", result[0]);
}
- public void testContainer() {
+ public void testNested() {
Mapper mapper1 = new Mapper(project);
Mapper.MapperType mt = new Mapper.MapperType();
mt.setValue("glob");
@@ -171,7 +171,7 @@ public class MapperTest extends TestCase {
list.contains("mergefile"));
}
- public void testChainedContainer() {
+ public void testChained() {
// a --> b --> c --- def
// \-- ghi
@@ -184,6 +184,7 @@ public class MapperTest extends TestCase {
mapperBC.setFrom("b");
mapperBC.setTo("c");
+ //implicit composite
Mapper mapperCX = new Mapper(project);
FileNameMapper mapperDEF = new GlobPatternMapper();
@@ -197,20 +198,19 @@ public class MapperTest extends TestCase {
mapperCX.add(mapperDEF);
mapperCX.add(mapperGHI);
- ContainerMapper chained = new ContainerMapper();
- chained.setChained(true);
+ Mapper chained = new Mapper(project);
+ chained.setClassname(ChainedMapper.class.getName());
chained.add(mapperAB);
chained.add(mapperBC);
chained.addConfiguredMapper(mapperCX);
- String[] targets = chained.mapFileName("a");
+ FileNameMapper fileNameMapper = chained.getImplementation();
+ String[] targets = fileNameMapper.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"));
+ assertTrue("cannot find expected target \"def\"", list.contains("def"));
+ assertTrue("cannot find expected target \"ghi\"", list.contains("ghi"));
}
public void testCopyTaskWithTwoFilesets() {