View Javadoc

1   /*
2    * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
3    *
4    * This software is open source.
5    * See the bottom of this file for the licence.
6    */
7   
8   package org.dom4j.jaxb;
9   
10  import java.io.File;
11  import java.io.FileInputStream;
12  import java.io.FileNotFoundException;
13  import java.io.InputStream;
14  import java.io.InputStreamReader;
15  import java.io.Reader;
16  import java.net.URL;
17  import java.nio.charset.Charset;
18  
19  import org.dom4j.Document;
20  import org.dom4j.DocumentException;
21  import org.dom4j.Element;
22  import org.dom4j.ElementHandler;
23  import org.dom4j.ElementPath;
24  import org.dom4j.io.SAXReader;
25  
26  import org.xml.sax.InputSource;
27  
28  /***
29   * Reads an XML document and creates a DOM4J tree from SAX parsing events.
30   * {@link JAXBObjectHandler}objects can be registered to automatically receive
31   * unmarshalled XML fragments. Registered {@linkorg.dom4j.ElementHandler}
32   * implementations are notified when a certain element path is encountered
33   * 
34   * @author Wonne Keysers (Realsoftware.be)
35   * 
36   * @see org.dom4j.io.SAXReader
37   * @see javax.xml.bind.JAXBContext
38   */
39  public class JAXBReader extends JAXBSupport {
40      private SAXReader reader;
41  
42      private boolean pruneElements;
43  
44      /***
45       * Creates a new JAXBReader for the given JAXB context path. This is the
46       * Java package where JAXB can find the generated XML classes. This package
47       * MUST contain jaxb.properties!
48       * 
49       * @param contextPath
50       *            context path to be used
51       * 
52       * @see javax.xml.bind.JAXBContext
53       */
54      public JAXBReader(String contextPath) {
55          super(contextPath);
56      }
57  
58      /***
59       * Creates a new JAXBReader for the given JAXB context path, using the
60       * specified {@link java.lang.Classloader}. This is the Java package where
61       * JAXB can find the generated XML classes. This package MUST contain
62       * jaxb.properties!
63       * 
64       * @param contextPath
65       *            to be used
66       * @param classloader
67       *            to be used
68       * 
69       * @see javax.xml.bind.JAXBContext
70       */
71      public JAXBReader(String contextPath, ClassLoader classloader) {
72          super(contextPath, classloader);
73      }
74  
75      /***
76       * Parses the specified {@link java.io.File}
77       * 
78       * @param source
79       *            the file to parse
80       * 
81       * @return the resulting DOM4J document
82       * 
83       * @throws DocumentException
84       *             when an error occurs while parsing
85       */
86      public Document read(File source) throws DocumentException {
87          return getReader().read(source);
88      }
89  
90      /***
91       * Parses the specified {@link java.io.File}, using the given {@link
92       * java.nio.charset.Charset}.
93       * 
94       * @param file
95       *            the file to parse
96       * @param charset
97       *            the charset to be used
98       * 
99       * @return the resulting DOM4J document
100      * 
101      * @throws DocumentException
102      *             when an error occurs while parsing
103      */
104     public Document read(File file, Charset charset) throws DocumentException {
105         try {
106             Reader xmlReader = new InputStreamReader(new FileInputStream(file),
107                     charset);
108 
109             return getReader().read(xmlReader);
110         } catch (JAXBRuntimeException ex) {
111             Throwable cause = ex.getCause();
112             throw new DocumentException(cause.getMessage(), cause);
113         } catch (FileNotFoundException ex) {
114             throw new DocumentException(ex.getMessage(), ex);
115         }
116     }
117 
118     /***
119      * Parses the specified {@link org.xml.sax.InputSource}
120      * 
121      * @param source
122      *            the source to parse
123      * 
124      * @return the resulting DOM4J document
125      * 
126      * @throws DocumentException
127      *             when an error occurs while parsing
128      */
129     public Document read(InputSource source) throws DocumentException {
130         try {
131             return getReader().read(source);
132         } catch (JAXBRuntimeException ex) {
133             Throwable cause = ex.getCause();
134             throw new DocumentException(cause.getMessage(), cause);
135         }
136     }
137 
138     /***
139      * Parses the specified {@link java.io.InputStream}
140      * 
141      * @param source
142      *            the input stream to parse
143      * 
144      * @return the resulting DOM4J document
145      * 
146      * @throws DocumentException
147      *             when an error occurs while parsing
148      */
149     public Document read(InputStream source) throws DocumentException {
150         try {
151             return getReader().read(source);
152         } catch (JAXBRuntimeException ex) {
153             Throwable cause = ex.getCause();
154             throw new DocumentException(cause.getMessage(), cause);
155         }
156     }
157 
158     /***
159      * Parses the specified {@link java.io.InputStream}
160      * 
161      * @param source
162      *            the input stream to parse
163      * @param systemId
164      *            is the URI for the input
165      * 
166      * @return the resulting DOM4J document
167      * 
168      * @throws DocumentException
169      *             when an error occurs while parsing
170      */
171     public Document read(InputStream source, String systemId)
172             throws DocumentException {
173         try {
174             return getReader().read(source);
175         } catch (JAXBRuntimeException ex) {
176             Throwable cause = ex.getCause();
177             throw new DocumentException(cause.getMessage(), cause);
178         }
179     }
180 
181     /***
182      * Parses the specified {@link java.io.Reader}
183      * 
184      * @param source
185      *            the input reader to use
186      * 
187      * @return the resulting DOM4J document
188      * 
189      * @throws DocumentException
190      *             when an error occurs while parsing
191      */
192     public Document read(Reader source) throws DocumentException {
193         try {
194             return getReader().read(source);
195         } catch (JAXBRuntimeException ex) {
196             Throwable cause = ex.getCause();
197             throw new DocumentException(cause.getMessage(), cause);
198         }
199     }
200 
201     /***
202      * Parses the specified {@link java.io.Reader}
203      * 
204      * @param source
205      *            the input reader to parse
206      * @param systemId
207      *            is the URI for the input
208      * 
209      * @return the resulting DOM4J document
210      * 
211      * @throws DocumentException
212      *             when an error occurs while parsing
213      */
214     public Document read(Reader source, String systemId)
215             throws DocumentException {
216         try {
217             return getReader().read(source);
218         } catch (JAXBRuntimeException ex) {
219             Throwable cause = ex.getCause();
220             throw new DocumentException(cause.getMessage(), cause);
221         }
222     }
223 
224     /***
225      * Parses the the given URL or filename.
226      * 
227      * @param source
228      *            the location to parse
229      * 
230      * @return the resulting DOM4J document
231      * 
232      * @throws DocumentException
233      *             when an error occurs while parsing
234      */
235     public Document read(String source) throws DocumentException {
236         try {
237             return getReader().read(source);
238         } catch (JAXBRuntimeException ex) {
239             Throwable cause = ex.getCause();
240             throw new DocumentException(cause.getMessage(), cause);
241         }
242     }
243 
244     /***
245      * Parses the the given URL.
246      * 
247      * @param source
248      *            the URL to parse
249      * 
250      * @return the resulting DOM4J document
251      * 
252      * @throws DocumentException
253      *             when an error occurs while parsing
254      */
255     public Document read(URL source) throws DocumentException {
256         try {
257             return getReader().read(source);
258         } catch (JAXBRuntimeException ex) {
259             Throwable cause = ex.getCause();
260             throw new DocumentException(cause.getMessage(), cause);
261         }
262     }
263 
264     /***
265      * Registers a {@link JAXBObjectHandler}that will be supplied with the
266      * unmarshalled representation of the xml fragment whenever the specified
267      * path is encounted.
268      * 
269      * @param path
270      *            the path to listen for
271      * @param handler
272      *            the handler to be notified
273      */
274     public void addObjectHandler(String path, JAXBObjectHandler handler) {
275         ElementHandler eHandler = new UnmarshalElementHandler(this, handler);
276         getReader().addHandler(path, eHandler);
277     }
278 
279     /***
280      * Removes the {@link JAXBObjectHandler}from the event based processor, for
281      * the specified element path.
282      * 
283      * @param path
284      *            The path to remove the {@link JAXBObjectHandler}for
285      */
286     public void removeObjectHandler(String path) {
287         getReader().removeHandler(path);
288     }
289 
290     /***
291      * Adds the <code>ElementHandler</code> to be called when the specified
292      * path is encounted.
293      * 
294      * @param path
295      *            is the path to be handled
296      * @param handler
297      *            is the <code>ElementHandler</code> to be called by the event
298      *            based processor.
299      */
300     public void addHandler(String path, ElementHandler handler) {
301         getReader().addHandler(path, handler);
302     }
303 
304     /***
305      * Removes the <code>ElementHandler</code> from the event based processor,
306      * for the specified path.
307      * 
308      * @param path
309      *            is the path to remove the <code>ElementHandler</code> for.
310      */
311     public void removeHandler(String path) {
312         getReader().removeHandler(path);
313     }
314 
315     /***
316      * Removes all registered {@link JAXBObjectHandler}and {@link
317      * org.dom4j.ElementHandler} instances from the event based processor.
318      */
319     public void resetHandlers() {
320         getReader().resetHandlers();
321     }
322 
323     /***
324      * When 'true', the DOM4J document will not be kept in memory while parsing.
325      * 
326      * @return Returns the pruneElements.
327      */
328     public boolean isPruneElements() {
329         return pruneElements;
330     }
331 
332     /***
333      * Set to true when DOM4J elements must immediately be pruned from the tree.
334      * The {@link Document}will not be available afterwards!
335      * 
336      * @param pruneElements
337      */
338     public void setPruneElements(boolean pruneElements) {
339         this.pruneElements = pruneElements;
340 
341         if (pruneElements) {
342             getReader().setDefaultHandler(new PruningElementHandler());
343         }
344     }
345 
346     private SAXReader getReader() {
347         if (reader == null) {
348             reader = new SAXReader();
349         }
350 
351         return reader;
352     }
353 
354     private class UnmarshalElementHandler implements ElementHandler {
355         private JAXBReader jaxbReader;
356 
357         private JAXBObjectHandler handler;
358 
359         public UnmarshalElementHandler(JAXBReader documentReader,
360                 JAXBObjectHandler handler) {
361             this.jaxbReader = documentReader;
362             this.handler = handler;
363         }
364 
365         public void onStart(ElementPath elementPath) {
366         }
367 
368         public void onEnd(ElementPath elementPath) {
369             try {
370                 org.dom4j.Element elem = elementPath.getCurrent();
371 
372                 javax.xml.bind.Element jaxbObject 
373                         = (javax.xml.bind.Element) jaxbReader.unmarshal(elem);
374 
375                 if (jaxbReader.isPruneElements()) {
376                     elem.detach();
377                 }
378 
379                 handler.handleObject(jaxbObject);
380             } catch (Exception ex) {
381                 throw new JAXBRuntimeException(ex);
382             }
383         }
384     }
385 
386     private class PruningElementHandler implements ElementHandler {
387         public PruningElementHandler() {
388         }
389 
390         public void onStart(ElementPath parm1) {
391         }
392 
393         public void onEnd(ElementPath elementPath) {
394             Element elem = elementPath.getCurrent();
395             elem.detach();
396             elem = null;
397         }
398     }
399 }
400 
401 /*
402  * Redistribution and use of this software and associated documentation
403  * ("Software"), with or without modification, are permitted provided that the
404  * following conditions are met:
405  * 
406  * 1. Redistributions of source code must retain copyright statements and
407  * notices. Redistributions must also contain a copy of this document.
408  * 
409  * 2. Redistributions in binary form must reproduce the above copyright notice,
410  * this list of conditions and the following disclaimer in the documentation
411  * and/or other materials provided with the distribution.
412  * 
413  * 3. The name "DOM4J" must not be used to endorse or promote products derived
414  * from this Software without prior written permission of MetaStuff, Ltd. For
415  * written permission, please contact dom4j-info@metastuff.com.
416  * 
417  * 4. Products derived from this Software may not be called "DOM4J" nor may
418  * "DOM4J" appear in their names without prior written permission of MetaStuff,
419  * Ltd. DOM4J is a registered trademark of MetaStuff, Ltd.
420  * 
421  * 5. Due credit should be given to the DOM4J Project - http://www.dom4j.org
422  * 
423  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS ``AS IS'' AND
424  * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
425  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
426  * ARE DISCLAIMED. IN NO EVENT SHALL METASTUFF, LTD. OR ITS CONTRIBUTORS BE
427  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
428  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
429  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
430  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
431  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
432  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
433  * POSSIBILITY OF SUCH DAMAGE.
434  * 
435  * Copyright 2001-2005 (C) MetaStuff, Ltd. All Rights Reserved.
436  */