KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javolution > xml > ConstructorHandler


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.util.List;
12 import j2me.lang.CharSequence;
13 import javolution.lang.Reusable;
14 import javolution.lang.Text;
15 import javolution.lang.TextBuilder;
16 import javolution.util.FastComparator;
17 import javolution.util.FastMap;
18 import javolution.util.FastTable;
19 import javolution.xml.sax.Attributes;
20 import javolution.xml.sax.AttributesImpl;
21 import javolution.xml.sax.ContentHandler;
22 import org.xml.sax.ErrorHandler;
23 import org.xml.sax.Locator;
24 import org.xml.sax.SAXException;
25 import org.xml.sax.SAXParseException;
26
27 /**
28  * <p> This class handles SAX2 events in order to build objects from
29  * their xml representation.</p>
30  *
31  * <p> For example, the following formats and parses an object without
32  * intermediate xml document:<pre>
33  * ConstructorHandler ch = new ConstructorHandler();
34  * ObjectWriter.write(obj, ch);
35  * assert(obj.equals(ch.getRoot()));
36  * </pre></p>
37  *
38  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
39  * @version 3.2, March 20, 2005
40  */

41 public final class ConstructorHandler implements ContentHandler, ErrorHandler,
42         Reusable {
43
44     /**
45      * Holds the current nesting level (0 is the document level)
46      */

47     private int _level;
48
49     /**
50      * Holds the root object.
51      */

52     private Object _root;
53
54     /**
55      * Holds the stack of XML elements.
56      */

57     private final FastTable _stack = new FastTable();
58
59     /**
60      * Holds the persistent id to object mapping.
61      */

62     private final FastMap _idToObject = new FastMap()
63             .setKeyComparator(FastComparator.LEXICAL);
64
65     /**
66      * Default constructor.
67      */

68     ConstructorHandler() {
69         _stack.addLast(new XmlElement());
70     }
71
72     /**
73      * Returns the root object.
74      *
75      * @return the object corresponding to the root xml element.
76      */

77     public Object getRoot() {
78         return _root;
79     }
80
81     /**
82      * Receives notification of the beginning of the document.
83      *
84      * @throws SAXException any SAX exception, possibly wrapping
85      * another exception.
86      */

87     public void startDocument() throws SAXException {
88         _level = 0;
89         _root = null;
90     }
91
92     /**
93      * Receives notification of the end of the document.
94      *
95      * @throws SAXException any SAX exception, possibly wrapping
96      * another exception.
97      */

98     public void endDocument() throws SAXException {
99         List roots = ((XmlElement) _stack.get(0)).getContent();
100         if (roots.size() > 0) {
101             _root = roots.get(0);
102         }
103         // Clean-up (e.g. if parsing failed)
104
for (int i = 0; i <= _level;) {
105             ((XmlElement) _stack.get(i++)).reset();
106         }
107     }
108
109     /**
110      * Receives notification of the start of an element.
111      *
112      * @param uri the namespace.
113      * @param localName the local name.
114      * @param qName the raw XML 1.0 name.
115      * @param attrs the attributes (instance of AttributesImpl).
116      * @throws SAXException any SAX exception, possibly wrapping
117      * another exception.
118      */

119     public void startElement(CharSequence uri, CharSequence localName,
120             CharSequence qName, Attributes attrs) throws SAXException {
121
122         if (++_level >= _stack.size()) {
123             XmlElement tmp = (XmlElement) XmlElement.FACTORY.newObject();
124             tmp._parent = (XmlElement) _stack.get(_level - 1);
125             _stack.addLast(tmp);
126         }
127         XmlElement xml = (XmlElement) _stack.get(_level);
128         xml._name = localName;
129
130         final AttributesImpl attributes = (AttributesImpl) attrs;
131         Class objectClass = xml.classFor(localName);
132         if (objectClass == null) {
133             // Searches if attribute "j:class" is specified.
134
int i = attributes.getIndex("j:class");
135             if (i >= 0) { // Class name from attribute.
136
objectClass = XmlFormat.classFor("", attributes.getValue(i));
137             } else { // Class name from element tag.
138
objectClass = XmlFormat.classFor(uri, localName);
139                 xml._name = null;
140             }
141         }
142         final XmlFormat xmlFormat = XmlFormat.getInstance(objectClass);
143         final int attLength = attributes.getLength();
144
145         // Checks for references.
146
if (xmlFormat._idRef != null) {
147             int j = attributes.getIndex(xmlFormat._idRef);
148             if (j >= 0) { // Holds id reference.
149
final CharSequence idValue = attributes.getValue(j);
150                 xml._object = _idToObject.get(idValue);
151                 if (xml._object != null)
152                     return; // Reference found.
153
if (!xmlFormat._idRef.equals(xmlFormat._idName))
154                     throw new SAXException("Referenced object (" + idValue
155                             + ") not found");
156                 // Use the same attribute for identifiers and references.
157
}
158         }
159
160         // Setup xml element.
161
xml._attributes = attributes;
162         if (xmlFormat._idName != null) {
163             xml._idValue = attributes.getValue(xmlFormat._idName);
164         }
165         xml._format = xmlFormat;
166         xml._objectClass = objectClass;
167         xml._object = xmlFormat.preallocate(xml);
168
169         // If preallocated and identifier, then maps id to object.
170
if ((xml._object != null) && (xml._idValue != null)) {
171             _idToObject.put(newId().append(xml._idValue), xml._object);
172         }
173     }
174
175     
176     /**
177      * Receives notification of the end of an element.
178      *
179      * @param uri the namespace.
180      * @param localName the local name.
181      * @param qName the raw XML 1.0 name.
182      * @throws SAXException any SAX exception, possibly wrapping
183      * another exception.
184      */

185     public void endElement(CharSequence uri, CharSequence localName,
186             CharSequence qName) throws SAXException {
187         XmlElement xml = ((XmlElement) _stack.get(_level));
188         if (xml._format != null) { // Not a reference.
189
xml._object = xml._format.parse(xml);
190             if (xml._idValue != null) {
191                 _idToObject.put(newId().append(xml._idValue), xml._object);
192             }
193         }
194
195         // Adds to parent.
196
if (xml._name == null) { // Anonymous.
197
((XmlElement) _stack.get(--_level))._content.addLast(xml._object);
198         } else { // Named child element.
199
((XmlElement) _stack.get(--_level)).add(xml._name, xml._object);
200         }
201
202         // Clears the xml element (for reuse latter).
203
xml.reset();
204     }
205
206     /**
207      * Receives notification of (non whitespace) character data.
208      *
209      * @param ch the characters from the XML document.
210      * @param start the start position in the array.
211      * @param length the number of characters to read from the array.
212      * @throws SAXException any SAX exception, possibly wrapping
213      * another exception.
214      */

215     public void characters(char ch[], int start, int length)
216             throws SAXException {
217         CharacterData charData = CharacterData.valueOf(Text.valueOf(ch, start,
218                 length));
219         ((XmlElement) _stack.get(_level))._content.addLast(charData);
220     }
221
222     // Implements ContentHandler
223
public void setDocumentLocator(Locator locator) {
224     }
225
226     // Implements ContentHandler
227
public void startPrefixMapping(CharSequence prefix, CharSequence uri)
228             throws SAXException {
229     }
230
231     // Implements ContentHandler
232
public void endPrefixMapping(CharSequence prefix) throws SAXException {
233     }
234
235     // Implements ContentHandler
236
public void ignorableWhitespace(char ch[], int start, int length)
237             throws SAXException {
238     }
239
240     // Implements ContentHandler
241
public void processingInstruction(CharSequence target, CharSequence data)
242             throws SAXException {
243     }
244
245     // Implements ContentHandler
246
public void skippedEntity(CharSequence name) throws SAXException {
247     }
248
249     /**
250      * Receives notification of a parser warning. The warning is printed to
251      * the error stream (System.err)
252      *
253      * @param e the warning information encoded as an exception.
254      * @throws SAXException any SAX exception, possibly wrapping
255      * another exception.
256      */

257     public void warning(SAXParseException e) throws SAXException {
258         System.err.println("XML Parsing Warning: " + e);
259     }
260
261     /**
262      * Receive notification of a recoverable parser error.
263      * This implementation throws a XmlException.
264      *
265      * @param e the error encoded as an exception.
266      * @throws SAXException any SAX exception, possibly wrapping
267      * another exception.
268      */

269     public void error(SAXParseException e) throws SAXException {
270         throw e;
271     }
272
273     /**
274      * Report a fatal XML parsing error.
275      *
276      * @param e the error information encoded as an exception.
277      * @throws SAXException any SAX exception, possibly wrapping
278      * another exception.
279      */

280     public void fatalError(SAXParseException e) throws SAXException {
281         throw e;
282     }
283
284     // Implements Reusable.
285
public void reset() {
286         // Recycles the ids.
287
_idPool.addAll(_idToObject.keySet());
288         _idToObject.clear();
289         _root = null;
290     }
291
292     /**
293      * Returns a persistent mutable character sequence from a local pool.
294      *
295      * @return a new or recycled text builder instance.
296      */

297     private TextBuilder newId() {
298         if (_idPool.isEmpty())
299             return (TextBuilder) TextBuilder.newInstance().moveHeap();
300         TextBuilder tb = (TextBuilder) _idPool.removeLast();
301         tb.reset();
302         return tb;
303     }
304
305     private FastTable _idPool = new FastTable(); // Persistent pool.
306
}
Popular Tags