KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xerces > internal > impl > xs > SubstitutionGroupHandler


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Xerces" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation and was
52  * originally based on software copyright (c) 2001, International
53  * Business Machines, Inc., http://www.apache.org. For more
54  * information on the Apache Software Foundation, please see
55  * <http://www.apache.org/>.
56  */

57
58 package com.sun.org.apache.xerces.internal.impl.xs;
59
60 import com.sun.org.apache.xerces.internal.xs.XSConstants;
61 import com.sun.org.apache.xerces.internal.xs.XSTypeDefinition;
62 import com.sun.org.apache.xerces.internal.xni.QName;
63 import java.util.Hashtable JavaDoc;
64 import java.util.Vector JavaDoc;
65
66 /**
67  * To store and validate information about substitutionGroup
68  *
69  * @author Sandy Gao, IBM
70  *
71  * @version $Id: SubstitutionGroupHandler.java,v 1.14 2003/11/11 20:14:58 sandygao Exp $
72  */

73 public class SubstitutionGroupHandler {
74
75     // grammar resolver
76
XSGrammarBucket fGrammarBucket;
77
78     /**
79      * Default constructor
80      */

81     public SubstitutionGroupHandler(XSGrammarBucket grammarBucket) {
82         fGrammarBucket = grammarBucket;
83     }
84
85     // 3.9.4 Element Sequence Locally Valid (Particle) 2.3.3
86
// check whether one element decl matches an element with the given qname
87
public XSElementDecl getMatchingElemDecl(QName element, XSElementDecl exemplar) {
88         if (element.localpart == exemplar.fName &&
89             element.uri == exemplar.fTargetNamespace) {
90             return exemplar;
91         }
92
93         // if the exemplar is not a global element decl, then it's not possible
94
// to be substituted by another element.
95
if (exemplar.fScope != XSConstants.SCOPE_GLOBAL)
96             return null;
97
98         // if the decl blocks substitution, return false
99
if ((exemplar.fBlock & XSConstants.DERIVATION_SUBSTITUTION) != 0)
100             return null;
101
102         // get grammar of the element
103
SchemaGrammar sGrammar = fGrammarBucket.getGrammar(element.uri);
104         if (sGrammar == null)
105             return null;
106
107         // get the decl for the element
108
XSElementDecl eDecl = sGrammar.getGlobalElementDecl(element.localpart);
109         if (eDecl == null)
110             return null;
111
112         // and check by using substitutionGroup information
113
if (substitutionGroupOK(eDecl, exemplar, exemplar.fBlock))
114             return eDecl;
115
116         return null;
117     }
118
119     // 3.3.6 Substitution Group OK (Transitive)
120
// check whether element can substitute exemplar
121
protected boolean substitutionGroupOK(XSElementDecl element, XSElementDecl exemplar, short blockingConstraint) {
122         // For an element declaration (call it D) to be validly substitutable for another element declaration (call it C) subject to a blocking constraint (a subset of {substitution, extension, restriction}, the value of a {disallowed substitutions}) one of the following must be true:
123
// 1. D and C are the same element declaration.
124
if (element == exemplar)
125             return true;
126         
127         // 2 All of the following must be true:
128
// 2.1 The blocking constraint does not contain substitution.
129
if ((blockingConstraint & XSConstants.DERIVATION_SUBSTITUTION) != 0)
130             return false;
131
132         // 2.2 There is a chain of {substitution group affiliation}s from D to C, that is, either D's {substitution group affiliation} is C, or D's {substitution group affiliation}'s {substitution group affiliation} is C, or . . .
133
XSElementDecl subGroup = element.fSubGroup;
134         while (subGroup != null && subGroup != exemplar) {
135             subGroup = subGroup.fSubGroup;
136         }
137
138         if (subGroup == null)
139             return false;
140
141         // 2.3 The set of all {derivation method}s involved in the derivation of D's {type definition} from C's {type definition} does not intersect with the union of the blocking constraint, C's {prohibited substitutions} (if C is complex, otherwise the empty set) and the {prohibited substitutions} (respectively the empty set) of any intermediate {type definition}s in the derivation of D's {type definition} from C's {type definition}.
142
// prepare the combination of {derivation method} and
143
// {disallowed substitution}
144
short devMethod = 0, blockConstraint = blockingConstraint;
145
146         // element.fType should be derived from exemplar.fType
147
// add derivation methods of derived types to devMethod;
148
// add block of base types to blockConstraint.
149
XSTypeDefinition type = element.fType;
150         while (type != exemplar.fType && type != SchemaGrammar.fAnyType) {
151             if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
152                 devMethod |= ((XSComplexTypeDecl)type).fDerivedBy;
153             else
154                 devMethod |= XSConstants.DERIVATION_RESTRICTION;
155             type = type.getBaseType();
156             // type == null means the current type is anySimpleType,
157
// whose base type should be anyType
158
if (type == null)
159                 type = SchemaGrammar.fAnyType;
160             if (type.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
161                 blockConstraint |= ((XSComplexTypeDecl)type).fBlock;
162         }
163         if (type != exemplar.fType)
164             return false;
165         
166         if ((devMethod & blockConstraint) != 0)
167             return false;
168
169         return true;
170     }
171
172     // check whether element is in exemplar's substitution group
173
public boolean inSubstitutionGroup(XSElementDecl element, XSElementDecl exemplar) {
174         // [Definition:] Every element declaration (call this HEAD) in the {element declarations} of a schema defines a substitution group, a subset of those {element declarations}, as follows:
175
// Define PSG, the potential substitution group for HEAD, as follows:
176
// 1 The element declaration itself is in PSG;
177
// 2 PSG is closed with respect to {substitution group affiliation}, that is, if any element declaration in the {element declarations} has a {substitution group affiliation} in PSG, then it is also in PSG itself.
178
// HEAD's actual substitution group is then the set consisting of each member of PSG such that all of the following must be true:
179
// 1 Its {abstract} is false.
180
// 2 It is validly substitutable for HEAD subject to an empty blocking constraint, as defined in Substitution Group OK (Transitive) (3.3.6).
181
return substitutionGroupOK(element, exemplar, exemplar.fBlock);
182     }
183
184     // to store substitution group information
185
// the key to the hashtable is an element decl, and the value is
186
// - a Vector, which contains all elements that has this element as their
187
// substitution group affilication
188
// - an array of OneSubGroup, which contains its substitution group before block.
189
Hashtable JavaDoc fSubGroupsB = new Hashtable JavaDoc();
190     private static final OneSubGroup[] EMPTY_VECTOR = new OneSubGroup[0];
191     // The real substitution groups (after "block")
192
Hashtable JavaDoc fSubGroups = new Hashtable JavaDoc();
193
194     /**
195      * clear the internal registry of substitutionGroup information
196      */

197     public void reset() {
198         fSubGroupsB.clear();
199         fSubGroups.clear();
200     }
201
202     /**
203      * add a list of substitution group information.
204      */

205     public void addSubstitutionGroup(XSElementDecl[] elements) {
206         XSElementDecl subHead, element;
207         Vector JavaDoc subGroup;
208         // for all elements with substitution group affiliation
209
for (int i = elements.length-1; i >= 0; i--) {
210             element = elements[i];
211             subHead = element.fSubGroup;
212             // check whether this an entry for this element
213
subGroup = (Vector JavaDoc)fSubGroupsB.get(subHead);
214             if (subGroup == null) {
215                 // if not, create a new one
216
subGroup = new Vector JavaDoc();
217                 fSubGroupsB.put(subHead, subGroup);
218             }
219             // add to the vactor
220
subGroup.addElement(element);
221         }
222     }
223
224     /**
225      * get all elements that can substitute the given element,
226      * according to the spec, we shouldn't consider the {block} constraints.
227      *
228      * from the spec, substitution group of a given element decl also contains
229      * the element itself. but the array returned from this method doesn't
230      * containt this element.
231      */

232     public XSElementDecl[] getSubstitutionGroup(XSElementDecl element) {
233         // If we already have sub group for this element, just return it.
234
Object JavaDoc subGroup = fSubGroups.get(element);
235         if (subGroup != null)
236             return (XSElementDecl[])subGroup;
237         
238         // Otherwise, get all potential sub group elements
239
// (without considering "block" on this element
240
OneSubGroup[] groupB = getSubGroupB(element, new OneSubGroup());
241         int len = groupB.length, rlen = 0;
242         XSElementDecl[] ret = new XSElementDecl[len];
243         // For each of such elements, check whether the derivation methods
244
// overlap with "block". If not, add it to the sub group
245
for (int i = 0 ; i < len; i++) {
246             if ((element.fBlock & groupB[i].dMethod) == 0)
247                 ret[rlen++] = groupB[i].sub;
248         }
249         // Resize the array if necessary
250
if (rlen < len) {
251             XSElementDecl[] ret1 = new XSElementDecl[rlen];
252             System.arraycopy(ret, 0, ret1, 0, rlen);
253             ret = ret1;
254         }
255         // Store the subgroup
256
fSubGroups.put(element, ret);
257
258         return ret;
259     }
260
261     // Get potential sub group element (without considering "block")
262
private OneSubGroup[] getSubGroupB(XSElementDecl element, OneSubGroup methods) {
263         Object JavaDoc subGroup = fSubGroupsB.get(element);
264
265         // substitution group for this one is empty
266
if (subGroup == null) {
267             fSubGroupsB.put(element, EMPTY_VECTOR);
268             return EMPTY_VECTOR;
269         }
270         
271         // we've already calculated the element, just return.
272
if (subGroup instanceof OneSubGroup[])
273             return (OneSubGroup[])subGroup;
274         
275         // we only have the *direct* substitutions
276
Vector JavaDoc group = (Vector JavaDoc)subGroup, newGroup = new Vector JavaDoc();
277         OneSubGroup[] group1;
278         // then for each of the direct substitutions, get its substitution
279
// group, and combine the groups together.
280
short dMethod, bMethod, dSubMethod, bSubMethod;
281         for (int i = group.size()-1, j; i >= 0; i--) {
282             // Check whether this element is blocked. If so, ignore it.
283
XSElementDecl sub = (XSElementDecl)group.elementAt(i);
284             if (!getDBMethods(sub.fType, element.fType, methods))
285                 continue;
286             // Remember derivation methods and blocks from the types
287
dMethod = methods.dMethod;
288             bMethod = methods.bMethod;
289             // Add this one to potential group
290
newGroup.addElement(new OneSubGroup(sub, methods.dMethod, methods.bMethod));
291             // Get potential group for this element
292
group1 = getSubGroupB(sub, methods);
293             for (j = group1.length-1; j >= 0; j--) {
294                 // For each of them, check whether it's blocked (by type)
295
dSubMethod = (short)(dMethod | group1[j].dMethod);
296                 bSubMethod = (short)(bMethod | group1[j].bMethod);
297                 // Ignore it if it's blocked
298
if ((dSubMethod & bSubMethod) != 0)
299                     continue;
300                 newGroup.addElement(new OneSubGroup(group1[j].sub, dSubMethod, bSubMethod));
301             }
302         }
303         // Convert to an array
304
OneSubGroup[] ret = new OneSubGroup[newGroup.size()];
305         for (int i = newGroup.size()-1; i >= 0; i--) {
306             ret[i] = (OneSubGroup)newGroup.elementAt(i);
307         }
308         // Store the potential sub group
309
fSubGroupsB.put(element, ret);
310         
311         return ret;
312     }
313
314     private boolean getDBMethods(XSTypeDefinition typed, XSTypeDefinition typeb,
315                                  OneSubGroup methods) {
316         short dMethod = 0, bMethod = 0;
317         while (typed != typeb && typed != SchemaGrammar.fAnyType) {
318             if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
319                 dMethod |= ((XSComplexTypeDecl)typed).fDerivedBy;
320             else
321                 dMethod |= XSConstants.DERIVATION_RESTRICTION;
322             typed = typed.getBaseType();
323             // type == null means the current type is anySimpleType,
324
// whose base type should be anyType
325
if (typed == null)
326                 typed = SchemaGrammar.fAnyType;
327             if (typed.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE)
328                 bMethod |= ((XSComplexTypeDecl)typed).fBlock;
329         }
330         // No derivation relation, or blocked, return false
331
if (typed != typeb || (dMethod & bMethod) != 0)
332             return false;
333         
334         // Remember the derivation methods and blocks, return true.
335
methods.dMethod = dMethod;
336         methods.bMethod = bMethod;
337         return true;
338     }
339
340     // Record the information about how one element substitute another one
341
private static final class OneSubGroup {
342         OneSubGroup() {}
343         OneSubGroup(XSElementDecl sub, short dMethod, short bMethod) {
344             this.sub = sub;
345             this.dMethod = dMethod;
346             this.bMethod = bMethod;
347         }
348         // The element that substitutes another one
349
XSElementDecl sub;
350         // The combination of all derivation methods from sub's type to
351
// the head's type
352
short dMethod;
353         // The combination of {block} of the types in the derivation chain
354
// excluding sub's type
355
short bMethod;
356     }
357 } // class SubstitutionGroupHandler
358
Popular Tags