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  */