KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > PathConvert


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18 package org.apache.tools.ant.taskdefs;
19
20 import java.io.File JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.Vector JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.StringTokenizer JavaDoc;
25 import org.apache.tools.ant.Task;
26 import org.apache.tools.ant.Project;
27 import org.apache.tools.ant.BuildException;
28 import org.apache.tools.ant.taskdefs.condition.Os;
29 import org.apache.tools.ant.types.Path;
30 import org.apache.tools.ant.types.Mapper;
31 import org.apache.tools.ant.types.Reference;
32 import org.apache.tools.ant.types.ResourceCollection;
33 import org.apache.tools.ant.types.EnumeratedAttribute;
34 import org.apache.tools.ant.types.resources.Union;
35 import org.apache.tools.ant.util.FileNameMapper;
36
37 /**
38  * Converts path and classpath information to a specific target OS
39  * format. The resulting formatted path is placed into the specified property.
40  *
41  * @since Ant 1.4
42  * @ant.task category="utility"
43  */

44 public class PathConvert extends Task {
45
46     /**
47      * Set if we're running on windows
48      */

49     private static boolean onWindows = Os.isFamily("dos");
50
51     // Members
52
/**
53      * Path to be converted
54      */

55     private Union path = null;
56     /**
57      * Reference to path/fileset to convert
58      */

59     private Reference refid = null;
60     /**
61      * The target OS type
62      */

63     private String JavaDoc targetOS = null;
64     /**
65      * Set when targetOS is set to windows
66      */

67     private boolean targetWindows = false;
68     /**
69      * Set if we should create a new property even if the result is empty
70      */

71     private boolean setonempty = true;
72     /**
73      * The property to receive the conversion
74      */

75     private String JavaDoc property = null;
76     /**
77      * Path prefix map
78      */

79     private Vector JavaDoc prefixMap = new Vector JavaDoc();
80     /**
81      * User override on path sep char
82      */

83     private String JavaDoc pathSep = null;
84     /**
85      * User override on directory sep char
86      */

87     private String JavaDoc dirSep = null;
88
89     /** Filename mapper */
90     private Mapper mapper = null;
91
92     /**
93      * Construct a new instance of the PathConvert task.
94      */

95     public PathConvert() {
96     }
97
98     /**
99      * Helper class, holds the nested <map> values. Elements will look like
100      * this: <map from="d:" to="/foo"/>
101      *
102      * When running on windows, the prefix comparison will be case
103      * insensitive.
104      */

105     public class MapEntry {
106
107         // Members
108
private String JavaDoc from = null;
109         private String JavaDoc to = null;
110
111         /**
112          * Set the "from" attribute of the map entry.
113          * @param from the prefix string to search for; required.
114          * Note that this value is case-insensitive when the build is
115          * running on a Windows platform and case-sensitive when running on
116          * a Unix platform.
117          */

118         public void setFrom(String JavaDoc from) {
119             this.from = from;
120         }
121
122         /**
123          * Set the replacement text to use when from is matched; required.
124          * @param to new prefix.
125          */

126         public void setTo(String JavaDoc to) {
127             this.to = to;
128         }
129
130         /**
131          * Apply this map entry to a given path element.
132          *
133          * @param elem Path element to process.
134          * @return String Updated path element after mapping.
135          */

136         public String JavaDoc apply(String JavaDoc elem) {
137             if (from == null || to == null) {
138                 throw new BuildException("Both 'from' and 'to' must be set "
139                      + "in a map entry");
140             }
141             // If we're on windows, then do the comparison ignoring case
142
// and treat the two directory characters the same
143
String JavaDoc cmpElem =
144                 onWindows ? elem.toLowerCase().replace('\\', '/') : elem;
145             String JavaDoc cmpFrom =
146                 onWindows ? from.toLowerCase().replace('\\', '/') : from;
147
148             // If the element starts with the configured prefix, then
149
// convert the prefix to the configured 'to' value.
150

151             return cmpElem.startsWith(cmpFrom)
152                 ? to + elem.substring(from.length()) : elem;
153         }
154     }
155
156     /**
157      * An enumeration of supported targets:
158      * "windows", "unix", "netware", and "os/2".
159      */

160     public static class TargetOs extends EnumeratedAttribute {
161         /**
162          * @return the list of values for this enumerated attribute.
163          */

164         public String JavaDoc[] getValues() {
165             return new String JavaDoc[]{"windows", "unix", "netware", "os/2", "tandem"};
166         }
167     }
168
169     /**
170      * Create a nested path element.
171      * @return a Path to be used by Ant reflection.
172      */

173     public Path createPath() {
174         if (isReference()) {
175             throw noChildrenAllowed();
176         }
177         Path result = new Path(getProject());
178         add(result);
179         return result;
180     }
181
182     /**
183      * Add an arbitrary ResourceCollection.
184      * @param rc the ResourceCollection to add.
185      * @since Ant 1.7
186      */

187     public void add(ResourceCollection rc) {
188         if (isReference()) {
189             throw noChildrenAllowed();
190         }
191         getPath().add(rc);
192     }
193
194     private synchronized Union getPath() {
195         if (path == null) {
196             path = new Union();
197             path.setProject(getProject());
198         }
199         return path;
200     }
201
202     /**
203      * Create a nested MAP element.
204      * @return a Map to configure.
205      */

206     public MapEntry createMap() {
207         MapEntry entry = new MapEntry();
208         prefixMap.addElement(entry);
209         return entry;
210     }
211
212     /**
213      * Set targetos to a platform to one of
214      * "windows", "unix", "netware", or "os/2";
215      * current platform settings are used by default.
216      * @param target the target os.
217      * @deprecated since 1.5.x.
218      * Use the method taking a TargetOs argument instead.
219      * @see #setTargetos(PathConvert.TargetOs)
220      */

221     public void setTargetos(String JavaDoc target) {
222         TargetOs to = new TargetOs();
223         to.setValue(target);
224         setTargetos(to);
225     }
226
227     /**
228      * Set targetos to a platform to one of
229      * "windows", "unix", "netware", or "os/2";
230      * current platform settings are used by default.
231      * @param target the target os
232      *
233      * @since Ant 1.5
234      */

235     public void setTargetos(TargetOs target) {
236         targetOS = target.getValue();
237
238         // Currently, we deal with only two path formats: Unix and Windows
239
// And Unix is everything that is not Windows
240

241         // for NetWare and OS/2, piggy-back on Windows, since in the
242
// validateSetup code, the same assumptions can be made as
243
// with windows - that ; is the path separator
244

245         targetWindows = !targetOS.equals("unix") && !targetOS.equals("tandem");
246     }
247
248     /**
249      * Set whether the specified property will be set if the result
250      * is the empty string.
251      * @param setonempty true or false.
252      *
253      * @since Ant 1.5
254      */

255      public void setSetonempty(boolean setonempty) {
256          this.setonempty = setonempty;
257      }
258
259     /**
260      * Set the name of the property into which the converted path will be placed.
261      * @param p the property name.
262      */

263     public void setProperty(String JavaDoc p) {
264         property = p;
265     }
266
267     /**
268      * Add a reference to a Path, FileSet, DirSet, or FileList defined elsewhere.
269      * @param r the reference to a path, fileset, dirset or filelist.
270      */

271     public void setRefid(Reference r) {
272         if (path != null) {
273             throw noChildrenAllowed();
274         }
275         refid = r;
276     }
277
278     /**
279      * Set the default path separator string; defaults to current JVM
280      * {@link java.io.File#pathSeparator File.pathSeparator}.
281      * @param sep path separator string.
282      */

283     public void setPathSep(String JavaDoc sep) {
284         pathSep = sep;
285     }
286
287
288     /**
289      * Set the default directory separator string;
290      * defaults to current JVM {@link java.io.File#separator File.separator}.
291      * @param sep directory separator string.
292      */

293     public void setDirSep(String JavaDoc sep) {
294         dirSep = sep;
295     }
296
297     /**
298      * Learn whether the refid attribute of this element been set.
299      * @return true if refid is valid.
300      */

301     public boolean isReference() {
302         return refid != null;
303     }
304
305     /**
306      * Do the execution.
307      * @throws BuildException if something is invalid.
308      */

309     public void execute() throws BuildException {
310         Union savedPath = path;
311         String JavaDoc savedPathSep = pathSep; // may be altered in validateSetup
312
String JavaDoc savedDirSep = dirSep; // may be altered in validateSetup
313

314         try {
315             // If we are a reference, create a Path from the reference
316
if (isReference()) {
317                 Object JavaDoc o = refid.getReferencedObject(getProject());
318                 if (!(o instanceof ResourceCollection)) {
319                     throw new BuildException("refid '" + refid.getRefId()
320                         + "' does not refer to a resource collection.");
321                 }
322                 getPath().add((ResourceCollection) o);
323             }
324             validateSetup(); // validate our setup
325

326             // Currently, we deal with only two path formats: Unix and Windows
327
// And Unix is everything that is not Windows
328
// (with the exception for NetWare and OS/2 below)
329

330             // for NetWare and OS/2, piggy-back on Windows, since here and
331
// in the apply code, the same assumptions can be made as with
332
// windows - that \\ is an OK separator, and do comparisons
333
// case-insensitive.
334
String JavaDoc fromDirSep = onWindows ? "\\" : "/";
335
336             StringBuffer JavaDoc rslt = new StringBuffer JavaDoc();
337
338             // Get the list of path components in canonical form
339
String JavaDoc[] elems = path.list();
340
341             if (mapper != null) {
342                 FileNameMapper impl = mapper.getImplementation();
343                 List JavaDoc ret = new ArrayList JavaDoc();
344                 for (int i = 0; i < elems.length; ++i) {
345                     String JavaDoc[] mapped = impl.mapFileName(elems[i]);
346                     for (int m = 0; mapped != null && m < mapped.length; ++m) {
347                         ret.add(mapped[m]);
348                     }
349                 }
350                 elems = (String JavaDoc[]) ret.toArray(new String JavaDoc[ret.size()]);
351             }
352             for (int i = 0; i < elems.length; i++) {
353                 String JavaDoc elem = mapElement(elems[i]); // Apply the path prefix map
354

355                 // Now convert the path and file separator characters from the
356
// current os to the target os.
357

358                 if (i != 0) {
359                     rslt.append(pathSep);
360                 }
361                 StringTokenizer JavaDoc stDirectory =
362                     new StringTokenizer JavaDoc(elem, fromDirSep, true);
363
364                 while (stDirectory.hasMoreTokens()) {
365                     String JavaDoc token = stDirectory.nextToken();
366                     rslt.append(fromDirSep.equals(token) ? dirSep : token);
367                 }
368             }
369             // Place the result into the specified property,
370
// unless setonempty == false
371
if (setonempty || rslt.length() > 0) {
372                 String JavaDoc value = rslt.toString();
373                 if (property == null) {
374                     log(value);
375                 } else {
376                     log("Set property " + property + " = " + value,
377                         Project.MSG_VERBOSE);
378                     getProject().setNewProperty(property, value);
379                 }
380             }
381         } finally {
382             path = savedPath;
383             dirSep = savedDirSep;
384             pathSep = savedPathSep;
385         }
386     }
387
388     /**
389      * Apply the configured map to a path element. The map is used to convert
390      * between Windows drive letters and Unix paths. If no map is configured,
391      * then the input string is returned unchanged.
392      *
393      * @param elem The path element to apply the map to.
394      * @return String Updated element.
395      */

396     private String JavaDoc mapElement(String JavaDoc elem) {
397
398         int size = prefixMap.size();
399
400         if (size != 0) {
401
402             // Iterate over the map entries and apply each one.
403
// Stop when one of the entries actually changes the element.
404

405             for (int i = 0; i < size; i++) {
406                 MapEntry entry = (MapEntry) prefixMap.elementAt(i);
407                 String JavaDoc newElem = entry.apply(elem);
408
409                 // Note I'm using "!=" to see if we got a new object back from
410
// the apply method.
411

412                 if (newElem != elem) {
413                     elem = newElem;
414                     break; // We applied one, so we're done
415
}
416             }
417         }
418         return elem;
419     }
420
421     /**
422      * Add a mapper to convert the file names.
423      *
424      * @param mapper a <code>Mapper</code> value.
425      */

426     public void addMapper(Mapper mapper) {
427         if (this.mapper != null) {
428             throw new BuildException(
429                 "Cannot define more than one mapper");
430         }
431         this.mapper = mapper;
432     }
433
434     /**
435      * Add a nested filenamemapper.
436      * @param fileNameMapper the mapper to add.
437      * @since Ant 1.6.3
438      */

439     public void add(FileNameMapper fileNameMapper) {
440         Mapper m = new Mapper(getProject());
441         m.add(fileNameMapper);
442         addMapper(m);
443     }
444
445     /**
446      * Validate that all our parameters have been properly initialized.
447      *
448      * @throws BuildException if something is not set up properly.
449      */

450     private void validateSetup() throws BuildException {
451
452         if (path == null) {
453             throw new BuildException("You must specify a path to convert");
454         }
455         // Determine the separator strings. The dirsep and pathsep attributes
456
// override the targetOS settings.
457
String JavaDoc dsep = File.separator;
458         String JavaDoc psep = File.pathSeparator;
459
460         if (targetOS != null) {
461             psep = targetWindows ? ";" : ":";
462             dsep = targetWindows ? "\\" : "/";
463         }
464         if (pathSep != null) {
465             // override with pathsep=
466
psep = pathSep;
467         }
468         if (dirSep != null) {
469             // override with dirsep=
470
dsep = dirSep;
471         }
472         pathSep = psep;
473         dirSep = dsep;
474     }
475
476     /**
477      * Creates an exception that indicates that this XML element must not have
478      * child elements if the refid attribute is set.
479      * @return BuildException.
480      */

481     private BuildException noChildrenAllowed() {
482         return new BuildException("You must not specify nested "
483              + "elements when using the refid attribute.");
484     }
485
486 }
487
488
Popular Tags