View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation
3    * ("Software"), with or without modification, are permitted provided
4    * that the following conditions are met:
5    *
6    * 1. Redistributions of source code must retain copyright
7    *    statements and notices.  Redistributions must also contain a
8    *    copy of this document.
9    *
10   * 2. Redistributions in binary form must reproduce the
11   *    above copyright notice, this list of conditions and the
12   *    following disclaimer in the documentation and/or other
13   *    materials provided with the distribution.
14   *
15   * 3. The name "Exolab" must not be used to endorse or promote
16   *    products derived from this Software without prior written
17   *    permission of Intalio, Inc.  For written permission,
18   *    please contact info@exolab.org.
19   *
20   * 4. Products derived from this Software may not be called "Exolab"
21   *    nor may "Exolab" appear in their names without prior written
22   *    permission of Intalio, Inc. Exolab is a registered
23   *    trademark of Intalio, Inc.
24   *
25   * 5. Due credit should be given to the Exolab Project
26   *    (http://www.exolab.org/).
27   *
28   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29   * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30   * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
32   * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33   * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35   * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39   * OF THE POSSIBILITY OF SUCH DAMAGE.
40   *
41   * Copyright 1999-2004 (C) Intalio, Inc. All Rights Reserved.
42   *
43   * $Id$
44   */
45  
46  package org.exolab.castor.xml;
47  
48  import java.util.HashMap;
49  import java.util.HashSet;
50  import java.util.Iterator;
51  import java.util.Map;
52  import java.util.Set;
53  import java.util.Vector;
54  
55  import org.castor.xml.BackwardCompatibilityContext;
56  import org.castor.xml.InternalContext;
57  import org.castor.xml.AbstractInternalContext;
58  import org.castor.xml.JavaNaming;
59  import org.exolab.castor.mapping.ClassDescriptor;
60  import org.exolab.castor.mapping.CollectionHandler;
61  import org.exolab.castor.mapping.FieldDescriptor;
62  import org.exolab.castor.mapping.MappingException;
63  import org.exolab.castor.mapping.loader.CollectionHandlers;
64  import org.exolab.castor.util.ReflectionUtil;
65  
66  
67  /**
68   * A core class for common code shared throughout the
69   * Marshalling Framework
70   * 
71   * @author <a href="mailto:kvisco-at-intalio.com">Keith Visco</a>
72   * @version $Revision$ $Date: 2005-12-13 14:58:48 -0700 (Tue, 13 Dec 2005) $
73   */
74  abstract class MarshalFramework {
75  
76      
77      
78      //--------------------------/
79      //- Public class variables -/
80      //--------------------------/
81  
82      /**
83       * JDK version 1.5 .
84       */
85      private static final double JDK_VERSION_1_5 = 1.5;
86  
87      /**
88       * The XSI Namespace URI.
89      **/
90      public static final String XSI_NAMESPACE
91          = "http://www.w3.org/2001/XMLSchema-instance";
92  
93      /**
94       * The name of the Schema location attribute.
95      **/
96      public static final String XSI_SCHEMA_LOCATION = "schemaLocation";
97  
98      /**
99       * The name of the no namespace schema location attribute.
100     **/
101     public static final String XSI_NO_NAMESPACE_SCHEMA_LOCATION 
102         = "noNamespaceSchemaLocation";
103    
104     /**
105      * The xml:lang attribute name.
106      */
107     public static final String XML_LANG_ATTR = "xml:lang";
108     
109     /**
110      * The xml:lang attribute, without the "xml:" prefix.
111      */
112     public static final String LANG_ATTR = "lang";
113     
114     /**
115      * The xsi:nil attribute, without the "xsi:" prefix.
116      */
117     public static final String NIL_ATTR = "nil";
118     
119     /**
120      * The xsi:nil attribute.
121      */
122     public static final String XSI_NIL_ATTR = "xsi:nil";
123     
124     /**
125      * The xml:space attribute name.
126      */    
127     public static final String XML_SPACE_ATTR = "xml:space";
128     
129     /**
130      * The xml:space attribute name, without the "xml:" prefix.
131      */    
132     public static final String SPACE_ATTR = "space";
133     
134     /**
135      * The xsi:type attribute name, without the "xsi:" prefix.
136      */    
137     public static final String TYPE_ATTR = "type";
138     
139     /**
140      * The value of 'true'.
141      */
142     public static final String TRUE_VALUE = "true";
143     
144     //-----------------------------/
145     //- Protected class variables -/
146     //-----------------------------/
147 
148     /**
149      * A constant to indicate a wrong name without setting null.
150      */
151     static final String INTERNAL_XML_NAME = "-error-if-this-is-used-";
152 
153     /**
154      * The default prefix used for specifying the
155      * xsi:type as a classname instead of a schema name.
156      * This is a Castor specific hack.
157      */
158     static final String JAVA_PREFIX = "java:";
159 
160     /**
161      * The name of the QName type.
162      */
163     static final String QNAME_NAME = "QName";
164     
165     /**
166      * An empty array of field descriptors.
167      */
168     static final XMLFieldDescriptor[] NO_FIELD_DESCRIPTORS 
169         = new XMLFieldDescriptor[0];
170 
171     //-----------------------------/
172     //- Private variables         -/
173     //-----------------------------/
174     
175     /**
176      * The {@link AbstractInternalContext} to use at all un-marshal actions.
177      * @since 1.1.3
178      */
179     private InternalContext _internalContext;
180     
181     //-----------------------------/
182     //- Public methods            -/
183     //-----------------------------/
184 
185     /**
186      * We need some stuff initialized here. MarshalFramework requires internally
187      * an {@link InternalContext}, so either one is given or {@link BackwardCompatibilityContext}
188      * is instantiated! Mind that instantiating {@link BackwardCompatibilityContext}
189      * means to (re-)read configuration files.
190      * @param internalContext either an {@link InternalContext} comes from outside
191      *          or {@link BackwardCompatibilityContext} is instantiated
192      */
193     public MarshalFramework(final InternalContext internalContext) {
194         if (internalContext == null) {
195             _internalContext = new BackwardCompatibilityContext();
196         } else {
197             _internalContext = internalContext;
198         }
199     }
200 
201     /**
202      * To get the {@link JavaNaming} instance to be used.
203      * @return the JavaNaming to be used
204      */
205     public JavaNaming getJavaNaming() {
206         return _internalContext.getJavaNaming();
207     }
208 
209     /**
210      * To set the {@link JavaNaming} instance to be used.
211      * @param javaNaming the JavaNaming to be used
212      * TODO: joachim remove me if possible!
213      */
214     private void setJavaNaming(final JavaNaming javaNaming) {
215         _internalContext.setJavaNaming(javaNaming);
216     }
217     
218     /**
219      * To get the {@link AbstractInternalContext} to use.
220      * @return the {@link AbstractInternalContext} to use
221      */
222     public InternalContext getInternalContext() {
223         return _internalContext;
224     }
225     
226     /**
227      * To set the {@link AbstractInternalContext} to use.
228      * @param internalContext the {@link AbstractInternalContext} to use
229      */
230     public void setInternalContext(final InternalContext internalContext) {
231         _internalContext = internalContext;
232     }
233 
234     /**
235      * Returns true if the given Class is a considered a
236      * collection by the marshalling framework.
237      * @param clazz the Class to check
238      * @return true if the given Class is considered a collection.
239      * TODO: joachim: this code exists somewhere else too!!
240      */
241     public static boolean isCollection(final Class clazz) {
242         return CollectionHandlers.hasHandler(clazz);
243     } //-- isCollection
244     
245     /**
246      * Returns the CollectionHandler associated with the
247      * given collection, or null if no such handler exists.
248      * @param clazz the Class to check
249      * @return the CollectionHandler for the associated type.
250      */
251     public CollectionHandler getCollectionHandler(final Class clazz) {
252         CollectionHandler handler = null;
253         try {
254             handler = CollectionHandlers.getHandler(clazz);
255         }
256         catch (MappingException mx) {
257             //-- Not a collection, or no handler exists, return null.
258         }
259         return handler;
260     } //-- getCollectionHandler
261     
262     
263     /**
264      * Returns true if the given class should be treated as a primitive
265      * type. This method will return true for all Java primitive
266      * types, the set of primitive object wrappers, as well
267      * as Strings.
268      * @param type the Class to check
269      * @return true if the given class should be treated as a primitive type
270      * TODO: joachim: this code exists somewhere else too!!
271     **/
272     static boolean isPrimitive(final Class type) {
273 
274         if (type == null) {
275             return false;
276         }
277 
278         //-- java primitive
279         if (type.isPrimitive()) {
280             return true;
281         }
282 
283         //-- we treat strings as primitives
284         if (type == String.class) {
285             return true;
286         }
287 
288         //-- primtive wrapper classes
289         if ((type == Boolean.class) || (type == Character.class)) {
290             return true;
291         }
292 
293         Class superClass = type.getSuperclass();
294         if (superClass == Number.class) {
295             return true;
296         }
297 
298         if (superClass != null) {
299             return superClass.getName().equals("java.lang.Enum");
300         }
301         
302         return false;
303         
304     } //-- isPrimitive
305 
306     /**
307      * Returns true if the given class should be treated as an enum type. This method 
308      * will return true for all Java 5 (or later) enums, and for enum-style
309      * classes.
310      * @param type the Class to check
311      * @return true if the given class should be treated as an enum
312      **/
313     static boolean isEnum(final Class type) {
314 
315         if (type == null) {
316             return false;
317         }
318 
319         float javaVersion = 
320             Float.valueOf(System.getProperty("java.specification.version")).floatValue();
321         if (javaVersion >= JDK_VERSION_1_5) {
322             try {
323                 Boolean isEnum = ReflectionUtil.isEnumViaReflection(type);
324                 return isEnum.booleanValue();
325             } catch (Exception e) {
326                 // nothing to report; implies that there's no such method
327             }
328         }
329         
330         // TODO: add code to cover 1.4 enum-stype classes as well.
331         
332         return false;
333 
334     } //-- isPrimitive
335 
336 //    /**
337 //     * Calls isEnum() method on target class vi areflection to find out
338 //     * whether the given type is a Java 5 enumeration.
339 //     * @param type The type to analyze.
340 //     * @return True if the type given is a Java 5.0 enum.
341 //     * @throws NoSuchMethodException If the method can not be found.
342 //     * @throws IllegalAccessException If access to this method is illegal
343 //     * @throws InvocationTargetException If the target method can not be invoked.
344 //     */
345 //    private static Boolean isEnumViaReflection(Class type) 
346 //    throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
347 //        Method isEnumMethod = type.getClass().getMethod("isEnum", (Class[]) null);
348 //        return (Boolean) isEnumMethod.invoke(type, (Object[]) null);
349 //    }
350 //    
351 
352     /**
353      * Returns true if any of the fields associated with the given
354      * XMLClassDescriptor are located at, or beneath, the given location.
355      *
356      * @param location the location to compare against
357      * @param classDesc the XMLClassDescriptor in which to check the field 
358      * locations
359      * @return true if any of the fields has a location associated
360      */
361     static final boolean hasFieldsAtLocation
362         (final String location, final XMLClassDescriptor classDesc) {
363         //-- check elements
364         XMLFieldDescriptor[] descriptors = classDesc.getElementDescriptors();
365         for (int i = 0; i < descriptors.length; i++) {
366             if (descriptors[i] == null) {
367                 continue;
368             }
369             String tmpLocation = descriptors[i].getLocationPath();
370             if ((tmpLocation != null) && (tmpLocation.startsWith(location))) {
371                 return true;
372             }
373         }
374         
375         //-- check attributes
376         descriptors = classDesc.getAttributeDescriptors();
377         for (int i = 0; i < descriptors.length; i++) {
378             if (descriptors[i] == null) {
379                 continue;
380             }
381             String tmpLocation = descriptors[i].getLocationPath();
382             if ((tmpLocation != null) && (tmpLocation.startsWith(location))) {
383                 return true;
384             }
385         }
386         
387         //-- check content/text
388         XMLFieldDescriptor content = classDesc.getContentDescriptor();
389         if (content != null) {
390             String tmpLocation = content.getLocationPath();
391             if ((tmpLocation != null) && (tmpLocation.startsWith(location))) {
392                 return true;
393             }
394         }
395         return false;
396     } //-- hasFieldsAtLocation
397     
398     /**
399      * Compares the given namespaces (as strings) for equality.
400      * null and empty values are considered equal.
401      *
402      * @param ns1 the namespace to compare to argument ns2
403      * @param ns2 the namespace to compare to argument ns1
404      * @return true if the namespaces are considert equal
405      * TODO: joachim put it into XMLNaming!
406      */
407     public static boolean namespaceEquals(final String ns1, final String ns2) {
408         if (ns1 == null) {
409             return ((ns2 == null) || (ns2.length() == 0));
410         }
411         if (ns2 == null) {
412             return (ns1.length() == 0);
413         }
414         return ns1.equals(ns2);
415     } //-- namespaceEquals
416     
417     /**
418      * Returns true if the given classes are both the same
419      * primitive or primitive wrapper class. For exmaple, if 
420      * class "a" is an int (Integer.TYPE) and class "b" is 
421      * either an int or Integer.class then true will be
422      * returned, otherwise false.
423      * @param a compare a with b
424      * @param b compare a with b
425      * @return true if both a and b are considered equal
426      */
427     static boolean primitiveOrWrapperEquals(final Class a, final Class b) {
428         if (!isPrimitive(a)) {
429             return false;
430         }
431         if (!isPrimitive(b)) {
432             return false;
433         }
434         
435         if (a == b) {
436             return true;
437         }
438         
439         //-- Boolean/boolean
440         if ((a == Boolean.class) || (a == Boolean.TYPE)) {
441             return ((b == Boolean.class) || (b == Boolean.TYPE));
442         }
443         //-- Byte/byte
444         else if ((a == Byte.class) || (a == Byte.TYPE)) {
445             return ((b == Byte.class) || (b == Byte.TYPE));
446         }
447         //-- Character/char
448         else if ((a == Character.class) || (a == Character.TYPE)) {
449             return ((b == Character.class) || (b == Character.TYPE));
450         }
451         //-- Double/double
452         else if ((a == Double.class) || (a == Double.TYPE)) {
453             return ((b == Double.class) || (b == Double.TYPE));
454         }
455         else if ((a == Float.class) || (a == Float.TYPE)) {
456             return ((b == Float.class) || (b == Float.TYPE));
457         }
458         //-- Integer/int
459         else if ((a == Integer.class) || (a == Integer.TYPE)) {
460             return ((b == Integer.class) || (b == Integer.TYPE));
461         }
462         //-- Long/long
463         else if ((a == Long.class) || (a == Long.TYPE)) {
464             return ((b == Long.class) || (b == Long.TYPE));
465         }
466         //-- Short/short
467         else if ((a == Short.class) || (a == Short.TYPE)) {
468             return ((b == Short.class) || (b == Short.TYPE));
469         }
470         
471         return false;
472     } //-- primitiveOrWrapperEquals
473     
474     /**
475      * 
476      */
477     private static final InheritanceMatch[] NO_MATCH_ARRAY = new InheritanceMatch[0];
478     
479     /**
480      * Search there is a field descriptor which can accept one of the class
481      * descriptor which match the given name and namespace.
482      * 
483      * @param name XML name of the field
484      * @param namespace namespace of the field
485      * @param classDesc the class descriptor to match against
486      * @param cdResolver the class descriptor resolver to use
487      * @return An array of InheritanceMatch.
488      * @throws MarshalException if the resolver called fails fatally
489      */
490     protected InheritanceMatch[] searchInheritance(final String name, 
491             final String namespace,
492             final XMLClassDescriptor classDesc)
493     throws MarshalException {
494         Iterator classDescriptorIterator = null;
495         
496         try {
497             //-- A little required logic for finding Not-Yet-Loaded
498             //-- descriptors
499             String className = getJavaNaming().toJavaClassName(name);
500             //-- should use namespace-to-prefix mappings, but
501             //-- just create package for now.
502             Class clazz = classDesc.getJavaClass();
503             String pkg = null;
504             if (clazz != null) {
505                 while (clazz.getDeclaringClass() != null) {
506                     clazz = clazz.getDeclaringClass();
507                 }
508                 pkg = clazz.getName();
509                 int idx = pkg.lastIndexOf('.');
510                 if (idx >= 0) {
511                     pkg = pkg.substring(0, idx + 1);
512                     className = pkg + className;
513                 }
514             }
515             getInternalContext().getXMLClassDescriptorResolver().resolve(
516                     className, classDesc.getClass().getClassLoader());
517             //-- end Not-Yet-Loaded descriptor logic
518             
519             //-- resolve all by XML name + namespace URI
520             classDescriptorIterator = 
521                 getInternalContext().getXMLClassDescriptorResolver().resolveAllByXMLName(
522                         name, namespace, null);
523         }
524         catch (ResolverException rx) {
525             Throwable actual = rx.getCause();
526             if (actual instanceof MarshalException) {
527                 throw (MarshalException) actual;
528             }
529             if (actual != null) {
530                 throw new MarshalException(actual);
531             }
532             throw new MarshalException(rx);
533         }
534 
535         Vector inheritanceList = null;
536         XMLFieldDescriptor descriptor  = null;
537         XMLFieldDescriptor[] descriptors = classDesc.getElementDescriptors();
538         XMLClassDescriptor cdInherited = null;
539 
540         if (classDescriptorIterator.hasNext()) {
541             while (classDescriptorIterator.hasNext() && (descriptor == null)) {
542                 cdInherited = (XMLClassDescriptor) classDescriptorIterator.next();
543                 Class subclass = cdInherited.getJavaClass();
544 
545                 for (int i = 0; i < descriptors.length; i++) {
546 
547                     if (descriptors[i] == null) {
548                         continue;
549                     }
550                     
551                     //-- skip descriptors with special internal name
552                     if (INTERNAL_XML_NAME.equals(descriptors[i].getXMLName())) {
553                         continue;
554                     }
555                     
556                     //-- check for inheritence
557                     Class superclass = descriptors[i].getFieldType();
558 
559                     // It is possible that the superclass is of type object if we use any node.
560                     if (superclass.isAssignableFrom(subclass) && (superclass != Object.class)) {
561                         descriptor = descriptors[i];
562                         if (inheritanceList == null) {
563                             inheritanceList = new Vector(3);
564                         }
565                         inheritanceList.addElement(new InheritanceMatch(descriptor, cdInherited));
566                     }
567                 }
568             }
569             //-- reset inherited class descriptor, if necessary
570             if (descriptor == null) {
571                 cdInherited = null;
572             }
573         }
574         
575         if (inheritanceList != null) {
576             InheritanceMatch[] result = new InheritanceMatch[inheritanceList.size()];
577             inheritanceList.toArray(result);
578             return result;
579         }
580         return NO_MATCH_ARRAY;
581         
582     }
583 
584      /**
585      * Used to store the information when we find a possible inheritance. It
586      * store the XMLClassDescriptor of the object to instantiate and the
587      * XMLFieldDescriptor of the parent, where the instance of the
588      * XMLClassDescriptor will be put.
589      */
590     public static class InheritanceMatch {
591         /**
592          * The field descriptor of the parent.
593          */
594         public XMLFieldDescriptor parentFieldDesc;
595         /**
596          * The class descriptor to instantiate.
597          */
598         public XMLClassDescriptor inheritedClassDesc;
599 
600         public InheritanceMatch(XMLFieldDescriptor fieldDesc, XMLClassDescriptor classDesc) {
601             parentFieldDesc    = fieldDesc;
602             inheritedClassDesc = classDesc;
603         }
604     }
605 
606 
607 
608     /**
609      * An internal implementation of XMLClassDescriptor used by
610      * the Unmarshaller and Marshaller...
611      */
612     class InternalXMLClassDescriptor implements XMLClassDescriptor {
613 
614         private XMLClassDescriptor _classDesc = null;
615         
616         /**
617          * Cached arrays.
618          */
619         private XMLFieldDescriptor[] _attributes = null;
620         /**
621          * Cached arrays.
622          */
623         private XMLFieldDescriptor[] _elements   = null;
624         /**
625          * Cached arrays.
626          */
627         private FieldDescriptor[]    _fields     = null;
628         
629         /**
630          * Map holding the properties set and read by Natures.
631          */
632         private Map _properties = new HashMap();
633         
634         /**
635          * Map holding the available natures.
636          */
637         private Set _natures = new HashSet();
638         
639         /**
640          * Creates a new InternalXMLClassDescriptor for the given
641          * XMLClassDescriptor.
642          */
643         protected InternalXMLClassDescriptor(XMLClassDescriptor classDesc)
644         {
645             if (classDesc == null) {
646                 String err = "The argument 'classDesc' must not be null.";
647                 throw new IllegalArgumentException(err);
648             }
649             
650             //-- prevent wrapping another InternalXMLClassDescriptor,
651             while (classDesc instanceof InternalXMLClassDescriptor) {
652                 classDesc = ((InternalXMLClassDescriptor) classDesc).getClassDescriptor();
653             }
654             _classDesc = classDesc;
655         }
656         
657         /**
658          * Returns the XMLClassDescriptor that this InternalXMLClassDescriptor
659          * wraps.
660          *
661          * @return the XMLClassDescriptor
662          */
663         public XMLClassDescriptor getClassDescriptor() {
664             return _classDesc;
665         } //-- getClassDescriptor
666         
667         
668         /**
669          * Returns the set of XMLFieldDescriptors for all members
670          * that should be marshalled as XML attributes. This
671          * includes namespace nodes.
672          *
673          * @return an array of XMLFieldDescriptors for all members
674          * that should be marshalled as XML attributes.
675          */
676         public XMLFieldDescriptor[]  getAttributeDescriptors() {
677             if (_attributes == null) {
678                 _attributes = _classDesc.getAttributeDescriptors();
679             }
680             return _attributes;
681         } //-- getAttributeDescriptors
682 
683         /**
684          * Returns the XMLFieldDescriptor for the member
685          * that should be marshalled as text content.
686          *
687          * @return the XMLFieldDescriptor for the member
688          * that should be marshalled as text content.
689          */
690         public XMLFieldDescriptor getContentDescriptor() {
691             return _classDesc.getContentDescriptor();
692         } //-- getContentDescriptor
693 
694 
695         /**
696          * Returns the XML field descriptor matching the given
697          * xml name and nodeType. If NodeType is null, then
698          * either an AttributeDescriptor, or ElementDescriptor
699          * may be returned. Null is returned if no matching
700          * descriptor is available.
701          *
702          * @param name the xml name to match against
703          * @param namespace the xml namespace to match
704          * @param nodeType the NodeType to match against, or null if
705          * the node type is not known.
706          * @return the matching descriptor, or null if no matching
707          * descriptor is available.
708          *
709          */
710         public XMLFieldDescriptor getFieldDescriptor
711             (final String name, final String namespace, final NodeType nodeType) 
712         {
713             return _classDesc.getFieldDescriptor(name, namespace, nodeType);
714         } //-- getFieldDescriptor
715 
716         /**
717          * Returns the set of XMLFieldDescriptors for all members
718          * that should be marshalled as XML elements.
719          *
720          * @return an array of XMLFieldDescriptors for all members
721          * that should be marshalled as XML elements.
722          */
723         public XMLFieldDescriptor[]  getElementDescriptors() {
724             if (_elements == null) {
725                 _elements = _classDesc.getElementDescriptors();
726             }
727             return _elements;
728         } //-- getElementDescriptors
729 
730         /**
731          * @return the namespace prefix to use when marshalling as XML.
732          */
733         public String getNameSpacePrefix() {
734             return _classDesc.getNameSpacePrefix();
735         } //-- getNameSpacePrefix
736 
737         /**
738          * @return the namespace URI used when marshalling and unmarshalling as XML.
739          */
740         public String getNameSpaceURI() {
741             return _classDesc.getNameSpaceURI();
742         } //-- getNameSpaceURI
743 
744         /**
745          * Returns a specific validator for the class described by
746          * this ClassDescriptor. A null value may be returned
747          * if no specific validator exists.
748          *
749          * @return the type validator for the class described by this
750          * ClassDescriptor.
751          */
752         public TypeValidator getValidator() {
753             return _classDesc.getValidator();
754         } //-- getValidator
755 
756         /**
757          * Returns the XML Name for the Class being described.
758          *
759          * @return the XML name.
760          */
761         public String getXMLName() {
762             return _classDesc.getXMLName();
763         } //-- getXMLName
764 
765         /**
766          * Returns true if the wrapped ClassDescriptor was created
767          * by introspection.
768          * 
769          * @return true if the wrapped ClassDescriptor was created
770          * by introspection.
771          */
772         public boolean introspected() {
773             return Introspector.introspected(_classDesc);
774         } //-- introspected
775         
776         /**
777          * @see org.exolab.castor.xml.XMLClassDescriptor#canAccept(
778          *      java.lang.String, java.lang.String, java.lang.Object)
779          */
780         public boolean canAccept(final String name, final String namespace, final Object object) {
781             return _classDesc.canAccept(name, namespace, object);
782         } //-- canAccept
783 
784         /** 
785          * {@inheritDoc}
786          * 
787          * @see org.exolab.castor.xml.XMLClassDescriptor#checkDescriptorForCorrectOrderWithinSequence(org.exolab.castor.xml.XMLFieldDescriptor, org.exolab.castor.xml.UnmarshalState, java.lang.String)
788          */
789         public void checkDescriptorForCorrectOrderWithinSequence(
790                 final XMLFieldDescriptor elementDescriptor, 
791                 final UnmarshalState parentState, 
792                 final String xmlName) 
793             throws ValidationException {
794             _classDesc.checkDescriptorForCorrectOrderWithinSequence(elementDescriptor, parentState, xmlName);
795         }
796 
797         //-------------------------------------/
798         //- Implementation of ClassDescriptor -/
799         //-------------------------------------/
800         
801         /**
802          * Returns the Java class represented by this descriptor.
803          *
804          * @return The Java class
805          */
806         public Class getJavaClass() {
807             return _classDesc.getJavaClass();
808         } //-- getJavaClass
809 
810 
811         /**
812          * Returns a list of fields represented by this descriptor.
813          *
814          * @return A list of fields
815          */
816         public FieldDescriptor[] getFields() {
817             if (_fields == null) {
818                 _fields = _classDesc.getFields();
819             }
820             return _fields;
821         } //-- getFields
822 
823 
824         /**
825          * Returns the class descriptor of the class extended by this class.
826          *
827          * @return The extended class descriptor
828          */
829         public ClassDescriptor getExtends() {
830             return _classDesc.getExtends();
831         } //-- getExtends
832 
833 
834         /**
835          * Returns the identity field, null if this class has no identity.
836          *
837          * @return The identity field
838          */
839         public FieldDescriptor getIdentity() {
840             return _classDesc.getIdentity();
841         } //-- getIdentity
842         
843         /**
844          * {@inheritDoc}
845          * 
846          * @see org.exolab.castor.xml.XMLClassDescriptor#isChoice()
847          */
848         public boolean isChoice() {
849             return false;
850         }
851 
852         /**
853          * @see org.exolab.castor.builder.info.nature.PropertyHolder#
854          *      getProperty(java.lang.String)
855          * @param name
856          *            of the property
857          * @return value of the property
858          */
859         public Object getProperty(final String name) {
860             return _properties.get(name);
861         }
862 
863         /**
864          * @see org.exolab.castor.builder.info.nature.PropertyHolder#
865          *      setProperty(java.lang.String, java.lang.Object)
866          * @param name
867          *            of the property
868          * @param value
869          *            of the property
870          */
871         public void setProperty(final String name, final Object value) {
872             _properties.put(name, value);
873         }
874 
875         /**
876          * @see org.exolab.castor.builder.info.nature.NatureExtendable#
877          *      addNature(java.lang.String)
878          * @param nature
879          *            ID of the Nature
880          */
881         public void addNature(final String nature) {
882             _natures.add(nature);
883         }
884 
885         /**
886          * @see org.exolab.castor.builder.info.nature.NatureExtendable#
887          *      hasNature(java.lang.String)
888          * @param nature
889          *            ID of the Nature
890          * @return true if the Nature ID was added.
891          */
892         public boolean hasNature(final String nature) {
893             return _natures.contains(nature);
894         }
895 
896     } //-- InternalXMLClassDescriptor
897     
898     
899 } //-- MarshalFramework