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