KickJava   Java API By Example, From Geeks To Geeks.

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


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.Enumeration JavaDoc;
24 import org.apache.tools.ant.Project;
25 import org.apache.tools.ant.BuildException;
26 import org.apache.tools.ant.DirectoryScanner;
27 import org.apache.tools.ant.types.FileSet;
28 import org.apache.tools.ant.types.FilterSet;
29 import org.apache.tools.ant.types.FilterSetCollection;
30
31 /**
32  * Moves a file or directory to a new file or directory.
33  * By default, the
34  * destination file is overwritten if it already exists.
35  * When <i>overwrite</i> is
36  * turned off, then files are only moved if the source file is
37  * newer than the destination file, or when the destination file does
38  * not exist.
39  *
40  * <p>Source files and directories are only deleted when the file or
41  * directory has been copied to the destination successfully. Filtering
42  * also works.</p>
43  *
44  * <p>This implementation is based on Arnout Kuiper's initial design
45  * document, the following mailing list discussions, and the
46  * copyfile/copydir tasks.</p>
47  *
48  *
49  * @since Ant 1.2
50  *
51  * @ant.task category="filesystem"
52  */

53 public class Move extends Copy {
54
55     /**
56      * Constructor of object.
57      * This sets the forceOverwrite attribute of the Copy parent class
58      * to true.
59      *
60      */

61     public Move() {
62         super();
63         setOverwrite(true);
64     }
65
66     /** {@inheritDoc}. */
67     protected void validateAttributes() throws BuildException {
68         if (file != null && file.isDirectory()) {
69             if ((destFile != null && destDir != null)
70                 || (destFile == null && destDir == null)) {
71                 throw new BuildException("One and only one of tofile and todir "
72                                          + "must be set.");
73             }
74             destFile = (destFile == null)
75                 ? new File JavaDoc(destDir, file.getName()) : destFile;
76             destDir = (destDir == null)
77                 ? destFile.getParentFile() : destDir;
78
79             completeDirMap.put(file, destFile);
80             file = null;
81         } else {
82             super.validateAttributes();
83         }
84     }
85
86 //************************************************************************
87
// protected and private methods
88
//************************************************************************
89

90     /**
91      * Override copy's doFileOperations to move the
92      * files instead of copying them.
93      */

94     protected void doFileOperations() {
95         //Attempt complete directory renames, if any, first.
96
if (completeDirMap.size() > 0) {
97             Enumeration JavaDoc e = completeDirMap.keys();
98             while (e.hasMoreElements()) {
99                 File JavaDoc fromDir = (File JavaDoc) e.nextElement();
100                 File JavaDoc toDir = (File JavaDoc) completeDirMap.get(fromDir);
101                 boolean renamed = false;
102                 try {
103                     log("Attempting to rename dir: " + fromDir
104                         + " to " + toDir, verbosity);
105                     renamed =
106                         renameFile(fromDir, toDir, filtering, forceOverwrite);
107                 } catch (IOException JavaDoc ioe) {
108                     String JavaDoc msg = "Failed to rename dir " + fromDir
109                         + " to " + toDir
110                         + " due to " + ioe.getMessage();
111                     throw new BuildException(msg, ioe, getLocation());
112                 }
113                 if (!renamed) {
114                     FileSet fs = new FileSet();
115                     fs.setProject(getProject());
116                     fs.setDir(fromDir);
117                     addFileset(fs);
118                     DirectoryScanner ds = fs.getDirectoryScanner(getProject());
119                     String JavaDoc[] files = ds.getIncludedFiles();
120                     String JavaDoc[] dirs = ds.getIncludedDirectories();
121                     scan(fromDir, toDir, files, dirs);
122                 }
123             }
124         }
125         int moveCount = fileCopyMap.size();
126         if (moveCount > 0) { // files to move
127
log("Moving " + moveCount + " file"
128                 + ((moveCount == 1) ? "" : "s")
129                 + " to " + destDir.getAbsolutePath());
130
131             Enumeration JavaDoc e = fileCopyMap.keys();
132             while (e.hasMoreElements()) {
133                 String JavaDoc fromFile = (String JavaDoc) e.nextElement();
134
135                 File JavaDoc f = new File JavaDoc(fromFile);
136                 boolean selfMove = false;
137                 if (f.exists()) { //Is this file still available to be moved?
138
String JavaDoc[] toFiles = (String JavaDoc[]) fileCopyMap.get(fromFile);
139                     for (int i = 0; i < toFiles.length; i++) {
140                         String JavaDoc toFile = (String JavaDoc) toFiles[i];
141
142                         if (fromFile.equals(toFile)) {
143                             log("Skipping self-move of " + fromFile, verbosity);
144                             selfMove = true;
145
146                             // if this is the last time through the loop then
147
// move will not occur, but that's what we want
148
continue;
149                         }
150                         File JavaDoc d = new File JavaDoc(toFile);
151                         if ((i + 1) == toFiles.length && !selfMove) {
152                             // Only try to move if this is the last mapped file
153
// and one of the mappings isn't to itself
154
moveFile(f, d, filtering, forceOverwrite);
155                         } else {
156                             copyFile(f, d, filtering, forceOverwrite);
157                         }
158                     }
159                 }
160             }
161         }
162
163         if (includeEmpty) {
164             Enumeration JavaDoc e = dirCopyMap.keys();
165             int createCount = 0;
166             while (e.hasMoreElements()) {
167                 String JavaDoc fromDirName = (String JavaDoc) e.nextElement();
168                 String JavaDoc[] toDirNames = (String JavaDoc[]) dirCopyMap.get(fromDirName);
169                 boolean selfMove = false;
170                 for (int i = 0; i < toDirNames.length; i++) {
171
172                     if (fromDirName.equals(toDirNames[i])) {
173                         log("Skipping self-move of " + fromDirName, verbosity);
174                         selfMove = true;
175                         continue;
176                     }
177
178                     File JavaDoc d = new File JavaDoc(toDirNames[i]);
179                     if (!d.exists()) {
180                         if (!d.mkdirs()) {
181                             log("Unable to create directory "
182                                 + d.getAbsolutePath(), Project.MSG_ERR);
183                         } else {
184                             createCount++;
185                         }
186                     }
187                 }
188
189                 File JavaDoc fromDir = new File JavaDoc(fromDirName);
190                 if (!selfMove && okToDelete(fromDir)) {
191                     deleteDir(fromDir);
192                 }
193
194             }
195
196             if (createCount > 0) {
197                 log("Moved " + dirCopyMap.size()
198                     + " empty director"
199                     + (dirCopyMap.size() == 1 ? "y" : "ies")
200                     + " to " + createCount
201                     + " empty director"
202                     + (createCount == 1 ? "y" : "ies") + " under "
203                     + destDir.getAbsolutePath());
204             }
205         }
206     }
207
208     /**
209      * Try to move the file via a rename, but if this fails or filtering
210      * is enabled, copy the file then delete the sourceFile.
211      */

212     private void moveFile(File JavaDoc fromFile, File JavaDoc toFile,
213                           boolean filtering, boolean overwrite) {
214         boolean moved = false;
215         try {
216             log("Attempting to rename: " + fromFile
217                 + " to " + toFile, verbosity);
218             moved = renameFile(fromFile, toFile, filtering, forceOverwrite);
219         } catch (IOException JavaDoc ioe) {
220             String JavaDoc msg = "Failed to rename " + fromFile
221                 + " to " + toFile
222                 + " due to " + ioe.getMessage();
223             throw new BuildException(msg, ioe, getLocation());
224         }
225
226         if (!moved) {
227             copyFile(fromFile, toFile, filtering, overwrite);
228             if (!fromFile.delete()) {
229                 throw new BuildException("Unable to delete "
230                                         + "file "
231                                         + fromFile.getAbsolutePath());
232             }
233         }
234     }
235
236     /**
237      * Copy fromFile to toFile.
238      * @param fromFile
239      * @param toFile
240      * @param filtering
241      * @param overwrite
242      */

243     private void copyFile(File JavaDoc fromFile, File JavaDoc toFile,
244                           boolean filtering, boolean overwrite) {
245         try {
246             log("Copying " + fromFile + " to " + toFile,
247                 verbosity);
248
249             FilterSetCollection executionFilters =
250                 new FilterSetCollection();
251             if (filtering) {
252                 executionFilters
253                     .addFilterSet(getProject().getGlobalFilterSet());
254             }
255             for (Enumeration JavaDoc filterEnum =
256                     getFilterSets().elements();
257                 filterEnum.hasMoreElements();) {
258                 executionFilters
259                     .addFilterSet((FilterSet) filterEnum
260                                 .nextElement());
261             }
262
263             getFileUtils().copyFile(fromFile, toFile, executionFilters,
264                                     getFilterChains(),
265                                     forceOverwrite,
266                                     getPreserveLastModified(),
267                                     getEncoding(),
268                                     getOutputEncoding(),
269                                     getProject());
270
271         } catch (IOException JavaDoc ioe) {
272             String JavaDoc msg = "Failed to copy " + fromFile
273                 + " to " + toFile
274                 + " due to " + ioe.getMessage();
275             throw new BuildException(msg, ioe, getLocation());
276         }
277     }
278
279
280     /**
281      * Its only ok to delete a directory tree if there are
282      * no files in it.
283      * @param d the directory to check
284      * @return true if a deletion can go ahead
285      */

286     protected boolean okToDelete(File JavaDoc d) {
287         String JavaDoc[] list = d.list();
288         if (list == null) {
289             return false;
290         } // maybe io error?
291

292         for (int i = 0; i < list.length; i++) {
293             String JavaDoc s = list[i];
294             File JavaDoc f = new File JavaDoc(d, s);
295             if (f.isDirectory()) {
296                 if (!okToDelete(f)) {
297                     return false;
298                 }
299             } else {
300                 return false; // found a file
301
}
302         }
303
304         return true;
305     }
306
307     /**
308      * Go and delete the directory tree.
309      * @param d the directory to delete
310      */

311     protected void deleteDir(File JavaDoc d) {
312         deleteDir(d, false);
313     }
314
315     /**
316      * Go and delete the directory tree.
317      * @param d the directory to delete
318      * @param deleteFiles whether to delete files
319      */

320     protected void deleteDir(File JavaDoc d, boolean deleteFiles) {
321         String JavaDoc[] list = d.list();
322         if (list == null) {
323             return;
324         } // on an io error list() can return null
325

326         for (int i = 0; i < list.length; i++) {
327             String JavaDoc s = list[i];
328             File JavaDoc f = new File JavaDoc(d, s);
329             if (f.isDirectory()) {
330                 deleteDir(f);
331             } else if (deleteFiles && !(f.delete())) {
332                 throw new BuildException("Unable to delete file "
333                                          + f.getAbsolutePath());
334             } else {
335                 throw new BuildException("UNEXPECTED ERROR - The file "
336                                          + f.getAbsolutePath()
337                                          + " should not exist!");
338             }
339         }
340         log("Deleting directory " + d.getAbsolutePath(), verbosity);
341         if (!d.delete()) {
342             throw new BuildException("Unable to delete directory "
343                                      + d.getAbsolutePath());
344         }
345     }
346
347     /**
348      * Attempts to rename a file from a source to a destination.
349      * If overwrite is set to true, this method overwrites existing file
350      * even if the destination file is newer. Otherwise, the source file is
351      * renamed only if the destination file is older than it.
352      * Method then checks if token filtering is used. If it is, this method
353      * returns false assuming it is the responsibility to the copyFile method.
354      *
355      * @param sourceFile the file to rename
356      * @param destFile the destination file
357      * @param filtering if true, filtering is in operation, file will
358      * be copied/deleted instead of renamed
359      * @param overwrite if true force overwrite even if destination file
360      * is newer than source file
361      * @return true if the file was renamed
362      * @exception IOException if an error occurs
363      * @exception BuildException if an error occurs
364      */

365     protected boolean renameFile(File JavaDoc sourceFile, File JavaDoc destFile,
366                                  boolean filtering, boolean overwrite)
367         throws IOException JavaDoc, BuildException {
368
369         boolean renamed = false;
370         if ((getFilterSets().size() + getFilterChains().size() == 0)
371             && !(filtering || destFile.isDirectory())) {
372             // ensure that parent dir of dest file exists!
373
File JavaDoc parent = destFile.getParentFile();
374             if (parent != null && !parent.exists()) {
375                 parent.mkdirs();
376             }
377             if (destFile.isFile() && !destFile.equals(sourceFile)
378                 && !destFile.delete()) {
379                 throw new BuildException("Unable to remove existing "
380                                          + "file " + destFile);
381             }
382             renamed = sourceFile.renameTo(destFile);
383         }
384         return renamed;
385     }
386 }
387
Popular Tags