Source code: org/apache/commons/jocl/JOCLContentHandler.java
1 /*
2 * Copyright 1999-2004 The Apache Software Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package org.apache.commons.jocl;
18
19 import org.xml.sax.*;
20 import org.xml.sax.helpers.*;
21 import java.util.ArrayList;
22 import java.lang.reflect.InvocationTargetException;
23 import java.io.InputStream;
24 import java.io.Reader;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileNotFoundException;
28 import java.io.IOException;
29
30 // to do:
31 // + add support for arrays
32 // + add support for strings as CDATA (makes multiline strings easier, for example)
33 // ? some kind of support for invoking methods?
34
35 /**
36 * A {@link org.xml.sax.ContentHandler}
37 * for the Java Object Configuration Language.
38 * <p>
39 * JOCL provides an XML syntax for constructing arbitrary Java
40 * {@link java.lang.Object} instances. It does not define a full
41 * XML document type (there's no root element), but rather an
42 * XML fragment describing the {@link java.lang.Object <tt>Object</tt>s} to be
43 * constructed.
44 * <p>
45 * In a JOCL fragment, one may define a series of objects using
46 * the <tt>object</tt> element. A trivial example is:
47 * <pre> <object class="java.util.Date"/></pre>
48 * which constructs an instance of <tt>java.util.Date</tt>
49 * using the no-argument constructor.
50 * <p>
51 * After a "root-level" <tt><object></tt> element has been processed
52 * (that is, once {@link #endElement(java.lang.String,java.lang.String,java.lang.String)}
53 * has been invoked by the {@link XMLReader}), it will be appended to a list of <tt>Object</tt>s
54 * maintained by the <tt>JOCLContentHandler</tt>.
55 * <p>
56 * (See {@link #size},
57 * {@link #clear},
58 * {@link #clear(int)},
59 * {@link #getType(int)},
60 * {@link #getValue(int)},
61 * {@link #getTypeArray},
62 * and
63 * {@link #getValueArray}.)
64 * <p>
65 * You can list multiple <tt>object</tt> elements in a fragment. For example,
66 * after processing the JOCL fragment:
67 * <pre> <object class="java.util.Date"/>
68 * <object class="java.util.Date"/></pre>
69 * The {@link #getTypeArray} method
70 * will return an composed
71 * of two instances of <tt>java.util.Date</tt>. The sequence of
72 * {@link java.lang.Object <tt>Object</tt>s} in the array
73 * will correspond to the sequence of <tt><object></tt> elements in the JOCL fragment.
74 * <p>
75 * As we've seen, when used with no child-elements, the <tt><object></tt>
76 * tag will cause the no-argument constructor of the specified class to be invoked.
77 * It is also possible to nest <tt><object></tt> tags to provide arguments
78 * for the constructor.
79 * For example, the fragment:
80 * <pre> <object class="mypackage.Foo">
81 * <object class="mypackage.Bar"/>
82 * </object></pre>
83 * will add an instance of <tt>mypackage.Foo</tt> to the object list, constructed via
84 * <tt>new mypackage.Foo(new mypackage.Bar())</tt>.
85 * <p>
86 * There is a special syntax available creating primative values and arguments,
87 * as well as for constructing {@link java.lang.String <tt>String</tt>}s. Some examples:
88 * <p>
89 * <pre> <byte value="3"/>
90 * <boolean value="false"/>
91 * <char value="c"/>
92 * <double value="3.14159"/>
93 * <float value="3.14"/>
94 * <int value="17"/>
95 * <long value="1700000"/>
96 * <short value="1"/>
97 * <string value="The quick brown fox..."/></pre>
98 * <p>
99 * When invoked at the "root" level (that is, with no <tt><object></tt> parent),
100 * this will cause the corresponding "object wrapper" to be added to the list of
101 * {@link java.lang.Object <tt>Object</tt>}s. The {@link #getType type} for these
102 * objects will reflect the proper primative type, however. When invoked with an
103 * <tt><object></tt> parent, these will be treated as primitive arguments to the
104 * specified {@link java.lang.Object <tt>Object</tt>}'s constructor. For example, while:
105 * <p>
106 * <pre> <int value="5"/>
107 * <int value="26"/>
108 * <int value="100"/></pre>
109 * <p>
110 * results in three {@link java.lang.Integer} instances being added to the
111 * list of values, with types corresponding to {@link java.lang.Integer}, the fragment:
112 * <p>
113 * <pre> <int value="5"/>
114 * <int value="26"/>
115 * <int value="100"/></pre>
116 * <p>
117 * results in three {@link java.lang.Integer} instances being added to the
118 * list of values, with types corresponding to {@link java.lang.Integer#TYPE}.
119 * <p>
120 * Hence if you want to invoke the <tt>mypackage.Foo(java.lang.Integer,java.lang.Integer,java.lang.Integer)</tt>
121 * constructor, use:
122 * <pre> <object class="mypackage.Foo"/>
123 * <object class="java.lang.Integer"><int value="5"/></object>
124 * <object class="java.lang.Integer"><int value="26"/></object>
125 * <object class="java.lang.Integer"><int value="100"/></object>
126 * </object></pre>
127 * <p>
128 * If you want to invoke the <tt>mypackage.Foo(int,int,int)</tt>
129 * constructor, use:
130 * <pre> <object class="mypackage.Foo"/>
131 * <int value="5"/>
132 * <int value="26"/>
133 * <int value="100"/>
134 * </object></pre>
135 * <p>
136 * If you'd like to creat a <tt>null</tt> object, use:
137 * <pre> <object class="mypackage.Bar" null="true"/></pre>
138 * <p>
139 * Here's a simple but complete example:
140 * <pre> <?xml version="1.0"?>
141 * <arbitrary-root xmlns="http://apache.org/xml/xmlns/jakarta/commons/jocl">
142 * <string value="Hello World!"/>
143 * <string/>
144 * <boolean/>
145 * <boolean value="true"/>
146 * <byte value="1"/>
147 * <short value="1"/>
148 * <int value="1"/>
149 * <long value="1"/>
150 * <float value="1.0"/>
151 * <double value="1.0"/>
152 * <object class="java.util.Date"/>
153 * <object class="java.util.Date">
154 * <int value="1"/>
155 * <int value="1"/>
156 * <int value="1"/>
157 * </object>
158 * </arbitrary-root></pre>
159 * <p>
160 * Formally, a DTD for the JOCL grammar is as follows:
161 * <p>
162 * <pre>
163 * <!ELEMENT object (object|byte|boolean|char|double|float|int|long|short|string)*>
164 * <!ATTLIST object
165 * class CDATA #REQUIRED
166 * null (true|false) "false">
167 *
168 * <!ELEMENT byte EMPTY>
169 * <!ATTLIST byte value CDATA #REQUIRED>
170 *
171 * <!ELEMENT boolean EMPTY>
172 * <!ATTLIST boolean value (true|false) #REQUIRED>
173 *
174 * <!ELEMENT char EMPTY>
175 * <!ATTLIST char value CDATA #REQUIRED>
176 *
177 * <!ELEMENT double EMPTY>
178 * <!ATTLIST double value CDATA #REQUIRED>
179 *
180 * <!ELEMENT float EMPTY>
181 * <!ATTLIST float value CDATA #REQUIRED>
182 *
183 * <!ELEMENT int EMPTY>
184 * <!ATTLIST int value CDATA #REQUIRED>
185 *
186 * <!ELEMENT long EMPTY>
187 * <!ATTLIST long value CDATA #REQUIRED>
188 *
189 * <!ELEMENT short EMPTY>
190 * <!ATTLIST short value CDATA #REQUIRED>
191 *
192 * <!ELEMENT string EMPTY>
193 * <!ATTLIST string value CDATA #REQUIRED>
194 * </pre>
195 * <p>
196 * This class can also be used as a base class for {@link org.xml.sax.ContentHandler}s
197 * that include JOCL as part of their grammar. Simply extend this class, and override the
198 * {@link #startElement},
199 * {@link #characters},
200 * and {@link #endElement} methods to handle
201 * your tags, and invoke the method of the parent class (i.e., <tt>super.<i>XXX</i></tt> for
202 * elements and data that you don't handle.
203 * <p>
204 * A number of static methods are available for simply reading a list of objects from
205 * a {@link InputStream}, {@link Reader} or {@link InputSource}.
206 * <p>
207 * <b>Note that this class is not synchronized.</b>
208 * <p>
209 * @author Rodney Waldhoff
210 * @version $Revision: 1.6 $ $Date: 2004/02/28 21:37:42 $
211 */
212 public class JOCLContentHandler extends DefaultHandler implements ContentHandler {
213
214 //--- Static Methods ---------------------------------------------
215 /**
216 * A simple tester method. Reads a JOCL document from standard in
217 * and prints a list of the objects created to standard out.
218 * (Use the <tt>org.xml.sax.driver</tt> system property to specify
219 * an {@link XMLReader}.
220 */
221 public static void main(String[] args) throws Exception {
222 JOCLContentHandler jocl = JOCLContentHandler.parse(System.in,null);
223 for(int i=0;i<jocl.size();i++) {
224 System.out.println("<" + jocl.getType(i) + ">\t" + jocl.getValue(i));
225 }
226 }
227
228 /**
229 * Parses a JOCL document from the specified file, using the
230 * {@link XMLReader} specified by the <tt>org.xml.sax.driver</tt>
231 * property.
232 * The returned {@link JOCLContentHandler} will contain the
233 * list of objects described by the file.
234 * @param f a {@link File} containing the JOCL document
235 * @return a {@link JOCLContentHandler} containing the list of objects described by the JOCL document
236 */
237 public static JOCLContentHandler parse(File f) throws SAXException, FileNotFoundException, IOException {
238 return JOCLContentHandler.parse(new FileInputStream(f),null);
239 }
240
241 /**
242 * Parses a JOCL document from the specified {@link Reader}, using the
243 * {@link XMLReader} specified by the <tt>org.xml.sax.driver</tt>
244 * property.
245 * The returned {@link JOCLContentHandler} will contain the
246 * list of objects described by the file.
247 * @param in a {@link Reader} containing the JOCL document
248 * @return a {@link JOCLContentHandler} containing the list of objects described by the JOCL document
249 */
250 public static JOCLContentHandler parse(Reader in) throws SAXException, IOException {
251 return JOCLContentHandler.parse(new InputSource(in),null);
252 }
253
254 /**
255 * Parses a JOCL document from the specified {@link InputStream}, using the
256 * {@link XMLReader} specified by the <tt>org.xml.sax.driver</tt>
257 * property.
258 * The returned {@link JOCLContentHandler} will contain the
259 * list of objects described by the file.
260 * @param in a {@link InputStream} containing the JOCL document
261 * @return a {@link JOCLContentHandler} containing the list of objects described by the JOCL document
262 */
263 public static JOCLContentHandler parse(InputStream in) throws SAXException, IOException {
264 return JOCLContentHandler.parse(new InputSource(in),null);
265 }
266
267 /**
268 * Parses a JOCL document from the specified {@link InputSource}, using thethe
269 * {@link XMLReader} specified by the <tt>org.xml.sax.driver</tt>
270 * property.
271 * The returned {@link JOCLContentHandler} will contain the
272 * list of objects described by the file.
273 * @param in a {@link InputSource} containing the JOCL document
274 * @return a {@link JOCLContentHandler} containing the list of objects described by the JOCL document
275 */
276 public static JOCLContentHandler parse(InputSource in) throws SAXException, IOException {
277 return JOCLContentHandler.parse(in,null);
278 }
279
280 /**
281 * Parses a JOCL document from the specified file, using the
282 * {@link XMLReader} specified by the <tt>org.xml.sax.driver</tt>
283 * property.
284 * The returned {@link JOCLContentHandler} will contain the
285 * list of objects described by the file.
286 * @param f a {@link File} containing the JOCL document
287 * @param reader the {@link XMLReader} to use to parse the file
288 * @return a {@link JOCLContentHandler} containing the list of objects described by the JOCL document
289 */
290 public static JOCLContentHandler parse(File f, XMLReader reader) throws SAXException, FileNotFoundException, IOException {
291 return JOCLContentHandler.parse(new FileInputStream(f),reader);
292 }
293
294 /**
295 * Parses a JOCL document from the specified {@link Reader}, using the specified
296 * {@link XMLReader}.
297 * The returned {@link JOCLContentHandler} will contain the
298 * list of objects described by the file.
299 * @param in a {@link Reader} containing the JOCL document
300 * @param reader the {@link XMLReader} to use to parse the document
301 * @return a {@link JOCLContentHandler} containing the list of objects described by the JOCL document
302 */
303 public static JOCLContentHandler parse(Reader in, XMLReader reader) throws SAXException, IOException {
304 return JOCLContentHandler.parse(new InputSource(in),reader);
305 }
306
307 /**
308 * Parses a JOCL document from the specified {@link InputStream}, using the specified
309 * {@link XMLReader}.
310 * The returned {@link JOCLContentHandler} will contain the
311 * list of objects described by the file.
312 * @param in a {@link InputStream} containing the JOCL document
313 * @param reader the {@link XMLReader} to use to parse the document
314 * @return a {@link JOCLContentHandler} containing the list of objects described by the JOCL document
315 */
316 public static JOCLContentHandler parse(InputStream in, XMLReader reader) throws SAXException, IOException {
317 return JOCLContentHandler.parse(new InputSource(in),reader);
318 }
319
320 /**
321 * Parses a JOCL document from the specified {@link InputSource}, using the
322 * specified {@link XMLReader}.
323 * The returned {@link JOCLContentHandler} will contain the
324 * list of objects described by the file.
325 * @param in a {@link InputSource} containing the JOCL document
326 * @param reader the {@link XMLReader} to use to parse the document
327 * @return a {@link JOCLContentHandler} containing the list of objects described by the JOCL document
328 */
329 public static JOCLContentHandler parse(InputSource in, XMLReader reader) throws SAXException, IOException {
330 JOCLContentHandler jocl = new JOCLContentHandler();
331 if(null == reader) {
332 reader = XMLReaderFactory.createXMLReader();
333 }
334 reader.setContentHandler(jocl);
335 reader.parse(in);
336 return jocl;
337 }
338
339 //--- Construtors ------------------------------------------------
340
341 /**
342 * Equivalent to {@link #JOCLContentHandler(boolean,boolean,boolean,boolean) JOCLContentHandler(true,true,true,true)}.
343 */
344 public JOCLContentHandler() {
345 this(true,true,true,true);
346 }
347
348 /**
349 * Construct a JOCLContentHandler.
350 * @param emtpyEltNs when <tt>true</tt> I should assume any element with an empty namespace is within the JOCL namespace
351 * @param joclEltPrefix when <tt>true</tt> I should assume any element who's prefix is <tt>jocl:</tt> and who's namespace is empty is within the JOCL namespace
352 * @param emptyAttrNS when <tt>true</tt> I should assume any attribute with an empty namespace is within the JOCL namespace
353 * @param joclAttrPrefix when <tt>true</tt> I should assume any attribute who's prefix is <tt>jocl:</tt> and who's namespace is empty is within the JOCL namespace
354 */
355 public JOCLContentHandler(boolean emptyEltNS, boolean joclEltPrefix, boolean emptyAttrNS, boolean joclAttrPrefix) {
356 _acceptEmptyNamespaceForElements = emptyEltNS;
357 _acceptJoclPrefixForElements = joclEltPrefix;
358 _acceptEmptyNamespaceForAttributes = emptyAttrNS;
359 _acceptJoclPrefixForAttributes = joclAttrPrefix;
360 }
361
362 //--- Public Methods - Accessing Objects -------------------------
363
364 /**
365 * Returns the number of values and types in my list.
366 * @return the number of values and types in my list.
367 */
368 public int size() {
369 return _typeList.size();
370 }
371
372 /**
373 * Clears all the values and types in my list.
374 */
375 public void clear() {
376 _typeList = new ArrayList();
377 _valueList = new ArrayList();
378 }
379
380 /**
381 * Removes the value/type pair at the specified index.
382 */
383 public void clear(int i) {
384 _typeList.remove(i);
385 _valueList.remove(i);
386 }
387
388 /**
389 * Returns the type of the object at the specified index.
390 */
391 public Class getType(int i) {
392 return(Class)(_typeList.get(i));
393 }
394
395 /**
396 * Returns the value of the object at the specified index.
397 */
398 public Object getValue(int i) {
399 return _valueList.get(i);
400 }
401
402 /**
403 * Returns a shallow copy of my list of values.
404 */
405 public Object[] getValueArray() {
406 return _valueList.toArray();
407 }
408
409 /**
410 * Returns a shallow copy of my list of types.
411 */
412 public Object[] getTypeArray() {
413 return _typeList.toArray();
414 }
415
416 //--- Public Methods - DocumentHandler ---------------------------
417
418 public void startElement(String uri, String localName, String qname, Attributes attr) throws SAXException {
419 try {
420 if(isJoclNamespace(uri,localName,qname)) {
421 if(ELT_OBJECT.equals(localName)) {
422 String cname = getAttributeValue(ATT_CLASS,attr);
423 String isnullstr = getAttributeValue(ATT_ISNULL,attr,"false");
424 boolean isnull = ("true".equalsIgnoreCase(isnullstr) || "yes".equalsIgnoreCase(isnullstr));
425 _cur = new ConstructorDetails(cname,_cur,isnull);
426 } else if(ELT_BOOLEAN.equals(localName)) {
427 String valstr = getAttributeValue(ATT_VALUE,attr,"false");
428 boolean val = ("true".equalsIgnoreCase(valstr) || "yes".equalsIgnoreCase(valstr));
429 addObject(Boolean.TYPE,new Boolean(val));
430 } else if(ELT_BYTE.equals(localName)) {
431 byte val = Byte.parseByte(getAttributeValue(ATT_VALUE,attr,"0"));
432 addObject(Byte.TYPE,new Byte(val));
433 } else if(ELT_CHAR.equals(localName)) {
434 char val = '\u0000';
435 String valstr = getAttributeValue(ATT_VALUE,attr);
436 if(null == valstr) {
437 val = '\u0000';
438 } else if(valstr.length() > 1) {
439 throw new SAXException("if present, char value must be exactly one character long");
440 } else if(valstr.length()==1) {
441 val = valstr.charAt(0);
442 } else if(valstr.length()==0) {
443 throw new SAXException("if present, char value must be exactly one character long");
444 }
445 addObject(Character.TYPE,new Character(val));
446 } else if(ELT_DOUBLE.equals(localName)) {
447 double val = Double.parseDouble(getAttributeValue(ATT_VALUE,attr,"0"));
448 addObject(Double.TYPE,new Double(val));
449 } else if(ELT_FLOAT.equals(localName)) {
450 float val = Float.parseFloat(getAttributeValue(ATT_VALUE,attr,"0"));
451 addObject(Float.TYPE,new Float(val));
452 } else if(ELT_INT.equals(localName)) {
453 int val = Integer.parseInt(getAttributeValue(ATT_VALUE,attr,"0"));
454 addObject(Integer.TYPE,new Integer(val));
455 } else if(ELT_LONG.equals(localName)) {
456 long val = Long.parseLong(getAttributeValue(ATT_VALUE,attr,"0"));
457 addObject(Long.TYPE,new Long(val));
458 } else if(ELT_SHORT.equals(localName)) {
459 short val = Short.parseShort(getAttributeValue(ATT_VALUE,attr,"0"));
460 addObject(Short.TYPE,new Short(val));
461 } else if(ELT_STRING.equals(localName)) {
462 String val = getAttributeValue(ATT_VALUE,attr);
463 addObject("".getClass(),val);
464 } else {
465 // unrecognized JOCL element warning?
466 }
467 }
468 } catch(Exception e) {
469 throw new SAXException(e);
470 }
471 }
472
473 public void endElement(String uri, String localName, String qname) throws SAXException {
474 try {
475 if(isJoclNamespace(uri,localName,qname)) {
476 if(ELT_OBJECT.equals(localName)) {
477 ConstructorDetails temp = _cur;
478 _cur = _cur.getParent();
479 if(null == _cur) {
480 _typeList.add(temp.getType());
481 _valueList.add(temp.createObject());
482 } else {
483 _cur.addArgument(temp.getType(),temp.createObject());
484 }
485 } else if(ELT_BOOLEAN.equals(localName)) {
486 // nothing to do here
487 } else if(ELT_BYTE.equals(localName)) {
488 // nothing to do here
489 } else if(ELT_CHAR.equals(localName)) {
490 // nothing to do here
491 } else if(ELT_DOUBLE.equals(localName)) {
492 // nothing to do here
493 } else if(ELT_FLOAT.equals(localName)) {
494 // nothing to do here
495 } else if(ELT_INT.equals(localName)) {
496 // nothing to do here
497 } else if(ELT_LONG.equals(localName)) {
498 // nothing to do here
499 } else if(ELT_SHORT.equals(localName)) {
500 // nothing to do here
501 } else if(ELT_STRING.equals(localName)) {
502 // nothing to do here
503 } else {
504 // unrecognized JOCL element warning?
505 }
506 }
507 } catch(Exception e) {
508 throw new SAXException(e);
509 }
510 }
511
512 public void setDocumentLocator(Locator locator) {
513 _locator = locator;
514 }
515
516 //--- Protected Methods ------------------------------------------
517
518 /**
519 * Returns <tt>true</tt> if the given attributes define an
520 * element within the JOCL namespace (according to my current
521 * configuration.)
522 *
523 * @see #_acceptEmptyNamespaceForElements
524 * @see #_acceptJoclPrefixForElements
525 */
526 protected boolean isJoclNamespace(String uri, String localname, String qname) {
527 if(JOCL_NAMESPACE_URI.equals(uri)) {
528 return true;
529 } else if(_acceptEmptyNamespaceForElements && (null == uri || "".equals(uri))) {
530 return true;
531 } else if(_acceptJoclPrefixForElements && (null == uri || "".equals(uri)) && qname.startsWith(JOCL_PREFIX)) {
532 return true;
533 } else {
534 return false;
535 }
536 }
537
538 /**
539 * Equivalent to {@link #getAttributeValue(java.lang.String,org.xml.sax.Attributes,java.lang.String) <tt>getAttributeValue(localname,attr,null)</tt>}.
540 */
541 protected String getAttributeValue(String localname, Attributes attr) {
542 return getAttributeValue(localname,attr,null);
543 }
544
545 /**
546 * Returns the value of attribute with the given
547 * <tt><i>localname</i></tt> within the JOCL
548 * namespace from the given set of {@link Attributes}.
549 * If no such attribute can be found, returns
550 * <tt><i>implied</i></tt>.
551 *
552 * @param localname the unqualified name of the attribute to look for
553 * @param attr the Attributes in which to find the value
554 * @param implied the default value for the attribute
555 * @return the value of attribute with the given
556 * <tt><i>localname</i></tt> within the JOCL
557 * namespace from the given set of {@link Attributes}.
558 * If no such attribute can be found, returns
559 * <tt><i>implied</i></tt>.
560 */
561 protected String getAttributeValue(String localname, Attributes attr, String implied) {
562 String val = attr.getValue(JOCL_NAMESPACE_URI,localname);
563 if(null == val && _acceptEmptyNamespaceForAttributes) {
564 val = attr.getValue("",localname);
565 }
566 if(null == val && _acceptJoclPrefixForAttributes) {
567 val = attr.getValue("",JOCL_PREFIX + localname);
568 }
569 return(null == val ? implied : val);
570 }
571
572 /**
573 * Add the specified object either to my type/value list, or
574 * as an argument to the object I'm currently constructing.
575 */
576 protected void addObject(Class type, Object val) {
577 if(null == _cur) {
578 _typeList.add(type);
579 _valueList.add(val);
580 } else {
581 _cur.addArgument(type,val);
582 }
583 }
584
585 //--- Protected Attributes ---------------------------------------
586
587 /**
588 * The JOCL namespace URI, <tt>http://apache.org/xml/xmlns/jakarta/commons/jocl</tt>.
589 */
590 public static final String JOCL_NAMESPACE_URI = "http://apache.org/xml/xmlns/jakarta/commons/jocl";
591
592 /**
593 * The default JOCL prefix, <tt>jocl:</tt>.
594 */
595 public static final String JOCL_PREFIX = "jocl:";
596
597 /**
598 * A list of the types ({@link Class}es) already created via the parse.
599 */
600 protected ArrayList _typeList = new ArrayList();
601
602 /**
603 * A list of the values ({@link Object}s) already created via the parse.
604 */
605 protected ArrayList _valueList = new ArrayList();
606
607 /**
608 * The object I'm currently working on.
609 */
610 protected ConstructorDetails _cur = null;
611
612 /**
613 * When <tt>true</tt>, I will treat elements with an
614 * empty namespace URI as part of the JOCL namespace.
615 *
616 * @see #JOCL_NAMESPACE_URI
617 */
618 protected boolean _acceptEmptyNamespaceForElements = true;
619
620 /**
621 * When <tt>true</tt>, I will treat elements with the
622 * {@link #JOCL_PREFIX} but no namespace URI as being
623 * mapped to the jocl namespace.
624 *
625 * @see #JOCL_PREFIX
626 * @see #JOCL_NAMESPACE_URI
627 */
628 protected boolean _acceptJoclPrefixForElements = true;
629
630 /**
631 * When <tt>true</tt>, I will treat attributes with an
632 * empty namespace URI as part of the JOCL namespace.
633 *
634 * @see #JOCL_NAMESPACE_URI
635 */
636 protected boolean _acceptEmptyNamespaceForAttributes = true;
637
638 /**
639 * When <tt>true</tt>, I will treat attributes with the
640 * {@link #JOCL_PREFIX} but no namespace URI as being
641 * mapped to the jocl namespace.
642 *
643 * @see #JOCL_PREFIX
644 * @see #JOCL_NAMESPACE_URI
645 */
646 protected boolean _acceptJoclPrefixForAttributes = true;
647
648 /** My {@link Locator}. */
649 protected Locator _locator = null;
650
651 /** The name of the "object" element. */
652 protected static final String ELT_OBJECT = "object";
653
654 /** The name of the "object" element's "class" attribute. */
655 protected static final String ATT_CLASS = "class";
656
657 /** The name of the "object" element's "isnull" attribute. */
658 protected static final String ATT_ISNULL = "null";
659
660 /** The name of the "boolean" element. */
661 protected static final String ELT_BOOLEAN = "boolean";
662
663 /** The name of the "byte" element. */
664 protected static final String ELT_BYTE = "byte";
665
666 /** The name of the "char" element. */
667 protected static final String ELT_CHAR = "char";
668
669 /** The name of the "double" element. */
670 protected static final String ELT_DOUBLE = "double";
671
672 /** The name of the "float" element. */
673 protected static final String ELT_FLOAT = "float";
674
675 /** The name of the "int" element. */
676 protected static final String ELT_INT = "int";
677
678 /** The name of the "long" element. */
679 protected static final String ELT_LONG = "long";
680
681 /** The name of the "short" element. */
682 protected static final String ELT_SHORT = "short";
683
684 /** The name of the "string" element. */
685 protected static final String ELT_STRING = "string";
686
687 /** The name of the "value" attribute. */
688 protected static final String ATT_VALUE = "value";
689
690 class ConstructorDetails {
691 private ConstructorDetails _parent = null;
692 private Class _type = null;
693 private ArrayList _argTypes = null;
694 private ArrayList _argValues = null;
695 private boolean _isnull = false;
696
697 public ConstructorDetails(String classname, ConstructorDetails parent) throws ClassNotFoundException {
698 this(Class.forName(classname),parent,false);
699 }
700
701 public ConstructorDetails(String classname, ConstructorDetails parent, boolean isnull) throws ClassNotFoundException {
702 this(Class.forName(classname),parent,isnull);
703 }
704
705 public ConstructorDetails(Class type, ConstructorDetails parent, boolean isnull) {
706 _parent = parent;
707 _type = type;
708 _argTypes = new ArrayList();
709 _argValues = new ArrayList();
710 _isnull = isnull;
711 }
712
713 public void addArgument(Object value) {
714 addArgument(value.getClass(),value);
715 }
716
717 public void addArgument(Class type, Object val) {
718 if(_isnull) {
719 throw new NullPointerException("can't add arguments to null instances");
720 }
721 _argTypes.add(type);
722 _argValues.add(val);
723 }
724
725 public Class getType() {
726 return _type;
727 }
728
729 public ConstructorDetails getParent() {
730 return _parent;
731 }
732
733 public Object createObject() throws InstantiationException, ClassNotFoundException, IllegalAccessException, InvocationTargetException {
734 if(_isnull) {
735 return null;
736 } else {
737 Class k = getType();
738 Class[] argtypes = (Class[])_argTypes.toArray(new Class[0]);
739 Object[] argvals = _argValues.toArray();
740 return ConstructorUtil.invokeConstructor(k,argtypes,argvals);
741 }
742 }
743 }
744
745 }