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