1. /*
  2. * @(#)XMLDecoder.java 1.30 04/06/01
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.beans;
  8. import com.sun.beans.ObjectHandler;
  9. import java.io.InputStream;
  10. import java.io.IOException;
  11. import java.lang.ref.Reference;
  12. import java.lang.ref.WeakReference;
  13. import org.xml.sax.SAXException;
  14. import javax.xml.parsers.SAXParserFactory;
  15. import javax.xml.parsers.ParserConfigurationException;
  16. import javax.xml.parsers.SAXParser;
  17. /**
  18. * The <code>XMLDecoder</code> class is used to read XML documents
  19. * created using the <code>XMLEncoder</code> and is used just like
  20. * the <code>ObjectInputStream</code>. For example, one can use
  21. * the following fragment to read the first object defined
  22. * in an XML document written by the <code>XMLEncoder</code>
  23. * class:
  24. * <pre>
  25. * XMLDecoder d = new XMLDecoder(
  26. * new BufferedInputStream(
  27. * new FileInputStream("Test.xml")));
  28. * Object result = d.readObject();
  29. * d.close();
  30. * </pre>
  31. *
  32. *<p>
  33. * For more information you might also want to check out
  34. * <a
  35. href="http://java.sun.com/products/jfc/tsc/articles/persistence3">Long Term Persistence of JavaBeans Components: XML Schema</a>,
  36. * an article in <em>The Swing Connection.</em>
  37. * @see XMLEncoder
  38. * @see java.io.ObjectInputStream
  39. *
  40. * @since 1.4
  41. *
  42. * @version 1.30 06/01/04
  43. * @author Philip Milne
  44. */
  45. public class XMLDecoder {
  46. private InputStream in;
  47. private Object owner;
  48. private ExceptionListener exceptionListener;
  49. private ObjectHandler handler;
  50. private Reference clref;
  51. /**
  52. * Creates a new input stream for reading archives
  53. * created by the <code>XMLEncoder</code> class.
  54. *
  55. * @param in The underlying stream.
  56. *
  57. * @see XMLEncoder#XMLEncoder(OutputStream)
  58. */
  59. public XMLDecoder(InputStream in) {
  60. this(in, null);
  61. }
  62. /**
  63. * Creates a new input stream for reading archives
  64. * created by the <code>XMLEncoder</code> class.
  65. *
  66. * @param in The underlying stream.
  67. * @param owner The owner of this stream.
  68. *
  69. */
  70. public XMLDecoder(InputStream in, Object owner) {
  71. this(in, owner, null);
  72. }
  73. /**
  74. * Creates a new input stream for reading archives
  75. * created by the <code>XMLEncoder</code> class.
  76. *
  77. * @param in the underlying stream.
  78. * @param owner the owner of this stream.
  79. * @param exceptionListener the exception handler for the stream;
  80. * if <code>null</code> the default exception listener will be used.
  81. */
  82. public XMLDecoder(InputStream in, Object owner, ExceptionListener exceptionListener) {
  83. this(in, owner, exceptionListener, null);
  84. }
  85. /**
  86. * Creates a new input stream for reading archives
  87. * created by the <code>XMLEncoder</code> class.
  88. *
  89. * @param in the underlying stream. <code>null</code> may be passed without
  90. * error, though the resulting XMLDecoder will be useless
  91. * @param owner the owner of this stream. <code>null</code> is a legal
  92. * value
  93. * @param exceptionListener the exception handler for the stream, or
  94. * <code>null</code> to use the default
  95. * @param cl the class loader used for instantiating objects.
  96. * <code>null</code> indicates that the default class loader should
  97. * be used
  98. * @since 1.5
  99. */
  100. public XMLDecoder(InputStream in, Object owner,
  101. ExceptionListener exceptionListener, ClassLoader cl) {
  102. this.in = in;
  103. setOwner(owner);
  104. setExceptionListener(exceptionListener);
  105. setClassLoader(cl);
  106. }
  107. /**
  108. * Set the class loader used to instantiate objects for this stream.
  109. *
  110. * @param cl a classloader to use; if null then the default class loader
  111. * will be used
  112. */
  113. private void setClassLoader(ClassLoader cl) {
  114. if (cl != null) {
  115. this.clref = new WeakReference(cl);
  116. }
  117. }
  118. /**
  119. * Return the class loader used to instantiate objects. If the class loader
  120. * has not been explicitly set then null is returned.
  121. *
  122. * @return the class loader used to instantiate objects
  123. */
  124. private ClassLoader getClassLoader() {
  125. if (clref != null) {
  126. return (ClassLoader)clref.get();
  127. }
  128. return null;
  129. }
  130. /**
  131. * This method closes the input stream associated
  132. * with this stream.
  133. */
  134. public void close() {
  135. if (in != null) {
  136. try {
  137. in.close();
  138. }
  139. catch (IOException e) {
  140. getExceptionListener().exceptionThrown(e);
  141. }
  142. }
  143. }
  144. /**
  145. * Sets the exception handler for this stream to <code>exceptionListener</code>.
  146. * The exception handler is notified when this stream catches recoverable
  147. * exceptions.
  148. *
  149. * @param exceptionListener The exception handler for this stream;
  150. * if <code>null</code> the default exception listener will be used.
  151. *
  152. * @see #getExceptionListener
  153. */
  154. public void setExceptionListener(ExceptionListener exceptionListener) {
  155. this.exceptionListener = exceptionListener;
  156. }
  157. /**
  158. * Gets the exception handler for this stream.
  159. *
  160. * @return The exception handler for this stream.
  161. * Will return the default exception listener if this has not explicitly been set.
  162. *
  163. * @see #setExceptionListener
  164. */
  165. public ExceptionListener getExceptionListener() {
  166. return (exceptionListener != null) ? exceptionListener :
  167. Statement.defaultExceptionListener;
  168. }
  169. /**
  170. * Reads the next object from the underlying input stream.
  171. *
  172. * @return the next object read
  173. *
  174. * @throws ArrayIndexOutOfBoundsException if the stream contains no objects
  175. * (or no more objects)
  176. *
  177. * @see XMLEncoder#writeObject
  178. */
  179. public Object readObject() {
  180. if (in == null) {
  181. return null;
  182. }
  183. if (handler == null) {
  184. SAXParserFactory factory = SAXParserFactory.newInstance();
  185. try {
  186. SAXParser saxParser = factory.newSAXParser();
  187. handler = new ObjectHandler(this, getClassLoader());
  188. saxParser.parse(in, handler);
  189. }
  190. catch (ParserConfigurationException e) {
  191. getExceptionListener().exceptionThrown(e);
  192. }
  193. catch (SAXException se) {
  194. Exception e = se.getException();
  195. getExceptionListener().exceptionThrown((e == null) ? se : e);
  196. }
  197. catch (IOException ioe) {
  198. getExceptionListener().exceptionThrown(ioe);
  199. }
  200. }
  201. return handler.dequeueResult();
  202. }
  203. /**
  204. * Sets the owner of this decoder to <code>owner</code>.
  205. *
  206. * @param owner The owner of this decoder.
  207. *
  208. * @see #getOwner
  209. */
  210. public void setOwner(Object owner) {
  211. this.owner = owner;
  212. }
  213. /**
  214. * Gets the owner of this decoder.
  215. *
  216. * @return The owner of this decoder.
  217. *
  218. * @see #setOwner
  219. */
  220. public Object getOwner() {
  221. return owner;
  222. }
  223. }