1   
2   
3   
4   
5   
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 
403 
404 
405 
406 
407 
408 
409 
410 
411 
412 
413 
414 
415 
416 
417 
418 
419 
420 
421 
422 
423 
424 
425 
426 
427 
428 
429 
430 
431 
432 
433 
434 
435 
436