1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46 package groovy.util;
47
48
49 import java.lang.reflect.Constructor;
50 import java.lang.reflect.InvocationTargetException;
51 import java.lang.reflect.Method;
52 import java.util.Collections;
53 import java.util.Iterator;
54 import java.util.Map;
55 import java.util.logging.Level;
56 import java.util.logging.Logger;
57
58 import org.apache.tools.ant.BuildException;
59 import org.apache.tools.ant.BuildLogger;
60 import org.apache.tools.ant.IntrospectionHelper;
61 import org.apache.tools.ant.NoBannerLogger;
62 import org.apache.tools.ant.Project;
63 import org.apache.tools.ant.Task;
64 import org.apache.tools.ant.TaskAdapter;
65 import org.apache.tools.ant.TaskContainer;
66 import org.apache.tools.ant.types.DataType;
67 import org.codehaus.groovy.ant.FileScanner;
68 import org.codehaus.groovy.runtime.InvokerHelper;
69
70 /***
71 * Allows Ant tasks to be used with GroovyMarkup
72 *
73 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
74 * @version $Revision: 1.8 $
75 */
76 public class AntBuilder extends BuilderSupport {
77
78 private static final Class[] addTaskParamTypes = { String.class };
79
80 private Logger log = Logger.getLogger(getClass().getName());
81 private Project project;
82
83 public AntBuilder() {
84 this.project = createProject();
85 }
86
87 public AntBuilder(Project project) {
88 this.project = project;
89 }
90
91 /***
92 * @return Factory method to create new Project instances
93 */
94 protected Project createProject() {
95 Project project = new Project();
96 BuildLogger logger = new NoBannerLogger();
97
98 logger.setMessageOutputLevel(org.apache.tools.ant.Project.MSG_INFO);
99 logger.setOutputPrintStream(System.out);
100 logger.setErrorPrintStream(System.err);
101
102 project.addBuildListener(logger);
103
104 project.init();
105 project.getBaseDir();
106 return project;
107 }
108
109 protected void setParent(Object parent, Object child) {
110 }
111
112 protected void nodeCompleted(Object parent, Object node) {
113 if (node instanceof Task) {
114 Task task = (Task) node;
115 task.perform();
116 }
117 }
118
119 protected Object createNode(Object tagName) {
120 return createNode(tagName.toString(), Collections.EMPTY_MAP);
121 }
122
123 protected Object createNode(Object name, Object value) {
124 Object task = createNode(name);
125 setText(task, value.toString());
126 return task;
127 }
128
129 protected Object createNode(Object name, Map attributes, Object value) {
130 Object task = createNode(name, attributes);
131 setText(task, value.toString());
132 return task;
133 }
134
135 protected Object createNode(Object name, Map attributes) {
136
137 if (name.equals("fileScanner")) {
138 return new FileScanner(project);
139 }
140
141 String tagName = name.toString();
142 Object answer = null;
143
144 Object parentObject = getCurrent();
145 Object parentTask = getParentTask();
146
147
148
149
150
151
152
153
154 Object nested = null;
155 if (parentObject != null && !(parentTask instanceof TaskContainer)) {
156 nested = createNestedObject(parentObject, tagName);
157 }
158
159 Task task = null;
160 if (nested == null) {
161 task = createTask(tagName);
162 if (task != null) {
163 if (log.isLoggable(Level.FINE)) {
164 log.fine("Creating an ant Task for name: " + tagName);
165 }
166
167
168
169
170
171
172 if (task instanceof TaskAdapter) {
173 answer = ((TaskAdapter) task).getProxy();
174 }
175 else {
176 answer = task;
177 }
178
179
180 Object id = attributes.remove("id");
181 if (id != null) {
182 project.addReference((String) id, task);
183 }
184
185
186 task.init();
187
188
189 setBeanProperties(task, attributes);
190 }
191 }
192
193 if (task == null) {
194 if (nested == null) {
195 if (log.isLoggable(Level.FINE)) {
196 log.fine("Trying to create a data type for tag: " + tagName);
197 }
198 nested = createDataType(tagName);
199 }
200 else {
201 if (log.isLoggable(Level.FINE)) {
202 log.fine("Created nested property tag: " + tagName);
203 }
204 }
205
206 if (nested != null) {
207 answer = nested;
208
209
210 Object id = attributes.remove("id");
211 if (id != null) {
212 project.addReference((String) id, nested);
213 }
214
215 try {
216 InvokerHelper.setProperty(nested, "name", tagName);
217 }
218 catch (Exception e) {
219 }
220
221
222 setBeanProperties(nested, attributes);
223
224
225 if (parentObject != null) {
226 IntrospectionHelper ih = IntrospectionHelper.getHelper(parentObject.getClass());
227 try {
228 if (log.isLoggable(Level.FINE)) {
229 log.fine(
230 "About to set the: "
231 + tagName
232 + " property on: "
233 + parentObject
234 + " to value: "
235 + nested
236 + " with type: "
237 + nested.getClass());
238 }
239
240 ih.storeElement(project, parentObject, nested, tagName);
241 }
242 catch (Exception e) {
243 log.log(Level.WARNING, "Caught exception setting nested: " + tagName, e);
244 }
245
246
247
248
249 try {
250 InvokerHelper.setProperty(parentObject, tagName, nested);
251 }
252 catch (Exception e) {
253 log.fine("Caught exception trying to set property: " + tagName + " on: " + parentObject);
254 }
255 }
256 }
257 else {
258 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?");
259 }
260 }
261
262 return answer;
263 }
264
265 protected void setText(Object task, String text) {
266
267 Method method = getAccessibleMethod(task.getClass(), "addText", addTaskParamTypes);
268 if (method != null) {
269 Object[] args = { text };
270 try {
271 method.invoke(task, args);
272 }
273 catch (Exception e) {
274 log.log(Level.WARNING, "Cannot call addText on: " + task + ". Reason: " + e, e);
275 }
276 }
277 }
278
279 protected Method getAccessibleMethod(Class theClass, String name, Class[] paramTypes) {
280 while (true) {
281 try {
282 Method answer = theClass.getDeclaredMethod(name, paramTypes);
283 if (answer != null) {
284 return answer;
285 }
286 }
287 catch (Exception e) {
288
289 }
290 theClass = theClass.getSuperclass();
291 if (theClass == null) {
292 return null;
293 }
294 }
295 }
296
297 public Project getAntProject() {
298 return project;
299 }
300
301
302
303 protected void setBeanProperties(Object object, Map map) {
304 for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
305 Map.Entry entry = (Map.Entry) iter.next();
306 String name = (String) entry.getKey();
307 Object value = entry.getValue();
308 setBeanProperty(object, name, ((value == null) ? null : value.toString()));
309 }
310 }
311
312 protected void setBeanProperty(Object object, String name, Object value) {
313 if (log.isLoggable(Level.FINE)) {
314 log.fine("Setting bean property on: " + object + " name: " + name + " value: " + value);
315 }
316
317 IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass());
318
319 if (value instanceof String) {
320 try {
321 ih.setAttribute(getAntProject(), object, name.toLowerCase(), (String) value);
322 return;
323 }
324 catch (Exception e) {
325
326 }
327 }
328
329 try {
330
331 ih.storeElement(getAntProject(), object, value, name);
332 }
333 catch (Exception e) {
334
335 InvokerHelper.setProperty(object, name, value);
336 }
337 }
338
339 /***
340 * Creates a nested object of the given object with the specified name
341 */
342 protected Object createNestedObject(Object object, String name) {
343 Object dataType = null;
344 if (object != null) {
345 IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass());
346
347 if (ih != null) {
348 try {
349 dataType = ih.createElement(getAntProject(), object, name.toLowerCase());
350 }
351 catch (BuildException be) {
352 log.log(Level.SEVERE, "Caught: " + be, be);
353 }
354 }
355 }
356 if (dataType == null) {
357 dataType = createDataType(name);
358 }
359 return dataType;
360 }
361
362 protected Object createDataType(String name) {
363 Object dataType = null;
364
365 Class type = (Class) getAntProject().getDataTypeDefinitions().get(name);
366
367 if (type != null) {
368
369 Constructor ctor = null;
370 boolean noArg = false;
371
372
373
374 try {
375 ctor = type.getConstructor(new Class[0]);
376 noArg = true;
377 }
378 catch (NoSuchMethodException nse) {
379 try {
380 ctor = type.getConstructor(new Class[] { Project.class });
381 noArg = false;
382 }
383 catch (NoSuchMethodException nsme) {
384 log.log(Level.INFO, "datatype '" + name + "' didn't have a constructor with an Ant Project", nsme);
385 }
386 }
387
388 if (noArg) {
389 dataType = createDataType(ctor, new Object[0], name, "no-arg constructor");
390 }
391 else {
392 dataType = createDataType(ctor, new Object[] { getAntProject()}, name, "an Ant project");
393 }
394 if (dataType != null) {
395 ((DataType) dataType).setProject(getAntProject());
396 }
397 }
398
399 return dataType;
400 }
401
402 /***
403 * @return an object create with the given constructor and args.
404 * @param ctor a constructor to use creating the object
405 * @param args the arguments to pass to the constructor
406 * @param name the name of the data type being created
407 * @param argDescription a human readable description of the args passed
408 */
409 protected Object createDataType(Constructor ctor, Object[] args, String name, String argDescription) {
410 try {
411 Object datatype = ctor.newInstance(args);
412 return datatype;
413 }
414 catch (InstantiationException ie) {
415 log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ie);
416 }
417 catch (IllegalAccessException iae) {
418 log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, iae);
419 }
420 catch (InvocationTargetException ite) {
421 log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ite);
422 }
423 return null;
424 }
425
426 /***
427 * @param taskName the name of the task to create
428 * @return a newly created task
429 */
430 protected Task createTask(String taskName) {
431 return createTask(taskName, (Class) getAntProject().getTaskDefinitions().get(taskName));
432 }
433
434 protected Task createTask(String taskName, Class taskType) {
435 if (taskType == null) {
436 return null;
437 }
438 try {
439 Object o = taskType.newInstance();
440 Task task = null;
441 if (o instanceof Task) {
442 task = (Task) o;
443 }
444 else {
445 TaskAdapter taskA = new TaskAdapter();
446 taskA.setProxy(o);
447 task = taskA;
448 }
449
450 task.setProject(getAntProject());
451 task.setTaskName(taskName);
452
453 return task;
454 }
455 catch (Exception e) {
456 log.log(Level.WARNING, "Could not create task: " + taskName + ". Reason: " + e, e);
457 return null;
458 }
459 }
460
461 protected Task getParentTask() {
462 Object current = getCurrent();
463 if (current instanceof Task) {
464 return (Task) current;
465 }
466 return null;
467 }
468 }