KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.Serializable JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.Enumeration JavaDoc;
25 import java.util.HashMap JavaDoc;
26 import java.util.Hashtable JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Locale JavaDoc;
29 import java.util.Map JavaDoc;
30 import java.util.Iterator JavaDoc;
31
32 import org.apache.tools.ant.util.CollectionUtils;
33 import org.xml.sax.AttributeList JavaDoc;
34 import org.xml.sax.helpers.AttributeListImpl JavaDoc;
35
36 /**
37  * Wrapper class that holds the attributes of an element, its children, and
38  * any text within it. It then takes care of configuring that element at
39  * runtime.
40  *
41  */

42 public class RuntimeConfigurable implements Serializable JavaDoc {
43
44     /** Empty Hashtable. */
45     private static final Hashtable JavaDoc EMPTY_HASHTABLE = new Hashtable JavaDoc(0);
46
47     /** Name of the element to configure. */
48     private String JavaDoc elementTag = null;
49
50     /** List of child element wrappers. */
51     private List JavaDoc/*<RuntimeConfigurable>*/ children = null;
52
53     /** The element to configure. It is only used during
54      * maybeConfigure.
55      */

56     private transient Object JavaDoc wrappedObject = null;
57
58     /** the creator used to make the wrapped object */
59     private transient IntrospectionHelper.Creator creator;
60
61     /**
62      * XML attributes for the element.
63      * @deprecated since 1.6.x
64      */

65     private transient AttributeList JavaDoc attributes;
66
67     /** Attribute names and values. While the XML spec doesn't require
68      * preserving the order ( AFAIK ), some ant tests do rely on the
69      * exact order. The following code is copied from AttributeImpl.
70      * We could also just use SAX2 Attributes and convert to SAX1 ( DOM
71      * attribute Nodes can also be stored in SAX2 Attributes )
72      * XXX under JDK 1.4 you can just use a LinkedHashMap for this purpose -jglick
73      * The only exception to this order is the treatment of
74      * refid. A number of datatypes check if refid is set
75      * when other attributes are set. This check will not
76      * work if the build script has the other attribute before
77      * the "refid" attribute, so now (ANT 1.7) the refid
78      * attribute will be processed first.
79      */

80     private List JavaDoc/*<String>*/ attributeNames = null;
81
82     /** Map of attribute names to values */
83     private Map JavaDoc/*<String,String>*/ attributeMap = null;
84
85     /** Text appearing within the element. */
86     private StringBuffer JavaDoc characters = null;
87
88     /** Indicates if the wrapped object has been configured */
89     private boolean proxyConfigured = false;
90
91     /** the polymorphic type */
92     private String JavaDoc polyType = null;
93
94     /** the "id" of this Element if it has one */
95     private String JavaDoc id = null;
96
97     /**
98      * Sole constructor creating a wrapper for the specified object.
99      *
100      * @param proxy The element to configure. Must not be <code>null</code>.
101      * @param elementTag The tag name generating this element.
102      */

103     public RuntimeConfigurable(Object JavaDoc proxy, String JavaDoc elementTag) {
104         setProxy(proxy);
105         setElementTag(elementTag);
106         // Most likely an UnknownElement
107
if (proxy instanceof Task) {
108             ((Task) proxy).setRuntimeConfigurableWrapper(this);
109         }
110     }
111
112     /**
113      * Sets the element to configure.
114      *
115      * @param proxy The element to configure. Must not be <code>null</code>.
116      */

117     public synchronized void setProxy(Object JavaDoc proxy) {
118         wrappedObject = proxy;
119         proxyConfigured = false;
120     }
121
122     /**
123      * Sets the creator of the element to be configured
124      * used to store the element in the parent.
125      *
126      * @param creator the creator object.
127      */

128     synchronized void setCreator(IntrospectionHelper.Creator creator) {
129         this.creator = creator;
130     }
131
132     /**
133      * Get the object for which this RuntimeConfigurable holds the configuration
134      * information.
135      *
136      * @return the object whose configure is held by this instance.
137      */

138     public synchronized Object JavaDoc getProxy() {
139         return wrappedObject;
140     }
141
142     /**
143      * Returns the id for this element.
144      * @return the id.
145      */

146     public synchronized String JavaDoc getId() {
147         return id;
148     }
149
150     /**
151      * Get the polymorphic type for this element.
152      * @return the ant component type name, null if not set.
153      */

154     public synchronized String JavaDoc getPolyType() {
155         return polyType;
156     }
157
158     /**
159      * Set the polymorphic type for this element.
160      * @param polyType the ant component type name, null if not set.
161      */

162     public synchronized void setPolyType(String JavaDoc polyType) {
163         this.polyType = polyType;
164     }
165
166     /**
167      * Sets the attributes for the wrapped element.
168      *
169      * @deprecated since 1.6.x.
170      * @param attributes List of attributes defined in the XML for this
171      * element. May be <code>null</code>.
172      */

173     public synchronized void setAttributes(AttributeList JavaDoc attributes) {
174         this.attributes = new AttributeListImpl JavaDoc(attributes);
175         for (int i = 0; i < attributes.getLength(); i++) {
176             setAttribute(attributes.getName(i), attributes.getValue(i));
177         }
178     }
179
180     /**
181      * Set an attribute to a given value.
182      *
183      * @param name the name of the attribute.
184      * @param value the attribute's value.
185      */

186     public synchronized void setAttribute(String JavaDoc name, String JavaDoc value) {
187         if (name.equalsIgnoreCase(ProjectHelper.ANT_TYPE)) {
188             this.polyType = value;
189         } else {
190             if (attributeNames == null) {
191                 attributeNames = new ArrayList JavaDoc();
192                 attributeMap = new HashMap JavaDoc();
193             }
194             if (name.toLowerCase(Locale.US).equals("refid")) {
195                 attributeNames.add(0, name);
196             } else {
197                 attributeNames.add(name);
198             }
199             attributeMap.put(name, value);
200             if (name.equals("id")) {
201                 this.id = value;
202             }
203         }
204     }
205
206     /**
207      * Delete an attribute. Not for the faint of heart.
208      * @param name the name of the attribute to be removed.
209      */

210     public synchronized void removeAttribute(String JavaDoc name) {
211         attributeNames.remove(name);
212         attributeMap.remove(name);
213     }
214
215     /**
216      * Return the attribute map.
217      *
218      * @return Attribute name to attribute value map.
219      * @since Ant 1.6
220      */

221     public synchronized Hashtable JavaDoc getAttributeMap() {
222         return (attributeMap == null)
223             ? EMPTY_HASHTABLE : new Hashtable JavaDoc(attributeMap);
224     }
225
226     /**
227      * Returns the list of attributes for the wrapped element.
228      *
229      * @deprecated Deprecated since Ant 1.6 in favor of {@link #getAttributeMap}.
230      * @return An AttributeList representing the attributes defined in the
231      * XML for this element. May be <code>null</code>.
232      */

233     public synchronized AttributeList JavaDoc getAttributes() {
234         return attributes;
235     }
236
237     /**
238      * Adds a child element to the wrapped element.
239      *
240      * @param child The child element wrapper to add to this one.
241      * Must not be <code>null</code>.
242      */

243     public synchronized void addChild(RuntimeConfigurable child) {
244         children = (children == null) ? new ArrayList JavaDoc() : children;
245         children.add(child);
246     }
247
248     /**
249      * Returns the child wrapper at the specified position within the list.
250      *
251      * @param index The index of the child to return.
252      *
253      * @return The child wrapper at position <code>index</code> within the
254      * list.
255      */

256     synchronized RuntimeConfigurable getChild(int index) {
257         return (RuntimeConfigurable) children.get(index);
258     }
259
260     /**
261      * Returns an enumeration of all child wrappers.
262      * @return an enumeration of the child wrappers.
263      * @since Ant 1.6
264      */

265     public synchronized Enumeration JavaDoc getChildren() {
266         return (children == null) ? new CollectionUtils.EmptyEnumeration()
267             : Collections.enumeration(children);
268     }
269
270     /**
271      * Adds characters from #PCDATA areas to the wrapped element.
272      *
273      * @param data Text to add to the wrapped element.
274      * Should not be <code>null</code>.
275      */

276     public synchronized void addText(String JavaDoc data) {
277         if (data.length() == 0) {
278             return;
279         }
280         characters = (characters == null)
281             ? new StringBuffer JavaDoc(data) : characters.append(data);
282     }
283
284     /**
285      * Adds characters from #PCDATA areas to the wrapped element.
286      *
287      * @param buf A character array of the text within the element.
288      * Must not be <code>null</code>.
289      * @param start The start element in the array.
290      * @param count The number of characters to read from the array.
291      *
292      */

293     public synchronized void addText(char[] buf, int start, int count) {
294         if (count == 0) {
295             return;
296         }
297         characters = ((characters == null)
298             ? new StringBuffer JavaDoc(count) : characters).append(buf, start, count);
299     }
300
301     /**
302      * Get the text content of this element. Various text chunks are
303      * concatenated, there is no way ( currently ) of keeping track of
304      * multiple fragments.
305      *
306      * @return the text content of this element.
307      * @since Ant 1.6
308      */

309     public synchronized StringBuffer JavaDoc getText() {
310         return (characters == null) ? new StringBuffer JavaDoc(0) : characters;
311     }
312
313     /**
314      * Set the element tag.
315      * @param elementTag The tag name generating this element.
316      */

317     public synchronized void setElementTag(String JavaDoc elementTag) {
318         this.elementTag = elementTag;
319     }
320
321     /**
322      * Returns the tag name of the wrapped element.
323      *
324      * @return The tag name of the wrapped element. This is unlikely
325      * to be <code>null</code>, but may be.
326      */

327     public synchronized String JavaDoc getElementTag() {
328         return elementTag;
329     }
330
331     /**
332      * Configures the wrapped element and all its children.
333      * The attributes and text for the wrapped element are configured,
334      * and then each child is configured and added. Each time the
335      * wrapper is configured, the attributes and text for it are
336      * reset.
337      *
338      * If the element has an <code>id</code> attribute, a reference
339      * is added to the project as well.
340      *
341      * @param p The project containing the wrapped element.
342      * Must not be <code>null</code>.
343      *
344      * @exception BuildException if the configuration fails, for instance due
345      * to invalid attributes or children, or text being added to
346      * an element which doesn't accept it.
347      */

348     public void maybeConfigure(Project p) throws BuildException {
349         maybeConfigure(p, true);
350     }
351
352     /**
353      * Configures the wrapped element. The attributes and text for
354      * the wrapped element are configured. Each time the wrapper is
355      * configured, the attributes and text for it are reset.
356      *
357      * If the element has an <code>id</code> attribute, a reference
358      * is added to the project as well.
359      *
360      * @param p The project containing the wrapped element.
361      * Must not be <code>null</code>.
362      *
363      * @param configureChildren ignored.
364
365      *
366      * @exception BuildException if the configuration fails, for instance due
367      * to invalid attributes , or text being added to
368      * an element which doesn't accept it.
369      */

370     public synchronized void maybeConfigure(Project p, boolean configureChildren)
371         throws BuildException {
372
373         if (proxyConfigured) {
374             return;
375         }
376
377         // Configure the object
378
Object JavaDoc target = (wrappedObject instanceof TypeAdapter)
379             ? ((TypeAdapter) wrappedObject).getProxy() : wrappedObject;
380
381         IntrospectionHelper ih =
382             IntrospectionHelper.getHelper(p, target.getClass());
383
384         if (attributeNames != null) {
385             for (int i = 0; i < attributeNames.size(); i++) {
386                 String JavaDoc name = (String JavaDoc) attributeNames.get(i);
387                 String JavaDoc value = (String JavaDoc) attributeMap.get(name);
388
389                 // reflect these into the target
390
value = p.replaceProperties(value);
391                 try {
392                     ih.setAttribute(p, target, name, value);
393                 } catch (UnsupportedAttributeException be) {
394                     // id attribute must be set externally
395
if (name.equals("id")) {
396                         // Do nothing
397
} else if (getElementTag() == null) {
398                         throw be;
399                     } else {
400                         throw new BuildException(
401                             getElementTag() + " doesn't support the \""
402                             + be.getAttribute() + "\" attribute", be);
403                     }
404                 } catch (BuildException be) {
405                     if (name.equals("id")) {
406                         // Assume that this is an not supported attribute type
407
// thrown for example by a dymanic attribute task
408
// Do nothing
409
} else {
410                         throw be;
411                     }
412                 }
413             }
414         }
415
416         if (characters != null) {
417             ProjectHelper.addText(p, wrappedObject, characters.substring(0));
418         }
419
420         if (id != null) {
421             p.addReference(id, wrappedObject);
422         }
423         proxyConfigured = true;
424     }
425
426     /**
427      * Reconfigure the element, even if it has already been configured.
428      *
429      * @param p the project instance for this configuration.
430      */

431     public void reconfigure(Project p) {
432         proxyConfigured = false;
433         maybeConfigure(p);
434     }
435
436
437     /**
438      * Apply presets, attributes and text are set if not currently set.
439      * Nested elements are prepended.
440      *
441      * @param r a <code>RuntimeConfigurable</code> value.
442      */

443     public void applyPreSet(RuntimeConfigurable r) {
444         // Attributes
445
if (r.attributeMap != null) {
446             for (Iterator JavaDoc i = r.attributeMap.keySet().iterator(); i.hasNext();) {
447                 String JavaDoc name = (String JavaDoc) i.next();
448                 if (attributeMap == null || attributeMap.get(name) == null) {
449                     setAttribute(name, (String JavaDoc) r.attributeMap.get(name));
450                 }
451             }
452         }
453         // poly type
454

455         polyType = (polyType == null) ? r.polyType : polyType;
456
457         // Children (this is a shadow of UnknownElement#children)
458
if (r.children != null) {
459             List JavaDoc newChildren = new ArrayList JavaDoc();
460             newChildren.addAll(r.children);
461             if (children != null) {
462                 newChildren.addAll(children);
463             }
464             children = newChildren;
465         }
466
467         // Text
468
if (r.characters != null) {
469             if (characters == null
470                 || characters.toString().trim().length() == 0) {
471                 characters = new StringBuffer JavaDoc(r.characters.toString());
472             }
473         }
474     }
475 }
476
Popular Tags