source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/UnknownElement.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 22.2 KB
Line 
1/*
2 * Copyright 2000-2004 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17
18package org.apache.tools.ant;
19
20import java.util.ArrayList;
21import java.util.Iterator;
22import java.util.List;
23import java.io.IOException;
24import org.apache.tools.ant.taskdefs.PreSetDef;
25
26/**
27 * Wrapper class that holds all the information necessary to create a task
28 * or data type that did not exist when Ant started, or one which
29 * has had its definition updated to use a different implementation class.
30 *
31 */
32public class UnknownElement extends Task {
33
34 /**
35 * Holds the name of the task/type or nested child element of a
36 * task/type that hasn't been defined at parser time or has
37 * been redefined since original creation.
38 */
39 private String elementName;
40
41 /**
42 * Holds the namespace of the element.
43 */
44 private String namespace;
45
46 /**
47 * Holds the namespace qname of the element.
48 */
49 private String qname;
50
51 /**
52 * The real object after it has been loaded.
53 */
54 private Object realThing;
55
56 /**
57 * List of child elements (UnknownElements).
58 */
59 private List/*<UnknownElement>*/ children = null;
60
61 /** Specifies if a predefined definition has been done */
62 private boolean presetDefed = false;
63
64 /**
65 * Creates an UnknownElement for the given element name.
66 *
67 * @param elementName The name of the unknown element.
68 * Must not be <code>null</code>.
69 */
70 public UnknownElement (String elementName) {
71 this.elementName = elementName;
72 }
73
74 /**
75 * @return the list of nested UnknownElements for this UnknownElement.
76 */
77 public List getChildren() {
78 return children;
79 }
80
81 /**
82 * Returns the name of the XML element which generated this unknown
83 * element.
84 *
85 * @return the name of the XML element which generated this unknown
86 * element.
87 */
88 public String getTag() {
89 return elementName;
90 }
91
92 /** Return the namespace of the XML element associated with this component.
93 *
94 * @return Namespace URI used in the xmlns declaration.
95 */
96 public String getNamespace() {
97 return namespace;
98 }
99
100 /**
101 * Set the namespace of the XML element associated with this component.
102 * This method is typically called by the XML processor.
103 * If the namespace is "ant:current", the component helper
104 * is used to get the current antlib uri.
105 *
106 * @param namespace URI used in the xmlns declaration.
107 */
108 public void setNamespace(String namespace) {
109 if (namespace.equals(ProjectHelper.ANT_CURRENT_URI)) {
110 ComponentHelper helper = ComponentHelper.getComponentHelper(
111 getProject());
112 namespace = helper.getCurrentAntlibUri();
113 }
114 this.namespace = namespace;
115 }
116
117 /** Return the qname of the XML element associated with this component.
118 *
119 * @return namespace Qname used in the element declaration.
120 */
121 public String getQName() {
122 return qname;
123 }
124
125 /** Set the namespace qname of the XML element.
126 * This method is typically called by the XML processor.
127 *
128 * @param qname the qualified name of the element
129 */
130 public void setQName(String qname) {
131 this.qname = qname;
132 }
133
134
135 /**
136 * Get the RuntimeConfigurable instance for this UnknownElement, containing
137 * the configuration information.
138 *
139 * @return the configuration info.
140 */
141 public RuntimeConfigurable getWrapper() {
142 return super.getWrapper();
143 }
144
145 /**
146 * Creates the real object instance and child elements, then configures
147 * the attributes and text of the real object. This unknown element
148 * is then replaced with the real object in the containing target's list
149 * of children.
150 *
151 * @exception BuildException if the configuration fails
152 */
153 public void maybeConfigure() throws BuildException {
154 //ProjectComponentHelper helper=ProjectComponentHelper.getProjectComponentHelper();
155 //realThing = helper.createProjectComponent( this, getProject(), null,
156 // this.getTag());
157
158 configure(makeObject(this, getWrapper()));
159 }
160
161 /**
162 * Configure the given object from this UnknownElement
163 *
164 * @param realObject the real object this UnknownElement is representing.
165 *
166 */
167 public void configure(Object realObject) {
168 realThing = realObject;
169
170 getWrapper().setProxy(realThing);
171 Task task = null;
172 if (realThing instanceof Task) {
173 task = (Task) realThing;
174
175 task.setRuntimeConfigurableWrapper(getWrapper());
176
177 // For Script to work. Ugly
178 // The reference is replaced by RuntimeConfigurable
179 this.getOwningTarget().replaceChild(this, (Task) realThing);
180 }
181
182 handleChildren(realThing, getWrapper());
183
184 // configure attributes of the object and it's children. If it is
185 // a task container, defer the configuration till the task container
186 // attempts to use the task
187
188 if (task != null) {
189 task.maybeConfigure();
190 } else {
191 getWrapper().maybeConfigure(getProject());
192 }
193 }
194
195 /**
196 * Handles output sent to System.out by this task or its real task.
197 *
198 * @param output The output to log. Should not be <code>null</code>.
199 */
200 protected void handleOutput(String output) {
201 if (realThing instanceof Task) {
202 ((Task) realThing).handleOutput(output);
203 } else {
204 super.handleOutput(output);
205 }
206 }
207
208 /**
209 * @see Task#handleInput(byte[], int, int)
210 *
211 * @since Ant 1.6
212 */
213 protected int handleInput(byte[] buffer, int offset, int length)
214 throws IOException {
215 if (realThing instanceof Task) {
216 return ((Task) realThing).handleInput(buffer, offset, length);
217 } else {
218 return super.handleInput(buffer, offset, length);
219 }
220
221 }
222 /**
223 * Handles output sent to System.out by this task or its real task.
224 *
225 * @param output The output to log. Should not be <code>null</code>.
226 */
227 protected void handleFlush(String output) {
228 if (realThing instanceof Task) {
229 ((Task) realThing).handleFlush(output);
230 } else {
231 super.handleFlush(output);
232 }
233 }
234
235 /**
236 * Handles error output sent to System.err by this task or its real task.
237 *
238 * @param output The error output to log. Should not be <code>null</code>.
239 */
240 protected void handleErrorOutput(String output) {
241 if (realThing instanceof Task) {
242 ((Task) realThing).handleErrorOutput(output);
243 } else {
244 super.handleErrorOutput(output);
245 }
246 }
247
248
249 /**
250 * Handles error output sent to System.err by this task or its real task.
251 *
252 * @param output The error output to log. Should not be <code>null</code>.
253 */
254 protected void handleErrorFlush(String output) {
255 if (realThing instanceof Task) {
256 ((Task) realThing).handleErrorOutput(output);
257 } else {
258 super.handleErrorOutput(output);
259 }
260 }
261
262 /**
263 * Executes the real object if it's a task. If it's not a task
264 * (e.g. a data type) then this method does nothing.
265 */
266 public void execute() {
267 if (realThing == null) {
268 // plain impossible to get here, maybeConfigure should
269 // have thrown an exception.
270 throw new BuildException("Could not create task of type: "
271 + elementName, getLocation());
272 }
273
274 if (realThing instanceof Task) {
275 ((Task) realThing).execute();
276 }
277
278 // the task will not be reused ( a new init() will be called )
279 // Let GC do its job
280 realThing = null;
281 }
282
283 /**
284 * Adds a child element to this element.
285 *
286 * @param child The child element to add. Must not be <code>null</code>.
287 */
288 public void addChild(UnknownElement child) {
289 if (children == null) {
290 children = new ArrayList();
291 }
292 children.add(child);
293 }
294
295 /**
296 * Creates child elements, creates children of the children
297 * (recursively), and sets attributes of the child elements.
298 *
299 * @param parent The configured object for the parent.
300 * Must not be <code>null</code>.
301 *
302 * @param parentWrapper The wrapper containing child wrappers
303 * to be configured. Must not be <code>null</code>
304 * if there are any children.
305 *
306 * @exception BuildException if the children cannot be configured.
307 */
308 protected void handleChildren(
309 Object parent,
310 RuntimeConfigurable parentWrapper)
311 throws BuildException {
312 if (parent instanceof TypeAdapter) {
313 parent = ((TypeAdapter) parent).getProxy();
314 }
315
316 String parentUri = getNamespace();
317 Class parentClass = parent.getClass();
318 IntrospectionHelper ih = IntrospectionHelper.getHelper(parentClass);
319
320
321 if (children != null) {
322 Iterator it = children.iterator();
323 for (int i = 0; it.hasNext(); i++) {
324 RuntimeConfigurable childWrapper = parentWrapper.getChild(i);
325 UnknownElement child = (UnknownElement) it.next();
326 if (!handleChild(
327 parentUri, ih, parent, child, childWrapper)) {
328 if (!(parent instanceof TaskContainer)) {
329 ih.throwNotSupported(getProject(), parent,
330 child.getTag());
331 } else {
332 // a task container - anything could happen - just add the
333 // child to the container
334 TaskContainer container = (TaskContainer) parent;
335 container.addTask(child);
336 }
337 }
338 }
339 }
340 }
341
342 /**
343 * @return the component name - uses ProjectHelper#genComponentName()
344 */
345 protected String getComponentName() {
346 return ProjectHelper.genComponentName(getNamespace(), getTag());
347 }
348
349 /**
350 * This is used then the realobject of the UE is a PreSetDefinition.
351 * This is also used when a presetdef is used on a presetdef
352 * The attributes, elements and text are applied to this
353 * UE.
354 *
355 * @param u an UnknownElement containing the attributes, elements and text
356 */
357 public void applyPreSet(UnknownElement u) {
358 if (presetDefed) {
359 return;
360 }
361 // Do the runtime
362 getWrapper().applyPreSet(u.getWrapper());
363 if (u.children != null) {
364 List newChildren = new ArrayList();
365 newChildren.addAll(u.children);
366 if (children != null) {
367 newChildren.addAll(children);
368 }
369 children = newChildren;
370 }
371 presetDefed = true;
372 }
373
374 /**
375 * Creates a named task or data type. If the real object is a task,
376 * it is configured up to the init() stage.
377 *
378 * @param ue The unknown element to create the real object for.
379 * Must not be <code>null</code>.
380 * @param w Ignored in this implementation.
381 *
382 * @return the task or data type represented by the given unknown element.
383 */
384 protected Object makeObject(UnknownElement ue, RuntimeConfigurable w) {
385 ComponentHelper helper = ComponentHelper.getComponentHelper(
386 getProject());
387 String name = ue.getComponentName();
388 Object o = helper.createComponent(ue, ue.getNamespace(), name);
389
390 if (o == null) {
391 throw getNotFoundException("task or type", name);
392 }
393
394 if (o instanceof PreSetDef.PreSetDefinition) {
395 PreSetDef.PreSetDefinition def = (PreSetDef.PreSetDefinition) o;
396 o = def.createObject(ue.getProject());
397 if (o == null) {
398 throw getNotFoundException(
399 "preset " + name,
400 def.getPreSets().getComponentName());
401 }
402 ue.applyPreSet(def.getPreSets());
403 if (o instanceof Task) {
404 Task task = (Task) o;
405 task.setTaskType(ue.getTaskType());
406 task.setTaskName(ue.getTaskName());
407 }
408 }
409
410 if (o instanceof Task) {
411 Task task = (Task) o;
412 task.setOwningTarget(getOwningTarget());
413 task.init();
414 }
415 return o;
416 }
417
418 /**
419 * Creates a named task and configures it up to the init() stage.
420 *
421 * @param ue The UnknownElement to create the real task for.
422 * Must not be <code>null</code>.
423 * @param w Ignored.
424 *
425 * @return the task specified by the given unknown element, or
426 * <code>null</code> if the task name is not recognised.
427 */
428 protected Task makeTask(UnknownElement ue, RuntimeConfigurable w) {
429 Task task = getProject().createTask(ue.getTag());
430
431 if (task != null) {
432 task.setLocation(getLocation());
433 // UnknownElement always has an associated target
434 task.setOwningTarget(getOwningTarget());
435 task.init();
436 }
437 return task;
438 }
439
440 /**
441 * Returns a very verbose exception for when a task/data type cannot
442 * be found.
443 *
444 * @param what The kind of thing being created. For example, when
445 * a task name could not be found, this would be
446 * <code>"task"</code>. Should not be <code>null</code>.
447 * @param elementName The name of the element which could not be found.
448 * Should not be <code>null</code>.
449 *
450 * @return a detailed description of what might have caused the problem.
451 */
452 protected BuildException getNotFoundException(String what,
453 String elementName) {
454 String lSep = System.getProperty("line.separator");
455 String msg = "Could not create " + what + " of type: " + elementName
456 + "." + lSep + lSep
457 + "Ant could not find the task or a class this "
458 + "task relies upon." + lSep + lSep
459 + "This is common and has a number of causes; the usual " + lSep
460 + "solutions are to read the manual pages then download and" + lSep
461 + "install needed JAR files, or fix the build file: " + lSep
462 + " - You have misspelt '" + elementName + "'." + lSep
463 + " Fix: check your spelling." + lSep
464 + " - The task needs an external JAR file to execute" + lSep
465 + " and this is not found at the right place in the classpath." + lSep
466 + " Fix: check the documentation for dependencies." + lSep
467 + " Fix: declare the task." + lSep
468 + " - The task is an Ant optional task and the JAR file and/or libraries" + lSep
469 + " implementing the functionality were not found at the time you" + lSep
470 + " yourself built your installation of Ant from the Ant sources." + lSep
471 + " Fix: Look in the ANT_HOME/lib for the 'ant-' JAR corresponding to the" + lSep
472 + " task and make sure it contains more than merely a META-INF/MANIFEST.MF." + lSep
473 + " If all it contains is the manifest, then rebuild Ant with the needed" + lSep
474 + " libraries present in ${ant.home}/lib/optional/ , or alternatively," + lSep
475 + " download a pre-built release version from apache.org" + lSep
476 + " - The build file was written for a later version of Ant" + lSep
477 + " Fix: upgrade to at least the latest release version of Ant" + lSep
478 + " - The task is not an Ant core or optional task " + lSep
479 + " and needs to be declared using <taskdef>." + lSep
480 + " - You are attempting to use a task defined using " + lSep
481 + " <presetdef> or <macrodef> but have spelt wrong or not " + lSep
482 + " defined it at the point of use" + lSep
483 + lSep
484 + "Remember that for JAR files to be visible to Ant tasks implemented" + lSep
485 + "in ANT_HOME/lib, the files must be in the same directory or on the" + lSep
486 + "classpath" + lSep
487 + lSep
488 + "Please neither file bug reports on this problem, nor email the" + lSep
489 + "Ant mailing lists, until all of these causes have been explored," + lSep
490 + "as this is not an Ant bug.";
491
492
493 return new BuildException(msg, getLocation());
494 }
495
496 /**
497 * Returns the name to use in logging messages.
498 *
499 * @return the name to use in logging messages.
500 */
501 public String getTaskName() {
502 //return elementName;
503 return realThing == null
504 || !(realThing instanceof Task) ? super.getTaskName()
505 : ((Task) realThing).getTaskName();
506 }
507
508 /**
509 * Returns the task instance after it has been created and if it is a task.
510 *
511 * @return a task instance or <code>null</code> if the real object is not
512 * a task.
513 */
514 public Task getTask() {
515 if (realThing instanceof Task) {
516 return (Task) realThing;
517 }
518 return null;
519 }
520
521 /**
522 * Return the configured object
523 *
524 * @return the real thing whatever it is
525 *
526 * @since ant 1.6
527 */
528 public Object getRealThing() {
529 return realThing;
530 }
531 /**
532 * Try to create a nested element of <code>parent</code> for the
533 * given tag.
534 *
535 * @return whether the creation has been successful
536 */
537 private boolean handleChild(
538 String parentUri,
539 IntrospectionHelper ih,
540 Object parent, UnknownElement child,
541 RuntimeConfigurable childWrapper) {
542 String childName = ProjectHelper.genComponentName(
543 child.getNamespace(), child.getTag());
544 if (ih.supportsNestedElement(parentUri, childName)) {
545 IntrospectionHelper.Creator creator =
546 ih.getElementCreator(
547 getProject(), parentUri, parent, childName, child);
548 creator.setPolyType(childWrapper.getPolyType());
549 Object realChild = creator.create();
550 if (realChild instanceof PreSetDef.PreSetDefinition) {
551 PreSetDef.PreSetDefinition def =
552 (PreSetDef.PreSetDefinition) realChild;
553 realChild = creator.getRealObject();
554 child.applyPreSet(def.getPreSets());
555 }
556 childWrapper.setCreator(creator);
557 childWrapper.setProxy(realChild);
558 if (realChild instanceof Task) {
559 Task childTask = (Task) realChild;
560 childTask.setRuntimeConfigurableWrapper(childWrapper);
561 childTask.setTaskName(childName);
562 childTask.setTaskType(childName);
563 childTask.setLocation(child.getLocation());
564 }
565 child.handleChildren(realChild, childWrapper);
566 return true;
567 }
568 return false;
569 }
570
571 /**
572 * like contents equals, but ignores project
573 * @param obj the object to check against
574 * @return true if this unknownelement has the same contents the other
575 */
576 public boolean similar(Object obj) {
577 if (obj == null) {
578 return false;
579 }
580 if (!getClass().getName().equals(obj.getClass().getName())) {
581 return false;
582 }
583 UnknownElement other = (UnknownElement) obj;
584 // Are the names the same ?
585 if (!equalsString(elementName, other.elementName)) {
586 return false;
587 }
588 if (!namespace.equals(other.namespace)) {
589 return false;
590 }
591 if (!qname.equals(other.qname)) {
592 return false;
593 }
594 // Are attributes the same ?
595 if (!getWrapper().getAttributeMap().equals(
596 other.getWrapper().getAttributeMap())) {
597 return false;
598 }
599 // Is the text the same?
600 // Need to use equals on the string and not
601 // on the stringbuffer as equals on the string buffer
602 // does not compare the contents.
603 if (!getWrapper().getText().toString().equals(
604 other.getWrapper().getText().toString())) {
605 return false;
606 }
607 // Are the sub elements the same ?
608 if (children == null || children.size() == 0) {
609 return other.children == null || other.children.size() == 0;
610 }
611 if (other.children == null) {
612 return false;
613 }
614 if (children.size() != other.children.size()) {
615 return false;
616 }
617 for (int i = 0; i < children.size(); ++i) {
618 UnknownElement child = (UnknownElement) children.get(i);
619 if (!child.similar(other.children.get(i))) {
620 return false;
621 }
622 }
623 return true;
624 }
625
626 private boolean equalsString(String a, String b) {
627 if (a == null) {
628 return b == null;
629 }
630 return a.equals(b);
631 }
632}
Note: See TracBrowser for help on using the repository browser.