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