001: /**
002: * Redistribution and use of this software and associated documentation
003: * ("Software"), with or without modification, are permitted provided
004: * that the following conditions are met:
005: *
006: * 1. Redistributions of source code must retain copyright
007: * statements and notices. Redistributions must also contain a
008: * copy of this document.
009: *
010: * 2. Redistributions in binary form must reproduce the
011: * above copyright notice, this list of conditions and the
012: * following disclaimer in the documentation and/or other
013: * materials provided with the distribution.
014: *
015: * 3. The name "Exolab" must not be used to endorse or promote
016: * products derived from this Software without prior written
017: * permission of Intalio, Inc. For written permission,
018: * please contact info@exolab.org.
019: *
020: * 4. Products derived from this Software may not be called "Exolab"
021: * nor may "Exolab" appear in their names without prior written
022: * permission of Intalio, Inc. Exolab is a registered
023: * trademark of Intalio, Inc.
024: *
025: * 5. Due credit should be given to the Exolab Project
026: * (http://www.exolab.org/).
027: *
028: * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
029: * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
030: * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
031: * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
032: * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
033: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
034: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
035: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
036: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
037: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
038: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
039: * OF THE POSSIBILITY OF SUCH DAMAGE.
040: *
041: * Copyright 1999, 2000 (C) Intalio, Inc. All Rights Reserved.
042: *
043: * $Id: Group.java 6230 2006-09-19 07:56:07Z wguttmn $
044: */package org.exolab.castor.xml.schema;
045:
046: import java.util.Enumeration;
047:
048: import org.exolab.castor.xml.ValidationException;
049:
050: /**
051: * An XML Schema Group
052: * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
053: * @version $Revision: 6230 $ $Date: 2006-04-14 04:14:43 -0600 (Fri, 14 Apr 2006) $
054: **/
055: public class Group extends Particle implements ContentModelGroup,
056: Referable {
057: /** SerialVersionUID */
058: private static final long serialVersionUID = 3133443973681261845L;
059:
060: /**
061: * the implementation of ContentModelGroup
062: **/
063: private ContentModelGroup _contentModel = null;
064:
065: /**
066: * The name of this Group
067: **/
068: private String name = null;
069:
070: /**
071: * The Compositor for the Group
072: **/
073: private Order _order = Order.seq;
074:
075: private String _id = null;
076:
077: /**
078: * True if was created for a group tag, false otherwise
079: * (all, choice, sequence)
080: */
081: private boolean _isModelGroupDefinition = false;
082:
083: /**
084: * The parent for this Group (either another Group or a ComplexType)
085: **/
086: private Structure _parent = null;
087:
088: /**
089: * Creates a new Group, with no name
090: **/
091: public Group() {
092: this (null);
093: } //-- Group
094:
095: /**
096: * Creates a new Group with the given name
097: * @param name of the Group
098: **/
099: public Group(String name) {
100: super ();
101: this .name = name;
102: _contentModel = new ContentModelGroupImpl();
103: } //-- Group
104:
105: /**
106: * Adds a wildcard to this Group model
107: * @param wildcard the Wildcard to add
108: * @exception SchemaException thrown when the wildcard
109: * is an {@literal <anyAttribute>} element
110: */
111: public void addWildcard(Wildcard wildcard) throws SchemaException {
112: if (wildcard.isAttributeWildcard())
113: throw new SchemaException(
114: "only <any> should be add in a group.");
115: _contentModel.addWildcard(wildcard);
116: }
117:
118: /**
119: * Removes the given Wildcard from this Group.
120: * @param wildcard the Wildcard to remove.
121: * @return true if the wildcard has been successfully removed, false otherwise.
122: */
123: public boolean removeWildcard(Wildcard wildcard) {
124: if (wildcard == null)
125: return false;
126: return _contentModel.removeWildcard(wildcard);
127: }
128:
129: /**
130: * Returns the ContentModelGroup for this group
131: * Only used for a <group> element
132: * @return the ContentModelGroup for this group
133: */
134: public ContentModelGroup getContentModelGroup() {
135: return _contentModel;
136: }
137:
138: /**
139: * Returns the ID for this Group
140: * @return the ID for this Group, or null if no ID is present
141: **/
142: public String getId() {
143: return _id;
144: } //-- getId
145:
146: /**
147: * Returns the name of this Group, or null if no name was defined.
148: * @return the name of this Group, or null if no name was defined
149: **/
150: public String getName() {
151: return name;
152: } //-- getName
153:
154: /**
155: * Returns the compositor for this Group
156: * @return the compositor for this Group
157: **/
158: public Order getOrder() {
159:
160: //-- Return proper compositor...
161: //-- according to XML Schema spec 20000407 section 4.3.5
162:
163: //-- Note: it's important not to simply call
164: //-- #getParticleCount or #getParticle because those
165: //-- methods also perform some trickery
166: if (_contentModel.getParticleCount() == 1) {
167: Particle particle = _contentModel.getParticle(0);
168: if (particle.getStructureType() == Structure.GROUP) {
169: if ((getMinOccurs() == 1) && (getMaxOccurs() == 1))
170: return ((Group) particle).getOrder();
171: }
172: }
173: return this ._order;
174: } //-- getOrder
175:
176: /**
177: * Returns the parent of this Group, this value may be null if
178: * no parent has been set.
179: *
180: * @return the parent Structure of this Group.
181: **/
182: public Structure getParent() {
183: return _parent;
184: } //-- getParent
185:
186: /**
187: * Sets if the group is a model group definition
188: * @deprecated Since Castor 0.9.2, to handle properly the <group>
189: * element the class ModelGroup has been created
190: */
191: public void setIsModelGroupDefinition(boolean isModelGroupDefinition) {
192: _isModelGroupDefinition = isModelGroupDefinition;
193: }
194:
195: /**
196: * Tells if the group is a model group definition
197: * @return true if the group is a model group definition (<group> tag), false
198: * otherwise {@literal <all>}, <choice>, or <sequence> tags.
199: * @deprecated Since Castor 0.9.2, to handle properly the <group>
200: * element the class ModelGroup has been created
201:
202: */
203: public boolean isModelGroupDefinition() {
204: return _isModelGroupDefinition;
205: }
206:
207: /**
208: * Returns the Id used to Refer to this Object
209: * @return the Id used to Refer to this Object
210: * @see Referable
211: **/
212: public String getReferenceId() {
213: if (name != null)
214: return "group:" + name;
215: return null;
216: } //-- getReferenceId
217:
218: /**
219: * Sets the name of this Group
220: * @param name the new name for this Group
221: **/
222: public void setName(String name) {
223: this .name = name;
224: } //--setName
225:
226: /**
227: * Sets the ID for this Group
228: * @param id the ID for this Group
229: **/
230: public void setId(String id) {
231: _id = id;
232: } //-- setId
233:
234: /**
235: * Sets the Order option for this Group
236: * @param order the type of order that this group is restricted to
237: **/
238: public void setOrder(Order order) {
239: if (order == null)
240: this ._order = Order.all;
241: else
242: this ._order = order;
243: } //-- setOrder
244:
245: //---------------------------------------/
246: //- Implementation of ContentModelGroup -/
247: //---------------------------------------/
248:
249: /**
250: * Adds the given ElementDecl to this ContentModelGroup
251: * @param elementDecl the ElementDecl to add
252: * @exception SchemaException when an ElementDecl already
253: * exists with the same name as the given ElementDecl
254: **/
255: public void addElementDecl(ElementDecl elementDecl)
256: throws SchemaException {
257: _contentModel.addElementDecl(elementDecl);
258: //--set the parent
259: elementDecl.setParent(this );
260: } //-- addElementDecl
261:
262: /**
263: * Removes the given ElementDecl from this ContentModelGroup.
264: * @param element the ElementDecl to remove.
265: * @return true if the element has been successfully removed, false otherwise.
266: */
267: public boolean removeElementDecl(ElementDecl element) {
268: return _contentModel.removeElementDecl(element);
269: }
270:
271: /**
272: * Adds the given Group to this ContentModelGroup
273: * @param group the Group to add
274: * @exception SchemaException when a group with the same name as the
275: * specified group already exists in the current scope
276: **/
277: public void addGroup(Group group) throws SchemaException {
278: _contentModel.addGroup(group);
279:
280: //-- set reference to parent
281: group.setParent(this );
282:
283: } //-- addGroup
284:
285: /**
286: * Removes the given Group from this Group.
287: * @param group the Group to remove.
288: * @return true if the group has been successfully removed, false otherwise.
289: */
290: public boolean removeGroup(Group group) {
291: boolean result = _contentModel.removeGroup(group);
292: group.setParent(null);
293: return result;
294: }
295:
296: /**
297: * Adds the given ModelGroup Definition to this Group
298: * @param group the ModelGroup to add
299: * @exception SchemaException when a group with the same name as the
300: * specified group already exists in the current scope
301: **/
302: public void addGroup(ModelGroup group) throws SchemaException {
303: _contentModel.addGroup(group);
304:
305: //-- set reference to parent
306: group.setParent(this );
307: } //-- addGroup
308:
309: /**
310: * Removes the given ModelGroup Definition from this Group.
311: * @param group the ModelGroup Definition to remove.
312: * @return true if the group has been successfully removed, false otherwise.
313: */
314: public boolean removeGroup(ModelGroup group) {
315: boolean result = _contentModel.removeGroup(group);
316: group.setParent(null);
317: return result;
318: }
319:
320: /**
321: * Returns an enumeration of all the Particles of this
322: * ContentModelGroup
323: *
324: * @return an enumeration of the Particles contained
325: * within this ContentModelGroup
326: **/
327: public Enumeration enumerate() {
328: //-- Some trickery to properly handle
329: //-- XML Schema spec 20000407 section 4.3.5
330:
331: if (_contentModel.getParticleCount() == 1) {
332: Particle particle = _contentModel.getParticle(0);
333: if (particle.getStructureType() == Structure.GROUP) {
334: Group temp = (Group) particle;
335: if (((getMinOccurs() == 1) && (getMaxOccurs() == 1))
336: && ((temp.getMinOccurs() == 1) && (temp
337: .getMaxOccurs() == 1)))
338: return temp.enumerate();
339: }
340: }
341: return _contentModel.enumerate();
342: } //-- enumerate
343:
344: /**
345: * Returns the element declaration with the given name, or null if no
346: * element declaration with that name exists in this ContentModelGroup.
347: *
348: * @param name the name of the element.
349: * @return the ElementDecl with the given name, or null if no
350: * ElementDecl exists in this ContentModelGroup.
351: **/
352: public ElementDecl getElementDecl(String name) {
353: return _contentModel.getElementDecl(name);
354: } //-- getElementDecl
355:
356: /**
357: * Returns the Particle at the specified index
358: * @param index the index of the particle to return
359: * @return the CMParticle at the specified index
360: **/
361: public Particle getParticle(int index) {
362: //-- Some trickery to properly handle
363: //-- XML Schema spec 20000407 section 4.3.5
364: if (_contentModel.getParticleCount() == 1) {
365: Particle particle = _contentModel.getParticle(0);
366: if (particle.getStructureType() == Structure.GROUP) {
367: if ((getMinOccurs() == 1) && (getMaxOccurs() == 1))
368: return ((Group) particle).getParticle(index);
369: }
370: }
371: return _contentModel.getParticle(index);
372: } //-- getParticle
373:
374: /**
375: * Returns the number of particles contained within
376: * this ContentModelGroup
377: *
378: * @return the number of particles
379: **/
380: public int getParticleCount() {
381: //-- Some trickery to properly handle
382: //-- XML Schema spec 20000407 section 4.3.5
383: if (_contentModel.getParticleCount() == 1) {
384: Particle particle = _contentModel.getParticle(0);
385: if (particle.getStructureType() == Structure.GROUP) {
386: if ((getMinOccurs() == 1) && (getMaxOccurs() == 1))
387: return ((Group) particle).getParticleCount();
388: }
389: }
390: return _contentModel.getParticleCount();
391: } //-- getParticleCount
392:
393: //-------------------------------/
394: //- Implementation of Structure -/
395: //-------------------------------/
396:
397: /**
398: * Returns the type of this Schema Structure
399: * @return the type of this Schema Structure
400: **/
401: public short getStructureType() {
402: return Structure.GROUP;
403: } //-- getStructureType
404:
405: /**
406: * A helper method that returns true if this group
407: * contains an {@literal <any>} element.
408: * @return method that returns true if this group
409: * contains an {@literal <any>} element.
410: */
411: public boolean hasAny() {
412: boolean result = false;
413: Enumeration enumeration = _contentModel.enumerate();
414: while (enumeration.hasMoreElements() && !result) {
415: Structure struct = (Structure) enumeration.nextElement();
416: switch (struct.getStructureType()) {
417: case Structure.ELEMENT:
418: break;
419: case Structure.GROUP:
420: case Structure.MODELGROUP:
421: result = ((Group) struct).hasAny();
422: break;
423: case Structure.WILDCARD:
424: result = true;
425: break;
426: default:
427: break;
428: }
429: }
430: return result;
431: }
432:
433: /**
434: * Checks the validity of this Group defintion.
435: *
436: * @throws ValidationException when this Group definition
437: * is invalid.
438: **/
439: public void validate() throws ValidationException {
440: if (_order == Order.all) {
441: if (getMaxOccurs() != 1) {
442: String err = "Wrong maxOccurs value for a <all>:"
443: + getMaxOccurs();
444: err += "\n1 is the only possible value.";
445: throw new ValidationException(err);
446: }
447: if (getMinOccurs() > 1) {
448: String err = "Wrong minOccurs value for a <all>:"
449: + getMinOccurs();
450: err += "\n0 or 1 are the only possible values.";
451: throw new ValidationException(err);
452: }
453: }
454: Enumeration enumeration = _contentModel.enumerate();
455: while (enumeration.hasMoreElements()) {
456: ((Structure) enumeration.nextElement()).validate();
457: }
458: } //-- validate
459:
460: /**
461: * Sets the parent for this Group
462: *
463: * @param parent the parent Structure for this Group
464: **/
465: protected void setParent(Structure parent) {
466: if (parent != null) {
467: switch (parent.getStructureType()) {
468: case Structure.COMPLEX_TYPE:
469: case Structure.GROUP:
470: case Structure.MODELGROUP:
471: case Structure.SCHEMA:
472: break;
473: default:
474: String error = "Invalid parent for group";
475: throw new IllegalArgumentException(error);
476: }
477: }
478: _parent = parent;
479: } //-- setParent
480:
481: /**
482: * @return true if this Particle is emptiable
483: */
484: public boolean isEmptiable() {
485: if (getMinOccurs() == 0) {
486: return true;
487: }
488:
489: boolean result = false;
490: switch (this .getOrder().getType()) {
491: case Order.CHOICE: {
492: result = false;
493: Enumeration enumerate = this .enumerate();
494: while (enumerate.hasMoreElements()) {
495: Particle p = (Particle) enumerate.nextElement();
496: if (p.isEmptiable()) {
497: result = true;
498: break;
499: }
500: }
501: }
502: break;
503:
504: case Order.ALL:
505: case Order.SEQUENCE: {
506: result = true;
507: Enumeration enumerate = this .enumerate();
508: while (enumerate.hasMoreElements()) {
509: Particle p = (Particle) enumerate.nextElement();
510: if (!p.isEmptiable()) {
511: result = false;
512: break;
513: }
514: }
515: }
516: break;
517: }
518: return result;
519:
520: }
521:
522: } //-- Group
|