View Javadoc

1   /*
2    * Copyright 2001-2004 (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    * $Id: JAXBModifier.java,v 1.1 2004/08/02 18:44:07 maartenc Exp $
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  * Redistribution and use of this software and associated documentation
406  * ("Software"), with or without modification, are permitted provided
407  * that the following conditions are met:
408  *
409  * 1. Redistributions of source code must retain copyright
410  *    statements and notices.  Redistributions must also contain a
411  *    copy of this document.
412  *
413  * 2. Redistributions in binary form must reproduce the
414  *    above copyright notice, this list of conditions and the
415  *    following disclaimer in the documentation and/or other
416  *    materials provided with the distribution.
417  *
418  * 3. The name "DOM4J" must not be used to endorse or promote
419  *    products derived from this Software without prior written
420  *    permission of MetaStuff, Ltd.  For written permission,
421  *    please contact dom4j-info@metastuff.com.
422  *
423  * 4. Products derived from this Software may not be called "DOM4J"
424  *    nor may "DOM4J" appear in their names without prior written
425  *    permission of MetaStuff, Ltd. DOM4J is a registered
426  *    trademark of MetaStuff, Ltd.
427  *
428  * 5. Due credit should be given to the DOM4J Project - 
429  *    http://www.dom4j.org
430  *
431  * THIS SOFTWARE IS PROVIDED BY METASTUFF, LTD. AND CONTRIBUTORS
432  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
433  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
434  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
435  * METASTUFF, LTD. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
436  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
437  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
438  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
439  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
440  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
441  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
442  * OF THE POSSIBILITY OF SUCH DAMAGE.
443  *
444  * Copyright 2001-2004 (C) MetaStuff, Ltd. All Rights Reserved.
445  *
446  * $Id: JAXBModifier.java,v 1.1 2004/08/02 18:44:07 maartenc Exp $
447  */