/* * Redistribution and use of this software and associated documentation * ("Software"), with or without modification, are permitted provided * that the following conditions are met: * * 1. Redistributions of source code must retain copyright * statements and notices. Redistributions must also contain a * copy of this document. * * 2. Redistributions in binary form must reproduce the * above copyright notice, this list of conditions and the * following disclaimer in the documentation and/or other * materials provided with the distribution. * * 3. The name "Exolab" must not be used to endorse or promote * products derived from this Software without prior written * permission of Intalio, Inc. For written permission, * please contact info@exolab.org. * * 4. Products derived from this Software may not be called "Exolab" * nor may "Exolab" appear in their names without prior written * permission of Intalio, Inc. Exolab is a registered * trademark of Intalio, Inc. * * 5. Due credit should be given to the Exolab Project * (http://www.exolab.org/). * * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * * Copyright 2002-2004 (C) Intalio Inc. All Rights Reserved. * * Any portions of this file developed by Keith Visco after Jan 19 2005 * are Copyright (C) 2005 Keith Visco. All Rights Reserverd. * * * $Id$ */ package org.exolab.castor.builder.binding; import java.util.Enumeration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.exolab.castor.builder.BindingComponent; import org.exolab.castor.builder.BuilderConfiguration; import org.exolab.castor.builder.GroupNaming; import org.exolab.castor.builder.TypeConversion; import org.exolab.castor.builder.binding.xml.ClassType; import org.exolab.castor.builder.binding.xml.ComponentBindingType; import org.exolab.castor.builder.binding.xml.ComponentBindingTypeChoice; import org.exolab.castor.builder.binding.xml.EnumBindingType; import org.exolab.castor.builder.binding.xml.FieldType; import org.exolab.castor.builder.binding.xml.Interface; import org.exolab.castor.builder.binding.xml.NamingXMLType; import org.exolab.castor.builder.binding.xml.types.FieldTypeVisibilityType; import org.exolab.castor.builder.types.XSClass; import org.exolab.castor.builder.types.XSType; import org.exolab.castor.xml.schema.Annotated; import org.exolab.castor.xml.schema.AttributeDecl; import org.exolab.castor.xml.schema.ComplexType; import org.exolab.castor.xml.schema.ContentModelGroup; import org.exolab.castor.xml.schema.ElementDecl; import org.exolab.castor.xml.schema.Form; import org.exolab.castor.xml.schema.Group; import org.exolab.castor.xml.schema.ModelGroup; import org.exolab.castor.xml.schema.Schema; import org.exolab.castor.xml.schema.SimpleType; import org.exolab.castor.xml.schema.Structure; import org.exolab.castor.xml.schema.XMLType; import org.exolab.javasource.JClass; /** * This class is the implementation of BindingComponent from an XML Schema point * of view. This specific implementation wraps an XML Schema annotated * structure. * <p> * The XML Schema structure can be only of four different types: * <ul> * <li>Element: it represents an XML Schema element.</li> * <li>ComplexType: it represents an XML Schema complexType.</li> * <li>ModelGroup: it represents an XML Schema Model group definition.</li> * <li>Group: it represents an XML Schema Model Group.</li> * </ul> * <p> * The three first items can be customized using a binding file. Thus the * XMLBindingComponent class takes into account the presence or not of a custom * binding document in the computation of the needed information for the Source * Generator to generate java classes from an XML Schema. * <p> * The customizable items are detailled in the binding file documentation. * <p> * This class acts like a <i>window</i> on a particular XML Schema structure * that the user controls by changing the view on the Annotated Structure he is * interested in. * <p> * * @see org.exolab.castor.builder.BindingComponent * * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a> * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a> * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $ */ public final class XMLBindingComponent implements BindingComponent { /** * Log instance for all logging purposes. */ private static final Log LOG = LogFactory.getLog(XMLBindingComponent.class); /** * The Extended Binding used to retrieve the ComponentBindingType. */ private ExtendedBinding _binding; /** * The binding component to use, if no binding component is present then * the default behavior applies. */ private ComponentBindingType _compBinding; /** * The BuilderConfiguration instance for obtaining default properties. */ private BuilderConfiguration _config = null; /** * The XML Schema Annotated structure encapsulated in that XMLBinding object. */ private Annotated _annotated; /** * The prefix used to generate the java names. */ private String _prefix; /** * The suffix used to generate the java names. */ private String _suffix; /** * The type of the XMLBinding. -1 is no component binding have been defined. */ private short _type = -1; /** * Caches of several computations. */ private int _hashCode = -1; private String _javaClassName = null; private String _javaMemberName = null; private String _javaPackage = null; private FieldType _member = null; private ClassType _class = null; private Interface _interface = null; private EnumBindingType _enum = null; private Schema _schema = null; private boolean _userSpecifiedMemberName = false; /** * A GroupNaming helper class used to named anonymous groups. */ private GroupNaming _groupNaming = null; /** * Returns the current group naming scheme in use. * @return The current group naming scheme */ private synchronized GroupNaming getGroupNaming() { return _groupNaming; } /** * Sets the group naming instance to be used. * @param groupNaming The current group naming scheme to be used. */ private void setGroupNaming(final GroupNaming groupNaming) { _groupNaming = groupNaming; } /** * The TypeConversion to use when creating XSTypes from SimpleType. */ private TypeConversion _typeConversion = null; private String _contentMemberName; /** * Constructs an XMLBindingComponent from an XML Schema Component. * * @param config the BuilderConfiguration instance (must not be null). * @param groupNaming The group naming scheme to be used. */ public XMLBindingComponent(final BuilderConfiguration config, final GroupNaming groupNaming) { if (config == null) { String error = "The argument 'config' must not be null."; throw new IllegalArgumentException(error); } _config = config; _typeConversion = new TypeConversion(_config); setGroupNaming(groupNaming); } //-- XMLBindingComponent /** * Returns the Binding Object Model on which this XMLBindingComponent will * query information. * * @return the Extended Binding Object Model that wraps the information * located in a binding file */ public ExtendedBinding getBinding() { return _binding; } //-- getBinding /** * Sets the Binding Object Model on which this XMLBindingComponent will * query information. * * @param binding the Extended Binding Object Model that wraps the * information located in a binding file */ public void setBinding(final ExtendedBinding binding) { _binding = binding; } /** * Sets the <i>window</i> on the given Annotated XML Schema structure. Once * the window is set on a particular XML Schema structure all the * information returned by this class are relative to that XML Schema * structure. * * @param annotated an Annotated XML Schema structure. * @see org.exolab.castor.xml.schema.Annotated */ public void setView(final Annotated annotated) { if (annotated == null) { throw new IllegalArgumentException("The XML Schema annotated structure is null."); } _annotated = annotated; //--reset all the variables _javaClassName = null; _javaMemberName = null; _javaPackage = null; _schema = null; _member = null; _class = null; _interface = null; _type = -1; _prefix = null; _suffix = null; _userSpecifiedMemberName = false; _compBinding = null; //--look up for the particular componentBinding relative to the //-- given annotated structure if (_binding != null) { _compBinding = _binding.getComponentBindingType(annotated); NamingXMLType naming = _binding.getNamingXML(); if (naming != null) { switch (annotated.getStructureType()) { case Structure.COMPLEX_TYPE: if (naming.getComplexTypeName() != null) { _prefix = naming.getComplexTypeName().getPrefix(); _suffix = naming.getComplexTypeName().getSuffix(); } break; case Structure.ELEMENT: if (naming.getElementName() != null) { _prefix = naming.getElementName().getPrefix(); _suffix = naming.getElementName().getSuffix(); } break; case Structure.MODELGROUP: if (naming.getModelGroupName() != null) { _prefix = naming.getModelGroupName().getPrefix(); _suffix = naming.getModelGroupName().getSuffix(); } break; default: break; } } //--naming != null; } //--binding != null if (_compBinding != null) { ComponentBindingTypeChoice choice = _compBinding.getComponentBindingTypeChoice(); if (choice.getInterface() != null) { _type = INTERFACE; _interface = choice.getInterface(); } else if (choice.getJavaClass() != null) { _type = CLASS; _class = choice.getJavaClass(); } else if (choice.getMember() != null) { _type = MEMBER; _member = choice.getMember(); } else if (choice.getEnumDef() != null) { _type = ENUM_TYPE; _enum = choice.getEnumDef(); } else if (choice.getContentMember() != null) { _type = CONTENT_MEMBER_TYPE; _contentMemberName = choice.getContentMember().getName(); } else { String err = "Illegal Binding component:"; err += "it does not define a class, an interface or a member binding."; throw new IllegalStateException(err); } } } //--setView //--Object manipulation methods /** * Returns true if the given Object is equal to this instance of * XMLBindingComponent. * * @return true if the given Object is equal to this instance of * XMLBindingComponent. * @param object {@inheritDoc} * @see java.lang.Object#equals(java.lang.Object) */ public boolean equals(final Object object) { if (object == null) { return false; } boolean result = false; if (object instanceof XMLBindingComponent) { XMLBindingComponent temp = (XMLBindingComponent) object; result = _annotated.equals(temp.getAnnotated()); if (_compBinding != null) { if (temp.getComponentBinding() != null) { result = result && (_compBinding.equals(temp.getComponentBinding())); } else { result = false; } } else if (temp.getComponentBinding() != null) { result = false; } } else { result = false; } return result; } /** * Returns the hashCode value for this object. * * @return the hashcode value for this object. * @see java.lang.Object#hashCode() */ public int hashCode() { if (_hashCode == -1) { int compBindingHash = 0; if (_compBinding != null) { compBindingHash = _compBinding.getName().hashCode(); } //WARNING: THE CASTOR SOM doesn't override hashCode or equals _hashCode = 37 * (_annotated.hashCode()) + compBindingHash; } return _hashCode; } /** * Returns the ComponentBinding used in that XMLBindingComponent * to retrieve customized information. * * @return the ComponentBinding used in that XMLBinding. */ protected ComponentBindingType getComponentBinding() { return _compBinding; } //--XML Schema information methods /** * Returns the XML Schema annotated structure used in this XMLBindingComponent. * * @return the XML Schema annotated structure used in this XMLBindingComponent. */ public Annotated getAnnotated() { return _annotated; } /** * Returns true if the binding of this XMLBindingComponent will require the * generation of 2 java classes. Indeed an a nested Model Group that can * occur more than once is described by the SourceGenerator with a wrapper * class. * * @return true if the binding of this XMLBindingComponent will require the * generation of 2 java classes. */ public boolean createGroupItem() { int maxOccurs = 0; boolean result = false; switch (_annotated.getStructureType()) { case Structure.ELEMENT: XMLType type = ((ElementDecl) _annotated).getType(); if (type.isComplexType()) { maxOccurs = ((ComplexType) type).getMaxOccurs(); if (((maxOccurs > 1) || (maxOccurs < 0)) && (type.getName() == null)) { result = true; } } break; case Structure.COMPLEX_TYPE: maxOccurs = ((ComplexType) _annotated).getMaxOccurs(); if ((maxOccurs > 1) || (maxOccurs < 0)) { result = true; } break; case Structure.MODELGROUP: case Structure.GROUP: Group group = (Group) _annotated; maxOccurs = group.getMaxOccurs(); if ((maxOccurs > 1) || (maxOccurs < 0)) { result = true; } break; case Structure.ATTRIBUTE: default: break; } return result; } /** * Returns the schemaLocation of the parent schema of the wrapped structure. * * @return the schemaLocation of the parent schema of the wrapped structure. */ public String getSchemaLocation() { String location = null; Schema schema = getSchema(); if (schema != null) { location = schema.getSchemaLocation(); } return location; } /** * Returns the targetNamespace of the parent schema of the wrapped structure. * * @return the targetNamespace of the parent schema of the wrapped structure. */ public String getTargetNamespace() { String result = null; Schema schema = null; Form form = null; switch (_annotated.getStructureType()) { case Structure.ATTRIBUTE: AttributeDecl attribute = (AttributeDecl) _annotated; //-- resolve reference if (attribute.isReference()) { attribute = attribute.getReference(); } schema = attribute.getSchema(); //-- top-level (use targetNamespace of schema) if (attribute.getParent() == schema) { break; } //-- check form (qualified or unqualified) form = attribute.getForm(); if (form == null) { form = schema.getAttributeFormDefault(); } if ((form == null) || form.isUnqualified()) { //-- no targetNamespace by default return null; } //-- use targetNamespace of schema break; case Structure.ELEMENT: //--resolve reference? ElementDecl element = (ElementDecl) _annotated; if (element.isReference()) { element = element.getReference(); } schema = element.getSchema(); //-- top-level (use targetNamespace of schema) if (element.getParent() == schema) { break; } //-- check form (qualified or unqualified) form = element.getForm(); if (form == null) { form = schema.getElementFormDefault(); } //-- no targetNamespace by default if ((form == null) || form.isUnqualified()) { return null; } //-- use targetNamespace of schema break; case Structure.COMPLEX_TYPE: ComplexType complexType = (ComplexType) _annotated; schema = complexType.getSchema(); if (complexType.getParent() == schema) { break; } return null; case Structure.SIMPLE_TYPE: SimpleType simpleType = (SimpleType) _annotated; schema = simpleType.getSchema(); if (simpleType.getParent() == schema) { break; } return null; default: break; } if (schema == null) { schema = getSchema(); } if (schema != null) { result = schema.getTargetNamespace(); } return result; } //-- getTargetNamespace /** * Returns the underlying Schema of the wrapped structure. * * @return the parent schema of the wrapped structure. */ public Schema getSchema() { if (_schema != null) { return _schema; } switch (_annotated.getStructureType()) { case Structure.ATTRIBUTE: //--resolve reference? AttributeDecl attribute = (AttributeDecl) _annotated; if (attribute.isReference()) { attribute = attribute.getReference(); } _schema = attribute.getSchema(); attribute = null; break; case Structure.ELEMENT: //--resolve reference? ElementDecl element = (ElementDecl) _annotated; if (element.isReference()) { element = element.getReference(); } _schema = element.getSchema(); element = null; break; case Structure.COMPLEX_TYPE: _schema = ((ComplexType) _annotated).getSchema(); break; case Structure.MODELGROUP: //--resolve reference? ModelGroup group = (ModelGroup) _annotated; if (group.isReference()) { group = group.getReference(); } _schema = group.getSchema(); group = null; break; case Structure.GROUP: Structure parent = ((Group) _annotated).getParent(); short structure = parent.getStructureType(); while (structure == Structure.GROUP) { parent = ((Group) parent).getParent(); structure = parent.getStructureType(); } if (structure == Structure.COMPLEX_TYPE) { _schema = ((ComplexType) parent).getSchema(); } else if (structure == Structure.MODELGROUP) { _schema = ((ModelGroup) parent).getSchema(); } break; case Structure.SIMPLE_TYPE: case Structure.UNION: case Structure.LIST: _schema = ((SimpleType) _annotated).getSchema(); break; default: break; } return _schema; } /** * Returns the XMLType of the underlying structure. The XMLType of an * element being its XML Schema type, the XMLType of a ComplexType being * itself and the XMLType of an attribute being its XML Schema simpleType. * Null is returned for a Model Group. * * @return the XMLType of the underlying structure. */ public XMLType getXMLType() { XMLType result = null; switch (_annotated.getStructureType()) { case Structure.ELEMENT: result = ((ElementDecl) _annotated).getType(); break; case Structure.COMPLEX_TYPE: result = ((ComplexType) _annotated); break; case Structure.SIMPLE_TYPE: result = ((SimpleType) _annotated); break; case Structure.ATTRIBUTE: result = ((AttributeDecl) _annotated).getSimpleType(); break; case Structure.MODELGROUP: default: break; } return result; } /** * Returns the XML name declared in the XML Schema for this XMLBindingComponent. * * @return the XML name declared in the XML Schema for this XMLBindingComponent. */ public String getXMLName() { String result = null; if (_annotated != null) { switch (_annotated.getStructureType()) { case Structure.ELEMENT: result = ((ElementDecl) _annotated).getName(); break; case Structure.COMPLEX_TYPE: result = ((ComplexType) _annotated).getName(); break; case Structure.SIMPLE_TYPE: result = ((SimpleType) _annotated).getName(); break; case Structure.ATTRIBUTE: result = ((AttributeDecl) _annotated).getName(); break; case Structure.MODELGROUP: case Structure.GROUP: result = ((Group) _annotated).getName(); break; default: break; } } return result; } //--Implementation of BindingComponent /** * Returns the value specified in the XML Schema for the XML Schema * component wrapped in this XMLBindingComponent. The value returned is the * <i>default</i> or <i>fixed</i> value for an Element or an Attribute. * * @return the value specified in the XML Schema for the XML Schema * annotated structure wrapped in this XMLBindingComponent. */ public String getValue() { String result = null; switch (_annotated.getStructureType()) { case Structure.ELEMENT: result = ((ElementDecl) _annotated).getDefaultValue(); if (result == null) { result = ((ElementDecl) _annotated).getFixedValue(); } break; case Structure.ATTRIBUTE: result = ((AttributeDecl) _annotated).getDefaultValue(); if (result == null) { result = ((AttributeDecl) _annotated).getFixedValue(); } break; case Structure.COMPLEX_TYPE: case Structure.SIMPLE_TYPE: case Structure.MODELGROUP: default: break; } return result; } /** * Returns a valid Java Class Name corresponding to this XMLBindingComponent. * This name is not qualified, this is only a local Java class name. * * @return a valid Java Class Name corresponding to this XMLBindingComponent. * This name is not qualified, this is only a local Java class name. * @see #getQualifiedName */ public String getJavaClassName() { if (_javaClassName == null) { String result = null; //--is there a class name defined (local name) if (_compBinding != null) { switch (getType()) { case CLASS: result = _class.getName(); break; case INTERFACE: result = _interface.getName(); break; default: break; } } if (result == null || result.length() <= 0) { //--is there a reference? if (_annotated != null && _annotated.getStructureType() == Structure.ELEMENT) { ElementDecl element = (ElementDecl) _annotated; if (element.isReference()) { Annotated temp = _annotated; setView(element.getReference()); result = getJavaClassName(); setView(temp); temp = null; } else if (_config.mappingSchemaType2Java()) { // deal with (global) element declarations in type mode, // where no Java class will be generated per definition; // in this case, the class name to be used should be taken from the // underlying (complex) type XMLType xmlType = element.getType(); if (xmlType != null && xmlType.isComplexType()) { ComplexType complexType = (ComplexType) xmlType; Annotated temp = _annotated; setView(complexType); result = getJavaClassName(); setView(temp); } } element = null; } //--Still null? if (result == null || result.length() <= 0) { //--create the name result = getXMLName(); //--create a java name for an anonymous group if (result == null && _annotated != null && (_annotated.getStructureType() == Structure.GROUP || _annotated.getStructureType() == Structure.MODELGROUP)) { GroupNaming groupNaming = getGroupNaming(); result = groupNaming.createClassName((Group) _annotated, getJavaPackage()); if (result == null) { String err = "Unable to create name for group."; throw new IllegalStateException(err); } } if (_prefix != null) { result = _prefix + result; } if (_suffix != null) { result = result + _suffix; } } } _javaClassName = _config.getJavaNaming().toJavaClassName(result); } // TODO ADD A SWITCH TO DETERMINE WETHER OR NOT TO USE JAVA CONVENTIONS // FOR THE JAVA CLASS NAME (SEE JAXB) return _javaClassName; } /** * Returns a valid Java Member Name corresponding to this XMLBindingComponent. * This name is not qualified, this is only a local Java Member name. * * @return a valid Java Member Name corresponding to this XMLBindingComponent. * This name is not qualified, this is only a local Java member name. * @see #getQualifiedName */ public String getJavaMemberName() { if (_javaMemberName == null) { String result = null; if (_compBinding != null) { switch (getType()) { case CLASS: result = _class.getName(); break; case INTERFACE: result = _interface.getName(); break; case MEMBER: result = _member.getName(); break; default: break; } } if (result == null || result.length() <= 0) { Annotated temp = null; if (_annotated.getStructureType() == Structure.ATTRIBUTE) { AttributeDecl att = (AttributeDecl) _annotated; if (att.isReference()) { temp = _annotated; setView(att.getReference()); result = getJavaMemberName(); setView(temp); } att = null; } else if (_annotated.getStructureType() == Structure.ELEMENT) { ElementDecl element = (ElementDecl) _annotated; if (element.isReference()) { temp = _annotated; setView(element.getReference()); result = getJavaMemberName(); boolean userSpecified = _userSpecifiedMemberName; setView(temp); //-- there might be more than once reference, so we //-- need to do a little counting here. if (!userSpecified) { String refName = element.getReferenceName(); int count = 0; int index = 0; Structure structure = element.getParent(); if (structure instanceof ContentModelGroup) { ContentModelGroup cmg = (ContentModelGroup) structure; Enumeration<Structure> enumeration = cmg.enumerate(); while (enumeration.hasMoreElements()) { Structure tmpStruct = enumeration.nextElement(); if (tmpStruct.getStructureType() == Structure.ELEMENT) { ElementDecl tmpDecl = (ElementDecl) tmpStruct; if (tmpDecl.isReference() && tmpDecl.getReferenceName().equals(refName)) { ++count; if (tmpDecl == element) { index = count; } } } } } if (count > 1) { result = result + index; } } } element = null; } temp = null; //--Still null? if (result == null || result.length() <= 0) { //--create the name result = getXMLName(); //--create a java name for an anonymous group if (result == null && (_annotated.getStructureType() == Structure.GROUP || _annotated.getStructureType() == Structure.MODELGROUP)) { result = getGroupNaming().createClassName( (Group) _annotated, getJavaPackage()); if (result == null) { String err = "Unable to create name for group."; throw new IllegalStateException(err); } } if (_prefix != null) { result = _prefix + result; } if (_suffix != null) { result = result + _suffix; } } } else { _userSpecifiedMemberName = true; } _javaMemberName = _config.getJavaNaming().toJavaMemberName(result); } // TODO ADD A SWITCH TO DETERMINE WETHER OR NOT TO USE JAVA CONVENTIONS // FOR THE JAVA CLASS NAME (SEE JAXB) return _javaMemberName; } /** * Returns the fully qualified name used for generating a java name that * represents this XMLBindingComponent. * <p> * The fully qualified name is computed according the following priority * order: * <ul> * <li>If the XMLBinding wraps a class binding then the package name is the * name defined locally in the {@literal <java-class>} element. More * precisely the package name will be the value of the attribute package.</li> * <li>Else the package name will be computed from the schemaLocation of * the parent schema.</li> * <li>Else the package name will be computed from the target namespace of * the parent schema.</li> * </ul> * * Note: the computation of the namespace is a direct look-up for a defined * mapping (Namespace, package) or (schema location, package). * * @return the fully qualified name used for generating a java name that * represents this XMLBindingComponent. */ public String getQualifiedName() { String result = getJavaClassName(); String packageName = getJavaPackage(); if (packageName != null && packageName.length() > 0) { packageName += '.'; result = packageName + result; } return result; } /** * Returns the java package associated with this XML BindingComponent. The * algorithm used to resolve the package is defined according to the * following priorities: * <ol> * <li>The package defined locally in the class declaration inside the * binding file is used.</li> * <li>If no package has been defined locally then a lookup to a defined * mapping {targetNamespace, package name} is performed.</li> * <li>If no package has been defined locally then a lookup to a defined * mapping {schema location, package name} is performed.</li> * </ol> * * @return the java package associated with this XML BindingComponent. */ public String getJavaPackage() { if (_javaPackage == null) { String packageName = null; String schemaLocation = getSchemaLocation(); String targetNamespace = getTargetNamespace(); //-- adjust targetNamespace null -> "" if (targetNamespace == null) { targetNamespace = ""; } if (_compBinding != null) { switch (getType()) { case CLASS: packageName = _class.getPackage(); break; default: break; } //--switch } if (isPackageNameNotSet(packageName)) { if (isPackageNameNotSet(packageName)) { // look for a namespace mapping packageName = _config.lookupPackageByNamespace(targetNamespace); } if (schemaLocation != null && isPackageNameNotSet(packageName)) { // look for schema location mapping packageName = _config.lookupPackageByLocation(schemaLocation); } } _javaPackage = packageName; } return _javaPackage; } /** * Indicates whether a package name has already been set. * @param packageName The package name to analyse. * @return True if the package name has been set correctly. */ private boolean isPackageNameNotSet(final String packageName) { return (packageName == null || packageName.length() == 0); } /** * Returns the upper bound of the collection that is generated from this * BindingComponent. The upper bound is a positive integer. -1 is returned * to indicate that the upper bound is unbounded. * <p> * In the case of an XML Schema component, the upper bound corresponds to * the XML Schema maxOccurs attribute, if any. * * @return an int representing the lower bound of the collection generated * from this BindingComponent. -1 is returned to indicate that the * upper bound is unbounded. 1 is the default value. */ public int getUpperBound() { switch (_annotated.getStructureType()) { case Structure.ELEMENT: return ((ElementDecl) _annotated).getMaxOccurs(); case Structure.COMPLEX_TYPE: return ((ComplexType) _annotated).getMaxOccurs(); case Structure.GROUP: case Structure.MODELGROUP: return ((Group) _annotated).getMaxOccurs(); case Structure.ATTRIBUTE: default: break; } return 1; } /** * Returns the lower bound of the collection that is generated from this * BindingComponent. The lower bound is a positive integer. In the case of * an XML Schema component, it corresponds to the XML Schema minOccurs * attribute, if any. * * @return an int representing the lower bound of the collection generated * from this BindingComponent. 0 is returned by default. */ public int getLowerBound() { return getLowerBound(_annotated); } ////////METHODS RELATED TO A CLASS BINDING /** * Returns the name of a super class for the current XMLBinding. Null is * returned if this XMLBinding is not meant to be mapped to a java class. * * @return the name of a super class for the current XMLBinding. Null is * returned if this XMLBinding is not meant to be mapped to a java * class */ public String getExtends() { if (getType() == CLASS) { return _class.getExtends(); } return _config.getProperty(BuilderConfiguration.Property.SUPER_CLASS, null); } //-- getExtends /** * Returns an array of the different interface names implemented by the * class that will represent the current XMLBindingComponent. Null is * returned if no class binding is defined for the wrapped XML Schema * structure. * * @return array of interface names */ public String[] getImplements() { if (getType() == CLASS) { return _class.getImplements(); } return null; } /** * Returns true if bound properties must be generated for the class that * will represent the current XMLBindingComponent. * * @return true if bound properties must be generated for the class the * class that will represent the current XMLBindingComponent. */ public boolean hasBoundProperties() { if (getType() == CLASS && _class.hasBound()) { return _class.getBound(); } return _config.boundPropertiesEnabled(); } /** * Returns true if equal method must be generated for the class that will * represent the current XMLBindingComponent. * * @return true if equal method must be generated for the class the class * that will represent the current XMLBindingComponent. */ public boolean hasEquals() { if (getType() == CLASS && _class.hasEquals()) { return _class.getEquals(); } return _config.equalsMethod(); } /** * Returns true if the class that will represent the current * XMLBindingComponent must be abstract. * * @return true if the class that will represent the current * XMLBindingComponent must be abstract. */ public boolean isAbstract() { boolean result = false; if (getType() == CLASS && _class.hasAbstract()) { result = _class.getAbstract(); } if (!result) { switch(_annotated.getStructureType()) { case Structure.COMPLEX_TYPE: ComplexType cType = (ComplexType) _annotated; result = cType.isAbstract(); //-- if we're in element-centric mode, then all //-- complexTypes are treated as abstract result = result || _config.mappingSchemaElement2Java(); break; case Structure.ELEMENT: ElementDecl eDecl = (ElementDecl) _annotated; result = eDecl.isAbstract(); break; default: break; } } return result; } /** * Returns true if the class that will represent the current XMLBindingComponent * must be final. * * @return true if the class that will represent the current XMLBindingComponent * must be final. */ public boolean isFinal() { if (getType() == CLASS) { return _class.getFinal(); } return false; } /** * Returns true if the wrapped XML Schema component is fixed (i.e the value * used is fixed). * * @return true if the wrapped XML Schema component is fixed (i.e the value * used is fixed). */ public boolean isFixed() { switch (_annotated.getStructureType()) { case Structure.ELEMENT: String fixed = ((ElementDecl) _annotated).getFixedValue(); return (fixed != null); case Structure.ATTRIBUTE: return ((AttributeDecl) _annotated).isFixed(); case Structure.GROUP: case Structure.COMPLEX_TYPE: case Structure.SIMPLE_TYPE: case Structure.MODELGROUP: default: break; } return false; } /** * Returns true if the wrapped XML Schema component is nillable. * * @return true if the wrapped XML Schema component is nillable. */ public boolean isNillable() { switch (_annotated.getStructureType()) { case Structure.ELEMENT: return ((ElementDecl) _annotated).isNillable(); default: break; } return false; } //-- isNillable ////////METHODS RELATED TO A MEMBER BINDING /** * Returns true if the member represented by that XMLBindingComponent is to * be represented by an Object wrapper. For instance an int will be * represented by a java Integer if the property is set to true. * * @return true if the member represented by that XMLBindingComponent is to * be represented by an Object wrapper. */ public boolean useWrapper() { if (_type != BindingComponent.MEMBER) { return _config.usePrimitiveWrapper(); } if (_member.hasWrapper()) { return _member.getWrapper(); } return false; } /** * Returns the XSType that corresponds to the Java type chosen to represent * the XML Schema component represented by this XMLBindingComponent. An * XSType is an abstraction of a Java type used in the Source Generator. It * wraps a JType as well as the necessary methods to convert to/from String. * <p> * If a name of java type is specified then this name will have higher * priority than the simpleType resolution. * * @return an XSType */ public XSType getJavaType() { //--no need for caching it is called only once XSType result = null; boolean useWrapper = useWrapper(); XMLType type = getXMLType(); if (type != null && type.isComplexType()) { if (_type == MEMBER && _member.getJavaType() != null) { String javaType = _member.getJavaType(); if (javaType != null && javaType.length() > 0) { result = TypeConversion.convertType(javaType); } } else { result = new XSClass(new JClass(getJavaClassName())); } } else { if (_type == MEMBER) { String javaType = _member.getJavaType(); if (javaType != null && javaType.length() > 0) { result = TypeConversion.convertType(javaType); } } } if (result == null) { //--simpleType or AnyType if (type != null && type.isSimpleType()) { String packageName = null; String className = null; if (((SimpleType) type).getSchema() != getSchema()) { XMLBindingComponent comp = new XMLBindingComponent(_config, getGroupNaming()); comp.setBinding(_binding); comp.setView(type); packageName = comp.getJavaPackage(); if (comp.getClass() != null) { className = comp.getJavaClassName(); } } else { packageName = getJavaPackage(); if (_class != null) { className = getJavaClassName(); } } if ((packageName == null) || (packageName.length() == 0)) { String ns = ((SimpleType) type).getSchema().getTargetNamespace(); packageName = _config.lookupPackageByNamespace(ns); } result = _typeConversion.convertType((SimpleType) type, packageName, useWrapper, _config.useJava50(), className); } } return result; } /** * Returns the collection name specified in the binding file. If no * collection was specified, null will be returned and the default * collection settings will be used. * * @return a string that represents the collection name specified in the * binding file. If no collection was specified, null will be * returned and the default collection settings will be used. */ public String getCollectionType() { String result = null; if ((_type == MEMBER) && (_member.getCollection() != null)) { result = _member.getCollection().toString(); } return result; } /** * Returns the fully qualified name of the Validator to use. * * @return the fully qualified name of the Validator to use. */ public String getValidator() { if (_type == MEMBER) { return _member.getValidator(); } return null; } /** * Returns the fully qualified name of the XMLFieldHandler to use. * * @return the fully qualified name of the XMLFieldHandler to use. */ public String getXMLFieldHandler() { if (_type == MEMBER) { return _member.getHandler(); } return null; } /** * Returns the visibility of the Java member to generate. * * @return the visibility of the Java member to generate. */ public String getVisiblity() { if (_type == MEMBER) { final FieldTypeVisibilityType visibility = _member.getVisibility(); if (visibility != null) { return visibility.toString(); } return "private"; } return null; } /** * Returns the type of this component binding. A component binding can be of * three different types: * <ul> * <li>Interface: it represents the binding to a java interface.</li> * <li>Class: it represents the binding to a java class.</li> * <li>Member: it represents the binding to a java class member.</li> * </ul> * <p> * -1 is returned if the component binding is null. * * @return the type of this component binding. */ public short getType() { return _type; } /** * Returns the lower bound of the collection that is generated from this * BindingComponent. The lower bound is a positive integer. In the case of * an XML Schema component, it corresponds to the XML Schema minOccurs * attribute, if any. * * @param annotated an Annotated XML Schema structure. * @return an int representing the lower bound of the collection generated * from this BindingComponent. 0 is returned by default. */ private static int getLowerBound(final Annotated annotated) { switch (annotated.getStructureType()) { case Structure.ELEMENT: return ((ElementDecl) annotated).getMinOccurs(); case Structure.COMPLEX_TYPE: return ((ComplexType) annotated).getMinOccurs(); case Structure.MODELGROUP: case Structure.GROUP: Group group = (Group) annotated; //-- if the group is top-level, then we always return 0 Structure parent = group.getParent(); if (parent != null && parent.getStructureType() == Structure.SCHEMA) { return 0; } int minOccurs = group.getMinOccurs(); //-- if minOccurs == 1, then check to see if all elements inside group are //-- optional, if so, we return 0, not 1. if (minOccurs == 1) { Enumeration<Annotated> enumeration = group.enumerate(); while (enumeration.hasMoreElements()) { if (getLowerBound(enumeration.nextElement()) != 0) { return 1; } } //-- if we make it here, all items in group have a lowerbound of 0, so //-- the group can be considered optional return 0; } return minOccurs; case Structure.ATTRIBUTE: if (((AttributeDecl) annotated).isRequired()) { return 1; } break; default: break; } return 0; } //-- getLowerBound /** * Returns the EnumBindingType instance for the active binding component. * @return The EnumBindingType instance */ public EnumBindingType getEnumBinding() { return _enum; } /** * Returns the name 'override' of a content member as specified in a binding file. * @return the name of the name 'override' for the content member. */ public String getContentMemberName() { return _contentMemberName; } } //-- class: XMLBindingComponent