KickJava   Java API By Example, From Geeks To Geeks.

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


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
19 package org.apache.tools.ant.taskdefs;
20
21 import java.io.File JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Enumeration JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.HashSet JavaDoc;
27 import java.util.Hashtable JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.Vector JavaDoc;
32 import org.apache.tools.ant.Task;
33 import org.apache.tools.ant.Project;
34 import org.apache.tools.ant.BuildException;
35 import org.apache.tools.ant.DirectoryScanner;
36 import org.apache.tools.ant.types.Mapper;
37 import org.apache.tools.ant.types.FileSet;
38 import org.apache.tools.ant.types.FilterSet;
39 import org.apache.tools.ant.types.FilterChain;
40 import org.apache.tools.ant.types.FilterSetCollection;
41 import org.apache.tools.ant.types.Resource;
42 import org.apache.tools.ant.types.ResourceCollection;
43 import org.apache.tools.ant.types.ResourceFactory;
44 import org.apache.tools.ant.types.resources.FileResource;
45 import org.apache.tools.ant.util.FileUtils;
46 import org.apache.tools.ant.util.FileNameMapper;
47 import org.apache.tools.ant.util.IdentityMapper;
48 import org.apache.tools.ant.util.ResourceUtils;
49 import org.apache.tools.ant.util.SourceFileScanner;
50 import org.apache.tools.ant.util.FlatFileNameMapper;
51
52 /**
53  * Copies a file or directory to a new file
54  * or directory. Files are only copied if the source file is newer
55  * than the destination file, or when the destination file does not
56  * exist. It is possible to explicitly overwrite existing files.</p>
57  *
58  * <p>This implementation is based on Arnout Kuiper's initial design
59  * document, the following mailing list discussions, and the
60  * copyfile/copydir tasks.</p>
61  *
62  *
63  * @since Ant 1.2
64  *
65  * @ant.task category="filesystem"
66  */

67 public class Copy extends Task {
68     static final File JavaDoc NULL_FILE_PLACEHOLDER = new File JavaDoc("/NULL_FILE");
69     static final String JavaDoc LINE_SEPARATOR = System.getProperty("line.separator");
70     // CheckStyle:VisibilityModifier OFF - bc
71
protected File JavaDoc file = null; // the source file
72
protected File JavaDoc destFile = null; // the destination file
73
protected File JavaDoc destDir = null; // the destination directory
74
protected Vector JavaDoc rcs = new Vector JavaDoc();
75
76     private boolean enableMultipleMappings = false;
77     protected boolean filtering = false;
78     protected boolean preserveLastModified = false;
79     protected boolean forceOverwrite = false;
80     protected boolean flatten = false;
81     protected int verbosity = Project.MSG_VERBOSE;
82     protected boolean includeEmpty = true;
83     protected boolean failonerror = true;
84
85     protected Hashtable JavaDoc fileCopyMap = new Hashtable JavaDoc();
86     protected Hashtable JavaDoc dirCopyMap = new Hashtable JavaDoc();
87     protected Hashtable JavaDoc completeDirMap = new Hashtable JavaDoc();
88
89     protected Mapper mapperElement = null;
90     protected FileUtils fileUtils;
91     private Vector JavaDoc filterChains = new Vector JavaDoc();
92     private Vector JavaDoc filterSets = new Vector JavaDoc();
93     private String JavaDoc inputEncoding = null;
94     private String JavaDoc outputEncoding = null;
95     private long granularity = 0;
96     // CheckStyle:VisibilityModifier ON
97

98     /**
99      * Copy task constructor.
100      */

101     public Copy() {
102         fileUtils = FileUtils.getFileUtils();
103         granularity = fileUtils.getFileTimestampGranularity();
104     }
105
106     /**
107      * Get the FileUtils for this task.
108      * @return the fileutils object.
109      */

110     protected FileUtils getFileUtils() {
111         return fileUtils;
112     }
113
114     /**
115      * Set a single source file to copy.
116      * @param file the file to copy.
117      */

118     public void setFile(File JavaDoc file) {
119         this.file = file;
120     }
121
122     /**
123      * Set the destination file.
124      * @param destFile the file to copy to.
125      */

126     public void setTofile(File JavaDoc destFile) {
127         this.destFile = destFile;
128     }
129
130     /**
131      * Set the destination directory.
132      * @param destDir the destination directory.
133      */

134     public void setTodir(File JavaDoc destDir) {
135         this.destDir = destDir;
136     }
137
138     /**
139      * Add a FilterChain.
140      * @return a filter chain object.
141      */

142     public FilterChain createFilterChain() {
143         FilterChain filterChain = new FilterChain();
144         filterChains.addElement(filterChain);
145         return filterChain;
146     }
147
148     /**
149      * Add a filterset.
150      * @return a filter set object.
151      */

152     public FilterSet createFilterSet() {
153         FilterSet filterSet = new FilterSet();
154         filterSets.addElement(filterSet);
155         return filterSet;
156     }
157
158     /**
159      * Give the copied files the same last modified time as the original files.
160      * @param preserve a boolean string.
161      * @deprecated since 1.5.x.
162      * setPreserveLastModified(String) has been deprecated and
163      * replaced with setPreserveLastModified(boolean) to
164      * consistently let the Introspection mechanism work.
165      */

166     public void setPreserveLastModified(String JavaDoc preserve) {
167         setPreserveLastModified(Project.toBoolean(preserve));
168     }
169
170     /**
171      * Give the copied files the same last modified time as the original files.
172      * @param preserve if true preserve the modified time; default is false.
173      */

174     public void setPreserveLastModified(boolean preserve) {
175         preserveLastModified = preserve;
176     }
177
178     /**
179      * Get whether to give the copied files the same last modified time as
180      * the original files.
181      * @return the whether destination files will inherit the modification
182      * times of the corresponding source files.
183      * @since 1.32, Ant 1.5
184      */

185     public boolean getPreserveLastModified() {
186         return preserveLastModified;
187     }
188
189     /**
190      * Get the filtersets being applied to this operation.
191      *
192      * @return a vector of FilterSet objects.
193      */

194     protected Vector JavaDoc getFilterSets() {
195         return filterSets;
196     }
197
198     /**
199      * Get the filterchains being applied to this operation.
200      *
201      * @return a vector of FilterChain objects.
202      */

203     protected Vector JavaDoc getFilterChains() {
204         return filterChains;
205     }
206
207     /**
208      * Set filtering mode.
209      * @param filtering if true enable filtering; default is false.
210      */

211     public void setFiltering(boolean filtering) {
212         this.filtering = filtering;
213     }
214
215     /**
216      * Set overwrite mode regarding existing destination file(s).
217      * @param overwrite if true force overwriting of destination file(s)
218      * even if the destination file(s) are younger than
219      * the corresponding source file. Default is false.
220      */

221     public void setOverwrite(boolean overwrite) {
222         this.forceOverwrite = overwrite;
223     }
224
225     /**
226      * Set whether files copied from directory trees will be "flattened"
227      * into a single directory. If there are multiple files with
228      * the same name in the source directory tree, only the first
229      * file will be copied into the "flattened" directory, unless
230      * the forceoverwrite attribute is true.
231      * @param flatten if true flatten the destination directory. Default
232      * is false.
233      */

234     public void setFlatten(boolean flatten) {
235         this.flatten = flatten;
236     }
237
238     /**
239      * Set verbose mode. Used to force listing of all names of copied files.
240      * @param verbose whether to output the names of copied files.
241      * Default is false.
242      */

243     public void setVerbose(boolean verbose) {
244         this.verbosity = verbose ? Project.MSG_INFO : Project.MSG_VERBOSE;
245     }
246
247     /**
248      * Set whether to copy empty directories.
249      * @param includeEmpty if true copy empty directories. Default is true.
250      */

251     public void setIncludeEmptyDirs(boolean includeEmpty) {
252         this.includeEmpty = includeEmpty;
253     }
254
255     /**
256      * Set method of handling mappers that return multiple
257      * mappings for a given source path.
258      * @param enableMultipleMappings If true the task will
259      * copy to all the mappings for a given source path, if
260      * false, only the first file or directory is
261      * processed.
262      * By default, this setting is false to provide backward
263      * compatibility with earlier releases.
264      * @since Ant 1.6
265      */

266     public void setEnableMultipleMappings(boolean enableMultipleMappings) {
267         this.enableMultipleMappings = enableMultipleMappings;
268     }
269
270     /**
271      * Get whether multiple mapping is enabled.
272      * @return true if multiple mapping is enabled; false otherwise.
273      */

274     public boolean isEnableMultipleMapping() {
275         return enableMultipleMappings;
276     }
277
278     /**
279      * Set whether to fail when errors are encountered. If false, note errors
280      * to the output but keep going. Default is true.
281      * @param failonerror true or false.
282      */

283     public void setFailOnError(boolean failonerror) {
284         this.failonerror = failonerror;
285     }
286
287     /**
288      * Add a set of files to copy.
289      * @param set a set of files to copy.
290      */

291     public void addFileset(FileSet set) {
292         add(set);
293     }
294
295     /**
296      * Add a collection of files to copy.
297      * @param res a resource collection to copy.
298      * @since Ant 1.7
299      */

300     public void add(ResourceCollection res) {
301         rcs.add(res);
302     }
303
304     /**
305      * Define the mapper to map source to destination files.
306      * @return a mapper to be configured.
307      * @exception BuildException if more than one mapper is defined.
308      */

309     public Mapper createMapper() throws BuildException {
310         if (mapperElement != null) {
311             throw new BuildException("Cannot define more than one mapper",
312                                      getLocation());
313         }
314         mapperElement = new Mapper(getProject());
315         return mapperElement;
316     }
317
318     /**
319      * Add a nested filenamemapper.
320      * @param fileNameMapper the mapper to add.
321      * @since Ant 1.6.3
322      */

323     public void add(FileNameMapper fileNameMapper) {
324         createMapper().add(fileNameMapper);
325     }
326
327     /**
328      * Set the character encoding.
329      * @param encoding the character encoding.
330      * @since 1.32, Ant 1.5
331      */

332     public void setEncoding(String JavaDoc encoding) {
333         this.inputEncoding = encoding;
334         if (outputEncoding == null) {
335             outputEncoding = encoding;
336         }
337     }
338
339     /**
340      * Get the character encoding to be used.
341      * @return the character encoding, <code>null</code> if not set.
342      *
343      * @since 1.32, Ant 1.5
344      */

345     public String JavaDoc getEncoding() {
346         return inputEncoding;
347     }
348
349     /**
350      * Set the character encoding for output files.
351      * @param encoding the output character encoding.
352      * @since Ant 1.6
353      */

354     public void setOutputEncoding(String JavaDoc encoding) {
355         this.outputEncoding = encoding;
356     }
357
358     /**
359      * Get the character encoding for output files.
360      * @return the character encoding for output files,
361      * <code>null</code> if not set.
362      *
363      * @since Ant 1.6
364      */

365     public String JavaDoc getOutputEncoding() {
366         return outputEncoding;
367     }
368
369     /**
370      * Set the number of milliseconds leeway to give before deciding a
371      * target is out of date.
372      *
373      * <p>Default is 1 second, or 2 seconds on DOS systems.</p>
374      * @param granularity the granularity used to decide if a target is out of
375      * date.
376      * @since Ant 1.6.2
377      */

378     public void setGranularity(long granularity) {
379         this.granularity = granularity;
380     }
381
382     /**
383      * Perform the copy operation.
384      * @exception BuildException if an error occurs.
385      */

386     public void execute() throws BuildException {
387         File JavaDoc savedFile = file; // may be altered in validateAttributes
388
File JavaDoc savedDestFile = destFile;
389         File JavaDoc savedDestDir = destDir;
390         ResourceCollection savedRc = null;
391         if (file == null && destFile != null && rcs.size() == 1) {
392             // will be removed in validateAttributes
393
savedRc = (ResourceCollection) rcs.elementAt(0);
394         }
395         // make sure we don't have an illegal set of options
396
validateAttributes();
397
398         try {
399             // deal with the single file
400
if (file != null) {
401                 if (file.exists()) {
402                     if (destFile == null) {
403                         destFile = new File JavaDoc(destDir, file.getName());
404                     }
405                     if (forceOverwrite || !destFile.exists()
406                         || (file.lastModified() - granularity
407                                 > destFile.lastModified())) {
408                         fileCopyMap.put(file.getAbsolutePath(),
409                                         new String JavaDoc[] {destFile.getAbsolutePath()});
410                     } else {
411                         log(file + " omitted as " + destFile
412                             + " is up to date.", Project.MSG_VERBOSE);
413                     }
414                 } else {
415                     String JavaDoc message = "Warning: Could not find file "
416                         + file.getAbsolutePath() + " to copy.";
417                     if (!failonerror) {
418                         log(message, Project.MSG_ERR);
419                     } else {
420                         throw new BuildException(message);
421                     }
422                 }
423             }
424             // deal with the ResourceCollections
425

426             /* for historical and performance reasons we have to do
427                things in a rather complex way.
428
429                (1) Move is optimized to move directories if a fileset
430                has been included completely, therefore FileSets need a
431                special treatment. This is also required to support
432                the failOnError semantice (skip filesets with broken
433                basedir but handle the remaining collections).
434
435                (2) We carry around a few protected methods that work
436                on basedirs and arrays of names. To optimize stuff, all
437                resources with the same basedir get collected in
438                separate lists and then each list is handled in one go.
439             */

440
441             HashMap JavaDoc filesByBasedir = new HashMap JavaDoc();
442             HashMap JavaDoc dirsByBasedir = new HashMap JavaDoc();
443             HashSet JavaDoc baseDirs = new HashSet JavaDoc();
444             ArrayList JavaDoc nonFileResources = new ArrayList JavaDoc();
445             for (int i = 0; i < rcs.size(); i++) {
446                 ResourceCollection rc = (ResourceCollection) rcs.elementAt(i);
447
448                 // Step (1) - beware of the ZipFileSet
449
if (rc instanceof FileSet && rc.isFilesystemOnly()) {
450                     FileSet fs = (FileSet) rc;
451                     DirectoryScanner ds = null;
452                     try {
453                         ds = fs.getDirectoryScanner(getProject());
454                     } catch (BuildException e) {
455                         if (failonerror
456                             || !getMessage(e).endsWith(" not found.")) {
457                             throw e;
458                         } else {
459                             log("Warning: " + getMessage(e), Project.MSG_ERR);
460                             continue;
461                         }
462                     }
463                     File JavaDoc fromDir = fs.getDir(getProject());
464
465                     String JavaDoc[] srcFiles = ds.getIncludedFiles();
466                     String JavaDoc[] srcDirs = ds.getIncludedDirectories();
467                     if (!flatten && mapperElement == null
468                         && ds.isEverythingIncluded() && !fs.hasPatterns()) {
469                         completeDirMap.put(fromDir, destDir);
470                     }
471                     add(fromDir, srcFiles, filesByBasedir);
472                     add(fromDir, srcDirs, dirsByBasedir);
473                     baseDirs.add(fromDir);
474                 } else { // not a fileset or contains non-file resources
475

476                     if (!rc.isFilesystemOnly() && !supportsNonFileResources()) {
477                         throw new BuildException(
478                                    "Only FileSystem resources are supported.");
479                     }
480
481                     Iterator JavaDoc resources = rc.iterator();
482                     while (resources.hasNext()) {
483                         Resource r = (Resource) resources.next();
484                         if (!r.isExists()) {
485                             continue;
486                         }
487
488                         File JavaDoc baseDir = NULL_FILE_PLACEHOLDER;
489                         String JavaDoc name = r.getName();
490                         if (r instanceof FileResource) {
491                             FileResource fr = (FileResource) r;
492                             baseDir = getKeyFile(fr.getBaseDir());
493                             if (fr.getBaseDir() == null) {
494                                 name = fr.getFile().getAbsolutePath();
495                             }
496                         }
497
498                         // copying of dirs is trivial and can be done
499
// for non-file resources as well as for real
500
// files.
501
if (r.isDirectory() || r instanceof FileResource) {
502                             add(baseDir, name,
503                                 r.isDirectory() ? dirsByBasedir
504                                                 : filesByBasedir);
505                             baseDirs.add(baseDir);
506                         } else { // a not-directory file resource
507
// needs special treatment
508
nonFileResources.add(r);
509                         }
510                     }
511                 }
512             }
513
514             Iterator JavaDoc iter = baseDirs.iterator();
515             while (iter.hasNext()) {
516                 File JavaDoc f = (File JavaDoc) iter.next();
517                 List JavaDoc files = (List JavaDoc) filesByBasedir.get(f);
518                 List JavaDoc dirs = (List JavaDoc) dirsByBasedir.get(f);
519
520                 String JavaDoc[] srcFiles = new String JavaDoc[0];
521                 if (files != null) {
522                     srcFiles = (String JavaDoc[]) files.toArray(srcFiles);
523                 }
524                 String JavaDoc[] srcDirs = new String JavaDoc[0];
525                 if (dirs != null) {
526                     srcDirs = (String JavaDoc[]) dirs.toArray(srcDirs);
527                 }
528                 scan(f == NULL_FILE_PLACEHOLDER ? null : f, destDir, srcFiles,
529                      srcDirs);
530             }
531
532             // do all the copy operations now...
533
try {
534                 doFileOperations();
535             } catch (BuildException e) {
536                 if (!failonerror) {
537                     log("Warning: " + getMessage(e), Project.MSG_ERR);
538                 } else {
539                     throw e;
540                 }
541             }
542
543             if (nonFileResources.size() > 0) {
544                 Resource[] nonFiles =
545                     (Resource[]) nonFileResources.toArray(new Resource[nonFileResources.size()]);
546                 // restrict to out-of-date resources
547
Map JavaDoc map = scan(nonFiles, destDir);
548                 try {
549                     doResourceOperations(map);
550                 } catch (BuildException e) {
551                     if (!failonerror) {
552                         log("Warning: " + getMessage(e), Project.MSG_ERR);
553                     } else {
554                         throw e;
555                     }
556                 }
557             }
558         } finally {
559             // clean up again, so this instance can be used a second
560
// time
561
file = savedFile;
562             destFile = savedDestFile;
563             destDir = savedDestDir;
564             if (savedRc != null) {
565                 rcs.insertElementAt(savedRc, 0);
566             }
567             fileCopyMap.clear();
568             dirCopyMap.clear();
569             completeDirMap.clear();
570         }
571     }
572
573     /************************************************************************
574      ** protected and private methods
575      ************************************************************************/

576
577     /**
578      * Ensure we have a consistent and legal set of attributes, and set
579      * any internal flags necessary based on different combinations
580      * of attributes.
581      * @exception BuildException if an error occurs.
582      */

583     protected void validateAttributes() throws BuildException {
584         if (file == null && rcs.size() == 0) {
585             throw new BuildException(
586                 "Specify at least one source--a file or a resource collection.");
587         }
588         if (destFile != null && destDir != null) {
589             throw new BuildException(
590                 "Only one of tofile and todir may be set.");
591         }
592         if (destFile == null && destDir == null) {
593             throw new BuildException("One of tofile or todir must be set.");
594         }
595         if (file != null && file.isDirectory()) {
596             throw new BuildException("Use a resource collection to copy directories.");
597         }
598         if (destFile != null && rcs.size() > 0) {
599             if (rcs.size() > 1) {
600                 throw new BuildException(
601                     "Cannot concatenate multiple files into a single file.");
602             } else {
603                 ResourceCollection rc = (ResourceCollection) rcs.elementAt(0);
604                 if (!rc.isFilesystemOnly()) {
605                     throw new BuildException("Only FileSystem resources are"
606                                              + " supported when concatenating"
607                                              + " files.");
608                 }
609                 if (rc.size() == 0) {
610                     throw new BuildException(
611                         "Cannot perform operation from directory to file.");
612                 } else if (rc.size() == 1) {
613                     FileResource r = (FileResource) rc.iterator().next();
614                     if (file == null) {
615                         file = r.getFile();
616                         rcs.removeElementAt(0);
617                     } else {
618                         throw new BuildException(
619                             "Cannot concatenate multiple files into a single file.");
620                     }
621                 } else {
622                     throw new BuildException(
623                         "Cannot concatenate multiple files into a single file.");
624                 }
625             }
626         }
627         if (destFile != null) {
628             destDir = destFile.getParentFile();
629         }
630     }
631
632     /**
633      * Compares source files to destination files to see if they should be
634      * copied.
635      *
636      * @param fromDir The source directory.
637      * @param toDir The destination directory.
638      * @param files A list of files to copy.
639      * @param dirs A list of directories to copy.
640      */

641     protected void scan(File JavaDoc fromDir, File JavaDoc toDir, String JavaDoc[] files,
642                         String JavaDoc[] dirs) {
643         FileNameMapper mapper = getMapper();
644         buildMap(fromDir, toDir, files, mapper, fileCopyMap);
645
646         if (includeEmpty) {
647             buildMap(fromDir, toDir, dirs, mapper, dirCopyMap);
648         }
649     }
650
651     /**
652      * Compares source resources to destination files to see if they
653      * should be copied.
654      *
655      * @param fromResources The source resources.
656      * @param toDir The destination directory.
657      *
658      * @return a Map with the out-of-date resources as keys and an
659      * array of target file names as values.
660      *
661      * @since Ant 1.7
662      */

663     protected Map JavaDoc scan(Resource[] fromResources, File JavaDoc toDir) {
664         return buildMap(fromResources, toDir, getMapper());
665     }
666
667     /**
668      * Add to a map of files/directories to copy.
669      *
670      * @param fromDir the source directory.
671      * @param toDir the destination directory.
672      * @param names a list of filenames.
673      * @param mapper a <code>FileNameMapper</code> value.
674      * @param map a map of source file to array of destination files.
675      */

676     protected void buildMap(File JavaDoc fromDir, File JavaDoc toDir, String JavaDoc[] names,
677                             FileNameMapper mapper, Hashtable JavaDoc map) {
678         String JavaDoc[] toCopy = null;
679         if (forceOverwrite) {
680             Vector JavaDoc v = new Vector JavaDoc();
681             for (int i = 0; i < names.length; i++) {
682                 if (mapper.mapFileName(names[i]) != null) {
683                     v.addElement(names[i]);
684                 }
685             }
686             toCopy = new String JavaDoc[v.size()];
687             v.copyInto(toCopy);
688         } else {
689             SourceFileScanner ds = new SourceFileScanner(this);
690             toCopy = ds.restrict(names, fromDir, toDir, mapper, granularity);
691         }
692         for (int i = 0; i < toCopy.length; i++) {
693             File JavaDoc src = new File JavaDoc(fromDir, toCopy[i]);
694             String JavaDoc[] mappedFiles = mapper.mapFileName(toCopy[i]);
695
696             if (!enableMultipleMappings) {
697                 map.put(src.getAbsolutePath(),
698                         new String JavaDoc[] {new File JavaDoc(toDir, mappedFiles[0]).getAbsolutePath()});
699             } else {
700                 // reuse the array created by the mapper
701
for (int k = 0; k < mappedFiles.length; k++) {
702                     mappedFiles[k] = new File JavaDoc(toDir, mappedFiles[k]).getAbsolutePath();
703                 }
704                 map.put(src.getAbsolutePath(), mappedFiles);
705             }
706         }
707     }
708
709     /**
710      * Create a map of resources to copy.
711      *
712      * @param fromResources The source resources.
713      * @param toDir the destination directory.
714      * @param mapper a <code>FileNameMapper</code> value.
715      * @return a map of source resource to array of destination files.
716      * @since Ant 1.7
717      */

718     protected Map JavaDoc buildMap(Resource[] fromResources, final File JavaDoc toDir,
719                            FileNameMapper mapper) {
720         HashMap JavaDoc map = new HashMap JavaDoc();
721         Resource[] toCopy = null;
722         if (forceOverwrite) {
723             Vector JavaDoc v = new Vector JavaDoc();
724             for (int i = 0; i < fromResources.length; i++) {
725                 if (mapper.mapFileName(fromResources[i].getName()) != null) {
726                     v.addElement(fromResources[i]);
727                 }
728             }
729             toCopy = new Resource[v.size()];
730             v.copyInto(toCopy);
731         } else {
732             toCopy =
733                 ResourceUtils.selectOutOfDateSources(this, fromResources,
734                                                      mapper,
735                                                      new ResourceFactory() {
736                            public Resource getResource(String JavaDoc name) {
737                                return new FileResource(toDir, name);
738                            }
739                                                      },
740                                                      granularity);
741         }
742         for (int i = 0; i < toCopy.length; i++) {
743             String JavaDoc[] mappedFiles = mapper.mapFileName(toCopy[i].getName());
744
745             if (!enableMultipleMappings) {
746                 map.put(toCopy[i],
747                         new String JavaDoc[] {new File JavaDoc(toDir, mappedFiles[0]).getAbsolutePath()});
748             } else {
749                 // reuse the array created by the mapper
750
for (int k = 0; k < mappedFiles.length; k++) {
751                     mappedFiles[k] = new File JavaDoc(toDir, mappedFiles[k]).getAbsolutePath();
752                 }
753                 map.put(toCopy[i], mappedFiles);
754             }
755         }
756         return map;
757     }
758
759     /**
760      * Actually does the file (and possibly empty directory) copies.
761      * This is a good method for subclasses to override.
762      */

763     protected void doFileOperations() {
764         if (fileCopyMap.size() > 0) {
765             log("Copying " + fileCopyMap.size()
766                 + " file" + (fileCopyMap.size() == 1 ? "" : "s")
767                 + " to " + destDir.getAbsolutePath());
768
769             Enumeration JavaDoc e = fileCopyMap.keys();
770             while (e.hasMoreElements()) {
771                 String JavaDoc fromFile = (String JavaDoc) e.nextElement();
772                 String JavaDoc[] toFiles = (String JavaDoc[]) fileCopyMap.get(fromFile);
773
774                 for (int i = 0; i < toFiles.length; i++) {
775                     String JavaDoc toFile = toFiles[i];
776
777                     if (fromFile.equals(toFile)) {
778                         log("Skipping self-copy of " + fromFile, verbosity);
779                         continue;
780                     }
781                     try {
782                         log("Copying " + fromFile + " to " + toFile, verbosity);
783
784                         FilterSetCollection executionFilters =
785                             new FilterSetCollection();
786                         if (filtering) {
787                             executionFilters
788                                 .addFilterSet(getProject().getGlobalFilterSet());
789                         }
790                         for (Enumeration JavaDoc filterEnum = filterSets.elements();
791                             filterEnum.hasMoreElements();) {
792                             executionFilters
793                                 .addFilterSet((FilterSet) filterEnum.nextElement());
794                         }
795                         fileUtils.copyFile(fromFile, toFile, executionFilters,
796                                            filterChains, forceOverwrite,
797                                            preserveLastModified, inputEncoding,
798                                            outputEncoding, getProject());
799                     } catch (IOException JavaDoc ioe) {
800                         String JavaDoc msg = "Failed to copy " + fromFile + " to " + toFile
801                             + " due to " + getDueTo(ioe);
802                         File JavaDoc targetFile = new File JavaDoc(toFile);
803                         if (targetFile.exists() && !targetFile.delete()) {
804                             msg += " and I couldn't delete the corrupt " + toFile;
805                         }
806                         if (failonerror) {
807                             throw new BuildException(msg, ioe, getLocation());
808                         }
809                         log(msg, Project.MSG_ERR);
810                     }
811                 }
812             }
813         }
814         if (includeEmpty) {
815             Enumeration JavaDoc e = dirCopyMap.elements();
816             int createCount = 0;
817             while (e.hasMoreElements()) {
818                 String JavaDoc[] dirs = (String JavaDoc[]) e.nextElement();
819                 for (int i = 0; i < dirs.length; i++) {
820                     File JavaDoc d = new File JavaDoc(dirs[i]);
821                     if (!d.exists()) {
822                         if (!d.mkdirs()) {
823                             log("Unable to create directory "
824                                 + d.getAbsolutePath(), Project.MSG_ERR);
825                         } else {
826                             createCount++;
827                         }
828                     }
829                 }
830             }
831             if (createCount > 0) {
832                 log("Copied " + dirCopyMap.size()
833                     + " empty director"
834                     + (dirCopyMap.size() == 1 ? "y" : "ies")
835                     + " to " + createCount
836                     + " empty director"
837                     + (createCount == 1 ? "y" : "ies") + " under "
838                     + destDir.getAbsolutePath());
839             }
840         }
841     }
842
843     /**
844      * Actually does the resource copies.
845      * This is a good method for subclasses to override.
846      * @param map a map of source resource to array of destination files.
847      * @since Ant 1.7
848      */

849     protected void doResourceOperations(Map JavaDoc map) {
850         if (map.size() > 0) {
851             log("Copying " + map.size()
852                 + " resource" + (map.size() == 1 ? "" : "s")
853                 + " to " + destDir.getAbsolutePath());
854
855             Iterator JavaDoc iter = map.keySet().iterator();
856             while (iter.hasNext()) {
857                 Resource fromResource = (Resource) iter.next();
858                 String JavaDoc[] toFiles = (String JavaDoc[]) map.get(fromResource);
859
860                 for (int i = 0; i < toFiles.length; i++) {
861                     String JavaDoc toFile = toFiles[i];
862
863                     try {
864                         log("Copying " + fromResource + " to " + toFile,
865                             verbosity);
866
867                         FilterSetCollection executionFilters =
868                             new FilterSetCollection();
869                         if (filtering) {
870                             executionFilters
871                                 .addFilterSet(getProject().getGlobalFilterSet());
872                         }
873                         for (Enumeration JavaDoc filterEnum = filterSets.elements();
874                             filterEnum.hasMoreElements();) {
875                             executionFilters
876                                 .addFilterSet((FilterSet) filterEnum.nextElement());
877                         }
878                         ResourceUtils.copyResource(fromResource,
879                                                    new FileResource(destDir,
880                                                                     toFile),
881                                                    executionFilters,
882                                                    filterChains,
883                                                    forceOverwrite,
884                                                    preserveLastModified,
885                                                    inputEncoding,
886                                                    outputEncoding,
887                                                    getProject());
888                     } catch (IOException JavaDoc ioe) {
889                         String JavaDoc msg = "Failed to copy " + fromResource
890                             + " to " + toFile
891                             + " due to " + getDueTo(ioe);
892                         File JavaDoc targetFile = new File JavaDoc(toFile);
893                         if (targetFile.exists() && !targetFile.delete()) {
894                             msg += " and I couldn't delete the corrupt " + toFile;
895                         }
896                         if (failonerror) {
897                             throw new BuildException(msg, ioe, getLocation());
898                         }
899                         log(msg, Project.MSG_ERR);
900                     }
901                 }
902             }
903         }
904     }
905
906     /**
907      * Whether this task can deal with non-file resources.
908      *
909      * <p>&lt;copy&gt; can while &lt;move&gt; can't since we don't
910      * know how to remove non-file resources.</p>
911      *
912      * <p>This implementation returns true only if this task is
913      * &lt;copy&gt;. Any subclass of this class that also wants to
914      * support non-file resources needs to override this method. We
915      * need to do so for backwards compatibility reasons since we
916      * can't expect subclasses to support resources.</p>
917      * @return true if this task supports non file resources.
918      * @since Ant 1.7
919      */

920     protected boolean supportsNonFileResources() {
921         return getClass().equals(Copy.class);
922     }
923
924     /**
925      * Adds the given strings to a list contained in the given map.
926      * The file is the key into the map.
927      */

928     private static void add(File JavaDoc baseDir, String JavaDoc[] names, Map JavaDoc m) {
929         if (names != null) {
930             baseDir = getKeyFile(baseDir);
931             List JavaDoc l = (List JavaDoc) m.get(baseDir);
932             if (l == null) {
933                 l = new ArrayList JavaDoc(names.length);
934                 m.put(baseDir, l);
935             }
936             l.addAll(java.util.Arrays.asList(names));
937         }
938     }
939
940     /**
941      * Adds the given string to a list contained in the given map.
942      * The file is the key into the map.
943      */

944     private static void add(File JavaDoc baseDir, String JavaDoc name, Map JavaDoc m) {
945         if (name != null) {
946             add(baseDir, new String JavaDoc[] {name}, m);
947         }
948     }
949
950     /**
951      * Either returns its argument or a plaeholder if the argument is null.
952      */

953     private static File JavaDoc getKeyFile(File JavaDoc f) {
954         return f == null ? NULL_FILE_PLACEHOLDER : f;
955     }
956
957     /**
958      * returns the mapper to use based on nested elements or the
959      * flatten attribute.
960      */

961     private FileNameMapper getMapper() {
962         FileNameMapper mapper = null;
963         if (mapperElement != null) {
964             mapper = mapperElement.getImplementation();
965         } else if (flatten) {
966             mapper = new FlatFileNameMapper();
967         } else {
968             mapper = new IdentityMapper();
969         }
970         return mapper;
971     }
972
973     /**
974      * Handle getMessage() for exceptions.
975      * @param ex the exception to handle
976      * @return ex.getMessage() if ex.getMessage() is not null
977      * otherwise return ex.toString()
978      */

979     private String JavaDoc getMessage(Exception JavaDoc ex) {
980         return ex.getMessage() == null ? ex.toString() : ex.getMessage();
981     }
982
983     /**
984      * Returns a reason for failure based on
985      * the exception thrown.
986      * If the exception is not IOException output the class name,
987      * output the message
988      * if the exception is MalformedInput add a little note.
989      */

990     private String JavaDoc getDueTo(Exception JavaDoc ex) {
991         boolean baseIOException = ex.getClass() == IOException JavaDoc.class;
992         StringBuffer JavaDoc message = new StringBuffer JavaDoc();
993         if (!baseIOException || ex.getMessage() == null) {
994             message.append(ex.getClass().getName());
995         }
996         if (ex.getMessage() != null) {
997             if (!baseIOException) {
998                 message.append(" ");
999             }
1000            message.append(ex.getMessage());
1001        }
1002        if (ex.getClass().getName().indexOf("MalformedInput") != -1) {
1003            message.append(LINE_SEPARATOR);
1004            message.append(
1005                "This is normally due to the input file containing invalid");
1006             message.append(LINE_SEPARATOR);
1007            message.append("bytes for the character encoding used : ");
1008            message.append(
1009                (inputEncoding == null
1010                 ? fileUtils.getDefaultEncoding() : inputEncoding));
1011            message.append(LINE_SEPARATOR);
1012        }
1013        return message.toString();
1014    }
1015}
1016
Popular Tags