1 /*
2 * Copyright 2000-2005 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25 package java.beans;
26
27 import com.sun.beans.ObjectHandler;
28
29 import java.io.InputStream;
30 import java.io.IOException;
31
32 import java.lang.ref.Reference;
33 import java.lang.ref.WeakReference;
34
35 import org.xml.sax.SAXException;
36
37 import javax.xml.parsers.SAXParserFactory;
38 import javax.xml.parsers.ParserConfigurationException;
39 import javax.xml.parsers.SAXParser;
40
41 /**
42 * The <code>XMLDecoder</code> class is used to read XML documents
43 * created using the <code>XMLEncoder</code> and is used just like
44 * the <code>ObjectInputStream</code>. For example, one can use
45 * the following fragment to read the first object defined
46 * in an XML document written by the <code>XMLEncoder</code>
47 * class:
48 * <pre>
49 * XMLDecoder d = new XMLDecoder(
50 * new BufferedInputStream(
51 * new FileInputStream("Test.xml")));
52 * Object result = d.readObject();
53 * d.close();
54 * </pre>
55 *
56 *<p>
57 * For more information you might also want to check out
58 * <a
59 href="http://java.sun.com/products/jfc/tsc/articles/persistence3">Long Term Persistence of JavaBeans Components: XML Schema</a>,
60 * an article in <em>The Swing Connection.</em>
61 * @see XMLEncoder
62 * @see java.io.ObjectInputStream
63 *
64 * @since 1.4
65 *
66 * @author Philip Milne
67 */
68 public class XMLDecoder {
69 private InputStream in;
70 private Object owner;
71 private ExceptionListener exceptionListener;
72 private ObjectHandler handler;
73 private Reference clref;
74
75 /**
76 * Creates a new input stream for reading archives
77 * created by the <code>XMLEncoder</code> class.
78 *
79 * @param in The underlying stream.
80 *
81 * @see XMLEncoder#XMLEncoder(java.io.OutputStream)
82 */
83 public XMLDecoder(InputStream in) {
84 this(in, null);
85 }
86
87 /**
88 * Creates a new input stream for reading archives
89 * created by the <code>XMLEncoder</code> class.
90 *
91 * @param in The underlying stream.
92 * @param owner The owner of this stream.
93 *
94 */
95 public XMLDecoder(InputStream in, Object owner) {
96 this(in, owner, null);
97 }
98
99 /**
100 * Creates a new input stream for reading archives
101 * created by the <code>XMLEncoder</code> class.
102 *
103 * @param in the underlying stream.
104 * @param owner the owner of this stream.
105 * @param exceptionListener the exception handler for the stream;
106 * if <code>null</code> the default exception listener will be used.
107 */
108 public XMLDecoder(InputStream in, Object owner, ExceptionListener exceptionListener) {
109 this(in, owner, exceptionListener, null);
110 }
111
112 /**
113 * Creates a new input stream for reading archives
114 * created by the <code>XMLEncoder</code> class.
115 *
116 * @param in the underlying stream. <code>null</code> may be passed without
117 * error, though the resulting XMLDecoder will be useless
118 * @param owner the owner of this stream. <code>null</code> is a legal
119 * value
120 * @param exceptionListener the exception handler for the stream, or
121 * <code>null</code> to use the default
122 * @param cl the class loader used for instantiating objects.
123 * <code>null</code> indicates that the default class loader should
124 * be used
125 * @since 1.5
126 */
127 public XMLDecoder(InputStream in, Object owner,
128 ExceptionListener exceptionListener, ClassLoader cl) {
129 this.in = in;
130 setOwner(owner);
131 setExceptionListener(exceptionListener);
132 setClassLoader(cl);
133 }
134
135
136 /**
137 * Set the class loader used to instantiate objects for this stream.
138 *
139 * @param cl a classloader to use; if null then the default class loader
140 * will be used
141 */
142 private void setClassLoader(ClassLoader cl) {
143 if (cl != null) {
144 this.clref = new WeakReference(cl);
145 }
146 }
147
148 /**
149 * Return the class loader used to instantiate objects. If the class loader
150 * has not been explicitly set then null is returned.
151 *
152 * @return the class loader used to instantiate objects
153 */
154 private ClassLoader getClassLoader() {
155 if (clref != null) {
156 return (ClassLoader)clref.get();
157 }
158 return null;
159 }
160
161 /**
162 * This method closes the input stream associated
163 * with this stream.
164 */
165 public void close() {
166 if (in != null) {
167 getHandler();
168 try {
169 in.close();
170 }
171 catch (IOException e) {
172 getExceptionListener().exceptionThrown(e);
173 }
174 }
175 }
176
177 /**
178 * Sets the exception handler for this stream to <code>exceptionListener</code>.
179 * The exception handler is notified when this stream catches recoverable
180 * exceptions.
181 *
182 * @param exceptionListener The exception handler for this stream;
183 * if <code>null</code> the default exception listener will be used.
184 *
185 * @see #getExceptionListener
186 */
187 public void setExceptionListener(ExceptionListener exceptionListener) {
188 this.exceptionListener = exceptionListener;
189 }
190
191 /**
192 * Gets the exception handler for this stream.
193 *
194 * @return The exception handler for this stream.
195 * Will return the default exception listener if this has not explicitly been set.
196 *
197 * @see #setExceptionListener
198 */
199 public ExceptionListener getExceptionListener() {
200 return (exceptionListener != null) ? exceptionListener :
201 Statement.defaultExceptionListener;
202 }
203
204 /**
205 * Reads the next object from the underlying input stream.
206 *
207 * @return the next object read
208 *
209 * @throws ArrayIndexOutOfBoundsException if the stream contains no objects
210 * (or no more objects)
211 *
212 * @see XMLEncoder#writeObject
213 */
214 public Object readObject() {
215 if (in == null) {
216 return null;
217 }
218 return getHandler().dequeueResult();
219 }
220
221 /**
222 * Sets the owner of this decoder to <code>owner</code>.
223 *
224 * @param owner The owner of this decoder.
225 *
226 * @see #getOwner
227 */
228 public void setOwner(Object owner) {
229 this.owner = owner;
230 }
231
232 /**
233 * Gets the owner of this decoder.
234 *
235 * @return The owner of this decoder.
236 *
237 * @see #setOwner
238 */
239 public Object getOwner() {
240 return owner;
241 }
242
243 /**
244 * Returns the object handler for input stream.
245 * The object handler is created if necessary.
246 *
247 * @return the object handler
248 */
249 private ObjectHandler getHandler() {
250 if ( handler == null ) {
251 SAXParserFactory factory = SAXParserFactory.newInstance();
252 try {
253 SAXParser parser = factory.newSAXParser();
254 handler = new ObjectHandler( this, getClassLoader() );
255 parser.parse( in, handler );
256 }
257 catch ( ParserConfigurationException e ) {
258 getExceptionListener().exceptionThrown( e );
259 }
260 catch ( SAXException se ) {
261 Exception e = se.getException();
262 if ( e == null ) {
263 e = se;
264 }
265 getExceptionListener().exceptionThrown( e );
266 }
267 catch ( IOException ioe ) {
268 getExceptionListener().exceptionThrown( ioe );
269 }
270 }
271 return handler;
272 }
273 }