/** * 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 1999-2003 (C) Intalio, Inc. All Rights Reserved. * * $Id$ */ package org.exolab.castor.xml.schema; import org.exolab.castor.xml.ValidationException; /** * An XML Schema Attribute Definition * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a> * @version $Revision$ $Date: 2006-04-14 04:14:43 -0600 (Fri, 14 Apr 2006) $ **/ public final class AttributeDecl extends Annotated { /** SerialVersionUID */ private static final long serialVersionUID = -8720345516857919305L; /** * The use attribute value for optional **/ public static final String USE_OPTIONAL = "optional"; /** * The use attribute value for prohibited **/ public static final String USE_PROHIBITED = "prohibited"; /** * The use attribute value for required **/ public static final String USE_REQUIRED = "required"; private static final short OPTIONAL = 3; private static final short PROHIBITED = 4; private static final short REQUIRED = 5; /** * Error message for a null argument **/ private static String NULL_ARGUMENT = "A null argument was passed to the constructor of " + AttributeDecl.class.getName(); /** * The default namespace form for this AttributeDecl (optional). **/ private Form _form = null; /** * The id for this AttributeDecl **/ private String _id = null; /** * The name of attributes defined by this AttributeDecl **/ private String _name = null; /** * The parent for this AttributeDecl **/ private Structure _parent = null; /** * The Schema to which this AttributeDecl belongs **/ private Schema _schema = null; /** * The simple type for this AttributeDecl. **/ private SimpleType _simpleType = null; /** * The current value of the 'use' property. The value * is OPTIONAL by default. **/ private short _useFlag = OPTIONAL; /** * The fixed value for attribute instances of this * attribute declaration. **/ private String _fixed = null; /** * The default value for attribute instances of this attribute declaration. */ private String _default = null; /** * A reference to a top-level attribute */ private String _attributeRef = null; /** * Creates a new AttrDecl with the given name * @param name of the Attribute defined by this attribute declaration * @param schema the schema that contains the new attrDecl **/ public AttributeDecl(Schema schema, String name) { if (schema == null) { String err = NULL_ARGUMENT + "; 'schema' must not be null."; throw new IllegalArgumentException(err); } _schema = schema; setName(name); } //-- AttributeDecl /** * Creates a new AttrDecl in the given schema. * @param schema the schema that contains the new attrDecl **/ public AttributeDecl(Schema schema) { if (schema == null) { String err = NULL_ARGUMENT + "; 'schema' must not be null."; throw new IllegalArgumentException(err); } _schema = schema; } //-- AttributeDecl /** * Returns the Form for this attribute declaration. The Form object species * whether or not names are qualified or unqualified for instances of * this attribute declaration. If null, the Form should be obtained from the * parent Schema. * * @return the Form for this attribute declaration, or null if not set. **/ public Form getForm() { return _form; } //-- getForm /** * Returns the Id for this attribute declaration * * @return the Id for this attribute declaration **/ public String getId() { return _id; } //-- getId /** * Returns the name of attributes defined by this AttributeDecl. * If this AttributeDecl is a reference to another AttributeDecl, * the reference will be resolved and the name of the referenced * AttributeDecl will be returned. The name will always be * an NCName, no namespace prefix will be included. * * @return the name of attributes defined by this AttributeDecl. **/ public String getName() { return getName(false); } //-- getName /** * Returns the name of this Attribute declaration. The name will * always be an NCName, no namespace prefix will be included. * * @param ignoreRef a boolean that when false, indicates * that if this is an attribute reference to return the * reference name. Otherwise the only the local name is used. * * @return the name of this attribute declaration **/ public String getName(boolean ignoreRef) { if (isReference() && ignoreRef == false) { //-- strip prefix we can only return //-- an NCName from this method String ncname = _attributeRef; //-- check for namespace prefix int idx = ncname.indexOf(':'); if (idx > 0) { ncname = ncname.substring(idx+1); } return ncname; } return _name; } //-- getName /** * Returns the parent of this AttributeDecl, this value may be null if * no parent has been set. * * @return the parent Structure of this AttributeDecl. **/ public Structure getParent() { return _parent; } //-- getParent /** * Returns the data type associated with this AttributeDecl. * * @return the data type associated with this AttributeDecl. **/ public SimpleType getSimpleType() { SimpleType result = null; if (isReference()) { AttributeDecl attribute = getReference(); if (attribute != null) result = attribute.getSimpleType(); else return null; } if (_simpleType == null) return null; result = (SimpleType)_simpleType.getType(); if (result != null) { Schema tempSchema = result.getSchema().getMasterSchema(); if (tempSchema != null) { SimpleType tempType = tempSchema.getSimpleType(result.getName()); if (tempType != null) { result = tempType; } } } return result; } //-- getSimpleType /** * Returns the AttributeDecl that this attribute definition references. * This will return null if this attribute definition does not reference * a different attribute definition. * @return the AttributeDecl that this attribute definition references **/ public AttributeDecl getReference() { AttributeDecl result = null; if (_attributeRef != null) { result = _schema.getAttribute(_attributeRef); if (result == null) { String err = "Unable to find attribute referenced :\" "; err += _attributeRef; err +="\""; throw new IllegalStateException(err); } } return result; } //-- getReference /** * Returns the actual reference name of this AttributeDecl, or null * if this AttributeDecl is not a reference. The name returned, if not * null, will be a QName, possibly containing the namespace prefix. * * @return the reference name */ public String getReferenceName() { return _attributeRef; } //-- getReference /** * Returns the Schema that this AttributeGroupDecl belongs to. * * @return the Schema that this AttributeGroupDecl belongs to. **/ public Schema getSchema() { return _schema; } //-- getSchema /** * Returns the value of the use attribute for this attribute * declaration or attribute reference. If this is a reference * the value of the use attribute will *not* be obtained * from the referenced attribute declaration as top-level * attributes do not take into account the use attribute. * * @return the value of the use attribute for this attribute * declaration */ public String getUse() { //-- Note: Do not resolve reference, since top-level //-- atts do not specify the "use" attribute. switch (_useFlag) { case PROHIBITED: return USE_PROHIBITED; case REQUIRED: return USE_REQUIRED; default: return USE_OPTIONAL; } } //-- getUse /** * Returns the default value of this element definition. * * @return the default value of this element definition, * or null if no default was specified. **/ public String getDefaultValue() { return _default; } //-- getDefaultValue /** * Returns the fixed value of this element definition. * * @return the fixed value of this element definition, * or null if no default was specified. */ public String getFixedValue() { return _fixed; } //-- getFixedValue /** * Returns true if the "default" flag is set. * * @return true if the "default" flag is set. */ public boolean isDefault() { return (_default != null) && (_default.length() > 0); } //-- isFixed /** * Returns true if the use attribute is equal to "optional". * * @return true if the use attribute is equal to "optional". **/ public boolean isFixed() { return (_fixed != null) && (_fixed.length() >0); } //-- isFixed /** * Returns true if the use attribute is equal to "optional". * * @return true if the use attribute is equal to "optional". **/ public boolean isOptional() { String use = getUse(); return use.equals(USE_OPTIONAL); } //-- isOptional /** * Returns true if the use attribute is equal to "prohibited". * * @return true if the use attribute is equal to "prohibited". **/ public boolean isProhibited() { String use = getUse(); return use.equals(USE_PROHIBITED); } //-- isProhibited /** * Returns true if the 'use' attribute is equal to REQUIRED and * there is no specified value. If a value is specifed and the * 'use' attribute is "required" then required is will return * false, because the attribute value automatically becomes * fixed. * * @return true if the use attribute is equal to "required" and * no default value has been specified, otherwise false **/ public boolean isRequired() { String use = getUse(); return (use.equals(USE_REQUIRED)); } //-- getRequired /** * Returns true if this attribute definition simply references another * attribute Definition * @return true if this attribute definition is a reference */ public boolean isReference() { return (_attributeRef != null); } //-- isReference /** * Sets the Form for this attribute declaration. The Form object species * whether or not names are qualified or unqualified for instances of * this attribute declaration. If null, the Form is to be obtained from * the parent Schema. * * @param form the Form type for this attribute declaration. **/ public void setForm(Form form) { _form = form; } //-- setForm /** * Sets the Id for this attribute declaration * * @param id the Id for this attribute declaration **/ public void setId(String id) { _id = id; } //-- setId /** * Sets the name of attributes defined by this attribute definition * @param name the name of the this AttributeDecl. Must be a valid NCName. * @exception IllegalArgumentException when the name is not valid **/ public void setName(String name) { if (name == null) { String err = "AttributeDecl#setName: 'name' must not be null."; throw new IllegalArgumentException(err); } //-- handle namespace if necessary int idx = name.indexOf(':'); if (idx >= 0) { //-- we should resolve nsPrefix...just ignore for now //-- use local name name = name.substring(idx + 1); } if (name.length() == 0) { String err = "AttributeDecl#setName: 'name' must not be "+ "zero-length."; throw new IllegalArgumentException(err); } _name = name; } //-- setName /** * Sets the parent for this AttributeDecl * * @param parent the parent Structure for this AttributeDecl **/ protected void setParent(Structure parent) { if (parent != null) { switch (parent.getStructureType()) { case Structure.ATTRIBUTE_GROUP: case Structure.COMPLEX_TYPE: case Structure.SCHEMA: break; default: String error = "Invalid parent for group"; throw new IllegalArgumentException(error); } } _parent = parent; } //-- setParent /** * Sets the reference for this attribute definition * @param reference the Attribute definition that this definition references **/ public void setReference(AttributeDecl reference) { if (reference == null) this._attributeRef = null; else this._attributeRef = reference.getName(); } //-- setReference /** * Sets the reference for this attribute definition * @param reference the name of the attribute definition that this * definition references **/ public void setReference(String reference) { this._attributeRef = reference; } //-- setReference /** * Sets the SimpleType for this attribute declaration * @param simpleType the SimpleType for this attribute * declaration **/ public void setSimpleType(SimpleType simpleType) { _simpleType = simpleType; if (simpleType != null) { simpleType.setParent(this); } } //-- setSimpleType /** * Sets the simple type of this attribute to be a reference. * * @param name the name of the simpleType being referenced, must * not be null. **/ public void setSimpleTypeReference(String name) { SimpleTypeReference reference = new SimpleTypeReference(_schema, name); setSimpleType(reference); } //-- setSimpleTypeReference /** * Sets the 'use' attribute of this attribute declaration * Note: this should not be used to set the flag to FIXED or DEFAULT * @param value one of the following: * ("prohibited" | "optional" | "required") * * @see #USE_PROHIBITED * @see #USE_OPTIONAL * @see #USE_REQUIRED **/ public void setUse(String value) { if (value == null) { _useFlag = OPTIONAL; return; } if (value.equals(USE_REQUIRED)) _useFlag = REQUIRED; else if (value.equals(USE_OPTIONAL)) _useFlag = OPTIONAL; else if (value.equals(USE_PROHIBITED)) _useFlag = PROHIBITED; else { throw new IllegalArgumentException("Invalid value for 'use': " + value); } } //-- setUse /** * Sets the DEFAULT value */ public void setDefaultValue(String value) { if ((_fixed != null) && (_fixed.length() > 0)) { throw new IllegalStateException("'default' and 'fixed' must not be both present."); } _default = value; } /** * Sets the FIXED value. */ public void setFixedValue(String value) { if ((_default != null) && (_default.length() > 0)) { throw new IllegalStateException("'default' and 'fixed' must not be both present."); } _fixed = value; } //-------------------------------/ //- Implementation of Structure -/ //-------------------------------/ /** * Returns the type of this Schema Structure * @return the type of this Schema Structure **/ public short getStructureType() { return Structure.ATTRIBUTE; } //-- getStructureType /** * Checks the validity of this Attribute declaration * @exception ValidationException when this Attribute declaration * is invalid **/ public void validate() throws ValidationException { if ((_attributeRef == null) && (_name == null)) { String err = "<attribute> is missing required 'name' attribute."; throw new ValidationException(err); } if (_attributeRef != null) { if (_schema.getAttribute(_attributeRef) == null) { String err = "<attribute ref=\"" + _attributeRef + "\"> "+ "is not resolvable."; throw new ValidationException(err); } return; } } //-- validate /** * Set the parent schema of the current ElementDecl. * The parent schema should at least have the same targetNamespace * of the current schema. * * This method is protected since it is only meant to be used by the internal * API to propagate the parent XML Schema in case of a redefinition for instance. * @param schema */ protected void setSchema(Schema schema) { _schema = schema; } /** * Indicates whether a type is set for this element definiion. * @return True if a type is set. */ public boolean hasXMLType() { return (_simpleType != null); } } //-- AttrDecl