1
2
3
4
5
6
7
8
9
10 package org.dom4j.jaxb;
11
12 import java.io.File;
13 import java.io.FileInputStream;
14 import java.io.FileNotFoundException;
15 import java.io.FileOutputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.InputStreamReader;
19 import java.io.OutputStream;
20 import java.io.Reader;
21 import java.io.Writer;
22 import java.net.URL;
23 import java.nio.charset.Charset;
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.Map;
27
28 import org.dom4j.Document;
29 import org.dom4j.DocumentException;
30 import org.dom4j.io.ElementModifier;
31 import org.dom4j.io.OutputFormat;
32 import org.dom4j.io.SAXModifier;
33 import org.dom4j.io.XMLWriter;
34 import org.xml.sax.InputSource;
35
36 /***
37 * Reads an XML document using SAX and writes its content to the provided {@link org.dom4j.io.XMLWriter}.
38 * Modifications must be provided by {@link org.dom4j.jaxb.JAXBObjectModifier} objects,
39 * which are called prior to writing the XML fragment they are registered for.
40 *
41 * @see org.dom4j.io.SAXModifier
42 * @author Wonne Keysers (Realsoftware.be)
43 */
44 public class JAXBModifier extends JAXBSupport {
45
46 private SAXModifier modifier;
47 private XMLWriter xmlWriter;
48 private boolean pruneElements;
49 private OutputFormat outputFormat;
50 private HashMap modifiers = new HashMap();
51
52 /***
53 * Creates a new JAXBModifier for the given JAXB context path.
54 * This is the Java package where JAXB can find the generated XML classes.
55 * This package MUST contain jaxb.properties!
56 *
57 * @param contextPath JAXB context path to be used
58 * @see javax.xml.bind.JAXBContext
59 */
60 public JAXBModifier(String contextPath) {
61 super(contextPath);
62 this.outputFormat = new OutputFormat();
63 }
64
65 /***
66 * Creates a new JAXBModifier for the given JAXB context path, using the given {@link java.lang.ClassLoader}.
67 * This is the Java package where JAXB can find the generated XML classes.
68 * This package MUST contain jaxb.properties!
69 *
70 * @param contextPath JAXB context path to be used
71 * @param classloader the classloader to use
72 * @see javax.xml.bind.JAXBContext
73 */
74 public JAXBModifier(String contextPath, ClassLoader classloader) {
75 super(contextPath, classloader);
76 this.outputFormat = new OutputFormat();
77 }
78
79 /***
80 * Creates a new JAXBModifier for the given JAXB context path.
81 * The specified {@link org.dom4j.io.OutputFormat} will be used while writing the XML stream.
82 *
83 * @param contextPath JAXB context path to be used
84 * @param outputFormat the DOM4J {@link org.dom4j.io.OutputFormat} to be used
85 * @see javax.xml.bind.JAXBContext
86 */
87 public JAXBModifier(String contextPath, OutputFormat outputFormat) {
88 super(contextPath);
89 this.outputFormat = outputFormat;
90 }
91
92 /***
93 * Creates a new JAXBModifier for the given JAXB context path,
94 * using the specified {@link java.lang.Classloader}.
95 * The specified {@link org.dom4j.io.OutputFormat} will be used while writing the XML stream.
96 *
97 * @param contextPath JAXB context path to be used
98 * @param classloader the class loader to be used to load JAXB
99 * @param outputFormat the DOM4J {@link org.dom4j.io.OutputFormat} to be used
100 * @see javax.xml.bind.JAXBContext
101 */
102 public JAXBModifier(String contextPath, ClassLoader classloader, OutputFormat outputFormat) {
103 super(contextPath, classloader);
104 this.outputFormat = outputFormat;
105 }
106
107 /***
108 * Parses the specified {@link java.io.File} with SAX
109 *
110 * @param source the file to parse
111 * @return the resulting DOM4J document
112 * @throws DocumentException when an error occurs while parsing
113 * @throws IOException when an error occurs while writing to the {@link org.dom4j.io.XMLWriter}
114 */
115 public Document modify(File source) throws DocumentException, IOException {
116 return installModifier().modify(source);
117 }
118
119 /***
120 * Parses the specified {@link java.io.File} with SAX,
121 * using the given {@link java.nio.charset.Charset}.
122 *
123 * @param source the file to parse
124 * @param charset the character set to use
125 * @return the resulting DOM4J document
126 * @throws DocumentException when an error occurs while parsing
127 * @throws IOException when an error occurs while writing to the {@link org.dom4j.io.XMLWriter}
128 */
129 public Document modify(File source, Charset charset) throws DocumentException, IOException {
130 try {
131 return installModifier().modify(new InputStreamReader(new FileInputStream(source), charset));
132 }
133 catch (JAXBRuntimeException ex) {
134 Throwable cause = ex.getCause();
135 throw new DocumentException(cause.getMessage(), cause);
136 }
137 catch (FileNotFoundException ex) {
138 throw new DocumentException(ex.getMessage(), ex);
139 }
140 }
141
142 /***
143 * Parses the specified {@link org.xml.sax.InputSource} with SAX.
144 *
145 * @param source the input source to parse
146 * @return the resulting DOM4J document
147 * @throws DocumentException when an error occurs while parsing
148 * @throws IOException when an error occurs while writing to the {@link org.dom4j.io.XMLWriter}
149 */
150 public Document modify(InputSource source) throws DocumentException, IOException {
151 try {
152 return installModifier().modify(source);
153 }
154 catch (JAXBRuntimeException ex) {
155 Throwable cause = ex.getCause();
156 throw new DocumentException(cause.getMessage(), cause);
157 }
158 }
159
160 /***
161 * Parses the specified {@link java.io.InputStream} with SAX.
162 *
163 * @param source the inputstream to parse
164 * @return the resulting DOM4J document
165 * @throws DocumentException when an error occurs while parsing
166 * @throws IOException when an error occurs while writing to the {@link org.dom4j.io.XMLWriter}
167 */
168 public Document modify(InputStream source) throws DocumentException, IOException {
169 try {
170 return installModifier().modify(source);
171 }
172 catch (JAXBRuntimeException ex) {
173 Throwable cause = ex.getCause();
174 throw new DocumentException(cause.getMessage(), cause);
175 }
176 }
177
178 /***
179 * Parses the specified {@link java.io.InputStream} with SAX.
180 *
181 * @param source the inputstream to parse
182 * @param systemId the URI of the given inputstream
183 * @return the resulting DOM4J document
184 * @throws DocumentException when an error occurs while parsing
185 * @throws IOException when an error occurs while writing to the {@link org.dom4j.io.XMLWriter}
186 */
187 public Document modify(InputStream source, String systemId) throws DocumentException, IOException {
188 try {
189 return installModifier().modify(source);
190 }
191 catch (JAXBRuntimeException ex) {
192 Throwable cause = ex.getCause();
193 throw new DocumentException(cause.getMessage(), cause);
194 }
195 }
196
197 /***
198 * Parses the specified {@link java.io.Reader} with SAX.
199 *
200 * @param source the reader to use for parsing
201 * @return the resulting DOM4J document
202 * @throws DocumentException when an error occurs while parsing
203 * @throws IOException when an error occurs while writing to the {@link org.dom4j.io.XMLWriter}
204 */
205 public Document modify(Reader source) throws DocumentException, IOException {
206 try {
207 return installModifier().modify(source);
208 }
209 catch (JAXBRuntimeException ex) {
210 Throwable cause = ex.getCause();
211 throw new DocumentException(cause.getMessage(), cause);
212 }
213 }
214
215 /***
216 * Parses the specified {@link java.io.Reader} with SAX.
217 *
218 * @param source the reader to parse
219 * @param systemId the URI of the given reader
220 * @return the resulting DOM4J document
221 * @throws DocumentException when an error occurs while parsing
222 * @throws IOException when an error occurs while writing to the {@link org.dom4j.io.XMLWriter}
223 */
224 public Document modify(Reader source, String systemId) throws DocumentException, IOException {
225 try {
226 return installModifier().modify(source);
227 }
228 catch (JAXBRuntimeException ex) {
229 Throwable cause = ex.getCause();
230 throw new DocumentException(cause.getMessage(), cause);
231 }
232 }
233
234 /***
235 * Parses the the given URL or filename.
236 *
237 * @param source the URL or filename to parse
238 * @return the resulting DOM4J document
239 * @throws DocumentException when an error occurs while parsing
240 * @throws IOException when an error occurs while writing to the {@link org.dom4j.io.XMLWriter}
241 */
242 public Document modify(String source) throws DocumentException, IOException {
243 try {
244 return installModifier().modify(source);
245 }
246 catch (JAXBRuntimeException ex) {
247 Throwable cause = ex.getCause();
248 throw new DocumentException(cause.getMessage(), cause);
249 }
250 }
251
252 /***
253 * Parses the the given URL.
254 *
255 * @param source the URL to parse
256 * @return the resulting DOM4J document
257 * @throws DocumentException when an error occurs while parsing
258 * @throws IOException when an error occurs while writing to the {@link org.dom4j.io.XMLWriter}
259 */
260 public Document modify(URL source) throws DocumentException, IOException {
261 try {
262 return installModifier().modify(source);
263 }
264 catch (JAXBRuntimeException ex) {
265 Throwable cause = ex.getCause();
266 throw new DocumentException(cause.getMessage(), cause);
267 }
268 }
269
270 /***
271 * Sets the Output to write the (modified) xml document to.
272 *
273 * @param file the {@link java.io.File} to write to
274 * @throws IOException when the file cannot be found or when the outputformat
275 */
276 public void setOutput(File file) throws IOException {
277 createXMLWriter().setOutputStream(new FileOutputStream(file));
278 }
279
280 /***
281 * Sets the Output to write the (modified) xml document to.
282 *
283 * @param outputStream the {@link java.io.OutputStream} to write to
284 * @throws IOException when an error occurs
285 */
286 public void setOutput(OutputStream outputStream) throws IOException {
287 createXMLWriter().setOutputStream(outputStream);
288 }
289
290 /***
291 * Sets the Output to write the (modified) xml document to.
292 *
293 * @param writer the {@link java.io.Writer} to write to
294 * @throws IOException when an error occurs
295 */
296 public void setOutput(Writer writer) throws IOException {
297 createXMLWriter().setWriter(writer);
298 }
299
300 /***
301 * Adds the {@link JAXBObjectModifier} to be called
302 * when the specified xml path is encounted while parsing the source.
303 *
304 * @param path the element path to listen for
305 * @param modifier the modifier to register
306 */
307 public void addObjectModifier(String path, JAXBObjectModifier modifier) {
308 modifiers.put(path, modifier);
309 }
310
311 /***
312 * Removes the {@link JAXBObjectModifier} from the event based processor,
313 * for the specified element path.
314 *
315 * @param path the xml path to remove the modifier for
316 */
317 public void removeObjectModifier(String path) {
318 modifiers.remove(path);
319 getModifier().removeModifier(path);
320 }
321
322 /***
323 * Removes all registered {@link JAXBObjectModifier} instances from the event based processor.
324 */
325 public void resetObjectModifiers() {
326 modifiers.clear();
327 getModifier().resetModifiers();
328 }
329
330 /***
331 * Returns true when the modified {@link org.dom4j.Document} is not kept in memory.
332 *
333 * @return Returns true if elements are pruned.
334 */
335 public boolean isPruneElements() {
336 return pruneElements;
337 }
338
339 /***
340 * Define whether the modified {@link org.dom4j.Document} must only be written
341 * to the output and pruned from the DOM4J tree.
342 *
343 * @param pruneElements When true, elements will not be kept in memory
344 */
345 public void setPruneElements(boolean pruneElements) {
346 this.pruneElements = pruneElements;
347 }
348
349 private SAXModifier installModifier() throws IOException {
350 modifier = new SAXModifier(isPruneElements());
351
352 modifier.resetModifiers();
353 Iterator modifierIt = modifiers.entrySet().iterator();
354 while( modifierIt.hasNext() ){
355 Map.Entry entry = (Map.Entry)modifierIt.next();
356 getModifier().addModifier((String)entry.getKey(), new JAXBElementModifier(this, (JAXBObjectModifier)entry.getValue()));
357 }
358
359 modifier.setXMLWriter(getXMLWriter());
360
361 return modifier;
362 }
363
364 private SAXModifier getModifier() {
365 if (this.modifier == null) {
366 modifier = new SAXModifier(isPruneElements());
367 }
368 return modifier;
369 }
370
371 private XMLWriter getXMLWriter() {
372 return xmlWriter;
373 }
374
375 private XMLWriter createXMLWriter() throws IOException {
376 if (this.xmlWriter == null) {
377 xmlWriter = new XMLWriter(outputFormat);
378 }
379 return xmlWriter;
380 }
381
382 private class JAXBElementModifier implements ElementModifier {
383
384 private JAXBModifier jaxbModifier;
385 private JAXBObjectModifier objectModifier;
386
387 public JAXBElementModifier(JAXBModifier jaxbModifier, JAXBObjectModifier objectModifier) {
388 this.jaxbModifier = jaxbModifier;
389 this.objectModifier = objectModifier;
390 }
391
392 public org.dom4j.Element modifyElement(org.dom4j.Element element) throws Exception {
393 javax.xml.bind.Element originalObject = jaxbModifier.unmarshal(element);
394 javax.xml.bind.Element modifiedObject = objectModifier.modifyObject(originalObject);
395 return jaxbModifier.marshal(modifiedObject);
396 }
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
437
438
439
440
441
442
443
444
445
446
447