/* * @(#)XMLDecoder.java 1.30 04/06/01 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.beans; import com.sun.beans.ObjectHandler; import java.io.InputStream; import java.io.IOException; import java.lang.ref.Reference; import java.lang.ref.WeakReference; import org.xml.sax.SAXException; import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; /** * The XMLDecoder class is used to read XML documents * created using the XMLEncoder and is used just like * the ObjectInputStream. For example, one can use * the following fragment to read the first object defined * in an XML document written by the XMLEncoder * class: *
 *       XMLDecoder d = new XMLDecoder(
 *                          new BufferedInputStream(
 *                              new FileInputStream("Test.xml")));
 *       Object result = d.readObject();
 *       d.close();
 * 
* *

* For more information you might also want to check out * Long Term Persistence of JavaBeans Components: XML Schema, * an article in The Swing Connection. * @see XMLEncoder * @see java.io.ObjectInputStream * * @since 1.4 * * @version 1.30 06/01/04 * @author Philip Milne */ public class XMLDecoder { private InputStream in; private Object owner; private ExceptionListener exceptionListener; private ObjectHandler handler; private Reference clref; /** * Creates a new input stream for reading archives * created by the XMLEncoder class. * * @param in The underlying stream. * * @see XMLEncoder#XMLEncoder(OutputStream) */ public XMLDecoder(InputStream in) { this(in, null); } /** * Creates a new input stream for reading archives * created by the XMLEncoder class. * * @param in The underlying stream. * @param owner The owner of this stream. * */ public XMLDecoder(InputStream in, Object owner) { this(in, owner, null); } /** * Creates a new input stream for reading archives * created by the XMLEncoder class. * * @param in the underlying stream. * @param owner the owner of this stream. * @param exceptionListener the exception handler for the stream; * if null the default exception listener will be used. */ public XMLDecoder(InputStream in, Object owner, ExceptionListener exceptionListener) { this(in, owner, exceptionListener, null); } /** * Creates a new input stream for reading archives * created by the XMLEncoder class. * * @param in the underlying stream. null may be passed without * error, though the resulting XMLDecoder will be useless * @param owner the owner of this stream. null is a legal * value * @param exceptionListener the exception handler for the stream, or * null to use the default * @param cl the class loader used for instantiating objects. * null indicates that the default class loader should * be used * @since 1.5 */ public XMLDecoder(InputStream in, Object owner, ExceptionListener exceptionListener, ClassLoader cl) { this.in = in; setOwner(owner); setExceptionListener(exceptionListener); setClassLoader(cl); } /** * Set the class loader used to instantiate objects for this stream. * * @param cl a classloader to use; if null then the default class loader * will be used */ private void setClassLoader(ClassLoader cl) { if (cl != null) { this.clref = new WeakReference(cl); } } /** * Return the class loader used to instantiate objects. If the class loader * has not been explicitly set then null is returned. * * @return the class loader used to instantiate objects */ private ClassLoader getClassLoader() { if (clref != null) { return (ClassLoader)clref.get(); } return null; } /** * This method closes the input stream associated * with this stream. */ public void close() { if (in != null) { try { in.close(); } catch (IOException e) { getExceptionListener().exceptionThrown(e); } } } /** * Sets the exception handler for this stream to exceptionListener. * The exception handler is notified when this stream catches recoverable * exceptions. * * @param exceptionListener The exception handler for this stream; * if null the default exception listener will be used. * * @see #getExceptionListener */ public void setExceptionListener(ExceptionListener exceptionListener) { this.exceptionListener = exceptionListener; } /** * Gets the exception handler for this stream. * * @return The exception handler for this stream. * Will return the default exception listener if this has not explicitly been set. * * @see #setExceptionListener */ public ExceptionListener getExceptionListener() { return (exceptionListener != null) ? exceptionListener : Statement.defaultExceptionListener; } /** * Reads the next object from the underlying input stream. * * @return the next object read * * @throws ArrayIndexOutOfBoundsException if the stream contains no objects * (or no more objects) * * @see XMLEncoder#writeObject */ public Object readObject() { if (in == null) { return null; } if (handler == null) { SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser saxParser = factory.newSAXParser(); handler = new ObjectHandler(this, getClassLoader()); saxParser.parse(in, handler); } catch (ParserConfigurationException e) { getExceptionListener().exceptionThrown(e); } catch (SAXException se) { Exception e = se.getException(); getExceptionListener().exceptionThrown((e == null) ? se : e); } catch (IOException ioe) { getExceptionListener().exceptionThrown(ioe); } } return handler.dequeueResult(); } /** * Sets the owner of this decoder to owner. * * @param owner The owner of this decoder. * * @see #getOwner */ public void setOwner(Object owner) { this.owner = owner; } /** * Gets the owner of this decoder. * * @return The owner of this decoder. * * @see #setOwner */ public Object getOwner() { return owner; } }