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