KickJava   Java API By Example, From Geeks To Geeks.

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


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.text.DateFormat JavaDoc;
24 import java.text.ParseException JavaDoc;
25 import java.text.SimpleDateFormat JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.Locale JavaDoc;
28 import java.util.Vector JavaDoc;
29 import org.apache.tools.ant.BuildException;
30 import org.apache.tools.ant.DirectoryScanner;
31 import org.apache.tools.ant.Project;
32 import org.apache.tools.ant.Task;
33 import org.apache.tools.ant.types.Mapper;
34 import org.apache.tools.ant.types.FileSet;
35 import org.apache.tools.ant.types.FileList;
36 import org.apache.tools.ant.types.Resource;
37 import org.apache.tools.ant.types.ResourceCollection;
38 import org.apache.tools.ant.types.resources.FileResource;
39 import org.apache.tools.ant.types.resources.Touchable;
40 import org.apache.tools.ant.types.resources.Union;
41 import org.apache.tools.ant.util.FileUtils;
42 import org.apache.tools.ant.util.FileNameMapper;
43
44 /**
45  * Touch a file and/or fileset(s) and/or filelist(s);
46  * corresponds to the Unix touch command.
47  *
48  * <p>If the file to touch doesn't exist, an empty one is created.</p>
49  *
50  * @since Ant 1.1
51  *
52  * @ant.task category="filesystem"
53  */

54 public class Touch extends Task {
55
56     private interface DateFormatFactory {
57         DateFormat JavaDoc getPrimaryFormat();
58         DateFormat JavaDoc getFallbackFormat();
59     }
60
61     private static final DateFormatFactory DEFAULT_DF_FACTORY
62         = new DateFormatFactory() {
63         /*
64          * The initial version used DateFormat.SHORT for the
65          * time format, which ignores seconds. If we want
66          * seconds as well, we need DateFormat.MEDIUM, which
67          * in turn would break all old build files.
68          *
69          * First try to parse with DateFormat.SHORT and if
70          * that fails with MEDIUM - throw an exception if both
71          * fail.
72          */

73         public DateFormat JavaDoc getPrimaryFormat() {
74             return DateFormat.getDateTimeInstance(DateFormat.SHORT,
75                 DateFormat.SHORT, Locale.US);
76         }
77         public DateFormat JavaDoc getFallbackFormat() {
78             return DateFormat.getDateTimeInstance(DateFormat.SHORT,
79                 DateFormat.MEDIUM, Locale.US);
80         }
81     };
82     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
83
84     private File JavaDoc file;
85     private long millis = -1;
86     private String JavaDoc dateTime;
87     private Vector JavaDoc filesets = new Vector JavaDoc();
88     private Union resources = new Union();
89     private boolean dateTimeConfigured;
90     private boolean mkdirs;
91     private boolean verbose = true;
92     private FileNameMapper fileNameMapper = null;
93     private DateFormatFactory dfFactory = DEFAULT_DF_FACTORY;
94
95     /**
96      * Construct a new <code>Touch</code> task.
97      */

98     public Touch() {
99     }
100
101     /**
102      * Sets a single source file to touch. If the file does not exist
103      * an empty file will be created.
104      * @param file the <code>File</code> to touch.
105      */

106     public void setFile(File JavaDoc file) {
107         this.file = file;
108     }
109
110     /**
111      * Set the new modification time of file(s) touched
112      * in milliseconds since midnight Jan 1 1970. Optional, default=now.
113      * @param millis the <code>long</code> timestamp to use.
114      */

115     public void setMillis(long millis) {
116         this.millis = millis;
117     }
118
119     /**
120      * Set the new modification time of file(s) touched
121      * in the format &quot;MM/DD/YYYY HH:MM AM <i>or</i> PM&quot;
122      * or &quot;MM/DD/YYYY HH:MM:SS AM <i>or</i> PM&quot;.
123      * Optional, default=now.
124      * @param dateTime the <code>String</code> date in the specified format.
125      */

126     public void setDatetime(String JavaDoc dateTime) {
127         if (this.dateTime != null) {
128             log("Resetting datetime attribute to " + dateTime, Project.MSG_VERBOSE);
129         }
130         this.dateTime = dateTime;
131         dateTimeConfigured = false;
132     }
133
134     /**
135      * Set whether nonexistent parent directories should be created
136      * when touching new files.
137      * @param mkdirs <code>boolean</code> whether to create parent directories.
138      * @since Ant 1.6.3
139      */

140     public void setMkdirs(boolean mkdirs) {
141         this.mkdirs = mkdirs;
142     }
143
144     /**
145      * Set whether the touch task will report every file it creates;
146      * defaults to <code>true</code>.
147      * @param verbose <code>boolean</code> flag.
148      * @since Ant 1.6.3
149      */

150     public void setVerbose(boolean verbose) {
151         this.verbose = verbose;
152     }
153
154     /**
155      * Set the format of the datetime attribute.
156      * @param pattern the <code>SimpleDateFormat</code>-compatible format pattern.
157      * @since Ant 1.6.3
158      */

159     public void setPattern(final String JavaDoc pattern) {
160         dfFactory = new DateFormatFactory() {
161             public DateFormat JavaDoc getPrimaryFormat() {
162                 return new SimpleDateFormat JavaDoc(pattern);
163             }
164             public DateFormat JavaDoc getFallbackFormat() {
165                 return null;
166             }
167         };
168     }
169
170     /**
171      * Add a <code>Mapper</code>.
172      * @param mapper the <code>Mapper</code> to add.
173      * @since Ant 1.6.3
174      */

175     public void addConfiguredMapper(Mapper mapper) {
176         add(mapper.getImplementation());
177     }
178
179     /**
180      * Add a <code>FileNameMapper</code>.
181      * @param fileNameMapper the <code>FileNameMapper</code> to add.
182      * @since Ant 1.6.3
183      * @throws BuildException if multiple mappers are added.
184      */

185     public void add(FileNameMapper fileNameMapper) throws BuildException {
186         if (this.fileNameMapper != null) {
187             throw new BuildException("Only one mapper may be added to the "
188                 + getTaskName() + " task.");
189         }
190         this.fileNameMapper = fileNameMapper;
191     }
192
193     /**
194      * Add a set of files to touch.
195      * @param set the <code>Fileset</code> to add.
196      */

197     public void addFileset(FileSet set) {
198         filesets.add(set);
199         add(set);
200     }
201
202     /**
203      * Add a filelist to touch.
204      * @param list the <code>Filelist</code> to add.
205      */

206     public void addFilelist(FileList list) {
207         add(list);
208     }
209
210     /**
211      * Add a collection of resources to touch.
212      * @param rc the collection to add.
213      * @since Ant 1.7
214      */

215     public void add(ResourceCollection rc) {
216         resources.add(rc);
217     }
218
219     /**
220      * Check that this task has been configured properly.
221      * @throws BuildException if configuration errors are detected.
222      * @since Ant 1.6.3
223      */

224     protected synchronized void checkConfiguration() throws BuildException {
225         if (file == null && resources.size() == 0) {
226             throw new BuildException("Specify at least one source"
227                                    + "--a file or resource collection.");
228         }
229         if (file != null && file.exists() && file.isDirectory()) {
230             throw new BuildException("Use a resource collection to touch directories.");
231         }
232         if (dateTime != null && !dateTimeConfigured) {
233             long workmillis = millis;
234             DateFormat JavaDoc df = dfFactory.getPrimaryFormat();
235             ParseException JavaDoc pe = null;
236             try {
237                 workmillis = df.parse(dateTime).getTime();
238             } catch (ParseException JavaDoc peOne) {
239                 df = dfFactory.getFallbackFormat();
240                 if (df == null) {
241                     pe = peOne;
242                 } else {
243                     try {
244                         workmillis = df.parse(dateTime).getTime();
245                     } catch (ParseException JavaDoc peTwo) {
246                         pe = peTwo;
247                     }
248                 }
249             }
250             if (pe != null) {
251                 throw new BuildException(pe.getMessage(), pe, getLocation());
252             }
253             if (workmillis < 0) {
254                 throw new BuildException("Date of " + dateTime
255                                          + " results in negative "
256                                          + "milliseconds value "
257                                          + "relative to epoch "
258                                          + "(January 1, 1970, "
259                                          + "00:00:00 GMT).");
260             }
261             log("Setting millis to " + workmillis + " from datetime attribute",
262                 ((millis < 0) ? Project.MSG_DEBUG : Project.MSG_VERBOSE));
263             setMillis(workmillis);
264             //only set if successful to this point:
265
dateTimeConfigured = true;
266         }
267     }
268
269     /**
270      * Execute the touch operation.
271      * @throws BuildException if an error occurs.
272      */

273     public void execute() throws BuildException {
274         checkConfiguration();
275         touch();
276     }
277
278     /**
279      * Does the actual work; assumes everything has been checked by now.
280      * @throws BuildException if an error occurs.
281      */

282     protected void touch() throws BuildException {
283         long defaultTimestamp = getTimestamp();
284
285         if (file != null) {
286             touch(new FileResource(file.getParentFile(), file.getName()),
287                   defaultTimestamp);
288         }
289         // deal with the resource collections
290
Iterator JavaDoc iter = resources.iterator();
291         while (iter.hasNext()) {
292             Resource r = (Resource) iter.next();
293             if (!(r instanceof Touchable)) {
294                 throw new BuildException("Can't touch " + r);
295             }
296             touch(r, defaultTimestamp);
297         }
298
299         // deal with filesets in a special way since the task
300
// originally also used the directories and Union won't return
301
// them.
302
for (int i = 0; i < filesets.size(); i++) {
303             FileSet fs = (FileSet) filesets.elementAt(i);
304             DirectoryScanner ds = fs.getDirectoryScanner(getProject());
305             File JavaDoc fromDir = fs.getDir(getProject());
306
307             String JavaDoc[] srcDirs = ds.getIncludedDirectories();
308
309             for (int j = 0; j < srcDirs.length; j++) {
310                 touch(new FileResource(fromDir, srcDirs[j]), defaultTimestamp);
311             }
312         }
313     }
314
315     /**
316      * Touch a single file with the current timestamp (this.millis). This method
317      * does not interact with any nested mappers and remains for reasons of
318      * backwards-compatibility only.
319      * @param file file to touch
320      * @throws BuildException on error
321      * @deprecated since 1.6.x.
322      */

323     protected void touch(File JavaDoc file) {
324         touch(file, getTimestamp());
325     }
326
327     private long getTimestamp() {
328         return (millis < 0) ? System.currentTimeMillis() : millis;
329     }
330
331     private void touch(Resource r, long defaultTimestamp) {
332         if (fileNameMapper == null) {
333             if (r instanceof FileResource) {
334                 // use this to create file and deal with non-writable files
335
touch(((FileResource) r).getFile(), defaultTimestamp);
336             } else {
337                 ((Touchable) r).touch(defaultTimestamp);
338             }
339         } else {
340             String JavaDoc[] mapped = fileNameMapper.mapFileName(r.getName());
341             if (mapped != null && mapped.length > 0) {
342                 long modTime = (r.isExists()) ? r.getLastModified()
343                     : defaultTimestamp;
344                 for (int i = 0; i < mapped.length; i++) {
345                     touch(getProject().resolveFile(mapped[i]), modTime);
346                 }
347             }
348         }
349     }
350
351     private void touch(File JavaDoc file, long modTime) {
352         if (!file.exists()) {
353             log("Creating " + file,
354                 ((verbose) ? Project.MSG_INFO : Project.MSG_VERBOSE));
355             try {
356                 FILE_UTILS.createNewFile(file, mkdirs);
357             } catch (IOException JavaDoc ioe) {
358                 throw new BuildException("Could not create " + file, ioe,
359                                          getLocation());
360             }
361         }
362         if (!file.canWrite()) {
363             throw new BuildException("Can not change modification date of "
364                                      + "read-only file " + file);
365         }
366         FILE_UTILS.setFileLastModified(file, modTime);
367     }
368
369 }
370
Popular Tags