KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > xdoclet > ant > modulesbuilder > ModulesGrandBuilderTask


1 /*
2  * Copyright (c) 2001, 2002 The XDoclet team
3  * All rights reserved.
4  */

5 package xdoclet.ant.modulesbuilder;
6
7 import java.io.File JavaDoc;
8 import java.io.FileInputStream JavaDoc;
9 import java.io.FileNotFoundException JavaDoc;
10 import java.io.IOException JavaDoc;
11 import java.util.*;
12
13 import org.apache.tools.ant.BuildException;
14 import org.apache.tools.ant.Project;
15 import org.apache.tools.ant.Task;
16 import org.apache.tools.ant.taskdefs.Execute;
17 import org.apache.tools.ant.taskdefs.LogStreamHandler;
18 import org.apache.tools.ant.types.CommandlineJava;
19 import org.apache.tools.ant.types.DTDLocation;
20 import org.apache.tools.ant.types.Environment;
21 import org.apache.tools.ant.types.Path;
22 import org.apache.tools.ant.types.XMLCatalog;
23
24 /**
25  * Loops over all modules and builds each one. It builds modules the module depends on first. The module dependency is
26  * specified in a module.xml file in the root of each module. It's based on Ant's dependency checking code. Refer to
27  * that code for more details.
28  *
29  * @author Ara Abrahamian (ara_e_w@yahoo.com)
30  * @created Jun 9, 2002
31  * @version $Revision: 1.13 $
32  */

33 public class ModulesGrandBuilderTask extends Task
34 {
35     /**
36      * Constant for the "visiting" state, used when traversing a DFS of target dependencies.
37      */

38     private final static String JavaDoc VISITING = "VISITING";
39     /**
40      * Constant for the "visited" state, used when traversing a DFS of target dependencies.
41      */

42     private final static String JavaDoc VISITED = "VISITED";
43
44     private static ModuleXmlParser parser = new ModuleXmlParser();
45
46     private String JavaDoc target = null;
47
48     /**
49      * for resolving entities such as dtds
50      */

51     private XMLCatalog xmlCatalog = new XMLCatalog();
52
53     private static boolean isModule(File JavaDoc file)
54     {
55         File JavaDoc module_build_xml = new File JavaDoc(file, "build.xml");
56
57         return (!file.getName().equalsIgnoreCase("build")) && (!file.getName().equalsIgnoreCase("cvs")) && module_build_xml.exists();
58     }
59
60     private static BuildException makeCircularException(String JavaDoc end, Stack stk)
61     {
62         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Circular dependency: ");
63
64         sb.append(end);
65
66         String JavaDoc c;
67
68         do {
69             c = (String JavaDoc) stk.pop();
70             sb.append(" <- ");
71             sb.append(c);
72         } while (!c.equals(end));
73
74         return new BuildException(new String JavaDoc(sb));
75     }
76
77     /**
78      * set the name of the target to be called in each of the modules' build files
79      *
80      * @param target the target name
81      */

82     public void setTarget(String JavaDoc target)
83     {
84         this.target = target;
85     }
86
87     public final Vector topoSort(String JavaDoc root, Hashtable modules) throws BuildException
88     {
89         Vector ret = new Vector();
90         Hashtable state = new Hashtable();
91         Stack visiting = new Stack();
92
93         // We first run a DFS based sort using the root as the starting node.
94
// This creates the minimum sequence of Modules to the root node.
95
// We then do a sort on any remaining unVISITED modules.
96
// This is unnecessary for doing our build, but it catches
97
// circular dependencies or missing Modules on the entire
98
// dependency tree, not just on the Modules that depend on the
99
// build Module.
100
tsort(root, modules, state, visiting, ret);
101
102         for (Enumeration en = modules.keys(); en.hasMoreElements(); ) {
103             String JavaDoc cur_module = (String JavaDoc) en.nextElement();
104             String JavaDoc st = (String JavaDoc) state.get(cur_module);
105
106             if (st == null) {
107                 tsort(cur_module, modules, state, visiting, ret);
108             }
109             else if (st.equals(VISITING)) {
110                 throw new RuntimeException JavaDoc("Unexpected node in visiting state: " + cur_module);
111             }
112         }
113
114         return ret;
115     }
116
117     /**
118      * add an XMLCatalog as a nested element; optional.
119      *
120      * @param catalog The feature to be added to the ConfiguredXMLCatalog attribute
121      */

122     public void addConfiguredXMLCatalog(XMLCatalog catalog)
123     {
124         xmlCatalog.addConfiguredXMLCatalog(catalog);
125     }
126
127     /**
128      * Create a DTD location record; optional. This stores the location of a DTD. The DTD is identified by its public
129      * Id.
130      *
131      * @return
132      */

133     public DTDLocation createDTD()
134     {
135         DTDLocation dtdLocation = new DTDLocation();
136
137         xmlCatalog.addDTD(dtdLocation);
138         return dtdLocation;
139     }
140
141     /**
142      * Initialize internal instance of XMLCatalog
143      *
144      * @exception BuildException
145      */

146     public void init() throws BuildException
147     {
148         super.init();
149         xmlCatalog.setProject(project);
150     }
151
152     public void execute() throws BuildException
153     {
154         File JavaDoc base_dir = this.getProject().getBaseDir();
155         File JavaDoc[] files = base_dir.listFiles();
156         Hashtable modules = new Hashtable();
157
158         parser.setEntityResolver(xmlCatalog);
159
160         for (int i = 0; i < files.length; i++) {
161             File JavaDoc file = files[i];
162
163             if (file.isDirectory() && isModule(file)) {
164                 Module module = createModule(file);
165
166                 modules.put(module.getName(), module);
167             }
168         }
169
170         //for all modules, one by one, execute each one, but first sort the list based on dependency path of each module
171
for (Enumeration en = modules.elements(); en.hasMoreElements(); ) {
172             Module module = (Module) en.nextElement();
173             Vector sorted_modules = topoSort(module.getName(), modules);
174
175             int curidx = 0;
176             Module cur_module;
177
178             do {
179                 cur_module = (Module) sorted_modules.elementAt(curidx++);
180
181                 if (cur_module.isExecuted() == false) {
182                     executeModule(cur_module);
183                     cur_module.setExecuted(true);
184                 }
185             } while (!cur_module.getName().equals(module.getName()));
186         }
187     }
188
189     /**
190      * @param root
191      * @param targets
192      * @param state
193      * @param visiting
194      * @param ret
195      * @exception BuildException
196      * @todo i18n
197      */

198     private final void tsort(String JavaDoc root, Hashtable targets, Hashtable state, Stack visiting, Vector ret) throws BuildException
199     {
200         state.put(root, VISITING);
201         visiting.push(root);
202
203         Module module = (Module) targets.get(root);
204
205         // Make sure we exist
206
if (module == null) {
207             StringBuffer JavaDoc sb = new StringBuffer JavaDoc("Module `");
208
209             sb.append(root);
210             sb.append("' does not exist. ");
211
212             visiting.pop();
213             if (!visiting.empty()) {
214                 String JavaDoc parent = (String JavaDoc) visiting.peek();
215
216                 sb.append("It is used from module `");
217                 sb.append(parent);
218                 sb.append("'.");
219             }
220
221             throw new BuildException(new String JavaDoc(sb));
222         }
223
224         for (Enumeration en = module.getDependencies(); en.hasMoreElements(); ) {
225             String JavaDoc cur = (String JavaDoc) en.nextElement();
226             String JavaDoc m = (String JavaDoc) state.get(cur);
227
228             if (m == null) {
229                 // Not been visited
230
tsort(cur, targets, state, visiting, ret);
231             }
232             else if (m.equals(VISITING)) {
233                 // Currently visiting this node, so have a cycle
234
throw makeCircularException(cur, visiting);
235             }
236         }
237
238         String JavaDoc p = (String JavaDoc) visiting.pop();
239
240         if (!root.equals(p)) {
241             throw new RuntimeException JavaDoc("Unexpected internal error: expected to " + "pop " + root + " but got " + p);
242         }
243
244         state.put(root, VISITED);
245         ret.addElement(module);
246     }
247
248     private void executeModule(Module module)
249     {
250         Execute exe = new Execute(new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN), null);
251
252         exe.setAntRun(project);
253         exe.setWorkingDirectory(module.getBaseDir());
254
255         CommandlineJava cmdl = new CommandlineJava();
256
257         Environment.Variable ant_home = new Environment.Variable();
258
259         //set ant_home
260
String JavaDoc env_ant_home = project.getProperty("env.ANT_HOME");
261
262         if (env_ant_home != null) {
263             ant_home.setKey("ant.home");
264             ant_home.setValue(env_ant_home);
265             cmdl.addSysproperty(ant_home);
266         }
267
268         Path classpath = cmdl.createClasspath(project);
269
270         classpath.setPath(System.getProperty("java.class.path"));
271
272         //set the class name
273
cmdl.setClassname("org.apache.tools.ant.Main");
274
275         // add the Ant target name, if specified
276
if (target != null) {
277             cmdl.createArgument().setValue(target);
278         }
279
280         // pass on all the properties
281
Hashtable props = getProject().getProperties();
282         Enumeration prop_keys = props.keys();
283
284         while (prop_keys.hasMoreElements()) {
285             String JavaDoc arg = prop_keys.nextElement().toString();
286
287             if (argumentShouldntBePassedOn(arg))
288                 continue;
289
290             String JavaDoc value = props.get(arg).toString();
291
292             //don't try to set a property if it will mess up a windows command line due to spaces.
293
//Patch by Adrian Brock.
294
if (value == null || value.indexOf(" ") == -1) {
295                 cmdl.createArgument().setValue("-D" + arg + "=" + value);
296             }
297             // end of if ()
298

299         }
300
301         exe.setCommandline(cmdl.getCommandline());
302
303         try {
304             int exit = exe.execute();
305
306             if (exe.killedProcess()) {
307                 log("Timeout: killed the sub-process", Project.MSG_WARN);
308             }
309             if (exit != 0) {
310                 throw new BuildException("" + exit, location);
311             }
312         }
313         catch (IOException JavaDoc e) {
314             e.printStackTrace();
315             throw new BuildException(e, location);
316         }
317     }
318
319     private boolean argumentShouldntBePassedOn(String JavaDoc arg)
320     {
321         return "basedir".equals(arg) || "ant.file".equals(arg) || arg.startsWith("java.") || arg.startsWith("sun.");
322     }
323
324     private Module createModule(File JavaDoc file)
325     {
326         //load dependency info
327
File JavaDoc module_xml = new File JavaDoc(file, "module.xml");
328         Module module = null;
329
330         if (module_xml.exists()) {
331             try {
332                 FileInputStream JavaDoc module_xml_in = new FileInputStream JavaDoc(module_xml);
333
334                 module = parser.parse(module_xml_in);
335             }
336             catch (FileNotFoundException JavaDoc e) {
337                 e.printStackTrace();
338             }
339         }
340         else {
341             module = new Module();
342         }
343
344         module.setName(file.getName());
345         module.setBaseDir(file);
346
347         return module;
348     }
349
350 }
351
Popular Tags