1 /*
   2  * Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
   3  */
   4 /*
   5  * Licensed to the Apache Software Foundation (ASF) under one or more
   6  * contributor license agreements.  See the NOTICE file distributed with
   7  * this work for additional information regarding copyright ownership.
   8  * The ASF licenses this file to You under the Apache License, Version 2.0
   9  * (the "License"); you may not use this file except in compliance with
  10  * the License.  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.models;
  22 
  23 import com.sun.org.apache.xerces.internal.impl.xs.SubstitutionGroupHandler;
  24 import com.sun.org.apache.xerces.internal.impl.xs.XMLSchemaException;
  25 import com.sun.org.apache.xerces.internal.impl.xs.XSConstraints;
  26 import com.sun.org.apache.xerces.internal.impl.xs.XSElementDecl;
  27 import com.sun.org.apache.xerces.internal.xni.QName;
  28 import java.util.ArrayList;
  29 import java.util.List;
  30 
  31 /**
  32  * XSAllCM implements XSCMValidator and handles <all>.
  33  *
  34  * @xerces.internal
  35  *
  36  * @author Pavani Mukthipudi, Sun Microsystems Inc.
  37  * @LastModified: Oct 2017
  38  */
  39 public class XSAllCM implements XSCMValidator {
  40 
  41     //
  42     // Constants
  43     //
  44 
  45     // start the content model: did not see any children
  46     private static final short STATE_START = 0;
  47     private static final short STATE_VALID = 1;
  48     private static final short STATE_CHILD = 1;
  49 
  50 
  51     //
  52     // Data
  53     //
  54 
  55     private XSElementDecl fAllElements[];
  56     private boolean fIsOptionalElement[];
  57     private boolean fHasOptionalContent = false;
  58     private int fNumElements = 0;
  59 
  60     //
  61     // Constructors
  62     //
  63 
  64     public XSAllCM (boolean hasOptionalContent, int size) {
  65         fHasOptionalContent = hasOptionalContent;
  66         fAllElements = new XSElementDecl[size];
  67         fIsOptionalElement = new boolean[size];
  68     }
  69 
  70     public void addElement (XSElementDecl element, boolean isOptional) {
  71         fAllElements[fNumElements] = element;
  72         fIsOptionalElement[fNumElements] = isOptional;
  73         fNumElements++;
  74     }
  75 
  76 
  77     //
  78     // XSCMValidator methods
  79     //
  80 
  81     /**
  82      * This methods to be called on entering a first element whose type
  83      * has this content model. It will return the initial state of the
  84      * content model
  85      *
  86      * @return Start state of the content model
  87      */
  88     public int[] startContentModel() {
  89 
  90         int[] state = new int[fNumElements + 1];
  91 
  92         for (int i = 0; i <= fNumElements; i++) {
  93             state[i] = STATE_START;
  94         }
  95         return state;
  96     }
  97 
  98     // convinient method: when error occurs, to find a matching decl
  99     // from the candidate elements.
 100     Object findMatchingDecl(QName elementName, SubstitutionGroupHandler subGroupHandler) {
 101         Object matchingDecl = null;
 102         for (int i = 0; i < fNumElements; i++) {
 103             matchingDecl = subGroupHandler.getMatchingElemDecl(elementName, fAllElements[i]);
 104             if (matchingDecl != null)
 105                 break;
 106         }
 107         return matchingDecl;
 108     }
 109 
 110     /**
 111      * The method corresponds to one transition in the content model.
 112      *
 113      * @param elementName
 114      * @param currentState  Current state
 115      * @return an element decl object
 116      */
 117     public Object oneTransition (QName elementName, int[] currentState, SubstitutionGroupHandler subGroupHandler) {
 118 
 119         // error state
 120         if (currentState[0] < 0) {
 121             currentState[0] = XSCMValidator.SUBSEQUENT_ERROR;
 122             return findMatchingDecl(elementName, subGroupHandler);
 123         }
 124 
 125         // seen child
 126         currentState[0] = STATE_CHILD;
 127 
 128         Object matchingDecl = null;
 129 
 130         for (int i = 0; i < fNumElements; i++) {
 131             // we only try to look for a matching decl if we have not seen
 132             // this element yet.
 133             if (currentState[i+1] != STATE_START)
 134                 continue;
 135             matchingDecl = subGroupHandler.getMatchingElemDecl(elementName, fAllElements[i]);
 136             if (matchingDecl != null) {
 137                 // found the decl, mark this element as "seen".
 138                 currentState[i+1] = STATE_VALID;
 139                 return matchingDecl;
 140             }
 141         }
 142 
 143         // couldn't find the decl, change to error state.
 144         currentState[0] = XSCMValidator.FIRST_ERROR;
 145         return findMatchingDecl(elementName, subGroupHandler);
 146     }
 147 
 148 
 149     /**
 150      * The method indicates the end of list of children
 151      *
 152      * @param currentState  Current state of the content model
 153      * @return true if the last state was a valid final state
 154      */
 155     public boolean endContentModel (int[] currentState) {
 156 
 157         int state = currentState[0];
 158 
 159         if (state == XSCMValidator.FIRST_ERROR || state == XSCMValidator.SUBSEQUENT_ERROR) {
 160             return false;
 161         }
 162 
 163         // If <all> has minOccurs of zero and there are
 164         // no children to validate, it is trivially valid
 165         if (fHasOptionalContent && state == STATE_START) {
 166             return true;
 167         }
 168 
 169         for (int i = 0; i < fNumElements; i++) {
 170             // if one element is required, but not present, then error
 171             if (!fIsOptionalElement[i] && currentState[i+1] == STATE_START)
 172                 return false;
 173         }
 174 
 175         return true;
 176     }
 177 
 178     /**
 179      * check whether this content violates UPA constraint.
 180      *
 181      * @param subGroupHandler the substitution group handler
 182      * @return true if this content model contains other or list wildcard
 183      */
 184     public boolean checkUniqueParticleAttribution(SubstitutionGroupHandler subGroupHandler) throws XMLSchemaException {
 185         // check whether there is conflict between any two leaves
 186         for (int i = 0; i < fNumElements; i++) {
 187             for (int j = i+1; j < fNumElements; j++) {
 188                 if (XSConstraints.overlapUPA(fAllElements[i], fAllElements[j], subGroupHandler)) {
 189                     // REVISIT: do we want to report all errors? or just one?
 190                     throw new XMLSchemaException("cos-nonambig", new Object[]{fAllElements[i].toString(),
 191                                                                               fAllElements[j].toString()});
 192                 }
 193             }
 194         }
 195 
 196         return false;
 197     }
 198 
 199     /**
 200      * Check which elements are valid to appear at this point. This method also
 201      * works if the state is in error, in which case it returns what should
 202      * have been seen.
 203      *
 204      * @param state  the current state
 205      * @return       a list whose entries are instances of
 206      *               either XSWildcardDecl or XSElementDecl.
 207      */
 208     public List<Object> whatCanGoHere(int[] state) {
 209         List<Object> ret = new ArrayList<>();
 210         for (int i = 0; i < fNumElements; i++) {
 211             // we only try to look for a matching decl if we have not seen
 212             // this element yet.
 213             if (state[i+1] == STATE_START) {
 214                 ret.add(fAllElements[i]);
 215             }
 216         }
 217         return ret;
 218     }
 219 
 220     public List<String> checkMinMaxBounds() {
 221         return null;
 222     }
 223 
 224     public int [] occurenceInfo(int[] state) {
 225         return null;
 226     }
 227 
 228     public String getTermName(int termId) {
 229         return null;
 230     }
 231 
 232     public boolean isCompactedForUPA() {
 233         return false;
 234     }
 235 } // class XSAllCM