KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > xml > XmlElement


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2005 - Javolution (http://javolution.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package javolution.xml;
10
11 import j2me.lang.CharSequence;
12 import javolution.lang.Text;
13 import javolution.lang.TextBuilder;
14 import javolution.lang.TypeFormat;
15 import javolution.realtime.ObjectFactory;
16 import javolution.util.FastComparator;
17 import javolution.util.FastList;
18 import javolution.util.FastMap;
19 import javolution.util.FastTable;
20 import javolution.xml.sax.Attributes;
21 import javolution.xml.sax.AttributesImpl;
22
23 /**
24  * <p> This class represents a XML element. Instances of this class are made
25  * available only during the XML serialization/deserialization process.</p>
26  *
27  * <p> During serialization, {@link XmlFormat#format
28  * XmlFormat.format(XmlElement)} is used to represent the Java objects
29  * into XML.
30  *
31  * <p> During deserialization, {@link XmlFormat#format
32  * XmlFormat.parse(XmlElement)} is used to restore the objects from their
33  * XML representations.</p>
34  *
35  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
36  * @version 3.2, March 18, 2005
37  */

38 public final class XmlElement {
39
40     /**
41      * Holds the associate factory (for preallocation).
42      */

43     static final ObjectFactory FACTORY = new ObjectFactory() {
44         protected Object create() {
45             return new XmlElement();
46         }
47     };
48
49     /**
50      * Holds the object class corresponding to this xml element.
51      */

52     Class _objectClass;
53
54     /**
55      * Holds the parent xml element.
56      */

57     XmlElement _parent;
58
59     /**
60      * Holds the associated format
61      */

62     XmlFormat _format;
63
64     /**
65      * Holds the corresponding object.
66      */

67     Object _object;
68
69     /**
70      * Holds the id value (if any).
71      */

72     CharSequence _idValue;
73
74     /**
75      * Holds this element attributes when parsing/formatting.
76      */

77     AttributesImpl _attributes = new AttributesImpl();
78
79     /**
80      * Holds the name for this xml element if any.
81      */

82     CharSequence _name;
83
84     /**
85      * Holds the anonymous elements content.
86      */

87     final FastList _content = new FastList();
88
89     /**
90      * Holds the named child elements.
91      */

92     final FastMap _nameToChild
93         = new FastMap().setKeyComparator(FastComparator.LEXICAL);
94
95     /**
96      * Holds a pool of text builder instances.
97      */

98     private FastTable _pool = new FastTable();
99     
100     /**
101      * Holds the index of the first free instance in the pool.
102      */

103     private int _poolIndex;
104     
105     /**
106      * Default constructor.
107      */

108     XmlElement() {
109     }
110
111     /**
112      * Returns the object corresponding to this xml element; this object has
113      * been either {@link XmlFormat#preallocate(XmlElement) preallocated}
114      * or created using the {@link #objectClass} default constructor.
115      *
116      * @return the (uninitialized) object corresponding to this xml element.
117      */

118     public /*<T>*/ Object/*T*/ object() throws XmlException {
119         if (_object == null) {
120             try {
121                 _object = _objectClass.newInstance();
122             } catch (IllegalAccessException e2) {
123                 throw new XmlException(_objectClass
124                         + " default constructor inaccessible");
125             } catch (InstantiationException e3) {
126                 throw new XmlException(_objectClass
127                         + " default constructor throws an exception");
128             }
129         }
130         return (Object/*T*/) _object;
131     }
132
133     /**
134      * Returns the list of anonymous objects associated to this xml element
135      * (positional association). During serialization these objects are
136      * represented as child elements with their class name (or alias) for
137      * element name. During deserialization this list is constructed from
138      * deserialization of all anonymous child elements.
139      *
140      * @return the list of anonymous objects content of this xml element.
141      */

142     public FastList getContent() {
143         return _content;
144     }
145
146     ///////////////////
147
// Serialization //
148
///////////////////
149

150     /**
151      * Adds a named element corresponding to the specified object
152      * (<code>null</code> objects are ignored). Named elements are
153      * always serialized before anonymous one (see {@link #getContent}).
154      *
155      * @param name the tag name of the nested xml element corresponding
156      * to the object being added.
157      * @param obj the object added as child element or <code>null</code>.
158      */

159     public void add(String name, Object obj) {
160         if (obj == null) return;
161         _nameToChild.put(name, obj);
162     }
163
164     /**
165      * Returns a new text builder to hold the specified attribute.
166      * This method allows for custom attribute formatting. For example:<pre>
167      * // Formats the color RGB value in hexadecimal.
168      * xml.newAttribute("color").append(_color.getRGB(), 16);
169      *
170      * // Formats the error using 4 digits.
171      * xml.newAttribute("error").append(error, 4, false, false);</pre>
172      *
173      * @param name the attribute name.
174      * @return the text builder to hold the attribute value.
175      */

176     public TextBuilder newAttribute(String name) {
177         TextBuilder value = newTextBuilder();
178         setAttribute(name, value);
179         return value;
180     }
181     
182     /**
183      * Sets the specified <code>CharSequence</code> attribute
184      * (<code>null</code> values are ignored).
185      *
186      * @param name the attribute name.
187      * @param value the attribute value or <code>null</code>.
188      */

189     public void setAttribute(String name, CharSequence value) {
190         if (value == null)
191             return;
192         CharSequence csqName = toCharSeq(name);
193         _attributes.addAttribute(Text.EMPTY, csqName, Text.EMPTY, csqName, "CDATA", value);
194     }
195     
196
197     /**
198      * Sets the specified <code>String</code> attribute
199      * (<code>null</code> values are ignored).
200      *
201      * @param name the attribute name.
202      * @param value the attribute value.
203      */

204     public void setAttribute(String name, String value) {
205         if (value == null)
206             return;
207         CharSequence csqName = toCharSeq(name);
208         CharSequence csqValue = toCharSeq(value);
209         _attributes.addAttribute(Text.EMPTY, csqName, Text.EMPTY, csqName, "CDATA", csqValue);
210     }
211
212     /**
213      * Sets the specified <code>boolean</code> attribute.
214      *
215      * @param name the name of the attribute.
216      * @param value the <code>boolean</code> value for the specified attribute.
217      * @see #getAttribute(String, boolean)
218      */

219     public void setAttribute(String name, boolean value) {
220         newAttribute(name).append(value);
221     }
222
223     /**
224      * Sets the specified <code>int</code> attribute.
225      *
226      * @param name the name of the attribute.
227      * @param value the <code>int</code> value for the specified attribute.
228      * @see #getAttribute(String, int)
229      */

230     public void setAttribute(String name, int value) {
231         newAttribute(name).append(value);
232     }
233
234     /**
235      * Sets the specified <code>long</code> attribute.
236      *
237      * @param name the name of the attribute.
238      * @param value the <code>long</code> value for the specified attribute.
239      * @see #getAttribute(String, long)
240      */

241     public void setAttribute(String name, long value) {
242         newAttribute(name).append(value);
243     }
244
245     /**
246      * Sets the specified <code>float</code> attribute.
247      *
248      * @param name the name of the attribute.
249      * @param value the <code>float</code> value for the specified attribute.
250      * @see #getAttribute(String, float)
251      /*@FLOATING_POINT@
252      public void setAttribute(String name, float value) {
253         newAttribute(name).append(value);
254      }
255      /**/

256
257     /**
258      * Sets the specified <code>double</code> attribute.
259      *
260      * @param name the name of the attribute.
261      * @param value the <code>double</code> value for the specified attribute.
262      * @see #getAttribute(String, double)
263      /*@FLOATING_POINT@
264      public void setAttribute(String name, double value) {
265         newAttribute(name).append(value);
266      }
267      /**/

268
269     /////////////////////
270
// Deserialization //
271
/////////////////////
272

273     /**
274      * Adds a child element having the specified element name (mutable).
275      *
276      * @param name the name for the object added.
277      * @param obj the object added as child element.
278      */

279     void add(CharSequence name, Object obj) {
280         TextBuilder tb = newTextBuilder();
281         tb.append(name);
282         _nameToChild.put(tb, obj);
283     }
284
285     /**
286      * Returns the parent container xml element.
287      *
288      * @return the parent xml element or <code>null</code> if root element.
289      */

290     public XmlElement getParent() {
291         return _parent;
292     }
293
294     /**
295      * Returns the Java(tm) class corresponding to this XML element;
296      * the class is identified by the tag name of this xml element or the <code>
297      * "j:class" attribute when present.
298      *
299      * @return this XML element's corresponding class.
300      */

301     public Class objectClass() {
302         return _objectClass;
303     }
304
305     /**
306      * Returns the object corresponding to the child element having the
307      * specified element name (tag name).
308      *
309      * @param name the name of the child element.
310      * @return the object corresponding to the child element.
311      */

312     public /*<T>*/ Object/*T*/ get(String name) {
313         return (Object/*T*/)_nameToChild.get(name);
314     }
315
316     /**
317      * Returns the attributes for this xml element.
318      *
319      * @return the attributes mapping.
320      */

321     public Attributes getAttributes() {
322         return _attributes;
323     }
324
325     /**
326      * Searches for the attribute having the specified name.
327      *
328      * @param name the qualified name of the attribute (qName).
329      * @return the value for the specified attribute or <code>null</code>
330      * if the attribute is not found.
331      */

332     public CharSequence getAttribute(String name) {
333         return _attributes.getValue(name);
334     }
335
336     /**
337      * Indicates if the specified attribute is present.
338      *
339      * @param name the qualified name of the attribute (qName).
340      * @return <code>true</code> if this xml element contains the specified
341      * attribute; <code>false</code> otherwise.
342      */

343     public boolean isAttribute(String name) {
344         return _attributes.getIndex(name) >= 0;
345     }
346
347     /**
348      * Returns the specified <code>CharSequence</code> attribute.
349      *
350      * @param name the name of the attribute.
351      * @param defaultValue a default value.
352      * @return the value for the specified attribute or
353      * the <code>defaultValue</code> if the attribute is not found.
354      */

355     public CharSequence getAttribute(String name, CharSequence defaultValue) {
356         CharSequence value = _attributes.getValue(name);
357         return (value != null) ? value : defaultValue;
358     }
359
360     /**
361      * Returns the specified <code>String</code> attribute.
362      *
363      * @param name the name of the attribute.
364      * @param defaultValue a default value.
365      * @return the value for the specified attribute or
366      * the <code>defaultValue</code> if the attribute is not found.
367      */

368     public String getAttribute(String name, String defaultValue) {
369         CharSequence value = _attributes.getValue(name);
370         return (value != null) ? value.toString() : defaultValue;
371     }
372
373     /**
374      * Returns the specified <code>boolean</code> attribute.
375      *
376      * @param name the name of the attribute searched for.
377      * @param defaultValue the value returned if the attribute is not found.
378      * @return the <code>boolean</code> value for the specified attribute or
379      * the default value if the attribute is not found.
380      */

381     public boolean getAttribute(String name, boolean defaultValue) {
382         CharSequence value = _attributes.getValue(name);
383         return (value != null) ? TypeFormat.parseBoolean(value) : defaultValue;
384     }
385
386     /**
387      * Returns the specified <code>int</code> attribute. This method handles
388      * string formats that are used to represent octal and hexadecimal numbers.
389      *
390      * @param name the name of the attribute searched for.
391      * @param defaultValue the value returned if the attribute is not found.
392      * @return the <code>int</code> value for the specified attribute or
393      * the default value if the attribute is not found.
394      */

395     public int getAttribute(String name, int defaultValue) {
396         CharSequence value = _attributes.getValue(name);
397         return (value != null) ? TypeFormat.parseInt(value) : defaultValue;
398     }
399
400     /**
401      * Returns the specified <code>long</code> attribute. This method handles
402      * string formats that are used to represent octal and hexadecimal numbers.
403      *
404      * @param name the name of the attribute searched for.
405      * @param defaultValue the value returned if the attribute is not found.
406      * @return the <code>long</code> value for the specified attribute or
407      * the default value if the attribute is not found.
408      */

409     public long getAttribute(String name, long defaultValue) {
410         CharSequence value = _attributes.getValue(name);
411         return (value != null) ? TypeFormat.parseLong(value) : defaultValue;
412     }
413
414     /**
415      * Returns the specified <code>float</code> attribute.
416      *
417      * @param name the name of the attribute searched for.
418      * @param defaultValue the value returned if the attribute is not found.
419      * @return the <code>float</code> value for the specified attribute or
420      * the default value if the attribute is not found.
421      /*@FLOATING_POINT@
422      public float getAttribute(String name, float defaultValue) {
423         CharSequence value = _attributes.getValue(name);
424      return (value != null) ? (float) TypeFormat.parseDouble(value)
425      : defaultValue;
426      }
427      /**/

428
429     /**
430      * Returns the specified <code>double</code> attribute.
431      *
432      * @param name the name of the attribute searched for.
433      * @param defaultValue the value returned if the attribute is not found.
434      * @return the <code>double</code> value for the specified attribute or
435      * the default value if the attribute is not found.
436      /*@FLOATING_POINT@
437     public double getAttribute(String name, double defaultValue) {
438         CharSequence value = _attributes.getValue(name);
439         return (value != null) ? TypeFormat.parseDouble(value) : defaultValue;
440     }
441      /**/

442      
443     /**
444      * Resets this XML element for reuse.
445      */

446     void reset() {
447         _object = null;
448         _format = null;
449         _objectClass = null;
450         _idValue = null;
451         _name = null;
452         _content.clear();
453         _nameToChild.clear();
454         _attributes.reset();
455         _poolIndex = 0;
456     }
457
458     /**
459      * Converts a String to a CharSequence (for J2ME compatibility)
460      *
461      * @param str the String to convert.
462      * @return the corresponding CharSequence instance.
463      */

464     private CharSequence toCharSeq(Object str) {
465         if (str instanceof CharSequence)
466             return (CharSequence) str;
467         TextBuilder tb = newTextBuilder();
468         tb.append(str);
469         return tb;
470     }
471
472     /**
473      * Returns a text builder instance from the internal pool.
474      */

475     private TextBuilder newTextBuilder() {
476         if (_poolIndex >= _pool.size()) {
477             _pool.addLast(TextBuilder.newInstance().moveHeap());
478         }
479         TextBuilder tb = (TextBuilder) _pool.get(_poolIndex++);
480         tb.reset();
481         return tb;
482     }
483
484     /**
485      * Indicates if the current object is already referenced in the
486      * element hierarchy (parents).
487      */

488     boolean isRecursion() {
489         for (XmlElement xml = _parent; xml != null; xml = xml._parent) {
490             if (xml._object == _object) return true;
491         }
492         return false;
493     }
494     
495     /**
496      * Returns the class for the specified tag name (as set by enclosing
497      * xml element format).
498      *
499      * @param tagName the name for which the class is searched for.
500      * @return the corresponding class.
501      */

502     final Class classFor(CharSequence tagName) {
503         return ((_parent != null) && (_parent._format != null)) ?
504             _parent._format.classFor(tagName) : null;
505     }
506 }
Popular Tags