KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > UnknownElement


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18
19 package org.apache.tools.ant;
20
21 import java.util.ArrayList JavaDoc;
22 import java.util.Enumeration JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26 import java.io.IOException JavaDoc;
27 import org.apache.tools.ant.taskdefs.PreSetDef;
28
29 /**
30  * Wrapper class that holds all the information necessary to create a task
31  * or data type that did not exist when Ant started, or one which
32  * has had its definition updated to use a different implementation class.
33  *
34  */

35 public class UnknownElement extends Task {
36
37     /**
38      * Holds the name of the task/type or nested child element of a
39      * task/type that hasn't been defined at parser time or has
40      * been redefined since original creation.
41      */

42     private String JavaDoc elementName;
43
44     /**
45      * Holds the namespace of the element.
46      */

47     private String JavaDoc namespace = "";
48
49     /**
50      * Holds the namespace qname of the element.
51      */

52     private String JavaDoc qname;
53
54     /**
55      * The real object after it has been loaded.
56      */

57     private Object JavaDoc realThing;
58
59     /**
60      * List of child elements (UnknownElements).
61      */

62     private List JavaDoc/*<UnknownElement>*/ children = null;
63
64     /** Specifies if a predefined definition has been done */
65     private boolean presetDefed = false;
66
67     /**
68      * Creates an UnknownElement for the given element name.
69      *
70      * @param elementName The name of the unknown element.
71      * Must not be <code>null</code>.
72      */

73     public UnknownElement (String JavaDoc elementName) {
74         this.elementName = elementName;
75     }
76
77     /**
78      * @return the list of nested UnknownElements for this UnknownElement.
79      */

80     public List JavaDoc getChildren() {
81         return children;
82     }
83
84     /**
85      * Returns the name of the XML element which generated this unknown
86      * element.
87      *
88      * @return the name of the XML element which generated this unknown
89      * element.
90      */

91     public String JavaDoc getTag() {
92         return elementName;
93     }
94
95     /** Return the namespace of the XML element associated with this component.
96      *
97      * @return Namespace URI used in the xmlns declaration.
98      */

99     public String JavaDoc getNamespace() {
100         return namespace;
101     }
102
103     /**
104      * Set the namespace of the XML element associated with this component.
105      * This method is typically called by the XML processor.
106      * If the namespace is "ant:current", the component helper
107      * is used to get the current antlib uri.
108      *
109      * @param namespace URI used in the xmlns declaration.
110      */

111     public void setNamespace(String JavaDoc namespace) {
112         if (namespace.equals(ProjectHelper.ANT_CURRENT_URI)) {
113             ComponentHelper helper = ComponentHelper.getComponentHelper(
114                 getProject());
115             namespace = helper.getCurrentAntlibUri();
116         }
117         this.namespace = namespace == null ? "" : namespace;
118     }
119
120     /** Return the qname of the XML element associated with this component.
121      *
122      * @return namespace Qname used in the element declaration.
123      */

124     public String JavaDoc getQName() {
125         return qname;
126     }
127
128     /** Set the namespace qname of the XML element.
129      * This method is typically called by the XML processor.
130      *
131      * @param qname the qualified name of the element
132      */

133     public void setQName(String JavaDoc qname) {
134         this.qname = qname;
135     }
136
137
138     /**
139      * Get the RuntimeConfigurable instance for this UnknownElement, containing
140      * the configuration information.
141      *
142      * @return the configuration info.
143      */

144     public RuntimeConfigurable getWrapper() {
145         return super.getWrapper();
146     }
147
148     /**
149      * Creates the real object instance and child elements, then configures
150      * the attributes and text of the real object. This unknown element
151      * is then replaced with the real object in the containing target's list
152      * of children.
153      *
154      * @exception BuildException if the configuration fails
155      */

156     public void maybeConfigure() throws BuildException {
157         if (realThing != null) {
158             return;
159         }
160         configure(makeObject(this, getWrapper()));
161     }
162
163     /**
164      * Configure the given object from this UnknownElement
165      *
166      * @param realObject the real object this UnknownElement is representing.
167      *
168      */

169     public void configure(Object JavaDoc realObject) {
170         realThing = realObject;
171
172         getWrapper().setProxy(realThing);
173         Task task = null;
174         if (realThing instanceof Task) {
175             task = (Task) realThing;
176
177             task.setRuntimeConfigurableWrapper(getWrapper());
178
179             // For Script example that modifies id'ed tasks in other
180
// targets to work. *very* Ugly
181
// The reference is replaced by RuntimeConfigurable
182
if (getWrapper().getId() != null) {
183                 this.getOwningTarget().replaceChild(this, (Task) realThing);
184             }
185        }
186
187
188         // configure attributes of the object and it's children. If it is
189
// a task container, defer the configuration till the task container
190
// attempts to use the task
191

192         if (task != null) {
193             task.maybeConfigure();
194         } else {
195             getWrapper().maybeConfigure(getProject());
196         }
197
198         handleChildren(realThing, getWrapper());
199     }
200
201     /**
202      * Handles output sent to System.out by this task or its real task.
203      *
204      * @param output The output to log. Should not be <code>null</code>.
205      */

206     protected void handleOutput(String JavaDoc output) {
207         if (realThing instanceof Task) {
208             ((Task) realThing).handleOutput(output);
209         } else {
210             super.handleOutput(output);
211         }
212     }
213
214     /**
215      * Delegate to realThing if present and if it as task.
216      * @see Task#handleInput(byte[], int, int)
217      * @param buffer the buffer into which data is to be read.
218      * @param offset the offset into the buffer at which data is stored.
219      * @param length the amount of data to read.
220      *
221      * @return the number of bytes read.
222      *
223      * @exception IOException if the data cannot be read.
224      * @since Ant 1.6
225      */

226     protected int handleInput(byte[] buffer, int offset, int length)
227         throws IOException JavaDoc {
228         if (realThing instanceof Task) {
229             return ((Task) realThing).handleInput(buffer, offset, length);
230         } else {
231             return super.handleInput(buffer, offset, length);
232         }
233
234     }
235     /**
236      * Handles output sent to System.out by this task or its real task.
237      *
238      * @param output The output to log. Should not be <code>null</code>.
239      */

240     protected void handleFlush(String JavaDoc output) {
241         if (realThing instanceof Task) {
242             ((Task) realThing).handleFlush(output);
243         } else {
244             super.handleFlush(output);
245         }
246     }
247
248     /**
249      * Handles error output sent to System.err by this task or its real task.
250      *
251      * @param output The error output to log. Should not be <code>null</code>.
252      */

253     protected void handleErrorOutput(String JavaDoc output) {
254         if (realThing instanceof Task) {
255             ((Task) realThing).handleErrorOutput(output);
256         } else {
257             super.handleErrorOutput(output);
258         }
259     }
260
261
262     /**
263      * Handles error output sent to System.err by this task or its real task.
264      *
265      * @param output The error output to log. Should not be <code>null</code>.
266      */

267     protected void handleErrorFlush(String JavaDoc output) {
268         if (realThing instanceof Task) {
269             ((Task) realThing).handleErrorOutput(output);
270         } else {
271             super.handleErrorOutput(output);
272         }
273     }
274
275     /**
276      * Executes the real object if it's a task. If it's not a task
277      * (e.g. a data type) then this method does nothing.
278      */

279     public void execute() {
280         if (realThing == null) {
281             // plain impossible to get here, maybeConfigure should
282
// have thrown an exception.
283
throw new BuildException("Could not create task of type: "
284                                      + elementName, getLocation());
285         }
286
287         if (realThing instanceof Task) {
288             ((Task) realThing).execute();
289         }
290
291         // Finished executing the task, null it to allow
292
// GC do its job
293
// If this UE is used again, a new "realthing" will be made
294
realThing = null;
295         getWrapper().setProxy(null);
296
297     }
298
299     /**
300      * Adds a child element to this element.
301      *
302      * @param child The child element to add. Must not be <code>null</code>.
303      */

304     public void addChild(UnknownElement child) {
305         if (children == null) {
306             children = new ArrayList JavaDoc();
307         }
308         children.add(child);
309     }
310
311     /**
312      * Creates child elements, creates children of the children
313      * (recursively), and sets attributes of the child elements.
314      *
315      * @param parent The configured object for the parent.
316      * Must not be <code>null</code>.
317      *
318      * @param parentWrapper The wrapper containing child wrappers
319      * to be configured. Must not be <code>null</code>
320      * if there are any children.
321      *
322      * @exception BuildException if the children cannot be configured.
323      */

324     protected void handleChildren(
325         Object JavaDoc parent,
326         RuntimeConfigurable parentWrapper)
327         throws BuildException {
328         if (parent instanceof TypeAdapter) {
329             parent = ((TypeAdapter) parent).getProxy();
330         }
331
332         String JavaDoc parentUri = getNamespace();
333         Class JavaDoc parentClass = parent.getClass();
334         IntrospectionHelper ih = IntrospectionHelper.getHelper(getProject(), parentClass);
335
336
337         if (children != null) {
338             Iterator JavaDoc it = children.iterator();
339             for (int i = 0; it.hasNext(); i++) {
340                 RuntimeConfigurable childWrapper = parentWrapper.getChild(i);
341                 UnknownElement child = (UnknownElement) it.next();
342                 try {
343                     if (!handleChild(
344                             parentUri, ih, parent, child, childWrapper)) {
345                         if (!(parent instanceof TaskContainer)) {
346                             ih.throwNotSupported(getProject(), parent,
347                                                  child.getTag());
348                         } else {
349                             // a task container - anything could happen - just add the
350
// child to the container
351
TaskContainer container = (TaskContainer) parent;
352                             container.addTask(child);
353                         }
354                     }
355                 } catch (UnsupportedElementException ex) {
356                     throw new BuildException(
357                         parentWrapper.getElementTag()
358                         + " doesn't support the nested \"" + ex.getElement()
359                         + "\" element.", ex);
360                 }
361             }
362         }
363     }
364
365     /**
366      * @return the component name - uses ProjectHelper#genComponentName()
367      */

368     protected String JavaDoc getComponentName() {
369         return ProjectHelper.genComponentName(getNamespace(), getTag());
370     }
371
372     /**
373      * This is used then the realobject of the UE is a PreSetDefinition.
374      * This is also used when a presetdef is used on a presetdef
375      * The attributes, elements and text are applied to this
376      * UE.
377      *
378      * @param u an UnknownElement containing the attributes, elements and text
379      */

380     public void applyPreSet(UnknownElement u) {
381         if (presetDefed) {
382             return;
383         }
384         // Do the runtime
385
getWrapper().applyPreSet(u.getWrapper());
386         if (u.children != null) {
387             List JavaDoc newChildren = new ArrayList JavaDoc();
388             newChildren.addAll(u.children);
389             if (children != null) {
390                 newChildren.addAll(children);
391             }
392             children = newChildren;
393         }
394         presetDefed = true;
395     }
396
397     /**
398      * Creates a named task or data type. If the real object is a task,
399      * it is configured up to the init() stage.
400      *
401      * @param ue The unknown element to create the real object for.
402      * Must not be <code>null</code>.
403      * @param w Ignored in this implementation.
404      *
405      * @return the task or data type represented by the given unknown element.
406      */

407     protected Object JavaDoc makeObject(UnknownElement ue, RuntimeConfigurable w) {
408         ComponentHelper helper = ComponentHelper.getComponentHelper(
409             getProject());
410         String JavaDoc name = ue.getComponentName();
411         Object JavaDoc o = helper.createComponent(ue, ue.getNamespace(), name);
412         if (o == null) {
413             throw getNotFoundException("task or type", name);
414         }
415         if (o instanceof PreSetDef.PreSetDefinition) {
416             PreSetDef.PreSetDefinition def = (PreSetDef.PreSetDefinition) o;
417             o = def.createObject(ue.getProject());
418             if (o == null) {
419                 throw getNotFoundException(
420                     "preset " + name,
421                     def.getPreSets().getComponentName());
422             }
423             ue.applyPreSet(def.getPreSets());
424             if (o instanceof Task) {
425                 Task task = (Task) o;
426                 task.setTaskType(ue.getTaskType());
427                 task.setTaskName(ue.getTaskName());
428                 task.init();
429             }
430         }
431         if (o instanceof UnknownElement) {
432             o = ((UnknownElement) o).makeObject((UnknownElement) o, w);
433         }
434         if (o instanceof Task) {
435             ((Task) o).setOwningTarget(getOwningTarget());
436         }
437         if (o instanceof ProjectComponent) {
438             ((ProjectComponent) o).setLocation(getLocation());
439         }
440         return o;
441     }
442
443     /**
444      * Creates a named task and configures it up to the init() stage.
445      *
446      * @param ue The UnknownElement to create the real task for.
447      * Must not be <code>null</code>.
448      * @param w Ignored.
449      *
450      * @return the task specified by the given unknown element, or
451      * <code>null</code> if the task name is not recognised.
452      */

453     protected Task makeTask(UnknownElement ue, RuntimeConfigurable w) {
454         Task task = getProject().createTask(ue.getTag());
455
456         if (task != null) {
457             task.setLocation(getLocation());
458             // UnknownElement always has an associated target
459
task.setOwningTarget(getOwningTarget());
460             task.init();
461         }
462         return task;
463     }
464
465     /**
466      * Returns a very verbose exception for when a task/data type cannot
467      * be found.
468      *
469      * @param what The kind of thing being created. For example, when
470      * a task name could not be found, this would be
471      * <code>"task"</code>. Should not be <code>null</code>.
472      * @param name The name of the element which could not be found.
473      * Should not be <code>null</code>.
474      *
475      * @return a detailed description of what might have caused the problem.
476      */

477     protected BuildException getNotFoundException(String JavaDoc what,
478                                                   String JavaDoc name) {
479         ComponentHelper helper = ComponentHelper.getComponentHelper(getProject());
480         String JavaDoc msg = helper.diagnoseCreationFailure(name, what);
481         return new BuildException(msg, getLocation());
482     }
483
484     /**
485      * Returns the name to use in logging messages.
486      *
487      * @return the name to use in logging messages.
488      */

489     public String JavaDoc getTaskName() {
490         //return elementName;
491
return realThing == null
492             || !(realThing instanceof Task) ? super.getTaskName()
493                                             : ((Task) realThing).getTaskName();
494     }
495
496     /**
497      * Returns the task instance after it has been created and if it is a task.
498      *
499      * @return a task instance or <code>null</code> if the real object is not
500      * a task.
501      */

502     public Task getTask() {
503         if (realThing instanceof Task) {
504             return (Task) realThing;
505         }
506         return null;
507     }
508
509     /**
510      * Return the configured object
511      *
512      * @return the real thing whatever it is
513      *
514      * @since ant 1.6
515      */

516     public Object JavaDoc getRealThing() {
517         return realThing;
518     }
519
520     /**
521      * Set the configured object
522      * @param realThing the configured object
523      * @since ant 1.7
524      */

525     public void setRealThing(Object JavaDoc realThing) {
526         this.realThing = realThing;
527     }
528
529     /**
530      * Try to create a nested element of <code>parent</code> for the
531      * given tag.
532      *
533      * @return whether the creation has been successful
534      */

535     private boolean handleChild(
536         String JavaDoc parentUri,
537         IntrospectionHelper ih,
538         Object JavaDoc parent, UnknownElement child,
539         RuntimeConfigurable childWrapper) {
540         String JavaDoc childName = ProjectHelper.genComponentName(
541             child.getNamespace(), child.getTag());
542         if (ih.supportsNestedElement(parentUri, childName)) {
543             IntrospectionHelper.Creator creator =
544                 ih.getElementCreator(
545                     getProject(), parentUri, parent, childName, child);
546             creator.setPolyType(childWrapper.getPolyType());
547             Object JavaDoc realChild = creator.create();
548             if (realChild instanceof PreSetDef.PreSetDefinition) {
549                 PreSetDef.PreSetDefinition def =
550                     (PreSetDef.PreSetDefinition) realChild;
551                 realChild = creator.getRealObject();
552                 child.applyPreSet(def.getPreSets());
553             }
554             childWrapper.setCreator(creator);
555             childWrapper.setProxy(realChild);
556             if (realChild instanceof Task) {
557                 Task childTask = (Task) realChild;
558                 childTask.setRuntimeConfigurableWrapper(childWrapper);
559                 childTask.setTaskName(childName);
560                 childTask.setTaskType(childName);
561             }
562             if (realChild instanceof ProjectComponent) {
563                 ((ProjectComponent) realChild).setLocation(child.getLocation());
564             }
565             childWrapper.maybeConfigure(getProject());
566             child.handleChildren(realChild, childWrapper);
567             creator.store();
568             return true;
569         }
570         return false;
571     }
572
573     /**
574      * like contents equals, but ignores project
575      * @param obj the object to check against
576      * @return true if this unknownelement has the same contents the other
577      */

578     public boolean similar(Object JavaDoc obj) {
579         if (obj == null) {
580             return false;
581         }
582         if (!getClass().getName().equals(obj.getClass().getName())) {
583             return false;
584         }
585         UnknownElement other = (UnknownElement) obj;
586         // Are the names the same ?
587
if (!equalsString(elementName, other.elementName)) {
588             return false;
589         }
590         if (!namespace.equals(other.namespace)) {
591             return false;
592         }
593         if (!qname.equals(other.qname)) {
594             return false;
595         }
596         // Are attributes the same ?
597
if (!getWrapper().getAttributeMap().equals(
598                 other.getWrapper().getAttributeMap())) {
599             return false;
600         }
601         // Is the text the same?
602
// Need to use equals on the string and not
603
// on the stringbuffer as equals on the string buffer
604
// does not compare the contents.
605
if (!getWrapper().getText().toString().equals(
606                 other.getWrapper().getText().toString())) {
607             return false;
608         }
609         // Are the sub elements the same ?
610
if (children == null || children.size() == 0) {
611             return other.children == null || other.children.size() == 0;
612         }
613         if (other.children == null) {
614             return false;
615         }
616         if (children.size() != other.children.size()) {
617             return false;
618         }
619         for (int i = 0; i < children.size(); ++i) {
620             UnknownElement child = (UnknownElement) children.get(i);
621             if (!child.similar(other.children.get(i))) {
622                 return false;
623             }
624         }
625         return true;
626     }
627
628     private static boolean equalsString(String JavaDoc a, String JavaDoc b) {
629         return (a == null) ? (b == null) : a.equals(b);
630     }
631
632     /**
633      * Make a copy of the unknown element and set it in the new project.
634      * @param newProject the project to create the UE in.
635      * @return the copied UE.
636      */

637     public UnknownElement copy(Project newProject) {
638         UnknownElement ret = new UnknownElement(getTag());
639         ret.setNamespace(getNamespace());
640         ret.setProject(newProject);
641         ret.setQName(getQName());
642         ret.setTaskType(getTaskType());
643         ret.setTaskName(getTaskName());
644         ret.setLocation(getLocation());
645         if (getOwningTarget() == null) {
646             Target t = new Target();
647             t.setProject(getProject());
648             ret.setOwningTarget(t);
649         } else {
650             ret.setOwningTarget(getOwningTarget());
651         }
652         RuntimeConfigurable copyRC = new RuntimeConfigurable(
653             ret, getTaskName());
654         copyRC.setPolyType(getWrapper().getPolyType());
655         Map JavaDoc m = getWrapper().getAttributeMap();
656         for (Iterator JavaDoc i = m.entrySet().iterator(); i.hasNext();) {
657             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) i.next();
658             copyRC.setAttribute(
659                 (String JavaDoc) entry.getKey(), (String JavaDoc) entry.getValue());
660         }
661         copyRC.addText(getWrapper().getText().toString());
662
663         for (Enumeration JavaDoc e = getWrapper().getChildren(); e.hasMoreElements();) {
664             RuntimeConfigurable r = (RuntimeConfigurable) e.nextElement();
665             UnknownElement ueChild = (UnknownElement) r.getProxy();
666             UnknownElement copyChild = ueChild.copy(newProject);
667             copyRC.addChild(copyChild.getWrapper());
668             ret.addChild(copyChild);
669         }
670         return ret;
671     }
672 }
673
Popular Tags