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    * Portions of this file developed by Keith Visco after Jan 19 2005 are
   44    * Copyright (C) Keith Visco. All Rights Reserverd.
   45    *
   46    * $Id: UnmarshalHandler.java 8057 2009-02-05 22:26:22Z jgrueneis $
   47    */
   48   package org.exolab.castor.xml;
   49   
   50   import java.io.PrintWriter;
   51   import java.io.Serializable;
   52   import java.io.StringWriter;
   53   import java.lang.reflect.Array;
   54   import java.lang.reflect.InvocationTargetException;
   55   import java.lang.reflect.Method;
   56   import java.lang.reflect.Modifier;
   57   import java.util.ArrayList;
   58   import java.util.Enumeration;
   59   import java.util.HashMap;
   60   import java.util.Hashtable;
   61   import java.util.Iterator;
   62   import java.util.List;
   63   import java.util.Stack;
   64   import java.util.StringTokenizer;
   65   
   66   import org.apache.commons.logging.Log;
   67   import org.apache.commons.logging.LogFactory;
   68   import org.castor.core.util.Base64Decoder;
   69   import org.castor.core.util.HexDecoder;
   70   import org.castor.xml.InternalContext;
   71   import org.castor.xml.UnmarshalListenerAdapter;
   72   import org.castor.xml.XMLProperties;
   73   import org.exolab.castor.mapping.ClassDescriptor;
   74   import org.exolab.castor.mapping.ExtendedFieldHandler;
   75   import org.exolab.castor.mapping.FieldHandler;
   76   import org.exolab.castor.mapping.MapItem;
   77   import org.exolab.castor.mapping.loader.FieldHandlerImpl;
   78   import org.exolab.castor.util.DefaultObjectFactory;
   79   import org.exolab.castor.util.ObjectFactory;
   80   import org.exolab.castor.xml.descriptors.PrimitivesClassDescriptor;
   81   import org.exolab.castor.xml.descriptors.StringClassDescriptor;
   82   import org.exolab.castor.xml.util.AttributeSetImpl;
   83   import org.exolab.castor.xml.util.ContainerElement;
   84   import org.exolab.castor.xml.util.SAX2ANY;
   85   import org.exolab.castor.xml.util.XMLClassDescriptorImpl;
   86   import org.exolab.castor.xml.util.XMLFieldDescriptorImpl;
   87   import org.xml.sax.AttributeList;
   88   import org.xml.sax.Attributes;
   89   import org.xml.sax.ContentHandler;
   90   import org.xml.sax.DocumentHandler;
   91   import org.xml.sax.ErrorHandler;
   92   import org.xml.sax.Locator;
   93   import org.xml.sax.SAXException;
   94   import org.xml.sax.SAXParseException;
   95   
   96   /**
   97    * An unmarshaller to allowing unmarshaling of XML documents to
   98    * Java Objects. The Class must specify
   99    * the proper access methods (setters/getters) in order for instances
  100    * of the Class to be properly unmarshaled.
  101    * 
  102    * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
  103    * @version $Revision: 8057 $ $Date: 2006-05-25 06:41:12 -0600 (Thu, 25 May 2006) $
  104    */
  105   public final class UnmarshalHandler extends MarshalFramework
  106   implements ContentHandler, DocumentHandler, ErrorHandler {
  107       /**
  108        * Logger from commons-logging.
  109        */
  110       private static final Log LOG = LogFactory.getLog(UnmarshalHandler.class);
  111   
  112       //---------------------------/
  113       //- Private Class Variables -/
  114       //---------------------------/
  115   
  116       /**
  117        * The error message when no class descriptor has been found
  118        * TODO: move to resource bundle
  119        */
  120       private static final String ERROR_DID_NOT_FIND_CLASSDESCRIPTOR =
  121           "unable to find or create a ClassDescriptor for class: ";
  122   
  123       /**
  124        * The built-in XML prefix used for xml:space, xml:lang
  125        * and, as the XML 1.0 Namespaces document specifies, are
  126        * reserved for use by XML and XML related specs.
  127       **/
  128       private static final String XML_PREFIX = "xml";
  129   
  130       /**
  131        * Attribute name for default namespace declaration
  132       **/
  133       private static final String   XMLNS             = "xmlns";
  134   
  135       /**
  136        * Attribute prefix for prefixed namespace declaration
  137       **/
  138       private final static String XMLNS_PREFIX        = "xmlns:";
  139       private final static int    XMLNS_PREFIX_LENGTH = XMLNS_PREFIX.length();
  140   
  141       /**
  142        * The type attribute (xsi:type) used to denote the
  143        * XML Schema type of the parent element
  144       **/
  145       private static final String XSI_TYPE = "type";
  146       
  147       private static final String XML_SPACE = "space";
  148       private static final String XML_SPACE_WITH_PREFIX = "xml:space";
  149       private static final String PRESERVE = "preserve";
  150   
  151       //----------------------------/
  152       //- Private Member Variables -/
  153       //----------------------------/
  154   
  155       private Stack            _stateInfo    = null;
  156       private UnmarshalState   _topState     = null;
  157       private Class            _topClass     = null;
  158   
  159       /**
  160        * The top-level instance object, this may be set by the user
  161        * by calling #setRootObject();.
  162       **/
  163       private Object           _topObject    = null;
  164   
  165       /**
  166        * Indicates whether or not collections should be cleared
  167        * upon first use (to remove default values, or old values).
  168        * False by default for backward compatibility.
  169        */
  170       private boolean          _clearCollections = false;
  171   
  172       /**
  173        * The SAX Document Locator.
  174       **/
  175       private Locator          _locator      = null;
  176   
  177       /**
  178        * The IDResolver for resolving IDReferences.
  179       **/
  180       private IDResolverImpl _idResolver = null;
  181   
  182      /**
  183       * The unmarshaller listener.
  184       */
  185       private org.castor.xml.UnmarshalListener _unmarshalListener = null;
  186       
  187       /**
  188        * A flag indicating whether or not to perform validation.
  189        **/
  190       private boolean _validate = true;
  191   
  192       private Hashtable _resolveTable = new Hashtable();
  193       
  194   	private HashMap _javaPackages = null;    
  195   
  196       private ClassLoader _loader = null;
  197   
  198       private static final StringClassDescriptor _stringDescriptor
  199           = new StringClassDescriptor();
  200   
  201       /**
  202        * A SAX2ANY unmarshaller in case we are dealing with {@literal <any>}.
  203        */
  204        private SAX2ANY _anyUnmarshaller = null;
  205   
  206       /**
  207        * The any branch depth.
  208        */
  209       private int _depth = 0;
  210   
  211       /**
  212        * The AnyNode to add (if any).
  213        */
  214        private org.exolab.castor.types.AnyNode _node = null;
  215   
  216       /**
  217        * The namespace stack.
  218        */
  219       private Namespaces _namespaces = null;
  220   
  221       /**
  222        * A map of namespace URIs to Package Names.
  223        */
  224       private HashMap _namespaceToPackage = null;
  225   
  226       /**
  227        * A reference to the ObjectFactory used to create instances
  228        * of the classes if the FieldHandler is not used.
  229        */
  230       private ObjectFactory _objectFactory = new DefaultObjectFactory();
  231       
  232       /**
  233        * A boolean to indicate that objects should
  234        * be re-used where appropriate.
  235       **/
  236       private boolean _reuseObjects = false;
  237   
  238       /**
  239        * A boolean that indicates attribute processing should
  240        * be strict and an error should be flagged if any
  241        * extra attributes exist.
  242       **/
  243       private boolean _strictAttributes = false;
  244   
  245       /**
  246        * A boolean that indicates element processing should
  247        * be strict and an error should be flagged if any
  248        * extra elements exist.
  249       **/
  250       private boolean _strictElements = true;
  251   
  252       /**
  253        * A depth counter that increases as we skip elements ( in startElement )
  254        * and decreases as we process and endElement. Only active if _strictElemnts
  255        */
  256       private int     _ignoreElementDepth = 0;
  257   
  258       /**
  259        * A flag to keep track of when a new namespace scope is needed.
  260        */
  261       private boolean _createNamespaceScope = true;
  262       
  263       /**
  264        * Keeps track of the current element information
  265        * as passed by the parser.
  266        */
  267       private ElementInfo _elemInfo = null;
  268       
  269       /**
  270        * A "reusable" AttributeSet, for use when handling
  271        * SAX 2 ContentHandler.
  272        */
  273       private AttributeSetImpl _reusableAtts = null;
  274       
  275       /**
  276        * The top-level xml:space value.
  277        */
  278       private boolean _wsPreserve = false;
  279       
  280       //----------------/
  281       //- Constructors -/
  282       //----------------/
  283   
  284       /**
  285        * Creates a new UnmarshalHandler
  286        * The "root" class will be obtained by looking into the mapping
  287        * for a descriptor that matches the root element.
  288       **/
  289       protected UnmarshalHandler() {
  290           this(null);
  291       }
  292   
  293       /**
  294        * Creates a new UnmarshalHandler.
  295        * 
  296        * @param topClass the Class to create the UnmarshalHandler for
  297        */
  298       protected UnmarshalHandler(final Class<?> topClass) {
  299           this(null, topClass);
  300       }
  301       
  302       /**
  303        * Creates a new UnmarshalHandler.
  304        * @param internalContext the {@link InternalContext} to use
  305        * @param topClass the Class to work for
  306        */
  307       protected UnmarshalHandler(final InternalContext internalContext, final Class<?> topClass) {
  308           super(internalContext);
  309           _stateInfo          = new Stack();
  310           _idResolver         = new IDResolverImpl();
  311           _javaPackages       = new HashMap();
  312           _topClass           = topClass;
  313           _namespaces         = new Namespaces();
  314           _namespaceToPackage = new HashMap();
  315       }
  316       
  317       /**
  318        * Adds a mapping from the given namespace URI to the given
  319        * package name
  320        * 
  321        * @param nsURI the namespace URI to map from
  322        * @param packageName the package name to map to
  323        */
  324       public void addNamespaceToPackageMapping(String nsURI, String packageName) 
  325       {
  326           if (nsURI == null) nsURI = "";
  327           if (packageName == null) packageName = "";
  328       	_namespaceToPackage.put(nsURI, packageName);
  329           
  330       } //-- addNamespaceToPackageMapping
  331   
  332       /**
  333        * Returns the Object that the UnmarshalHandler is currently
  334        * handling (within the object model), or null if the current
  335        * element is a simpleType.
  336        *
  337        * @return the Object currently being unmarshalled, or null if the
  338        * current element is a simpleType.
  339        */
  340       public Object getCurrentObject() {
  341           if (!_stateInfo.isEmpty()) {
  342               UnmarshalState state = (UnmarshalState)_stateInfo.peek();
  343               if (state != null)  {
  344                   return state.object;
  345               }
  346           }
  347           return null;
  348       } //-- getCurrentObject
  349   
  350       /**
  351        * Returns the "root" Object (ie. the entire object model)
  352        * being unmarshalled.
  353        *
  354        * @return the root Object being unmarshalled.
  355       **/
  356       public Object getObject() {
  357           if (_topState != null) return _topState.object;
  358           return null;
  359       } //-- getObject
  360   
  361   
  362   
  363       /**
  364        * Sets the ClassLoader to use when loading classes
  365        *
  366        * @param loader the ClassLoader to use
  367       **/
  368       public void setClassLoader(ClassLoader loader) {
  369           _loader = loader;
  370       } //-- setClassLoader
  371   
  372       /**
  373        * Sets whether or not to clear collections (including arrays)
  374        * upon first use to remove default values. By default, and
  375        * for backward compatibility with previous versions of Castor
  376        * this value is false, indicating that collections are not
  377        * cleared before initial use by Castor.
  378        *
  379        * @param clear the boolean value that when true indicates
  380        * collections should be cleared upon first use.
  381        */
  382       public void setClearCollections(boolean clear) {
  383           _clearCollections = clear;
  384       } //-- setClearCollections
  385   
  386       /**
  387   	 * Included for backward compatibility. Debug is replaced with 
  388   	 * commons-logging.
  389   	 * @deprecated
  390       **/
  391       public void setDebug(boolean debug) {
  392       	// no-op
  393       }
  394   
  395       /**
  396        * Sets the IDResolver to use when resolving IDREFs for
  397        * which no associated element may exist in XML document.
  398        *
  399        * @param idResolver the IDResolver to use when resolving
  400        * IDREFs for which no associated element may exist in the
  401        * XML document.
  402       **/
  403       public void setIDResolver(IDResolver idResolver) {
  404           _idResolver.setResolver(idResolver);
  405       } //-- setIdResolver
  406   
  407   
  408       /**
  409        * Sets whether or not attributes that do not match
  410        * a specific field should simply be ignored or
  411        * reported as an error. By default, extra attributes
  412        * are ignored.
  413        *
  414        * @param ignoreExtraAtts a boolean that when true will
  415        * allow non-matched attributes to simply be ignored.
  416       **/
  417       public void setIgnoreExtraAttributes(boolean ignoreExtraAtts) {
  418           _strictAttributes = (!ignoreExtraAtts);
  419       } //-- setIgnoreExtraAttributes
  420   
  421       /**
  422        * Sets whether or not elements that do not match
  423        * a specific field should simply be ignored or
  424        * reported as an error. By default, extra attributes
  425        * are ignored.
  426        *
  427        * @param ignoreExtraElems a boolean that when true will
  428        * allow non-matched attributes to simply be ignored.
  429       **/
  430       public void setIgnoreExtraElements(boolean ignoreExtraElems) {
  431           _strictElements = (!ignoreExtraElems);
  432       } //-- setIgnoreExtraElements
  433   
  434       /**
  435        * Custom logging replaced with commons-logging.
  436        * @deprecated
  437       **/
  438       public void setLogWriter(PrintWriter printWriter) {
  439       	// no-op
  440       } //-- setLogWriter
  441   
  442       /**
  443        * Sets a boolean that when true indicates that objects
  444        * contained within the object model should be re-used
  445        * where appropriate. This is only valid when unmarshalling
  446        * to an existing object.
  447        *
  448        * @param reuse the boolean indicating whether or not
  449        * to re-use existing objects in the object model.
  450       **/
  451       public void setReuseObjects(boolean reuse) {
  452           _reuseObjects = reuse;
  453       } //-- setReuseObjects
  454   
  455   //    /**
  456   //     * Sets the ClassDescriptorResolver to use for loading and
  457   //     * resolving ClassDescriptors
  458   //     *
  459   //     * @param cdResolver the ClassDescriptorResolver to use
  460   //    **/
  461   //    public void setResolver(XMLClassDescriptorResolver cdResolver) {
  462   //        this._cdResolver = cdResolver;
  463   //    } //-- setResolver
  464   
  465       /**
  466        * Sets the root (top-level) object to use for unmarshalling into.
  467        *
  468        * @param root the instance to unmarshal into.
  469       **/
  470       public void setRootObject(Object root) {
  471           _topObject = root;
  472       } //-- setRootObject
  473   
  474       /**
  475        * Sets an {@link org.exolab.castor.xml.UnmarshalListener}.
  476        *
  477        * @param listener the {@link org.exolab.castor.xml.UnmarshalListener} to use with this instance
  478        * of the UnmarshalHandler.
  479        * @deprecated please move to the new {@link org.castor.xml.UnmarshalListener} interface
  480        */
  481       public void setUnmarshalListener (org.exolab.castor.xml.UnmarshalListener listener) {
  482           if (listener == null) {
  483               listener = null;
  484           } else {
  485               UnmarshalListenerAdapter adapter = new UnmarshalListenerAdapter();
  486               adapter.setOldListener(listener);
  487               _unmarshalListener = adapter;
  488           }
  489       }
  490   
  491       /**
  492        * Sets an {@link org.castor.xml.UnmarshalListener}.
  493        *
  494        * @param listener the {@link org.castor.xml.UnmarshalListener} to use with this instance
  495        * of the UnmarshalHandler.
  496        */
  497       public void setUnmarshalListener (org.castor.xml.UnmarshalListener listener) {
  498           _unmarshalListener = listener;
  499       }
  500   
  501       /**
  502        * Sets the flag for validation.
  503        * 
  504        * @param validate A boolean to indicate whether or not validation should be done
  505        *        during umarshalling.
  506        *        <br/>
  507        *        By default, validation will be performed.
  508        */
  509       public void setValidation(boolean validate) {
  510           this._validate = validate;
  511       } //-- setValidation
  512       
  513       /**
  514        * Sets the top-level whitespace (xml:space) to either
  515        * preserving or non preserving. The XML document
  516        * can override this value using xml:space on specific
  517        * elements. This sets the "default" behavior
  518        * when xml:space="default".
  519        *
  520        * @param preserve a boolean that when true enables
  521        * whitespace preserving by default. 
  522        */
  523       public void setWhitespacePreserve(boolean preserve) {
  524           _wsPreserve = preserve;
  525       } //-- setWhitespacePreserve
  526   
  527       //-----------------------------------/
  528       //- SAX Methods for DocumentHandler -/
  529       //-----------------------------------/
  530   
  531       public void characters(char[] ch, int start, int length)
  532           throws SAXException
  533       {
  534       	if (LOG.isTraceEnabled()) {
  535               StringBuffer sb = new StringBuffer(21 + length);
  536               sb.append("#characters: ");
  537               sb.append(ch, start, length);
  538               LOG.trace(sb.toString());
  539       	}
  540           
  541           //-- If we are skipping elements that have appeared in the XML but for
  542           //-- which we have no mapping, skip the text and return
  543           if ( _ignoreElementDepth > 0) {
  544               return;
  545           }
  546   
  547           if (_stateInfo.empty()) {
  548               return;
  549           }
  550           if (_anyUnmarshaller != null)
  551              _anyUnmarshaller.characters(ch, start, length);
  552           else {
  553                UnmarshalState state = (UnmarshalState)_stateInfo.peek();
  554                //-- handle whitespace
  555                boolean removedTrailingWhitespace = false;
  556                boolean removedLeadingWhitespace = false;
  557                if (!state.wsPreserve) {
  558                   //-- trim leading whitespace characters
  559                   while (length > 0) {
  560                       boolean whitespace = false;
  561                       switch(ch[start]) {
  562                           case ' ':
  563                           case '\r':
  564                           case '\n':
  565                           case '\t':
  566                           	whitespace = true;
  567                               break;
  568                           default:
  569                               break;
  570                       }
  571                       if (!whitespace) break;
  572                       removedLeadingWhitespace = true;
  573                       ++start;
  574                       --length;
  575                   }
  576                   
  577                   if (length == 0) {
  578                       //-- we also need to mark trailing whitespace removed
  579                       //-- when we received only whitespace characters
  580                       removedTrailingWhitespace = removedLeadingWhitespace;
  581                   }
  582                   else {
  583                       //-- trim trailing whitespace characters
  584                       while (length > 0) {
  585                           boolean whitespace = false;
  586                           switch(ch[start+length-1]) {
  587                               case ' ':
  588                               case '\r':
  589                               case '\n':
  590                               case '\t':
  591                                   whitespace = true;
  592                                   break;
  593                               default:
  594                                   break;
  595                           }
  596                           if (!whitespace) break;
  597                           removedTrailingWhitespace = true;
  598                           --length;
  599                       }
  600                   }
  601                }
  602                
  603                if (state.buffer == null) state.buffer = new StringBuffer();
  604                else {
  605                   //-- non-whitespace content exists, add a space
  606                   if ((!state.wsPreserve) && (length > 0)) {
  607                   	if (state.trailingWhitespaceRemoved || removedLeadingWhitespace)
  608                       {
  609                   		state.buffer.append(' ');
  610                       }
  611                   }
  612                }
  613                state.trailingWhitespaceRemoved = removedTrailingWhitespace;
  614                state.buffer.append(ch, start, length);
  615           }
  616       } //-- characters
  617   
  618   
  619       public void endDocument()
  620           throws org.xml.sax.SAXException
  621       {
  622           //-- I've found many application don't always call
  623           //-- #endDocument, so I usually never put any
  624           //-- important logic here
  625   
  626       } //-- endDocument
  627   
  628   
  629       public void endElement(String name)
  630           throws org.xml.sax.SAXException
  631       {
  632           
  633           if (LOG.isTraceEnabled()) {
  634           	LOG.trace("#endElement: " + name);
  635           }
  636           
  637           //-- If we are skipping elements that have appeared in the XML but for
  638           //-- which we have no mapping, decrease the ignore depth counter and return
  639           if ( _ignoreElementDepth > 0) {
  640               --_ignoreElementDepth;
  641               return;
  642           }
  643   
  644           //-- Do delagation if necessary
  645           if (_anyUnmarshaller != null) {
  646               _anyUnmarshaller.endElement(name);
  647               --_depth;
  648               //we are back to the starting node
  649               if (_depth == 0) {
  650                  _node = _anyUnmarshaller.getStartingNode();
  651                  _anyUnmarshaller = null;
  652               }
  653               else return;
  654           }
  655   
  656           if (_stateInfo.empty()) {
  657               throw new SAXException("missing start element: " + name);
  658           }
  659   
  660           //-- * Begin Namespace Handling
  661           //-- XXX Note: This code will change when we update the XML event API
  662   
  663            int idx = name.indexOf(':');
  664            if (idx >= 0) {
  665                name = name.substring(idx+1);
  666            }
  667           //-- * End Namespace Handling
  668   
  669           UnmarshalState state = (UnmarshalState) _stateInfo.pop();
  670   
  671           //-- make sure we have the correct closing tag
  672           XMLFieldDescriptor descriptor = state.fieldDesc;
  673           
  674           if (!state.elementName.equals(name)) {
  675               
  676               //maybe there is still a container to end
  677               if (descriptor.isContainer()) {
  678                   _stateInfo.push(state);
  679                   //-- check for possible characters added to
  680                   //-- the container's state that should
  681                   //-- really belong to the parent state
  682                   StringBuffer tmpBuffer = null;
  683                   if (state.buffer != null) {
  684                       if (!isWhitespace(state.buffer)) {
  685                           if (state.classDesc.getContentDescriptor() == null) {
  686                               tmpBuffer = state.buffer;
  687                               state.buffer = null;
  688                           }
  689                       }
  690                   }
  691                   //-- end container
  692                   endElement(state.elementName);
  693                   
  694                   if (tmpBuffer != null) {
  695                       state = (UnmarshalState) _stateInfo.peek();
  696                       if (state.buffer == null)
  697                           state.buffer = tmpBuffer;
  698                       else
  699                           state.buffer.append(tmpBuffer.toString());
  700                   }
  701                   endElement(name);
  702                   return;
  703               }
  704               String err = "error in xml, expecting </" + state.elementName;
  705               err += ">, but received </" + name + "> instead.";
  706               throw new SAXException(err);
  707           }
  708           
  709           
  710           //-- clean up current Object
  711           Class type = state.type;
  712   
  713           if ( type == null ) {
  714               if (!state.wrapper) {
  715                   //-- this message will only show up if debug
  716                   //-- is turned on...how should we handle this case?
  717                   //-- should it be a fatal error?
  718                   LOG.info("Ignoring " + state.elementName + " no descriptor was found");
  719               }
  720               
  721               //-- handle possible location text content
  722               //-- TODO: cleanup location path support.
  723               //-- the following code needs to be improved as 
  724               //-- for searching descriptors in this manner can
  725               //-- be slow
  726               StringBuffer tmpBuffer = null;
  727               if (state.buffer != null) {
  728                   if (!isWhitespace(state.buffer)) {
  729                       tmpBuffer = state.buffer;
  730                       state.buffer = null;
  731                   }
  732               }
  733               if (tmpBuffer != null) {
  734                   UnmarshalState targetState = state;
  735                   String locPath = targetState.elementName;
  736                   while ((targetState = targetState.parent) != null) {
  737                       if ((targetState.wrapper) || 
  738                           (targetState.classDesc == null))
  739                       {
  740                           locPath = targetState.elementName + "/" + locPath;
  741                           continue;
  742                       }
  743                       
  744                       XMLFieldDescriptor tmpDesc = targetState.classDesc.getContentDescriptor();
  745                       if (tmpDesc != null && locPath.equals(tmpDesc.getLocationPath())) {
  746                           if (targetState.buffer == null)
  747                               targetState.buffer = tmpBuffer;
  748                           else
  749                               targetState.buffer.append(tmpBuffer.toString());
  750                       }
  751                   }
  752               }
  753               
  754               //-- remove current namespace scoping
  755               _namespaces = _namespaces.getParent();
  756               return;
  757           }
  758   
  759           //-- check for special cases
  760           boolean byteArray = false;
  761           if (type.isArray()) {
  762               byteArray = (type.getComponentType() == Byte.TYPE);
  763           }
  764   
  765           //-- If we don't have an instance object and the Class type
  766           //-- is not a primitive or a byte[] we must simply return
  767           if ((state.object == null) && (!state.primitiveOrImmutable)) {
  768               //-- remove current namespace scoping
  769               _namespaces = _namespaces.getParent();
  770               return;
  771           }
  772           
  773           /// DEBUG System.out.println("end: " + name);
  774   
  775           if (state.primitiveOrImmutable) {
  776               
  777               String str = null;
  778   
  779               if (state.buffer != null) {
  780                   str = state.buffer.toString();
  781                   state.buffer.setLength(0);
  782               }
  783   
  784               if (type == String.class && !((XMLFieldDescriptorImpl) descriptor).isDerivedFromXSList()) {
  785                   if (str != null)
  786                       state.object = str;
  787                   else if (state.nil) {
  788                       state.object = null;
  789                   }
  790                   else {
  791                       state.object = "";
  792                   }
  793               }
  794               //-- special handling for byte[]
  795               else if (byteArray && !descriptor.isDerivedFromXSList()) {
  796                   if (str == null)
  797                       state.object = new byte[0];
  798                   else {
  799                       state.object = decodeBinaryData(descriptor, str);
  800                   }
  801               }
  802               else if (state.args != null) {
  803               	state.object = createInstance(state.type, state.args);
  804               }
  805               else if (descriptor.isMultivalued()
  806                       && descriptor.getSchemaType() != null
  807                       && descriptor.getSchemaType().equals("list")
  808                       && ((XMLFieldDescriptorImpl) descriptor).isDerivedFromXSList()) {
  809                   StringTokenizer attrValueTokenizer = new StringTokenizer(str);
  810                   List primitives = new ArrayList();
  811                   while (attrValueTokenizer.hasMoreTokens()) {
  812                       String tokenValue = attrValueTokenizer.nextToken();
  813                       if (isPrimitive(descriptor.getFieldType())) {
  814                           primitives.add(toPrimitiveObject(type, tokenValue, state.fieldDesc));
  815                       } else {
  816                           Class valueType = descriptor.getFieldType();
  817                           //-- handle base64/hexBinary
  818                           if (valueType.isArray()
  819                                   && (valueType.getComponentType() == Byte.TYPE)) {
  820                               primitives.add(decodeBinaryData(descriptor, tokenValue));
  821                           }
  822                       }
  823                       
  824                   }
  825                   state.object = primitives;
  826               } else {
  827                   if (state.nil) {
  828                       state.object = null;
  829                   } else {
  830                       state.object = toPrimitiveObject(type,str,state.fieldDesc);
  831                   }
  832               }
  833           }
  834           else if (ArrayHandler.class.isAssignableFrom(state.type)) {
  835               state.object = ((ArrayHandler)state.object).getObject();
  836               state.type = state.object.getClass();
  837               
  838           }
  839   
  840           //-- check for character content
  841           if ((state.buffer != null) &&
  842               (state.buffer.length() > 0) &&
  843               (state.classDesc != null)) {
  844               XMLFieldDescriptor cdesc = state.classDesc.getContentDescriptor();
  845               if (cdesc != null) {
  846                   Object value = state.buffer.toString();
  847                   if (isPrimitive(cdesc.getFieldType()))
  848                       value = toPrimitiveObject(cdesc.getFieldType(), (String)value, state.fieldDesc);
  849                   else {
  850                       Class valueType = cdesc.getFieldType();
  851                       //-- handle base64/hexBinary
  852                       if (valueType.isArray()
  853                               && (valueType.getComponentType() == Byte.TYPE)) {
  854                           value = decodeBinaryData(descriptor, (String) value);
  855                       }
  856                   }
  857   
  858   
  859                   try {
  860                       FieldHandler handler = cdesc.getHandler();
  861                       boolean addObject = true;
  862                       if (_reuseObjects) {
  863                           //-- check to see if we need to
  864                           //-- add the object or not
  865                           Object tmp = handler.getValue(state.object);
  866                           if (tmp != null) {
  867                               //-- Do not add object if values
  868                               //-- are equal
  869                               addObject = (!tmp.equals(value));
  870                           }
  871                       }
  872                       if (addObject) handler.setValue(state.object, value);
  873                   }
  874                   catch(java.lang.IllegalStateException ise) {
  875                       String err = "unable to add text content to ";
  876                       err += descriptor.getXMLName();
  877                       err += " due to the following error: " + ise;
  878                       throw new SAXException(err, ise);
  879                   }
  880               }
  881               //-- Handle references
  882               else if (descriptor.isReference()) {
  883                   UnmarshalState pState = (UnmarshalState) _stateInfo.peek();
  884                   processIDREF(state.buffer.toString(), descriptor, pState.object);
  885                   _namespaces = _namespaces.getParent();
  886                   return;
  887               } else {
  888                   //-- check for non-whitespace...and report error
  889                   if (!isWhitespace(state.buffer)) {
  890                       String err = "Illegal Text data found as child of: "
  891                           + name;
  892                       err += "\n  value: \"" + state.buffer + "\"";
  893                       throw new SAXException(err);
  894                   }
  895               }
  896           }
  897           
  898           //-- We're finished processing the object, so notify the
  899           //-- Listener (if any).
  900           if (_unmarshalListener != null && state.object != null) {
  901               _unmarshalListener.unmarshalled(state.object, 
  902                       (state.parent == null) ? null : state.parent.object);
  903           }
  904   
  905           //-- if we are at root....just validate and we are done
  906            if (_stateInfo.empty()) {
  907                if (isValidating()) {
  908                   ValidationException first = null;
  909                   ValidationException last = null;
  910                   
  911                   //-- check unresolved references
  912                   if (_resolveTable != null && !getInternalContext().getLenientIdValidation()) {
  913                       Enumeration enumeration = _resolveTable.keys();
  914                       while (enumeration.hasMoreElements()) {
  915                           Object ref = enumeration.nextElement();
  916                           //if (ref.toString().startsWith(MapItem.class.getName())) continue;
  917                           String msg = "unable to resolve reference: " + ref;                        
  918                           if (first == null) {
  919                               first = new ValidationException(msg);
  920                               last = first;
  921                           }
  922                           else {
  923                               last.setNext(new ValidationException(msg));
  924                               last = last.getNext();
  925                           }                            
  926                       }
  927                   }
  928                   try {
  929                       Validator validator = new Validator();
  930                       ValidationContext context = new ValidationContext();
  931                       context.setInternalContext(getInternalContext());
  932                       validator.validate(state.object, context);
  933                       if (!getInternalContext().getLenientIdValidation()) {
  934                           validator.checkUnresolvedIdrefs(context);
  935                       }
  936                       context.cleanup();
  937                   }
  938                   catch(ValidationException vEx) {
  939                       if (first == null)
  940                           first = vEx;
  941                       else 
  942                           last.setNext(vEx);
  943                   }
  944                   if (first != null) {
  945                       throw new SAXException(first);
  946                   }
  947               }
  948               return;
  949           }
  950            
  951           //-- Add object to parent if necessary
  952   
  953           if (descriptor.isIncremental()) {
  954               //-- remove current namespace scoping
  955              _namespaces = _namespaces.getParent();
  956              return; //-- already added
  957           }
  958   
  959           Object val = state.object;
  960           
  961           //--special code for AnyNode handling
  962           if (_node != null) {
  963              val = _node;
  964              _node = null;
  965           }
  966   
  967           //-- save fieldState
  968           UnmarshalState fieldState = state;
  969   
  970           //-- have we seen this object before?
  971           boolean firstOccurance = false;
  972   
  973           //-- get target object
  974           state = (UnmarshalState) _stateInfo.peek();
  975           if (state.wrapper) {
  976               state = fieldState.targetState;
  977           }
  978           
  979           //-- check to see if we have already read in
  980           //-- an element of this type. 
  981           //-- (Q: if we have a container, do we possibly need to 
  982           //--     also check the container's multivalued status?)
  983           if ( ! descriptor.isMultivalued() ) {
  984   
  985               if (state.isUsed(descriptor)) {
  986                   
  987                   String err = "element \"" + name;
  988                   err += "\" occurs more than once. (parent class: " + state.type.getName() + ")";
  989                   
  990                   String location = name;
  991                   while (!_stateInfo.isEmpty()) {
  992                       UnmarshalState tmpState = (UnmarshalState)_stateInfo.pop();
  993                       if (!tmpState.wrapper) {
  994                           if (tmpState.fieldDesc.isContainer()) continue;
  995                       }
  996                       location = state.elementName + "/" + location;
  997                   }
  998                   
  999                   err += "\n location: /" + location;
 1000                   
 1001                   ValidationException vx =
 1002                       new ValidationException(err);
 1003                   
 1004               	throw new SAXException(vx);
 1005               }
 1006               state.markAsUsed(descriptor);
 1007               //-- if this is the identity then save id
 1008               if (state.classDesc.getIdentity() == descriptor) {
 1009                   state.key = val;
 1010               }
 1011           }
 1012           else {
 1013               //-- check occurance of descriptor
 1014               if (!state.isUsed(descriptor)) {
 1015                   firstOccurance = true;
 1016               }
 1017                   
 1018               //-- record usage of descriptor
 1019               state.markAsUsed(descriptor);            
 1020           }
 1021   
 1022           try {
 1023               FieldHandler handler = descriptor.getHandler();
 1024               //check if the value is a QName that needs to
 1025               //be resolved (ns:value -> {URI}value)
 1026               String valueType = descriptor.getSchemaType();
 1027               if ((valueType != null) && (valueType.equals(QNAME_NAME))) {
 1028                    val = resolveNamespace(val);
 1029               }
 1030   
 1031               boolean addObject = true;
 1032               if (_reuseObjects && fieldState.primitiveOrImmutable) {
 1033                    //-- check to see if we need to
 1034                    //-- add the object or not
 1035                    Object tmp = handler.getValue(state.object);
 1036                    if (tmp != null) {
 1037                        //-- Do not add object if values
 1038                        //-- are equal
 1039                        addObject = (!tmp.equals(val));
 1040                    }
 1041               }
 1042               
 1043               //-- special handling for mapped objects
 1044               if (descriptor.isMapped()) {
 1045                   if (!(val instanceof MapItem)) {
 1046                       MapItem mapItem = new MapItem(fieldState.key, val);
 1047                       val = mapItem;
 1048                   }
 1049                   else {
 1050                       //-- make sure value exists (could be a reference)
 1051                       MapItem mapItem = (MapItem)val;
 1052                       if (mapItem.getValue() == null) {
 1053                           //-- save for later...
 1054                           addObject = false;
 1055                           addReference(mapItem.toString(), state.object, descriptor);
 1056                       }
 1057                   }
 1058               }
 1059               
 1060               if (addObject) {
 1061                   //-- clear any collections if necessary
 1062                   if (firstOccurance && _clearCollections) {
 1063                       handler.resetValue(state.object);
 1064                   }
 1065   
 1066                   if (descriptor.isMultivalued() 
 1067                           && descriptor.getSchemaType() != null
 1068                           && descriptor.getSchemaType().equals("list")
 1069                           && ((XMLFieldDescriptorImpl) descriptor).isDerivedFromXSList()) {
 1070                       List values = (List) val;
 1071                       for (Iterator iterator = values.iterator(); iterator.hasNext();) {
 1072                           //-- finally set the value!!
 1073                           Object value = iterator.next();
 1074                           handler.setValue(state.object, value);
 1075                           
 1076                           // If there is a parent for this object, pass along
 1077                           // a notification that we've finished adding a child
 1078                           if ( _unmarshalListener != null ) {
 1079                               _unmarshalListener.fieldAdded(descriptor.getFieldName(), state.object, fieldState.object);
 1080                           }
 1081                       }
 1082                   } else {
 1083                   
 1084                       //-- finally set the value!!
 1085                       handler.setValue(state.object, val);
 1086   
 1087                       // If there is a parent for this object, pass along
 1088                       // a notification that we've finished adding a child
 1089                       if ( _unmarshalListener != null ) {
 1090                           _unmarshalListener.fieldAdded(descriptor.getFieldName(), state.object, fieldState.object);
 1091                       }
 1092                   }                
 1093               }
 1094   
 1095           }
 1096           /*
 1097           catch(java.lang.reflect.InvocationTargetException itx) {
 1098   
 1099               Throwable toss = itx.getTargetException();
 1100               if (toss == null) toss = itx;
 1101   
 1102               String err = "unable to add '" + name + "' to <";
 1103               err += state.descriptor.getXMLName();
 1104               err += "> due to the following exception: " + toss;
 1105               throw new SAXException(err);
 1106           }
 1107           */
 1108           catch(Exception ex) {
 1109               StringWriter sw = new StringWriter();
 1110               PrintWriter  pw = new PrintWriter(sw);
 1111               ex.printStackTrace(pw);
 1112               pw.flush();
 1113               String err = "unable to add '" + name + "' to <";
 1114               err += state.fieldDesc.getXMLName();
 1115               err += "> due to the following exception: \n";
 1116               err += ">>>--- Begin Exception ---<<< \n";
 1117               err += sw.toString();
 1118               err += ">>>---- End Exception ----<<< \n";
 1119               throw new SAXException(err, ex);
 1120           }
 1121   
 1122           //-- remove current namespace scoping
 1123           _namespaces = _namespaces.getParent();
 1124   
 1125           // remove additional (artifical aka container) state introduced for single-valued (iow maxOccurs="1") choices.
 1126           if (state.fieldDesc.isContainer() 
 1127                   && state.classDesc.isChoice() 
 1128                   && !state.fieldDesc.isMultivalued()) {
 1129               this.endElement(state.elementName);
 1130           }
 1131       } //-- endElement
 1132   
 1133       /**
 1134        * Decode binary data and return decoded value.
 1135        * @param descriptor {@link XMLFieldDescriptor} instance for the field whose value requires decoding.
 1136        * @param binaryData The binary data value to be decoded
 1137        * @return Decode data.
 1138        */
 1139       private byte[] decodeBinaryData(final XMLFieldDescriptor descriptor,
 1140               final String binaryData) {
 1141           //-- Base64/HexBinary decoding
 1142           byte[] decodedValue;
 1143           if ((descriptor.isMultivalued() 
 1144                   && HexDecoder.DATA_TYPE.equals(descriptor.getComponentType())) 
 1145                   || HexDecoder.DATA_TYPE.equals(descriptor.getSchemaType())) {
 1146               decodedValue = HexDecoder.decode(binaryData);
 1147           } else {
 1148               decodedValue = Base64Decoder.decode(binaryData);
 1149           }
 1150           return decodedValue;
 1151       }
 1152   
 1153       /**
 1154        * <p>ContentHandler#endElement</p>
 1155        *
 1156        * Signals the end of an element
 1157        *
 1158        * @param localName The name of the element.
 1159        */
 1160       public void endElement(String namespaceURI, String localName, String qName)
 1161       throws org.xml.sax.SAXException {        
 1162           if ((qName == null) || (qName.length() == 0)) {
 1163               if ((localName == null) || (localName.length() == 0)) {
 1164                   String error = "Missing either 'qName' or 'localName', both cannot be null or emtpy.";
 1165                   throw new SAXException(error);
 1166               }
 1167               qName = localName;
 1168               if ((namespaceURI != null) && (namespaceURI.length() > 0)) {
 1169                   //-- rebuild qName, for now
 1170                   String prefix = _namespaces.getNamespacePrefix(namespaceURI);
 1171                   if ((prefix != null) && (prefix.length() > 0))
 1172                       qName = prefix + ":" + localName;
 1173               }
 1174           }
 1175          
 1176           endElement(qName); 
 1177       } //-- endElement
 1178       
 1179       
 1180       /**
 1181        * Signals to end the namespace prefix mapping
 1182        * 
 1183        * @param prefix the namespace prefix 
 1184        */
 1185       public void endPrefixMapping(String prefix)
 1186           throws SAXException
 1187       { 
 1188           //-- nothing to do , already taken care of in 
 1189           //-- endElement except if we are unmarshalling an 
 1190           //-- AnyNode
 1191           if (_anyUnmarshaller != null) {
 1192               _anyUnmarshaller.endPrefixMapping(prefix);
 1193           }
 1194           
 1195       } //-- endPrefixMapping
 1196   
 1197   
 1198       public void ignorableWhitespace(char[] ch, int start, int length)
 1199           throws org.xml.sax.SAXException
 1200       {
 1201           
 1202           //-- If we are skipping elements that have appeared in the XML but for
 1203           //-- which we have no mapping, skip the text and return
 1204           if ( _ignoreElementDepth > 0) {
 1205               return;
 1206           }
 1207   
 1208           if (_stateInfo.empty()) {
 1209               return;
 1210           }
 1211           
 1212           if (_anyUnmarshaller != null)
 1213              _anyUnmarshaller.ignorableWhitespace(ch, start, length);
 1214           else {
 1215                UnmarshalState state = (UnmarshalState)_stateInfo.peek();
 1216                if (state.wsPreserve) {
 1217                   if (state.buffer == null) state.buffer = new StringBuffer();
 1218                   state.buffer.append(ch, start, length);
 1219                }
 1220           }
 1221       } //-- ignorableWhitespace
 1222   
 1223       public void processingInstruction(String target, String data)
 1224           throws org.xml.sax.SAXException
 1225       {
 1226           //-- do nothing for now
 1227       } //-- processingInstruction
 1228   
 1229   
 1230       public void setDocumentLocator(Locator locator) {
 1231           this._locator = locator;
 1232       } //-- setDocumentLocator
 1233   
 1234       public Locator getDocumentLocator() {
 1235           return _locator;
 1236       } //-- getDocumentLocator
 1237   
 1238       /**
 1239        * Signals that an entity was skipped by the parser
 1240        *
 1241        * @param name the skipped entity's name
 1242        */
 1243       public void skippedEntity(String name)
 1244           throws SAXException
 1245       {
 1246           //-- do nothing
 1247           
 1248       } //-- skippedEntity
 1249       
 1250       /**
 1251        * Signals the start of a new document
 1252        */
 1253       public void startDocument()
 1254           throws org.xml.sax.SAXException
 1255       {
 1256   
 1257           //-- I've found many application don't always call
 1258           //-- #startDocument, so I usually never put any
 1259           //-- important logic here
 1260   
 1261       } //-- startDocument
 1262       
 1263       
 1264       /**
 1265        * <p>ContentHandler#startElement</p>
 1266        *
 1267        * Signals the start of element.
 1268        *
 1269        * @param localName The name of the element.
 1270        * @param atts The AttributeList containing the associated attributes for the element.
 1271        */
 1272       public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
 1273       throws org.xml.sax.SAXException {
 1274           if (LOG.isTraceEnabled()) {
 1275               if ((qName != null) && (qName.length() > 0))
 1276                   LOG.trace("#startElement: " + qName);
 1277               else
 1278               	LOG.trace("#startElement: " + localName);
 1279           }
 1280           
 1281           //-- If we are skipping elements that have appeared in the XML but for
 1282           //-- which we have no mapping, increase the ignore depth counter and return
 1283           if ((!_strictElements) && (_ignoreElementDepth > 0)) {
 1284               ++_ignoreElementDepth;
 1285               return;
 1286           }
 1287   
 1288           //-- if we are in an <any> section
 1289           //-- we delegate the event handling
 1290           if (_anyUnmarshaller != null) {
 1291               _depth++;
 1292              _anyUnmarshaller.startElement(namespaceURI, localName, qName, atts);
 1293              return;
 1294           }
 1295           
 1296           //-- Create a new namespace scope if necessary and
 1297           //-- make sure the flag is reset to true
 1298           if (_createNamespaceScope)
 1299               _namespaces = _namespaces.createNamespaces();
 1300           else
 1301               _createNamespaceScope = true;
 1302               
 1303           
 1304           if (_reusableAtts == null) {
 1305               if (atts != null) 
 1306                   _reusableAtts = new AttributeSetImpl(atts.getLength());
 1307               else {
 1308                   //-- we can't pass a null AttributeSet to the
 1309                   //-- startElement
 1310                   _reusableAtts = new AttributeSetImpl();
 1311               }
 1312           }
 1313           else {
 1314               _reusableAtts.clear();
 1315           }
 1316           
 1317           //-- process attributes
 1318           boolean hasQNameAtts = false;
 1319           if ((atts != null) && (atts.getLength() > 0)) {
 1320               //-- look for any potential namespace declarations
 1321               //-- in case namespace processing was disable
 1322               //-- on the parser
 1323               for (int i = 0; i < atts.getLength(); i++) {
 1324                   String attName = atts.getQName(i);
 1325                   if ((attName != null) && (attName.length() > 0)) {
 1326                       if (attName.equals(XMLNS)) {
 1327                           _namespaces.addNamespace("", atts.getValue(i));
 1328                       }
 1329                       else if (attName.startsWith(XMLNS_PREFIX)) {
 1330                           String prefix = attName.substring(XMLNS_PREFIX.length());
 1331                           _namespaces.addNamespace(prefix, atts.getValue(i));
 1332                       }
 1333                       else {
 1334                           //-- check for prefix
 1335                           if (attName.indexOf(':') < 0) {
 1336                               _reusableAtts.setAttribute(attName,
 1337                                   atts.getValue(i), atts.getURI(i));
 1338                           }
 1339                           else hasQNameAtts = true;
 1340                       }
 1341                   }
 1342                   else {
 1343                       //-- if attName is null or empty, just process as a normal
 1344                       //-- attribute
 1345                       attName = atts.getLocalName(i);
 1346                       if (XMLNS.equals(attName)) {
 1347                           _namespaces.addNamespace("", atts.getValue(i));
 1348                       }
 1349                       else {
 1350                           _reusableAtts.setAttribute(attName, atts.getValue(i), atts.getURI(i));
 1351                       }
 1352                   }
 1353               }
 1354           }
 1355           //-- if we found any qName-only atts, process those
 1356           if (hasQNameAtts) {
 1357               for (int i = 0; i < atts.getLength(); i++) {
 1358                   String attName = atts.getQName(i);
 1359                   if ((attName != null) && (attName.length() > 0)) {
 1360                       //-- process any non-namespace qName atts
 1361                       if ((!attName.equals(XMLNS)) && (!attName.startsWith(XMLNS_PREFIX))) 
 1362                       {
 1363                           int idx = attName.indexOf(':');
 1364                           if (idx >= 0) {
 1365                               String prefix = attName.substring(0, idx);
 1366                               attName = attName.substring(idx+1);
 1367                               String nsURI = atts.getURI(i);
 1368                               if ((nsURI == null) || (nsURI.length() == 0)) {
 1369                                   nsURI = _namespaces.getNamespaceURI(prefix);
 1370                               }
 1371                               _reusableAtts.setAttribute(attName, atts.getValue(i), nsURI);
 1372                           }
 1373                       }
 1374                   }
 1375                   //-- else skip already processed in previous loop
 1376               }
 1377           }
 1378           
 1379           //-- preserve parser passed arguments for any potential
 1380           //-- delegation
 1381           if (_elemInfo == null) {
 1382               _elemInfo = new ElementInfo(null, atts);
 1383           }
 1384           else {
 1385               _elemInfo.clear();
 1386               _elemInfo.attributes = atts;
 1387           }
 1388           
 1389           if ((localName == null) || (localName.length() == 0)) {
 1390               if ((qName == null) || (qName.length() == 0)) {
 1391                   String error = "Missing either 'localName' or 'qName', both cannot be emtpy or null.";
 1392                   throw new SAXException(error);
 1393               }
 1394               localName = qName;
 1395               _elemInfo.qName = qName;
 1396           }
 1397           else {
 1398               if ((qName == null) || (qName.length() == 0)) {
 1399                   if ((namespaceURI == null) || (namespaceURI.length() == 0)) {
 1400                       _elemInfo.qName = localName;
 1401                   }
 1402                   else {
 1403                       String prefix = _namespaces.getNamespacePrefix(namespaceURI);
 1404                       if ((prefix != null) && (prefix.length() > 0)) {
 1405                           _elemInfo.qName = prefix + ":" + localName;
 1406                       }
 1407                   }
 1408                   
 1409               }
 1410               else {
 1411                   _elemInfo.qName = qName;
 1412               }
 1413           }
 1414           
 1415           int idx = localName.indexOf(':');
 1416           if (idx >= 0) {
 1417               String prefix = localName.substring(0, idx);
 1418               localName = localName.substring(idx+1);
 1419               if ((namespaceURI == null) || (namespaceURI.length() == 0)) {
 1420                   namespaceURI = _namespaces.getNamespaceURI(prefix);
 1421               }
 1422           } else {
 1423               // check for default namespace declaration 
 1424               String defaultNamespace = _namespaces.getNamespaceURI("");
 1425               // TODO[WG]: remove unnecessary check as it simply is wrong
 1426               if (defaultNamespace != null && !defaultNamespace.equals("http://castor.exolab.org")) {
 1427                   namespaceURI = defaultNamespace;
 1428               }
 1429               //-- adjust empty namespace
 1430               if ((namespaceURI != null) && (namespaceURI.length() == 0))
 1431                   namespaceURI = null;
 1432           }
 1433           
 1434           //-- call private startElement
 1435           startElement(localName, namespaceURI, _reusableAtts);
 1436           
 1437       } //-- startElement
 1438       
 1439       /**
 1440        * <p>DocumentHandler#startElement</p>
 1441        *
 1442        * Signals the start of element.
 1443        *
 1444        * @param name The name of the element.
 1445        * @param attList The AttributeList containing the associated attributes for the
 1446        *        element.
 1447        */
 1448       public void startElement(String name, AttributeList attList)
 1449       throws org.xml.sax.SAXException {
 1450           if (LOG.isTraceEnabled()) {
 1451           	LOG.trace("#startElement: " + name);
 1452           }
 1453           
 1454           //-- If we are skipping elements that have appeared in the XML but for
 1455           //-- which we have no mapping, increase the ignore depth counter and return
 1456           if ((!_strictElements) && (_ignoreElementDepth > 0)) {
 1457               ++_ignoreElementDepth;
 1458               return;
 1459           }
 1460   
 1461           //-- if we are in an <any> section
 1462           //-- we delegate the event handling
 1463           if (_anyUnmarshaller != null) {
 1464               _depth++;
 1465              _anyUnmarshaller.startElement(name,attList);
 1466              return;
 1467           }
 1468           
 1469           if (_elemInfo == null) {
 1470               _elemInfo = new ElementInfo(name, attList);
 1471           }
 1472           else {
 1473               _elemInfo.clear();
 1474               _elemInfo.qName = name;
 1475               _elemInfo.attributeList = attList;
 1476           }
 1477           
 1478           //-- The namespace of the given element
 1479           String namespace = null;
 1480   
 1481           //-- Begin Namespace Handling :
 1482           //-- XXX Note: This code will change when we update the XML event API
 1483   
 1484           _namespaces = _namespaces.createNamespaces();
 1485   
 1486           //-- convert AttributeList to AttributeSet and process
 1487           //-- namespace declarations
 1488           AttributeSet atts = processAttributeList(attList);
 1489   
 1490           String prefix = "";
 1491           //String qName = name;
 1492           int idx = name.indexOf(':');
 1493           if (idx >= 0) {
 1494                prefix = name.substring(0,idx);
 1495                name = name.substring(idx+1);
 1496           }
 1497   
 1498           namespace = _namespaces.getNamespaceURI(prefix);
 1499           
 1500           //-- End Namespace Handling
 1501           
 1502           //-- call private startElement method
 1503           startElement(name, namespace, atts);
 1504           
 1505       } //-- startElement
 1506           
 1507       /**
 1508        * Signals the start of an element with the given name.
 1509        *
 1510        * @param name the NCName of the element. It is an error
 1511        * if the name is a QName (ie. contains a prefix).
 1512        * @param namespace the namespace of the element. This may be null.
 1513        * Note: A null namespace is not the same as the default namespace unless
 1514        * the default namespace is also null.
 1515        * @param atts the AttributeSet containing the attributes associated
 1516        * with the element.
 1517        */
 1518       private void startElement
 1519           (String name, String namespace, AttributeSet atts) 
 1520           throws SAXException
 1521       {
 1522   
 1523           UnmarshalState state = null;
 1524           String xmlSpace = null;
 1525   
 1526   
 1527           //-- handle special atts
 1528           if (atts != null) {
 1529               //-- xml:space
 1530               xmlSpace = atts.getValue(XML_SPACE, Namespaces.XML_NAMESPACE);
 1531               if (xmlSpace == null) {
 1532                   xmlSpace = atts.getValue(XML_SPACE_WITH_PREFIX, "");
 1533               }
 1534           }
 1535   
 1536           if (_stateInfo.empty()) {
 1537               //-- Initialize since this is the first element
 1538   
 1539               if (_topClass == null) {
 1540                   if (_topObject != null) {
 1541                       _topClass = _topObject.getClass();
 1542                   }
 1543               }
 1544   //            if (_cdResolver == null) {
 1545   //                if (_topClass == null) {
 1546   //                    String err = "The class for the root element '" +
 1547   //                        name + "' could not be found.";
 1548   //                    throw new SAXException(err);
 1549   //                }
 1550   //                _cdResolver = (XMLClassDescriptorResolver) ClassDescriptorResolverFactory.createClassDescriptorResolver(BindingType.XML);
 1551   //                _cdResolver.setClassLoader(_loader);
 1552   //            }
 1553               if (getInternalContext().getXMLClassDescriptorResolver() == null) {
 1554                   // Joachim 2007-09-04 check is new
 1555                   String message = "XMLClassDescriptorResolver is not set!";
 1556                   LOG.warn(message);
 1557                   throw new IllegalStateException(message);
 1558               }
 1559   
 1560               _topState = new UnmarshalState();            
 1561               _topState.elementName = name;
 1562               _topState.wsPreserve = (xmlSpace != null) ? PRESERVE.equals(xmlSpace) : _wsPreserve;
 1563               
 1564               XMLClassDescriptor classDesc = null;
 1565               //-- If _topClass is null, then we need to search
 1566               //-- the resolver for one
 1567               String instanceClassname = null;
 1568               if (_topClass == null) {
 1569   
 1570                   //-- check for xsi:type
 1571                   instanceClassname = getInstanceType(atts, null);
 1572                   if (instanceClassname != null) {
 1573                       //-- first try loading class directly
 1574                       try {
 1575                           _topClass = loadClass(instanceClassname, null);
 1576                       }
 1577                       catch(ClassNotFoundException cnfe) {}
 1578                           
 1579                       if (_topClass == null) {
 1580                           classDesc = getClassDescriptor(instanceClassname);
 1581                           if (classDesc != null) {
 1582                               _topClass = classDesc.getJavaClass();
 1583                           }
 1584                           if (_topClass == null) {
 1585                               throw new SAXException("Class not found: " +
 1586                                   instanceClassname);
 1587                           }
 1588                       }
 1589                   }
 1590                   else {
 1591                       classDesc = resolveByXMLName(name, namespace, null);
 1592                       if (classDesc == null) {
 1593                           classDesc = getClassDescriptor(name, _loader);
 1594                           if (classDesc == null) {
 1595                               classDesc = getClassDescriptor(getJavaNaming().toJavaClassName(name));
 1596                           }
 1597                       }
 1598                       if (classDesc != null) {
 1599                           _topClass = classDesc.getJavaClass();
 1600                       }
 1601                   }
 1602   
 1603                   if (_topClass == null) {
 1604                       String err = "The class for the root element '" +
 1605                           name + "' could not be found.";
 1606                       throw new SAXException(err);
 1607                   }
 1608               }
 1609   
 1610               //-- create a "fake" FieldDescriptor for the root element
 1611               XMLFieldDescriptorImpl fieldDesc
 1612                   = new XMLFieldDescriptorImpl(_topClass,
 1613                                                name,
 1614                                                name,
 1615                                                NodeType.Element);
 1616   
 1617               _topState.fieldDesc = fieldDesc;
 1618               //-- look for XMLClassDescriptor if null
 1619               //-- always check resolver first
 1620               if (classDesc == null)
 1621                   classDesc = getClassDescriptor(_topClass);
 1622                   
 1623               //-- check for top-level primitives 
 1624               if (classDesc == null) {
 1625                   if (isPrimitive(_topClass)) {
 1626                       classDesc = new PrimitivesClassDescriptor(_topClass);
 1627                       fieldDesc.setIncremental(false);
 1628                       _topState.primitiveOrImmutable = true;
 1629                   }
 1630               }
 1631               
 1632               fieldDesc.setClassDescriptor(classDesc);
 1633               if (classDesc == null) {
 1634                   //-- report error
 1635   			    if ((!isPrimitive(_topClass)) &&
 1636                (!Serializable.class.isAssignableFrom( _topClass )))
 1637                throw new SAXException(MarshalException.NON_SERIALIZABLE_ERR);
 1638             String err = "unable to create XMLClassDescriptor " +
 1639                          "for class: " + _topClass.getName();
 1640             throw new SAXException(err);
 1641               }
 1642               _topState.classDesc = classDesc;
 1643               _topState.type = _topClass;
 1644   
 1645               if  ((_topObject == null) && (!_topState.primitiveOrImmutable)) {
 1646                   // Retrieving the xsi:type attribute, if present
 1647                   String topPackage = getJavaPackage(_topClass);
 1648                   
 1649                   if (instanceClassname == null)
 1650                       instanceClassname = getInstanceType(atts, topPackage);
 1651                   else {
 1652                       //-- instance type already processed above, reset
 1653                       //-- to null to prevent entering next block
 1654                       instanceClassname = null;
 1655                   }
 1656                       
 1657                   if (instanceClassname != null) {
 1658                       Class instanceClass = null;
 1659                       try {
 1660   
 1661                           XMLClassDescriptor xcd =
 1662                               getClassDescriptor(instanceClassname);
 1663   
 1664                           boolean loadClass = true;
 1665                           if (xcd != null) {
 1666                               instanceClass = xcd.getJavaClass();
 1667                               if (instanceClass != null) {
 1668                                   loadClass = (!instanceClassname.equals(instanceClass.getName()));
 1669                               }
 1670                           }
 1671                           
 1672                           if (loadClass) {
 1673                               try {
 1674                                   instanceClass = loadClass(instanceClassname, null);
 1675                               }
 1676                               catch(ClassNotFoundException cnfe) {
 1677                                   //-- revert back to ClassDescriptor's associated
 1678                                   //-- class
 1679                                   if (xcd != null)
 1680                                       instanceClass = xcd.getJavaClass();
 1681                               }
 1682                           }
 1683   
 1684                           if (instanceClass == null) {
 1685                               throw new SAXException("Class not found: " +
 1686                                   instanceClassname);
 1687                           }
 1688   
 1689                           if (!_topClass.isAssignableFrom(instanceClass)) {
 1690                               String err = instanceClass + " is not a subclass of "
 1691                                   + _topClass;
 1692                               throw new SAXException(err);
 1693                           }
 1694   
 1695                       }
 1696                       catch(Exception ex) {
 1697                           String msg = "unable to instantiate " +
 1698                               instanceClassname + "; ";
 1699                           throw new SAXException(msg + ex, ex);
 1700                       }
 1701   
 1702                       //-- try to create instance of the given Class
 1703                       Arguments args = processConstructorArgs(atts, classDesc);
 1704                       _topState.object = createInstance(instanceClass, args);
 1705                   }
 1706                   //-- no xsi type information present
 1707                   else {
 1708                       //-- try to create instance of the given Class
 1709                       Arguments args = processConstructorArgs(atts, classDesc);
 1710                       _topState.object = createInstance(_topClass, args);
 1711                   }
 1712               }
 1713               //-- otherwise use _topObject
 1714               else {
 1715                   _topState.object = _topObject;
 1716               }
 1717               
 1718               _stateInfo.push(_topState);
 1719               
 1720               if (!_topState.primitiveOrImmutable) {
 1721                   //--The top object has just been initialized
 1722                   //--notify the listener
 1723                   if ( _unmarshalListener != null )
 1724                       _unmarshalListener.initialized(_topState.object, (_topState.parent==null)?null:_topState.parent.object);
 1725                       
 1726                   processAttributes(atts, classDesc);
 1727                   if ( _unmarshalListener != null )
 1728                       _unmarshalListener.attributesProcessed(_topState.object, (_topState.parent==null)?null:_topState.parent.object);
 1729                   processNamespaces(classDesc);
 1730               }
 1731               
 1732               String pkg = getJavaPackage(_topClass);
 1733               if (getMappedPackage(namespace) == null) 
 1734               {
 1735                   addNamespaceToPackageMapping(namespace, pkg);
 1736               }
 1737               return;
 1738           } //--rootElement
 1739   
 1740   
 1741           //-- get MarshalDescriptor for the given element
 1742           UnmarshalState parentState = (UnmarshalState)_stateInfo.peek();
 1743   
 1744           //Test if we can accept the field in the parentState
 1745           //in case the parentState fieldDesc is a container
 1746           //-- This following logic tests to see if we are in a
 1747           //-- container and we need to close out the container
 1748           //-- before proceeding:
 1749           boolean canAccept = false;
 1750           while ((parentState.fieldDesc != null) &&
 1751                  (parentState.fieldDesc.isContainer() && !canAccept) )
 1752           {
 1753               XMLClassDescriptor tempClassDesc = parentState.classDesc;
 1754   
 1755               //-- Find ClassDescriptor for Parent
 1756               if (tempClassDesc == null) {
 1757                  tempClassDesc = (XMLClassDescriptor)parentState.fieldDesc.getClassDescriptor();
 1758                  if (tempClassDesc == null)
 1759                     tempClassDesc = getClassDescriptor(parentState.object.getClass());
 1760               }
 1761               
 1762               canAccept = tempClassDesc.canAccept(name, namespace, parentState.object);
 1763   
 1764               if (!canAccept) {
 1765                   //-- Does container class even handle this field?
 1766                   if (tempClassDesc.getFieldDescriptor(name, namespace, NodeType.Element) != null) {
 1767                       if (!parentState.fieldDesc.isMultivalued()) { 
 1768                           String error = "The container object (" + tempClassDesc.getJavaClass().getName();
 1769                           error += ") cannot accept the child object associated with the element '" + name + "'";
 1770                           error += " because the container is already full!";
 1771                           ValidationException vx = new ValidationException(error);
 1772                           throw new SAXException(vx);    
 1773                       }
 1774                   }
 1775                   endElement(parentState.elementName);
 1776                   parentState = (UnmarshalState)_stateInfo.peek();
 1777               }
 1778               tempClassDesc = null;
 1779           }
 1780           
 1781           
 1782           
 1783   
 1784   
 1785           //-- create new state object
 1786           state = new UnmarshalState();
 1787           state.elementName = name;
 1788           state.parent = parentState;
 1789           
 1790           if (xmlSpace != null)        
 1791               state.wsPreserve = PRESERVE.equals(xmlSpace);
 1792           else
 1793               state.wsPreserve = parentState.wsPreserve;
 1794           
 1795           _stateInfo.push(state);
 1796   
 1797           //-- make sure we should proceed
 1798           if (parentState.object == null) {
 1799               if (!parentState.wrapper) return;
 1800           }
 1801   
 1802           Class _class = null;
 1803   
 1804           //-- Find ClassDescriptor for Parent
 1805           XMLClassDescriptor classDesc = parentState.classDesc;
 1806           if (classDesc == null) {
 1807               classDesc = (XMLClassDescriptor)parentState.fieldDesc.getClassDescriptor();
 1808               if (classDesc == null)
 1809                   classDesc = getClassDescriptor(parentState.object.getClass());
 1810           } else {
 1811               // classDesc.resetElementCount();
 1812           }
 1813   
 1814           //----------------------------------------------------/
 1815           //- Find FieldDescriptor associated with the element -/
 1816           //----------------------------------------------------/
 1817           
 1818           //-- A reference to the FieldDescriptor associated
 1819           //-- the the "current" element
 1820           XMLFieldDescriptor descriptor = null; 
 1821           
 1822           //-- inherited class descriptor 
 1823           //-- (only needed if descriptor cannot be found directly)
 1824           XMLClassDescriptor cdInherited = null;
 1825           
 1826           
 1827           //-- loop through stack and find correct descriptor
 1828           //int pIdx = _stateInfo.size() - 2; //-- index of parentState
 1829           UnmarshalState targetState = parentState;
 1830           String path = "";
 1831           StringBuffer pathBuf = null;
 1832           int count = 0;
 1833           boolean isWrapper = false;
 1834           XMLClassDescriptor oldClassDesc = classDesc;
 1835           while (descriptor == null) {
 1836               
 1837               //-- NOTE (kv 20050228): 
 1838               //-- we need to clean this code up, I made this
 1839               //-- fix to make sure the correct descriptor which
 1840               //-- matches the location path is used
 1841               if (path.length() > 0) {
 1842                   String tmpName = path + "/" + name;
 1843                   descriptor = classDesc.getFieldDescriptor(tmpName, namespace, NodeType.Element);
 1844               }
 1845               //-- End Patch
 1846               
 1847               if (descriptor == null) { 
 1848                   descriptor = classDesc.getFieldDescriptor(name, namespace, NodeType.Element);
 1849               }
 1850               
 1851               //-- Namespace patch, should be moved to XMLClassDescriptor, but
 1852               //-- this is the least intrusive patch at the moment. kv - 20030423
 1853               if ((descriptor != null) && (!descriptor.isContainer())) {
 1854                   if ((namespace != null) && (namespace.length() > 0)) {
 1855                       if (!namespaceEquals(namespace, descriptor.getNameSpaceURI())) {
 1856                           //-- if descriptor namespace is not null, then we must
 1857                           //-- have a namespace match, so set descriptor to null,
 1858                           //-- or if descriptor is not a wildcard we can also
 1859                           //-- set to null. 
 1860                           if ((descriptor.getNameSpaceURI() != null) || (!descriptor.matches("*"))) {
 1861                               descriptor = null;
 1862                           }
 1863                           
 1864                       }
 1865                   }
 1866               }
 1867               //-- end namespace patch
 1868               
 1869               
 1870               /*
 1871                  If descriptor is null, we need to handle possible inheritence,
 1872                  which might not be described in the current ClassDescriptor.
 1873                  This can be a slow process...for speed use the match attribute
 1874                  of the xml element in the mapping file. This logic might
 1875                  not be completely necessary, and perhaps we should remove it.
 1876               */
 1877               // handle multiple level locations (where count > 0) (CASTOR-1039)
 1878               // if ((descriptor == null) && (count == 0) && (!targetState.wrapper)) {
 1879               if ((descriptor == null) && (!targetState.wrapper)) {
 1880                   MarshalFramework.InheritanceMatch[] matches = null;
 1881                   try {
 1882                       matches = searchInheritance(name, namespace, classDesc); // TODO: Joachim, _cdResolver);
 1883                   }
 1884                   catch(MarshalException rx) {
 1885                       //-- TODO: 
 1886                   }
 1887                   if (matches.length != 0) {
 1888                       InheritanceMatch match = null;
 1889                       // It may be the case that this class descriptor can
 1890                       // appear under multiple parent field descriptors.  Look
 1891                       // for the first match whose parent file descriptor XML
 1892                       // name matches the name of the element we are under
 1893                       for(int i = 0; i < matches.length; i++) {
 1894                           if(parentState.elementName.equals(matches[i].parentFieldDesc.getLocationPath())) {
 1895                               match = matches[i];
 1896                               break;
 1897                           }
 1898                       }
 1899                       if(match == null) match = matches[0];                    
 1900                       descriptor  = match.parentFieldDesc;
 1901                       cdInherited = match.inheritedClassDesc;
 1902                       break; //-- found
 1903                   }
 1904                   /* */
 1905                   
 1906                   // handle multiple level locations (where count > 0) (CASTOR-1039)
 1907                   // isWrapper = (isWrapper || hasFieldsAtLocation(name, classDesc));
 1908                   String tmpLocation = name;
 1909                   if (count > 0) { tmpLocation = path + "/" + name; }
 1910                   isWrapper = (isWrapper || hasFieldsAtLocation(tmpLocation, classDesc));
 1911               }
 1912               else if (descriptor != null) {
 1913                   String tmpPath = descriptor.getLocationPath();
 1914                   if (tmpPath == null) tmpPath = "";
 1915                   if (path.equals(tmpPath))break; //-- found
 1916                   descriptor = null; //-- not found, try again
 1917               }
 1918               else {
 1919                   if (pathBuf == null) 
 1920                       pathBuf = new StringBuffer();
 1921                   else 
 1922                       pathBuf.setLength(0);
 1923                   pathBuf.append(path);
 1924                   pathBuf.append('/');
 1925                   pathBuf.append(name);
 1926                   isWrapper = (isWrapper || hasFieldsAtLocation(pathBuf.toString(), classDesc));
 1927               }
 1928               
 1929               //-- Make sure there are more parent classes on stack
 1930               //-- otherwise break, since there is nothing to do
 1931               //if (pIdx == 0) break;
 1932               if (targetState == _topState) break;
 1933               
 1934               //-- adjust name and try parent
 1935               if (count == 0)
 1936                   path = targetState.elementName;
 1937               else {
 1938                   if (pathBuf == null) 
 1939                       pathBuf = new StringBuffer();
 1940                   else 
 1941                       pathBuf.setLength(0);
 1942                   pathBuf.append(targetState.elementName);
 1943                   pathBuf.append('/');
 1944                   pathBuf.append(path);
 1945                   path = pathBuf.toString();
 1946               }
 1947                   
 1948               //-- get 
 1949               //--pIdx;
 1950               //targetState = (UnmarshalState)_stateInfo.elementAt(pIdx);
 1951               targetState = targetState.parent;
 1952               classDesc = targetState.classDesc;
 1953               count++;
 1954           }
 1955           
 1956           if (descriptor != null && isValidating() && !getInternalContext().getLenientSequenceOrder()) {
 1957               try {
 1958                   classDesc.checkDescriptorForCorrectOrderWithinSequence(descriptor, parentState, name);
 1959               } catch (ValidationException e) {
 1960                   throw new SAXException(e);
 1961               }
 1962           }
 1963           
 1964           
 1965           //-- The field descriptor is still null, we face a problem
 1966           if (descriptor == null) {
 1967               
 1968               //-- reset classDesc
 1969               classDesc = oldClassDesc;
 1970               
 1971               //-- isWrapper?
 1972               if (isWrapper) {
 1973                   state.classDesc = new XMLClassDescriptorImpl(ContainerElement.class, name);
 1974                   state.wrapper = true;
 1975                   if (LOG.isDebugEnabled()) {
 1976                   	LOG.debug("wrapper-element: " + name);
 1977                   }
 1978                   //-- process attributes
 1979                   processWrapperAttributes(atts);
 1980                   return;
 1981               }
 1982               
 1983               String mesg = "unable to find FieldDescriptor for '" + name;
 1984               mesg += "' in ClassDescriptor of " + classDesc.getXMLName();
 1985   
 1986               //-- unwrap classDesc, if necessary, for the check
 1987               //-- Introspector.introspected done below
 1988               if (classDesc instanceof InternalXMLClassDescriptor) {
 1989                   classDesc = ((InternalXMLClassDescriptor)classDesc).getClassDescriptor();
 1990               }
 1991   
 1992               //-- If we are skipping elements that have appeared in the XML but for
 1993               //-- which we have no mapping, increase the ignore depth counter and return
 1994               boolean lenientElementStrictnessForIntrospection = 
 1995                   getInternalContext()
 1996                   .getBooleanProperty(XMLProperties.LENIENT_INTROSPECTED_ELEMENT_STRICTNESS)
 1997                   .booleanValue();
 1998               if (! _strictElements) {
 1999                   ++_ignoreElementDepth;
 2000                   //-- remove the StateInfo we just added
 2001                   _stateInfo.pop();
 2002                   // drop Namespace instance as well
 2003                   _namespaces = _namespaces.getParent();
 2004                   if (LOG.isDebugEnabled()) {
 2005                   	LOG.debug(mesg + " - ignoring extra element.");
 2006                   }
 2007                   return;
 2008               }
 2009               //if we have no field descriptor and
 2010               //the class descriptor was introspected
 2011               //just log it
 2012               else if (lenientElementStrictnessForIntrospection && Introspector.introspected(classDesc)) {
 2013                   LOG.warn(mesg);
 2014                   return;
 2015               }
 2016               //-- otherwise report error since we cannot find a suitable 
 2017               //-- descriptor
 2018               else {
 2019                   throw new SAXException(mesg);
 2020               }
 2021           } //-- end null descriptor
 2022           
 2023           /// DEBUG: System.out.println("path: " + path);
 2024   
 2025           //-- Save targetState (used in endElement)
 2026           if (targetState != parentState) {
 2027               state.targetState = targetState;
 2028               parentState = targetState; //-- reassign
 2029           }
 2030   
 2031           Object object = parentState.object;
 2032           //--container support
 2033           if (descriptor.isContainer()) {
 2034               //create a new state to set the container as the object
 2035               //don't save the current state, it will be recreated later
 2036               
 2037               if (LOG.isDebugEnabled()) {
 2038               	LOG.debug("#container: " + descriptor.getFieldName());
 2039               }
 2040               
 2041               //-- clear current state and re-use for the container
 2042               state.clear();
 2043               //-- inherit whitespace preserving from the parentState
 2044               state.wsPreserve = parentState.wsPreserve;
 2045               state.parent = parentState;
 2046               
 2047               //here we can hard-code a name or take the field name
 2048               state.elementName = descriptor.getFieldName();
 2049               state.fieldDesc = descriptor;
 2050               state.classDesc = (XMLClassDescriptor)descriptor.getClassDescriptor();
 2051               Object containerObject = null;
 2052   
 2053               //1-- the container is not multivalued (not a collection)
 2054               if (!descriptor.isMultivalued()) {
 2055                   // Check if the container object has already been instantiated
 2056                   FieldHandler handler = descriptor.getHandler();
 2057                   containerObject = handler.getValue(object);
 2058                   if (containerObject != null){
 2059                       if (state.classDesc != null) {
 2060                       	if (state.classDesc.canAccept(name, namespace, containerObject)) {
 2061                               //remove the descriptor from the used list
 2062                               parentState.markAsNotUsed(descriptor);
 2063                           }
 2064                       }
 2065                       else {
 2066                           //remove the descriptor from the used list
 2067                           parentState.markAsNotUsed(descriptor);
 2068                       }
 2069                   }
 2070                   else {
 2071                       containerObject = handler.newInstance(object);
 2072                   }
 2073   
 2074               }
 2075               //2-- the container is multivalued
 2076               else {
 2077                   Class containerClass = descriptor.getFieldType();
 2078                   try {
 2079                        containerObject = containerClass.newInstance();
 2080                   }
 2081                   catch(Exception ex) {
 2082                       throw new SAXException(ex);
 2083                   }
 2084               }
 2085               state.object = containerObject;
 2086               state.type = containerObject.getClass();
 2087   
 2088               //we need to recall startElement()
 2089               //so that we can find a more appropriate descriptor in for the given name
 2090               _namespaces = _namespaces.createNamespaces();
 2091               startElement(name, namespace, atts);
 2092               return;
 2093           }
 2094           //--End of the container support
 2095           
 2096           
 2097   
 2098           //-- Find object type and create new Object of that type
 2099           state.fieldDesc = descriptor;
 2100   
 2101           /* <update>
 2102               *  we need to add this code back in, to make sure
 2103               *  we have proper access rights.
 2104               *
 2105           if (!descriptor.getAccessRights().isWritable()) {
 2106               if (debug) {
 2107                   buf.setLength(0);
 2108                   buf.append("The field for element '");
 2109                   buf.append(name);
 2110                   buf.append("' is read-only.");
 2111                   message(buf.toString());
 2112               }
 2113               return;
 2114           }
 2115           */
 2116   
 2117           //-- Find class to instantiate
 2118           //-- check xml names to see if we should look for a more specific
 2119           //-- ClassDescriptor, otherwise just use the one found in the
 2120           //-- descriptor
 2121           classDesc = null;
 2122           if (cdInherited != null) classDesc = cdInherited;
 2123           else if (!name.equals(descriptor.getXMLName()))
 2124               classDesc = resolveByXMLName(name, namespace, null);
 2125   
 2126           if (classDesc == null)
 2127               classDesc = (XMLClassDescriptor)descriptor.getClassDescriptor();
 2128           FieldHandler handler = descriptor.getHandler();
 2129           boolean useHandler = true;
 2130   
 2131           try {
 2132   
 2133               //-- Get Class type...first use ClassDescriptor,
 2134               //-- since it could be more specific than
 2135               //-- the FieldDescriptor
 2136               if (classDesc != null) {
 2137                   _class = classDesc.getJavaClass();
 2138   
 2139                   //-- XXXX This is a hack I know...but we
 2140                   //-- XXXX can't use the handler if the field
 2141                   //-- XXXX types are different
 2142                   if (descriptor.getFieldType() != _class) {
 2143                       state.derived = true;
 2144                   }
 2145               }
 2146               else {
 2147                   _class = descriptor.getFieldType();
 2148               }
 2149               
 2150               //-- This *shouldn't* happen, but a custom implementation
 2151               //-- could return null in the XMLClassDesctiptor#getJavaClass
 2152               //-- or XMLFieldDescriptor#getFieldType. If so, just replace
 2153               //-- with java.lang.Object.class (basically "anyType").
 2154               if (_class == null) {
 2155                   _class = java.lang.Object.class;
 2156               }
 2157   
 2158               // Retrieving the xsi:type attribute, if present
 2159               String currentPackage = getJavaPackage(parentState.type);
 2160               String instanceType = getInstanceType(atts, currentPackage);
 2161               if (instanceType != null) {
 2162                   
 2163                   Class instanceClass = null;
 2164                   try {
 2165   
 2166                       XMLClassDescriptor instanceDesc
 2167                           = getClassDescriptor(instanceType, _loader);
 2168   
 2169                       boolean loadClass = true;
 2170   
 2171                       if (instanceDesc != null) {
 2172                           instanceClass = instanceDesc.getJavaClass();
 2173                           classDesc = instanceDesc;
 2174                           if (instanceClass != null) {
 2175                               loadClass = (!instanceClass.getName().equals(instanceType));
 2176                           }
 2177                       }
 2178   
 2179                       if (loadClass) {
 2180                           instanceClass = loadClass(instanceType, null);
 2181                           //the FieldHandler can be either an XMLFieldHandler
 2182                           //or a FieldHandlerImpl
 2183                           FieldHandler tempHandler = descriptor.getHandler();
 2184   
 2185                           boolean collection = false;
 2186                           if (tempHandler instanceof FieldHandlerImpl) {
 2187                               collection = ((FieldHandlerImpl) tempHandler).isCollection(); 
 2188                           }
 2189                           else {
 2190                               collection = Introspector.isCollection(instanceClass);
 2191                           }
 2192   
 2193                           if ((!collection) && !_class.isAssignableFrom(instanceClass))
 2194                           {
 2195                               if (!isPrimitive(_class)) {
 2196                                   String err = instanceClass.getName()
 2197                                       + " is not a subclass of " + _class.getName();
 2198                                   throw new SAXException(err);
 2199                               }
 2200                           }
 2201                       }
 2202                       _class = instanceClass;
 2203                       useHandler = false;
 2204                   }
 2205                   catch(Exception ex) {
 2206                       String msg = "unable to instantiate " + instanceType;
 2207                       throw new SAXException(msg + "; " + ex, ex);
 2208                   }
 2209   
 2210               }
 2211   
 2212               //-- Handle ArrayHandler
 2213               if (_class == Object.class) {
 2214                   if (parentState.object instanceof ArrayHandler)
 2215                       _class = ((ArrayHandler)parentState.object).componentType();
 2216               }
 2217               
 2218               //-- Handle support for "Any" type
 2219   
 2220               if (_class == Object.class) {
 2221                   Class pClass = parentState.type;
 2222                   ClassLoader loader = pClass.getClassLoader();
 2223                   //-- first look for a descriptor based
 2224                   //-- on the XML name
 2225                   classDesc = resolveByXMLName(name, namespace, loader);
 2226                   //-- if null, create classname, and try resolving
 2227                   String cname = null;
 2228                   if (classDesc == null) {
 2229                       //-- create class name
 2230                       cname = getJavaNaming().toJavaClassName(name);
 2231                       classDesc = getClassDescriptor(cname, loader);
 2232                   }
 2233                   //-- if still null, try using parents package
 2234                   if (classDesc == null) {
 2235                       //-- use parent to get package information
 2236                       String pkg = pClass.getName();
 2237                       int idx = pkg.lastIndexOf('.');
 2238                       if (idx > 0) {
 2239                           pkg = pkg.substring(0,idx+1);
 2240                           cname = pkg + cname;
 2241                           classDesc = getClassDescriptor(cname, loader);
 2242                       }
 2243                   }
 2244   
 2245                   if (classDesc != null) {
 2246                       _class = classDesc.getJavaClass();
 2247                       useHandler = false;
 2248                   }
 2249                   else {
 2250                       //we are dealing with an AnyNode
 2251                       //1- creates a new SAX2ANY handler
 2252                       _anyUnmarshaller = new SAX2ANY(_namespaces, state.wsPreserve);
 2253                       //2- delegates the element handling
 2254                       if (_elemInfo.attributeList != null) {
 2255                           //-- SAX 1
 2256                           _anyUnmarshaller.startElement(_elemInfo.qName, 
 2257                               _elemInfo.attributeList);
 2258                       }
 2259                       else {
 2260                           //-- SAX 2
 2261                           _anyUnmarshaller.startElement(namespace, name, _elemInfo.qName, 
 2262                               _elemInfo.attributes);
 2263                       }
 2264                       //first element so depth can only be one at this point
 2265                       _depth = 1;
 2266                       state.object = _anyUnmarshaller.getStartingNode();
 2267                       state.type = _class;
 2268                       //don't need to continue
 2269                        return;
 2270                   }
 2271               }
 2272               
 2273               boolean byteArray = false;
 2274               if (_class.isArray())
 2275                   byteArray = (_class.getComponentType() == Byte.TYPE);
 2276   
 2277               //-- check for immutable
 2278               if (isPrimitive(_class) ||
 2279                   descriptor.isImmutable() ||
 2280                   byteArray)
 2281               {
 2282                   state.object = null;
 2283                   state.primitiveOrImmutable = true;  
 2284                   //-- handle immutable types, such as java.util.Locale
 2285                   if (descriptor.isImmutable()) {
 2286                       if (classDesc == null)
 2287                           classDesc = getClassDescriptor(_class);
 2288                       state.classDesc = classDesc;
 2289                       Arguments args = processConstructorArgs(atts, classDesc);
 2290                       if ((args != null) && (args.size() > 0)) {
 2291                       	state.args = args;
 2292                       }
 2293                   }
 2294               }
 2295               else {
 2296                   if (classDesc == null)
 2297                       classDesc = getClassDescriptor(_class);
 2298                       
 2299                   //-- XXXX should remove this test once we can
 2300                   //-- XXXX come up with a better solution
 2301                   if ((!state.derived) && useHandler) {
 2302   
 2303                       boolean create = true;
 2304                       if (_reuseObjects) {
 2305                           state.object = handler.getValue(parentState.object);
 2306                           create = (state.object == null);
 2307                       }
 2308                       if (create) {
 2309                           Arguments args = processConstructorArgs(atts, classDesc);
 2310                           if ((args._values != null) && (args._values.length > 0)) {
 2311                               if (handler instanceof ExtendedFieldHandler) {
 2312                                   ExtendedFieldHandler efh = 
 2313                                       (ExtendedFieldHandler)handler;
 2314                                   state.object = efh.newInstance(parentState.object, args._values);
 2315                               }
 2316                               else {
 2317                                   String err = "constructor arguments can only be " +
 2318                                       "used with an ExtendedFieldHandler.";
 2319                                   throw new SAXException(err);
 2320                               }
 2321                           }
 2322                           else {
 2323                               state.object = handler.newInstance(parentState.object);
 2324                           }
 2325                       }
 2326                   }
 2327                   //-- reassign class in case there is a conflict
 2328                   //-- between descriptor#getFieldType and
 2329                   //-- handler#newInstance...I should hope not, but
 2330                   //-- who knows
 2331                   if (state.object != null) {
 2332                       _class = state.object.getClass();
 2333                       if (classDesc != null) {
 2334                           if (classDesc.getJavaClass() != _class) {
 2335                               classDesc = null;
 2336                           }
 2337                       }
 2338                   }
 2339                   else {
 2340                       try {
 2341                           if (_class.isArray()) {
 2342                               state.object = new ArrayHandler(_class.getComponentType());
 2343                               _class = ArrayHandler.class;
 2344                           }
 2345                           else {
 2346                               Arguments args = processConstructorArgs(atts, classDesc);
 2347                               state.object = createInstance(_class, args);
 2348                               //state.object = _class.newInstance();
 2349                           }
 2350                       }
 2351                       catch(java.lang.Exception ex) {
 2352                           String err = "unable to instantiate a new type of: ";
 2353                           err += className(_class);
 2354                           err += "; " + ex.getMessage();
 2355                           //storing causal exception using SAX non-standard method...
 2356                           SAXException sx = new SAXException(err, ex);
 2357                           //...and also using Java 1.4 method
 2358                           //sx.initCause(ex);
 2359                           throw sx;
 2360                       }
 2361                   }
 2362               }
 2363               state.type = _class;
 2364           }
 2365           catch (java.lang.IllegalStateException ise) {
 2366               LOG.error(ise.toString());
 2367               throw new SAXException(ise);
 2368           }
 2369   
 2370           //-- At this point we should have a new object, unless
 2371           //-- we are dealing with a primitive type, or a special
 2372           //-- case such as byte[]
 2373           if (classDesc == null) {
 2374               classDesc = getClassDescriptor(_class);
 2375           }
 2376           state.classDesc = classDesc;
 2377   
 2378           if ((state.object == null) && (!state.primitiveOrImmutable))
 2379           {
 2380               String err = "unable to unmarshal: " + name + "\n";
 2381               err += " - unable to instantiate: " + className(_class);
 2382               throw new SAXException(err);
 2383           }
 2384   
 2385           //-- assign object, if incremental
 2386   
 2387           if (descriptor.isIncremental()) {
 2388               if (LOG.isDebugEnabled()) {
 2389               	LOG.debug("debug: Processing incrementally for element: " + name);
 2390               }
 2391               try {
 2392                   handler.setValue(parentState.object, state.object);
 2393               }
 2394               catch(java.lang.IllegalStateException ise) {
 2395                   String err = "unable to add \"" + name + "\" to ";
 2396                   err += parentState.fieldDesc.getXMLName();
 2397                   err += " due to the following error: " + ise;
 2398                   throw new SAXException(err, ise);
 2399               }
 2400           }
 2401   
 2402           if (state.object != null) {
 2403               //--The object has just been initialized
 2404               //--notify the listener
 2405               if ( _unmarshalListener != null )
 2406                   _unmarshalListener.initialized(state.object, (state.parent==null)?null:state.parent.object);
 2407               processAttributes(atts, classDesc);
 2408               if ( _unmarshalListener != null )
 2409                   _unmarshalListener.attributesProcessed(state.object, (state.parent==null)?null:state.parent.object);
 2410               processNamespaces(classDesc);
 2411           }
 2412           else if ((state.type != null) && (!state.primitiveOrImmutable)) {
 2413               if (atts != null) {
 2414                   processWrapperAttributes(atts);
 2415                   StringBuffer buffer = new StringBuffer();
 2416                   buffer.append("The current object for element '");
 2417                   buffer.append(name);
 2418                   buffer.append("\' is null. Processing attributes as location");
 2419                   buffer.append("/wrapper only and ignoring all other attribtes.");
 2420                   LOG.warn(buffer.toString());
 2421               }
 2422           }
 2423           else {
 2424           	//-- check for special attributes, such as xsi:nil
 2425               if (atts != null) {
 2426               	String nil = atts.getValue(NIL_ATTR, XSI_NAMESPACE);
 2427                   state.nil = "true".equals(nil);
 2428                   processWrapperAttributes(atts);
 2429               }
 2430           }
 2431   
 2432       } //-- void startElement(String, AttributeList)
 2433   
 2434   
 2435   
 2436       /**
 2437        * Indicates whether validation is enabled or not.
 2438        * @return True if validation is enabled.
 2439        */
 2440       private boolean isValidating() {
 2441           return _validate;
 2442       }
 2443   
 2444       /**
 2445        * Signals to start the namespace - prefix mapping
 2446        * 
 2447        * @param prefix the namespace prefix to map
 2448        * @param uri the namespace URI
 2449        */
 2450       public void startPrefixMapping(String prefix, String uri)
 2451           throws SAXException
 2452       { 
 2453           
 2454           //-- Patch for Xerces 2.x bug
 2455           //-- prevent attempting to declare "XML" namespace
 2456           if (Namespaces.XML_NAMESPACE_PREFIX.equals(prefix) && 
 2457               Namespaces.XML_NAMESPACE.equals(uri))             
 2458           {
 2459               return;
 2460           }
 2461           else if (XMLNS.equals(prefix)) {
 2462           	return;
 2463           }
 2464           //-- end Xerces 2.x bug
 2465           
 2466           //-- Forward the call to SAX2ANY 
 2467           //-- or create a namespace node
 2468           if (_anyUnmarshaller != null) {
 2469               _anyUnmarshaller.startPrefixMapping(prefix, uri);
 2470           }
 2471           else if (_createNamespaceScope) {
 2472               _namespaces = _namespaces.createNamespaces();
 2473               _createNamespaceScope = false;
 2474           }
 2475           
 2476           _namespaces.addNamespace(prefix, uri);
 2477           
 2478           /*
 2479           //-- add namespace declarations to set of current attributes        
 2480           String attName = null;
 2481           if ((prefix == null)  || (prefix.length() == 0))
 2482               attName = XMLNS_DECL;
 2483           else
 2484               attName = XMLNS_PREFIX + prefix;
 2485               
 2486           _currentAtts.addAttribute(attName, uri);
 2487           */
 2488           
 2489       } //-- startPrefixMapping
 2490   
 2491   
 2492        //------------------------------------/
 2493       //- org.xml.sax.ErrorHandler methods -/
 2494       //------------------------------------/
 2495   
 2496       public void error(SAXParseException exception)
 2497           throws org.xml.sax.SAXException
 2498       {
 2499           String err = "Parsing Error : "+exception.getMessage()+'\n'+
 2500                        "Line : "+ exception.getLineNumber() + '\n'+
 2501                        "Column : "+exception.getColumnNumber() + '\n';
 2502           throw new SAXException (err, exception);
 2503       } //-- error
 2504   
 2505       public void fatalError(SAXParseException exception)
 2506           throws org.xml.sax.SAXException
 2507       {
 2508           String err = "Parsing Error : "+exception.getMessage()+'\n'+
 2509                        "Line : "+ exception.getLineNumber() + '\n'+
 2510                        "Column : "+exception.getColumnNumber() + '\n';
 2511           throw new SAXException (err, exception);
 2512   
 2513       } //-- fatalError
 2514   
 2515   
 2516       public void warning(SAXParseException exception)
 2517           throws org.xml.sax.SAXException
 2518       {
 2519           String err = "Parsing Error : "+exception.getMessage()+'\n'+
 2520                        "Line : "+ exception.getLineNumber() + '\n'+
 2521                        "Column : "+exception.getColumnNumber() + '\n';
 2522           throw new SAXException (err, exception);
 2523   
 2524       } //-- warning
 2525   
 2526         //---------------------/
 2527        //- Protected Methods -/
 2528       //---------------------/
 2529   
 2530       // TODO: Joachim 2007-09-04 remove me
 2531   //    /**
 2532   //     * Sets the current Castor configuration. Currently this
 2533   //     * Configuration is only used during Validation (which is
 2534   //     * why this method is currently protected, since it has
 2535   //     * no effect at this point on the actual configuration of 
 2536   //     * the unmarshaller)
 2537   //     *
 2538   //     * Currently, this method should only be called by the 
 2539   //     * Unmarshaller.
 2540   //     */
 2541   //    protected void setConfiguration(Configuration config) {
 2542   //        _config = config;
 2543   //    } //-- setConfiguration
 2544       
 2545         //-------------------/
 2546        //- Private Methods -/
 2547       //-------------------/
 2548   
 2549       /**
 2550        * Adds the given reference to the "queue" until the referenced object
 2551        * has been unmarshalled.
 2552        *
 2553        * @param idRef the ID being referenced
 2554        * @param parent the target/parent object for the field
 2555        * @param descriptor the XMLFieldDescriptor for the field
 2556        */
 2557       private void addReference(final String idRef, final Object parent, 
 2558               final XMLFieldDescriptor descriptor) {
 2559           
 2560           ReferenceInfo refInfo = new ReferenceInfo(idRef, parent, descriptor);
 2561           refInfo.setNext((ReferenceInfo) _resolveTable.get(idRef));
 2562           _resolveTable.put(idRef, refInfo);
 2563       }
 2564       
 2565       /**
 2566        * Creates an instance of the given class /type, using 
 2567        * the arguments provided (if there are any).
 2568        * @param type The class type to be used during instantiation
 2569        * @param args (Optional) arguments to be used during instantiation
 2570        */
 2571        private Object createInstance(final Class type, final Arguments args)
 2572               throws SAXException {
 2573           Object instance = null;
 2574           try {
 2575               if (args == null) {
 2576                   instance = _objectFactory.createInstance(type);
 2577               } else {
 2578                   instance = _objectFactory.createInstance(type, args._types,
 2579                           args._values);
 2580               }
 2581           } catch (Exception ex) {
 2582               String msg = "Unable to instantiate " + type.getName() + "; ";
 2583               throw new SAXException(msg, ex);
 2584           }
 2585           return instance;
 2586       } // -- createInstance
 2587        
 2588        /**
 2589        * Returns the resolved instance type attribute (xsi:type).
 2590        * If present the instance type attribute is resolved into
 2591        * a java class name and then returned.
 2592        *
 2593        * @param atts the AttributeList to search for the instance type
 2594        * attribute.
 2595        * @return the java class name corresponding to the value of
 2596        * the instance type attribute, or null if no instance type
 2597        * attribute exists in the given AttributeList.
 2598        */
 2599       private String getInstanceType(AttributeSet atts, String currentPackage) 
 2600           throws SAXException
 2601       {
 2602   
 2603           if (atts == null) return null;
 2604   
 2605           //-- find xsi:type attribute
 2606           String type = atts.getValue(XSI_TYPE, XSI_NAMESPACE);
 2607   
 2608           if (type != null) {
 2609               
 2610               if (type.startsWith(JAVA_PREFIX)) {
 2611                   return type.substring(JAVA_PREFIX.length());
 2612               }
 2613               
 2614               // check for namespace prefix in type
 2615               int idx = type.indexOf(':');
 2616               String typeNamespaceURI = null;
 2617               if (idx >= 0) {
 2618                   // there is a namespace prefix
 2619                   String prefix = type.substring(0, idx);
 2620                   type = type.substring(idx + 1);
 2621                   typeNamespaceURI = _namespaces.getNamespaceURI(prefix);
 2622               }
 2623   
 2624               //-- Retrieve the type corresponding to the schema name and
 2625               //-- return it.
 2626               XMLClassDescriptor classDesc = null;
 2627               
 2628               try {
 2629                   classDesc = getInternalContext().getXMLClassDescriptorResolver().resolveByXMLName(type, typeNamespaceURI, _loader);            
 2630   
 2631                   if (classDesc != null)
 2632                       return classDesc.getJavaClass().getName();
 2633   
 2634   
 2635                   //-- if class descriptor is not found here, then no descriptors
 2636                   //-- existed in memory...try to load one based on name of
 2637                   //-- Schema type
 2638                   final String className = getJavaNaming().toJavaClassName(type);
 2639               
 2640                   String adjClassName = className;
 2641                   String mappedPackage = getMappedPackage(typeNamespaceURI);
 2642                   if ((mappedPackage != null) && (mappedPackage.length() > 0)) {
 2643                       adjClassName = mappedPackage + "." + className;
 2644                   }
 2645               	classDesc = getInternalContext().getXMLClassDescriptorResolver().resolve(adjClassName, _loader);
 2646                   if (classDesc != null)
 2647                       return classDesc.getJavaClass().getName();
 2648   
 2649                   //-- try to use "current Package"
 2650                   if ((currentPackage != null) && currentPackage.length() > 0) {
 2651                   	adjClassName = currentPackage + '.' + className;
 2652                   }
 2653                   
 2654                   classDesc = getInternalContext().getXMLClassDescriptorResolver().resolve(adjClassName, _loader);
 2655                   if (classDesc != null)
 2656                       return classDesc.getJavaClass().getName();
 2657                   
 2658                   //-- Still can't find type, this may be due to an
 2659                   //-- attempt to unmarshal an older XML instance
 2660                   //-- that was marshalled with a previous Castor. A
 2661                   //-- bug fix in the XMLMappingLoader prevents old
 2662                   //-- xsi:type that are missing the "java:"
 2663                   classDesc = getInternalContext().getXMLClassDescriptorResolver().resolve(type, _loader);
 2664                   if (classDesc != null)
 2665                       return classDesc.getJavaClass().getName();
 2666               }
 2667               catch(ResolverException rx) {
 2668                   throw new SAXException(rx);
 2669               }
 2670           }
 2671           return null;
 2672       } //-- getInstanceType
 2673       
 2674       /**
 2675        * Looks up the package name from the given namespace URI.
 2676        * 
 2677        * @param namespace the namespace URI to lookup
 2678        * @return the package name or null.
 2679        */
 2680       private String getMappedPackage(final String namespace) {
 2681           String lookUpKey = (namespace != null) ? namespace : "";
 2682           return (String) _namespaceToPackage.get(lookUpKey);
 2683       }
 2684   
 2685       /**
 2686        * Processes the given attribute list, and attempts to add each
 2687        * {@link Attributes} to the current {@link Object} on the stack.
 2688        *
 2689        * @param atts the AttributeSet to process
 2690        * @param classDesc the classDesc to use during processing
 2691       **/
 2692       private void processAttributes(final AttributeSet atts, XMLClassDescriptor classDesc)
 2693           throws SAXException {
 2694   
 2695           //-- handle empty attributes
 2696           if ((atts == null) || (atts.getSize() == 0)) {
 2697               if (classDesc != null) {
 2698                   XMLFieldDescriptor[] descriptors
 2699                       = classDesc.getAttributeDescriptors();
 2700                   for (int i = 0; i < descriptors.length; i++) {
 2701                       XMLFieldDescriptor descriptor = descriptors[i];
 2702                       if (descriptor == null) {
 2703                           continue;
 2704                       }
 2705                       //-- Since many attributes represent primitive
 2706                       //-- fields, we add an extra validation check here
 2707                       //-- in case the class doesn't have a "has-method".
 2708                       if (descriptor.isRequired() && (isValidating() || LOG.isDebugEnabled())) {
 2709                           String err = classDesc.getXMLName() + " is missing " 
 2710                               + "required attribute: " + descriptor.getXMLName();
 2711                           if (_locator != null) {
 2712                               err += "\n  - line: " + _locator.getLineNumber() 
 2713                                   + " column: " + _locator.getColumnNumber();
 2714                           }
 2715                           if (isValidating()) {
 2716                               throw new SAXException(err);
 2717                           }
 2718                           LOG.debug(err);
 2719                       }
 2720                   }
 2721               }
 2722               return;
 2723           }
 2724   
 2725   
 2726           UnmarshalState state = (UnmarshalState) _stateInfo.peek();
 2727           Object object = state.object;
 2728   
 2729           if (classDesc == null) {
 2730               classDesc = state.classDesc;
 2731               if (classDesc == null) {
 2732                   //-- no class desc, cannot process atts
 2733                   //-- except for wrapper/location atts
 2734                   processWrapperAttributes(atts);                
 2735                   return;
 2736               }
 2737           }
 2738           
 2739           //-- First loop through Attribute Descriptors.
 2740           //-- Then, if we have any attributes which
 2741           //-- haven't been processed we can ask
 2742           //-- the XMLClassDescriptor for the FieldDescriptor.
 2743   
 2744           boolean[] processedAtts = new boolean[atts.getSize()];
 2745           XMLFieldDescriptor[] descriptors = classDesc.getAttributeDescriptors();
 2746           for (XMLFieldDescriptor descriptor : descriptors) {
 2747   
 2748               String name      = descriptor.getXMLName();
 2749               String namespace = descriptor.getNameSpaceURI();
 2750               String path = descriptor.getLocationPath();
 2751               String fullAttributePath = "";
 2752               
 2753               if (path != null && path.length() > 0) {
 2754                   fullAttributePath += path + "/"; 
 2755               }
 2756               
 2757               fullAttributePath += name;
 2758               
 2759               if (fullAttributePath != null && !name.equals(fullAttributePath)) {
 2760                   int index = atts.getIndex(name, namespace);
 2761                   if (index >= 0) {
 2762                       processedAtts[index] = true;
 2763                   }
 2764                   continue;
 2765               }
 2766   
 2767               int index = atts.getIndex(name, namespace);
 2768   
 2769               String attValue = null;
 2770               if (index >= 0) {
 2771                   attValue = atts.getValue(index);
 2772                   processedAtts[index] = true;
 2773               }
 2774   
 2775               try {
 2776                   processAttribute(name, namespace, attValue, descriptor, classDesc, object);
 2777               } catch (IllegalStateException ise) {
 2778                   String err = "unable to add attribute \"" + name + "\" to '";
 2779                   err += state.classDesc.getJavaClass().getName();
 2780                   err += "' due to the following error: " + ise;
 2781                   throw new SAXException(err, ise);
 2782               }
 2783           }
 2784   
 2785           //-- Handle any non processed attributes...
 2786           //-- This is useful for descriptors that might use
 2787           //-- wild-cards or other types of matching...as well
 2788           //-- as backward compatibility...attribute descriptors
 2789           //-- were erronously getting set with the default
 2790           //-- namespace by the source generator...this is
 2791           //-- also true of the generated classes for the
 2792           //-- Mapping Framework...we need to clean this up
 2793           //-- at some point in the future.
 2794           for (int i = 0; i < processedAtts.length; i++) {
 2795               if (processedAtts[i]) {
 2796                   continue;
 2797               }
 2798   
 2799               String namespace = atts.getNamespace(i);
 2800               String name = atts.getName(i);
 2801               
 2802               //-- skip XSI attributes
 2803               if (XSI_NAMESPACE.equals(namespace)) {
 2804                   if (NIL_ATTR.equals(name)) {
 2805                       String value = atts.getValue(i);
 2806                       state.nil = ("true".equals(value));
 2807                   }
 2808                   continue;
 2809               }
 2810                   
 2811   
 2812               if (name.startsWith(XML_PREFIX + ':')) {
 2813                   
 2814                   //-- XML specification specific attribute
 2815                   //-- It should be safe to ignore these...but
 2816                   //-- if you think otherwise...let use know!
 2817                   if (LOG.isDebugEnabled()) {
 2818                       String msg = "ignoring attribute '" + name + "' for class: "
 2819                                  + state.classDesc.getJavaClass().getName();
 2820                       LOG.debug(msg);
 2821                   }
 2822                   continue;
 2823               }
 2824   
 2825               //-- This really should handle namespace...but it currently
 2826               //-- doesn't. Ignoring namespaces also helps with the
 2827               //-- backward compatibility issue mentioned above.
 2828               XMLFieldDescriptor descriptor =
 2829                   classDesc.getFieldDescriptor(name, namespace, NodeType.Attribute);
 2830                   
 2831               if (descriptor == null) {
 2832                   //-- check for nested attribute...loop through
 2833                   //-- stack and find correct descriptor
 2834                   int pIdx = _stateInfo.size() - 2; //-- index of parentState
 2835                   String path = state.elementName;
 2836                   StringBuffer pathBuf = null;
 2837                   while (pIdx >= 0) {
 2838                       UnmarshalState targetState = (UnmarshalState) _stateInfo.elementAt(pIdx);
 2839                       --pIdx;
 2840                       if (targetState.wrapper) {
 2841                           //path = targetState.elementName + "/" + path;
 2842                           if (pathBuf == null) {
 2843                               pathBuf = new StringBuffer();
 2844                           } else {
 2845                               pathBuf.setLength(0);
 2846                           }
 2847                           pathBuf.append(targetState.elementName);
 2848                           pathBuf.append('/');
 2849                           pathBuf.append(path);
 2850                           path = pathBuf.toString();
 2851                           continue;
 2852                       }
 2853                       classDesc = targetState.classDesc;
 2854                       descriptor = classDesc.getFieldDescriptor(name, namespace, NodeType.Attribute);
 2855                   
 2856                       if (descriptor != null) {
 2857                           String tmpPath = descriptor.getLocationPath();
 2858                           if (tmpPath == null) {
 2859                               tmpPath = "";
 2860                           }
 2861                           if (path.equals(tmpPath)) {
 2862                               break; //-- found
 2863                           }
 2864                       }
 2865                           
 2866                       if (pathBuf == null) {
 2867                           pathBuf = new StringBuffer();
 2868                       } else {
 2869                           pathBuf.setLength(0);
 2870                       }
 2871                       pathBuf.append(targetState.elementName);
 2872                       pathBuf.append('/');
 2873                       pathBuf.append(path);
 2874                       path = pathBuf.toString();
 2875                       //path = targetState.elementName + "/" + path;
 2876                       //-- reset descriptor to make sure we don't
 2877                       //-- exit the loop with a reference to a 
 2878                       //-- potentially incorrect one.
 2879                       descriptor = null;
 2880                   }
 2881               }
 2882               if (descriptor == null) {
 2883                   if (_strictAttributes) {
 2884                       //-- handle error
 2885                       String error = "The attribute '" + name 
 2886                           + "' appears illegally on element '" 
 2887                           + state.elementName + "'.";
 2888                       throw new SAXException(error);
 2889                   }
 2890                   continue;
 2891               }
 2892   
 2893               try {
 2894                   processAttribute(name, namespace, atts.getValue(i), descriptor, classDesc, object);
 2895               } catch (IllegalStateException ise) {
 2896                   String err = "unable to add attribute \"" + name + "\" to '";
 2897                   err += state.classDesc.getJavaClass().getName();
 2898                   err += "' due to the following error: " + ise;
 2899                   throw new SAXException(err, ise);
 2900               }
 2901           }
 2902   
 2903       }
 2904   
 2905       /**
 2906        * Processes the given AttributeSet for wrapper elements.
 2907        * 
 2908        * @param atts the AttributeSet to process
 2909        * @throws SAXException If the AttributeSet cannot be processed
 2910        */
 2911       private void processWrapperAttributes(final AttributeSet atts)
 2912           throws SAXException {
 2913           
 2914           UnmarshalState state = (UnmarshalState) _stateInfo.peek();
 2915           
 2916           //-- loop through attributes and look for the
 2917           //-- ancestor objects that they may belong to
 2918           for (int i = 0; i < atts.getSize(); i++) {
 2919               String name = atts.getName(i);
 2920               String namespace = atts.getNamespace(i);
 2921               
 2922               //-- skip XSI attributes
 2923               if (XSI_NAMESPACE.equals(namespace)) {
 2924                   continue;
 2925               }
 2926                   
 2927               XMLFieldDescriptor descriptor = null;
 2928               XMLClassDescriptor classDesc = null;
 2929               //-- check for nested attribute...loop through
 2930               //-- stack and find correct descriptor
 2931               int pIdx = _stateInfo.size() - 2; //-- index of parentState
 2932               String path = state.elementName;
 2933               StringBuffer pathBuf = null;
 2934               UnmarshalState targetState = null;
 2935               while (pIdx >= 0) {
 2936                   targetState = (UnmarshalState) _stateInfo.elementAt(pIdx);
 2937                   --pIdx;
 2938                   if (targetState.wrapper) {
 2939                       //path = targetState.elementName + "/" + path;
 2940                       if (pathBuf == null) {
 2941                           pathBuf = new StringBuffer();
 2942                       } else {
 2943                           pathBuf.setLength(0);
 2944                       }
 2945                       pathBuf.append(targetState.elementName);
 2946                       pathBuf.append('/');
 2947                       pathBuf.append(path);
 2948                       path = pathBuf.toString();
 2949                       continue;
 2950                   }
 2951                   classDesc = targetState.classDesc;
 2952                   
 2953                   XMLFieldDescriptor[] descriptors = classDesc.getAttributeDescriptors();
 2954                   boolean found = false;
 2955                   for (int a = 0; a < descriptors.length; a++) {
 2956                       descriptor = descriptors[a];
 2957                       if (descriptor == null) {
 2958                           continue;
 2959                       }
 2960                       if (descriptor.matches(name)) {
 2961                           String tmpPath = descriptor.getLocationPath();
 2962                           if (tmpPath == null) {
 2963                               tmpPath = "";
 2964                           }
 2965                           if (path.equals(tmpPath)) {
 2966                               found = true;
 2967                               break;
 2968                           }
 2969                       }
 2970                   }
 2971                   if (found) {
 2972                       break;
 2973                   }
 2974                           
 2975                   //path = targetState.elementName + "/" + path;
 2976                   if (pathBuf == null) {
 2977                       pathBuf = new StringBuffer();
 2978                   } else {
 2979                       pathBuf.setLength(0);
 2980                   }
 2981                   pathBuf.append(targetState.elementName);
 2982                   pathBuf.append('/');
 2983                   pathBuf.append(path);
 2984                   path = pathBuf.toString();
 2985                   
 2986                   //-- reset descriptor to make sure we don't
 2987                   //-- exit the loop with a reference to a 
 2988                   //-- potentially incorrect one.
 2989                   descriptor = null;
 2990               }
 2991               if (descriptor != null) {
 2992                   try {
 2993                       processAttribute(name, namespace, atts.getValue(i),
 2994                               descriptor, classDesc, targetState.object);
 2995                   } catch (IllegalStateException ise) {
 2996                       String err = "unable to add attribute \"" + name + "\" to '";
 2997                       err += state.classDesc.getJavaClass().getName();
 2998                       err += "' due to the following error: " + ise;
 2999                       throw new SAXException(err, ise);
 3000                   }
 3001               }
 3002           }
 3003           
 3004       }
 3005       
 3006       /**
 3007        * Processes the given Attribute.
 3008       **/
 3009       private void processAttribute
 3010           (final String attName, final String attNamespace, String attValue,
 3011            XMLFieldDescriptor descriptor,
 3012            final XMLClassDescriptor classDesc,
 3013            Object parent) throws SAXException {
 3014   
 3015           //Object value = attValue;
 3016           while (descriptor.isContainer()) {
 3017               FieldHandler handler = descriptor.getHandler();
 3018               Object containerObject = handler.getValue(parent);
 3019   
 3020               if (containerObject == null) {
 3021                   containerObject = handler.newInstance(parent);
 3022                   handler.setValue(parent, containerObject);
 3023               }
 3024   
 3025               ClassDescriptor containerClassDesc = 
 3026                   ((XMLFieldDescriptorImpl) descriptor).getClassDescriptor();
 3027               descriptor = ((XMLClassDescriptor) containerClassDesc).getFieldDescriptor(
 3028                       attName, attNamespace, NodeType.Attribute);
 3029               parent = containerObject;
 3030           }
 3031   
 3032           if (attValue == null) {
 3033                //-- Since many attributes represent primitive
 3034                //-- fields, we add an extra validation check here
 3035                //-- in case the class doesn't have a "has-method".
 3036                if (descriptor.isRequired() && isValidating()) {
 3037                   String err = classDesc.getXMLName() + " is missing " 
 3038                       + "required attribute: " + attName;
 3039                   if (_locator != null) {
 3040                       err += "\n  - line: " + _locator.getLineNumber() 
 3041                           + " column: " + _locator.getColumnNumber();
 3042                   }
 3043                   throw new SAXException(err);
 3044               }
 3045               return;
 3046           }
 3047   
 3048           //-- if this is the identity then save id
 3049           if (classDesc.getIdentity() == descriptor) {
 3050               
 3051               try {
 3052                   _idResolver.bind(attValue, parent, 
 3053                           isValidating() && !getInternalContext().getLenientIdValidation());
 3054               } catch (ValidationException e) {
 3055                   throw new SAXException("Duplicate ID " + attValue + " encountered.", e);
 3056               }
 3057   
 3058               //-- save key in current state
 3059               UnmarshalState state = (UnmarshalState) _stateInfo.peek();
 3060               state.key = attValue;
 3061   
 3062               //-- resolve waiting references
 3063               resolveReferences(attValue, parent);
 3064           } else if (descriptor.isReference()) {
 3065               //-- if this is an IDREF(S) then resolve reference(s)
 3066               if (descriptor.isMultivalued()) {
 3067                   StringTokenizer st = new StringTokenizer(attValue);
 3068                   while (st.hasMoreTokens()) {
 3069                       processIDREF(st.nextToken(), descriptor, parent);
 3070                   }
 3071               } else {
 3072                   processIDREF(attValue, descriptor, parent);
 3073               }
 3074               //-- object values have been set by processIDREF
 3075               //-- simply return
 3076               return;
 3077           }
 3078           
 3079           //-- if it's a constructor argument, we can exit at this point
 3080           //-- since constructor arguments have already been set
 3081           if (descriptor.isConstructorArgument()) {
 3082               return;
 3083           }
 3084   
 3085           //-- attribute handler
 3086           FieldHandler handler = descriptor.getHandler();
 3087           if (handler == null) {
 3088               return;
 3089           }
 3090           
 3091           //-- attribute field type
 3092           Class type = descriptor.getFieldType();
 3093           String valueType = descriptor.getSchemaType();
 3094           boolean isPrimative = isPrimitive(type);
 3095           boolean isQName = (valueType != null && valueType.equals(QNAME_NAME));
 3096           
 3097           boolean isByteArray = false;
 3098           if (type.isArray()) {
 3099               isByteArray = (type.getComponentType() == Byte.TYPE);
 3100           }
 3101           
 3102           //-- if this is an multi-value attribute
 3103           if (descriptor.isMultivalued()) {
 3104               StringTokenizer attrValueTokenizer = new StringTokenizer(attValue);
 3105               while (attrValueTokenizer.hasMoreTokens()) {
 3106                   attValue = attrValueTokenizer.nextToken();
 3107                   setAttributeValueOnObject(attValue, descriptor, parent, handler,
 3108                           type, isPrimative, isQName, isByteArray);
 3109               }
 3110           } else {
 3111               setAttributeValueOnObject(attValue, descriptor, parent, handler,
 3112                       type, isPrimative, isQName, isByteArray);
 3113           }
 3114   
 3115       }
 3116   
 3117       /**
 3118        * Sets the value of an attribute on the target object, using the {@link FieldHandler}
 3119        * provided.
 3120        * @param attValue The attribute value.
 3121        * @param descriptor Corresponding {@link XMLFieldDescriptor} instance for the attribute processed.
 3122        * @param parent Parent object into which attribute value needs to be 'injected'.
 3123        * @param handler {@link FieldHandler} used for 'value injection'.
 3124        * @param type {@link Class} type.
 3125        * @param isPrimitive Indicates whether the attribute value represents a primitive value.
 3126        * @param isQName Indicates whether the attribute value represents a QName value.
 3127        * @param isByteArray Indicates whether the attribute value represents a byte array.
 3128        * @throws SAXException If there's a problem 'injecting' the attribute value into the target field.
 3129        */
 3130       private void setAttributeValueOnObject(final String attValue,
 3131               final XMLFieldDescriptor descriptor, 
 3132               final Object parent, 
 3133               final FieldHandler handler,
 3134               final Class type, 
 3135               final boolean isPrimitive, 
 3136               final boolean isQName,
 3137               final boolean isByteArray) throws SAXException {
 3138           //-- value to set
 3139           Object value = attValue;
 3140           //-- special type conversion for primitives
 3141           if (isPrimitive) {
 3142               value = toPrimitiveObject(type, attValue, descriptor);
 3143           }
 3144           
 3145           //-- special byte[]s provessing, if required
 3146           if (isByteArray) {
 3147               if (attValue == null) {
 3148                   value = new byte[0];
 3149               } else {
 3150                   //-- Base64/hexbinary decoding
 3151                   if (HexDecoder.DATA_TYPE.equals(descriptor.getComponentType())) {
 3152                       value = HexDecoder.decode(attValue);
 3153                   } else {
 3154                       value = Base64Decoder.decode(attValue);
 3155                   }
 3156               }
 3157           }
 3158           
 3159           //-- QName resolution (ns:value -> {URI}value), if required
 3160           if (isQName) {
 3161               value = resolveNamespace(value);
 3162           }
 3163           //-- set value
 3164           handler.setValue(parent, value);
 3165       }
 3166   
 3167       /**
 3168        * Processes the given attribute set, and creates the
 3169        * constructor arguments.
 3170        *
 3171        * @param atts the AttributeSet to process
 3172        * @param classDesc the XMLClassDescriptor of the objec
 3173        * @return the array of constructor argument values.
 3174        * @throws SAXException If there's a problem creating the constructor argument set. 
 3175        */
 3176       private Arguments processConstructorArgs
 3177           (final AttributeSet atts, final XMLClassDescriptor classDesc)
 3178           throws SAXException {
 3179           
 3180           if (classDesc == null) {
 3181               return new Arguments();
 3182           }
 3183   
 3184           //-- Loop through Attribute Descriptors and build
 3185           //-- the argument array
 3186   
 3187           //-- NOTE: Due to IDREF being able to reference an
 3188           //-- un-yet unmarshalled object, we cannot handle
 3189           //-- references as constructor arguments. 
 3190           //-- kvisco - 20030421
 3191           int count = 0;
 3192           XMLFieldDescriptor[] descriptors = classDesc.getAttributeDescriptors();
 3193           for (XMLFieldDescriptor fieldDescriptor : descriptors) {
 3194               if (fieldDescriptor == null) {
 3195                   continue;
 3196               }
 3197               if (fieldDescriptor.isConstructorArgument()) {
 3198                   ++count;
 3199               }
 3200           }
 3201           
 3202           Arguments args = new Arguments();
 3203           
 3204           if (count == 0) {
 3205               return args;
 3206           }
 3207           
 3208           args._values = new Object[count];
 3209           args._types  = new Class[count];
 3210           
 3211           for (XMLFieldDescriptor descriptor : descriptors) {
 3212               
 3213               if (descriptor == null) {
 3214                   continue;
 3215               }
 3216               if (!descriptor.isConstructorArgument()) {
 3217                   continue;
 3218               }
 3219               
 3220               int argIndex = descriptor.getConstructorArgumentIndex();
 3221               if (argIndex >= count) {
 3222                   String err = "argument index out of bounds: " + argIndex;
 3223                   throw new SAXException(err);
 3224               }
 3225   
 3226               args._types[argIndex] = descriptor.getFieldType();
 3227               String name = descriptor.getXMLName();
 3228               String namespace = descriptor.getNameSpaceURI();
 3229   
 3230               int index = atts.getIndex(name, namespace);
 3231   
 3232               if (index >= 0) {
 3233                   Object value = atts.getValue(index);
 3234                   //-- check for proper type and do type
 3235                   //-- conversion
 3236                   if (isPrimitive(args._types[argIndex])) {
 3237                       value = toPrimitiveObject(args._types[argIndex], (String) value, descriptor);
 3238                   } else {
 3239                       // check whether we are looking at an enum-style object, and if so,
 3240                       // convert the (string) value
 3241                       value = convertToEnumObject(descriptor, value);
 3242                   }
 3243                   
 3244                   //check if the value is a QName that needs to
 3245                   //be resolved (ns:value -> {URI}value)
 3246                   String valueType = descriptor.getSchemaType();
 3247                   if ((valueType != null) && (valueType.equals(QNAME_NAME))) {
 3248                           value = resolveNamespace(value);
 3249                   }
 3250                   args._values[argIndex] = value;
 3251               } else {
 3252                   if (isPrimitive(args._types[argIndex])) {
 3253                       args._values[argIndex] = 
 3254                           toPrimitiveObject(args._types[argIndex], null, descriptor);
 3255                   } else {
 3256                       args._values[argIndex] = null;
 3257                   }
 3258               }
 3259           }
 3260           return args;
 3261       }
 3262   
 3263       /**
 3264        * Checks whether the actual value passed in should be converted to an enum-style class
 3265        * instance.
 3266        * 
 3267        * @param descriptor The {@link XMLFieldDescriptor} instance in question.
 3268        * @param value The actual value (which might need conversion).
 3269        * @return The value, potentially converted to an enum-style class.
 3270        */
 3271       private Object convertToEnumObject(final XMLFieldDescriptor descriptor, Object value) {
 3272           Class fieldType = descriptor.getFieldType();
 3273           Method valueOfMethod;
 3274           try {
 3275               valueOfMethod = fieldType.getMethod("valueOf", new Class[] {String.class});
 3276               if (valueOfMethod != null 
 3277                       && Modifier.isStatic(valueOfMethod.getModifiers())) {
 3278                   Class returnType = valueOfMethod.getReturnType();
 3279                   if (returnType.isAssignableFrom(fieldType)) {
 3280                       Object enumObject = valueOfMethod.invoke(null, new Object[] {value});
 3281                       value = enumObject;
 3282                   }
 3283               }
 3284           } catch (SecurityException e) {
 3285               // TODO: well, cannot do anything about it 
 3286           } catch (NoSuchMethodException e) {
 3287               // TODO: nothing to do, as it simply isn't an enum-style class
 3288           } catch (IllegalArgumentException e) {
 3289               // TODO: cannot really happen
 3290           } catch (IllegalAccessException e) {
 3291               // TODO: indicates that the valueOf() method isn't public
 3292           } catch (InvocationTargetException e) {
 3293               // TODO: hmm .. what else
 3294           }
 3295           return value;
 3296       }
 3297   
 3298       /**
 3299        * Processes the given IDREF.
 3300        *
 3301        * @param idRef the ID of the object in which to reference
 3302        * @param descriptor the current FieldDescriptor
 3303        * @param parent the current parent object
 3304        * @return true if the ID was found and resolved properly
 3305        */
 3306       private boolean processIDREF (final String idRef, final XMLFieldDescriptor descriptor, 
 3307               final Object parent) {
 3308           Object value = _idResolver.resolve(idRef);
 3309           if (value == null) {
 3310               //-- save state to resolve later
 3311               addReference(idRef, parent, descriptor);
 3312           } else {
 3313               FieldHandler handler = descriptor.getHandler();
 3314               if (handler != null) {
 3315                   handler.setValue(parent, value);
 3316               }
 3317           }
 3318           return (value != null);
 3319       }
 3320   
 3321       /**
 3322        * Processes the attributes and namespace declarations found
 3323        * in the given SAX AttributeList. The global AttributeSet
 3324        * is cleared and updated with the attributes. Namespace
 3325        * declarations are added to the set of namespaces in scope.
 3326        *
 3327        * @param atts the AttributeList to process.
 3328       **/
 3329       private AttributeSet processAttributeList(AttributeList atts)
 3330           throws SAXException
 3331       {
 3332   
 3333           if (atts == null) return new AttributeSetImpl(0);
 3334   
 3335   
 3336           //-- process all namespaces first
 3337           int attCount = 0;
 3338           boolean[] validAtts = new boolean[atts.getLength()];
 3339           for (int i = 0; i < validAtts.length; i++) {
 3340               String attName = atts.getName(i);
 3341               if (attName.equals(XMLNS)) {
 3342                   _namespaces.addNamespace("", atts.getValue(i));
 3343               }
 3344               else if (attName.startsWith(XMLNS_PREFIX)) {
 3345                   String prefix = attName.substring(XMLNS_PREFIX_LENGTH);
 3346                   _namespaces.addNamespace(prefix, atts.getValue(i));
 3347               }
 3348               else {
 3349                   validAtts[i] = true;
 3350                   ++attCount;
 3351               }
 3352           }
 3353           //-- process validAtts...if any exist
 3354           AttributeSetImpl attSet = null;
 3355           if (attCount > 0) {
 3356               attSet = new AttributeSetImpl(attCount);
 3357               for (int i = 0; i < validAtts.length; i++) {
 3358                   if (!validAtts[i]) continue;
 3359                   String namespace = null;
 3360                   String attName = atts.getName(i);
 3361                   int idx = attName.indexOf(':');
 3362                   if (idx > 0) {
 3363                       String prefix = attName.substring(0, idx);
 3364                       if (!prefix.equals(XML_PREFIX)) {
 3365                           attName = attName.substring(idx+1);
 3366                           namespace = _namespaces.getNamespaceURI(prefix);
 3367                           if (namespace == null) {
 3368                               String error = "The namespace associated with "+
 3369                                   "the prefix '" + prefix +
 3370                                   "' could not be resolved.";
 3371                               throw new SAXException(error);
 3372   
 3373                           }
 3374                       }
 3375                   }
 3376                   attSet.setAttribute(attName, atts.getValue(i), namespace);
 3377               }
 3378           }
 3379           else attSet = new AttributeSetImpl(0);
 3380   
 3381           return attSet;
 3382   
 3383       } //-- method: processAttributeList
 3384   
 3385       /**
 3386        * Saves local namespace declarations to the object
 3387        * model if necessary.
 3388        *
 3389        * @param classDesc the current ClassDescriptor.
 3390       **/
 3391       private void processNamespaces(XMLClassDescriptor classDesc) {
 3392   
 3393   
 3394           if (classDesc == null) return;
 3395   
 3396           //-- process namespace nodes
 3397           XMLFieldDescriptor nsDescriptor =
 3398               classDesc.getFieldDescriptor(null, null, NodeType.Namespace);
 3399   
 3400           if (nsDescriptor != null) {
 3401               UnmarshalState state = (UnmarshalState) _stateInfo.peek();
 3402               FieldHandler handler = nsDescriptor.getHandler();
 3403               if (handler != null) {
 3404                   Enumeration enumeration = _namespaces.getLocalNamespacePrefixes();
 3405                   while (enumeration.hasMoreElements()) {
 3406                       String nsPrefix = (String)enumeration.nextElement();
 3407                       if (nsPrefix == null) nsPrefix = "";
 3408                       String nsURI = _namespaces.getNamespaceURI(nsPrefix);
 3409                       if (nsURI == null) nsURI = "";
 3410                       MapItem mapItem = new MapItem(nsPrefix, nsURI);
 3411                       handler.setValue(state.object, mapItem);
 3412                   }
 3413               }
 3414           }
 3415       } //-- processNamespaces
 3416   
 3417       /**
 3418        * Extracts the prefix and resolves it to it's associated namespace.
 3419        * If the prefix is 'xml', then no resolution will occur, however
 3420        * in all other cases the resolution will change the prefix:value
 3421        * as {NamespaceURI}value
 3422        *
 3423        * @param value the QName to resolve.
 3424        */
 3425       private Object resolveNamespace(Object value)
 3426           throws SAXException
 3427       {
 3428   
 3429           if ( (value == null) || !(value instanceof String))
 3430               return value;
 3431   
 3432           String result = (String)value;
 3433           int idx = result.indexOf(':');
 3434           String prefix = null;
 3435           if (idx > 0) {
 3436               prefix = result.substring(0,idx);
 3437               if (XML_PREFIX.equals(prefix)) {
 3438                   //-- Do NOT Resolve the 'xml' prefix.
 3439                   return value;
 3440               }
 3441               result = result.substring(idx+1);
 3442           }
 3443           String namespace = _namespaces.getNamespaceURI(prefix);
 3444           if  ((namespace != null) && (namespace.length() > 0)) {
 3445               result = '{'+namespace+'}'+result;
 3446               return result;
 3447           }
 3448           else if ((namespace == null) && (prefix!=null))
 3449                throw new SAXException("The namespace associated with the prefix: '" + 
 3450                   prefix + "' is null.");
 3451           else
 3452               return result;
 3453   
 3454       }
 3455   
 3456       /**
 3457        * Finds and returns an XMLClassDescriptor for the given class name.
 3458        * If a ClassDescriptor could not be found one will attempt to
 3459        * be generated.
 3460        * @param className the name of the class to find the descriptor for
 3461       **/
 3462       private XMLClassDescriptor getClassDescriptor (String className)
 3463           throws SAXException
 3464       {
 3465           Class type = null;
 3466           try {
 3467               //-- use specified ClassLoader if necessary
 3468   		    if (_loader != null) {
 3469   		        type = _loader.loadClass(className);
 3470   		    }
 3471   		    //-- no loader available use Class.forName
 3472   		    else type = Class.forName(className);
 3473   		}
 3474   		catch (ClassNotFoundException cnfe) {
 3475   		    return null;
 3476   		}
 3477           return getClassDescriptor(type);
 3478   
 3479       } //-- getClassDescriptor
 3480   
 3481       /**
 3482        * Finds and returns an XMLClassDescriptor for the given class. If
 3483        * a ClassDescriptor could not be found one will attempt to
 3484        * be generated.
 3485        * @param _class the Class to get the ClassDescriptor for
 3486       **/
 3487       private XMLClassDescriptor getClassDescriptor(Class _class)
 3488           throws SAXException
 3489       {
 3490           if (_class == null) return null;
 3491   
 3492   
 3493           //-- special case for strings
 3494           if (_class == String.class)
 3495               return _stringDescriptor;
 3496   
 3497           if (_class.isArray()) return null;
 3498           if (isPrimitive(_class)) return null;
 3499   
 3500   // TODO: Joachim
 3501   //        if (_cdResolver == null)
 3502   //            _cdResolver = (XMLClassDescriptorResolver) 
 3503   //                ClassDescriptorResolverFactory.createClassDescriptorResolver(BindingType.XML);
 3504   
 3505           XMLClassDescriptor classDesc = null;
 3506   
 3507   
 3508           try {
 3509               classDesc = (XMLClassDescriptor) getInternalContext().getXMLClassDescriptorResolver().resolve(_class);
 3510           }
 3511           catch(ResolverException rx) {
 3512               // TODO
 3513           }
 3514   
 3515           if (classDesc != null) {
 3516               return new InternalXMLClassDescriptor(classDesc);
 3517           }
 3518   
 3519           if (LOG.isDebugEnabled()) {
 3520           	LOG.debug(ERROR_DID_NOT_FIND_CLASSDESCRIPTOR + _class.getName());
 3521           }
 3522           
 3523           return classDesc;
 3524       } //-- getClassDescriptor
 3525   
 3526   
 3527       /**
 3528        * Finds and returns a ClassDescriptor for the given class. If
 3529        * a ClassDescriptor could not be found one will attempt to
 3530        * be generated.
 3531        * @param className the name of the class to get the Descriptor for
 3532       **/
 3533       private XMLClassDescriptor getClassDescriptor
 3534           (String className, ClassLoader loader)
 3535           throws SAXException
 3536       {
 3537   // TODO: Joachim
 3538   //        if (_cdResolver == null)
 3539   //            _cdResolver = (XMLClassDescriptorResolver) 
 3540   //                ClassDescriptorResolverFactory.createClassDescriptorResolver(BindingType.XML);
 3541   
 3542           
 3543           XMLClassDescriptor classDesc = null;
 3544           try {
 3545               classDesc = getInternalContext().getXMLClassDescriptorResolver().resolve(className, loader);
 3546           }
 3547           catch(ResolverException rx) {
 3548               throw new SAXException(rx);
 3549           }
 3550           
 3551   
 3552           if (classDesc != null) {
 3553               return new InternalXMLClassDescriptor(classDesc);
 3554           }
 3555   
 3556           if (LOG.isDebugEnabled()) {
 3557           	LOG.debug(ERROR_DID_NOT_FIND_CLASSDESCRIPTOR + className);
 3558           }
 3559           
 3560           return classDesc;
 3561       } //-- getClassDescriptor
 3562       
 3563       /**
 3564        * Returns the XMLClassLoader
 3565        */
 3566       private XMLClassDescriptor resolveByXMLName
 3567           (String name, String namespace, ClassLoader loader) 
 3568           throws SAXException
 3569       {
 3570           
 3571           try {
 3572               return getInternalContext().getXMLClassDescriptorResolver().resolveByXMLName(name, namespace, loader);
 3573           }
 3574           catch(ResolverException rx) {
 3575               throw new SAXException(rx);
 3576           }
 3577           
 3578       }
 3579   
 3580       /**
 3581        * Returns the package for the given Class
 3582        *
 3583        * @param type the Class to return the package of
 3584        * @return the package for the given Class
 3585       **/
 3586   	private String getJavaPackage(Class type)
 3587   	{
 3588   		if (type == null)
 3589   			return null;
 3590   		String pkg = (String)_javaPackages.get(type);
 3591   		if(pkg == null)
 3592   		{
 3593   			pkg = type.getName();
 3594   			int idx = pkg.lastIndexOf('.');
 3595   			if (idx > 0)
 3596   			pkg = pkg.substring(0,idx);
 3597   			else
 3598   			pkg = "";
 3599   			_javaPackages.put(type, pkg);
 3600   		}
 3601   		return pkg;
 3602   	} //-- getJavaPackage
 3603   
 3604       /**
 3605        * Returns the name of a class, handles array types
 3606        * @return the name of a class, handles array types
 3607       **/
 3608       private String className(Class type) {
 3609           if (type.isArray()) {
 3610               return className(type.getComponentType()) + "[]";
 3611           }
 3612           return type.getName();
 3613       } //-- className
 3614   
 3615   
 3616       /**
 3617        * Checks the given StringBuffer to determine if it only
 3618        * contains whitespace.
 3619        *
 3620        * @param sb the StringBuffer to check
 3621        * @return true if the only whitespace characters were
 3622        * found in the given StringBuffer
 3623       **/
 3624       private static boolean isWhitespace(StringBuffer sb) {
 3625           for (int i = 0; i < sb.length(); i++) {
 3626               char ch = sb.charAt(i);
 3627               switch (ch) {
 3628                   case ' ':
 3629                   case '\n':
 3630                   case '\t':
 3631                   case '\r':
 3632                       break;
 3633                   default:
 3634                       return false;
 3635               }
 3636           }
 3637           return true;
 3638       } //-- isWhitespace
 3639       
 3640       /**
 3641        * Loads and returns the class with the given class name using the
 3642        * given loader.
 3643        * @param className the name of the class to load
 3644        * @param loader the ClassLoader to use, this may be null.
 3645       **/
 3646       private Class loadClass(String className, ClassLoader loader)
 3647           throws ClassNotFoundException
 3648       {
 3649           //-- use passed in loader
 3650   	    if ( loader != null )
 3651   		    return loader.loadClass(className);
 3652   		//-- use internal loader
 3653   		else if (_loader != null)
 3654   		    return _loader.loadClass(className);
 3655   		//-- no loader available use Class.forName
 3656   		return Class.forName(className);
 3657       } //-- loadClass
 3658   
 3659       /**
 3660        * Resolves the current set of waiting references for the given Id.
 3661        * @param id the id that references are waiting for.
 3662        * @param value the value of the resolved id.
 3663        * @throws SAXException Indicates a problem resolving an IDREF
 3664       **/
 3665       private void resolveReferences(final String id, final Object value)
 3666           throws org.xml.sax.SAXException {
 3667           if ((id == null) || (value == null)) {
 3668               return;
 3669           }
 3670           if (_resolveTable == null) {
 3671               return;
 3672           }
 3673   
 3674           ReferenceInfo refInfo = (ReferenceInfo) _resolveTable.remove(id);
 3675           while (refInfo != null) {
 3676               try {
 3677                   FieldHandler handler = refInfo.getDescriptor().getHandler();
 3678                   if (handler != null) {
 3679                       handler.setValue(refInfo.getTarget(), value);
 3680                   }
 3681                       
 3682                   //-- special handling for MapItems
 3683                   if (refInfo.getTarget() instanceof MapItem) {
 3684                       resolveReferences(refInfo.getTarget().toString(), refInfo.getTarget());
 3685                   }
 3686               } catch (java.lang.IllegalStateException ise) {
 3687                   String err = "Attempting to resolve an IDREF: " +
 3688                           id + "resulted in the following error: " +
 3689                           ise.toString();
 3690                   throw new SAXException(err, ise);
 3691               }
 3692               refInfo = refInfo.getNext();
 3693           }
 3694       }
 3695   
 3696       /**
 3697        * Converts a String to the given primitive object type.
 3698        *
 3699        * @param type the class type of the primitive in which
 3700        * to convert the String to
 3701        * @param value the String to convert to a primitive
 3702        * @param fieldDesc Descriptor for the given field (value)
 3703        * @return the new primitive Object
 3704        * @exception SAXException If the String cannot be converted to a primitive object type
 3705        */
 3706       private Object toPrimitiveObject
 3707           (final Class type, final String value, final XMLFieldDescriptor fieldDesc) 
 3708           throws SAXException {
 3709           try {
 3710               return toPrimitiveObject(type, value);
 3711           } catch (Exception ex) {
 3712               String err = "The following error occured while trying to ";
 3713               err += "unmarshal field " + fieldDesc.getFieldName();
 3714               UnmarshalState state = (UnmarshalState) _stateInfo.peek();
 3715               if (state != null) {
 3716                   if (state.object != null) {
 3717                       err += " of class " + state.object.getClass().getName();
 3718                   }
 3719               }
 3720               err += "\n";
 3721               err += ex.getMessage();
 3722               
 3723               throw new SAXException(err, ex);
 3724           }
 3725       }
 3726   
 3727   
 3728       /**
 3729        * Converts a {@link String} to the given primitive object type.
 3730        *
 3731        * @param type the class type of the primitive in which
 3732        * to convert the String to
 3733        * @param value the {@link String} to convert to a primitive
 3734        * @return the new primitive {@link Object}
 3735        */
 3736       public static Object toPrimitiveObject(final Class type, String value) {
 3737   
 3738           Object primitive = value;
 3739   
 3740           if (value != null) {
 3741               //-- trim any numeric values
 3742               if ((type != Character.TYPE) && (type != Character.class)) {
 3743                   value = value.trim();
 3744               }
 3745           }
 3746           
 3747           boolean isNull = ((value == null) || (value.length() == 0));
 3748           
 3749           //-- I tried to order these in the order in which
 3750           //-- (I think) types are used more frequently
 3751           
 3752           // int
 3753           if ((type == Integer.TYPE) || (type == Integer.class)) {
 3754               if (isNull) {
 3755                   primitive = new Integer(0);
 3756               } else {
 3757                   primitive = new Integer(value);
 3758               }
 3759           } else if ((type == Boolean.TYPE) || (type == Boolean.class)) {
 3760               // boolean
 3761               if (isNull) {
 3762                   primitive = Boolean.FALSE;
 3763               } else {
 3764                   primitive = (value.equals("1") 
 3765                           || value.toLowerCase().equals("true")) ? Boolean.TRUE : Boolean.FALSE;
 3766               }
 3767           } else if ((type == Double.TYPE) || (type == Double.class)) {
 3768               // double
 3769               if (isNull) {
 3770                   primitive = new Double(0.0);
 3771               } else {
 3772                   primitive = new Double(value);
 3773               }
 3774           } else if ((type == Long.TYPE) || (type == Long.class)) {
 3775               // long
 3776               if (isNull) {
 3777                   primitive = new Long(0);
 3778               } else {
 3779                   primitive = new Long(value);
 3780               }
 3781           } else if ((type == Character.TYPE) || (type == Character.class)) {
 3782               // char
 3783               if (!isNull) {
 3784                   primitive = new Character(value.charAt(0));
 3785               } else {
 3786                   primitive = new Character('\0');
 3787               }
 3788           } else if ((type == Short.TYPE) || (type == Short.class)) {
 3789               // short
 3790               if (isNull) {
 3791                   primitive = new Short((short) 0);
 3792               } else {
 3793                   primitive = new Short(value);
 3794               }
 3795           } else if ((type == Float.TYPE) || (type == Float.class)) {
 3796               // float
 3797               if (isNull) {
 3798                   primitive = new Float(0);
 3799               } else {
 3800                   primitive = new Float(value);
 3801               }
 3802           } else if ((type == Byte.TYPE) || (type == Byte.class)) {
 3803               // byte
 3804               if (isNull) {
 3805                   primitive = new Byte((byte)0);
 3806               } else {
 3807                   primitive = new Byte(value);
 3808               }
 3809           } else if (type == java.math.BigDecimal.class) {
 3810               //BigDecimal
 3811               if (isNull) {
 3812                   primitive = new java.math.BigDecimal(0);
 3813               } else {
 3814                   primitive = new java.math.BigDecimal(value);
 3815               }
 3816           } else if (type == java.math.BigInteger.class) {
 3817               //BigInteger
 3818               if (isNull) {
 3819                   primitive = java.math.BigInteger.valueOf(0);
 3820               } else {
 3821                   primitive = new java.math.BigInteger(value);
 3822               }
 3823           } else if (type.getSuperclass().getName().equals("java.lang.Enum")) {
 3824               // Java 5.0 enums
 3825               if (isNull) {
 3826                   primitive = null;
 3827               } else {
 3828                   // try discover the fromValue Method
 3829                   try {
 3830                       Method valueOfMethod = type.getMethod("fromValue",
 3831                               new Class[] {String.class});
 3832                       primitive = valueOfMethod.invoke(null, new Object[] {value});
 3833                       return primitive;
 3834                   } catch (NoSuchMethodException e) {
 3835                       // do nothing, check valueOf method
 3836                   } catch (IllegalArgumentException e) {
 3837                       throw new IllegalStateException(e.toString());
 3838                   } catch (IllegalAccessException e) {
 3839                       throw new IllegalStateException(e.toString());
 3840                   } catch (InvocationTargetException e) {
 3841                       if (e.getTargetException() instanceof RuntimeException) {
 3842                           throw (RuntimeException) e.getTargetException();
 3843                       }
 3844                   } 
 3845                   
 3846                   // backwards compability, check valueOf method to support 
 3847                   // "simple" enums without value object
 3848                   try {
 3849                       Method valueOfMethod = type.getMethod("valueOf",
 3850                               new Class[] {String.class});
 3851                       primitive = valueOfMethod.invoke(null, new Object[] {value});
 3852                   } catch (IllegalAccessException e) {
 3853                       throw new IllegalStateException(e.toString());
 3854                   } catch (InvocationTargetException e) {
 3855                       if (e.getTargetException() instanceof RuntimeException) {
 3856                           throw (RuntimeException) e.getTargetException();
 3857                       }
 3858                   } catch (NoSuchMethodException e) {
 3859                       String err = type.getName()
 3860                               + " does not contain the required method: public static "
 3861                               + type.getName() + " valueOf(String);";
 3862                       throw new IllegalArgumentException(err);
 3863                   }
 3864               }
 3865           }
 3866           return primitive;
 3867       }
 3868       
 3869       /**
 3870        * A utility class for keeping track of the
 3871        * qName and how the SAX parser passed attributes
 3872        */
 3873       class ElementInfo {
 3874           
 3875           String qName = null;
 3876           Attributes attributes = null;
 3877           AttributeList attributeList = null;
 3878           
 3879           ElementInfo() {
 3880               super();
 3881           }
 3882           
 3883           ElementInfo(String qName, Attributes atts) {
 3884               super();
 3885               this.qName = qName;
 3886               this.attributes = atts;
 3887           }
 3888           
 3889           ElementInfo(String qName, AttributeList atts) {
 3890               super();
 3891               this.qName = qName;
 3892               this.attributeList = atts;
 3893           }
 3894           
 3895           void clear() {
 3896               qName = null;
 3897               attributes = null;
 3898               attributeList = null;
 3899           }
 3900       } //-- ElementInfo
 3901       
 3902       /**
 3903        * Internal class used for passing constructor argument
 3904        * information.
 3905        */
 3906       class Arguments {
 3907           /**
 3908            * Constructor argument values.
 3909            */
 3910           private Object[] _values = null;
 3911           /**
 3912            * Constructor argument types.
 3913            */
 3914           private Class[] _types  = null;
 3915           
 3916           /**
 3917            * Returns the number of constructor arguments.
 3918            * @return The number of constructor arguments.
 3919            */
 3920           public int size() {
 3921               if (_values == null) {
 3922                   return 0;
 3923               }
 3924               return _values.length;
 3925           }
 3926       }
 3927   
 3928       /**
 3929        * A class for handling Arrays during unmarshalling.
 3930        *
 3931        * @author <a href="mailto:kvisco@intalio.com">kvisco@intalio.com</a>
 3932        */
 3933       public static class ArrayHandler {
 3934           
 3935           Class _componentType = null;
 3936           
 3937           ArrayList<Object> _items = null;
 3938           
 3939           /**
 3940            * Creates a new ArrayHandler 
 3941            *
 3942            * @param componentType the ComponentType for the array.
 3943            */
 3944           ArrayHandler(final Class componentType) {
 3945               if (componentType == null) {
 3946                   String err = "The argument 'componentType' may not be null.";
 3947                   throw new IllegalArgumentException(err);
 3948               }
 3949               _componentType = componentType;
 3950               _items = new ArrayList<Object>();
 3951           } //-- ArrayHandler
 3952           
 3953           /**
 3954            * Adds the given object to the underlying array. 
 3955            * @param obj The object to be added to the underlying array.
 3956            */
 3957           public void addObject(final Object obj) {
 3958               if (obj == null) {
 3959                   return;
 3960               }
 3961               /* disable check for now until we write a 
 3962                  small function to handle primitive and their
 3963                  associated wrapper classes
 3964               if (!_componentType.isAssignableFrom(obj.getClass())) {
 3965                   String err = obj.getClass().getName() + " is not an instanceof " +
 3966                       _componentType.getName();
 3967                   throw new IllegalArgumentException(err);
 3968               }
 3969               */
 3970               _items.add(obj);
 3971           }
 3972           
 3973           /**
 3974            * Returns the data handled by this class as an array.
 3975            * @return The data handled internally in the form of an array.
 3976            */
 3977           public Object getObject() {
 3978               int size = _items.size();
 3979               Object array = Array.newInstance(_componentType, size);
 3980               for (int i = 0; i < size; i++) {
 3981                   Array.set(array, i, _items.get(i));
 3982               }
 3983               return array;
 3984           }
 3985          
 3986           /**
 3987            * Returns the component type handled by this class.
 3988            * @return The component type handled by this class.
 3989            */
 3990           public Class componentType() {
 3991               return _componentType;
 3992           }
 3993           
 3994       } //-- ArrayHandler
 3995   
 3996   	/**
 3997        * Returns the ObjectFactory instance in use.
 3998   	 * @return the ObjectFactory instance in use.
 3999   	 */
 4000   	public ObjectFactory getObjectFactory() {
 4001   		return _objectFactory;
 4002   	}
 4003   
 4004   	/**
 4005        * Sets a (custom) ObjectFactory instance.
 4006   	 * @param objectFactory A (custom) ObjectFactory instance
 4007   	 */
 4008   	public void setObjectFactory(ObjectFactory objectFactory) {
 4009   		_objectFactory = objectFactory;
 4010   	}
 4011   
 4012   } //-- Unmarshaller
 4013   

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