1 /*
   2  * reserved comment block
   3  * DO NOT REMOVE OR ALTER!
   4  */
   5 /*
   6  * Copyright 2001-2004 The Apache Software Foundation.
   7  *
   8  * Licensed under the Apache License, Version 2.0 (the "License");
   9  * you may not use this file except in compliance with the License.
  10  * You may obtain a copy of the License at
  11  *
  12  *      http://www.apache.org/licenses/LICENSE-2.0
  13  *
  14  * Unless required by applicable law or agreed to in writing, software
  15  * distributed under the License is distributed on an "AS IS" BASIS,
  16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17  * See the License for the specific language governing permissions and
  18  * limitations under the License.
  19  */
  20 
  21 package com.sun.org.apache.xerces.internal.impl.xs.traversers;
  22 
  23 import com.sun.org.apache.xerces.internal.impl.xs.SchemaGrammar;
  24 import com.sun.org.apache.xerces.internal.impl.xs.SchemaSymbols;
  25 import com.sun.org.apache.xerces.internal.impl.xs.XSAnnotationImpl;
  26 import com.sun.org.apache.xerces.internal.impl.xs.XSModelGroupImpl;
  27 import com.sun.org.apache.xerces.internal.impl.xs.XSParticleDecl;
  28 import com.sun.org.apache.xerces.internal.impl.xs.util.XInt;
  29 import com.sun.org.apache.xerces.internal.impl.xs.util.XSObjectListImpl;
  30 import com.sun.org.apache.xerces.internal.util.DOMUtil;
  31 import com.sun.org.apache.xerces.internal.xs.XSObject;
  32 import com.sun.org.apache.xerces.internal.xs.XSObjectList;
  33 import org.w3c.dom.Element;
  34 
  35 /**
  36  * @xerces.internal
  37  *
  38  * @author Elena Litani, IBM
  39  * @author Sandy Gao, IBM
  40  */
  41 abstract class XSDAbstractParticleTraverser extends XSDAbstractTraverser {
  42 
  43     XSDAbstractParticleTraverser (XSDHandler handler,
  44             XSAttributeChecker gAttrCheck) {
  45         super(handler, gAttrCheck);
  46     }
  47 
  48     /**
  49      *
  50      * Traverse the "All" declaration
  51      *
  52      * <all
  53      *   id = ID
  54      *   maxOccurs = 1 : 1
  55      *   minOccurs = (0 | 1) : 1>
  56      *   Content: (annotation? , element*)
  57      * </all>
  58      **/
  59     XSParticleDecl traverseAll(Element allDecl,
  60             XSDocumentInfo schemaDoc,
  61             SchemaGrammar grammar,
  62             int allContextFlags,
  63             XSObject parent) {
  64 
  65         // General Attribute Checking
  66 
  67         Object[] attrValues = fAttrChecker.checkAttributes(allDecl, false, schemaDoc);
  68 
  69         Element child = DOMUtil.getFirstChildElement(allDecl);
  70 
  71         XSAnnotationImpl annotation = null;
  72         if (child !=null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
  73             annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc);
  74             child = DOMUtil.getNextSiblingElement(child);
  75         }
  76         else {
  77             String text = DOMUtil.getSyntheticAnnotation(allDecl);
  78             if (text != null) {
  79                 annotation = traverseSyntheticAnnotation(allDecl, text, attrValues, false, schemaDoc);
  80             }
  81         }
  82         String childName = null;
  83         XSParticleDecl particle;
  84         fPArray.pushContext();
  85 
  86         for (; child != null; child = DOMUtil.getNextSiblingElement(child)) {
  87 
  88             particle = null;
  89             childName = DOMUtil.getLocalName(child);
  90 
  91             // Only elements are allowed in <all>
  92             if (childName.equals(SchemaSymbols.ELT_ELEMENT)) {
  93                 particle = fSchemaHandler.fElementTraverser.traverseLocal(child, schemaDoc, grammar, PROCESSING_ALL_EL, parent);
  94             }
  95             else {
  96                 Object[] args = {"all", "(annotation?, element*)", DOMUtil.getLocalName(child)};
  97                 reportSchemaError("s4s-elt-must-match.1", args, child);
  98             }
  99 
 100             if (particle != null)
 101                 fPArray.addParticle(particle);
 102         }
 103 
 104         particle = null;
 105         XInt minAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MINOCCURS];
 106         XInt maxAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS];
 107         Long defaultVals = (Long)attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT];
 108 
 109         XSModelGroupImpl group = new XSModelGroupImpl();
 110         group.fCompositor = XSModelGroupImpl.MODELGROUP_ALL;
 111         group.fParticleCount = fPArray.getParticleCount();
 112         group.fParticles = fPArray.popContext();
 113         XSObjectList annotations;
 114         if (annotation != null) {
 115             annotations = new XSObjectListImpl();
 116             ((XSObjectListImpl)annotations).addXSObject (annotation);
 117         } else {
 118             annotations = XSObjectListImpl.EMPTY_LIST;
 119         }
 120         group.fAnnotations = annotations;
 121         particle = new XSParticleDecl();
 122         particle.fType = XSParticleDecl.PARTICLE_MODELGROUP;
 123         particle.fMinOccurs = minAtt.intValue();
 124         particle.fMaxOccurs = maxAtt.intValue();
 125         particle.fValue = group;
 126         particle.fAnnotations = annotations;
 127 
 128         particle = checkOccurrences(particle,
 129                 SchemaSymbols.ELT_ALL,
 130                 (Element)allDecl.getParentNode(),
 131                 allContextFlags,
 132                 defaultVals.longValue());
 133         fAttrChecker.returnAttrArray(attrValues, schemaDoc);
 134 
 135         return particle;
 136     }
 137 
 138     /**
 139      * Traverse the Sequence declaration
 140      *
 141      * <sequence
 142      *   id = ID
 143      *   maxOccurs = string
 144      *   minOccurs = nonNegativeInteger>
 145      *   Content: (annotation? , (element | group | choice | sequence | any)*)
 146      * </sequence>
 147      *
 148      * @param seqDecl
 149      * @param schemaDoc
 150      * @param grammar
 151      * @return
 152      */
 153     XSParticleDecl traverseSequence(Element seqDecl,
 154             XSDocumentInfo schemaDoc,
 155             SchemaGrammar grammar,
 156             int allContextFlags,
 157             XSObject parent) {
 158 
 159         return traverseSeqChoice(seqDecl, schemaDoc, grammar, allContextFlags, false, parent);
 160     }
 161 
 162     /**
 163      * Traverse the Choice declaration
 164      *
 165      * <choice
 166      *   id = ID
 167      *   maxOccurs = string
 168      *   minOccurs = nonNegativeInteger>
 169      *   Content: (annotation? , (element | group | choice | sequence | any)*)
 170      * </choice>
 171      *
 172      * @param choiceDecl
 173      * @param schemaDoc
 174      * @param grammar
 175      * @return
 176      */
 177     XSParticleDecl traverseChoice(Element choiceDecl,
 178             XSDocumentInfo schemaDoc,
 179             SchemaGrammar grammar,
 180             int allContextFlags,
 181             XSObject parent) {
 182 
 183         return traverseSeqChoice (choiceDecl, schemaDoc, grammar, allContextFlags, true, parent);
 184     }
 185 
 186     /**
 187      * Common traversal for <choice> and <sequence>
 188      *
 189      * @param decl
 190      * @param schemaDoc
 191      * @param grammar
 192      * @param choice    If traversing <choice> this parameter is true.
 193      * @return
 194      */
 195     private XSParticleDecl traverseSeqChoice(Element decl,
 196             XSDocumentInfo schemaDoc,
 197             SchemaGrammar grammar,
 198             int allContextFlags,
 199             boolean choice,
 200             XSObject parent) {
 201 
 202         // General Attribute Checking
 203         Object[] attrValues = fAttrChecker.checkAttributes(decl, false, schemaDoc);
 204 
 205         Element child = DOMUtil.getFirstChildElement(decl);
 206         XSAnnotationImpl annotation = null;
 207         if (child !=null && DOMUtil.getLocalName(child).equals(SchemaSymbols.ELT_ANNOTATION)) {
 208             annotation = traverseAnnotationDecl(child, attrValues, false, schemaDoc);
 209             child = DOMUtil.getNextSiblingElement(child);
 210         }
 211         else {
 212             String text = DOMUtil.getSyntheticAnnotation(decl);
 213             if (text != null) {
 214                 annotation = traverseSyntheticAnnotation(decl, text, attrValues, false, schemaDoc);
 215             }
 216         }
 217 
 218         String childName = null;
 219         XSParticleDecl particle;
 220         fPArray.pushContext();
 221 
 222         for (;child != null;child = DOMUtil.getNextSiblingElement(child)) {
 223 
 224             particle = null;
 225 
 226             childName = DOMUtil.getLocalName(child);
 227             if (childName.equals(SchemaSymbols.ELT_ELEMENT)) {
 228                 particle = fSchemaHandler.fElementTraverser.traverseLocal(child, schemaDoc, grammar, NOT_ALL_CONTEXT, parent);
 229             }
 230             else if (childName.equals(SchemaSymbols.ELT_GROUP)) {
 231                 particle = fSchemaHandler.fGroupTraverser.traverseLocal(child, schemaDoc, grammar);
 232 
 233                 // A content type of all can only appear
 234                 // as the content type of a complex type definition.
 235                 if (hasAllContent(particle)) {
 236                     // don't insert the "all" particle, otherwise we won't be
 237                     // able to create DFA from this content model
 238                     particle = null;
 239                     reportSchemaError("cos-all-limited.1.2", null, child);
 240                 }
 241 
 242             }
 243             else if (childName.equals(SchemaSymbols.ELT_CHOICE)) {
 244                 particle = traverseChoice(child, schemaDoc, grammar, NOT_ALL_CONTEXT, parent);
 245             }
 246             else if (childName.equals(SchemaSymbols.ELT_SEQUENCE)) {
 247                 particle = traverseSequence(child, schemaDoc, grammar, NOT_ALL_CONTEXT, parent);
 248             }
 249             else if (childName.equals(SchemaSymbols.ELT_ANY)) {
 250                 particle = fSchemaHandler.fWildCardTraverser.traverseAny(child, schemaDoc, grammar);
 251             }
 252             else {
 253                 Object [] args;
 254                 if (choice) {
 255                     args = new Object[]{"choice", "(annotation?, (element | group | choice | sequence | any)*)", DOMUtil.getLocalName(child)};
 256                 }
 257                 else {
 258                     args = new Object[]{"sequence", "(annotation?, (element | group | choice | sequence | any)*)", DOMUtil.getLocalName(child)};
 259                 }
 260                 reportSchemaError("s4s-elt-must-match.1", args, child);
 261             }
 262 
 263             if (particle != null)
 264                 fPArray.addParticle(particle);
 265         }
 266 
 267         particle = null;
 268 
 269         XInt minAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MINOCCURS];
 270         XInt maxAtt = (XInt)attrValues[XSAttributeChecker.ATTIDX_MAXOCCURS];
 271         Long defaultVals = (Long)attrValues[XSAttributeChecker.ATTIDX_FROMDEFAULT];
 272 
 273         XSModelGroupImpl group = new XSModelGroupImpl();
 274         group.fCompositor = choice ? XSModelGroupImpl.MODELGROUP_CHOICE : XSModelGroupImpl.MODELGROUP_SEQUENCE;
 275         group.fParticleCount = fPArray.getParticleCount();
 276         group.fParticles = fPArray.popContext();
 277         XSObjectList annotations;
 278         if (annotation != null) {
 279             annotations = new XSObjectListImpl();
 280             ((XSObjectListImpl)annotations).addXSObject (annotation);
 281         } else {
 282             annotations = XSObjectListImpl.EMPTY_LIST;
 283         }
 284         group.fAnnotations = annotations;
 285         particle = new XSParticleDecl();
 286         particle.fType = XSParticleDecl.PARTICLE_MODELGROUP;
 287         particle.fMinOccurs = minAtt.intValue();
 288         particle.fMaxOccurs = maxAtt.intValue();
 289         particle.fValue = group;
 290         particle.fAnnotations = annotations;
 291 
 292         particle = checkOccurrences(particle,
 293                 choice ? SchemaSymbols.ELT_CHOICE : SchemaSymbols.ELT_SEQUENCE,
 294                         (Element)decl.getParentNode(),
 295                         allContextFlags,
 296                         defaultVals.longValue());
 297         fAttrChecker.returnAttrArray(attrValues, schemaDoc);
 298 
 299         return particle;
 300     }
 301 
 302     // Determines whether a content spec tree represents an "all" content model
 303     protected boolean hasAllContent(XSParticleDecl particle) {
 304         // If the content is not empty, is the top node ALL?
 305         if (particle != null && particle.fType == XSParticleDecl.PARTICLE_MODELGROUP) {
 306             return ((XSModelGroupImpl)particle.fValue).fCompositor == XSModelGroupImpl.MODELGROUP_ALL;
 307         }
 308 
 309         return false;
 310     }
 311 
 312     // the inner class: used to store particles for model groups
 313     // to avoid creating a new Vector in each model group, or when traversing
 314     // each model group, we use this one big array to store all particles
 315     // for model groups. when the traversal finishes, this class returns an
 316     // XSParticleDecl[] containing all particles for the current model group.
 317     // it's possible that we need to traverse another model group while
 318     // traversing one (one inside another one; referring to a global group,
 319     // etc.), so we have push/pos context methods to save the same of the
 320     // current traversal before starting the traversal of another model group.
 321     protected static class ParticleArray {
 322         // big array to contain all particles
 323         XSParticleDecl[] fParticles = new XSParticleDecl[10];
 324         // the ending position of particles in the array for each context
 325         // index 0 is reserved, with value 0. index 1 is used for the fist
 326         // context. so that the number of particles for context 'i' can be
 327         // computed simply by fPos[i] - fPos[i-1].
 328         int[] fPos = new int[5];
 329         // number of contexts
 330         int fContextCount = 0;
 331 
 332         // start a new context (start traversing a new model group)
 333         void pushContext() {
 334             fContextCount++;
 335             // resize position array if necessary
 336             if (fContextCount == fPos.length) {
 337                 int newSize = fContextCount * 2;
 338                 int[] newArray = new int[newSize];
 339                 System.arraycopy(fPos, 0, newArray, 0, fContextCount);
 340                 fPos = newArray;
 341             }
 342             // the initial ending position of the current context is the
 343             // ending position of the previsous context. which means there is
 344             // no particle for the current context yet.
 345             fPos[fContextCount] = fPos[fContextCount-1];
 346         }
 347 
 348         // get the number of particles of this context (model group)
 349         int getParticleCount() {
 350             return fPos[fContextCount] - fPos[fContextCount-1];
 351         }
 352 
 353         // add a particle to the current context
 354         void addParticle(XSParticleDecl particle) {
 355             // resize the particle array if necessary
 356             if (fPos[fContextCount] == fParticles.length) {
 357                 int newSize = fPos[fContextCount] * 2;
 358                 XSParticleDecl[] newArray = new XSParticleDecl[newSize];
 359                 System.arraycopy(fParticles, 0, newArray, 0, fPos[fContextCount]);
 360                 fParticles = newArray;
 361             }
 362             fParticles[fPos[fContextCount]++] = particle;
 363         }
 364 
 365         // end the current context, and return an array of particles
 366         XSParticleDecl[] popContext() {
 367             int count = fPos[fContextCount] - fPos[fContextCount-1];
 368             XSParticleDecl[] array = null;
 369             if (count != 0) {
 370                 array = new XSParticleDecl[count];
 371                 System.arraycopy(fParticles, fPos[fContextCount-1], array, 0, count);
 372                 // clear the particle array, to release memory
 373                 for (int i = fPos[fContextCount-1]; i < fPos[fContextCount]; i++)
 374                     fParticles[i] = null;
 375             }
 376             fContextCount--;
 377             return array;
 378         }
 379 
 380     }
 381 
 382     // the big particle array to hold all particles in model groups
 383     ParticleArray fPArray = new ParticleArray();
 384 }