KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > groovy > util > AntBuilder


1 /*
2  $Id: AntBuilder.java,v 1.9 2004/12/13 23:48:21 glaforge Exp $
3
4  Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5
6  Redistribution and use of this software and associated documentation
7  ("Software"), with or without modification, are permitted provided
8  that the following conditions are met:
9
10  1. Redistributions of source code must retain copyright
11     statements and notices. Redistributions must also contain a
12     copy of this document.
13
14  2. Redistributions in binary form must reproduce the
15     above copyright notice, this list of conditions and the
16     following disclaimer in the documentation and/or other
17     materials provided with the distribution.
18
19  3. The name "groovy" must not be used to endorse or promote
20     products derived from this Software without prior written
21     permission of The Codehaus. For written permission,
22     please contact info@codehaus.org.
23
24  4. Products derived from this Software may not be called "groovy"
25     nor may "groovy" appear in their names without prior written
26     permission of The Codehaus. "groovy" is a registered
27     trademark of The Codehaus.
28
29  5. Due credit should be given to The Codehaus -
30     http://groovy.codehaus.org/
31
32  THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33  ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34  NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
36  THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43  OF THE POSSIBILITY OF SUCH DAMAGE.
44
45  */

46 package groovy.util;
47
48
49 import java.lang.reflect.Constructor JavaDoc;
50 import java.lang.reflect.InvocationTargetException JavaDoc;
51 import java.lang.reflect.Method JavaDoc;
52 import java.util.Collections JavaDoc;
53 import java.util.Iterator JavaDoc;
54 import java.util.Map JavaDoc;
55 import java.util.logging.Level JavaDoc;
56 import java.util.logging.Logger JavaDoc;
57
58 import org.apache.tools.ant.*;
59 import org.apache.tools.ant.types.DataType;
60 import org.codehaus.groovy.ant.FileScanner;
61 import org.codehaus.groovy.runtime.InvokerHelper;
62
63 /**
64  * Allows Ant tasks to be used with GroovyMarkup
65  *
66  * @author <a HREF="mailto:james@coredevelopers.net">James Strachan</a>, changes by Dierk Koenig (dk)
67  * @version $Revision: 1.9 $
68  */

69 public class AntBuilder extends BuilderSupport {
70
71     private static final Class JavaDoc[] addTaskParamTypes = { String JavaDoc.class };
72
73     private Logger JavaDoc log = Logger.getLogger(getClass().getName());
74     private Project project;
75
76     public AntBuilder() {
77         this.project = createProject();
78     }
79
80     public AntBuilder(Project project) {
81         this.project = project;
82     }
83
84     // dk: introduced for convenience in subclasses
85
protected Project getProject() {
86         return project;
87     }
88
89     /**
90      * @return Factory method to create new Project instances
91      */

92     protected Project createProject() {
93         Project project = new Project();
94         BuildLogger logger = new NoBannerLogger();
95
96         logger.setMessageOutputLevel(org.apache.tools.ant.Project.MSG_INFO);
97         logger.setOutputPrintStream(System.out);
98         logger.setErrorPrintStream(System.err);
99
100         project.addBuildListener(logger);
101
102         project.init();
103         project.getBaseDir();
104         return project;
105     }
106
107     protected void setParent(Object JavaDoc parent, Object JavaDoc child) {
108     }
109
110     /**
111      * Determines, when the ANT Task that is represented by the "node" should perform.
112      * Node must be an ANT Task or no "perform" is called.
113      * If node is an ANT Task, it performs right after complete contstruction.
114      * If node is nested in a TaskContainer, calling "perform" is delegated to that
115      * TaskContainer.
116      * @param parent note: null when node is root
117      * @param node the node that now has all its children applied
118      */

119     protected void nodeCompleted(Object JavaDoc parent, Object JavaDoc node) {
120         if (parent instanceof TaskContainer) {
121             log.finest("parent is TaskContainer: no perform on nodeCompleted");
122             return; // parent will care about when children perform
123
}
124         if (node instanceof Task) {
125             Task task = (Task) node;
126             task.perform();
127         }
128     }
129
130     protected Object JavaDoc createNode(Object JavaDoc tagName) {
131         return createNode(tagName.toString(), Collections.EMPTY_MAP);
132     }
133
134     protected Object JavaDoc createNode(Object JavaDoc name, Object JavaDoc value) {
135         Object JavaDoc task = createNode(name);
136         setText(task, value.toString());
137         return task;
138     }
139
140     protected Object JavaDoc createNode(Object JavaDoc name, Map JavaDoc attributes, Object JavaDoc value) {
141         Object JavaDoc task = createNode(name, attributes);
142         setText(task, value.toString());
143         return task;
144     }
145     
146     protected Object JavaDoc createNode(Object JavaDoc name, Map JavaDoc attributes) {
147
148         if (name.equals("fileScanner")) {
149             return new FileScanner(project);
150         }
151         
152         String JavaDoc tagName = name.toString();
153         Object JavaDoc answer = null;
154
155         Object JavaDoc parentObject = getCurrent();
156         Object JavaDoc parentTask = getParentTask();
157
158         // lets assume that Task instances are not nested inside other Task instances
159
// for example <manifest> inside a <jar> should be a nested object, where as
160
// if the parent is not a Task the <manifest> should create a ManifestTask
161
//
162
// also its possible to have a root Ant tag which isn't a task, such as when
163
// defining <fileset id="...">...</fileset>
164

165         Object JavaDoc nested = null;
166         if (parentObject != null && !(parentTask instanceof TaskContainer)) {
167             nested = createNestedObject(parentObject, tagName);
168         }
169
170         Task task = null;
171         if (nested == null) {
172             task = createTask(tagName);
173             if (task != null) {
174                 if (log.isLoggable(Level.FINE)) {
175                     log.fine("Creating an ant Task for name: " + tagName);
176                 }
177
178                 // the following algorithm follows the lifetime of a tag
179
// http://jakarta.apache.org/ant/manual/develop.html#writingowntask
180
// kindly recommended by Stefan Bodewig
181

182                 // create and set its project reference
183
if (task instanceof TaskAdapter) {
184                     answer = ((TaskAdapter) task).getProxy();
185                 }
186                 else {
187                     answer = task;
188                 }
189
190                 // set the task ID if one is given
191
Object JavaDoc id = attributes.remove("id");
192                 if (id != null) {
193                     project.addReference((String JavaDoc) id, task);
194                 }
195
196                 // now lets initialize
197
task.init();
198
199                 // now lets set any attributes of this tag...
200
setBeanProperties(task, attributes);
201
202                 // dk: TaskContainers have their own adding logic
203
if (parentObject instanceof TaskContainer){
204                     ((TaskContainer)parentObject).addTask(task);
205                 }
206             }
207         }
208
209         if (task == null) {
210             if (nested == null) {
211                 if (log.isLoggable(Level.FINE)) {
212                     log.fine("Trying to create a data type for tag: " + tagName);
213                 }
214                 nested = createDataType(tagName);
215             }
216             else {
217                 if (log.isLoggable(Level.FINE)) {
218                     log.fine("Created nested property tag: " + tagName);
219                 }
220             }
221
222             if (nested != null) {
223                 answer = nested;
224
225                 // set the task ID if one is given
226
Object JavaDoc id = attributes.remove("id");
227                 if (id != null) {
228                     project.addReference((String JavaDoc) id, nested);
229                 }
230
231                 try {
232                     InvokerHelper.setProperty(nested, "name", tagName);
233                 }
234                 catch (Exception JavaDoc e) {
235                 }
236
237                 // now lets set any attributes of this tag...
238
setBeanProperties(nested, attributes);
239
240                 // now lets add it to its parent
241
if (parentObject != null) {
242                     IntrospectionHelper ih = IntrospectionHelper.getHelper(parentObject.getClass());
243                     try {
244                         if (log.isLoggable(Level.FINE)) {
245                             log.fine(
246                                 "About to set the: "
247                                     + tagName
248                                     + " property on: "
249                                     + parentObject
250                                     + " to value: "
251                                     + nested
252                                     + " with type: "
253                                     + nested.getClass());
254                         }
255
256                         ih.storeElement(project, parentObject, nested, tagName);
257                     }
258                     catch (Exception JavaDoc e) {
259                         log.log(Level.WARNING, "Caught exception setting nested: " + tagName, e);
260                     }
261
262                     // now try to set the property for good measure
263
// as the storeElement() method does not
264
// seem to call any setter methods of non-String types
265
try {
266                         InvokerHelper.setProperty(parentObject, tagName, nested);
267                     }
268                     catch (Exception JavaDoc e) {
269                         log.fine("Caught exception trying to set property: " + tagName + " on: " + parentObject);
270                     }
271                 }
272             }
273             else {
274                 log.log(Level.WARNING, "Could not convert tag: " + tagName + " into an Ant task, data type or property. Maybe the task is not on the classpath?");
275             }
276         }
277
278         return answer;
279     }
280
281     protected void setText(Object JavaDoc task, String JavaDoc text) {
282         // now lets set the addText() of the body content, if its applicaable
283
Method JavaDoc method = getAccessibleMethod(task.getClass(), "addText", addTaskParamTypes);
284         if (method != null) {
285             Object JavaDoc[] args = { text };
286             try {
287                 method.invoke(task, args);
288             }
289             catch (Exception JavaDoc e) {
290                 log.log(Level.WARNING, "Cannot call addText on: " + task + ". Reason: " + e, e);
291             }
292         }
293     }
294
295     protected Method JavaDoc getAccessibleMethod(Class JavaDoc theClass, String JavaDoc name, Class JavaDoc[] paramTypes) {
296         while (true) {
297             try {
298                 Method JavaDoc answer = theClass.getDeclaredMethod(name, paramTypes);
299                 if (answer != null) {
300                     return answer;
301                 }
302             }
303             catch (Exception JavaDoc e) {
304                 // ignore
305
}
306             theClass = theClass.getSuperclass();
307             if (theClass == null) {
308                 return null;
309             }
310         }
311     }
312
313     public Project getAntProject() {
314         return project;
315     }
316
317     // Implementation methods
318
//-------------------------------------------------------------------------
319
protected void setBeanProperties(Object JavaDoc object, Map JavaDoc map) {
320         for (Iterator JavaDoc iter = map.entrySet().iterator(); iter.hasNext();) {
321             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
322             String JavaDoc name = (String JavaDoc) entry.getKey();
323             Object JavaDoc value = entry.getValue();
324             setBeanProperty(object, name, ((value == null) ? null : value.toString()));
325         }
326     }
327
328     protected void setBeanProperty(Object JavaDoc object, String JavaDoc name, Object JavaDoc value) {
329         if (log.isLoggable(Level.FINE)) {
330             log.fine("Setting bean property on: " + object + " name: " + name + " value: " + value);
331         }
332
333         IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass());
334
335         if (value instanceof String JavaDoc) {
336             try {
337                 ih.setAttribute(getAntProject(), object, name.toLowerCase(), (String JavaDoc) value);
338                 return;
339             }
340             catch (Exception JavaDoc e) {
341                 // ignore: not a valid property
342
}
343         }
344
345         try {
346
347             ih.storeElement(getAntProject(), object, value, name);
348         }
349         catch (Exception JavaDoc e) {
350
351             InvokerHelper.setProperty(object, name, value);
352         }
353     }
354
355     /**
356      * Creates a nested object of the given object with the specified name
357      */

358     protected Object JavaDoc createNestedObject(Object JavaDoc object, String JavaDoc name) {
359         Object JavaDoc dataType = null;
360         if (object != null) {
361             IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass());
362
363             if (ih != null) {
364                 try {
365                     // dk: the line below resolves the deprecation warning but may not work
366
// properly with namespaces.
367
String JavaDoc namespaceUri = ""; // todo: how to set this?
368
UnknownElement unknownElement = null; // todo: what is expected here?
369
dataType = ih.getElementCreator(getAntProject(), namespaceUri, object, name.toLowerCase(), unknownElement).create();
370                 }
371                 catch (BuildException be) {
372                     log.log(Level.SEVERE, "Caught: " + be, be);
373                 }
374             }
375         }
376         if (dataType == null) {
377             dataType = createDataType(name);
378         }
379         return dataType;
380     }
381
382     protected Object JavaDoc createDataType(String JavaDoc name) {
383         Object JavaDoc dataType = null;
384
385         Class JavaDoc type = (Class JavaDoc) getAntProject().getDataTypeDefinitions().get(name);
386
387         if (type != null) {
388
389             Constructor JavaDoc ctor = null;
390             boolean noArg = false;
391
392             // DataType can have a "no arg" constructor or take a single
393
// Project argument.
394
try {
395                 ctor = type.getConstructor(new Class JavaDoc[0]);
396                 noArg = true;
397             }
398             catch (NoSuchMethodException JavaDoc nse) {
399                 try {
400                     ctor = type.getConstructor(new Class JavaDoc[] { Project.class });
401                     noArg = false;
402                 }
403                 catch (NoSuchMethodException JavaDoc nsme) {
404                     log.log(Level.INFO, "datatype '" + name + "' didn't have a constructor with an Ant Project", nsme);
405                 }
406             }
407
408             if (noArg) {
409                 dataType = createDataType(ctor, new Object JavaDoc[0], name, "no-arg constructor");
410             }
411             else {
412                 dataType = createDataType(ctor, new Object JavaDoc[] { getAntProject()}, name, "an Ant project");
413             }
414             if (dataType != null) {
415                 ((DataType) dataType).setProject(getAntProject());
416             }
417         }
418
419         return dataType;
420     }
421
422     /**
423      * @return an object create with the given constructor and args.
424      * @param ctor a constructor to use creating the object
425      * @param args the arguments to pass to the constructor
426      * @param name the name of the data type being created
427      * @param argDescription a human readable description of the args passed
428      */

429     protected Object JavaDoc createDataType(Constructor JavaDoc ctor, Object JavaDoc[] args, String JavaDoc name, String JavaDoc argDescription) {
430         try {
431             Object JavaDoc datatype = ctor.newInstance(args);
432             return datatype;
433         }
434         catch (InstantiationException JavaDoc ie) {
435             log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ie);
436         }
437         catch (IllegalAccessException JavaDoc iae) {
438             log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, iae);
439         }
440         catch (InvocationTargetException JavaDoc ite) {
441             log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ite);
442         }
443         return null;
444     }
445
446     /**
447      * @param taskName the name of the task to create
448      * @return a newly created task
449      */

450     protected Task createTask(String JavaDoc taskName) {
451         return createTask(taskName, (Class JavaDoc) getAntProject().getTaskDefinitions().get(taskName));
452     }
453
454     protected Task createTask(String JavaDoc taskName, Class JavaDoc taskType) {
455         if (taskType == null) {
456             return null;
457         }
458         try {
459             Object JavaDoc o = taskType.newInstance();
460             Task task = null;
461             if (o instanceof Task) {
462                 task = (Task) o;
463             }
464             else {
465                 TaskAdapter taskA = new TaskAdapter();
466                 taskA.setProxy(o);
467                 task = taskA;
468             }
469
470             task.setProject(getAntProject());
471             task.setTaskName(taskName);
472
473             return task;
474         }
475         catch (Exception JavaDoc e) {
476             log.log(Level.WARNING, "Could not create task: " + taskName + ". Reason: " + e, e);
477             return null;
478         }
479     }
480
481     protected Task getParentTask() {
482         Object JavaDoc current = getCurrent();
483         if (current instanceof Task) {
484             return (Task) current;
485         }
486         return null;
487     }
488 }
489
Popular Tags