mbenson 2004/04/22 13:27:21 Modified: src/main/org/apache/tools/ant/util ContainerMapper.java docs/manual/CoreTypes mapper.html src/main/org/apache/tools/ant/types Mapper.java defaults.properties src/testcases/org/apache/tools/ant/types MapperTest.java Added: src/main/org/apache/tools/ant/util ChainedMapper.java CompositeMapper.java Log: Make ContainerMapper abstract; move chained/composite behaviors to subclasses ChainedMapper and CompositeMapper, respectively. Revision Changes Path 1.3 +49 -77 ant/src/main/org/apache/tools/ant/util/ContainerMapper.java Index: ContainerMapper.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/util/ContainerMapper.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- ContainerMapper.java 15 Mar 2004 17:26:34 -0000 1.2 +++ ContainerMapper.java 22 Apr 2004 20:27:21 -0000 1.3 @@ -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 <code>FileNameMapper</code> that contains + * other <CODE>FileNameMapper</CODE>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 <code>Mapper</code>. + * @param mapper the <code>Mapper</code> 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 - */ - public void addConfiguredMapper(Mapper mapper) { - mappers.add(mapper.getImplementation()); + * Add a <code>FileNameMapper</code>. + * @param fileNameMapper a <CODE>FileNameMapper</CODE>. + * @throws <CODE>IllegalArgumentException</CODE> if attempting to add this + * <CODE>ContainerMapper</CODE> to itself, or if the specified + * <CODE>FileNameMapper</CODE> is itself a <CODE>ContainerMapper</CODE> + * that contains this <CODE>ContainerMapper</CODE>. + */ + 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); + } + } + + /** + * Return <CODE>true</CODE> if this <CODE>ContainerMapper</CODE> or any of + * its sub-elements contains the specified <CODE>FileNameMapper</CODE>. + * @param fileNameMapper the <CODE>FileNameMapper</CODE> to search for. + * @return <CODE>boolean</CODE>. + */ + 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; } /** - * 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. + * Get the <CODE>List</CODE> of <CODE>FileNameMapper</CODE>s. + * @return <CODE>List</CODE>. */ - public void setChained(boolean chained) { - this.chained = chained; + 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 setFrom(String ignore) { } /** - * This method is ignored, present to fullfill the FileNameMapper - * interface. - * @param ignore this parameter is ignored. + * Empty implementation. */ 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()]); - } } 1.1 ant/src/main/org/apache/tools/ant/util/ChainedMapper.java Index: ChainedMapper.java =================================================================== /* * 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 <CODE>ContainerMapper</CODE> that chains the results of the first * nested <CODE>FileNameMapper</CODE>s into sourcefiles for the second, * the second to the third, and so on, returning the resulting mapped * filenames from the last nested <CODE>FileNameMapper</CODE>. */ 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()]); } } 1.1 ant/src/main/org/apache/tools/ant/util/CompositeMapper.java Index: CompositeMapper.java =================================================================== /* * 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 <CODE>ContainerMapper</CODE> that unites the results of its constituent * <CODE>FileNameMapper</CODE>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()]); } } 1.17 +28 -34 ant/docs/manual/CoreTypes/mapper.html Index: mapper.html =================================================================== RCS file: /home/cvs/ant/docs/manual/CoreTypes/mapper.html,v retrieving revision 1.16 retrieving revision 1.17 diff -u -r1.16 -r1.17 --- mapper.html 11 Mar 2004 19:25:48 -0000 1.16 +++ mapper.html 22 Apr 2004 20:27:21 -0000 1.17 @@ -32,7 +32,7 @@ <tr> <td valign="top">type</td> <td valign="top">specifies one of the built-in implementations.</td> - <td rowspan="2" align="center" valign="middle">Exactly one of both</td> + <td rowspan="2" align="center" valign="middle">Exactly one of these</td> </tr> <tr> <td valign="top">classname</td> @@ -62,12 +62,6 @@ 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><mapper></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 @@ -77,18 +71,17 @@ <p>The classpath can be specified via a nested <code><classpath></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 +<p><b>Since Ant 1.6.2,</b> nested File Mappers can be supplied via either <CODE><mapper></CODE> elements or <a href="../CoreTasks/typedef.html"><code><typedef></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>. +If nested File Mappers are specified by either means, the mapper will be +implicitly configured as a <a href="#composite-mapper">composite 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 +<p><b>As of Ant 1.6.2,</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/> @@ -395,7 +388,7 @@ <td valign="top">ignored</td> </tr> </table> -<h4><a name="unpackage-mapper">unpackage (since ant 1.6)</a></h4> +<h4><a name="unpackage-mapper">unpackage (since ant 1.6.0)</a></h4> <p>This mapper is the inverse of the <a href="#package-mapper">package</a> 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 @@ <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><mapper></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> +<h4><a name="composite-mapper">composite (since ant 1.6.2)</a></h4> + <p>This mapper implementation can contain multiple nested mappers. + File mapping is performed by passing the source filename to each nested + <code><mapper></code> in turn, returning all results. + The <i>to</i> and <i>from</i> attributes are ignored.</p> <b>Examples:</b> <blockquote><pre> -<containermapper> +<compositemapper> <identitymapper /> <packagemapper from="*.java" to="*"/> -</containermapper> +</compositemapper> </pre></blockquote> <table border="1" cellpadding="2" cellspacing="0"> <tr> @@ -447,15 +435,25 @@ <td valign="top"><code>foo.bar.A</code></td> </tr> </table> + <p>The composite mapper has no corresponding + <code><mapper <b>type</b>></code> attribute. + </p> +<h4><a name="chained-mapper">chained (since ant 1.6.2)</a></h4> + <p>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 <i>to</i> and <i>from</i> attributes are ignored.</p> +<b>Examples:</b> <blockquote><pre> -<mapper chained="true"> +<chainedmapper> <flattenmapper /> <globmapper from="*" to="new/path/*"/> <mapper> <globmapper from="*" to="*1"/> <globmapper from="*" to="*2"/> </mapper> -</mapper> +</chainedmapper> </pre></blockquote> <table border="1" cellpadding="2" cellspacing="0"> <tr> @@ -477,13 +475,9 @@ <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><containermapper></code>, and the use of a common - <code><mapper></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><mapper type="..."></code> syntax.</p> + <p>The chained mapper has no corresponding + <code><mapper <b>type</b>></code> attribute. + </p> <hr> <p align="center">Copyright © 2000-2004 The Apache Software Foundation. All rights Reserved.</p> 1.28 +52 -51 ant/src/main/org/apache/tools/ant/types/Mapper.java Index: Mapper.java =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/types/Mapper.java,v retrieving revision 1.27 retrieving revision 1.28 diff -u -r1.27 -r1.28 --- Mapper.java 11 Mar 2004 19:25:48 -0000 1.27 +++ Mapper.java 22 Apr 2004 20:27:21 -0000 1.28 @@ -23,6 +23,7 @@ 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 @@ */ 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 new <CODE>Mapper</CODE> element. + * @param p the owning Ant <CODE>Project</CODE>. + */ public Mapper(Project p) { setProject(p); } /** - * Set the type of FileNameMapper to use. + * Set the type of <code>FileNameMapper</code> to use. + * @param type the <CODE>MapperType</CODE> enumerated attribute. */ public void setType(MapperType type) { if (isReference()) { @@ -49,15 +59,26 @@ this.type = type; } - protected String classname = null; - /** - * Add a nested filename mapper - * @param fileNameMapper the mapper to add + * Add a nested <CODE>FileNameMapper</CODE>. + * @param fileNameMapper the <CODE>FileNameMapper</CODE> 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 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 @@ this.classname = classname; } - protected Path classpath = null; - /** * Set the classpath to load the FileNameMapper through (attribute). */ @@ -129,8 +139,6 @@ createClasspath().setRefid(r); } - protected String from = null; - /** * Set the argument to FileNameMapper.setFrom */ @@ -141,8 +149,6 @@ this.from = from; } - protected String to = null; - /** * Set the argument to FileNameMapper.setTo */ @@ -181,15 +187,6 @@ } 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,35 +196,39 @@ } 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 <CODE>Class</CODE>. + */ + 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); } /** 1.24 +2 -1 ant/src/main/org/apache/tools/ant/types/defaults.properties Index: defaults.properties =================================================================== RCS file: /home/cvs/ant/src/main/org/apache/tools/ant/types/defaults.properties,v retrieving revision 1.23 retrieving revision 1.24 diff -u -r1.23 -r1.24 --- defaults.properties 27 Mar 2004 21:33:49 -0000 1.23 +++ defaults.properties 22 Apr 2004 20:27:21 -0000 1.24 @@ -16,7 +16,8 @@ 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 1.15 +9 -9 ant/src/testcases/org/apache/tools/ant/types/MapperTest.java Index: MapperTest.java =================================================================== RCS file: /home/cvs/ant/src/testcases/org/apache/tools/ant/types/MapperTest.java,v retrieving revision 1.14 retrieving revision 1.15 diff -u -r1.14 -r1.15 --- MapperTest.java 11 Mar 2004 19:25:48 -0000 1.14 +++ MapperTest.java 22 Apr 2004 20:27:21 -0000 1.15 @@ -140,7 +140,7 @@ 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 @@ list.contains("mergefile")); } - public void testChainedContainer() { + public void testChained() { // a --> b --> c --- def // \-- ghi @@ -184,6 +184,7 @@ mapperBC.setFrom("b"); mapperBC.setTo("c"); + //implicit composite Mapper mapperCX = new Mapper(project); FileNameMapper mapperDEF = new GlobPatternMapper(); @@ -197,20 +198,19 @@ 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() {
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]