KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > xml > XMLFormat


1 /*
2  * Javolution - Java(TM) Solution for Real-Time and Embedded Systems
3  * Copyright (C) 2006 - 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 java.util.Hashtable JavaDoc;
12 import j2me.lang.CharSequence;
13 import javolution.Javolution;
14 import javolution.text.CharArray;
15 import javolution.text.TextBuilder;
16 import javolution.text.TypeFormat;
17 import javolution.xml.sax.Attributes;
18 import javolution.xml.stream.XMLStreamException;
19 import javolution.xml.stream.XMLStreamReader;
20 import javolution.xml.stream.XMLStreamReaderImpl;
21 import javolution.xml.stream.XMLStreamWriter;
22 import javolution.xml.stream.XMLStreamWriterImpl;
23
24 /**
25  * <p> This class represents the format base class for XML serialization and
26  * deserialization.</p>
27  *
28  * <p> Application classes typically define a default XML format for their
29  * instances using static {@link XMLFormat} class members.
30  * Formats are inherited by sub-classes. For example:[code]
31  *
32  * public abstract class Graphic {
33  * private boolean _isVisible;
34  * private Paint _paint; // null if none.
35  * private Stroke _stroke; // null if none.
36  * private Transform _transform; // null if none.
37  *
38  * // XML format with positional associations (members identified by their position),
39  * // see XML package description for examples of name associations.
40  * private static final XMLFormat<Graphic> XML = new XMLFormat<Graphic>(Graphic.class) {
41  * public void write(Graphic g, OutputElement xml) {
42  * xml.setAttribute("isVisible", g._isVisible);
43  * xml.add(g._paint); // First.
44  * xml.add(g._stroke); // Second.
45  * xml.add(g._transform); // Third.
46  * }
47  * public void read(InputElement xml, Graphic g) {
48  * g._isVisible = xml.getAttribute("isVisible", true);
49  * g._paint = xml.getNext();
50  * g._stroke = xml.getNext();
51  * g._transform = xml.getNext();
52  * return g;
53  * }
54  * };
55  * }[/code]
56  *
57  * <p> Due to the sequential nature of XML serialization/deserialization,
58  * formatting/parsing of XML attributes should always be performed before
59  * formatting/parsing of the XML content.</p>
60  *
61  * <p> The mapping between classes and XML formats is defined by {@link
62  * XMLBinding} instances.
63  * Here is an example of serialization/deserialization:[code]
64  *
65  * // Creates a list holding diverse objects.
66  * List list = new ArrayList();
67  * list.add("John Doe");
68  * list.add(null);
69  * Map map = new FastMap();
70  * map.put("ONE", new Integer(1));
71  * map.put("TWO", new Integer(2));
72  * list.add(map);
73  *
74  * // Creates some aliases to use instead of class names.
75  * XMLBinding binding = new XMLBinding();
76  * binding.setAlias(FastMap.class, "Map");
77  * binding.setAlias(String.class, "String");
78  * binding.setAlias(Integer.class, "Integer");
79  *
80  * // Formats the list to XML .
81  * OutputStream out = new FileOutputStream("C:/list.xml");
82  * XMLObjectWriter writer = new XMLObjectWriter().setOutput(out).setBinding(binding);
83  * writer.write(list, "MyList", ArrayList.class);
84  * writer.close();[/code]
85  *
86  * Here is the output <code>list.xml</code> document produced:[code]
87  *
88  * <MyList>
89  * <String value="John Doe"/>
90  * <Null/>
91  * <Map>
92  * <Key class="String" value="ONE"/>
93  * <Value class="Integer" value="1"/>
94  * <Key class="String" value="TWO"/>
95  * <Value class="Integer" value="2"/>
96  * </Map>
97  * </MyList>[/code]
98  *
99  * The list can be read back with the following code:[code]
100  *
101  * // Reads back to a FastTable instance.
102  * InputStream in = new FileInputStream("C:/list.xml");
103  * XMLObjectReader reader = new XMLObjectReader().setInput(in).setBinding(binding);
104  * FastTable table = reader.read("MyList", FastTable.class);
105  * reader.close();[/code]
106  * </p>
107  *
108  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
109  * @version 4.0, September 4, 2006
110  */

111 public abstract class XMLFormat/*<T>*/{
112
113     /**
114      * Holds <code>null</code> representation.
115      */

116     private static final String JavaDoc NULL = "Null";
117
118     /**
119      * Holds the class instances.
120      */

121     static volatile XMLFormat[] _ClassInstances = new XMLFormat[64];
122
123     /**
124      * Holds the number of class instances.
125      */

126     static volatile int _ClassInstancesLength;
127
128     /**
129      * Holds the class associated to this format (static instances only).
130      */

131     final Class JavaDoc _class;
132
133     /**
134      * Creates an unmmapped format which can be used to define
135      * custom {@link XMLBinding}.
136      */

137     protected XMLFormat() {
138         _class = null;
139     }
140
141     /**
142      * Creates a default XML format for instances of the specified
143      * class/interface (should be statically allocated).
144      *
145      * @param cls the root class/interface for this XML format.
146      * @throws IllegalArgumentException if the specified class is already
147      * statically bounded to another format.
148      */

149     protected XMLFormat(Class JavaDoc/*<T>*/cls) {
150         if (cls == null)
151             throw new NullPointerException JavaDoc();
152         _class = cls;
153         synchronized (_ClassToFormat) {
154             // Check if statically bounded.
155
if (_ClassToFormat.containsKey(cls))
156                 throw new IllegalArgumentException JavaDoc(
157                         "Multiple static binding for class " + cls
158                         + " The XMLFormat(Class) constructor should be " +
159                                 "used solely for static instances.");
160             final int length = XMLFormat._ClassInstancesLength;
161             final XMLFormat[] formats = XMLFormat._ClassInstances;
162             if (length >= formats.length) { // Resizes (ImmortalMemory).
163
XMLFormat[] tmp = new XMLFormat[length * 2];
164                 System.arraycopy(formats, 0, tmp, 0, length);
165                 XMLFormat._ClassInstances = tmp;
166             }
167             XMLFormat._ClassInstances[XMLFormat._ClassInstancesLength++] = this;
168             _ClassToFormat.put(cls, this);
169         }
170     }
171
172     private static Hashtable JavaDoc _ClassToFormat = new Hashtable JavaDoc();
173
174     /**
175      * Returns the class/interface statically bound to this format or
176      * <code>null</code> if none.
177      *
178      * @return the class/interface bound to this format.
179      */

180     public final Class JavaDoc/*<T>*/getBoundClass() {
181         return _class;
182     }
183
184     /**
185      * Indicates if the object serialized through this format can be referenced
186      * to (default <code>true</code>). This method can be overriden to return
187      * <code>false</code> if serialized objects are manipulated "by value".
188      *
189      * @return <code>true</code> if serialized object may hold a reference;
190      * <code>false</code> otherwise.
191      * @see XMLReferenceResolver
192      */

193     public boolean isReferenceable() {
194         return true;
195     }
196
197     /**
198      * Allocates a new object of the specified class from the specified
199      * XML input element. By default, this method returns an object created
200      * using the public no-arg constructor of the specified class.
201      * XML formats may override this method in order to use private/multi-arg
202      * constructors.
203      *
204      * @param cls the class of the object to return.
205      * @param xml the XML input element.
206      * @return the object corresponding to the specified XML element.
207      */

208     public Object JavaDoc/*{T}*/newInstance(Class JavaDoc/*<T>*/cls, InputElement xml)
209             throws XMLStreamException {
210         try {
211             return cls.newInstance();
212         } catch (InstantiationException JavaDoc e) {
213             throw new XMLStreamException(e);
214         } catch (IllegalAccessException JavaDoc e) {
215             throw new XMLStreamException(e);
216         }
217     }
218
219     /**
220      * Formats an object into the specified XML output element.
221      *
222      * @param obj the object to format.
223      * @param xml the <code>XMLElement</code> destination.
224      */

225     public abstract void write(Object JavaDoc/*{T}*/obj, OutputElement xml)
226             throws XMLStreamException;
227
228     /**
229      * Parses an XML input element into the specified object.
230      *
231      * @param xml the XML element to parse.
232      * @param obj the object created through {@link #newInstance}
233      * and to setup from the specified XML element.
234      */

235     public abstract void read(InputElement xml, Object JavaDoc/*{T}*/obj)
236             throws XMLStreamException;
237
238     /**
239      * This class represents an input XML element (unmarshalling).
240      */

241     protected static final class InputElement {
242
243         /**
244          * Holds the stream reader.
245          */

246         final XMLStreamReaderImpl _reader = new XMLStreamReaderImpl();
247
248         /**
249          * Holds the XML binding.
250          */

251         private XMLBinding _binding;
252
253         /**
254          * Holds the reference resolver.
255          */

256         private XMLReferenceResolver _referenceResolver;
257
258         /**
259          * Indicates if the reader is currently positioned on the next element.
260          */

261         private boolean _isReaderAtNext;
262
263         /**
264          * Default constructor.
265          */

266         InputElement() {
267             reset();
268         }
269
270         /**
271          * Returns the StAX-like stream reader (provides complete control
272          * over the unmarshalling process).
273          *
274          * @return the stream reader.
275          */

276         public XMLStreamReader getStreamReader() {
277             return _reader;
278         }
279
280         /**
281          * Indicates if more nested XML element can be read. This method
282          * positions the {@link #getStreamReader reader} at the start of the
283          * next XML element to be read (if any).
284          *
285          * @return <code>true</code> if there is more XML element to be read;
286          * <code>false</code> otherwise.
287          */

288         public boolean hasNext() throws XMLStreamException {
289             if (!_isReaderAtNext) {
290                 _isReaderAtNext = true;
291                 _reader.nextTag();
292             }
293             return _reader.getEventType() == XMLStreamReader.START_ELEMENT;
294         }
295
296         /**
297          * Returns the next object whose type is identified by the local name
298          * and URI of the current XML element (see {@link XMLBinding}).
299          *
300          * @return the next nested object which can be <code>null</code>.
301          * @throws XMLStreamException if <code>hasNext() == false</code>.
302          */

303         public/*<T>*/Object JavaDoc/*{T}*/getNext() throws XMLStreamException {
304             if (!hasNext()) // Asserts isReaderAtNext == true
305
throw new XMLStreamException("No more element to read", _reader
306                         .getLocation());
307
308             // Checks for null.
309
if (_reader.getLocalName().equals(NULL)) {
310                 if (_reader.next() != XMLStreamReader.END_ELEMENT)
311                     throw new XMLStreamException("Non Empty Null Element");
312                 _isReaderAtNext = false;
313                 return null;
314             }
315
316             // Checks if reference.
317
if (_referenceResolver != null) {
318                 Object JavaDoc obj = _referenceResolver.readReference(this);
319                 if (obj != null) {
320                     if (_reader.next() != XMLStreamReader.END_ELEMENT)
321                         throw new XMLStreamException("Non Empty Reference Element");
322                     _isReaderAtNext = false;
323                     return (Object JavaDoc/*{T}*/) obj;
324                 }
325             }
326
327             // Retrieves object's class.
328
Class JavaDoc cls;
329             try {
330                 cls = _binding.getClass(_reader.getLocalName(), _reader
331                         .getNamespaceURI());
332             } catch (ClassNotFoundException JavaDoc e) {
333                 throw new XMLStreamException(e);
334             }
335
336             return (Object JavaDoc/*{T}*/) get(cls);
337         }
338
339         /**
340          * Returns the object whose type is identified by a XML class attribute
341          * only if the XML element has the specified local name.
342          *
343          * @param name the local name of the next element.
344          * @return the next nested object or <code>null</code>.
345          */

346         public/*<T>*/Object JavaDoc/*{T}*/get(String JavaDoc name) throws XMLStreamException {
347             if (!hasNext()// Asserts isReaderAtNext == true
348
|| !_reader.getLocalName().equals(name))
349                 return null;
350
351             // Checks if reference.
352
if (_referenceResolver != null) {
353                 Object JavaDoc obj = _referenceResolver.readReference(this);
354                 if (obj != null) {
355                     if (_reader.next() != XMLStreamReader.END_ELEMENT)
356                         throw new XMLStreamException("Non Empty Reference Element");
357                     _isReaderAtNext = false;
358                     return (Object JavaDoc/*{T}*/) obj;
359                 }
360             }
361
362             // Retrieves object's class from class attribute.
363
Class JavaDoc cls = _binding.readClassAttribute(_reader);
364
365             return (Object JavaDoc/*{T}*/) get(cls);
366         }
367
368         /**
369          * Returns the object whose type is identified by a XML class attribute
370          * only if the XML element has the specified local name and URI.
371          *
372          * @param localName the local name.
373          * @param uri the namespace URI or <code>null</code>.
374          * @return the next nested object or <code>null</code>.
375          */

376         public/*<T>*/Object JavaDoc/*{T}*/get(String JavaDoc localName, String JavaDoc uri)
377                 throws XMLStreamException {
378             if (uri == null)
379                 return (Object JavaDoc/*{T}*/) get(localName);
380
381             if (!hasNext()// Asserts isReaderAtNext == true
382
|| !_reader.getLocalName().equals(localName)
383                     || !_reader.getNamespaceURI().equals(uri))
384                 return null;
385
386             // Checks if reference.
387
if (_referenceResolver != null) {
388                 Object JavaDoc obj = _referenceResolver.readReference(this);
389                 if (obj != null) {
390                     if (_reader.next() != XMLStreamReader.END_ELEMENT)
391                         throw new XMLStreamException("Non Empty Reference Element");
392                     _isReaderAtNext = false;
393                     return (Object JavaDoc/*{T}*/) obj;
394                 }
395             }
396
397             // Retrieves object's class from class attribute.
398
Class JavaDoc cls = _binding.readClassAttribute(_reader);
399
400             return (Object JavaDoc/*{T}*/) get(cls);
401         }
402
403         /**
404          * Returns the object of specified type only if the XML element has the
405          * specified local name.
406          *
407          * @param name the local name of the element to match.
408          * @param cls the class identifying the format of the object to return.
409          * @return the next nested object or <code>null</code>.
410          */

411         public/*<T>*/Object JavaDoc/*{T}*/get(String JavaDoc name, Class JavaDoc/*<T>*/cls)
412                 throws XMLStreamException {
413             if (!hasNext()// Asserts isReaderAtNext == true
414
|| !_reader.getLocalName().equals(name))
415                 return null;
416
417             // Checks if reference.
418
if (_referenceResolver != null) {
419                 Object JavaDoc obj = _referenceResolver.readReference(this);
420                 if (obj != null) {
421                     if (_reader.next() != XMLStreamReader.END_ELEMENT)
422                         throw new XMLStreamException("Non Empty Reference Element");
423                     _isReaderAtNext = false;
424                     return (Object JavaDoc/*{T}*/) obj;
425                 }
426             }
427
428             return (Object JavaDoc/*{T}*/) get(cls);
429         }
430
431         /**
432          * Returns the object of specified type only if the
433          * XML element has the specified local name and namespace URI.
434          *
435          * @param localName the local name.
436          * @param uri the namespace URI or <code>null</code>.
437          * @param cls the class identifying the format of the object to return.
438          * @return the next nested object or <code>null</code>.
439          */

440         public/*<T>*/Object JavaDoc/*{T}*/get(String JavaDoc localName, String JavaDoc uri,
441                 Class JavaDoc/*<T>*/cls) throws XMLStreamException {
442             if (uri == null)
443                 return get(localName, cls);
444
445             if (!hasNext()// Asserts isReaderAtNext == true
446
|| !_reader.getLocalName().equals(localName)
447                     || !_reader.getNamespaceURI().equals(uri))
448                 return null;
449
450             // Checks if reference.
451
if (_referenceResolver != null) {
452                 Object JavaDoc obj = _referenceResolver.readReference(this);
453                 if (obj != null) {
454                     if (_reader.next() != XMLStreamReader.END_ELEMENT)
455                         throw new XMLStreamException("Non Empty Reference Element");
456                     _isReaderAtNext = false;
457                     return (Object JavaDoc/*{T}*/) obj;
458                 }
459             }
460
461             return (Object JavaDoc/*{T}*/) get(cls);
462         }
463
464         // Builds object of specified class.
465
private Object JavaDoc get(Class JavaDoc cls) throws XMLStreamException {
466
467             // Retrieves format.
468
XMLFormat xmlFormat = _binding.getFormat(cls);
469
470             // Creates object.
471
_isReaderAtNext = false; // Makes attributes accessible.
472
Object JavaDoc obj = xmlFormat.newInstance(cls, this);
473
474             // Adds reference (before reading to support circular reference).
475
if (_referenceResolver != null) {
476                 _referenceResolver.createReference(obj, this);
477             }
478
479             // Parses xml.
480
xmlFormat.read(this, obj);
481             if (hasNext()) // Asserts _isReaderAtNext == true
482
throw new XMLStreamException("Incomplete element reading",
483                         _reader.getLocation());
484             _isReaderAtNext = false; // Skips end element.
485
return obj;
486         }
487
488         /**
489          * Returns the content of a text-only element (equivalent to
490          * {@link javolution.xml.stream.XMLStreamReader#getElementText
491          * getStreamReader().getElementText()}).
492          *
493          * @return the element text content or an empty sequence if none.
494          */

495         public CharArray getText() throws XMLStreamException {
496             CharArray txt = _reader.getElementText();
497             _isReaderAtNext = true; // End element is next.
498
return txt;
499         }
500
501         /**
502          * Returns the attributes for this XML input element.
503          *
504          * @return the attributes mapping.
505          */

506         public Attributes getAttributes() throws XMLStreamException {
507             if (_isReaderAtNext)
508                 throw new XMLStreamException(
509                         "Attributes should be read before content");
510             return _reader.getAttributes();
511         }
512
513         /**
514          * Searches for the attribute having the specified name.
515          *
516          * @param name the name of the attribute.
517          * @return the value for the specified attribute or <code>null</code>
518          * if the attribute is not found.
519          */

520         public CharArray getAttribute(String JavaDoc name) throws XMLStreamException {
521             if (_isReaderAtNext)
522                 throw new XMLStreamException(
523                         "Attributes should be read before reading content");
524             return _reader.getAttributeValue(null, toCsq(name));
525         }
526
527         /**
528          * Returns the specified <code>String</code> attribute.
529          *
530          * @param name the name of the attribute.
531          * @param defaultValue a default value.
532          * @return the value for the specified attribute or
533          * the <code>defaultValue</code> if the attribute is not found.
534          */

535         public String JavaDoc getAttribute(String JavaDoc name, String JavaDoc defaultValue)
536                 throws XMLStreamException {
537             CharArray value = getAttribute(name);
538             return (value != null) ? value.toString() : defaultValue;
539         }
540
541         /**
542          * Returns the specified <code>boolean</code> attribute.
543          *
544          * @param name the name of the attribute searched for.
545          * @param defaultValue the value returned if the attribute is not found.
546          * @return the <code>boolean</code> value for the specified attribute or
547          * the default value if the attribute is not found.
548          */

549         public boolean getAttribute(String JavaDoc name, boolean defaultValue)
550                 throws XMLStreamException {
551             CharArray value = getAttribute(name);
552             return (value != null) ? value.toBoolean() : defaultValue;
553         }
554
555         /**
556          * Returns the specified <code>int</code> attribute. This method handles
557          * string formats that are used to represent octal and hexadecimal numbers.
558          *
559          * @param name the name of the attribute searched for.
560          * @param defaultValue the value returned if the attribute is not found.
561          * @return the <code>int</code> value for the specified attribute or
562          * the default value if the attribute is not found.
563          */

564         public int getAttribute(String JavaDoc name, int defaultValue)
565                 throws XMLStreamException {
566             CharArray value = getAttribute(name);
567             return (value != null) ? value.toInt() : defaultValue;
568         }
569
570         /**
571          * Returns the specified <code>long</code> attribute. This method handles
572          * string formats that are used to represent octal and hexadecimal numbers.
573          *
574          * @param name the name of the attribute searched for.
575          * @param defaultValue the value returned if the attribute is not found.
576          * @return the <code>long</code> value for the specified attribute or
577          * the default value if the attribute is not found.
578          */

579         public long getAttribute(String JavaDoc name, long defaultValue)
580                 throws XMLStreamException {
581             CharArray value = getAttribute(name);
582             return (value != null) ? value.toLong() : defaultValue;
583         }
584
585         /**
586          * Returns the specified <code>float</code> attribute.
587          *
588          * @param name the name of the attribute searched for.
589          * @param defaultValue the value returned if the attribute is not found.
590          * @return the <code>float</code> value for the specified attribute or
591          * the default value if the attribute is not found.
592          /*@JVM-1.1+@
593          public float getAttribute(String name, float defaultValue) throws XMLStreamException {
594          CharArray value = getAttribute(name);
595          return (value != null) ? value.toFloat() : defaultValue;
596          }
597          /**/

598
599         /**
600          * Returns the specified <code>double</code> attribute.
601          *
602          * @param name the name of the attribute searched for.
603          * @param defaultValue the value returned if the attribute is not found.
604          * @return the <code>double</code> value for the specified attribute or
605          * the default value if the attribute is not found.
606          /*@JVM-1.1+@
607          public double getAttribute(String name, double defaultValue) throws XMLStreamException {
608          CharArray value = getAttribute(name);
609          return (value != null) ? value.toDouble() : defaultValue;
610          }
611          /**/

612
613         ////////////////////////
614
// Primitive Wrappers //
615
////////////////////////
616
/**
617          * Searches for the specified <code>Boolean</code> attribute.
618          *
619          * @param name the name of the attribute.
620          * @param defaultValue the value returned if the attribute is not found.
621          * @return the <code>Boolean</code> value for the specified attribute or
622          * the default value if the attribute is not found.
623          */

624         public Boolean JavaDoc getAttribute(String JavaDoc name, Boolean JavaDoc defaultValue)
625                 throws XMLStreamException {
626             CharArray value = getAttribute(name);
627             return (value != null) ? value.toBoolean() ? TRUE : FALSE
628                     : defaultValue;
629         }
630
631         private static final Boolean JavaDoc TRUE = new Boolean JavaDoc(true);
632
633         private static final Boolean JavaDoc FALSE = new Boolean JavaDoc(false);
634
635         /**
636          * Searches for the specified <code>Byte</code> attribute.
637          *
638          * @param name the name of the attribute.
639          * @param defaultValue the value returned if the attribute is not found.
640          * @return the <code>Byte</code> value for the specified attribute or
641          * the default value if the attribute is not found.
642          */

643         public Byte JavaDoc getAttribute(String JavaDoc name, Byte JavaDoc defaultValue)
644                 throws XMLStreamException {
645             CharArray value = getAttribute(name);
646             return (value != null) ? new Byte JavaDoc(TypeFormat.parseByte(value))
647                     : defaultValue;
648         }
649
650         /**
651          * Searches for the specified <code>Short</code> attribute.
652          *
653          * @param name the name of the attribute.
654          * @param defaultValue the value returned if the attribute is not found.
655          * @return the <code>Short</code> value for the specified attribute or
656          * the default value if the attribute is not found.
657          */

658         public Short JavaDoc getAttribute(String JavaDoc name, Short JavaDoc defaultValue)
659                 throws XMLStreamException {
660             CharArray value = getAttribute(name);
661             return (value != null) ? new Short JavaDoc(TypeFormat.parseShort(value))
662                     : defaultValue;
663         }
664
665         /**
666          * Searches for the specified <code>Integer</code> attribute.
667          *
668          * @param name the name of the attribute.
669          * @param defaultValue the value returned if the attribute is not found.
670          * @return the <code>Integer</code> value for the specified attribute or
671          * the default value if the attribute is not found.
672          */

673         public Integer JavaDoc getAttribute(String JavaDoc name, Integer JavaDoc defaultValue)
674                 throws XMLStreamException {
675             CharArray value = getAttribute(name);
676             return (value != null) ? new Integer JavaDoc(value.toInt()) : defaultValue;
677         }
678
679         /**
680          * Searches for the specified <code>Long</code> attribute.
681          *
682          * @param name the name of the attribute.
683          * @param defaultValue the value returned if the attribute is not found.
684          * @return the <code>Long</code> value for the specified attribute or
685          * the default value if the attribute is not found.
686          */

687         public Long JavaDoc getAttribute(String JavaDoc name, Long JavaDoc defaultValue)
688                 throws XMLStreamException {
689             CharArray value = getAttribute(name);
690             return (value != null) ? new Long JavaDoc(value.toLong()) : defaultValue;
691         }
692
693         /**
694          * Searches for the specified <code>Float</code> attribute.
695          *
696          * @param name the name of the attribute.
697          * @param defaultValue the value returned if the attribute is not found.
698          * @return the <code>Float</code> value for the specified attribute or
699          * the default value if the attribute is not found.
700          /*@JVM-1.1+@
701          public Float getAttribute(String name, Float defaultValue) throws XMLStreamException {
702          CharArray value = getAttribute(name);
703          return (value != null) ? new Float(value.toFloat()) : defaultValue;
704          }
705          /**/

706
707         /**
708          * Searches for the specified <code>Double</code> attribute.
709          *
710          * @param name the name of the attribute.
711          * @param defaultValue the value returned if the attribute is not found.
712          * @return the <code>Double</code> value for the specified attribute or
713          * the default value if the attribute is not found.
714          /*@JVM-1.1+@
715          public Double getAttribute(String name, Double defaultValue) throws XMLStreamException {
716          CharArray value = getAttribute(name);
717          return (value != null) ? new Double(value.toDouble()) : defaultValue;
718          }
719          /**/

720
721         // Sets XML binding.
722
void setBinding(XMLBinding xmlBinding) {
723             _binding = xmlBinding;
724         }
725
726         // Sets XML reference resolver.
727
void setReferenceResolver(XMLReferenceResolver xmlReferenceResolver) {
728             _referenceResolver = xmlReferenceResolver;
729         }
730
731         // Resets for reuse.
732
void reset() {
733             _binding = XMLBinding.DEFAULT;
734             _isReaderAtNext = false;
735             _reader.reset();
736             _referenceResolver = null;
737         }
738     }
739
740     /**
741      * This class represents an output XML element (marshalling).
742      */

743     protected static class OutputElement {
744
745         /**
746          * Holds the stream writer.
747          */

748         final XMLStreamWriterImpl _writer = new XMLStreamWriterImpl();
749
750         /**
751          * Holds the XML binding.
752          */

753         private XMLBinding _binding;
754
755         /**
756          * Holds the reference resolver.
757          */

758         private XMLReferenceResolver _referenceResolver;
759
760         /**
761          * Default constructor.
762          */

763         OutputElement() {
764             reset();
765         }
766
767         /**
768          * Returns the StAX-like stream writer (provides complete control over
769          * the marshalling process).
770          *
771          * @return the stream writer.
772          */

773         public XMLStreamWriter getStreamWriter() {
774             return _writer;
775         }
776
777         /**
778          * Adds the specified object or <code>null</code> as an anonymous
779          * nested element of unknown type.
780          *
781          * @param obj the object added as nested element or <code>null</code>.
782          */

783         public void add(Object JavaDoc obj) throws XMLStreamException {
784             if (obj == null) {
785                 _writer.writeEmptyElement(toCsq(NULL));
786                 return;
787             }
788
789             // Writes start element.
790
Class JavaDoc cls = obj.getClass();
791             String JavaDoc localName = _binding.getLocalName(cls);
792             String JavaDoc uri = _binding.getURI(cls);
793             if (uri == null) {
794                 _writer.writeStartElement(toCsq(localName));
795             } else {
796                 _writer.writeStartElement(toCsq(uri),
797                         toCsq(localName));
798             }
799
800             // Check if reference to be written.
801
XMLFormat xmlFormat = _binding.getFormat(cls);
802             if ((_referenceResolver != null) && xmlFormat.isReferenceable()
803                     && _referenceResolver.writeReference(obj, this)) {
804                 _writer.writeEndElement();
805                 return; // Reference written.
806
}
807
808             xmlFormat.write(obj, this);
809             _writer.writeEndElement();
810         }
811
812         /**
813          * Adds the specified object as a named nested element of unknown type
814          * (<code>null</code> objects are ignored).
815          * The nested XML element contains a class attribute identifying
816          * the object type.
817          *
818          * @param obj the object added as nested element or <code>null</code>.
819          * @param name the name of the nested element.
820          */

821         public void add(Object JavaDoc obj, String JavaDoc name) throws XMLStreamException {
822             if (obj == null)
823                 return;
824
825             // Writes start element.
826
_writer.writeStartElement(toCsq(name));
827
828             // Writes class attribute.
829
Class JavaDoc cls = obj.getClass();
830             _binding.writeClassAttribute(_writer, cls);
831
832             // Check if reference is to be written.
833
XMLFormat xmlFormat = _binding.getFormat(cls);
834             if ((_referenceResolver != null) && xmlFormat.isReferenceable()
835                     && _referenceResolver.writeReference(obj, this)) {
836                 _writer.writeEndElement();
837                 return; // Reference written.
838
}
839
840             xmlFormat.write(obj, this);
841             _writer.writeEndElement();
842         }
843
844         /**
845          * Adds the specified object as a fully qualified nested element of
846          * unknown type (<code>null</code> objects are ignored).
847          * The nested XML element contains a class attribute identifying
848          * the object type.
849          *
850          * @param obj the object added as nested element or <code>null</code>.
851          * @param localName the local name of the nested element.
852          * @param uri the namespace URI of the nested element.
853          */

854         public void add(Object JavaDoc obj, String JavaDoc localName, String JavaDoc uri)
855                 throws XMLStreamException {
856             if (obj == null)
857                 return;
858
859             // Writes start element.
860
_writer.writeStartElement(toCsq(uri), toCsq(localName));
861
862             // Writes class attribute.
863
Class JavaDoc cls = obj.getClass();
864             _binding.writeClassAttribute(_writer, cls);
865
866             // Check if reference is to be written.
867
XMLFormat xmlFormat = _binding.getFormat(cls);
868             if ((_referenceResolver != null) && xmlFormat.isReferenceable()
869                     && _referenceResolver.writeReference(obj, this)) {
870                 _writer.writeEndElement();
871                 return; // Reference written.
872
}
873
874             xmlFormat.write(obj, this);
875             _writer.writeEndElement();
876         }
877
878         /**
879          * Adds the specified object as a named nested element of specified
880          * actual type (<code>null</code> objects are ignored).
881          * The nested XML element does not contain any class attribute.
882          *
883          * @param obj the object added as nested element or <code>null</code>.
884          * @param name the name of the nested element.
885          * @param cls the class identifying the format of the specified object.
886          */

887         public/*<T>*/void add(Object JavaDoc/*{T}*/ obj, String JavaDoc name, Class JavaDoc/*<T>*/ cls)
888                 throws XMLStreamException {
889             if (obj == null)
890                 return;
891
892             // Writes start element.
893
_writer.writeStartElement(toCsq(name));
894
895             // Check if reference is to be written.
896
XMLFormat xmlFormat = _binding.getFormat(cls);
897             if ((_referenceResolver != null) && xmlFormat.isReferenceable()
898                     && _referenceResolver.writeReference(obj, this)) {
899                 _writer.writeEndElement();
900                 return; // Reference written.
901
}
902
903             xmlFormat.write(obj, this);
904             _writer.writeEndElement();
905         }
906
907         /**
908          * Adds the specified object as a fully qualified nested element of
909          * specified actual type (<code>null</code> objects are ignored).
910          * The nested XML element does not contain any class attribute.
911          *
912          * @param obj the object added as nested element or <code>null</code>.
913          * @param localName the local name of the nested element.
914          * @param uri the namespace URI of the nested element.
915          * @param cls the class identifying the format of the specified object.
916          */

917         public/*<T>*/void add(Object JavaDoc/*{T}*/obj, String JavaDoc localName, String JavaDoc uri,
918                 Class JavaDoc/*<T>*/cls) throws XMLStreamException {
919             if (obj == null)
920                 return;
921
922             // Writes start element.
923
_writer.writeStartElement(toCsq(uri), toCsq(localName));
924
925             // Check if reference is to be written.
926
XMLFormat xmlFormat = _binding.getFormat(cls);
927             if ((_referenceResolver != null) && xmlFormat.isReferenceable()
928                     && _referenceResolver.writeReference(obj, this)) {
929                 _writer.writeEndElement();
930                 return; // Reference written.
931
}
932
933             xmlFormat.write(obj, this);
934             _writer.writeEndElement();
935         }
936
937         /**
938          * Adds the content of a text-only element (equivalent to {@link
939          * javolution.xml.stream.XMLStreamWriter#writeCharacters(CharSequence)
940          * getStreamWriter().writeCharacters(text)}).
941          *
942          * @param text the element text content or an empty sequence if none.
943          */

944         public void addText(CharSequence JavaDoc text) throws XMLStreamException {
945             _writer.writeCharacters(text);
946         }
947         
948         /**
949          * Equivalent to {@link #addText(CharSequence)}
950          * (for J2ME compatibility).
951          *
952          * @param text the element text content or an empty sequence if none.
953          */

954         public void addText(String JavaDoc text) throws XMLStreamException {
955             _writer.writeCharacters(toCsq(text));
956         }
957
958         /**
959          * Sets the specified <code>CharSequence</code> attribute
960          * (<code>null</code> values are ignored).
961          *
962          * @param name the attribute name.
963          * @param value the attribute value or <code>null</code>.
964          */

965         public void setAttribute(String JavaDoc name, CharSequence JavaDoc value)
966                 throws XMLStreamException {
967             if (value == null)
968                 return;
969             _writer.writeAttribute(toCsq(name), value);
970         }
971
972         /**
973          * Sets the specified <code>String</code> attribute
974          * (<code>null</code> values are ignored).
975          *
976          * @param name the attribute name.
977          * @param value the attribute value.
978          */

979         public void setAttribute(String JavaDoc name, String JavaDoc value)
980                 throws XMLStreamException {
981             if (value == null)
982                 return;
983             _writer.writeAttribute(toCsq(name),
984                     toCsq(value));
985         }
986
987         /**
988          * Sets the specified <code>boolean</code> attribute.
989          *
990          * @param name the attribute name.
991          * @param value the <code>boolean</code> value for the specified attribute.
992          */

993         public void setAttribute(String JavaDoc name, boolean value)
994                 throws XMLStreamException {
995             setAttribute(name, _tmpTextBuilder.clear().append(value));
996         }
997
998         private TextBuilder _tmpTextBuilder = new TextBuilder();
999
1000        /**
1001         * Sets the specified <code>int</code> attribute.
1002         *
1003         * @param name the attribute name.
1004         * @param value the <code>int</code> value for the specified attribute.
1005         */

1006        public void setAttribute(String JavaDoc name, int value)
1007                throws XMLStreamException {
1008            setAttribute(name, _tmpTextBuilder.clear().append(value));
1009        }
1010
1011        /**
1012         * Sets the specified <code>long</code> attribute.
1013         *
1014         * @param name the attribute name.
1015         * @param value the <code>long</code> value for the specified attribute.
1016         */

1017        public void setAttribute(String JavaDoc name, long value)
1018                throws XMLStreamException {
1019            setAttribute(name, _tmpTextBuilder.clear().append(value));
1020        }
1021
1022        /**
1023         * Sets the specified <code>float</code> attribute.
1024         *
1025         * @param name the attribute name.
1026         * @param value the <code>float</code> value for the specified attribute.
1027         /*@JVM-1.1+@
1028         public void setAttribute(String name, float value) throws XMLStreamException {
1029         setAttribute(name, _tmpTextBuilder.clear().append(value));
1030         }
1031         /**/

1032
1033        /**
1034         * Sets the specified <code>double</code> attribute.
1035         *
1036         * @param name the attribute name.
1037         * @param value the <code>double</code> value for the specified attribute.
1038         /*@JVM-1.1+@
1039         public void setAttribute(String name, double value) throws XMLStreamException {
1040         setAttribute(name, _tmpTextBuilder.clear().append(value));
1041         }
1042         /**/

1043
1044        ////////////////////////
1045
// Primitive Wrappers //
1046
////////////////////////
1047
/**
1048         * Sets the specified <code>Boolean</code> attribute.
1049         *
1050         * @param name the name of the attribute.
1051         * @param value the <code>Boolean</code> value for the specified attribute
1052         * or <code>null</code> in which case the attribute is not set.
1053         */

1054        public void setAttribute(String JavaDoc name, Boolean JavaDoc value)
1055                throws XMLStreamException {
1056            if (value == null)
1057                return;
1058            setAttribute(name, value.booleanValue());
1059        }
1060
1061        /**
1062         * Sets the specified <code>Byte</code> attribute.
1063         *
1064         * @param name the name of the attribute.
1065         * @param value the <code>Byte</code> value for the specified attribute
1066         * or <code>null</code> in which case the attribute is not set.
1067         */

1068        public void setAttribute(String JavaDoc name, Byte JavaDoc value)
1069                throws XMLStreamException {
1070            if (value == null)
1071                return;
1072            setAttribute(name, value.byteValue());
1073        }
1074
1075        /**
1076         * Sets the specified <code>Short</code> attribute.
1077         *
1078         * @param name the name of the attribute.
1079         * @param value the <code>Short</code> value for the specified attribute
1080         * or <code>null</code> in which case the attribute is not set.
1081         */

1082        public void setAttribute(String JavaDoc name, Short JavaDoc value)
1083                throws XMLStreamException {
1084            if (value == null)
1085                return;
1086            setAttribute(name, value.shortValue());
1087        }
1088
1089        /**
1090         * Sets the specified <code>Integer</code> attribute.
1091         *
1092         * @param name the name of the attribute.
1093         * @param value the <code>Integer</code> value for the specified attribute
1094         * or <code>null</code> in which case the attribute is not set.
1095         */

1096        public void setAttribute(String JavaDoc name, Integer JavaDoc value)
1097                throws XMLStreamException {
1098            if (value == null)
1099                return;
1100            setAttribute(name, value.intValue());
1101        }
1102
1103        /**
1104         * Sets the specified <code>Long</code> attribute.
1105         *
1106         * @param name the name of the attribute.
1107         * @param value the <code>Long</code> value for the specified attribute
1108         * or <code>null</code> in which case the attribute is not set.
1109         */

1110        public void setAttribute(String JavaDoc name, Long JavaDoc value)
1111                throws XMLStreamException {
1112            if (value == null)
1113                return;
1114            setAttribute(name, value.longValue());
1115        }
1116
1117        /**
1118         * Sets the specified <code>Float</code> attribute.
1119         *
1120         * @param name the name of the attribute.
1121         * @param value the <code>Float</code> value for the specified attribute
1122         * or <code>null</code> in which case the attribute is not set.
1123         /*@JVM-1.1+@
1124         public void setAttribute(String name, Float value) throws XMLStreamException {
1125         if (value == null)
1126         return;
1127         setAttribute(name, value.floatValue());
1128         }
1129         /**/

1130
1131        /**
1132         * Sets the specified <code>Double</code> attribute.
1133         *
1134         * @param name the name of the attribute.
1135         * @param value the <code>Double</code> value for the specified attribute
1136         * or <code>null</code> in which case the attribute is not set.
1137         /*@JVM-1.1+@
1138         public void setAttribute(String name, Double value) throws XMLStreamException {
1139         if (value == null)
1140         return;
1141         }
1142         /**/

1143
1144        // Sets XML binding.
1145
void setBinding(XMLBinding xmlBinding) {
1146            _binding = xmlBinding;
1147        }
1148
1149        // Sets XML reference resolver.
1150
void setReferenceResolver(XMLReferenceResolver xmlReferenceResolver) {
1151            _referenceResolver = xmlReferenceResolver;
1152        }
1153
1154        // Resets for reuse.
1155
void reset() {
1156            _binding = XMLBinding.DEFAULT;
1157            _writer.reset();
1158            _writer.setRepairingNamespaces(true);
1159            _writer.setAutomaticEmptyElements(true);
1160            _referenceResolver = null;
1161        }
1162
1163    }
1164    
1165    private static CharSequence JavaDoc toCsq/**/(Object JavaDoc str) {
1166        return Javolution.j2meToCharSeq(str);
1167    }
1168
1169}
Popular Tags