KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > vfs > tasks > AbstractSyncTask


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

16 package org.apache.commons.vfs.tasks;
17
18 import org.apache.commons.vfs.FileName;
19 import org.apache.commons.vfs.FileObject;
20 import org.apache.commons.vfs.FileType;
21 import org.apache.commons.vfs.NameScope;
22 import org.apache.commons.vfs.Selectors;
23 import org.apache.commons.vfs.util.Messages;
24 import org.apache.tools.ant.BuildException;
25 import org.apache.tools.ant.Project;
26
27 import java.util.ArrayList JavaDoc;
28 import java.util.HashSet JavaDoc;
29 import java.util.Set JavaDoc;
30 import java.util.StringTokenizer JavaDoc;
31
32 /**
33  * An abstract file synchronization task. Scans a set of source files and
34  * folders, and a destination folder, and performs actions on missing and
35  * out-of-date files. Specifically, performs actions on the following:
36  * <ul>
37  * <li>Missing destination file.
38  * <li>Missing source file.
39  * <li>Out-of-date destination file.
40  * <li>Up-to-date destination file.
41  * </ul>
42  *
43  * @author <a HREF="mailto:adammurdoch@apache.org">Adam Murdoch</a>
44  * @todo Deal with case where dest file maps to a child of one of the source files
45  * @todo Deal with case where dest file already exists and is incorrect type (not file, not a folder)
46  * @todo Use visitors
47  * @todo Add default excludes
48  * @todo Allow selector, mapper, filters, etc to be specified.
49  * @todo Handle source/dest directories as well
50  * @todo Allow selector to be specified for choosing which dest files to sync
51  */

52 public abstract class AbstractSyncTask
53     extends VfsTask
54 {
55     private final ArrayList JavaDoc srcFiles = new ArrayList JavaDoc();
56     private String JavaDoc destFileUrl;
57     private String JavaDoc destDirUrl;
58     private String JavaDoc srcDirUrl;
59     private boolean srcDirIsBase;
60     private String JavaDoc filesList;
61
62     /**
63      * Sets the destination file.
64      */

65     public void setDestFile(final String JavaDoc destFile)
66     {
67         this.destFileUrl = destFile;
68     }
69
70     /**
71      * Sets the destination directory.
72      */

73     public void setDestDir(final String JavaDoc destDir)
74     {
75         this.destDirUrl = destDir;
76     }
77
78     /**
79      * Sets the source file
80      */

81     public void setSrc(final String JavaDoc srcFile)
82     {
83         final SourceInfo src = new SourceInfo();
84         src.setFile(srcFile);
85         addConfiguredSrc(src);
86     }
87
88     /**
89      * Sets the source directory
90      */

91     public void setSrcDir(final String JavaDoc srcDir)
92     {
93         this.srcDirUrl = srcDir;
94     }
95
96     /**
97      * Sets whether the source directory should be consider as the base directory.
98      */

99     public void setSrcDirIsBase(final boolean srcDirIsBase)
100     {
101         this.srcDirIsBase = srcDirIsBase;
102     }
103
104     /**
105      * Sets the files to includes
106      */

107     public void setIncludes(final String JavaDoc filesList)
108     {
109         this.filesList = filesList;
110     }
111
112     /**
113      * Adds a nested <src> element.
114      */

115     public void addConfiguredSrc(final SourceInfo srcInfo)
116         throws BuildException
117     {
118         if (srcInfo.file == null)
119         {
120             final String JavaDoc message = Messages.getString("vfs.tasks/sync.no-source-file.error");
121             throw new BuildException(message);
122         }
123         srcFiles.add(srcInfo);
124     }
125
126     /**
127      * Executes this task.
128      */

129     public void execute() throws BuildException
130     {
131         // Validate
132
if (destFileUrl == null && destDirUrl == null)
133         {
134             final String JavaDoc message =
135                 Messages.getString("vfs.tasks/sync.no-destination.error");
136             throw new BuildException(message);
137         }
138
139         if (destFileUrl != null && destDirUrl != null)
140         {
141             final String JavaDoc message =
142                 Messages.getString("vfs.tasks/sync.too-many-destinations.error");
143             throw new BuildException(message);
144         }
145
146         // Add the files of the includes attribute to the list
147
if (srcDirUrl != null && !srcDirUrl.equals(destDirUrl) && filesList != null && filesList.length() > 0)
148         {
149             if (!srcDirUrl.endsWith("/"))
150             {
151                 srcDirUrl += "/";
152             }
153             StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(filesList, ", \t\n\r\f", false);
154             while (tok.hasMoreTokens())
155             {
156                 String JavaDoc nextFile = tok.nextToken();
157
158                 // Basic compatibility with Ant fileset for directories
159
if (nextFile.endsWith("/**"))
160                 {
161                     nextFile = nextFile.substring(0, nextFile.length() - 2);
162                 }
163
164                 final SourceInfo src = new SourceInfo();
165                 src.setFile(srcDirUrl + nextFile);
166                 addConfiguredSrc(src);
167             }
168         }
169
170         if (srcFiles.size() == 0)
171         {
172             final String JavaDoc message = Messages.getString("vfs.tasks/sync.no-source-files.warn");
173             log(message, Project.MSG_WARN);
174             return;
175         }
176
177         // Perform the sync
178
try
179         {
180             if (destFileUrl != null)
181             {
182                 handleSingleFile();
183             }
184             else
185             {
186                 handleFiles();
187             }
188         }
189         catch (final BuildException e)
190         {
191             throw e;
192         }
193         catch (final Exception JavaDoc e)
194         {
195             throw new BuildException(e.getMessage(), e);
196         }
197     }
198
199     /**
200      * Copies the source files to the destination.
201      */

202     private void handleFiles() throws Exception JavaDoc
203     {
204         // Locate the destination folder, and make sure it exists
205
final FileObject destFolder = resolveFile(destDirUrl);
206         destFolder.createFolder();
207
208         // Locate the source files, and make sure they exist
209
FileName srcDirName = null;
210         if (srcDirUrl !=null )
211         {
212             srcDirName = resolveFile(srcDirUrl).getName();
213         }
214         final ArrayList JavaDoc srcs = new ArrayList JavaDoc();
215         for (int i = 0; i < srcFiles.size(); i++)
216         {
217             // Locate the source file, and make sure it exists
218
final SourceInfo src = (SourceInfo) srcFiles.get(i);
219             final FileObject srcFile = resolveFile(src.file);
220             if (!srcFile.exists())
221             {
222                 final String JavaDoc message =
223                     Messages.getString("vfs.tasks/sync.src-file-no-exist.warn", srcFile);
224                 log(message, Project.MSG_WARN);
225             }
226             else
227             {
228                 srcs.add(srcFile);
229             }
230         }
231
232         // Scan the source files
233
final Set JavaDoc destFiles = new HashSet JavaDoc();
234         for (int i = 0; i < srcs.size(); i++)
235         {
236             final FileObject rootFile = (FileObject) srcs.get(i);
237             final FileName rootName = rootFile.getName();
238
239             if (rootFile.getType() == FileType.FILE)
240             {
241                 // Build the destination file name
242
String JavaDoc relName = null;
243                 if (srcDirName == null || !srcDirIsBase)
244                 {
245                     relName = rootName.getBaseName();
246                 }
247                 else
248                 {
249                     relName = srcDirName.getRelativeName(rootName);
250                 }
251                 final FileObject destFile = destFolder.resolveFile(relName, NameScope.DESCENDENT);
252
253                 // Do the copy
254
handleFile(destFiles, rootFile, destFile);
255             }
256             else
257             {
258                 // Find matching files
259
// If srcDirIsBase is true, select also the sub-directories
260
final FileObject[] files = rootFile.findFiles(srcDirIsBase ? Selectors.SELECT_ALL : Selectors.SELECT_FILES);
261
262                 for (int j = 0; j < files.length; j++)
263                 {
264                     final FileObject srcFile = files[j];
265
266                     // Build the destination file name
267
String JavaDoc relName = null;
268                     if (srcDirName == null || !srcDirIsBase)
269                     {
270                         relName = rootName.getRelativeName(srcFile.getName());
271                     }
272                     else
273                     {
274                         relName = srcDirName.getRelativeName(srcFile.getName());
275                     }
276
277                     final FileObject destFile =
278                         destFolder.resolveFile(relName, NameScope.DESCENDENT);
279
280                     // Do the copy
281
handleFile(destFiles, srcFile, destFile);
282                 }
283             }
284         }
285
286         // Scan the destination files for files with no source file
287
if (detectMissingSourceFiles())
288         {
289             final FileObject[] allDestFiles = destFolder.findFiles(Selectors.SELECT_FILES);
290             for (int i = 0; i < allDestFiles.length; i++)
291             {
292                 final FileObject destFile = allDestFiles[i];
293                 if (!destFiles.contains(destFile))
294                 {
295                     handleMissingSourceFile(destFile);
296                 }
297             }
298         }
299     }
300
301     /**
302      * Handles a single file, checking for collisions where more than one
303      * source file maps to the same destination file.
304      */

305     private void handleFile(final Set JavaDoc destFiles,
306                             final FileObject srcFile,
307                             final FileObject destFile) throws Exception JavaDoc
308
309     {
310         // Check for duplicate source files
311
if (destFiles.contains(destFile))
312         {
313             final String JavaDoc message = Messages.getString("vfs.tasks/sync.duplicate-source-files.warn", destFile);
314             log(message, Project.MSG_WARN);
315         }
316         else
317         {
318             destFiles.add(destFile);
319         }
320
321         // Handle the file
322
handleFile(srcFile, destFile);
323     }
324
325     /**
326      * Copies a single file.
327      */

328     private void handleSingleFile() throws Exception JavaDoc
329     {
330         // Make sure there is exactly one source file, and that it exists
331
// and is a file.
332
if (srcFiles.size() > 1)
333         {
334             final String JavaDoc message =
335                 Messages.getString("vfs.tasks/sync.too-many-source-files.error");
336             throw new BuildException(message);
337         }
338         final SourceInfo src = (SourceInfo) srcFiles.get(0);
339         final FileObject srcFile = resolveFile(src.file);
340         if (srcFile.getType() != FileType.FILE)
341         {
342             final String JavaDoc message =
343                 Messages.getString("vfs.tasks/sync.source-not-file.error", srcFile);
344             throw new BuildException(message);
345         }
346
347         // Locate the destination file
348
final FileObject destFile = resolveFile(destFileUrl);
349
350         // Do the copy
351
handleFile(srcFile, destFile);
352     }
353
354     /**
355      * Handles a single source file.
356      */

357     private void handleFile(final FileObject srcFile,
358                             final FileObject destFile)
359         throws Exception JavaDoc
360     {
361         if (!destFile.exists()
362             || srcFile.getContent().getLastModifiedTime() > destFile.getContent().getLastModifiedTime())
363         {
364             // Destination file is out-of-date
365
handleOutOfDateFile(srcFile, destFile);
366         }
367         else
368         {
369             // Destination file is up-to-date
370
handleUpToDateFile(srcFile, destFile);
371         }
372     }
373
374     /**
375      * Handles an out-of-date file (a file where the destination file
376      * either doesn't exist, or is older than the source file).
377      * This implementation does nothing.
378      */

379     protected void handleOutOfDateFile(final FileObject srcFile,
380                                        final FileObject destFile)
381         throws Exception JavaDoc
382     {
383     }
384
385     /**
386      * Handles an up-to-date file (where the destination file exists and is
387      * newer than the source file). This implementation does nothing.
388      */

389     protected void handleUpToDateFile(final FileObject srcFile,
390                                       final FileObject destFile)
391         throws Exception JavaDoc
392     {
393     }
394
395     /**
396      * Handles a destination for which there is no corresponding source file.
397      * This implementation does nothing.
398      */

399     protected void handleMissingSourceFile(final FileObject destFile)
400         throws Exception JavaDoc
401     {
402     }
403
404     /**
405      * Check if this task cares about destination files with a missing source
406      * file. This implementation returns false.
407      */

408     protected boolean detectMissingSourceFiles()
409     {
410         return false;
411     }
412
413     /**
414      * Information about a source file.
415      */

416     public static class SourceInfo
417     {
418         private String JavaDoc file;
419
420         public void setFile(final String JavaDoc file)
421         {
422             this.file = file;
423         }
424     }
425
426 }
427
Popular Tags