View Javadoc
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 1999 - 2004 (C) Intalio, Inc. All Rights Reserved.
42   *
43   * $Id$
44   */
45  
46  package org.exolab.castor.xml.schema;
47  
48  import org.exolab.castor.xml.*;
49  
50  import java.util.Vector;
51  import java.util.Enumeration;
52  
53  /**
54   * An XML Schema ModelGroup : <xsd:group>
55   * 
56   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
57   * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
58  **/
59  public class ModelGroup extends Group {
60      /** SerialVersionUID */
61      private static final long serialVersionUID = -2057934322265672413L;
62  
63      /**
64       * the name of the ModelGroup referenced
65       */
66       private String _groupRef = null;
67  
68      /**
69       * An ordered list of all ModelGroup definitions
70      **/
71      private Vector _modelDefs;
72      
73      /**
74       * An attribute that indicates if this Group is
75       * a redefinition
76       */
77      private boolean _redefinition = false;
78  
79  
80      /**
81       * the schema that contains this model group
82       */
83       private Schema _schema = null;
84  
85      /**
86       * Creates a new ModelGroup, with no name
87      **/
88      public ModelGroup() {
89          this(null);
90      } //-- ModelGroup
91  
92      /**
93       * Creates a new ModelGroup definition
94       * @param schema the XML Schema to which this ModelGroup
95       * belongs
96       */
97      public ModelGroup(Schema schema) {
98          this(null, schema);
99      }
100 
101     /**
102      * Creates a new ModelGroup with the given name
103      * @param name of the ModelGroup
104     **/
105     public ModelGroup(String name, Schema schema) {
106         super(name);
107         _schema = schema;
108         _modelDefs = new Vector();
109     } //-- ModelGroup
110 
111 
112     /**
113      * Adds the given ModelGroup to this ModelGroup
114      * @param modelGroup the ModelGroup to add to this ModelGroup
115     **/
116     public void addModelGroup(ModelGroup modelGroup) {
117         if (!_modelDefs.contains(modelGroup)) {
118             _modelDefs.addElement(modelGroup);
119         }
120     } //-- addModelGroup
121 
122     /**
123      * Returns an enumeration of all the Particles of this
124      * ContentModelGroup
125      *
126      * @return an enumeration of the Particles contained
127      * within this ContentModelGroup
128     **/
129     public Enumeration enumerate() {
130         return this.getContentModelGroup().enumerate();
131     } //-- enumerate
132 
133     /**
134      * Returns an ordered Enumeration of all the ContentModelType
135      * definitions (element, group, modelGroupRef)+
136     **/
137     public Enumeration getDeclarations() {
138         return _modelDefs.elements();
139     } //-- getDeclarations
140 
141     /**
142      * Returns the ContentModelGroup for this group
143      * Only used for a <group> element
144      * @return the ContentModelGroup for this group
145      */
146      public ContentModelGroup getContentModelGroup() {
147         if (_groupRef != null)
148             return getReference().getContentModelGroup();
149         return super.getContentModelGroup();
150      }
151     /**
152      * Returns the name of this ModelGroup.
153      * @return the name of this ModelGroup.
154     **/
155     public String getName() {
156         return getName(false);
157     } //-- getName
158 
159     /**
160      * Returns the name of this Model Group definition
161      *
162      * @param ignoreRef If True the name of the referenced
163      * model group (if specified) is returned
164      * @return the name of this element declaration
165     **/
166     public String getName(boolean ignoreRef) {
167 
168         if (ignoreRef == false && _groupRef !=null ) {
169             String localName = _groupRef;
170             //-- check for namespace prefix
171             int idx = localName.indexOf(':');
172             if (idx > 0) {
173                 localName = localName.substring(idx+1);
174             }
175             return localName;
176         }
177 		return super.getName();
178     } //-- getName
179     
180     /**
181      * Returns true if this model group definition simply references another
182      * model group Definition
183      * @return true if this model group definition is a reference
184      */
185     public boolean isReference() {
186         return (_groupRef != null);
187     } //-- isReference
188     
189     /**
190      * Sets this Group has redefined. 
191      */
192     public void setRedefined() {
193     	_redefinition = true;
194     }
195     
196     /**
197      * Returns true if this group is a redefinition.
198      * 
199      * @return true if this group is a redefinition.
200      */
201     public boolean isRedefined() {
202     	return _redefinition;
203     }
204     
205     /**
206      * Sets the reference for this ModelGroup definition
207      * @param reference the name of the ModelGroup that this
208      * definition references
209     **/
210     public void setReference(String reference) {
211         this._groupRef = reference;
212     } //-- setReference
213 
214     //-------------------------------/
215     //- Implementation of Structure -/
216     //-------------------------------/
217 
218     /**
219      * Returns the type of this Schema Structure
220      * @return the type of this Schema Structure
221     **/
222     public short getStructureType() {
223         return Structure.MODELGROUP;
224     } //-- getStructureType
225 
226     /**
227      * Returns the Id used to Refer to this Object
228      * @return the Id used to Refer to this Object
229      * @see Referable
230     **/
231     public String getReferenceId() {
232         if (this.getName() != null) return "group:"+this.getName();
233         return null;
234     } //-- getReferenceId
235 
236     /**
237      * Returns the reference if any
238      * @return the reference if any
239      */
240      public ModelGroup getReference() {
241         ModelGroup result = null;
242         if (_groupRef != null) {
243             result =  _schema.getModelGroup(_groupRef);
244             
245             //--check for redefinition
246             if (_schema.getMasterSchema() != null ) {
247             	ModelGroup temp = _schema.getMasterSchema().getModelGroup(_groupRef);
248             	if (temp != null)
249             		result = temp;
250             }
251             
252             if (result == null) {
253                 String err = "Unable to find group referenced :\" ";
254                 err += getName();
255                 err +="\"";
256                 throw new IllegalStateException(err);
257             }
258         }
259         return result;
260     } //-- getReference
261 
262 
263      /**
264       * Returns true if this ModelGroup is referencing another one
265       * @return true if this ModelGroup is referencing another one
266       */
267      public boolean hasReference() {
268        return (_groupRef != null)
269                ? (_groupRef.length() !=0)
270                : false;
271      }
272 
273     /**
274      * Checks the validity of this Schema defintion.
275      * @exception ValidationException when this Schema definition
276      * is invalid.
277     **/
278     public void validate()
279         throws ValidationException
280     {
281         //-- check name
282         if (getParent() != null && getParent().getStructureType() != Structure.SCHEMA) {
283            if (getName(true) != null) {
284                String err = "Only top-level model group definition (<group>) can be named.";
285                err += getName() + "is not a valid model group definition.";
286                throw new ValidationException(err);
287            }
288         }
289 
290         if (getContentModelGroup() == null) {
291             String err = "<group> should contains :\" ";
292             err += " 'all' or 'sequence' or 'choice'";
293             err +="\"";
294             throw new ValidationException(err);
295         }
296 
297         //-- Check for circular references
298         //-- Validation related to section 3.8.6 : Constraints on Model Group Schema Components
299         //-- Schema Component Constraint: Model Group Correct
300         //-- from the W3C XML Schema Recommendation
301         for (int i=0; i<getParticleCount(); i++) {
302             Structure temp = getParticle(i);
303             switch (temp.getStructureType()) {
304                 case Structure.MODELGROUP:
305                     ModelGroup tempGroup = (ModelGroup)temp;
306                     String name = null;
307                     if (tempGroup.getReference() != null)
308                         name = tempGroup.getReference().getName();
309 
310                     if (name != null && name.equals(this.getName())) {
311                         if (isRedefined()) {
312                         	if (getMaxOccurs() != 1 || getMinOccurs() != 1) {
313                         		String err = "in the redefined <group> named:"+this.getName();
314                         		err +=  "\nThe particle information (minOccurs, maxOccurs) of a circular group must be set to 1.\n";
315                         		throw new ValidationException(err);
316                         	}
317 
318                         }
319                     	else {
320                     		String err = "in <group> named:"+this.getName();
321                             err +=  "\nCircular groups are disallowed.\n";
322                             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";
323                             throw new ValidationException(err);
324                     	}
325                     }
326                     //check cross-reference
327                     int j = 0;
328                     tempGroup = tempGroup.getReference();
329                     while (j < tempGroup.getParticleCount()) {
330                         if (tempGroup.getParticle(j).getStructureType() == Structure.MODELGROUP) {
331                             ModelGroup referencedGroup = ((ModelGroup)tempGroup.getParticle(j)).getReference();
332                             if ((referencedGroup != null) && (referencedGroup.equals(this))) {
333                             	if (isRedefined()) {
334                             		if (getMaxOccurs() != 1 || getMinOccurs() != 1) {
335                             			String err = "in the redefined <group> named:"+this.getName();
336                             			err +=  "\nThe particle information (minOccurs, maxOccurs) of a circular group must be set to 1.\n";
337                             			throw new ValidationException(err);
338                             		}
339                             	}
340                             	else {
341 	                            	String err = "Cross reference between <group>:"+this.getName()+" and <group>:"+tempGroup.getName();
342 	                                err +=  "\nCircular groups are disallowed.\n";
343 	                                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";
344 	                                throw new ValidationException(err);
345                             	}
346                             }
347 
348                         }
349                         j++;
350 
351                     }
352                     break;
353                 default:
354                     break;
355 
356             }
357         }
358     } //-- validate
359 
360     /**
361      * Returns the schema that contains this modelGroup definition
362      */
363     public Schema getSchema() {
364        return _schema;
365     }
366     /**
367      * Sets the Schema that contains this group.
368      *
369      * @param schema the Schema that contains this group.
370      */
371     public void setSchema(Schema schema) {
372         _schema = schema;
373     }
374 
375 
376 
377 } //-- Group