View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999 - 2004 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$
34   */
35  
36  package org.exolab.castor.xml.schema;
37  
38  import org.exolab.castor.xml.*;
39  
40  import java.util.Vector;
41  import java.util.Enumeration;
42  
43  /**
44   * An XML Schema ModelGroup : <xsd:group>
45   * 
46   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
47   * @version $Revision$ $Date: 2006-04-25 15:08:23 -0600 (Tue, 25 Apr 2006) $
48   **/
49  public class ModelGroup extends Group {
50    /** SerialVersionUID */
51    private static final long serialVersionUID = -2057934322265672413L;
52  
53    /**
54     * the name of the ModelGroup referenced
55     */
56    private String _groupRef = null;
57  
58    /**
59     * An ordered list of all ModelGroup definitions
60     **/
61    private final Vector<ModelGroup> _modelDefs = new Vector<>();
62  
63    /**
64     * An attribute that indicates if this Group is a redefinition
65     */
66    private boolean _redefinition = false;
67  
68  
69    /**
70     * the schema that contains this model group
71     */
72    private Schema _schema = null;
73  
74    /**
75     * Creates a new ModelGroup, with no name
76     **/
77    public ModelGroup() {
78      this(null);
79    } // -- ModelGroup
80  
81    /**
82     * Creates a new ModelGroup definition
83     * 
84     * @param schema the XML Schema to which this ModelGroup belongs
85     */
86    public ModelGroup(Schema schema) {
87      this(null, schema);
88    }
89  
90    /**
91     * Creates a new ModelGroup with the given name
92     * 
93     * @param name of the ModelGroup
94     **/
95    public ModelGroup(String name, Schema schema) {
96      super(name);
97      _schema = schema;
98    } // -- ModelGroup
99  
100 
101   /**
102    * Adds the given ModelGroup to this ModelGroup
103    * 
104    * @param modelGroup the ModelGroup to add to this ModelGroup
105    **/
106   public void addModelGroup(ModelGroup modelGroup) {
107     if (!_modelDefs.contains(modelGroup)) {
108       _modelDefs.add(modelGroup);
109     }
110   } // -- addModelGroup
111 
112   /**
113    * Returns an enumeration of all the Particles of this ContentModelGroup
114    *
115    * @return an enumeration of the Particles contained within this ContentModelGroup
116    **/
117   public Enumeration<Particle> enumerate() {
118     return this.getContentModelGroup().enumerate();
119   } // -- enumerate
120 
121   /**
122    * Returns an ordered Enumeration of all the ContentModelType definitions (element, group,
123    * modelGroupRef)+
124    **/
125   public Enumeration<ModelGroup> getDeclarations() {
126     return _modelDefs.elements();
127   } // -- getDeclarations
128 
129   /**
130    * Returns the ContentModelGroup for this group Only used for a <group> element
131    * 
132    * @return the ContentModelGroup for this group
133    */
134   public ContentModelGroup getContentModelGroup() {
135     if (_groupRef != null)
136       return getReference().getContentModelGroup();
137     return super.getContentModelGroup();
138   }
139 
140   /**
141    * Returns the name of this ModelGroup.
142    * 
143    * @return the name of this ModelGroup.
144    **/
145   public String getName() {
146     return getName(false);
147   } // -- getName
148 
149   /**
150    * Returns the name of this Model Group definition
151    *
152    * @param ignoreRef If True the name of the referenced model group (if specified) is returned
153    * @return the name of this element declaration
154    **/
155   public String getName(boolean ignoreRef) {
156 
157     if (ignoreRef == false && _groupRef != null) {
158       String localName = _groupRef;
159       // -- check for namespace prefix
160       int idx = localName.indexOf(':');
161       if (idx > 0) {
162         localName = localName.substring(idx + 1);
163       }
164       return localName;
165     }
166     return super.getName();
167   } // -- getName
168 
169   /**
170    * Returns true if this model group definition simply references another model group Definition
171    * 
172    * @return true if this model group definition is a reference
173    */
174   public boolean isReference() {
175     return (_groupRef != null);
176   } // -- isReference
177 
178   /**
179    * Sets this Group has redefined.
180    */
181   public void setRedefined() {
182     _redefinition = true;
183   }
184 
185   /**
186    * Returns true if this group is a redefinition.
187    * 
188    * @return true if this group is a redefinition.
189    */
190   public boolean isRedefined() {
191     return _redefinition;
192   }
193 
194   /**
195    * Sets the reference for this ModelGroup definition
196    * 
197    * @param reference the name of the ModelGroup that this definition references
198    **/
199   public void setReference(String reference) {
200     this._groupRef = reference;
201   } // -- setReference
202 
203   // -------------------------------/
204   // - Implementation of Structure -/
205   // -------------------------------/
206 
207   /**
208    * Returns the type of this Schema Structure
209    * 
210    * @return the type of this Schema Structure
211    **/
212   public short getStructureType() {
213     return Structure.MODELGROUP;
214   } // -- getStructureType
215 
216   /**
217    * Returns the Id used to Refer to this Object
218    * 
219    * @return the Id used to Refer to this Object
220    * @see Referable
221    **/
222   public String getReferenceId() {
223     if (this.getName() != null)
224       return "group:" + this.getName();
225     return null;
226   } // -- getReferenceId
227 
228   /**
229    * Returns the reference if any
230    * 
231    * @return the reference if any
232    */
233   public ModelGroup getReference() {
234     ModelGroup result = null;
235     if (_groupRef != null) {
236       result = _schema.getModelGroup(_groupRef);
237 
238       // --check for redefinition
239       if (_schema.getMasterSchema() != null) {
240         ModelGroup temp = _schema.getMasterSchema().getModelGroup(_groupRef);
241         if (temp != null)
242           result = temp;
243       }
244 
245       if (result == null) {
246         String err = "Unable to find group referenced :\" ";
247         err += getName();
248         err += "\"";
249         throw new IllegalStateException(err);
250       }
251     }
252     return result;
253   } // -- getReference
254 
255 
256   /**
257    * Returns true if this ModelGroup is referencing another one
258    * 
259    * @return true if this ModelGroup is referencing another one
260    */
261   public boolean hasReference() {
262     return (_groupRef != null) ? (_groupRef.length() != 0) : false;
263   }
264 
265   /**
266    * Checks the validity of this Schema defintion.
267    * 
268    * @exception ValidationException when this Schema definition is invalid.
269    **/
270   public void validate() throws ValidationException {
271     // -- check name
272     if (getParent() != null && getParent().getStructureType() != Structure.SCHEMA) {
273       if (getName(true) != null) {
274         String err = "Only top-level model group definition (<group>) can be named.";
275         err += getName() + "is not a valid model group definition.";
276         throw new ValidationException(err);
277       }
278     }
279 
280     if (getContentModelGroup() == null) {
281       String err = "<group> should contains :\" ";
282       err += " 'all' or 'sequence' or 'choice'";
283       err += "\"";
284       throw new ValidationException(err);
285     }
286 
287     // -- Check for circular references
288     // -- Validation related to section 3.8.6 : Constraints on Model Group Schema Components
289     // -- Schema Component Constraint: Model Group Correct
290     // -- from the W3C XML Schema Recommendation
291     for (int i = 0; i < getParticleCount(); i++) {
292       Structure temp = getParticle(i);
293       switch (temp.getStructureType()) {
294         case Structure.MODELGROUP:
295           ModelGroup tempGroup = (ModelGroup) temp;
296           String name = null;
297           if (tempGroup.getReference() != null)
298             name = tempGroup.getReference().getName();
299 
300           if (name != null && name.equals(this.getName())) {
301             if (isRedefined()) {
302               if (getMaxOccurs() != 1 || getMinOccurs() != 1) {
303                 String err = "in the redefined <group> named:" + this.getName();
304                 err +=
305                     "\nThe particle information (minOccurs, maxOccurs) of a circular group must be set to 1.\n";
306                 throw new ValidationException(err);
307               }
308 
309             } else {
310               String err = "in <group> named:" + this.getName();
311               err += "\nCircular groups are disallowed.\n";
312               err +=
313                   "That is, within the {particles} of a group there must not be at any depth a particle whose {term} is the group itself.\n";
314               throw new ValidationException(err);
315             }
316           }
317           // check cross-reference
318           int j = 0;
319           tempGroup = tempGroup.getReference();
320           while (j < tempGroup.getParticleCount()) {
321             if (tempGroup.getParticle(j).getStructureType() == Structure.MODELGROUP) {
322               ModelGroup referencedGroup = ((ModelGroup) tempGroup.getParticle(j)).getReference();
323               if ((referencedGroup != null) && (referencedGroup.equals(this))) {
324                 if (isRedefined()) {
325                   if (getMaxOccurs() != 1 || getMinOccurs() != 1) {
326                     String err = "in the redefined <group> named:" + this.getName();
327                     err +=
328                         "\nThe particle information (minOccurs, maxOccurs) of a circular group must be set to 1.\n";
329                     throw new ValidationException(err);
330                   }
331                 } else {
332                   String err = "Cross reference between <group>:" + this.getName() + " and <group>:"
333                       + tempGroup.getName();
334                   err += "\nCircular groups are disallowed.\n";
335                   err +=
336                       "That is, within the {particles} of a group there must not be at any depth a particle whose {term} is the group itself.\n";
337                   throw new ValidationException(err);
338                 }
339               }
340 
341             }
342             j++;
343 
344           }
345           break;
346         default:
347           break;
348 
349       }
350     }
351   } // -- validate
352 
353   /**
354    * Returns the schema that contains this modelGroup definition
355    */
356   public Schema getSchema() {
357     return _schema;
358   }
359 
360   /**
361    * Sets the Schema that contains this group.
362    *
363    * @param schema the Schema that contains this group.
364    */
365   public void setSchema(Schema schema) {
366     _schema = schema;
367   }
368 
369 
370 
371 } // -- Group