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