001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.xerces.impl.xs.models;
019:
020: import org.apache.xerces.xni.QName;
021: import org.apache.xerces.impl.xs.XSElementDecl;
022: import org.apache.xerces.impl.xs.SubstitutionGroupHandler;
023: import org.apache.xerces.impl.xs.XMLSchemaException;
024: import org.apache.xerces.impl.xs.XSConstraints;
025:
026: import java.util.Vector;
027:
028: /**
029: * XSAllCM implements XSCMValidator and handles <all>.
030: *
031: * @xerces.internal
032: *
033: * @author Pavani Mukthipudi, Sun Microsystems Inc.
034: * @version $Id: XSAllCM.java 573322 2007-09-06 16:48:47Z peterjm $
035: */
036: public class XSAllCM implements XSCMValidator {
037:
038: //
039: // Constants
040: //
041:
042: // start the content model: did not see any children
043: private static final short STATE_START = 0;
044: private static final short STATE_VALID = 1;
045: private static final short STATE_CHILD = 1;
046:
047: //
048: // Data
049: //
050:
051: private final XSElementDecl fAllElements[];
052: private final boolean fIsOptionalElement[];
053: private final boolean fHasOptionalContent;
054: private int fNumElements = 0;
055:
056: //
057: // Constructors
058: //
059:
060: public XSAllCM(boolean hasOptionalContent, int size) {
061: fHasOptionalContent = hasOptionalContent;
062: fAllElements = new XSElementDecl[size];
063: fIsOptionalElement = new boolean[size];
064: }
065:
066: public void addElement(XSElementDecl element, boolean isOptional) {
067: fAllElements[fNumElements] = element;
068: fIsOptionalElement[fNumElements] = isOptional;
069: fNumElements++;
070: }
071:
072: //
073: // XSCMValidator methods
074: //
075:
076: /**
077: * This methods to be called on entering a first element whose type
078: * has this content model. It will return the initial state of the
079: * content model
080: *
081: * @return Start state of the content model
082: */
083: public int[] startContentModel() {
084:
085: int[] state = new int[fNumElements + 1];
086:
087: for (int i = 0; i <= fNumElements; i++) {
088: state[i] = STATE_START;
089: }
090: return state;
091: }
092:
093: // convinient method: when error occurs, to find a matching decl
094: // from the candidate elements.
095: Object findMatchingDecl(QName elementName,
096: SubstitutionGroupHandler subGroupHandler) {
097: Object matchingDecl = null;
098: for (int i = 0; i < fNumElements; i++) {
099: matchingDecl = subGroupHandler.getMatchingElemDecl(
100: elementName, fAllElements[i]);
101: if (matchingDecl != null)
102: break;
103: }
104: return matchingDecl;
105: }
106:
107: /**
108: * The method corresponds to one transition in the content model.
109: *
110: * @param elementName
111: * @param currentState Current state
112: * @return an element decl object
113: */
114: public Object oneTransition(QName elementName, int[] currentState,
115: SubstitutionGroupHandler subGroupHandler) {
116:
117: // error state
118: if (currentState[0] < 0) {
119: currentState[0] = XSCMValidator.SUBSEQUENT_ERROR;
120: return findMatchingDecl(elementName, subGroupHandler);
121: }
122:
123: // seen child
124: currentState[0] = STATE_CHILD;
125:
126: Object matchingDecl = null;
127:
128: for (int i = 0; i < fNumElements; i++) {
129: // we only try to look for a matching decl if we have not seen
130: // this element yet.
131: if (currentState[i + 1] != STATE_START)
132: continue;
133: matchingDecl = subGroupHandler.getMatchingElemDecl(
134: elementName, fAllElements[i]);
135: if (matchingDecl != null) {
136: // found the decl, mark this element as "seen".
137: currentState[i + 1] = STATE_VALID;
138: return matchingDecl;
139: }
140: }
141:
142: // couldn't find the decl, change to error state.
143: currentState[0] = XSCMValidator.FIRST_ERROR;
144: return findMatchingDecl(elementName, subGroupHandler);
145: }
146:
147: /**
148: * The method indicates the end of list of children
149: *
150: * @param currentState Current state of the content model
151: * @return true if the last state was a valid final state
152: */
153: public boolean endContentModel(int[] currentState) {
154:
155: int state = currentState[0];
156:
157: if (state == XSCMValidator.FIRST_ERROR
158: || state == XSCMValidator.SUBSEQUENT_ERROR) {
159: return false;
160: }
161:
162: // If <all> has minOccurs of zero and there are
163: // no children to validate, it is trivially valid
164: if (fHasOptionalContent && state == STATE_START) {
165: return true;
166: }
167:
168: for (int i = 0; i < fNumElements; i++) {
169: // if one element is required, but not present, then error
170: if (!fIsOptionalElement[i]
171: && 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(
185: SubstitutionGroupHandler subGroupHandler)
186: throws XMLSchemaException {
187: // check whether there is conflict between any two leaves
188: for (int i = 0; i < fNumElements; i++) {
189: for (int j = i + 1; j < fNumElements; j++) {
190: if (XSConstraints.overlapUPA(fAllElements[i],
191: fAllElements[j], subGroupHandler)) {
192: // REVISIT: do we want to report all errors? or just one?
193: throw new XMLSchemaException("cos-nonambig",
194: new Object[] { fAllElements[i].toString(),
195: fAllElements[j].toString() });
196: }
197: }
198: }
199:
200: return false;
201: }
202:
203: /**
204: * Check which elements are valid to appear at this point. This method also
205: * works if the state is in error, in which case it returns what should
206: * have been seen.
207: *
208: * @param state the current state
209: * @return a Vector whose entries are instances of
210: * either XSWildcardDecl or XSElementDecl.
211: */
212: public Vector whatCanGoHere(int[] state) {
213: Vector ret = new Vector();
214: for (int i = 0; i < fNumElements; i++) {
215: // we only try to look for a matching decl if we have not seen
216: // this element yet.
217: if (state[i + 1] == STATE_START)
218: ret.addElement(fAllElements[i]);
219: }
220: return ret;
221: }
222:
223: public boolean isCompactedForUPA() {
224: return false;
225: }
226: } // class XSAllCM
|