KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > antmod > tasks > ConditionalAnt


1 package org.antmod.tasks;
2
3 import java.io.BufferedInputStream JavaDoc;
4 import java.io.File JavaDoc;
5 import java.io.FileInputStream JavaDoc;
6 import java.io.IOException JavaDoc;
7 import java.util.ArrayList JavaDoc;
8 import java.util.Enumeration JavaDoc;
9 import java.util.HashMap JavaDoc;
10 import java.util.Iterator JavaDoc;
11 import java.util.List JavaDoc;
12 import java.util.Properties JavaDoc;
13
14 import org.antmod.util.AntUtil;
15 import org.apache.commons.io.FileUtils;
16 import org.apache.commons.lang.SystemUtils;
17 import org.apache.tools.ant.BuildException;
18 import org.apache.tools.ant.Project;
19 import org.apache.tools.ant.taskdefs.Ant;
20 import org.apache.tools.ant.taskdefs.Property;
21 import org.apache.tools.ant.types.FilterSet;
22
23 /**
24  * A task that conditionally calls a target in another build file,
25  * and if the other buildfile or target do not exist it invokes
26  * a 'defaulttarget' in the existing buildfile.
27  *
28  * @author Klaas Waslander
29  */

30 public class ConditionalAnt extends Ant {
31
32     private String JavaDoc defaultTarget;
33     private String JavaDoc otherAntfileName;
34     private String JavaDoc otherTarget;
35     private File JavaDoc checkChangesDir = null;
36     private boolean checkChangesOutput = false;
37     private ArrayList JavaDoc passbackRefs = new ArrayList JavaDoc(0);
38     
39     /**
40      * Property already available in superclass, needed here because it is private there
41      */

42     private boolean inheritAllProperty = true;
43
44     /**
45      * Property already available in superclass, needed here because it is private there
46      */

47     private boolean inheritRefsProperty = false;
48
49     /**
50      * Property already available in superclass, needed here because it is private there
51      */

52     private ArrayList JavaDoc properties = new ArrayList JavaDoc();
53
54     /**
55      * Property already available in superclass, needed here because it is private there
56      */

57     private File JavaDoc dirProperty = null;
58
59     /** timestamp of the newest file in a directory, key=dir, value=long */
60     private static HashMap JavaDoc newestFileInDir = new HashMap JavaDoc();
61
62     /**
63      * Create a new instance of ConditionalAnt.
64      */

65     public ConditionalAnt() {
66         // make inheritRefs default to "true"
67
setInheritRefs(true);
68     }
69
70     /**
71      * Override setInheritAll method only to capture the value of the setting
72      * in this subclass, because Ant's base-class does not allow access
73      * to the inheritAll variable.
74      */

75     public void setInheritAll(boolean inheritAll) {
76         this.inheritAllProperty = inheritAll;
77         super.setInheritAll(inheritAll);
78     }
79
80     /**
81      * Override setInheritRefs method only to capture the value of the setting
82      * in this subclass, because Ant's base-class does not allow access
83      * to the inheritRefs variable.
84      */

85     public void setInheritRefs(boolean inheritRefs) {
86         this.inheritRefsProperty = inheritRefs;
87         super.setInheritRefs(inheritRefs);
88     }
89
90     /**
91      * Override setDir method only to capture the value of the setting
92      * in this subclass, because Ant's base-class does not allow access
93      * to the dir variable.
94      */

95     public void setDir(File JavaDoc dir) {
96         this.dirProperty = dir;
97         super.setDir(dir);
98     }
99
100     /**
101      * Override createProperty method only to capture the added property
102      * in this subclass, because Ant's base-class does not allow access
103      * to the 'properties' variable.
104      */

105     public Property createProperty() {
106         Property result = super.createProperty();
107         this.properties.add(result);
108         return result;
109     }
110
111     public void setAntfile(String JavaDoc antFile) {
112         this.otherAntfileName = antFile;
113         super.setAntfile(antFile);
114     }
115
116     public void setTarget(String JavaDoc target) {
117         this.otherTarget = target;
118         super.setTarget(target);
119     }
120
121     public void setDefaultTarget(String JavaDoc defaultTarget) {
122         this.defaultTarget = defaultTarget;
123     }
124
125     public void setCheckChangesDir(File JavaDoc checkChangesDir) {
126         this.checkChangesDir = checkChangesDir;
127     }
128     
129     public void setCheckChangesOutput(boolean checkChangesOutput) {
130         this.checkChangesOutput = checkChangesOutput;
131     }
132
133     /**
134      * Add a reference element that may be present in the child
135      * Ant project after the Ant target has been invoked, and which
136      * is to be passed back to this Ant project.
137      * <br/>
138      * <b>Adding passback references means that the other Ant target
139      * is invoked using custom-maintained Java code that is not part
140      * of the Ant code base. This may break during an Ant version upgrade.</b>
141      *
142      * @param passbackReference The reference to be passed back to this Ant project
143      */

144     public void addPassbackRef(Reference passbackReference) {
145         this.passbackRefs.add(passbackReference);
146     }
147
148     /**
149      * Handy single API call to set all passback refs to be passed back.
150      * @see #addPassbackRef
151      * @param passbackRefs List of Reference objects
152      */

153     public void setPassbackRefs(List JavaDoc passbackRefs) {
154         this.passbackRefs = new ArrayList JavaDoc(passbackRefs);
155     }
156
157     /**
158      * Checks if changes are needed, based on directory to-be-checked, and the otherTarget+defaultTarget names.
159      * @param checkChangesDir
160      * @param otherTarget
161      * @param defaultTarget
162      * @return
163      */

164     public static boolean isExecuteNotNeeded(File JavaDoc checkChangesDir, String JavaDoc otherTarget, String JavaDoc defaultTarget) {
165         if (checkChangesDir != null) {
166         // check timestamp
167
File JavaDoc[] checkChangesDirList = checkChangesDir.listFiles();
168             if (checkChangesDirList != null && checkChangesDirList.length > 0) {
169                 File JavaDoc newestFile = getNewestFile(checkChangesDir);
170                 long lastExecTime = readLastExecTime(checkChangesDir, otherTarget + "-" + defaultTarget);
171                 if (newestFile == null) {
172                     System.err.println("Unknown whether changes occured in " + checkChangesDir.getPath() + ", continuing to execute '" + otherTarget + "'" + ((defaultTarget != null) ? " or '" + defaultTarget + "'" : ""));
173                 }
174                 else if (newestFile.lastModified() <= lastExecTime) {
175                     // nothing to do - ignore
176
//log("Not executing '" + this.otherTarget + "'" + ((defaultTarget != null) ? " or '" + defaultTarget + "'" : "") + " - nothing changed.", Project.MSG_WARN);
177
return true;
178                 }
179                 else {
180                     //log("Executing '" + this.otherTarget + "'" + ((defaultTarget != null) ? " or '" + defaultTarget + "'" : "") + ": changed="+newestFile.getName(), Project.MSG_WARN);
181
}
182             }
183         }
184         return false;
185     }
186
187     /**
188      * Invokes the Ant target as specified, conditionally checking
189      * if the Ant target exists in the new Ant project.
190      */

191     public void execute() throws BuildException {
192         // improve log output by setting a short task name
193
setTaskName("cond-ant");
194
195         if (isExecuteNotNeeded(this.checkChangesDir, this.otherTarget, this.defaultTarget)) {
196             if (this.checkChangesOutput) {
197                 log("No changes for '" + this.otherTarget + "' in module: '" + this.checkChangesDir.getName() + "'", Project.MSG_WARN);
198             }
199             return;
200         }
201
202
203         // check other ant file
204
File JavaDoc otherAntfile = null;
205         if (this.dirProperty != null) {
206             otherAntfile = new File JavaDoc(this.dirProperty, this.otherAntfileName);
207         } else {
208             otherAntfile = new File JavaDoc(this.otherAntfileName);
209         }
210         if (otherAntfile.exists()) {
211             Project newProject = AntUtil.getAntProject(getProject(), otherAntfile, false);
212
213             // see if it has the target
214
Enumeration JavaDoc targetNames = newProject.getTargets().keys();
215             while (targetNames.hasMoreElements()) {
216                 if (((String JavaDoc)targetNames.nextElement()).equalsIgnoreCase(this.otherTarget)) {
217                     if (this.passbackRefs.isEmpty()) {
218                         super.execute();
219                     } else {
220                         customExecute(otherAntfile);
221                     }
222
223                     // only update timestamp if everything was succesfull!
224
if (checkChangesDir != null) {
225                         writeLastExecTime(checkChangesDir, otherTarget + "-" + defaultTarget, System.currentTimeMillis());
226                     }
227                     return;
228                 }
229             }
230         }
231
232         // other ant file or other target did not exist -- invoke default target
233
if (this.defaultTarget != null) {
234             getProject().executeTarget(this.defaultTarget);
235         }
236
237         // only update timestamp if everything was succesfull!
238
if (checkChangesDir != null) {
239             writeLastExecTime(checkChangesDir, otherTarget + "-" + defaultTarget, System.currentTimeMillis());
240         }
241     }
242     
243     /**
244      * Custom execution code, that replaces the "super.execute()"
245      * method especially for passback-references.
246      * @param newProject Already initialized new Ant project
247      */

248     private void customExecute(File JavaDoc otherAntfile) {
249         //getProject().log("CUSTOM EXECUTE", Project.MSG_WARN);
250

251         // optionally inherit all
252
Project newProject = AntUtil.getAntProject(getProject(), otherAntfile, this.inheritAllProperty);
253
254         // set basedir correctly
255
if (this.dirProperty != null) {
256             newProject.setBaseDir(this.dirProperty);
257             newProject.setInheritedProperty("basedir", this.dirProperty.getAbsolutePath());
258         }
259
260         // optionally inherit refs
261
if (this.inheritRefsProperty) {
262             AntUtil.inheritRefs(getProject(), newProject);
263         }
264         
265         // optionally inherit nested properties
266
Iterator JavaDoc iter = this.properties.iterator();
267         while (iter.hasNext()) {
268             Property p = (Property) iter.next();
269             p.setProject(newProject);
270             p.execute();
271         }
272         getProject().copyInheritedProperties(newProject);
273
274         // execute the Ant target in the other Ant file
275
newProject.executeTarget(this.otherTarget);
276         
277         // optionally pass-back references from new project to parent project
278
Iterator JavaDoc refIter = this.passbackRefs.iterator();
279         while (refIter.hasNext()) {
280             Reference passbackRef = (Reference) refIter.next();
281             Object JavaDoc childRef = newProject.getReference(passbackRef.getRefId());
282             if (childRef != null) {
283                 String JavaDoc toRefid = passbackRef.getToRefid();
284                 if (toRefid == null) {
285                     toRefid = passbackRef.getRefId();
286                 }
287                 //getProject().log("PASSING BACK REFERENCE from \"" + otherAntfile.getPath() + "\" to \"" + getProject().getBaseDir() + "\" : " + passbackRef.getRefId(), Project.MSG_WARN);
288
getProject().addReference(toRefid, childRef);
289                 //getProject().log("PASSING BACK REFERENCE *DONE*: " + passbackRef.getRefId(), Project.MSG_WARN);
290
}
291         }
292     }
293
294     /**
295      * Reads the last execution time from a temporary file.
296      */

297     private static long readLastExecTime(File JavaDoc dir, String JavaDoc targetKey) {
298         File JavaDoc lastExecFile = getLastExecFile(dir, targetKey);
299         if (!lastExecFile.exists()) {
300             return -1;
301         } else {
302             return lastExecFile.lastModified();
303         }
304     }
305
306     /**
307      * Writes last execution time to a temporary file.
308      */

309     private void writeLastExecTime(File JavaDoc dir, String JavaDoc targetKey, long newTime) {
310         File JavaDoc lastExecFile = getLastExecFile(dir, targetKey);
311         if (lastExecFile.exists()) {
312             lastExecFile.delete();
313         }
314         try {
315             lastExecFile.getParentFile().mkdirs();
316             FileUtils.writeStringToFile(lastExecFile, "This file intentionally left blank.", SystemUtils.FILE_ENCODING);
317         }
318         catch (IOException JavaDoc e) {
319             e.printStackTrace();
320         }
321     }
322
323     /**
324      * Returns last exec file.
325      */

326     private static File JavaDoc getLastExecFile(File JavaDoc dir, String JavaDoc targetKey) {
327         File JavaDoc tmpDir = new File JavaDoc(
328             SystemUtils.JAVA_IO_TMPDIR,
329             SystemUtils.USER_NAME + File.separator + "antmod" + File.separator + dir.getPath().replace(':', File.separatorChar));
330         File JavaDoc lastExecFile = new File JavaDoc(tmpDir, targetKey + ".accesstime");
331         return lastExecFile;
332     }
333
334     /**
335      * Get the newest file in the given directory, ignoring everything
336      * listed in the ".cvsignore" file.
337      */

338     private static File JavaDoc getNewestFile(File JavaDoc dir) {
339         File JavaDoc result = (File JavaDoc)newestFileInDir.get(dir.getPath());
340         if (result == null) {
341             result = getNewestFileTimeImpl(dir);
342             newestFileInDir.put(dir.getPath(), result);
343         }
344         return result;
345     }
346
347     /**
348      * Recursively finds newest file in the given directory.
349      */

350     private static File JavaDoc getNewestFileTimeImpl(File JavaDoc dir) {
351         File JavaDoc result = null;
352         try {
353             // find out what to ignore
354
ArrayList JavaDoc ignores = new ArrayList JavaDoc(0);
355             File JavaDoc ignoreFile = new File JavaDoc(dir, ".cvsignore");
356             if (ignoreFile.exists()) {
357                 Properties JavaDoc fileNames = new Properties JavaDoc();
358                 BufferedInputStream JavaDoc in = new BufferedInputStream JavaDoc(new FileInputStream JavaDoc(ignoreFile));
359                 fileNames.load(in);
360                 Iterator JavaDoc it = fileNames.keySet().iterator();
361                 while (it.hasNext()) {
362                     String JavaDoc newIgnore = (String JavaDoc)it.next();
363                     ignores.add(newIgnore);
364                     //log("CVS ignore found: \"" + newIgnore + "\"", Project.MSG_WARN);
365
}
366             }
367             
368             // always add some files to the to-be-ignored check files
369
ignores.add("build.number");
370             ignores.add("CVS");
371             ignores.add(".svn");
372             ignores.add("build");
373             ignores.add("build.xml");
374
375             // iterate through files
376
File JavaDoc[] list = dir.listFiles();
377             for (int i = 0; list != null && i < list.length; i++) {
378                 File JavaDoc file = list[i];
379
380                 if (ignores.contains(file.getName())) {
381                     //log("Ignoring: " + file.getName(), Project.MSG_WARN);
382
// do nothing
383
}
384                 else if (file.isDirectory()) {
385                     File JavaDoc newestInDir = getNewestFileTimeImpl(file);
386                     if (result == null ||
387                         (newestInDir != null && newestInDir.lastModified() > result.lastModified()))
388                     {
389                         result = newestInDir;
390                     }
391                 }
392                 else if (result == null || file.lastModified() > result.lastModified()) {
393                     result = file;
394                 }
395             }
396         } catch (IOException JavaDoc ioe) {
397             ioe.printStackTrace();
398         }
399         return result;
400     }
401
402 }
403
Popular Tags