1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256
/* * @(#)XMLDecoder.java 1.32 05/11/30 * * Copyright 2006 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 <code>XMLDecoder</code> class is used to read XML documents * created using the <code>XMLEncoder</code> and is used just like * the <code>ObjectInputStream</code>. For example, one can use * the following fragment to read the first object defined * in an XML document written by the <code>XMLEncoder</code> * class: * <pre> * XMLDecoder d = new XMLDecoder( * new BufferedInputStream( * new FileInputStream("Test.xml"))); * Object result = d.readObject(); * d.close(); * </pre> * *<p> * For more information you might also want to check out * <a href="http://java.sun.com/products/jfc/tsc/articles/persistence3">Long Term Persistence of JavaBeans Components: XML Schema</a>, * an article in <em>The Swing Connection.</em> * @see XMLEncoder * @see java.io.ObjectInputStream * * @since 1.4 * * @version 1.32 11/30/05 * @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 <code>XMLEncoder</code> class. * * @param in The underlying stream. * * @see XMLEncoder#XMLEncoder(java.io.OutputStream) */ public XMLDecoder(InputStream in) { this(in, null); } /** * Creates a new input stream for reading archives * created by the <code>XMLEncoder</code> 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 <code>XMLEncoder</code> class. * * @param in the underlying stream. * @param owner the owner of this stream. * @param exceptionListener the exception handler for the stream; * if <code>null</code> 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 <code>XMLEncoder</code> class. * * @param in the underlying stream. <code>null</code> may be passed without * error, though the resulting XMLDecoder will be useless * @param owner the owner of this stream. <code>null</code> is a legal * value * @param exceptionListener the exception handler for the stream, or * <code>null</code> to use the default * @param cl the class loader used for instantiating objects. * <code>null</code> 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) { getHandler(); try { in.close(); } catch (IOException e) { getExceptionListener().exceptionThrown(e); } } } /** * Sets the exception handler for this stream to <code>exceptionListener</code>. * The exception handler is notified when this stream catches recoverable * exceptions. * * @param exceptionListener The exception handler for this stream; * if <code>null</code> 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; } return getHandler().dequeueResult(); } /** * Sets the owner of this decoder to <code>owner</code>. * * @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; } /** * Returns the object handler for input stream. * The object handler is created if necessary. * * @return the object handler */ private ObjectHandler getHandler() { if ( handler == null ) { SAXParserFactory factory = SAXParserFactory.newInstance(); try { SAXParser parser = factory.newSAXParser(); handler = new ObjectHandler( this, getClassLoader() ); parser.parse( in, handler ); } catch ( ParserConfigurationException e ) { getExceptionListener().exceptionThrown( e ); } catch ( SAXException se ) { Exception e = se.getException(); if ( e == null ) { e = se; } getExceptionListener().exceptionThrown( e ); } catch ( IOException ioe ) { getExceptionListener().exceptionThrown( ioe ); } } return handler; } }