KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > util > ResourceUtils


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.util;
19
20 import java.io.File JavaDoc;
21 import java.io.Reader JavaDoc;
22 import java.io.InputStream JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.io.BufferedReader JavaDoc;
26 import java.io.BufferedWriter JavaDoc;
27 import java.io.InputStreamReader JavaDoc;
28 import java.io.OutputStreamWriter JavaDoc;
29 import java.io.BufferedInputStream JavaDoc;
30 import java.util.Arrays JavaDoc;
31 import java.util.Vector JavaDoc;
32 import java.util.Iterator JavaDoc;
33
34 import org.apache.tools.ant.Project;
35 import org.apache.tools.ant.ProjectComponent;
36 import org.apache.tools.ant.filters.util.ChainReaderHelper;
37 import org.apache.tools.ant.types.Resource;
38 import org.apache.tools.ant.types.TimeComparison;
39 import org.apache.tools.ant.types.ResourceFactory;
40 import org.apache.tools.ant.types.ResourceCollection;
41 import org.apache.tools.ant.types.FilterSetCollection;
42 import org.apache.tools.ant.types.resources.Union;
43 import org.apache.tools.ant.types.resources.Restrict;
44 import org.apache.tools.ant.types.resources.Resources;
45 import org.apache.tools.ant.types.resources.Touchable;
46 import org.apache.tools.ant.types.resources.selectors.Or;
47 import org.apache.tools.ant.types.resources.selectors.And;
48 import org.apache.tools.ant.types.resources.selectors.Not;
49 import org.apache.tools.ant.types.resources.selectors.Date;
50 import org.apache.tools.ant.types.resources.selectors.Type;
51 import org.apache.tools.ant.types.resources.selectors.Exists;
52 import org.apache.tools.ant.types.resources.selectors.ResourceSelector;
53 import org.apache.tools.ant.types.selectors.SelectorUtils;
54
55 // CheckStyle:HideUtilityClassConstructorCheck OFF - bc
56

57 /**
58  * This class provides utility methods to process Resources.
59  *
60  * @since Ant 1.5.2
61  */

62 public class ResourceUtils {
63
64     private static final class Outdated implements ResourceSelector {
65         private Resource control;
66         private long granularity;
67         private Outdated(Resource control, long granularity) {
68             this.control = control;
69             this.granularity = granularity;
70         }
71         public boolean isSelected(Resource r) {
72             return SelectorUtils.isOutOfDate(control, r, granularity);
73         }
74     }
75     /** Utilities used for file operations */
76     private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
77
78     private static final ResourceSelector NOT_EXISTS = new Not(new Exists());
79
80     /**
81      * Tells which source files should be reprocessed based on the
82      * last modification date of target files.
83      * @param logTo where to send (more or less) interesting output.
84      * @param source array of resources bearing relative path and last
85      * modification date.
86      * @param mapper filename mapper indicating how to find the target
87      * files.
88      * @param targets object able to map as a resource a relative path
89      * at <b>destination</b>.
90      * @return array containing the source files which need to be
91      * copied or processed, because the targets are out of date or do
92      * not exist.
93      */

94     public static Resource[] selectOutOfDateSources(ProjectComponent logTo,
95                                                     Resource[] source,
96                                                     FileNameMapper mapper,
97                                                     ResourceFactory targets) {
98         return selectOutOfDateSources(logTo, source, mapper, targets,
99                                       FILE_UTILS.getFileTimestampGranularity());
100     }
101
102     /**
103      * Tells which source files should be reprocessed based on the
104      * last modification date of target files.
105      * @param logTo where to send (more or less) interesting output.
106      * @param source array of resources bearing relative path and last
107      * modification date.
108      * @param mapper filename mapper indicating how to find the target
109      * files.
110      * @param targets object able to map as a resource a relative path
111      * at <b>destination</b>.
112      * @param granularity The number of milliseconds leeway to give
113      * before deciding a target is out of date.
114      * @return array containing the source files which need to be
115      * copied or processed, because the targets are out of date or do
116      * not exist.
117      * @since Ant 1.6.2
118      */

119     public static Resource[] selectOutOfDateSources(ProjectComponent logTo,
120                                                     Resource[] source,
121                                                     FileNameMapper mapper,
122                                                     ResourceFactory targets,
123                                                     long granularity) {
124         Union u = new Union();
125         u.addAll(Arrays.asList(source));
126         ResourceCollection rc
127             = selectOutOfDateSources(logTo, u, mapper, targets, granularity);
128         return rc.size() == 0 ? new Resource[0] : ((Union) rc).listResources();
129     }
130
131     /**
132      * Tells which sources should be reprocessed based on the
133      * last modification date of targets.
134      * @param logTo where to send (more or less) interesting output.
135      * @param source ResourceCollection.
136      * @param mapper filename mapper indicating how to find the target Resources.
137      * @param targets object able to map a relative path as a Resource.
138      * @param granularity The number of milliseconds leeway to give
139      * before deciding a target is out of date.
140      * @return ResourceCollection.
141      * @since Ant 1.7
142      */

143     public static ResourceCollection selectOutOfDateSources(ProjectComponent logTo,
144                                                             ResourceCollection source,
145                                                             FileNameMapper mapper,
146                                                             ResourceFactory targets,
147                                                             long granularity) {
148         if (source.size() == 0) {
149             logTo.log("No sources found.", Project.MSG_VERBOSE);
150             return Resources.NONE;
151         }
152         source = Union.getInstance(source);
153         logFuture(logTo, source, granularity);
154
155         Union result = new Union();
156         for (Iterator JavaDoc iter = source.iterator(); iter.hasNext();) {
157             Resource sr = (Resource) iter.next();
158             String JavaDoc srName = sr.getName();
159             srName = srName == null
160                 ? srName : srName.replace('/', File.separatorChar);
161
162             String JavaDoc[] targetnames = null;
163             try {
164                 targetnames = mapper.mapFileName(srName);
165             } catch (Exception JavaDoc e) {
166         logTo.log("Caught " + e + " mapping resource " + sr,
167                     Project.MSG_VERBOSE);
168             }
169             if (targetnames == null || targetnames.length == 0) {
170                 logTo.log(sr + " skipped - don\'t know how to handle it",
171                       Project.MSG_VERBOSE);
172                 continue;
173             }
174             Union targetColl = new Union();
175             for (int i = 0; i < targetnames.length; i++) {
176                 targetColl.add(targets.getResource(
177                     targetnames[i].replace(File.separatorChar, '/')));
178             }
179             //find the out-of-date targets:
180
Restrict r = new Restrict();
181             r.add(new And(new ResourceSelector[] {Type.FILE, new Or(
182                 new ResourceSelector[] {NOT_EXISTS, new Outdated(sr, granularity)})}));
183             r.add(targetColl);
184             if (r.size() > 0) {
185                 result.add(sr);
186                 Resource t = (Resource) (r.iterator().next());
187                 logTo.log(sr.getName() + " added as " + t.getName()
188                     + (t.isExists() ? " is outdated." : " doesn\'t exist."),
189                     Project.MSG_VERBOSE);
190                 continue;
191             }
192             //log uptodateness of all targets:
193
logTo.log(sr.getName()
194                   + " omitted as " + targetColl.toString()
195                   + (targetColl.size() == 1 ? " is" : " are ")
196                   + " up to date.", Project.MSG_VERBOSE);
197         }
198         return result;
199     }
200
201     /**
202      * Convenience method to copy content from one Resource to another.
203      * No filtering is performed.
204      *
205      * @param source the Resource to copy from.
206      * Must not be <code>null</code>.
207      * @param dest the Resource to copy to.
208      * Must not be <code>null</code>.
209      *
210      * @throws IOException if the copying fails.
211      *
212      * @since Ant 1.7
213      */

214     public static void copyResource(Resource source, Resource dest) throws IOException JavaDoc {
215         copyResource(source, dest, null);
216     }
217
218     /**
219      * Convenience method to copy content from one Resource to another.
220      * No filtering is performed.
221      *
222      * @param source the Resource to copy from.
223      * Must not be <code>null</code>.
224      * @param dest the Resource to copy to.
225      * Must not be <code>null</code>.
226      * @param project the project instance.
227      *
228      * @throws IOException if the copying fails.
229      *
230      * @since Ant 1.7
231      */

232     public static void copyResource(Resource source, Resource dest, Project project)
233         throws IOException JavaDoc {
234         copyResource(source, dest, null, null, false,
235                      false, null, null, project);
236     }
237
238     // CheckStyle:ParameterNumberCheck OFF - bc
239
/**
240      * Convenience method to copy content from one Resource to another
241      * specifying whether token filtering must be used, whether filter chains
242      * must be used, whether newer destination files may be overwritten and
243      * whether the last modified time of <code>dest</code> file should be made
244      * equal to the last modified time of <code>source</code>.
245      *
246      * @param source the Resource to copy from.
247      * Must not be <code>null</code>.
248      * @param dest the Resource to copy to.
249      * Must not be <code>null</code>.
250      * @param filters the collection of filters to apply to this copy.
251      * @param filterChains filterChains to apply during the copy.
252      * @param overwrite Whether or not the destination Resource should be
253      * overwritten if it already exists.
254      * @param preserveLastModified Whether or not the last modified time of
255      * the destination Resource should be set to that
256      * of the source.
257      * @param inputEncoding the encoding used to read the files.
258      * @param outputEncoding the encoding used to write the files.
259      * @param project the project instance.
260      *
261      * @throws IOException if the copying fails.
262      *
263      * @since Ant 1.7
264      */

265     public static void copyResource(Resource source, Resource dest,
266                              FilterSetCollection filters, Vector JavaDoc filterChains,
267                              boolean overwrite, boolean preserveLastModified,
268                              String JavaDoc inputEncoding, String JavaDoc outputEncoding,
269                              Project project)
270         throws IOException JavaDoc {
271         if (!overwrite) {
272             long slm = source.getLastModified();
273             if (dest.isExists() && slm != 0
274                 && dest.getLastModified() > slm) {
275                 return;
276             }
277         }
278         final boolean filterSetsAvailable = (filters != null
279                                              && filters.hasFilters());
280         final boolean filterChainsAvailable = (filterChains != null
281                                                && filterChains.size() > 0);
282         if (filterSetsAvailable) {
283             BufferedReader JavaDoc in = null;
284             BufferedWriter JavaDoc out = null;
285             try {
286                 InputStreamReader JavaDoc isr = null;
287                 if (inputEncoding == null) {
288                     isr = new InputStreamReader JavaDoc(source.getInputStream());
289                 } else {
290                     isr = new InputStreamReader JavaDoc(source.getInputStream(),
291                                                 inputEncoding);
292                 }
293                 in = new BufferedReader JavaDoc(isr);
294                 OutputStreamWriter JavaDoc osw = null;
295                 if (outputEncoding == null) {
296                     osw = new OutputStreamWriter JavaDoc(dest.getOutputStream());
297                 } else {
298                     osw = new OutputStreamWriter JavaDoc(dest.getOutputStream(),
299                                                  outputEncoding);
300                 }
301                 out = new BufferedWriter JavaDoc(osw);
302                 if (filterChainsAvailable) {
303                     ChainReaderHelper crh = new ChainReaderHelper();
304                     crh.setBufferSize(FileUtils.BUF_SIZE);
305                     crh.setPrimaryReader(in);
306                     crh.setFilterChains(filterChains);
307                     crh.setProject(project);
308                     Reader JavaDoc rdr = crh.getAssembledReader();
309                     in = new BufferedReader JavaDoc(rdr);
310                 }
311                 LineTokenizer lineTokenizer = new LineTokenizer();
312                 lineTokenizer.setIncludeDelims(true);
313                 String JavaDoc newline = null;
314                 String JavaDoc line = lineTokenizer.getToken(in);
315                 while (line != null) {
316                     if (line.length() == 0) {
317                         // this should not happen, because the lines are
318
// returned with the end of line delimiter
319
out.newLine();
320                     } else {
321                         newline = filters.replaceTokens(line);
322                         out.write(newline);
323                     }
324                     line = lineTokenizer.getToken(in);
325                 }
326             } finally {
327                 FileUtils.close(out);
328                 FileUtils.close(in);
329             }
330         } else if (filterChainsAvailable
331                    || (inputEncoding != null
332                        && !inputEncoding.equals(outputEncoding))
333                    || (inputEncoding == null && outputEncoding != null)) {
334             BufferedReader JavaDoc in = null;
335             BufferedWriter JavaDoc out = null;
336             try {
337                 InputStreamReader JavaDoc isr = null;
338                 if (inputEncoding == null) {
339                     isr = new InputStreamReader JavaDoc(source.getInputStream());
340                 } else {
341                     isr = new InputStreamReader JavaDoc(source.getInputStream(),
342                                                 inputEncoding);
343                 }
344                 in = new BufferedReader JavaDoc(isr);
345                 OutputStreamWriter JavaDoc osw = null;
346                 if (outputEncoding == null) {
347                     osw = new OutputStreamWriter JavaDoc(dest.getOutputStream());
348                 } else {
349                     osw = new OutputStreamWriter JavaDoc(dest.getOutputStream(),
350                                                  outputEncoding);
351                 }
352                 out = new BufferedWriter JavaDoc(osw);
353                 if (filterChainsAvailable) {
354                     ChainReaderHelper crh = new ChainReaderHelper();
355                     crh.setBufferSize(FileUtils.BUF_SIZE);
356                     crh.setPrimaryReader(in);
357                     crh.setFilterChains(filterChains);
358                     crh.setProject(project);
359                     Reader JavaDoc rdr = crh.getAssembledReader();
360                     in = new BufferedReader JavaDoc(rdr);
361                 }
362                 char[] buffer = new char[FileUtils.BUF_SIZE];
363                 while (true) {
364                     int nRead = in.read(buffer, 0, buffer.length);
365                     if (nRead == -1) {
366                         break;
367                     }
368                     out.write(buffer, 0, nRead);
369                 }
370             } finally {
371                 FileUtils.close(out);
372                 FileUtils.close(in);
373             }
374         } else {
375             InputStream JavaDoc in = null;
376             OutputStream JavaDoc out = null;
377             try {
378                 in = source.getInputStream();
379                 out = dest.getOutputStream();
380
381                 byte[] buffer = new byte[FileUtils.BUF_SIZE];
382                 int count = 0;
383                 do {
384                     out.write(buffer, 0, count);
385                     count = in.read(buffer, 0, buffer.length);
386                 } while (count != -1);
387             } finally {
388                 FileUtils.close(out);
389                 FileUtils.close(in);
390             }
391         }
392         if (preserveLastModified && dest instanceof Touchable) {
393             setLastModified((Touchable) dest, source.getLastModified());
394         }
395     }
396     // CheckStyle:ParameterNumberCheck ON
397

398     /**
399      * Set the last modified time of an object implementing
400      * org.apache.tools.ant.types.resources.Touchable .
401      *
402      * @param t the Touchable whose modified time is to be set.
403      * @param time the time to which the last modified time is to be set.
404      * if this is -1, the current time is used.
405      * @since Ant 1.7
406      */

407     public static void setLastModified(Touchable t, long time) {
408         t.touch((time < 0) ? System.currentTimeMillis() : time);
409     }
410
411     /**
412      * Compares the contents of two Resources.
413      *
414      * @param r1 the Resource whose content is to be compared.
415      * @param r2 the other Resource whose content is to be compared.
416      * @param text true if the content is to be treated as text and
417      * differences in kind of line break are to be ignored.
418      *
419      * @return true if the content of the Resources is the same.
420      *
421      * @throws IOException if the Resources cannot be read.
422      * @since Ant 1.7
423      */

424     public static boolean contentEquals(Resource r1, Resource r2, boolean text) throws IOException JavaDoc {
425         if (r1.isExists() != r2.isExists()) {
426             return false;
427         }
428         if (!r1.isExists()) {
429             // two not existing files are equal
430
return true;
431         }
432         // should the following two be switched? If r1 and r2 refer to the same file,
433
// isn't their content equal regardless of whether that file is a directory?
434
if (r1.isDirectory() || r2.isDirectory()) {
435             // don't want to compare directory contents for now
436
return false;
437         }
438         if (r1.equals(r2)) {
439             return true;
440         }
441         if (!text && r1.getSize() != r2.getSize()) {
442             return false;
443         }
444         return compareContent(r1, r2, text) == 0;
445     }
446
447     /**
448      * Compare the content of two Resources. A nonexistent Resource's
449      * content is "less than" that of an existing Resource; a directory-type
450      * Resource's content is "less than" that of a file-type Resource.
451      * @param r1 the Resource whose content is to be compared.
452      * @param r2 the other Resource whose content is to be compared.
453      * @param text true if the content is to be treated as text and
454      * differences in kind of line break are to be ignored.
455      * @return a negative integer, zero, or a positive integer as the first
456      * argument is less than, equal to, or greater than the second.
457      * @throws IOException if the Resources cannot be read.
458      * @since Ant 1.7
459      */

460     public static int compareContent(Resource r1, Resource r2, boolean text) throws IOException JavaDoc {
461         if (r1.equals(r2)) {
462             return 0;
463         }
464         boolean e1 = r1.isExists();
465         boolean e2 = r2.isExists();
466         if (!(e1 || e2)) {
467             return 0;
468         }
469         if (e1 != e2) {
470             return e1 ? 1 : -1;
471         }
472         boolean d1 = r1.isDirectory();
473         boolean d2 = r2.isDirectory();
474         if (d1 && d2) {
475             return 0;
476         }
477         if (d1 || d2) {
478             return d1 ? -1 : 1;
479         }
480         return text ? textCompare(r1, r2) : binaryCompare(r1, r2);
481     }
482
483     /**
484      * Binary compares the contents of two Resources.
485      * <p>
486      * simple but sub-optimal comparision algorithm. written for working
487      * rather than fast. Better would be a block read into buffers followed
488      * by long comparisions apart from the final 1-7 bytes.
489      * </p>
490      *
491      * @param r1 the Resource whose content is to be compared.
492      * @param r2 the other Resource whose content is to be compared.
493      * @return a negative integer, zero, or a positive integer as the first
494      * argument is less than, equal to, or greater than the second.
495      * @throws IOException if the Resources cannot be read.
496      * @since Ant 1.7
497      */

498     private static int binaryCompare(Resource r1, Resource r2) throws IOException JavaDoc {
499         InputStream JavaDoc in1 = null;
500         InputStream JavaDoc in2 = null;
501         try {
502             in1 = new BufferedInputStream JavaDoc(r1.getInputStream());
503             in2 = new BufferedInputStream JavaDoc(r2.getInputStream());
504
505             for (int b1 = in1.read(); b1 != -1; b1 = in1.read()) {
506                 int b2 = in2.read();
507                 if (b1 != b2) {
508                     return b1 > b2 ? 1 : -1;
509                 }
510             }
511             return in2.read() == -1 ? 0 : -1;
512         } finally {
513             FileUtils.close(in1);
514             FileUtils.close(in2);
515         }
516     }
517
518     /**
519      * Text compares the contents of two Resources.
520      * Ignores different kinds of line endings.
521      * @param r1 the Resource whose content is to be compared.
522      * @param r2 the other Resource whose content is to be compared.
523      * @return a negative integer, zero, or a positive integer as the first
524      * argument is less than, equal to, or greater than the second.
525      * @throws IOException if the Resources cannot be read.
526      * @since Ant 1.7
527      */

528     private static int textCompare(Resource r1, Resource r2) throws IOException JavaDoc {
529         BufferedReader JavaDoc in1 = null;
530         BufferedReader JavaDoc in2 = null;
531         try {
532             in1 = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(r1.getInputStream()));
533             in2 = new BufferedReader JavaDoc(new InputStreamReader JavaDoc(r2.getInputStream()));
534
535             String JavaDoc expected = in1.readLine();
536             while (expected != null) {
537                 String JavaDoc actual = in2.readLine();
538                 if (!expected.equals(actual)) {
539                     return expected.compareTo(actual);
540                 }
541                 expected = in1.readLine();
542             }
543             return in2.readLine() == null ? 0 : -1;
544         } finally {
545             FileUtils.close(in1);
546             FileUtils.close(in2);
547         }
548     }
549
550     /**
551      * Log which Resources (if any) have been modified in the future.
552      * @param logTo the ProjectComponent to do the logging.
553      * @param rc the collection of Resources to check.
554      * @param granularity the timestamp granularity to use.
555      * @since Ant 1.7
556      */

557     private static void logFuture(ProjectComponent logTo,
558                                   ResourceCollection rc, long granularity) {
559         long now = System.currentTimeMillis() + granularity;
560         Date sel = new Date();
561         sel.setMillis(now);
562         sel.setWhen(TimeComparison.AFTER);
563         Restrict future = new Restrict();
564         future.add(sel);
565         future.add(rc);
566         for (Iterator JavaDoc iter = future.iterator(); iter.hasNext();) {
567             logTo.log("Warning: " + ((Resource) iter.next()).getName()
568                      + " modified in the future.", Project.MSG_WARN);
569         }
570     }
571
572 }
573
Popular Tags