View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 2002-2004 (C) Intalio Inc. All Rights Reserved.
32   *
33   * Any portions of this file developed by Keith Visco after Jan 19 2005 are Copyright (C) 2005 Keith
34   * Visco. All Rights Reserverd.
35   *
36   *
37   * $Id$
38   */
39  package org.exolab.castor.builder.binding;
40  
41  import java.util.Enumeration;
42  
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  import org.exolab.castor.builder.BindingComponent;
46  import org.exolab.castor.builder.BuilderConfiguration;
47  import org.exolab.castor.builder.GroupNaming;
48  import org.exolab.castor.builder.TypeConversion;
49  import org.exolab.castor.builder.binding.xml.ClassType;
50  import org.exolab.castor.builder.binding.xml.ComponentBindingType;
51  import org.exolab.castor.builder.binding.xml.ComponentBindingTypeChoice;
52  import org.exolab.castor.builder.binding.xml.EnumBindingType;
53  import org.exolab.castor.builder.binding.xml.FieldType;
54  import org.exolab.castor.builder.binding.xml.Interface;
55  import org.exolab.castor.builder.binding.xml.NamingXMLType;
56  import org.exolab.castor.builder.binding.xml.types.FieldTypeVisibilityType;
57  import org.exolab.castor.builder.types.XSClass;
58  import org.exolab.castor.builder.types.XSType;
59  import org.exolab.castor.xml.schema.Annotated;
60  import org.exolab.castor.xml.schema.AttributeDecl;
61  import org.exolab.castor.xml.schema.ComplexType;
62  import org.exolab.castor.xml.schema.ContentModelGroup;
63  import org.exolab.castor.xml.schema.ElementDecl;
64  import org.exolab.castor.xml.schema.Form;
65  import org.exolab.castor.xml.schema.Group;
66  import org.exolab.castor.xml.schema.ModelGroup;
67  import org.exolab.castor.xml.schema.Particle;
68  import org.exolab.castor.xml.schema.Schema;
69  import org.exolab.castor.xml.schema.SimpleType;
70  import org.exolab.castor.xml.schema.Structure;
71  import org.exolab.castor.xml.schema.XMLType;
72  import org.exolab.javasource.JClass;
73  
74  /**
75   * This class is the implementation of BindingComponent from an XML Schema point of view. This
76   * specific implementation wraps an XML Schema annotated structure.
77   * <p>
78   * The XML Schema structure can be only of four different types:
79   * <ul>
80   * <li>Element: it represents an XML Schema element.</li>
81   * <li>ComplexType: it represents an XML Schema complexType.</li>
82   * <li>ModelGroup: it represents an XML Schema Model group definition.</li>
83   * <li>Group: it represents an XML Schema Model Group.</li>
84   * </ul>
85   * <p>
86   * The three first items can be customized using a binding file. Thus the XMLBindingComponent class
87   * takes into account the presence or not of a custom binding document in the computation of the
88   * needed information for the Source Generator to generate java classes from an XML Schema.
89   * <p>
90   * The customizable items are detailled in the binding file documentation.
91   * <p>
92   * This class acts like a <i>window</i> on a particular XML Schema structure that the user controls
93   * by changing the view on the Annotated Structure he is interested in.
94   * <p>
95   *
96   * @see org.exolab.castor.builder.BindingComponent
97   *
98   * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a>
99   * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
100  * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
101  */
102 public final class XMLBindingComponent implements BindingComponent {
103 
104   /**
105    * Log instance for all logging purposes.
106    */
107   private static final Log LOG = LogFactory.getLog(XMLBindingComponent.class);
108 
109   /**
110    * The Extended Binding used to retrieve the ComponentBindingType.
111    */
112   private ExtendedBinding _binding;
113 
114   /**
115    * The binding component to use, if no binding component is present then the default behavior
116    * applies.
117    */
118   private ComponentBindingType _compBinding;
119 
120   /**
121    * The BuilderConfiguration instance for obtaining default properties.
122    */
123   private BuilderConfiguration _config = null;
124 
125   /**
126    * The XML Schema Annotated structure encapsulated in that XMLBinding object.
127    */
128   private Annotated _annotated;
129 
130   /**
131    * The prefix used to generate the java names.
132    */
133   private String _prefix;
134 
135   /**
136    * The suffix used to generate the java names.
137    */
138   private String _suffix;
139 
140   /**
141    * The type of the XMLBinding. -1 is no component binding have been defined.
142    */
143   private short _type = -1;
144 
145   /**
146    * Caches of several computations.
147    */
148   private int _hashCode = -1;
149   private String _javaClassName = null;
150   private String _javaMemberName = null;
151   private String _javaPackage = null;
152   private FieldType _member = null;
153   private ClassType _class = null;
154   private Interface _interface = null;
155   private EnumBindingType _enum = null;
156   private Schema _schema = null;
157   private boolean _userSpecifiedMemberName = false;
158 
159   /**
160    * A GroupNaming helper class used to named anonymous groups.
161    */
162   private GroupNaming _groupNaming = null;
163 
164   /**
165    * Returns the current group naming scheme in use.
166    * 
167    * @return The current group naming scheme
168    */
169   private synchronized GroupNaming getGroupNaming() {
170     return _groupNaming;
171   }
172 
173   /**
174    * Sets the group naming instance to be used.
175    * 
176    * @param groupNaming The current group naming scheme to be used.
177    */
178   private void setGroupNaming(final GroupNaming groupNaming) {
179     _groupNaming = groupNaming;
180   }
181 
182   /**
183    * The TypeConversion to use when creating XSTypes from SimpleType.
184    */
185   private TypeConversion _typeConversion = null;
186 
187   private String _contentMemberName;
188 
189   /**
190    * Constructs an XMLBindingComponent from an XML Schema Component.
191    *
192    * @param config the BuilderConfiguration instance (must not be null).
193    * @param groupNaming The group naming scheme to be used.
194    */
195   public XMLBindingComponent(final BuilderConfiguration config, final GroupNaming groupNaming) {
196     if (config == null) {
197       String error = "The argument 'config' must not be null.";
198       throw new IllegalArgumentException(error);
199     }
200     _config = config;
201     _typeConversion = new TypeConversion(_config);
202     setGroupNaming(groupNaming);
203   } // -- XMLBindingComponent
204 
205   /**
206    * Returns the Binding Object Model on which this XMLBindingComponent will query information.
207    *
208    * @return the Extended Binding Object Model that wraps the information located in a binding file
209    */
210   public ExtendedBinding getBinding() {
211     return _binding;
212   } // -- getBinding
213 
214   /**
215    * Sets the Binding Object Model on which this XMLBindingComponent will query information.
216    *
217    * @param binding the Extended Binding Object Model that wraps the information located in a
218    *        binding file
219    */
220   public void setBinding(final ExtendedBinding binding) {
221     _binding = binding;
222   }
223 
224   /**
225    * Sets the <i>window</i> on the given Annotated XML Schema structure. Once the window is set on a
226    * particular XML Schema structure all the information returned by this class are relative to that
227    * XML Schema structure.
228    *
229    * @param annotated an Annotated XML Schema structure.
230    * @see org.exolab.castor.xml.schema.Annotated
231    */
232   public void setView(final Annotated annotated) {
233     if (annotated == null) {
234       throw new IllegalArgumentException("The XML Schema annotated structure is null.");
235     }
236 
237     _annotated = annotated;
238 
239     // --reset all the variables
240     _javaClassName = null;
241     _javaMemberName = null;
242     _javaPackage = null;
243     _schema = null;
244     _member = null;
245     _class = null;
246     _interface = null;
247     _type = -1;
248     _prefix = null;
249     _suffix = null;
250     _userSpecifiedMemberName = false;
251     _compBinding = null;
252 
253     // --look up for the particular componentBinding relative to the
254     // -- given annotated structure
255     if (_binding != null) {
256       _compBinding = _binding.getComponentBindingType(annotated);
257       NamingXMLType naming = _binding.getNamingXML();
258       if (naming != null) {
259         switch (annotated.getStructureType()) {
260           case Structure.COMPLEX_TYPE:
261             if (naming.getComplexTypeName() != null) {
262               _prefix = naming.getComplexTypeName().getPrefix();
263               _suffix = naming.getComplexTypeName().getSuffix();
264             }
265             break;
266           case Structure.ELEMENT:
267             if (naming.getElementName() != null) {
268               _prefix = naming.getElementName().getPrefix();
269               _suffix = naming.getElementName().getSuffix();
270             }
271             break;
272           case Structure.MODELGROUP:
273             if (naming.getModelGroupName() != null) {
274               _prefix = naming.getModelGroupName().getPrefix();
275               _suffix = naming.getModelGroupName().getSuffix();
276             }
277             break;
278           default:
279             break;
280         }
281       } // --naming != null;
282     } // --binding != null
283 
284     if (_compBinding != null) {
285       ComponentBindingTypeChoice choice = _compBinding.getComponentBindingTypeChoice();
286       if (choice.getInterface() != null) {
287         _type = INTERFACE;
288         _interface = choice.getInterface();
289       } else if (choice.getJavaClass() != null) {
290         _type = CLASS;
291         _class = choice.getJavaClass();
292       } else if (choice.getMember() != null) {
293         _type = MEMBER;
294         _member = choice.getMember();
295       } else if (choice.getEnumDef() != null) {
296         _type = ENUM_TYPE;
297         _enum = choice.getEnumDef();
298       } else if (choice.getContentMember() != null) {
299         _type = CONTENT_MEMBER_TYPE;
300         _contentMemberName = choice.getContentMember().getName();
301       } else {
302         String err = "Illegal Binding component:";
303         err += "it does not define a class, an interface or a member binding.";
304         throw new IllegalStateException(err);
305       }
306     }
307   } // --setView
308 
309   // --Object manipulation methods
310 
311   /**
312    * Returns true if the given Object is equal to this instance of XMLBindingComponent.
313    *
314    * @return true if the given Object is equal to this instance of XMLBindingComponent.
315    * @param object {@inheritDoc}
316    * @see java.lang.Object#equals(java.lang.Object)
317    */
318   public boolean equals(final Object object) {
319     if (object == null) {
320       return false;
321     }
322 
323     boolean result = false;
324     if (object instanceof XMLBindingComponent) {
325       XMLBindingComponent temp = (XMLBindingComponent) object;
326       result = _annotated.equals(temp.getAnnotated());
327       if (_compBinding != null) {
328         if (temp.getComponentBinding() != null) {
329           result = result && (_compBinding.equals(temp.getComponentBinding()));
330         } else {
331           result = false;
332         }
333       } else if (temp.getComponentBinding() != null) {
334         result = false;
335       }
336     } else {
337       result = false;
338     }
339     return result;
340   }
341 
342   /**
343    * Returns the hashCode value for this object.
344    *
345    * @return the hashcode value for this object.
346    * @see java.lang.Object#hashCode()
347    */
348   public int hashCode() {
349     if (_hashCode == -1) {
350       int compBindingHash = 0;
351       if (_compBinding != null) {
352         compBindingHash = _compBinding.getName().hashCode();
353       }
354       // WARNING: THE CASTOR SOM doesn't override hashCode or equals
355       _hashCode = 37 * (_annotated.hashCode()) + compBindingHash;
356     }
357     return _hashCode;
358   }
359 
360   /**
361    * Returns the ComponentBinding used in that XMLBindingComponent to retrieve customized
362    * information.
363    *
364    * @return the ComponentBinding used in that XMLBinding.
365    */
366   protected ComponentBindingType getComponentBinding() {
367     return _compBinding;
368   }
369 
370   // --XML Schema information methods
371 
372   /**
373    * Returns the XML Schema annotated structure used in this XMLBindingComponent.
374    *
375    * @return the XML Schema annotated structure used in this XMLBindingComponent.
376    */
377   public Annotated getAnnotated() {
378     return _annotated;
379   }
380 
381   /**
382    * Returns true if the binding of this XMLBindingComponent will require the generation of 2 java
383    * classes. Indeed an a nested Model Group that can occur more than once is described by the
384    * SourceGenerator with a wrapper class.
385    *
386    * @return true if the binding of this XMLBindingComponent will require the generation of 2 java
387    *         classes.
388    */
389   public boolean createGroupItem() {
390     int maxOccurs = 0;
391     boolean result = false;
392     switch (_annotated.getStructureType()) {
393       case Structure.ELEMENT:
394         XMLType type = ((ElementDecl) _annotated).getType();
395         if (type.isComplexType()) {
396           maxOccurs = ((ComplexType) type).getMaxOccurs();
397           if (((maxOccurs > 1) || (maxOccurs < 0)) && (type.getName() == null)) {
398             result = true;
399           }
400         }
401         break;
402       case Structure.COMPLEX_TYPE:
403         maxOccurs = ((ComplexType) _annotated).getMaxOccurs();
404         if ((maxOccurs > 1) || (maxOccurs < 0)) {
405           result = true;
406         }
407         break;
408       case Structure.MODELGROUP:
409       case Structure.GROUP:
410         Group group = (Group) _annotated;
411         maxOccurs = group.getMaxOccurs();
412         if ((maxOccurs > 1) || (maxOccurs < 0)) {
413           result = true;
414         }
415         break;
416       case Structure.ATTRIBUTE:
417       default:
418         break;
419 
420     }
421     return result;
422   }
423 
424   /**
425    * Returns the schemaLocation of the parent schema of the wrapped structure.
426    *
427    * @return the schemaLocation of the parent schema of the wrapped structure.
428    */
429   public String getSchemaLocation() {
430     String location = null;
431     Schema schema = getSchema();
432     if (schema != null) {
433       location = schema.getSchemaLocation();
434     }
435 
436     return location;
437   }
438 
439   /**
440    * Returns the targetNamespace of the parent schema of the wrapped structure.
441    *
442    * @return the targetNamespace of the parent schema of the wrapped structure.
443    */
444   public String getTargetNamespace() {
445     String result = null;
446     Schema schema = null;
447     Form form = null;
448 
449     switch (_annotated.getStructureType()) {
450       case Structure.ATTRIBUTE:
451         AttributeDecl attribute = (AttributeDecl) _annotated;
452         // -- resolve reference
453         if (attribute.isReference()) {
454           attribute = attribute.getReference();
455         }
456 
457         schema = attribute.getSchema();
458 
459         // -- top-level (use targetNamespace of schema)
460         if (attribute.getParent() == schema) {
461           break;
462         }
463 
464         // -- check form (qualified or unqualified)
465         form = attribute.getForm();
466         if (form == null) {
467           form = schema.getAttributeFormDefault();
468         }
469 
470         if ((form == null) || form.isUnqualified()) {
471           // -- no targetNamespace by default
472           return null;
473         }
474         // -- use targetNamespace of schema
475         break;
476       case Structure.ELEMENT:
477         // --resolve reference?
478         ElementDecl element = (ElementDecl) _annotated;
479         if (element.isReference()) {
480           element = element.getReference();
481         }
482 
483         schema = element.getSchema();
484         // -- top-level (use targetNamespace of schema)
485         if (element.getParent() == schema) {
486           break;
487         }
488 
489         // -- check form (qualified or unqualified)
490         form = element.getForm();
491         if (form == null) {
492           form = schema.getElementFormDefault();
493         }
494 
495         // -- no targetNamespace by default
496         if ((form == null) || form.isUnqualified()) {
497           return null;
498         }
499         // -- use targetNamespace of schema
500         break;
501       case Structure.COMPLEX_TYPE:
502         ComplexType complexType = (ComplexType) _annotated;
503         schema = complexType.getSchema();
504         if (complexType.getParent() == schema) {
505           break;
506         }
507         return null;
508       case Structure.SIMPLE_TYPE:
509         SimpleType simpleType = (SimpleType) _annotated;
510         schema = simpleType.getSchema();
511         if (simpleType.getParent() == schema) {
512           break;
513         }
514         return null;
515       default:
516         break;
517     }
518     if (schema == null) {
519       schema = getSchema();
520     }
521 
522     if (schema != null) {
523       result = schema.getTargetNamespace();
524     }
525     return result;
526   } // -- getTargetNamespace
527 
528   /**
529    * Returns the underlying Schema of the wrapped structure.
530    *
531    * @return the parent schema of the wrapped structure.
532    */
533   public Schema getSchema() {
534     if (_schema != null) {
535       return _schema;
536     }
537 
538     switch (_annotated.getStructureType()) {
539       case Structure.ATTRIBUTE:
540         // --resolve reference?
541         AttributeDecl attribute = (AttributeDecl) _annotated;
542         if (attribute.isReference()) {
543           attribute = attribute.getReference();
544         }
545         _schema = attribute.getSchema();
546         attribute = null;
547         break;
548       case Structure.ELEMENT:
549         // --resolve reference?
550         ElementDecl element = (ElementDecl) _annotated;
551         if (element.isReference()) {
552           element = element.getReference();
553         }
554         _schema = element.getSchema();
555         element = null;
556         break;
557       case Structure.COMPLEX_TYPE:
558         _schema = ((ComplexType) _annotated).getSchema();
559         break;
560       case Structure.MODELGROUP:
561         // --resolve reference?
562         ModelGroup group = (ModelGroup) _annotated;
563         if (group.isReference()) {
564           group = group.getReference();
565         }
566         _schema = group.getSchema();
567         group = null;
568         break;
569       case Structure.GROUP:
570         Structure parent = ((Group) _annotated).getParent();
571         short structure = parent.getStructureType();
572         while (structure == Structure.GROUP) {
573           parent = ((Group) parent).getParent();
574           structure = parent.getStructureType();
575         }
576         if (structure == Structure.COMPLEX_TYPE) {
577           _schema = ((ComplexType) parent).getSchema();
578         } else if (structure == Structure.MODELGROUP) {
579           _schema = ((ModelGroup) parent).getSchema();
580         }
581         break;
582       case Structure.SIMPLE_TYPE:
583       case Structure.UNION:
584       case Structure.LIST:
585         _schema = ((SimpleType) _annotated).getSchema();
586         break;
587       default:
588         break;
589     }
590 
591     return _schema;
592   }
593 
594   /**
595    * Returns the XMLType of the underlying structure. The XMLType of an element being its XML Schema
596    * type, the XMLType of a ComplexType being itself and the XMLType of an attribute being its XML
597    * Schema simpleType. Null is returned for a Model Group.
598    *
599    * @return the XMLType of the underlying structure.
600    */
601   public XMLType getXMLType() {
602     XMLType result = null;
603     switch (_annotated.getStructureType()) {
604       case Structure.ELEMENT:
605         result = ((ElementDecl) _annotated).getType();
606         break;
607       case Structure.COMPLEX_TYPE:
608         result = ((ComplexType) _annotated);
609         break;
610       case Structure.SIMPLE_TYPE:
611         result = ((SimpleType) _annotated);
612         break;
613       case Structure.ATTRIBUTE:
614         result = ((AttributeDecl) _annotated).getSimpleType();
615         break;
616       case Structure.MODELGROUP:
617       default:
618         break;
619     }
620     return result;
621   }
622 
623   /**
624    * Returns the XML name declared in the XML Schema for this XMLBindingComponent.
625    *
626    * @return the XML name declared in the XML Schema for this XMLBindingComponent.
627    */
628   public String getXMLName() {
629     String result = null;
630 
631     if (_annotated != null) {
632       switch (_annotated.getStructureType()) {
633         case Structure.ELEMENT:
634           result = ((ElementDecl) _annotated).getName();
635           break;
636         case Structure.COMPLEX_TYPE:
637           result = ((ComplexType) _annotated).getName();
638           break;
639         case Structure.SIMPLE_TYPE:
640           result = ((SimpleType) _annotated).getName();
641           break;
642         case Structure.ATTRIBUTE:
643           result = ((AttributeDecl) _annotated).getName();
644           break;
645         case Structure.MODELGROUP:
646         case Structure.GROUP:
647           result = ((Group) _annotated).getName();
648           break;
649         default:
650           break;
651 
652       }
653     }
654     return result;
655   }
656 
657   // --Implementation of BindingComponent
658 
659   /**
660    * Returns the value specified in the XML Schema for the XML Schema component wrapped in this
661    * XMLBindingComponent. The value returned is the <i>default</i> or <i>fixed</i> value for an
662    * Element or an Attribute.
663    *
664    * @return the value specified in the XML Schema for the XML Schema annotated structure wrapped in
665    *         this XMLBindingComponent.
666    */
667   public String getValue() {
668     String result = null;
669     switch (_annotated.getStructureType()) {
670       case Structure.ELEMENT:
671         result = ((ElementDecl) _annotated).getDefaultValue();
672         if (result == null) {
673           result = ((ElementDecl) _annotated).getFixedValue();
674         }
675         break;
676       case Structure.ATTRIBUTE:
677         result = ((AttributeDecl) _annotated).getDefaultValue();
678         if (result == null) {
679           result = ((AttributeDecl) _annotated).getFixedValue();
680         }
681         break;
682       case Structure.COMPLEX_TYPE:
683       case Structure.SIMPLE_TYPE:
684       case Structure.MODELGROUP:
685       default:
686         break;
687     }
688 
689     return result;
690   }
691 
692   /**
693    * Returns a valid Java Class Name corresponding to this XMLBindingComponent. This name is not
694    * qualified, this is only a local Java class name.
695    *
696    * @return a valid Java Class Name corresponding to this XMLBindingComponent. This name is not
697    *         qualified, this is only a local Java class name.
698    * @see #getQualifiedName
699    */
700   public String getJavaClassName() {
701     if (_javaClassName == null) {
702       String result = null;
703       // --is there a class name defined (local name)
704       if (_compBinding != null) {
705         switch (getType()) {
706           case CLASS:
707             result = _class.getName();
708             break;
709           case INTERFACE:
710             result = _interface.getName();
711             break;
712           default:
713             break;
714         }
715       }
716 
717       if (result == null || result.length() <= 0) {
718         // --is there a reference?
719         if (_annotated != null && _annotated.getStructureType() == Structure.ELEMENT) {
720           ElementDecl element = (ElementDecl) _annotated;
721           if (element.isReference()) {
722             Annotated temp = _annotated;
723             setView(element.getReference());
724             result = getJavaClassName();
725             setView(temp);
726             temp = null;
727           } else if (_config.mappingSchemaType2Java()) {
728             // deal with (global) element declarations in type mode,
729             // where no Java class will be generated per definition;
730             // in this case, the class name to be used should be taken from the
731             // underlying (complex) type
732             XMLType xmlType = element.getType();
733             if (xmlType != null && xmlType.isComplexType()) {
734               ComplexType complexType = (ComplexType) xmlType;
735               Annotated temp = _annotated;
736               setView(complexType);
737               result = getJavaClassName();
738               setView(temp);
739             }
740           }
741           element = null;
742         }
743 
744         // --Still null?
745         if (result == null || result.length() <= 0) {
746           // --create the name
747           result = getXMLName();
748           // --create a java name for an anonymous group
749           if (result == null && _annotated != null
750               && (_annotated.getStructureType() == Structure.GROUP
751                   || _annotated.getStructureType() == Structure.MODELGROUP)) {
752             GroupNaming groupNaming = getGroupNaming();
753             result = groupNaming.createClassName((Group) _annotated, getJavaPackage());
754             if (result == null) {
755               String err = "Unable to create name for group.";
756               throw new IllegalStateException(err);
757             }
758           }
759 
760           if (_prefix != null) {
761             result = _prefix + result;
762           }
763           if (_suffix != null) {
764             result = result + _suffix;
765           }
766         }
767       }
768 
769       _javaClassName = _config.getJavaNaming().toJavaClassName(result);
770     }
771 
772     // TODO ADD A SWITCH TO DETERMINE WETHER OR NOT TO USE JAVA CONVENTIONS
773     // FOR THE JAVA CLASS NAME (SEE JAXB)
774     return _javaClassName;
775   }
776 
777   /**
778    * Returns a valid Java Member Name corresponding to this XMLBindingComponent. This name is not
779    * qualified, this is only a local Java Member name.
780    *
781    * @return a valid Java Member Name corresponding to this XMLBindingComponent. This name is not
782    *         qualified, this is only a local Java member name.
783    * @see #getQualifiedName
784    */
785   public String getJavaMemberName() {
786     if (_javaMemberName == null) {
787       String result = null;
788       if (_compBinding != null) {
789         switch (getType()) {
790           case CLASS:
791             result = _class.getName();
792             break;
793           case INTERFACE:
794             result = _interface.getName();
795             break;
796           case MEMBER:
797             result = _member.getName();
798             break;
799           default:
800             break;
801         }
802       }
803 
804       if (result == null || result.length() <= 0) {
805         Annotated temp = null;
806         if (_annotated.getStructureType() == Structure.ATTRIBUTE) {
807           AttributeDecl att = (AttributeDecl) _annotated;
808           if (att.isReference()) {
809             temp = _annotated;
810             setView(att.getReference());
811             result = getJavaMemberName();
812             setView(temp);
813           }
814           att = null;
815         } else if (_annotated.getStructureType() == Structure.ELEMENT) {
816           ElementDecl element = (ElementDecl) _annotated;
817           if (element.isReference()) {
818             temp = _annotated;
819             setView(element.getReference());
820             result = getJavaMemberName();
821             boolean userSpecified = _userSpecifiedMemberName;
822             setView(temp);
823 
824             // -- there might be more than once reference, so we
825             // -- need to do a little counting here.
826             if (!userSpecified) {
827               String refName = element.getReferenceName();
828               int count = 0;
829               int index = 0;
830               Structure structure = element.getParent();
831               if (structure instanceof ContentModelGroup) {
832                 ContentModelGroup cmg = (ContentModelGroup) structure;
833                 Enumeration<Particle> enumeration = cmg.enumerate();
834                 while (enumeration.hasMoreElements()) {
835                   Structure tmpStruct = enumeration.nextElement();
836                   if (tmpStruct.getStructureType() == Structure.ELEMENT) {
837                     ElementDecl tmpDecl = (ElementDecl) tmpStruct;
838                     if (tmpDecl.isReference() && tmpDecl.getReferenceName().equals(refName)) {
839                       ++count;
840                       if (tmpDecl == element) {
841                         index = count;
842                       }
843                     }
844                   }
845                 }
846               }
847               if (count > 1) {
848                 result = result + index;
849               }
850             }
851           }
852           element = null;
853         }
854         temp = null;
855 
856         // --Still null?
857         if (result == null || result.length() <= 0) {
858           // --create the name
859           result = getXMLName();
860           // --create a java name for an anonymous group
861           if (result == null && (_annotated.getStructureType() == Structure.GROUP
862               || _annotated.getStructureType() == Structure.MODELGROUP)) {
863             result = getGroupNaming().createClassName((Group) _annotated, getJavaPackage());
864             if (result == null) {
865               String err = "Unable to create name for group.";
866               throw new IllegalStateException(err);
867             }
868           }
869 
870           if (_prefix != null) {
871             result = _prefix + result;
872           }
873           if (_suffix != null) {
874             result = result + _suffix;
875           }
876         }
877       } else {
878         _userSpecifiedMemberName = true;
879       }
880       _javaMemberName = _config.getJavaNaming().toJavaMemberName(result);
881     }
882 
883     // TODO ADD A SWITCH TO DETERMINE WETHER OR NOT TO USE JAVA CONVENTIONS
884     // FOR THE JAVA CLASS NAME (SEE JAXB)
885     return _javaMemberName;
886   }
887 
888   /**
889    * Returns the fully qualified name used for generating a java name that represents this
890    * XMLBindingComponent.
891    * <p>
892    * The fully qualified name is computed according the following priority order:
893    * <ul>
894    * <li>If the XMLBinding wraps a class binding then the package name is the name defined locally
895    * in the {@literal &lt;java-class>} element. More precisely the package name will be the value of
896    * the attribute package.</li>
897    * <li>Else the package name will be computed from the schemaLocation of the parent schema.</li>
898    * <li>Else the package name will be computed from the target namespace of the parent schema.</li>
899    * </ul>
900    *
901    * Note: the computation of the namespace is a direct look-up for a defined mapping (Namespace,
902    * package) or (schema location, package).
903    *
904    * @return the fully qualified name used for generating a java name that represents this
905    *         XMLBindingComponent.
906    */
907   public String getQualifiedName() {
908     String result = getJavaClassName();
909     String packageName = getJavaPackage();
910     if (packageName != null && packageName.length() > 0) {
911       packageName += '.';
912       result = packageName + result;
913     }
914     return result;
915   }
916 
917   /**
918    * Returns the java package associated with this XML BindingComponent. The algorithm used to
919    * resolve the package is defined according to the following priorities:
920    * <ol>
921    * <li>The package defined locally in the class declaration inside the binding file is used.</li>
922    * <li>If no package has been defined locally then a lookup to a defined mapping {targetNamespace,
923    * package name} is performed.</li>
924    * <li>If no package has been defined locally then a lookup to a defined mapping {schema location,
925    * package name} is performed.</li>
926    * </ol>
927    *
928    * @return the java package associated with this XML BindingComponent.
929    */
930   public String getJavaPackage() {
931     if (_javaPackage == null) {
932       String packageName = null;
933       String schemaLocation = getSchemaLocation();
934       String targetNamespace = getTargetNamespace();
935       // -- adjust targetNamespace null -> ""
936       if (targetNamespace == null) {
937         targetNamespace = "";
938       }
939 
940       if (_compBinding != null) {
941         switch (getType()) {
942           case CLASS:
943             packageName = _class.getPackage();
944             break;
945           default:
946             break;
947         } // --switch
948       }
949 
950       if (isPackageNameNotSet(packageName)) {
951 
952         if (isPackageNameNotSet(packageName)) {
953           // look for a namespace mapping
954           packageName = _config.lookupPackageByNamespace(targetNamespace);
955         }
956 
957         if (schemaLocation != null && isPackageNameNotSet(packageName)) {
958           // look for schema location mapping
959           packageName = _config.lookupPackageByLocation(schemaLocation);
960         }
961 
962       }
963       _javaPackage = packageName;
964     }
965     return _javaPackage;
966   }
967 
968   /**
969    * Indicates whether a package name has already been set.
970    * 
971    * @param packageName The package name to analyse.
972    * @return True if the package name has been set correctly.
973    */
974   private boolean isPackageNameNotSet(final String packageName) {
975     return (packageName == null || packageName.length() == 0);
976   }
977 
978   /**
979    * Returns the upper bound of the collection that is generated from this BindingComponent. The
980    * upper bound is a positive integer. -1 is returned to indicate that the upper bound is
981    * unbounded.
982    * <p>
983    * In the case of an XML Schema component, the upper bound corresponds to the XML Schema maxOccurs
984    * attribute, if any.
985    *
986    * @return an int representing the lower bound of the collection generated from this
987    *         BindingComponent. -1 is returned to indicate that the upper bound is unbounded. 1 is
988    *         the default value.
989    */
990   public int getUpperBound() {
991     switch (_annotated.getStructureType()) {
992 
993       case Structure.ELEMENT:
994         return ((ElementDecl) _annotated).getMaxOccurs();
995 
996       case Structure.COMPLEX_TYPE:
997         return ((ComplexType) _annotated).getMaxOccurs();
998 
999       case Structure.GROUP:
1000       case Structure.MODELGROUP:
1001         return ((Group) _annotated).getMaxOccurs();
1002 
1003       case Structure.ATTRIBUTE:
1004       default:
1005         break;
1006     }
1007     return 1;
1008   }
1009 
1010   /**
1011    * Returns the lower bound of the collection that is generated from this BindingComponent. The
1012    * lower bound is a positive integer. In the case of an XML Schema component, it corresponds to
1013    * the XML Schema minOccurs attribute, if any.
1014    *
1015    * @return an int representing the lower bound of the collection generated from this
1016    *         BindingComponent. 0 is returned by default.
1017    */
1018   public int getLowerBound() {
1019     return getLowerBound(_annotated);
1020   }
1021 
1022   //////// METHODS RELATED TO A CLASS BINDING
1023 
1024   /**
1025    * Returns the name of a super class for the current XMLBinding. Null is returned if this
1026    * XMLBinding is not meant to be mapped to a java class.
1027    *
1028    * @return the name of a super class for the current XMLBinding. Null is returned if this
1029    *         XMLBinding is not meant to be mapped to a java class
1030    */
1031   public String getExtends() {
1032     if (getType() == CLASS) {
1033       return _class.getExtends();
1034     }
1035     return _config.getProperty(BuilderConfiguration.Property.SUPER_CLASS, null);
1036   } // -- getExtends
1037 
1038   /**
1039    * Returns an array of the different interface names implemented by the class that will represent
1040    * the current XMLBindingComponent. Null is returned if no class binding is defined for the
1041    * wrapped XML Schema structure.
1042    *
1043    * @return array of interface names
1044    */
1045   public String[] getImplements() {
1046     if (getType() == CLASS) {
1047       return _class.getImplements();
1048     }
1049     return null;
1050   }
1051 
1052   /**
1053    * Returns true if bound properties must be generated for the class that will represent the
1054    * current XMLBindingComponent.
1055    *
1056    * @return true if bound properties must be generated for the class the class that will represent
1057    *         the current XMLBindingComponent.
1058    */
1059   public boolean hasBoundProperties() {
1060     if (getType() == CLASS && _class.hasBound()) {
1061       return _class.getBound();
1062     }
1063     return _config.boundPropertiesEnabled();
1064   }
1065 
1066   /**
1067    * Returns true if equal method must be generated for the class that will represent the current
1068    * XMLBindingComponent.
1069    *
1070    * @return true if equal method must be generated for the class the class that will represent the
1071    *         current XMLBindingComponent.
1072    */
1073   public boolean hasEquals() {
1074     if (getType() == CLASS && _class.hasEquals()) {
1075       return _class.getEquals();
1076     }
1077     return _config.equalsMethod();
1078   }
1079 
1080   /**
1081    * Returns true if the class that will represent the current XMLBindingComponent must be abstract.
1082    *
1083    * @return true if the class that will represent the current XMLBindingComponent must be abstract.
1084    */
1085   public boolean isAbstract() {
1086     boolean result = false;
1087     if (getType() == CLASS && _class.hasAbstract()) {
1088       result = _class.getAbstract();
1089     }
1090 
1091     if (!result) {
1092       switch (_annotated.getStructureType()) {
1093         case Structure.COMPLEX_TYPE:
1094           ComplexType cType = (ComplexType) _annotated;
1095           result = cType.isAbstract();
1096           // -- if we're in element-centric mode, then all
1097           // -- complexTypes are treated as abstract
1098           result = result || _config.mappingSchemaElement2Java();
1099           break;
1100         case Structure.ELEMENT:
1101           ElementDecl eDecl = (ElementDecl) _annotated;
1102           result = eDecl.isAbstract();
1103           break;
1104         default:
1105           break;
1106       }
1107     }
1108     return result;
1109   }
1110 
1111   /**
1112    * Returns true if the class that will represent the current XMLBindingComponent must be final.
1113    *
1114    * @return true if the class that will represent the current XMLBindingComponent must be final.
1115    */
1116   public boolean isFinal() {
1117     if (getType() == CLASS) {
1118       return _class.getFinal();
1119     }
1120     return false;
1121   }
1122 
1123   /**
1124    * Returns true if the wrapped XML Schema component is fixed (i.e the value used is fixed).
1125    *
1126    * @return true if the wrapped XML Schema component is fixed (i.e the value used is fixed).
1127    */
1128   public boolean isFixed() {
1129 
1130     switch (_annotated.getStructureType()) {
1131       case Structure.ELEMENT:
1132         String fixed = ((ElementDecl) _annotated).getFixedValue();
1133         return (fixed != null);
1134 
1135       case Structure.ATTRIBUTE:
1136         return ((AttributeDecl) _annotated).isFixed();
1137 
1138       case Structure.GROUP:
1139       case Structure.COMPLEX_TYPE:
1140       case Structure.SIMPLE_TYPE:
1141       case Structure.MODELGROUP:
1142       default:
1143         break;
1144     }
1145     return false;
1146   }
1147 
1148   /**
1149    * Returns true if the wrapped XML Schema component is nillable.
1150    *
1151    * @return true if the wrapped XML Schema component is nillable.
1152    */
1153   public boolean isNillable() {
1154     switch (_annotated.getStructureType()) {
1155       case Structure.ELEMENT:
1156         return ((ElementDecl) _annotated).isNillable();
1157       default:
1158         break;
1159     }
1160     return false;
1161   } // -- isNillable
1162 
1163   //////// METHODS RELATED TO A MEMBER BINDING
1164 
1165   /**
1166    * Returns true if the member represented by that XMLBindingComponent is to be represented by an
1167    * Object wrapper. For instance an int will be represented by a java Integer if the property is
1168    * set to true.
1169    *
1170    * @return true if the member represented by that XMLBindingComponent is to be represented by an
1171    *         Object wrapper.
1172    */
1173   public boolean useWrapper() {
1174     if (_type != BindingComponent.MEMBER) {
1175       return _config.usePrimitiveWrapper();
1176     }
1177 
1178     if (_member.hasWrapper()) {
1179       return _member.getWrapper();
1180     }
1181 
1182     return false;
1183   }
1184 
1185   /**
1186    * Returns the XSType that corresponds to the Java type chosen to represent the XML Schema
1187    * component represented by this XMLBindingComponent. An XSType is an abstraction of a Java type
1188    * used in the Source Generator. It wraps a JType as well as the necessary methods to convert
1189    * to/from String.
1190    * <p>
1191    * If a name of java type is specified then this name will have higher priority than the
1192    * simpleType resolution.
1193    *
1194    * @return an XSType
1195    */
1196   public XSType getJavaType() {
1197     // --no need for caching it is called only once
1198     XSType result = null;
1199     boolean useWrapper = useWrapper();
1200     XMLType type = getXMLType();
1201 
1202     if (type != null && type.isComplexType()) {
1203       if (_type == MEMBER && _member.getJavaType() != null) {
1204         String javaType = _member.getJavaType();
1205         if (javaType != null && javaType.length() > 0) {
1206           result = TypeConversion.convertType(javaType);
1207         }
1208       } else {
1209         result = new XSClass(new JClass(getJavaClassName()));
1210       }
1211     } else {
1212       if (_type == MEMBER) {
1213         String javaType = _member.getJavaType();
1214         if (javaType != null && javaType.length() > 0) {
1215           result = TypeConversion.convertType(javaType);
1216         }
1217       }
1218     }
1219 
1220     if (result == null) {
1221       // --simpleType or AnyType
1222       if (type != null && type.isSimpleType()) {
1223         String packageName = null;
1224         String className = null;
1225         if (((SimpleType) type).getSchema() != getSchema()) {
1226           XMLBindingComponent comp = new XMLBindingComponent(_config, getGroupNaming());
1227           comp.setBinding(_binding);
1228           comp.setView(type);
1229           packageName = comp.getJavaPackage();
1230           if (comp.getClass() != null) {
1231             className = comp.getJavaClassName();
1232           }
1233         } else {
1234           packageName = getJavaPackage();
1235           if (_class != null) {
1236             className = getJavaClassName();
1237           }
1238         }
1239 
1240         if ((packageName == null) || (packageName.length() == 0)) {
1241           String ns = ((SimpleType) type).getSchema().getTargetNamespace();
1242           packageName = _config.lookupPackageByNamespace(ns);
1243         }
1244 
1245         result = _typeConversion.convertType((SimpleType) type, packageName, useWrapper,
1246             _config.useJava50(), className);
1247       }
1248     }
1249 
1250     return result;
1251   }
1252 
1253   /**
1254    * Returns the collection name specified in the binding file. If no collection was specified, null
1255    * will be returned and the default collection settings will be used.
1256    *
1257    * @return a string that represents the collection name specified in the binding file. If no
1258    *         collection was specified, null will be returned and the default collection settings
1259    *         will be used.
1260    */
1261   public String getCollectionType() {
1262     String result = null;
1263     if ((_type == MEMBER) && (_member.getCollection() != null)) {
1264       result = _member.getCollection().toString();
1265     }
1266     return result;
1267   }
1268 
1269   /**
1270    * Returns the fully qualified name of the Validator to use.
1271    *
1272    * @return the fully qualified name of the Validator to use.
1273    */
1274   public String getValidator() {
1275     if (_type == MEMBER) {
1276       return _member.getValidator();
1277     }
1278     return null;
1279   }
1280 
1281   /**
1282    * Returns the fully qualified name of the XMLFieldHandler to use.
1283    *
1284    * @return the fully qualified name of the XMLFieldHandler to use.
1285    */
1286   public String getXMLFieldHandler() {
1287     if (_type == MEMBER) {
1288       return _member.getHandler();
1289     }
1290     return null;
1291   }
1292 
1293   /**
1294    * Returns the visibility of the Java member to generate.
1295    *
1296    * @return the visibility of the Java member to generate.
1297    */
1298   public String getVisiblity() {
1299     if (_type == MEMBER) {
1300       final FieldTypeVisibilityType visibility = _member.getVisibility();
1301       if (visibility != null) {
1302         return visibility.toString();
1303       }
1304       return "private";
1305     }
1306     return null;
1307   }
1308 
1309   /**
1310    * Returns the type of this component binding. A component binding can be of three different
1311    * types:
1312    * <ul>
1313    * <li>Interface: it represents the binding to a java interface.</li>
1314    * <li>Class: it represents the binding to a java class.</li>
1315    * <li>Member: it represents the binding to a java class member.</li>
1316    * </ul>
1317    * <p>
1318    * -1 is returned if the component binding is null.
1319    *
1320    * @return the type of this component binding.
1321    */
1322   public short getType() {
1323     return _type;
1324   }
1325 
1326   /**
1327    * Returns the lower bound of the collection that is generated from this BindingComponent. The
1328    * lower bound is a positive integer. In the case of an XML Schema component, it corresponds to
1329    * the XML Schema minOccurs attribute, if any.
1330    *
1331    * @param annotated an Annotated XML Schema structure.
1332    * @return an int representing the lower bound of the collection generated from this
1333    *         BindingComponent. 0 is returned by default.
1334    */
1335   private static int getLowerBound(final Annotated annotated) {
1336     switch (annotated.getStructureType()) {
1337       case Structure.ELEMENT:
1338         return ((ElementDecl) annotated).getMinOccurs();
1339       case Structure.COMPLEX_TYPE:
1340         return ((ComplexType) annotated).getMinOccurs();
1341       case Structure.MODELGROUP:
1342       case Structure.GROUP:
1343         Group group = (Group) annotated;
1344         // -- if the group is top-level, then we always return 0
1345         Structure parent = group.getParent();
1346         if (parent != null && parent.getStructureType() == Structure.SCHEMA) {
1347           return 0;
1348         }
1349         int minOccurs = group.getMinOccurs();
1350         // -- if minOccurs == 1, then check to see if all elements inside group are
1351         // -- optional, if so, we return 0, not 1.
1352         if (minOccurs == 1) {
1353           Enumeration<Particle> enumeration = group.enumerate();
1354           while (enumeration.hasMoreElements()) {
1355             if (getLowerBound(enumeration.nextElement()) != 0) {
1356               return 1;
1357             }
1358           }
1359           // -- if we make it here, all items in group have a lowerbound of 0, so
1360           // -- the group can be considered optional
1361           return 0;
1362         }
1363         return minOccurs;
1364 
1365       case Structure.ATTRIBUTE:
1366         if (((AttributeDecl) annotated).isRequired()) {
1367           return 1;
1368         }
1369         break;
1370       default:
1371         break;
1372     }
1373     return 0;
1374   } // -- getLowerBound
1375 
1376   /**
1377    * Returns the EnumBindingType instance for the active binding component.
1378    * 
1379    * @return The EnumBindingType instance
1380    */
1381   public EnumBindingType getEnumBinding() {
1382     return _enum;
1383   }
1384 
1385   /**
1386    * Returns the name 'override' of a content member as specified in a binding file.
1387    * 
1388    * @return the name of the name 'override' for the content member.
1389    */
1390   public String getContentMemberName() {
1391     return _contentMemberName;
1392   }
1393 
1394 } // -- class: XMLBindingComponent