/** * 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 - 2004 (C) Intalio, Inc. All Rights Reserved. * * $Id$ */ package org.exolab.castor.xml.schema; import org.exolab.castor.xml.*; import java.util.Vector; import java.util.Enumeration; /** * An XML Schema ModelGroup : <xsd:group> * * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a> * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $ **/ public class ModelGroup extends Group { /** SerialVersionUID */ private static final long serialVersionUID = -2057934322265672413L; /** * the name of the ModelGroup referenced */ private String _groupRef = null; /** * An ordered list of all ModelGroup definitions **/ private Vector _modelDefs; /** * An attribute that indicates if this Group is * a redefinition */ private boolean _redefinition = false; /** * the schema that contains this model group */ private Schema _schema = null; /** * Creates a new ModelGroup, with no name **/ public ModelGroup() { this(null); } //-- ModelGroup /** * Creates a new ModelGroup definition * @param schema the XML Schema to which this ModelGroup * belongs */ public ModelGroup(Schema schema) { this(null, schema); } /** * Creates a new ModelGroup with the given name * @param name of the ModelGroup **/ public ModelGroup(String name, Schema schema) { super(name); _schema = schema; _modelDefs = new Vector(); } //-- ModelGroup /** * Adds the given ModelGroup to this ModelGroup * @param modelGroup the ModelGroup to add to this ModelGroup **/ public void addModelGroup(ModelGroup modelGroup) { if (!_modelDefs.contains(modelGroup)) { _modelDefs.addElement(modelGroup); } } //-- addModelGroup /** * Returns an enumeration of all the Particles of this * ContentModelGroup * * @return an enumeration of the Particles contained * within this ContentModelGroup **/ public Enumeration enumerate() { return this.getContentModelGroup().enumerate(); } //-- enumerate /** * Returns an ordered Enumeration of all the ContentModelType * definitions (element, group, modelGroupRef)+ **/ public Enumeration getDeclarations() { return _modelDefs.elements(); } //-- getDeclarations /** * Returns the ContentModelGroup for this group * Only used for a <group> element * @return the ContentModelGroup for this group */ public ContentModelGroup getContentModelGroup() { if (_groupRef != null) return getReference().getContentModelGroup(); return super.getContentModelGroup(); } /** * Returns the name of this ModelGroup. * @return the name of this ModelGroup. **/ public String getName() { return getName(false); } //-- getName /** * Returns the name of this Model Group definition * * @param ignoreRef If True the name of the referenced * model group (if specified) is returned * @return the name of this element declaration **/ public String getName(boolean ignoreRef) { if (ignoreRef == false && _groupRef !=null ) { String localName = _groupRef; //-- check for namespace prefix int idx = localName.indexOf(':'); if (idx > 0) { localName = localName.substring(idx+1); } return localName; } return super.getName(); } //-- getName /** * Returns true if this model group definition simply references another * model group Definition * @return true if this model group definition is a reference */ public boolean isReference() { return (_groupRef != null); } //-- isReference /** * Sets this Group has redefined. */ public void setRedefined() { _redefinition = true; } /** * Returns true if this group is a redefinition. * * @return true if this group is a redefinition. */ public boolean isRedefined() { return _redefinition; } /** * Sets the reference for this ModelGroup definition * @param reference the name of the ModelGroup that this * definition references **/ public void setReference(String reference) { this._groupRef = reference; } //-- setReference //-------------------------------/ //- Implementation of Structure -/ //-------------------------------/ /** * Returns the type of this Schema Structure * @return the type of this Schema Structure **/ public short getStructureType() { return Structure.MODELGROUP; } //-- getStructureType /** * Returns the Id used to Refer to this Object * @return the Id used to Refer to this Object * @see Referable **/ public String getReferenceId() { if (this.getName() != null) return "group:"+this.getName(); return null; } //-- getReferenceId /** * Returns the reference if any * @return the reference if any */ public ModelGroup getReference() { ModelGroup result = null; if (_groupRef != null) { result = _schema.getModelGroup(_groupRef); //--check for redefinition if (_schema.getMasterSchema() != null ) { ModelGroup temp = _schema.getMasterSchema().getModelGroup(_groupRef); if (temp != null) result = temp; } if (result == null) { String err = "Unable to find group referenced :\" "; err += getName(); err +="\""; throw new IllegalStateException(err); } } return result; } //-- getReference /** * Returns true if this ModelGroup is referencing another one * @return true if this ModelGroup is referencing another one */ public boolean hasReference() { return (_groupRef != null) ? (_groupRef.length() !=0) : false; } /** * Checks the validity of this Schema defintion. * @exception ValidationException when this Schema definition * is invalid. **/ public void validate() throws ValidationException { //-- check name if (getParent() != null && getParent().getStructureType() != Structure.SCHEMA) { if (getName(true) != null) { String err = "Only top-level model group definition (<group>) can be named."; err += getName() + "is not a valid model group definition."; throw new ValidationException(err); } } if (getContentModelGroup() == null) { String err = "<group> should contains :\" "; err += " 'all' or 'sequence' or 'choice'"; err +="\""; throw new ValidationException(err); } //-- Check for circular references //-- Validation related to section 3.8.6 : Constraints on Model Group Schema Components //-- Schema Component Constraint: Model Group Correct //-- from the W3C XML Schema Recommendation for (int i=0; i<getParticleCount(); i++) { Structure temp = getParticle(i); switch (temp.getStructureType()) { case Structure.MODELGROUP: ModelGroup tempGroup = (ModelGroup)temp; String name = null; if (tempGroup.getReference() != null) name = tempGroup.getReference().getName(); if (name != null && name.equals(this.getName())) { if (isRedefined()) { if (getMaxOccurs() != 1 || getMinOccurs() != 1) { String err = "in the redefined <group> named:"+this.getName(); err += "\nThe particle information (minOccurs, maxOccurs) of a circular group must be set to 1.\n"; throw new ValidationException(err); } } else { String err = "in <group> named:"+this.getName(); err += "\nCircular groups are disallowed.\n"; err += "That is, within the {particles} of a group there must not be at any depth a particle whose {term} is the group itself.\n"; throw new ValidationException(err); } } //check cross-reference int j = 0; tempGroup = tempGroup.getReference(); while (j < tempGroup.getParticleCount()) { if (tempGroup.getParticle(j).getStructureType() == Structure.MODELGROUP) { ModelGroup referencedGroup = ((ModelGroup)tempGroup.getParticle(j)).getReference(); if ((referencedGroup != null) && (referencedGroup.equals(this))) { if (isRedefined()) { if (getMaxOccurs() != 1 || getMinOccurs() != 1) { String err = "in the redefined <group> named:"+this.getName(); err += "\nThe particle information (minOccurs, maxOccurs) of a circular group must be set to 1.\n"; throw new ValidationException(err); } } else { String err = "Cross reference between <group>:"+this.getName()+" and <group>:"+tempGroup.getName(); err += "\nCircular groups are disallowed.\n"; err += "That is, within the {particles} of a group there must not be at any depth a particle whose {term} is the group itself.\n"; throw new ValidationException(err); } } } j++; } break; default: break; } } } //-- validate /** * Returns the schema that contains this modelGroup definition */ public Schema getSchema() { return _schema; } /** * Sets the Schema that contains this group. * * @param schema the Schema that contains this group. */ public void setSchema(Schema schema) { _schema = schema; } } //-- Group