1 /*
2  * reserved comment block
3  * DO NOT REMOVE OR ALTER!
4  */
5 /*
6  * Licensed to the Apache Software Foundation (ASF) under one or more
7  * contributor license agreements.  See the NOTICE file distributed with
8  * this work for additional information regarding copyright ownership.
9  * The ASF licenses this file to You under the Apache License, Version 2.0
10  * (the "License"); you may not use this file except in compliance with
11  * the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 package com.sun.org.apache.xerces.internal.impl.xs.identity;
23 
24 import com.sun.org.apache.xerces.internal.impl.xpath.XPathException;
25 import com.sun.org.apache.xerces.internal.impl.xs.util.ShortListImpl;
26 import com.sun.org.apache.xerces.internal.util.SymbolTable;
27 import com.sun.org.apache.xerces.internal.util.XMLChar;
28 import com.sun.org.apache.xerces.internal.xni.NamespaceContext;
29 import com.sun.org.apache.xerces.internal.xs.ShortList;
30 import com.sun.org.apache.xerces.internal.xs.XSComplexTypeDefinition;
31 import com.sun.org.apache.xerces.internal.xs.XSConstants;
32 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
33 
34 /**
35  * Schema identity constraint field.
36  *
37  * @xerces.internal
38  *
39  * @author Andy Clark, IBM
40  */
41 public class Field {
42 
43     //
44     // Data
45     //
46 
47     /** Field XPath. */
48     protected final Field.XPath fXPath;
49 
50 
51     /** Identity constraint. */
52     protected final IdentityConstraint fIdentityConstraint;
53 
54     //
55     // Constructors
56     //
57 
58     /** Constructs a field. */
Field(Field.XPath xpath, IdentityConstraint identityConstraint)59     public Field(Field.XPath xpath,
60                  IdentityConstraint identityConstraint) {
61         fXPath = xpath;
62         fIdentityConstraint = identityConstraint;
63     } // <init>(Field.XPath,IdentityConstraint)
64 
65     //
66     // Public methods
67     //
68 
69     /** Returns the field XPath. */
getXPath()70     public com.sun.org.apache.xerces.internal.impl.xpath.XPath getXPath() {
71         return fXPath;
72     } // getXPath():org.apache.xerces.impl.v1.schema.identity.XPath
73 
74     /** Returns the identity constraint. */
getIdentityConstraint()75     public IdentityConstraint getIdentityConstraint() {
76         return fIdentityConstraint;
77     } // getIdentityConstraint():IdentityConstraint
78 
79     // factory method
80 
81     /** Creates a field matcher. */
createMatcher(ValueStore store)82     public XPathMatcher createMatcher(ValueStore store) {
83         return new Field.Matcher(fXPath, store);
84     } // createMatcher(ValueStore):XPathMatcher
85 
86     //
87     // Object methods
88     //
89 
90     /** Returns a string representation of this object. */
toString()91     public String toString() {
92         return fXPath.toString();
93     } // toString():String
94 
95     //
96     // Classes
97     //
98 
99     /**
100      * Field XPath.
101      *
102      * @author Andy Clark, IBM
103      */
104     public static class XPath
105         extends com.sun.org.apache.xerces.internal.impl.xpath.XPath {
106 
107         //
108         // Constructors
109         //
110 
111         /** Constructs a field XPath expression. */
XPath(String xpath, SymbolTable symbolTable, NamespaceContext context)112         public XPath(String xpath,
113                      SymbolTable symbolTable,
114                      NamespaceContext context) throws XPathException {
115             super(fixupXPath(xpath), symbolTable, context);
116 
117             // verify that only one attribute is selected per branch
118             for (int i=0;i<fLocationPaths.length;i++) {
119                 for(int j=0; j<fLocationPaths[i].steps.length; j++) {
120                     com.sun.org.apache.xerces.internal.impl.xpath.XPath.Axis axis =
121                         fLocationPaths[i].steps[j].axis;
122                     if (axis.type == XPath.Axis.ATTRIBUTE &&
123                             (j < fLocationPaths[i].steps.length-1)) {
124                         throw new XPathException("c-fields-xpaths");
125                     }
126                 }
127             }
128         } // <init>(String,SymbolTable,NamespacesContext)
129 
130         /** Fixup XPath expression. Avoid creating a new String if possible. */
fixupXPath(String xpath)131         private static String fixupXPath(String xpath) {
132 
133             final int end = xpath.length();
134             int offset = 0;
135             boolean whitespace = true;
136             char c;
137 
138             // NOTE: We have to prefix the field XPath with "./" in
139             //       order to handle selectors such as "@attr" that
140             //       select the attribute because the fields could be
141             //       relative to the selector element. -Ac
142             //       Unless xpath starts with a descendant node -Achille Fokoue
143             //      ... or a / or a . - NG
144             for (; offset < end; ++offset) {
145                 c = xpath.charAt(offset);
146                 if (whitespace) {
147                     if (!XMLChar.isSpace(c)) {
148                         if (c == '.' || c == '/') {
149                             whitespace = false;
150                         }
151                         else if (c != '|') {
152                             return fixupXPath2(xpath, offset, end);
153                         }
154                     }
155                 }
156                 else if (c == '|') {
157                     whitespace = true;
158                 }
159             }
160             return xpath;
161 
162         } // fixupXPath(String):String
163 
fixupXPath2(String xpath, int offset, final int end)164         private static String fixupXPath2(String xpath, int offset, final int end) {
165 
166             StringBuffer buffer = new StringBuffer(end + 2);
167             for (int i = 0; i < offset; ++i) {
168                 buffer.append(xpath.charAt(i));
169             }
170             buffer.append("./");
171 
172             boolean whitespace = false;
173             char c;
174 
175             for (; offset < end; ++offset) {
176                 c = xpath.charAt(offset);
177                 if (whitespace) {
178                     if (!XMLChar.isSpace(c)) {
179                         if (c == '.' || c == '/') {
180                             whitespace = false;
181                         }
182                         else if (c != '|') {
183                             buffer.append("./");
184                             whitespace = false;
185                         }
186                     }
187                 }
188                 else if (c == '|') {
189                     whitespace = true;
190                 }
191                 buffer.append(c);
192             }
193             return buffer.toString();
194 
195         } // fixupXPath2(String, int, int):String
196 
197     } // class XPath
198 
199     /**
200      * Field matcher.
201      *
202      * @author Andy Clark, IBM
203      */
204     protected class Matcher
205         extends XPathMatcher {
206 
207         //
208         // Data
209         //
210 
211         /** Value store for data values. */
212         protected final ValueStore fStore;
213 
214         /** A flag indicating whether the field is allowed to match a value. */
215         protected boolean fMayMatch = true;
216 
217         //
218         // Constructors
219         //
220 
221         /** Constructs a field matcher. */
Matcher(Field.XPath xpath, ValueStore store)222         public Matcher(Field.XPath xpath, ValueStore store) {
223             super(xpath);
224             fStore = store;
225         } // <init>(Field.XPath,ValueStore)
226 
227         //
228         // XPathHandler methods
229         //
230 
231         /**
232          * This method is called when the XPath handler matches the
233          * XPath expression.
234          */
matched(Object actualValue, short valueType, ShortList itemValueType, boolean isNil)235         protected void matched(Object actualValue, short valueType, ShortList itemValueType, boolean isNil) {
236             super.matched(actualValue, valueType, itemValueType, isNil);
237             if(isNil && (fIdentityConstraint.getCategory() == IdentityConstraint.IC_KEY)) {
238                 String code = "KeyMatchesNillable";
239                 fStore.reportError(code,
240                     new Object[]{fIdentityConstraint.getElementName(), fIdentityConstraint.getIdentityConstraintName()});
241             }
242             fStore.addValue(Field.this, fMayMatch, actualValue, convertToPrimitiveKind(valueType), convertToPrimitiveKind(itemValueType));
243             // once we've stored the value for this field, we set the mayMatch
244             // member to false so that in the same scope, we don't match any more
245             // values (and throw an error instead).
246             fMayMatch = false;
247         } // matched(String)
248 
convertToPrimitiveKind(short valueType)249         private short convertToPrimitiveKind(short valueType) {
250             /** Primitive datatypes. */
251             if (valueType <= XSConstants.NOTATION_DT) {
252                 return valueType;
253             }
254             /** Types derived from string. */
255             if (valueType <= XSConstants.ENTITY_DT) {
256                 return XSConstants.STRING_DT;
257             }
258             /** Types derived from decimal. */
259             if (valueType <= XSConstants.POSITIVEINTEGER_DT) {
260                 return XSConstants.DECIMAL_DT;
261             }
262             /** Other types. */
263             return valueType;
264         }
265 
convertToPrimitiveKind(ShortList itemValueType)266         private ShortList convertToPrimitiveKind(ShortList itemValueType) {
267             if (itemValueType != null) {
268                 int i;
269                 final int length = itemValueType.getLength();
270                 for (i = 0; i < length; ++i) {
271                     short type = itemValueType.item(i);
272                     if (type != convertToPrimitiveKind(type)) {
273                         break;
274                     }
275                 }
276                 if (i != length) {
277                     final short [] arr = new short[length];
278                     for (int j = 0; j < i; ++j) {
279                         arr[j] = itemValueType.item(j);
280                     }
281                     for(; i < length; ++i) {
282                         arr[i] = convertToPrimitiveKind(itemValueType.item(i));
283                     }
284                     return new ShortListImpl(arr, arr.length);
285                 }
286             }
287             return itemValueType;
288         }
289 
handleContent(XSTypeDefinition type, boolean nillable, Object actualValue, short valueType, ShortList itemValueType)290         protected void handleContent(XSTypeDefinition type, boolean nillable, Object actualValue, short valueType, ShortList itemValueType) {
291             if (type == null ||
292                type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE &&
293                ((XSComplexTypeDefinition) type).getContentType()
294                 != XSComplexTypeDefinition.CONTENTTYPE_SIMPLE) {
295 
296                     // the content must be simpleType content
297                     fStore.reportError( "cvc-id.3", new Object[] {
298                             fIdentityConstraint.getName(),
299                             fIdentityConstraint.getElementName()});
300 
301             }
302             fMatchedString = actualValue;
303             matched(fMatchedString, valueType, itemValueType, nillable);
304         } // handleContent(XSElementDecl, String)
305 
306     } // class Matcher
307 
308 } // class Field
309