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