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 java.util.Enumeration;
39  
40  import org.exolab.castor.xml.ValidationException;
41  
42  /**
43   * The XML Schema ComplexType class.
44   * 
45   * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
46   * @version $Revision$ $Date: 2006-02-01 15:47:48 -0700 (Wed, 01 Feb 2006) $
47   */
48  public class ComplexType extends XMLType implements ContentModelGroup, Referable {
49    /** SerialVersionUID */
50    private static final long serialVersionUID = 5348120259072084658L;
51  
52    /**
53     * The abstract flag for this ComplexType.
54     */
55    private boolean _abstract = false;
56  
57    /**
58     * A wildcard that represents an {@literal <anyAttribute>} element if any. Only one {@literal 
59     * <anyAttribute>} can appear inside the global scope of a complexType
60     */
61    private Wildcard _anyAttribute = null;
62  
63    /**
64     * The attribute declarations for this ComplexType.
65     */
66    private AttributeGroupDecl _attributes = null;
67  
68    /**
69     * The name of the base type used in &lt;restriction>&gt; or &lt;extension&gt;.
70     */
71    private String _baseType = null;
72  
73    /**
74     * The value of the 'block' property for this ComplexType. This value may be null.
75     */
76    private BlockList _block = null;
77  
78    /**
79     * a flag set to true if this complexType is a complexContent.
80     */
81    private boolean _complexContent = true;
82  
83    /**
84     * The content type ("mixed", "simpleType","elemOnly") for this ComplexType.
85     */
86    private ContentType _content = ContentType.elemOnly;
87  
88    /**
89     * The ContentModel for this ComplexType.
90     */
91    private ContentModelGroup _contentModel = null;
92  
93    /**
94     * The final property for this ComplexType. This value may be null..
95     */
96    private FinalList _final = null;
97  
98    /**
99     * The parent structure for this {@link ComplexType} (either an {@link ElementDecl} or a
100    * {@link Schema}).
101    */
102   private Structure _parent = null;
103 
104   /**
105    * a flag set to true if this complexType is a restriction.
106    */
107   private boolean _restricted = false;
108 
109   /**
110    * An attribute that indicates if this ComplexType is a redefinition.
111    */
112   private boolean _redefinition = false;
113 
114   // ------------------/
115   // - Constructor(s) -/
116   // ------------------/
117 
118   /**
119    * Creates a new {@link ComplexType} instance with no name.
120    * 
121    * @param schema the owning {@link Schema} document
122    */
123   public ComplexType(final Schema schema) {
124     this(schema, null);
125   } // -- Complextype
126 
127   /**
128    * Creates a new {@link ComplexType} with the given name.
129    * 
130    * @param schema The owning {@link Schema} instance
131    * @param name Name of the {@link ComplexType}
132    */
133   public ComplexType(final Schema schema, final String name) {
134     super();
135     if (schema == null) {
136       String err = NULL_ARGUMENT + "; 'schema' must not be null.";
137       throw new IllegalArgumentException(err);
138     }
139 
140     setSchema(schema);
141     setName(name);
142     _attributes = new AttributeGroupDecl(schema);
143     _contentModel = new ContentModelGroupImpl();
144   } // -- Complextype
145 
146   /**
147    * Adds the given {@link AttributeDecl} to this {@link ComplexType}.
148    * 
149    * @param attrDecl the {@link AttributeDecl} to add to this {@link ComplexType}
150    */
151   public void addAttributeDecl(final AttributeDecl attrDecl) {
152     _attributes.addAttribute(attrDecl);
153 
154     // --set the parent
155     attrDecl.setParent(this);
156   } // -- addAttributeDecl
157 
158   /**
159    * Removes the given {@link AttributeDecl} from this {@link ComplexType}.
160    * 
161    * @param attrDecl the AttributeDecl to remove.
162    */
163   public void removeAttributeDecl(final AttributeDecl attrDecl) {
164     _attributes.removeAttribute(attrDecl);
165   }
166 
167   /**
168    * Adds the given AttributeGroupReference to this ComplexType.
169    * 
170    * @param attrGroupRef the AttributeGroupReference to add to this ComplexType
171    */
172   public void addAttributeGroupReference(final AttributeGroupReference attrGroupRef) {
173     _attributes.addReference(attrGroupRef);
174   } // -- addAttributeGroupReference
175 
176   /**
177    * Removes the given {@link AttributeGroupReference} from this {@link ComplexType}.
178    * 
179    * @param attrGroupRef the {@link AttributeGroupReference} to remove.
180    */
181   public void removeAttributeGroupReference(final AttributeGroupReference attrGroupRef) {
182     _attributes.removeReference(attrGroupRef);
183   }
184 
185   /**
186    * Creates an {@link AttributeDecl} with the given name. The attribute declaration will still need
187    * to be added to this {@link ComplexType}, or another archetype in the same schema, by making a
188    * call to #addAttributeDecl
189    * 
190    * @param name the name of the attribute
191    * @return the new AttributeDecl
192    */
193   public AttributeDecl createAttributeDecl(final String name) {
194     return new AttributeDecl(getSchema(), name);
195   } // -- createAttributeDecl
196 
197   /**
198    * Returns the wilcard used in this complexType (can be null).
199    * 
200    * @return the wilcard used in this complexType (can be null)
201    */
202   public Wildcard getAnyAttribute() {
203     return _anyAttribute;
204   }
205 
206   /**
207    * Returns the {@link AttributeDecl} associated with the given name.
208    * 
209    * @param name Name of the associated {@link AttributeDecl}
210    * 
211    * @return the {@link AttributeDecl} associated with the given name, or null if no
212    *         {@link AttributeDecl} with the given name was found.
213    */
214   public AttributeDecl getAttributeDecl(final String name) {
215     AttributeDecl result = _attributes.getAttribute(name);
216     return result;
217   } // -- getAttributeDecl
218 
219   /**
220    * Returns an Enumeration of *all* the AttributeDecl objects declared within this ComplexType. The
221    * Enumeration will contain all AttributeDecl from AttributeGroup references as well. To return
222    * only locally declared attributes make a call to <code>getLocalAttributeDecls</code>.
223    * 
224    * @return an Enumeration of all the AttributeDecl objects declared within this Complextype
225    */
226   public Enumeration<AttributeDecl> getAttributeDecls() {
227     return _attributes.getAttributes();
228   } // -- getAttributeDecls
229 
230   /**
231    * Returns an Enumeration of *all* locally defined AttributeDecl declared within this ComplexType.
232    * The Enumeration will not contain any AttributeDecl from AttributeGroup references.
233    * 
234    * @return an Enumeration of all locally declared AttributeDecl.
235    */
236   public Enumeration<AttributeDecl> getLocalAttributeDecls() {
237     return _attributes.getLocalAttributes();
238   } // -- getLocalAttributeDecls
239 
240   /**
241    * Returns an Enumeration of all the AttributeGroup that are referenced within this ComplexType.
242    * 
243    * @return an Enumeration of all the AttributeGroup that are referenced within this ComplexType.
244    */
245   public Enumeration<AttributeGroupReference> getAttributeGroupReferences() {
246     return _attributes.getLocalAttributeGroupReferences();
247   }
248 
249   /**
250    * Returns the base type that this type inherits from.
251    * 
252    * @return the base type (also called super type).
253    */
254   public XMLType getBaseType() {
255     if ((_baseType != null) && (super.getBaseType() == null)) {
256       XMLType baseType = getSchema().getType(_baseType);
257       setBaseType(baseType);
258     }
259     return super.getBaseType();
260   } // -- getBaseType
261 
262   /**
263    * Returns the value of the 'block' attribute for this element.
264    * 
265    * @return the value of the 'block' attribute for this element
266    */
267   public BlockList getBlock() {
268     return _block;
269   } // -- getBlock
270 
271   /**
272    * Returns the content type of this ComplexType. The Content Type holds the information about the
273    * content of the complexType. For instance, if this complexType is a simpleContent then the
274    * simpleType information will be hold in the content type.
275    * 
276    * @return the content type of this ComplexType
277    */
278   public ContentType getContentType() {
279     return _content;
280   } // -- getContentType
281 
282   /**
283    * Returns the list of values for the final property for this ComplexType, or null if no final
284    * values have been set.
285    * 
286    * @return the FinalList for this ComplexType
287    */
288   public FinalList getFinal() {
289     return _final;
290   } // -- getFinal
291 
292   /**
293    * Returns the parent of this ComplexType, this value may be null if no parent has been set.
294    * 
295    * @return the parent Structure of this ComplexType.
296    */
297   public Structure getParent() {
298     return _parent;
299   } // -- getParent
300 
301   /**
302    * Returns the Id used to Refer to this Object.
303    * 
304    * @return the Id used to Refer to this Object
305    * @see Referable
306    */
307   public String getReferenceId() {
308     return "complexType:" + getName();
309   } // -- getReferenceId
310 
311   /**
312    * A helper method that returns true if this complexType contains an {@literal <any>} element.
313    * 
314    * @return method that returns true if this complexType contains an {@literal <any>} element.
315    */
316   public boolean hasAny() {
317     boolean result = false;
318     Enumeration<Particle> enumeration = _contentModel.enumerate();
319     while (enumeration.hasMoreElements() && !result) {
320       Structure struct = enumeration.nextElement();
321       switch (struct.getStructureType()) {
322         case Structure.ELEMENT:
323           break;
324         case Structure.GROUP:
325         case Structure.MODELGROUP:
326           result = ((Group) struct).hasAny();
327           break;
328         case Structure.WILDCARD:
329           result = true;
330           break;
331         default:
332           break;
333       }
334     }
335     return result;
336   }
337 
338   /**
339    * Returns true if this ComplexType has been marked as Abstract.
340    * 
341    * @return true if this ComplexType is "abstract".
342    */
343   public boolean isAbstract() {
344     return _abstract;
345   } // -- isAbstract
346 
347   /**
348    * Returns true if this complexType is a redefinition.
349    * 
350    * @return true if this complexType is a redefinition.
351    */
352   public boolean isRedefined() {
353     return _redefinition;
354   }
355 
356   /**
357    * Returns true if this is a top level {@link ComplexType}.
358    * 
359    * @return true if this is a top level {@link ComplexType}
360    */
361   public boolean isTopLevel() {
362     if (getName() == null) {
363       return false;
364     }
365     if (getSchema() == null) {
366       return false;
367     }
368     return (getSchema().getComplexType(getName()) == this);
369   } // -- isTopLevel
370 
371   /**
372    * Returns true if this complexType is a 'complexContent'.
373    * 
374    * @return true if this complexType is a 'complexContent'
375    */
376   public boolean isComplexContent() {
377     return _complexContent;
378   }
379 
380   /**
381    * Returns true if this complexType is a 'simpleContent'.
382    * 
383    * @return true if this complexType is a 'simpleContent'
384    */
385   public boolean isSimpleContent() {
386     return (!_complexContent);
387   }
388 
389   /**
390    * Returns true if this complexType is a restriction.
391    * 
392    * @return true if this complexType is a restriction
393    */
394   public boolean isRestricted() {
395     return _restricted;
396   }
397 
398   /**
399    * Sets whether or not this ComplexType should be abstract.
400    * 
401    * @param isAbstract a boolean that when true makes this ComplexType abstract.
402    */
403   public void setAbstract(final boolean isAbstract) {
404     _abstract = isAbstract;
405   } // -- setAbstract
406 
407   /**
408    * Sets the wildcard (anyAttribute) of the {@link ComplexType}.
409    * 
410    * @exception SchemaException thrown when a wildcard as already be set or when the wildCard is not
411    *            an {@literal <anyAttribute>}.
412    */
413   public void setAnyAttribute(final Wildcard wildcard) throws SchemaException {
414     if (wildcard != null) {
415       if (_anyAttribute != null) {
416         String err = "<anyAttribute> already set in this complexType: " + this.getName();
417         throw new SchemaException(err);
418       }
419 
420       if (!wildcard.isAttributeWildcard()) {
421         String err = "In complexType, " + this.getName() + "the wildcard must be an <anyAttribute>";
422         throw new SchemaException(err);
423       }
424     }
425     _anyAttribute = wildcard;
426   }
427 
428   /**
429    * Removes the given Wildcard from this Group.
430    * 
431    * @param wildcard the Wildcard to remove.
432    * @return true if the wildcard has been successfully removed, false otherwise.
433    */
434   public boolean removeWildcard(final Wildcard wildcard) {
435     if (wildcard == null) {
436       return false;
437     }
438     if (wildcard.equals(_anyAttribute)) {
439       _anyAttribute = null;
440       return true;
441     }
442     return false;
443 
444   }
445 
446   public void addWildcard(final Wildcard wildcard) throws SchemaException {
447     setAnyAttribute(wildcard);
448   }
449 
450   /**
451    * Sets the base type that this type is derived from.
452    * 
453    * @param base the type that this type is derived from
454    */
455   public void setBase(final String base) {
456     _baseType = base;
457   } // -- setBase
458 
459   /**
460    * Sets the base type for this ComplexType.
461    * 
462    * @param baseType the base type which this ComplexType extends or restricts
463    */
464   public void setBaseType(final XMLType baseType) {
465     super.setBaseType(baseType);
466     if (baseType != null) {
467       if (baseType.isSimpleType()) {
468         _complexContent = false;
469         _content = new SimpleContent((SimpleType) baseType);
470       } else if (baseType.isComplexType()) {
471         ComplexType complexType = (ComplexType) baseType;
472         if (complexType.isSimpleContent()) {
473           _complexContent = false;
474           _content = ((SimpleContent) complexType.getContentType()).copy();
475         } else {
476           _complexContent = true;
477         }
478       } else {
479         // -- assuming anyType
480         _complexContent = true;
481       }
482     }
483   } // -- setBaseType
484 
485   /**
486    * Sets the value of the 'block' attribute for this ComplexType.
487    * 
488    * @param block the value of the block attribute for this ComplexType definition.
489    */
490   public void setBlock(final BlockList block) {
491 
492     if (block != null) {
493       if (block.hasSubstitution()) {
494         String err = "'substitution' is an illegal value of the "
495             + "'block' attribute for a complexType definition.";
496         throw new IllegalArgumentException(err);
497       }
498     }
499     _block = block;
500   } // -- setBlock
501 
502   /**
503    * Sets the value of the 'block' attribute for this ComplexType.
504    * 
505    * @param block the value of the block attribute for this ComplexType definition.
506    */
507   public void setBlock(final String block) {
508     if (block == null) {
509       _block = null;
510     } else {
511       setBlock(new BlockList(block));
512     }
513   } // -- setBlock
514 
515   /**
516    * Sets whether or not this complexType is a 'complexContent'.
517    * 
518    * @param complexContent true if this complexType is a 'complexContent'
519    */
520   public void setComplexContent(final boolean complexContent) {
521     this._complexContent = complexContent;
522   }
523 
524   /**
525    * Sets the content type of this complexType. The Content Type holds the information about the
526    * content of the complexType. For instance, if this complexType is a simpleContent then the
527    * simpleType information will be hold in the content type.
528    * 
529    * @param contentType the ContentType for this complexType
530    */
531   public void setContentType(final ContentType contentType) {
532     _content = contentType;
533   } // -- setContentType
534 
535   /**
536    * Sets the value of the 'final' attribute for this ComplexType definition.
537    * 
538    * @param finalList the value of the final attribute for this ComplexType definition.
539    */
540   public void setFinal(final FinalList finalList) {
541     _final = finalList;
542   } // -- setFinal
543 
544   /**
545    * Sets the value of the 'final' attribute for this ComplexType definition.
546    * 
547    * @param finalValue the value of the final attribute for this ComplexType definition.
548    */
549   public void setFinal(final String finalValue) {
550     if (finalValue == null) {
551       _final = null;
552     } else {
553       _final = new FinalList(finalValue);
554     }
555   } // -- setFinal
556 
557   /**
558    * Sets this Group has redefined.
559    */
560   public void setRedefined() {
561     _redefinition = true;
562   }
563 
564   /**
565    * Sets whether or not this complexType is a 'simpleContent'.
566    * 
567    * @param simpleContent true if this complexType is a 'simpleContent'
568    */
569   public void setSimpleContent(final boolean simpleContent) {
570     _complexContent = (!simpleContent);
571   }
572 
573   /**
574    * Sets whether or not this complexType is a restriction.
575    * 
576    * @param restricted true if this complexType is a restriction
577    */
578   public void setRestriction(final boolean restricted) {
579     this._restricted = restricted;
580   }
581 
582   public void useResolver(final Resolver resolver) {
583     // do nothing for now
584   }
585 
586   // ---------------------------------------/
587   // - Implementation of ContentModelGroup -/
588   // ---------------------------------------/
589 
590   /**
591    * Adds the given ElementDecl to this {@link ContentModelGroup}.
592    * 
593    * @param elementDecl the ElementDecl to add
594    * @exception SchemaException when an ElementDecl already exists with the same name as the given
595    *            ElementDecl
596    */
597   public void addElementDecl(final ElementDecl elementDecl) throws SchemaException {
598     _contentModel.addElementDecl(elementDecl);
599 
600     // --set the parent
601     elementDecl.setParent(this);
602   } // -- addElementDecl
603 
604   /**
605    * Removes the given ElementDecl from this ContentModelGroup.
606    * 
607    * @param element the ElementDecl to remove.
608    * @return true if the element has been successfully removed, false otherwise.
609    */
610   public boolean removeElementDecl(final ElementDecl element) {
611     return _contentModel.removeElementDecl(element);
612   }
613 
614   /**
615    * Adds the given Group to this {@link ContentModelGroup}.
616    * 
617    * @param group the Group to add
618    * @exception SchemaException when a group with the same name as the specified group already
619    *            exists in the current scope
620    */
621   public void addGroup(final Group group) throws SchemaException {
622     _contentModel.addGroup(group);
623 
624     // -- set reference to parent
625     group.setParent(this);
626   } // -- addGroup
627 
628   /**
629    * Removes the given Group from this ContentModelGroup.
630    * 
631    * @param group the Group to remove.
632    * @return true if the group has been successfully removed, false otherwise.
633    */
634   public boolean removeGroup(final Group group) {
635     boolean result = _contentModel.removeGroup(group);
636     group.setParent(null);
637     return result;
638   }
639 
640   /**
641    * Adds the given ModelGroup Definition to this {@link ContentModelGroup}.
642    * 
643    * @param group the ModelGroup to add
644    * @exception SchemaException when a group with the same name as the specified group already
645    *            exists in the current scope
646    */
647   public void addGroup(final ModelGroup group) throws SchemaException {
648     _contentModel.addGroup(group);
649 
650     // -- set reference to parent
651     group.setParent(this);
652   } // -- addGroup
653 
654   /**
655    * Removes the given ModelGroup Definition from this ContentModelGroup.
656    * 
657    * @param group the ModelGroup Definition to remove.
658    * @return true if the group has been successfully removed, false otherwise.
659    */
660   public boolean removeGroup(final ModelGroup group) {
661     boolean result = _contentModel.removeGroup(group);
662     group.setParent(null);
663     return result;
664   }
665 
666   /**
667    * Returns an enumeration of all the Particles of this ContentModelGroup.
668    * 
669    * @return an enumeration of the Particles contained within this ContentModelGroup
670    */
671   public Enumeration<Particle> enumerate() {
672     return _contentModel.enumerate();
673   } // -- enumerate
674 
675   /**
676    * Returns the element declaration with the given name, or null if no element declaration with
677    * that name exists in this ContentModelGroup.
678    * 
679    * @param name the name of the element.
680    * @return the ElementDecl with the given name, or null if no ElementDecl exists in this
681    *         ContentModelGroup.
682    */
683   public ElementDecl getElementDecl(final String name) {
684     ElementDecl result = _contentModel.getElementDecl(name);
685     return result;
686   } // -- getElementDecl
687 
688   /**
689    * Returns the maximum number of occurances that this ContentModelGroup may appear.
690    * 
691    * @return the maximum number of occurances that this ContentModelGroup may appear. A non positive
692    *         (n < 1) value indicates that the value is unspecified (ie. unbounded).
693    */
694   public int getMaxOccurs() {
695 
696     if (_contentModel.getParticleCount() > 0) {
697       Particle particle = _contentModel.getParticle(0);
698       if (particle instanceof ContentModelGroup) {
699         return particle.getMaxOccurs();
700       }
701     }
702 
703     return _contentModel.getMaxOccurs();
704   } // -- getMaxOccurs
705 
706   /**
707    * Returns the minimum number of occurances that this ContentModelGroup must appear.
708    * 
709    * @return the minimum number of occurances that this ContentModelGroup must appear A negative (n
710    *         < 0) value indicates that the value is unspecified.
711    */
712   public int getMinOccurs() {
713     if (_contentModel.getParticleCount() > 0) {
714       Particle particle = _contentModel.getParticle(0);
715       if (particle instanceof ContentModelGroup) {
716         return particle.getMinOccurs();
717       }
718     }
719     return _contentModel.getMinOccurs();
720   } // -- getMinOccurs
721 
722   /**
723    * Returns the Particle at the specified index
724    * 
725    * @param index the index of the particle to return
726    * @return the CMParticle at the specified index
727    */
728   public Particle getParticle(final int index) {
729     Particle result = _contentModel.getParticle(index);
730     return result;
731   } // -- getParticle
732 
733   /**
734    * Returns the number of particles contained within this ContentModelGroup.
735    * 
736    * @return the number of particles
737    */
738   public int getParticleCount() {
739     return _contentModel.getParticleCount();
740   } // -- getParticleCount
741 
742   // -------------------------------/
743   // - Implementation of Structure -/
744   // -------------------------------/
745 
746   /**
747    * Returns the type of this Schema Structure.
748    * 
749    * @return the type of this Schema Structure
750    */
751   public short getStructureType() {
752     return Structure.COMPLEX_TYPE;
753   } // -- getStructureType
754 
755   /**
756    * Checks the validity of this ComplexType defintion.
757    * 
758    * @throws ValidationException when this ComplexType definition is invalid.
759    */
760   public void validate() throws ValidationException {
761     // -- check name
762     if (_parent != null && _parent.getStructureType() != Structure.SCHEMA) {
763       if (getName() != null) {
764         String err = "Only top-level complexTypes can be named.";
765         err += getName() + "is not a valid complexType.";
766         throw new ValidationException(err);
767       }
768     }
769     // -- check attributes
770     _attributes.validate();
771 
772     // -- check content model
773     Enumeration<Particle> enumeration = _contentModel.enumerate();
774     while (enumeration.hasMoreElements()) {
775       enumeration.nextElement().validate();
776     }
777 
778     // -- make sure baseType is accessible
779     XMLType type = getBaseType();
780     if ((type == null) && (_baseType != null)) {
781       String error = "The base type '" + _baseType + "' was not found.";
782       throw new ValidationException(error);
783     }
784     if (type != null) {
785       if (type.getStructureType() == Structure.SIMPLE_TYPE) {
786         if (_restricted) {
787           String name = getName();
788           if (name == null) {
789             name = "anonymous-complexType-for-element: ";
790             if (_parent != null) {
791               // -- parent should be an element if name is null,
792               // but
793               // -- we'll check the type to be on the safe side
794               if (_parent.getStructureType() == Structure.ELEMENT) {
795                 name += ((ElementDecl) _parent).getName();
796               } else {
797                 name += _parent.toString();
798               }
799             }
800           }
801           String err = "complexType: " + name;
802           err += "; A complex type cannot be a restriction" + " of a simpleType:";
803           err += type.getName();
804           throw new ValidationException(err);
805         }
806       } else if (type.getStructureType() == Structure.COMPLEX_TYPE) {
807 
808         if (!_complexContent) {
809           // we are now sure that the base is a ComplexType
810           // but is the base of this complexType a simpleType? (see
811           // 4.3.3->simpleContent->content type)
812           if (((ComplexType) type).getContentType().getType() != ContentType.SIMPLE) {
813             String name = getName();
814             if (name == null) {
815               name = "anonymous-complexType-for-element: ";
816               if (_parent != null) {
817                 // -- parent should be an element if name is
818                 // null, but
819                 // -- we'll check the type to be on the safe
820                 // side
821                 if (_parent.getStructureType() == Structure.ELEMENT) {
822                   name += ((ElementDecl) _parent).getName();
823                 } else {
824                   name += _parent.toString();
825                 }
826               }
827             }
828             String err = "complexType: " + name;
829             err += "; When a complexType is a restriction of simpleContent the base type"
830                 + " must be a complexType whose base is also simpleContent.";
831             throw new ValidationException(err);
832           }
833         }
834       }
835     }
836 
837   } // -- validate
838 
839   // ---------------------/
840   // - Protected Methods -/
841   // ---------------------/
842 
843   /**
844    * Sets the parent for this ComplexType.
845    * 
846    * @param parent the parent Structure for this ComplexType
847    */
848   protected void setParent(final Structure parent) {
849     if (parent != null) {
850       switch (parent.getStructureType()) {
851         case Structure.SCHEMA:
852         case Structure.ELEMENT:
853           break;
854         default:
855           String error = "Invalid parent for ComplexType";
856           throw new IllegalArgumentException(error);
857       }
858     }
859     _parent = parent;
860   } // -- setParent
861 
862   /**
863    * @return true if the content model for this ComplexType is emptiable.
864    */
865   public boolean isEmptiable() {
866     switch (getParticleCount()) {
867       case 0:
868         return true;
869       case 1:
870         Particle p = getParticle(0);
871         if (p.isEmptiable()) {
872           if ((_baseType != null) && !isRestricted()) {
873             // derived by extension
874             XMLType baseType = getBaseType();
875             if ((baseType != null) && baseType.isComplexType()
876                 && ((ComplexType) baseType).isEmptiable()) {
877               return true;
878             }
879           } else {
880             // derived by restriction (explicit or shorthand from
881             // xs:anyType
882             return true;
883           }
884         }
885         break;
886     }
887     return false;
888   }
889 
890 } // -- Complextype