Home » Castor-1.3-src » org.exolab.castor » xml » [javadoc | source]

    1   /**
    2    * Redistribution and use of this software and associated documentation
    3    * ("Software"), with or without modification, are permitted provided
    4    * that the following conditions are met:
    5    *
    6    * 1. Redistributions of source code must retain copyright
    7    *    statements and notices.  Redistributions must also contain a
    8    *    copy of this document.
    9    *
   10    * 2. Redistributions in binary form must reproduce the
   11    *    above copyright notice, this list of conditions and the
   12    *    following disclaimer in the documentation and/or other
   13    *    materials provided with the distribution.
   14    *
   15    * 3. The name "Exolab" must not be used to endorse or promote
   16    *    products derived from this Software without prior written
   17    *    permission of Intalio, Inc.  For written permission,
   18    *    please contact info@exolab.org.
   19    *
   20    * 4. Products derived from this Software may not be called "Exolab"
   21    *    nor may "Exolab" appear in their names without prior written
   22    *    permission of Intalio, Inc. Exolab is a registered
   23    *    trademark of Intalio, Inc.
   24    *
   25    * 5. Due credit should be given to the Exolab Project
   26    *    (http://www.exolab.org/).
   27    *
   28    * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
   29    * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
   30    * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
   31    * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
   32    * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
   33    * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   34    * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   35    * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   36    * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   37    * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   38    * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   39    * OF THE POSSIBILITY OF SUCH DAMAGE.
   40    *
   41    * Copyright 1999-2004 (C) Intalio, Inc. All Rights Reserved.
   42    *
   43    * $Id: Unmarshaller.java 8057 2009-02-05 22:26:22Z jgrueneis $
   44    */
   45   
   46   package org.exolab.castor.xml;
   47   
   48   import java.io.PrintWriter;
   49   import java.io.Reader;
   50   import java.util.HashMap;
   51   import java.util.Iterator;
   52   import java.util.StringTokenizer;
   53   
   54   import org.apache.commons.logging.Log;
   55   import org.apache.commons.logging.LogFactory;
   56   import org.castor.mapping.BindingType;
   57   import org.castor.mapping.MappingUnmarshaller;
   58   import org.castor.xml.BackwardCompatibilityContext;
   59   import org.castor.xml.InternalContext;
   60   import org.castor.xml.UnmarshalListenerAdapter;
   61   import org.castor.xml.XMLProperties;
   62   import org.exolab.castor.mapping.Mapping;
   63   import org.exolab.castor.mapping.MappingException;
   64   import org.exolab.castor.mapping.MappingLoader;
   65   import org.exolab.castor.types.AnyNode;
   66   import org.exolab.castor.util.ObjectFactory;
   67   import org.exolab.castor.xml.location.FileLocation;
   68   import org.exolab.castor.xml.util.AnyNode2SAX2;
   69   import org.exolab.castor.xml.util.DOMEventProducer;
   70   import org.w3c.dom.Node;
   71   import org.xml.sax.ContentHandler;
   72   import org.xml.sax.EntityResolver;
   73   import org.xml.sax.InputSource;
   74   import org.xml.sax.Parser;
   75   import org.xml.sax.SAXException;
   76   import org.xml.sax.XMLReader;
   77   
   78   /**
   79    * An unmarshaller to allowing unmarshalling of XML documents to
   80    * Java Objects. The Class must specify
   81    * the proper access methods (setters/getters) in order for instances
   82    * of the Class to be properly unmarshalled.
   83    *
   84    * @author <a href="mailto:kvisco-at-intalio.com">Keith Visco</a>
   85    * @version $Revision: 8057 $ $Date: 2006-02-23 14:16:51 -0700 (Thu, 23 Feb 2006) $
   86    */
   87   public class Unmarshaller {
   88   
   89       /**
   90        * Logger from commons-logging.
   91        */
   92       private static final Log LOG = LogFactory.getLog(Unmarshaller.class);
   93   
   94       //----------------------------/
   95       //- Private Member Variables -/
   96       //----------------------------/
   97   
   98       /**
   99        * The Class that this Unmarshaller was created with.
  100        */
  101       private Class _class = null;
  102   
  103       /**
  104        * A boolean indicating whether or not collections (including
  105        * arrays) should be cleared upon initial use by Castor.
  106        * False by default for backward compatibility.
  107        */
  108        private boolean _clearCollections = false;    
  109   
  110       /**
  111        * A user specified IDResolver for resolving IDREFs.
  112        */
  113       private IDResolver _idResolver = null;
  114   
  115       /**
  116        * A boolean that specifies whether or not
  117        * non-matched attributes should be ignored upon
  118        * unmarshalling.
  119        */
  120       private boolean _ignoreExtraAtts = true;
  121   
  122       /**
  123        * A boolean that specifies whether or not
  124        * non-matched elements should be ignored upon
  125        * unmarshalling.
  126        */
  127       private boolean _ignoreExtraElements = false;
  128   
  129       /**
  130        * The instance of _class to Unmarshal into (optional)
  131        */
  132       private Object _instanceObj = null;
  133   
  134       /**
  135        * The EntityResolver used for resolving entities
  136        */
  137       EntityResolver entityResolver = null;
  138   
  139       /**
  140        * The class loader to use
  141        */
  142       private ClassLoader _loader = null;
  143   
  144       /**
  145        * A boolean to indicate that objects should
  146        * be re-used where appropriate
  147        */
  148       private boolean _reuseObjects = false;
  149   
  150       
  151       /**
  152        * The unmarshaller listener that listens to unmarshalling event
  153        */
  154       private org.castor.xml.UnmarshalListener _unmarshalListener = null;
  155   
  156       /**
  157        * The flag indicating whether or not to validate during
  158        * unmarshalling
  159        */
  160       private boolean _validate = false;
  161   
  162       /**
  163        * A flag indicating the unmarshaller should preserve 
  164        * "ignorable" whitespace. The XML instance can
  165        * control it's own behavior using the xml:space
  166        * attribute. This sets the "default" behavior
  167        * when xml:space="default".
  168        */
  169       private boolean _wsPreserve = false;
  170       
  171       /**
  172        * A list of namespace To Package Mappings
  173        */
  174       private HashMap _namespaceToPackage = null;
  175   
  176       /**
  177        * An optional factory for unmarshalling objects
  178        */
  179       private ObjectFactory _objectFactory;
  180   
  181       /** 
  182        * The Castor XML context to use at unmarshalling. 
  183        */
  184       private InternalContext _internalContext;
  185       
  186       //----------------/
  187       //- Constructors -/
  188       //----------------/
  189   
  190       /**
  191        * An empty default constructor which:
  192        * - sets the internal context to the backward compatibility context
  193        * - all other flags to defaults
  194        * Internally the Unmarshaller(Class) constructor is called.
  195        */
  196       public Unmarshaller() {
  197           this((Class) null);
  198       }
  199   
  200       /**
  201        * A constructor which sets the root class.
  202        * 
  203        * Internally calls constructor Unmarshaller(InternalContext, Class) with
  204        * an instance of BackwardCompatibilityContext as context.
  205        * 
  206        * @param clazz root class for unmarshalling
  207        */
  208       public Unmarshaller(final Class clazz) {
  209           this(new BackwardCompatibilityContext(), clazz);
  210       }
  211   
  212       /**
  213        * Creates a new basic Unmarshaller.
  214        *
  215        * When using this constructor it will most likely be
  216        * necessary to use a mapping file or ClassDescriptorResolver
  217        * So that the Unmarshaller can find the classes during the
  218        * unmarshalling process.
  219        * 
  220        * @param internalContext the {@link InternalContext} to use
  221        */
  222       public Unmarshaller(final InternalContext internalContext) {
  223           this(internalContext, (Class) null, (ClassLoader) null);
  224       }
  225   
  226       /**
  227        * Creates a new Unmarshaller with the given Class.
  228        * 
  229        * @param internalContext the {@link InternalContext} to use
  230        * @param c the Class to create the Unmarshaller for, this
  231        * may be null, if the Unmarshaller#setMapping is called
  232        * to load a mapping for the root element of xml document.
  233        */
  234       public Unmarshaller(final InternalContext internalContext, final Class c) {
  235           this(internalContext, c, null);
  236       } //-- Unmarshaller(Class)
  237   
  238       /**
  239        * Creates a new {@link Unmarshaller} with the given Class.
  240        *
  241        * @param internalContext the {@link InternalContext} to be used, for config, and such...
  242        * @param c the {@link Class} to create the {@link Unmarshaller} for, this
  243        * may be null, if the Unmarshaller#setMapping is called
  244        * to load a mapping for the root element of xml document.
  245        * @param loader The {@link ClassLoader} to use.
  246        */
  247       public Unmarshaller(
  248               final InternalContext internalContext, 
  249               final Class c, final ClassLoader loader) {
  250           super();
  251           if (internalContext == null) {
  252               String message = "InternalContext must not be null";
  253               LOG.warn(message);
  254               throw new IllegalArgumentException(message);
  255           }
  256           setInternalContext(internalContext);
  257   
  258           setClass(c);
  259           _loader = loader;
  260           if ((loader == null) && (c != null)) {
  261               _loader = c.getClassLoader();
  262           }
  263           _internalContext.setClassLoader(_loader);
  264       }
  265   
  266       /**
  267        * Creates a new Unmarshaller with the given Mapping.
  268        * An instance of BackwardsCompatibilityContext is used as InternalContext.
  269        *
  270        * @param mapping The Mapping to use.
  271        * @throws MappingException in case that Unmarshaller fails to be instantiated 
  272        */
  273       public Unmarshaller(final Mapping mapping) throws MappingException {
  274           this(new BackwardCompatibilityContext(), mapping);
  275       }
  276   
  277       /**
  278        * Creates a new Unmarshaller with the given Mapping.
  279        *
  280        * @param internalContext the internal context to use
  281        * @param mapping The Mapping to use.
  282        * @throws MappingException in case that Unmarshaller fails to be instantiated 
  283        */
  284       public Unmarshaller(final InternalContext internalContext, final Mapping mapping)
  285       throws MappingException {
  286           this(internalContext, null, null);
  287           if (mapping != null) {
  288               setMapping(mapping);
  289               this._loader = mapping.getClassLoader();
  290           }
  291       }
  292   
  293       /**
  294        * Creates a new Unmarshaller with the given Object.
  295        *
  296        * @param root the instance to unmarshal into. This
  297        * may be null, if the Unmarshaller#setMapping is called
  298        * to load a mapping for the root element of xml document.
  299        */
  300       public Unmarshaller(final Object root) {
  301           this(new BackwardCompatibilityContext(), root);
  302       }
  303   
  304       /**
  305        * Creates a new Unmarshaller with the given Object.
  306        *
  307        * @param internalContext the internal context to use
  308        * @param root the instance to unmarshal into. This
  309        * may be null, if the Unmarshaller#setMapping is called
  310        * to load a mapping for the root element of xml document.
  311        */
  312       public Unmarshaller(final InternalContext internalContext, final Object root) {
  313           this(internalContext, null, null);
  314           if (root != null) {
  315               final Class clazz = root.getClass();
  316               setClass(clazz);
  317               _loader = clazz.getClassLoader();
  318           }
  319           _instanceObj = root;
  320       }
  321       
  322       /**
  323        * Adds a mapping from the given namespace URI to the given
  324        * package name.
  325        * 
  326        * @param nsURI the namespace URI to map from
  327        * @param packageName the package name to map to
  328        */
  329       public void addNamespaceToPackageMapping(final String nsURI, final String packageName) {
  330           if (_namespaceToPackage == null) {
  331               _namespaceToPackage = new HashMap();
  332           }
  333           String iNsUri = (nsURI == null) ? "" : nsURI;
  334           String iPackageName = (packageName == null) ? "" : packageName;
  335           _namespaceToPackage.put(iNsUri, iPackageName);
  336           
  337       } //-- addNamespaceToPackageMapping
  338       
  339   
  340       /**
  341        * Creates and initalizes an UnmarshalHandler
  342        * @return the new UnmarshalHandler
  343       **/
  344       public UnmarshalHandler createHandler() {
  345   
  346           UnmarshalHandler handler = new UnmarshalHandler(_internalContext, _class);
  347           
  348           handler.setClearCollections(_clearCollections);
  349           handler.setReuseObjects(_reuseObjects);
  350           handler.setValidation(_validate);
  351           handler.setIgnoreExtraAttributes(_ignoreExtraAtts);
  352           handler.setIgnoreExtraElements(_ignoreExtraElements);
  353           handler.setInternalContext(_internalContext);
  354           handler.setWhitespacePreserve(_wsPreserve);
  355           
  356           // If the object factory has been set, set it on the handler
  357           if (this._objectFactory != null) {
  358           	handler.setObjectFactory(this._objectFactory);
  359           }
  360   
  361           //-- copy namespaceToPackageMappings
  362           if (_namespaceToPackage != null) {
  363           	Iterator keys = _namespaceToPackage.keySet().iterator();
  364               while (keys.hasNext()) {
  365                   String nsURI = (String)keys.next();
  366                   String pkgName = (String) _namespaceToPackage.get(nsURI);
  367               	handler.addNamespaceToPackageMapping(nsURI, pkgName);
  368               }
  369           }
  370   
  371           if (_instanceObj != null) {
  372               handler.setRootObject(_instanceObj);
  373           }
  374           if (_idResolver != null)
  375               handler.setIDResolver(_idResolver);
  376   
  377           if (_loader != null)
  378               handler.setClassLoader(_loader);
  379   
  380           if (_unmarshalListener != null)
  381               handler.setUnmarshalListener(_unmarshalListener);
  382   
  383           return handler;
  384       } //-- createHandler
  385       
  386       /**
  387        * Indicates whether or not validation should be performed during umarshalling.
  388        * @return True if validation is performed during umarshalling.
  389        */
  390       public boolean isValidating() {
  391           return _validate;
  392       }
  393   
  394       /**
  395        * Sets the 'expected' {@link Class} instance on the Unmarshaller.
  396        *
  397        * @param clazz the Class to create the Unmarshaller for, this
  398        * may be null, if the Unmarshaller#setMapping is called
  399        * to load a mapping for the root element of xml document.
  400        */
  401       public void setClass(Class clazz) {
  402           _class = clazz;
  403       } //-- setClass(Class)
  404   
  405       /**
  406        * Sets the 'expected' {@link Object} instance on the Unmarshaller, into
  407        * which will be unmarshalled.
  408        *
  409        * @param root the instance to unmarshal into. This
  410        * may be null, if the Unmarshaller#setMapping is called
  411        * to load a mapping for the root element of xml document.
  412        */
  413       public void setObject(Object root) {
  414           _instanceObj = root;
  415       } //-- setObject(Object)
  416       
  417       /**
  418        * Sets the ClassLoader to use when loading new classes.
  419        * <br />
  420        * <b>Note:</b>This ClassLoader is used for classes
  421        * loaded by the unmarshaller only. If a Mapping has
  422        * been set, the Mapping has it's own ClassLoader and
  423        * may also need to be set propertly.
  424        * <br />
  425        *
  426        * @param loader the ClassLoader to use
  427       **/
  428       public void setClassLoader(ClassLoader loader) {
  429           this._loader = loader;
  430       } //-- setClassLoader
  431   
  432   
  433       /**
  434        * Sets whether or not to clear collections (including arrays)
  435        * upon first use to remove default values. By default, and
  436        * for backward compatibility with previous versions of Castor
  437        * this value is false, indicating that collections are not
  438        * cleared before initial use by Castor.
  439        *
  440        * @param clear the boolean value that when true indicates
  441        * collections should be cleared upon first use.
  442        */
  443       public void setClearCollections(boolean clear) {
  444           _clearCollections = clear;
  445       } //-- setClearCollections
  446   
  447       /**
  448   	 * Custom debugging is replaced with commons-logging
  449        * @deprecated
  450       **/
  451       public void setDebug(boolean debug) {
  452       	//  no-op
  453       } //-- setDebug
  454   
  455       /**
  456        * Sets the EntityResolver to use when resolving system and
  457        * public ids with respect to entites and Document Type.
  458        * @param entityResolver the EntityResolver to use when
  459        * resolving System and Public ids.
  460       **/
  461       public void setEntityResolver(EntityResolver entityResolver) {
  462           this.entityResolver = entityResolver;
  463       } //-- entityResolver
  464   
  465       /**
  466        * Sets the IDResolver to use when resolving IDREFs for
  467        * which no associated element may exist in XML document.
  468        *
  469        * @param idResolver the IDResolver to use when resolving
  470        * IDREFs for which no associated element may exist in the
  471        * XML document.
  472       **/
  473       public void setIDResolver(IDResolver idResolver) {
  474           _idResolver = idResolver;
  475       } //-- idResolver
  476   
  477       /**
  478        * Sets whether or not attributes that do not match
  479        * a specific field should simply be ignored or
  480        * reported as an error. By default, extra attributes
  481        * are ignored.
  482        *
  483        * @param ignoreExtraAtts a boolean that when true will
  484        * allow non-matched attributes to simply be ignored.
  485        */
  486       public void setIgnoreExtraAttributes(boolean ignoreExtraAtts) {
  487           _ignoreExtraAtts = ignoreExtraAtts;
  488       } //-- setIgnoreExtraAttributes
  489   
  490       /**
  491        * Sets whether or not elements that do not match
  492        * a specific field should simply be ignored or
  493        * reported as an error. By default, extra elements
  494        * are flagged as an error.
  495        *
  496        * @param ignoreExtraElements a boolean that when true will
  497        * allow non-matched elements to simply be ignored.
  498        */
  499       public void setIgnoreExtraElements(boolean ignoreExtraElements) {
  500           _ignoreExtraElements = ignoreExtraElements;
  501       } //-- setIgnoreExtraElements
  502   
  503       /**
  504        * Logging is replaced with commons-logging.
  505        * @param printWriter the PrintWriter to use for logging
  506        * @deprecated
  507       **/
  508       public void setLogWriter(PrintWriter printWriter) {
  509   		// no-op
  510       } //-- setLogWriter
  511   
  512       /**
  513        * Sets the Mapping to use during unmarshalling. If the Mapping has a ClassLoader it
  514        * will be used during unmarshalling.
  515        *
  516        * @param mapping Mapping to use during unmarshalling.
  517        * @see #setResolver
  518        */
  519       public void setMapping(final Mapping mapping) throws MappingException {
  520           if (_loader == null) {
  521               _loader = mapping.getClassLoader();
  522           }
  523           
  524           MappingUnmarshaller mum = new MappingUnmarshaller();
  525           MappingLoader resolver = mum.getMappingLoader(mapping, BindingType.XML);
  526           _internalContext.getXMLClassDescriptorResolver().setMappingLoader(resolver);
  527       }
  528   
  529       /**
  530        * Sets a boolean that when true indicates that objects
  531        * contained within the object model should be re-used
  532        * where appropriate. This is only valid when unmarshalling
  533        * to an existing object.
  534        *
  535        * @param reuse the boolean indicating whether or not
  536        * to re-use existing objects in the object model.
  537       **/
  538       public void setReuseObjects(boolean reuse) {
  539           _reuseObjects = reuse;
  540       } //-- setReuseObjects
  541   
  542       /**
  543        * Sets an optional {@link org.exolab.castor.xml.UnmarshalListener} to receive pre and
  544        * post unmarshal notification for each Object in the tree.
  545        * An UnmarshalListener is often used to allow objects to
  546        * appropriately initialize themselves by taking application
  547        * specific behavior as they are unloaded.
  548        * Current only one (1) listener is allowed. If you need
  549        * register multiple listeners, you will have to create
  550        * your own master listener that will forward the
  551        * event notifications and manage the multiple
  552        * listeners.<br/>
  553        * The deprecated listener set with this method will be wrapped by an
  554        * adapter.
  555        *
  556        * @param listener the {@link org.exolab.castor.xml.UnmarshalListener} to set.
  557        * @deprecated replaced by {@link org.castor.xml.UnmarshalListener}
  558        */
  559       public void setUnmarshalListener(org.exolab.castor.xml.UnmarshalListener listener) {
  560           if (listener == null) {
  561               _unmarshalListener = null;
  562           } else {
  563               UnmarshalListenerAdapter adapter = new UnmarshalListenerAdapter();
  564               adapter.setOldListener(listener);
  565               _unmarshalListener = adapter;
  566           }
  567       }
  568   
  569       /**
  570        * Sets an optional {@link org.castor.xml.UnmarshalListener} to receive pre and
  571        * post unmarshal notification for each Object in the tree.
  572        * An UnmarshalListener is often used to allow objects to
  573        * appropriately initialize themselves by taking application
  574        * specific behavior as they are unloaded.
  575        * Current only one (1) listener is allowed. If you need
  576        * register multiple listeners, you will have to create
  577        * your own master listener that will forward the
  578        * event notifications and manage the multiple
  579        * listeners.
  580        *
  581        * @param listener the {@link org.castor.xml.UnmarshalListener} to set.
  582        */
  583       public void setUnmarshalListener(org.castor.xml.UnmarshalListener listener) {
  584           _unmarshalListener = listener;
  585       }
  586   
  587       /**
  588        * Sets the flag for validation.
  589        * 
  590        * @param validate A boolean to indicate whether or not validation should be done
  591        *        during umarshalling.
  592        *        <br/>
  593        *        By default validation will be performed.
  594        */
  595       public void setValidation(boolean validate) {
  596           _validate = validate;
  597       } //-- setValidation
  598   
  599       /**
  600        * Sets the top-level whitespace (xml:space) to either
  601        * preserving or non preserving. The XML document
  602        * can override this value using xml:space on specific
  603        * elements.This sets the "default" behavior
  604        * when xml:space="default".
  605        *
  606        * @param preserve a boolean that when true enables
  607        * whitespace preserving by default. 
  608        */
  609       public void setWhitespacePreserve(boolean preserve) {
  610           _wsPreserve = preserve;
  611       } //-- setWhitespacePreserve
  612   
  613       /**
  614        * Unmarshals Objects of this Unmarshaller's Class type.
  615        * The Class must specify the proper access methods
  616        * (setters/getters) in order for instances of the Class
  617        * to be properly unmarshalled.
  618        * @param reader the Reader to read the XML from
  619        * @exception MarshalException when there is an error during
  620        * the unmarshalling process
  621        * @exception ValidationException when there is a validation error
  622       **/
  623       public Object unmarshal(Reader reader)
  624           throws MarshalException, ValidationException
  625       {
  626           return unmarshal(new InputSource(reader));
  627       } //-- unmarshal(Reader reader)
  628   
  629       /**
  630        * Unmarshals Objects of this Unmarshaller's Class type.
  631        * The Class must specify the proper access methods
  632        * (setters/getters) in order for instances of the Class
  633        * to be properly unmarshalled.
  634        * @param eventProducer the EventProducer which produces
  635        * the SAX events
  636        * @exception MarshalException when there is an error during
  637        * the unmarshalling process
  638        * @exception ValidationException when there is a validation error
  639        * @deprecated please use @see #unmarshal(SAX2EventProducer) instead. 
  640       **/
  641       public Object unmarshal(EventProducer eventProducer)
  642           throws MarshalException, ValidationException
  643       {
  644           UnmarshalHandler handler = createHandler();
  645           eventProducer.setDocumentHandler(handler);
  646           try {
  647               eventProducer.start();
  648           }
  649           catch(org.xml.sax.SAXException sx) {
  650               convertSAXExceptionToMarshalException(handler, sx);
  651           }
  652           return handler.getObject();
  653   
  654       } //-- unmarshal(EventProducer)
  655   
  656       /**
  657        * Unmarshals Objects of this Unmarshaller's Class type.
  658        * The Class must specify the proper access methods
  659        * (setters/getters) in order for instances of the Class
  660        * to be properly unmarshalled.
  661        * @param eventProducer the SAX2EventProducer instance which produces
  662        * the SAX 2 events
  663        * @exception MarshalException when there is an error during
  664        * the unmarshalling process
  665        * @exception ValidationException when there is a validation error
  666        * @since 1.0M3
  667       **/
  668       public Object unmarshal(SAX2EventProducer eventProducer)
  669           throws MarshalException, ValidationException
  670       {
  671           UnmarshalHandler handler = createHandler();
  672           eventProducer.setContentHandler(handler);
  673           try {
  674               eventProducer.start();
  675           }
  676           catch(org.xml.sax.SAXException sx) {
  677               convertSAXExceptionToMarshalException(handler, sx);
  678           }
  679           return handler.getObject();
  680   
  681       } //-- unmarshal(SAX2EventProducer)
  682   
  683       /**
  684        * Unmarshals objects of this {@link Unmarshaller}'s Class type
  685        * from an {@link AnyNode} instance.
  686        * 
  687        * The Class must specify the proper access methods
  688        * (setters/getters) in order for instances of the Class
  689        * to be properly unmarshalled.
  690        * 
  691        * @param anyNode {@link AnyNode} instance to be unmarshalled from
  692        * @exception MarshalException when there is an error during
  693        * the unmarshalling process
  694        * @return The {@link Object} instance that is a result of unmarshalling.
  695        **/
  696       public Object unmarshal(final AnyNode anyNode)
  697       throws MarshalException {
  698           UnmarshalHandler handler = createHandler();
  699           try {
  700               AnyNode2SAX2.fireEvents(anyNode, handler);
  701           } catch (SAXException sex) {
  702               convertSAXExceptionToMarshalException(handler, sex);       
  703           }
  704           return handler.getObject();
  705       }
  706   
  707       /**
  708        * Unmarshals Objects of this Unmarshaller's Class type.
  709        * The Class must specify the proper access methods
  710        * (setters/getters) in order for instances of the Class
  711        * to be properly unmarshalled.
  712        * @param source the InputSource to read the XML from
  713        * @exception MarshalException when there is an error during
  714        * the unmarshalling process
  715        * @exception ValidationException when there is a validation error
  716       **/
  717       public Object unmarshal(InputSource source)
  718           throws MarshalException, ValidationException
  719       {
  720           XMLReader reader = null;
  721           Parser parser = null;
  722           
  723           //-- First try XMLReader
  724           try {
  725               reader = _internalContext.getXMLReader();
  726               if (entityResolver != null)
  727                   reader.setEntityResolver(entityResolver);
  728           } catch (RuntimeException rx) {
  729           	LOG.debug("Unable to create SAX XMLReader, attempting SAX Parser.");
  730           }
  731           
  732           if (reader == null) {
  733               parser = _internalContext.getParser();
  734               if (parser == null)
  735                   throw new MarshalException("Unable to create SAX Parser.");
  736               if (entityResolver != null)
  737                   parser.setEntityResolver(entityResolver);
  738           }
  739   
  740   
  741           UnmarshalHandler handler = createHandler();
  742           
  743   
  744           try {
  745               if (reader != null) {
  746                   reader.setContentHandler(handler);
  747                   reader.setErrorHandler(handler);
  748                   reader.parse(source);
  749               }
  750               else {
  751                   parser.setDocumentHandler(handler);
  752                   parser.setErrorHandler(handler);
  753                   parser.parse(source);
  754               }
  755           }
  756           catch (java.io.IOException ioe) {
  757               throw new MarshalException(ioe);
  758           }
  759           catch (org.xml.sax.SAXException sx) {
  760               convertSAXExceptionToMarshalException(handler, sx);
  761           }
  762   
  763           return handler.getObject();
  764       } //-- unmarshal(InputSource)
  765   
  766   
  767       /**
  768        * Unmarshals Objects of this Unmarshaller's Class type.
  769        * The Class must specify the proper access methods
  770        * (setters/getters) in order for instances of the Class
  771        * to be properly unmarshalled.
  772        * @param node the DOM node to read the XML from
  773        * @exception MarshalException when there is an error during
  774        * the unmarshalling process
  775        * @exception ValidationException when there is a validation error
  776       **/
  777       public Object unmarshal(Node node)
  778           throws MarshalException, ValidationException
  779       {
  780   		return unmarshal(new DOMEventProducer(node));
  781       } //-- unmarshal(EventProducer)
  782   
  783       /**
  784        * Converts a SAXException to a (localised) MarshalException.
  785        * @param handler The {@link UnmarshalHandler} required to obtain DocumentLocator instance.
  786        * @param sex The {@link SAXException} instance
  787        * @throws MarshalException The {@link MarshalException} instance derived from the SAX exception.
  788        */
  789       private void convertSAXExceptionToMarshalException(UnmarshalHandler handler, SAXException sex) throws MarshalException {
  790           Exception except = sex.getException();
  791           if (except == null) {
  792               except = sex;
  793           }
  794           MarshalException marshalEx = new MarshalException(except);
  795           if (handler.getDocumentLocator() != null) {
  796               FileLocation location = new FileLocation();
  797               location.setFilename(handler.getDocumentLocator().getSystemId());
  798               location.setLineNumber(handler.getDocumentLocator().getLineNumber());
  799               location.setColumnNumber(handler.getDocumentLocator().getColumnNumber());
  800               marshalEx.setLocation(location);
  801           }
  802           throw marshalEx;
  803       }
  804   
  805       //-------------------------/
  806       //- Public Static Methods -/
  807       //-------------------------/
  808   
  809   
  810       /**
  811        * Returns a ContentHandler for the given UnmarshalHandler
  812        *
  813        * @return the ContentHandler
  814        */
  815       public static ContentHandler getContentHandler(UnmarshalHandler handler)
  816           throws SAXException
  817       {
  818           return handler;
  819       } //-- getContentHandler
  820   
  821       /**
  822        * Unmarshals Objects of the given Class type. The Class must specify
  823        * the proper access methods (setters/getters) in order for instances
  824        * of the Class to be properly unmarshalled.
  825        *
  826        * <p><b>Note:</b>This is a *static* method, any mapping files set
  827        * on a particular Unmarshaller instance, and any changes made
  828        * via setters will be unavailable to this method.</p>
  829        *
  830        * @param c the Class to create a new instance of
  831        * @param reader the Reader to read the XML from
  832        * @exception MarshalException when there is an error during
  833        * the unmarshalling process
  834        * @exception ValidationException when there is a validation error
  835       **/
  836       public static Object unmarshal(Class c, Reader reader)
  837           throws MarshalException, ValidationException
  838       {
  839           Unmarshaller unmarshaller = createUnmarshaller(c);
  840           return unmarshaller.unmarshal(reader);
  841       } //-- void unmarshal(Writer)
  842   
  843       /**
  844        * Helper method for static #unmarshal methods to create
  845        * an {@link Unmarshaller} instance.
  846        * 
  847        * @param clazz The root class to be used during unmarshalling.
  848        * @return An {@link Unmarshaller} instance.
  849        */
  850       private static Unmarshaller createUnmarshaller(final Class clazz) {
  851           XMLContext xmlContext = new XMLContext();
  852           Unmarshaller unmarshaller = xmlContext.createUnmarshaller();
  853           unmarshaller.setClass(clazz);
  854           
  855           // TODO: Should this be at level INFO?
  856           if (LOG.isDebugEnabled()) {
  857               LOG.debug("*static* unmarshal method called, this will ignore any "
  858                       + "mapping files or changes made to an Unmarshaller instance.");
  859           }
  860           
  861           //-- for backward compatibility with Castor versions
  862           //-- prior to version 0.9.5.3
  863           unmarshaller.setWhitespacePreserve(true);
  864           
  865           return unmarshaller;
  866       }
  867   
  868       /**
  869        * Unmarshals Objects of the given Class type. The Class must specify
  870        * the proper access methods (setters/getters) in order for instances
  871        * of the Class to be properly unmarshalled.
  872        *
  873        * <p><b>Note:</b>This is a *static* method, any mapping files set
  874        * on a particular Unmarshaller instance, and any changes made
  875        * via setters will be unavailable to this method.</p>
  876        *
  877        * @param c the Class to create a new instance of
  878        * @param source the InputSource to read the XML from
  879        * @exception MarshalException when there is an error during
  880        * the unmarshalling process
  881        * @exception ValidationException when there is a validation error
  882        */
  883       public static Object unmarshal(Class c, InputSource source)
  884           throws MarshalException, ValidationException
  885       {
  886           Unmarshaller unmarshaller = createUnmarshaller(c);
  887           
  888           return unmarshaller.unmarshal(source);
  889       } //-- void unmarshal(Writer)
  890   
  891       /**
  892        * Unmarshals Objects of the given Class type. The Class must specify
  893        * the proper access methods (setters/getters) in order for instances
  894        * of the Class to be properly unmarshalled.
  895        *
  896        * <p><b>Note:</b>This is a *static* method, any mapping files set
  897        * on a particular Unmarshaller instance, and any changes made
  898        * via setters will be unavailable to this method.</p>
  899        *
  900        * @param c The Class to create a new instance of.
  901        * @param node The DOM Node to read the XML from.
  902        * @exception MarshalException When there is an error during the unmarshalling
  903        *            process.
  904        * @exception ValidationException When there is a validation error.
  905        */
  906       public static Object unmarshal(Class c, Node node)
  907       throws MarshalException, ValidationException {
  908           Unmarshaller unmarshaller = createUnmarshaller(c);
  909           
  910           return unmarshaller.unmarshal(node);
  911       } //-- void unmarshal(Writer)
  912   
  913       /**
  914        * Set an object factory for the unmarshaller. This factory will be used to
  915        * construct the objects being unmarshalled.
  916        * 
  917        * @param objectFactory
  918        *            Factory used for constructing objects during unmarshalling.
  919        */
  920       public void setObjectFactory(final ObjectFactory objectFactory) {
  921           this._objectFactory = objectFactory;
  922       } // -- setObjectFactory
  923       
  924       /**
  925        * Returns the value of the given Castor XML-specific property.
  926        * 
  927        * @param name
  928        *            Qualified name of the CASTOR XML-specific property.
  929        * @return The current value of the given property.
  930        * @since 1.1.2
  931        */
  932       public String getProperty(final String name) {
  933           Object propertyValue = _internalContext.getProperty(name);
  934           if ((propertyValue != null) && !(propertyValue instanceof String)) {
  935               String message = 
  936                   "Requested property: " + name 
  937                   + " is not of type String, but: " + propertyValue.getClass() 
  938                   + " throwing IllegalStateException.";
  939               LOG.warn(message);
  940               throw new IllegalStateException(message);
  941           }
  942           return (String) propertyValue;
  943       }
  944   
  945       /**
  946        * Sets a custom value of a given Castor XML-specific property.
  947        * 
  948        * @param name
  949        *            Name of the Castor XML property
  950        * @param value
  951        *            Custom value to set.
  952        * @since 1.1.2
  953        */
  954       public void setProperty(final String name, final String value) {
  955           _internalContext.setProperty(name, value);
  956       }
  957   
  958       /**
  959        * To set the internal XML Context to be used.
  960        * @param internalContext the context to be used
  961        */
  962       public void setInternalContext(final InternalContext internalContext) {
  963           _internalContext = internalContext;
  964           deriveProperties();
  965       }
  966   
  967       /**
  968        * Derive class-level properties from {@link XMLProperties} as defined
  969        * {@link InternalContext}. This method will be called after a new {@link InternalContext}
  970        * has been set.
  971        * @link #setInternalContext(InternalContext)
  972        */
  973       private void deriveProperties() {
  974           _validate = _internalContext.marshallingValidation();
  975           _ignoreExtraElements = (!_internalContext.strictElements());
  976           
  977           //-- process namespace to package mappings
  978           String mappings = 
  979               _internalContext.getStringProperty(XMLProperties.NAMESPACE_PACKAGE_MAPPINGS);
  980           if (mappings != null && mappings.length() > 0) {
  981               StringTokenizer tokens = new StringTokenizer(mappings, ",");
  982               while (tokens.hasMoreTokens()) {
  983                   String token = tokens.nextToken();
  984                   int sepIdx = token.indexOf('=');
  985                   if (sepIdx < 0) {
  986                       continue;
  987                   }
  988                   String ns = token.substring(0, sepIdx).trim();
  989                   String javaPackage = token.substring(sepIdx + 1).trim();
  990                   addNamespaceToPackageMapping(ns, javaPackage);
  991               }
  992           }
  993       }
  994       
  995       /**
  996        * To get the internal XML Context that is in use.
  997        * @return the {@link InternalContext} in use
  998        */
  999       public InternalContext getInternalContext() {
 1000           return _internalContext;
 1001       }
 1002       
 1003       /**
 1004        * Sets the XMLClassDescriptorResolver to use during unmarshalling
 1005        * @param xmlClassDescriptorResolver the XMLClassDescriptorResolver to use
 1006        * @see #setMapping
 1007        * <BR />
 1008        * <B>Note:</B> This method will nullify any Mapping
 1009        * currently being used by this Unmarshaller
 1010        */
 1011       public void setResolver(XMLClassDescriptorResolver xmlClassDescriptorResolver) {
 1012           _internalContext.setResolver(xmlClassDescriptorResolver);
 1013       }
 1014   } //-- Unmarshaller
 1015   

Home » Castor-1.3-src » org.exolab.castor » xml » [javadoc | source]