|
|||||||||||||||||||
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover | |||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
AntBuilder.java | 0% | 0% | 0% | 0% |
|
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;
|
|
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.*;
|
|
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[] addTaskParamTypes = { String.class }; |
|
72 |
|
|
73 |
private Logger log = Logger.getLogger(getClass().getName());
|
|
74 |
private Project project;
|
|
75 |
|
|
76 | 0 |
public AntBuilder() {
|
77 | 0 |
this.project = createProject();
|
78 |
} |
|
79 |
|
|
80 | 0 |
public AntBuilder(Project project) {
|
81 | 0 |
this.project = project;
|
82 |
} |
|
83 |
|
|
84 |
// dk: introduced for convenience in subclasses
|
|
85 | 0 |
protected Project getProject() {
|
86 | 0 |
return project;
|
87 |
} |
|
88 |
|
|
89 |
/**
|
|
90 |
* @return Factory method to create new Project instances
|
|
91 |
*/
|
|
92 | 0 |
protected Project createProject() {
|
93 | 0 |
Project project = new Project();
|
94 | 0 |
BuildLogger logger = new NoBannerLogger();
|
95 |
|
|
96 | 0 |
logger.setMessageOutputLevel(org.apache.tools.ant.Project.MSG_INFO); |
97 | 0 |
logger.setOutputPrintStream(System.out); |
98 | 0 |
logger.setErrorPrintStream(System.err); |
99 |
|
|
100 | 0 |
project.addBuildListener(logger); |
101 |
|
|
102 | 0 |
project.init(); |
103 | 0 |
project.getBaseDir(); |
104 | 0 |
return project;
|
105 |
} |
|
106 |
|
|
107 | 0 |
protected void setParent(Object parent, Object 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 | 0 |
protected void nodeCompleted(Object parent, Object node) { |
120 | 0 |
if (parent instanceof TaskContainer) { |
121 | 0 |
log.finest("parent is TaskContainer: no perform on nodeCompleted");
|
122 | 0 |
return; // parent will care about when children perform |
123 |
} |
|
124 | 0 |
if (node instanceof Task) { |
125 | 0 |
Task task = (Task) node; |
126 | 0 |
task.perform(); |
127 |
} |
|
128 |
} |
|
129 |
|
|
130 | 0 |
protected Object createNode(Object tagName) {
|
131 | 0 |
return createNode(tagName.toString(), Collections.EMPTY_MAP);
|
132 |
} |
|
133 |
|
|
134 | 0 |
protected Object createNode(Object name, Object value) {
|
135 | 0 |
Object task = createNode(name); |
136 | 0 |
setText(task, value.toString()); |
137 | 0 |
return task;
|
138 |
} |
|
139 |
|
|
140 | 0 |
protected Object createNode(Object name, Map attributes, Object value) {
|
141 | 0 |
Object task = createNode(name, attributes); |
142 | 0 |
setText(task, value.toString()); |
143 | 0 |
return task;
|
144 |
} |
|
145 |
|
|
146 | 0 |
protected Object createNode(Object name, Map attributes) {
|
147 |
|
|
148 | 0 |
if (name.equals("fileScanner")) { |
149 | 0 |
return new FileScanner(project); |
150 |
} |
|
151 |
|
|
152 | 0 |
String tagName = name.toString(); |
153 | 0 |
Object answer = null;
|
154 |
|
|
155 | 0 |
Object parentObject = getCurrent(); |
156 | 0 |
Object 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 | 0 |
Object nested = null;
|
166 | 0 |
if (parentObject != null && !(parentTask instanceof TaskContainer)) { |
167 | 0 |
nested = createNestedObject(parentObject, tagName); |
168 |
} |
|
169 |
|
|
170 | 0 |
Task task = null;
|
171 | 0 |
if (nested == null) { |
172 | 0 |
task = createTask(tagName); |
173 | 0 |
if (task != null) { |
174 | 0 |
if (log.isLoggable(Level.FINE)) {
|
175 | 0 |
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 | 0 |
if (task instanceof TaskAdapter) { |
184 | 0 |
answer = ((TaskAdapter) task).getProxy(); |
185 |
} |
|
186 |
else {
|
|
187 | 0 |
answer = task; |
188 |
} |
|
189 |
|
|
190 |
// set the task ID if one is given
|
|
191 | 0 |
Object id = attributes.remove("id");
|
192 | 0 |
if (id != null) { |
193 | 0 |
project.addReference((String) id, task); |
194 |
} |
|
195 |
|
|
196 |
// now lets initialize
|
|
197 | 0 |
task.init(); |
198 |
|
|
199 |
// now lets set any attributes of this tag...
|
|
200 | 0 |
setBeanProperties(task, attributes); |
201 |
|
|
202 |
// dk: TaskContainers have their own adding logic
|
|
203 | 0 |
if (parentObject instanceof TaskContainer){ |
204 | 0 |
((TaskContainer)parentObject).addTask(task); |
205 |
} |
|
206 |
} |
|
207 |
} |
|
208 |
|
|
209 | 0 |
if (task == null) { |
210 | 0 |
if (nested == null) { |
211 | 0 |
if (log.isLoggable(Level.FINE)) {
|
212 | 0 |
log.fine("Trying to create a data type for tag: " + tagName);
|
213 |
} |
|
214 | 0 |
nested = createDataType(tagName); |
215 |
} |
|
216 |
else {
|
|
217 | 0 |
if (log.isLoggable(Level.FINE)) {
|
218 | 0 |
log.fine("Created nested property tag: " + tagName);
|
219 |
} |
|
220 |
} |
|
221 |
|
|
222 | 0 |
if (nested != null) { |
223 | 0 |
answer = nested; |
224 |
|
|
225 |
// set the task ID if one is given
|
|
226 | 0 |
Object id = attributes.remove("id");
|
227 | 0 |
if (id != null) { |
228 | 0 |
project.addReference((String) id, nested); |
229 |
} |
|
230 |
|
|
231 | 0 |
try {
|
232 | 0 |
InvokerHelper.setProperty(nested, "name", tagName);
|
233 |
} |
|
234 |
catch (Exception e) {
|
|
235 |
} |
|
236 |
|
|
237 |
// now lets set any attributes of this tag...
|
|
238 | 0 |
setBeanProperties(nested, attributes); |
239 |
|
|
240 |
// now lets add it to its parent
|
|
241 | 0 |
if (parentObject != null) { |
242 | 0 |
IntrospectionHelper ih = IntrospectionHelper.getHelper(parentObject.getClass()); |
243 | 0 |
try {
|
244 | 0 |
if (log.isLoggable(Level.FINE)) {
|
245 | 0 |
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 | 0 |
ih.storeElement(project, parentObject, nested, tagName); |
257 |
} |
|
258 |
catch (Exception e) {
|
|
259 | 0 |
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 | 0 |
try {
|
266 | 0 |
InvokerHelper.setProperty(parentObject, tagName, nested); |
267 |
} |
|
268 |
catch (Exception e) {
|
|
269 | 0 |
log.fine("Caught exception trying to set property: " + tagName + " on: " + parentObject); |
270 |
} |
|
271 |
} |
|
272 |
} |
|
273 |
else {
|
|
274 | 0 |
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 | 0 |
return answer;
|
279 |
} |
|
280 |
|
|
281 | 0 |
protected void setText(Object task, String text) { |
282 |
// now lets set the addText() of the body content, if its applicaable
|
|
283 | 0 |
Method method = getAccessibleMethod(task.getClass(), "addText", addTaskParamTypes);
|
284 | 0 |
if (method != null) { |
285 | 0 |
Object[] args = { text }; |
286 | 0 |
try {
|
287 | 0 |
method.invoke(task, args); |
288 |
} |
|
289 |
catch (Exception e) {
|
|
290 | 0 |
log.log(Level.WARNING, "Cannot call addText on: " + task + ". Reason: " + e, e); |
291 |
} |
|
292 |
} |
|
293 |
} |
|
294 |
|
|
295 | 0 |
protected Method getAccessibleMethod(Class theClass, String name, Class[] paramTypes) {
|
296 | 0 |
while (true) { |
297 | 0 |
try {
|
298 | 0 |
Method answer = theClass.getDeclaredMethod(name, paramTypes); |
299 | 0 |
if (answer != null) { |
300 | 0 |
return answer;
|
301 |
} |
|
302 |
} |
|
303 |
catch (Exception e) {
|
|
304 |
// ignore
|
|
305 |
} |
|
306 | 0 |
theClass = theClass.getSuperclass(); |
307 | 0 |
if (theClass == null) { |
308 | 0 |
return null; |
309 |
} |
|
310 |
} |
|
311 |
} |
|
312 |
|
|
313 | 0 |
public Project getAntProject() {
|
314 | 0 |
return project;
|
315 |
} |
|
316 |
|
|
317 |
// Implementation methods
|
|
318 |
//-------------------------------------------------------------------------
|
|
319 | 0 |
protected void setBeanProperties(Object object, Map map) { |
320 | 0 |
for (Iterator iter = map.entrySet().iterator(); iter.hasNext();) {
|
321 | 0 |
Map.Entry entry = (Map.Entry) iter.next(); |
322 | 0 |
String name = (String) entry.getKey(); |
323 | 0 |
Object value = entry.getValue(); |
324 | 0 |
setBeanProperty(object, name, ((value == null) ? null : value.toString())); |
325 |
} |
|
326 |
} |
|
327 |
|
|
328 | 0 |
protected void setBeanProperty(Object object, String name, Object value) { |
329 | 0 |
if (log.isLoggable(Level.FINE)) {
|
330 | 0 |
log.fine("Setting bean property on: " + object + " name: " + name + " value: " + value); |
331 |
} |
|
332 |
|
|
333 | 0 |
IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass()); |
334 |
|
|
335 | 0 |
if (value instanceof String) { |
336 | 0 |
try {
|
337 | 0 |
ih.setAttribute(getAntProject(), object, name.toLowerCase(), (String) value); |
338 | 0 |
return;
|
339 |
} |
|
340 |
catch (Exception e) {
|
|
341 |
// ignore: not a valid property
|
|
342 |
} |
|
343 |
} |
|
344 |
|
|
345 | 0 |
try {
|
346 |
|
|
347 | 0 |
ih.storeElement(getAntProject(), object, value, name); |
348 |
} |
|
349 |
catch (Exception e) {
|
|
350 |
|
|
351 | 0 |
InvokerHelper.setProperty(object, name, value); |
352 |
} |
|
353 |
} |
|
354 |
|
|
355 |
/**
|
|
356 |
* Creates a nested object of the given object with the specified name
|
|
357 |
*/
|
|
358 | 0 |
protected Object createNestedObject(Object object, String name) {
|
359 | 0 |
Object dataType = null;
|
360 | 0 |
if (object != null) { |
361 | 0 |
IntrospectionHelper ih = IntrospectionHelper.getHelper(object.getClass()); |
362 |
|
|
363 | 0 |
if (ih != null) { |
364 | 0 |
try {
|
365 |
// dk: the line below resolves the deprecation warning but may not work
|
|
366 |
// properly with namespaces.
|
|
367 | 0 |
String namespaceUri = ""; // todo: how to set this? |
368 | 0 |
UnknownElement unknownElement = null; // todo: what is expected here? |
369 | 0 |
dataType = ih.getElementCreator(getAntProject(), namespaceUri, object, name.toLowerCase(), unknownElement).create(); |
370 |
} |
|
371 |
catch (BuildException be) {
|
|
372 | 0 |
log.log(Level.SEVERE, "Caught: " + be, be);
|
373 |
} |
|
374 |
} |
|
375 |
} |
|
376 | 0 |
if (dataType == null) { |
377 | 0 |
dataType = createDataType(name); |
378 |
} |
|
379 | 0 |
return dataType;
|
380 |
} |
|
381 |
|
|
382 | 0 |
protected Object createDataType(String name) {
|
383 | 0 |
Object dataType = null;
|
384 |
|
|
385 | 0 |
Class type = (Class) getAntProject().getDataTypeDefinitions().get(name); |
386 |
|
|
387 | 0 |
if (type != null) { |
388 |
|
|
389 | 0 |
Constructor ctor = null;
|
390 | 0 |
boolean noArg = false; |
391 |
|
|
392 |
// DataType can have a "no arg" constructor or take a single
|
|
393 |
// Project argument.
|
|
394 | 0 |
try {
|
395 | 0 |
ctor = type.getConstructor(new Class[0]);
|
396 | 0 |
noArg = true;
|
397 |
} |
|
398 |
catch (NoSuchMethodException nse) {
|
|
399 | 0 |
try {
|
400 | 0 |
ctor = type.getConstructor(new Class[] { Project.class }); |
401 | 0 |
noArg = false;
|
402 |
} |
|
403 |
catch (NoSuchMethodException nsme) {
|
|
404 | 0 |
log.log(Level.INFO, "datatype '" + name + "' didn't have a constructor with an Ant Project", nsme); |
405 |
} |
|
406 |
} |
|
407 |
|
|
408 | 0 |
if (noArg) {
|
409 | 0 |
dataType = createDataType(ctor, new Object[0], name, "no-arg constructor"); |
410 |
} |
|
411 |
else {
|
|
412 | 0 |
dataType = createDataType(ctor, new Object[] { getAntProject()}, name, "an Ant project"); |
413 |
} |
|
414 | 0 |
if (dataType != null) { |
415 | 0 |
((DataType) dataType).setProject(getAntProject()); |
416 |
} |
|
417 |
} |
|
418 |
|
|
419 | 0 |
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 | 0 |
protected Object createDataType(Constructor ctor, Object[] args, String name, String argDescription) {
|
430 | 0 |
try {
|
431 | 0 |
Object datatype = ctor.newInstance(args); |
432 | 0 |
return datatype;
|
433 |
} |
|
434 |
catch (InstantiationException ie) {
|
|
435 | 0 |
log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ie); |
436 |
} |
|
437 |
catch (IllegalAccessException iae) {
|
|
438 | 0 |
log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, iae); |
439 |
} |
|
440 |
catch (InvocationTargetException ite) {
|
|
441 | 0 |
log.log(Level.SEVERE, "datatype '" + name + "' couldn't be created with " + argDescription, ite); |
442 |
} |
|
443 | 0 |
return null; |
444 |
} |
|
445 |
|
|
446 |
/**
|
|
447 |
* @param taskName the name of the task to create
|
|
448 |
* @return a newly created task
|
|
449 |
*/
|
|
450 | 0 |
protected Task createTask(String taskName) {
|
451 | 0 |
return createTask(taskName, (Class) getAntProject().getTaskDefinitions().get(taskName));
|
452 |
} |
|
453 |
|
|
454 | 0 |
protected Task createTask(String taskName, Class taskType) {
|
455 | 0 |
if (taskType == null) { |
456 | 0 |
return null; |
457 |
} |
|
458 | 0 |
try {
|
459 | 0 |
Object o = taskType.newInstance(); |
460 | 0 |
Task task = null;
|
461 | 0 |
if (o instanceof Task) { |
462 | 0 |
task = (Task) o; |
463 |
} |
|
464 |
else {
|
|
465 | 0 |
TaskAdapter taskA = new TaskAdapter();
|
466 | 0 |
taskA.setProxy(o); |
467 | 0 |
task = taskA; |
468 |
} |
|
469 |
|
|
470 | 0 |
task.setProject(getAntProject()); |
471 | 0 |
task.setTaskName(taskName); |
472 |
|
|
473 | 0 |
return task;
|
474 |
} |
|
475 |
catch (Exception e) {
|
|
476 | 0 |
log.log(Level.WARNING, "Could not create task: " + taskName + ". Reason: " + e, e); |
477 | 0 |
return null; |
478 |
} |
|
479 |
} |
|
480 |
|
|
481 | 0 |
protected Task getParentTask() {
|
482 | 0 |
Object current = getCurrent(); |
483 | 0 |
if (current instanceof Task) { |
484 | 0 |
return (Task) current;
|
485 |
} |
|
486 | 0 |
return null; |
487 |
} |
|
488 |
} |
|
489 |
|
|