/** * 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-2000 (C) Intalio, Inc. All Rights Reserved. * * $Id$ */ package org.exolab.castor.xml.schema; import java.util.Enumeration; import org.exolab.castor.xml.ValidationException; /** * An XML Schema SimpleType. * * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a> * @version $Revision$ $Date: 2006-04-13 06:47:36 -0600 (Thu, 13 Apr * 2006) $ **/ public abstract class SimpleType extends XMLType implements Referable { /** * The value of the final attribute used for blocking all types of * derivation. **/ public static final String FINAL_ALL = "#all"; /** * The value of the final attribute used for blocking list derivation. **/ public static final String FINAL_LIST = "list"; /** * The value of the final attribute used for blocking union derivation. **/ public static final String FINAL_UNION = "union"; /** * The value of the final attribute used for blocking restriction * derivation. **/ public static final String FINAL_RESTRICTION = "restriction"; /** * The constraining facets of this type. **/ private FacetList _facets = null; /** * The value of the final attribute (optional). **/ private String _final = null; /** * The parent structure of this {@link SimpleType}. (Schema, AttributeDecl * or ElementDecl) **/ private Structure _parent = null; /** * The code for this simple type. (As defined by SimpleTypesFactory) **/ private int _typeCode = SimpleTypesFactory.INVALID_TYPE; /** * An attribute that indicates if this {@link SimpleType} is a redefinition. */ private boolean _redefinition = false; /** * Default constructor. */ public SimpleType() { super(); this._facets = new FacetList(); } /** * Adds the given Facet to this Simpletype. * * @param facet * the Facet to add to this Simpletype **/ public void addFacet(final Facet facet) { if (facet == null) { return; } String name = facet.getName(); if (name == null) { return; } _facets.add(facet); } /** * Returns the first facet associated with the given name. * * @param name * the name of the Facet to look for * @return the first facet associated with the given name **/ public Facet getFacet(final String name) { Enumeration<Facet> facets = getFacets(name); if (facets == null) { return null; } return facets.nextElement(); } /** * Returns the facets associated with the given name. * * @param name * the name of the Facet to look for * @return the facets associated with the given name **/ public Enumeration<Facet> getFacets(final String name) { FacetListEnumerator fle = null; SimpleType datatype = (SimpleType) getBaseType(); if (datatype != null) { fle = (FacetListEnumerator) datatype.getFacets(name); } fle = new FacetListEnumerator(_facets, fle); fle.setMask(name); return fle; } // -- getFacets /** * Returns an Enumeration of all the Facets (including inherited) facets for * this type. * * @return an Enumeration of all the Facets for this type **/ public Enumeration<Facet> getFacets() { FacetListEnumerator fle = null; SimpleType datatype = (SimpleType) getBaseType(); if (datatype != null) { fle = (FacetListEnumerator) datatype.getFacets(); } fle = new FacetListEnumerator(_facets, fle); return fle; } /** * Returns the value of the 'final' property, indicating which types of * derivation are not allowed, or null if the final property has not been * set. * * @return the value of the final property or null if no value has been set **/ public String getFinal() { return _final; } /** * Returns the facets of this type (without the parent's facets). * * @return the local facets of this type. */ public Enumeration<Facet> getLocalFacets() { if (_facets == null) { return null; } return _facets.enumerate(); } /** * Returns an enumeration of the effective facets for this type. A set of * effective facets contains all local facets and only those inherited * facets that are not overridden by the local facets. * * @return an enumeration of the effective facets for this type. * * @see #getLocalFacets() * @see #getFacets() */ public Enumeration<Facet> getEffectiveFacets() { final Enumeration<Facet> localFacets = getLocalFacets(); final SimpleType baseType = (SimpleType) getBaseType(); if (baseType == null) { // There's no base type ==> return local facets return localFacets; } final Enumeration<Facet> effectiveBaseFacets = baseType .getEffectiveFacets(); if (localFacets == null) { // There's a base type, but no local facets ==> return // effective facets of the base type return effectiveBaseFacets; } // There are both local and inherited facets ==> merge them final FacetList filteredBaseFacets = new FacetList(); OUTER: while (effectiveBaseFacets.hasMoreElements()) { final Facet baseFacet = effectiveBaseFacets.nextElement(); // Check whether one of the local facets // overrides the inherited facet for (int i = 0; i < _facets.size(); i++) { final Facet localFacet = _facets.get(i); if (localFacet.overridesBase(baseFacet)) { continue OUTER; } } // Base facet is not overridden ==> keep it in the list filteredBaseFacets.add(baseFacet); } return new FacetListEnumerator(_facets, (FacetListEnumerator) filteredBaseFacets.enumerate()); } /** * Returns the built in type this type is derived from. */ public SimpleType getBuiltInBaseType() { SimpleType base = this; while ((base != null) && (!SimpleTypesFactory.isBuiltInType(base.getTypeCode()))) { base = (SimpleType) base.getBaseType(); } return base; } /** * Returns the parent Structure that contains this SimpleType. This can be * either a Schema, AttributeDecl or ElementDecl. * * @return the parent of this SimpleType **/ public Structure getParent() { return _parent; } // -- getParent /** * Returns the Id used to Refer to this Object. * * @return the Id used to Refer to this Object * @see org.exolab.castor.xml.schema.Referable **/ public String getReferenceId() { return "datatype:" + getName(); } // -- getReferenceId /** * Returns true if this {@link SimpleType} has a specified {@link Facet} * with the given name. * * @param name * the name of the {@link Facet} to look for * @return true if this {@link SimpleType} has a specified {@link Facet} * with the given name **/ public boolean hasFacet(final String name) { if (name == null) { return false; } for (int i = 0; i < _facets.size(); i++) { Facet facet = _facets.get(i); if (name.equals(facet.getName())) { return true; } } return false; } /** * Returns true if this SimpleType is a built in type. * * @return true if this SimpleType is a built in type **/ public boolean isBuiltInType() { return SimpleTypesFactory.isBuiltInType(_typeCode); } /** * Indicates whether this {@link SimpleType} is a numeric type. * * @return True if this SimpleType is a numeric type **/ public boolean isNumericType() { if (!isBuiltInType()) { return ((SimpleType) getBaseType()).isNumericType(); } return false; } /** * Indicates whether this {@link SimpleType} is a date/time type. * * @return True if this SimpleType is a date/time type **/ public boolean isDateTimeType() { return SimpleTypesFactory.isDateTimeType(_typeCode); } /** * Returns true if this simpleType is a redefinition. * * @return true if this simpleType is a redefinition. */ public boolean isRedefined() { return _redefinition; } /** * Sets this Group has redefined. */ public void setRedefined() { _redefinition = true; } /** * Gets the code for this simple type. (as defined in SimpleTypesFactory) * * @return the type code for this simple type **/ public int getTypeCode() { return _typeCode; } /** * Package private setter of the code for this simple type. **/ void setTypeCode(final int code) { _typeCode = code; } // /////////////////////////////////////////////////////// // Helpers to get the min/max/length facets // (so that they are shared between listType // and binary, uriref, string // /** * Returns the value of the length facet result can be null **/ public Long getLength() { Facet lengthFacet = getFacet(Facet.LENGTH); if (lengthFacet == null) return null; try { return new Long(lengthFacet.toLong()); } catch (java.lang.Exception e) { return null; } } /** * Returns the value of the minlength facet result can be null **/ public Long getMinLength() { Facet minLengthFacet = getFacet(Facet.MIN_LENGTH); if (minLengthFacet == null) return null; try { return new Long(minLengthFacet.toLong()); } catch (java.lang.Exception e) { return null; } } /** * Returns the value of the maxlength facet result can be null **/ public Long getMaxLength() { Facet maxLengthFacet = getFacet(Facet.MAX_LENGTH); if (maxLengthFacet == null) return null; try { return new Long(maxLengthFacet.toLong()); } catch (java.lang.Exception e) { return null; } } // -- getMaxLength /** * Removes the given Facet from this SimpleType. Returns true if this * SimpleType actually contains the given facet. * * <p> * Removes only local facets. * </p> * * @param facet * the Facet to remove * @return true if the specified Facet has been removed */ public boolean removeFacet(Facet facet) { if (facet == null) return false; return _facets.remove(facet); } // -- removeFacet /** * Removes the facet with the given name from this SimpleType. Returns true * if this Simpletype has a facet with the given name and it is successfully * removed. * * <p> * Removes only local facets. * </p> * * @param name * the name of the Facet to remove * @return true if the specified Facet has been removed */ public boolean removeFacet(String name) { if (name == null) return false; for (int i = _facets.size() - 1; i > 0; i--) { Facet facet = _facets.get(i); if (name.equals(facet.getName())) { _facets.remove(i); return true; } } return false; } // -- removeFacet /** * Sets the value of the 'final' property, indicating which types of * derivation are not allowed. A null value will indicate all types of * derivation (list, restriction, union) are allowed. * * @param finalValue * the value of the final property. * @exception IllegalArgumentException * when the value is not a valid value. **/ public void setFinal(String finalValue) { if ((finalValue == null) || finalValue.equals(FINAL_ALL) || finalValue.equals(FINAL_UNION) || finalValue.equals(FINAL_LIST) || finalValue.equals(FINAL_RESTRICTION)) { _final = finalValue; } else { String err = "The value '" + finalValue + "' is not a valid" + "value of the final property."; throw new IllegalArgumentException(err); } } // -- setFinal // -------------------------------/ // - Implementation of Structure -/ // -------------------------------/ /** * Returns the type of this Schema Structure * * @return the type of this Schema Structure **/ public short getStructureType() { return Structure.SIMPLE_TYPE; } // -- getStructureType /** * Checks the validity of this SimpleType definition. * * @throws ValidationException * when this SimpleType definition is invalid. **/ public void validate() throws ValidationException { final Enumeration<Facet> localFacets = getLocalFacets(); final SimpleType datatype = (SimpleType) getBaseType(); if (localFacets != null) { while (localFacets.hasMoreElements()) { final Facet facet = localFacets.nextElement(); Enumeration<Facet> baseFacets = null; if (datatype != null) { baseFacets = datatype.getFacets(); } try { facet.checkConstraints(getLocalFacets(), baseFacets); } catch (SchemaException e) { throw new ValidationException( "Facet validation failed for type '" + getName() + "'", e); } } } // -- TODO: NOT YET FULLY IMPLEMENTED } // -- protected Methods -/ /** * A helper method for classes which extend SimpleType. This method allows * creating a reference to a SimpleType. * * @return the reference to the SimpleType. **/ protected SimpleType createReference(String name) { return new SimpleTypeReference(getSchema(), name); } // -- createReference /** * A helper method for classes which extend SimpleType. This method allows * resolving a SimpleType reference to a SimpleType. * * @return the resolved SimpleType. * @see #createReference **/ protected static SimpleType resolveReference(SimpleType simpleType) { return (SimpleType) simpleType.getType(); } // -- createReference /** * Sets the parent for this SimpleType * * @param parent * the Structure that contains this SimpleType. Currently this * should only be Schema, ElementDecl or AttributeDecl. **/ protected void setParent(Structure parent) { this._parent = parent; } // -- setParent /** * Copy this type's facets to the target type. * * @param target * the SimpleType to copy facets to */ protected void copyFacets(SimpleType target) { target._facets.add(_facets); } // -- copyFacets /** * Returns the number of facets named 'name' within the list of facets of * this simple type. * * @param name * Name (type) of the facet. * @return number of facets named 'name' */ public int getNumberOfFacets(final String name) { int counter = 0; for (Enumeration<Facet> enumerator = getFacets(); enumerator .hasMoreElements();) { Facet facet = enumerator.nextElement(); if (facet.getName().equals(name)) { counter++; } } return counter; } } // -- SimpleType