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