KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > schema > InitializationVisitor


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.schema;
24
25 import java.util.*;
26
27 import org.xquark.schema.datatypes.PrimitiveType;
28 import org.xquark.schema.loader.*;
29 import org.xquark.schema.validation.ValidationContextProvider;
30
31 public class InitializationVisitor extends DefaultSchemaVisitor implements SchemaConstants {
32     private static final String JavaDoc RCSRevision = "$Revision: 1.5 $";
33     private static final String JavaDoc RCSName = "$Name: $";
34     private ReferenceResolver refResolver = new ReferenceResolver();
35     private HashSet initialized = new HashSet();
36     private Schema schema;
37     private ArrayList pendingTypes = null;
38     private Map contextProviders = null;
39     private Loader loader = null;
40
41     public InitializationVisitor(Schema schema) {
42         this.schema = schema;
43     }
44
45     public InitializationVisitor(Schema schema, Map contextProviders, Loader loader) {
46         this.schema = schema;
47         this.contextProviders = contextProviders;
48         this.loader = loader;
49     }
50
51     public void visit(AttributeGroupDefinition attG) throws SchemaException {
52         if (attG.getSchema() != schema || initialized.contains(attG))
53             return;
54         initialized.add(attG);
55
56         Iterator it = attG.getAttributeDeclarations().iterator();
57         while (it.hasNext()) {
58             SchemaComponent comp = (SchemaComponent) it.next();
59             refResolver.resolve(comp);
60             comp.accept(this);
61         }
62     }
63
64     public void visit(ElementDeclaration decl) throws SchemaException {
65         if (initialized.contains(decl))
66             return;
67         // if (decl.getSchema() != schema || initialized.contains(decl)) return;
68
initialized.add(decl);
69
70         //System.err.println("Init element : " + decl.getName());
71

72         // if type isn't null, type is resolved by itself
73
if (decl.getType() != null) {
74             initType(decl);
75             // it's an error for NOTATION to be used directly in a schema
76
if (decl.getType().isSimpleType()
77                 && decl.getType().isDerivedFrom(decl.getManager().getType(XMLSCHEMA_URI, "NOTATION"))) {
78                 throw new SchemaException("enumeration-required-notation", decl);
79             }
80         }
81
82         // handle substitutionGroup (inheriting its type if required)
83
ElementDeclaration substitutionElement = null;
84         if (decl.getSubstitutionGroup() != null) {
85             substitutionElement = (ElementDeclaration) refResolver.resolve(decl.getSubstitutionGroup());
86             substitutionElement.accept(this);
87             if ((substitutionElement.getBlock() & SUBSTITUTION) != 0) {
88                 throw new SchemaException("cos-equiv-derived-ok-rec.1", decl);
89             }
90             if (decl.getType() == null) {
91                 decl.setType(substitutionElement.getType());
92             } else {
93                 String JavaDoc errCode =
94                     decl.getType().checkTypeDerivationOK(
95                         substitutionElement.getType(),
96                         substitutionElement.getFinal(),
97                         false);
98                 if (errCode != null) {
99                     // "Type is not validly derived from substitution element type";
100
throw new SchemaException("e-props-correct.3", decl);
101                 }
102             }
103             String JavaDoc errCode =
104                 decl.getType().checkTypeDerivationOK(
105                     substitutionElement.getType(),
106                     substitutionElement.getBlock(),
107                     true);
108             if (errCode != null) {
109                 // "Declaration is not substitutable to substitution element";
110
throw new SchemaException("cos-equiv-derived-ok-rec.3", decl);
111             }
112             decl.setSubstitutionGroup(substitutionElement);
113             substitutionElement.addSubstitutionMember(decl);
114             propagateSubstitution(substitutionElement, decl);
115         }
116         // if type still null, use ur-type definition
117
if (decl.getType() == null) {
118             Schema w3cSchema = schema.getManager().getSchema(XMLSCHEMA_URI);
119             if (w3cSchema == null)
120                 w3cSchema = schema;
121             Type type = new TypeRef(w3cSchema, ANY_TYPE);
122             decl.setType(type);
123             initType(decl);
124         }
125
126         // validate default value if there is any
127
if (decl.getValueConstraint() != null) {
128             ValidationContextProvider vcp = null;
129             if (contextProviders != null) {
130                 vcp = (ValidationContextProvider) contextProviders.get(decl);
131             }
132             decl.setValueConstraint(decl.getType().validateDefault(decl.getValueConstraint(), vcp));
133         }
134
135         // initialization identity-constraint
136
Collection identityConstraints = decl.getIdentityConstraints();
137         if (identityConstraints != null) {
138             Iterator it = identityConstraints.iterator();
139             while (it.hasNext()) {
140                 IdentityConstraint idConstraint = (IdentityConstraint) it.next();
141                 //initIdentityConstraint(idConstraint, decl);
142
if (idConstraint.getCategory() == IdentityConstraint.CATEGORY_KEYREF) {
143                     IdentityConstraint idRefer = idConstraint.getReferencedKey();
144                     // idRefer is verificated by Schema of Schemas
145
idRefer = (IdentityConstraint) refResolver.resolve(idRefer);
146                     idConstraint.setReferencedKey(idRefer);
147                     // if the category is keyref, the cardinality of the fields must equal
148
// that of the fields of the referenced key
149
// c-props-correct.2
150
if (!idConstraint.isEqualToKeyRefFields()) {
151                         throw new SchemaException("c-props-correct.2", idConstraint);
152                     }
153                 }
154             }
155         }
156     }
157
158     public void visit(AttributeDeclaration decl) throws SchemaException {
159         // if (decl.getSchema() != schema || initialized.contains(decl)) return;
160
if (initialized.contains(decl))
161             return;
162         initialized.add(decl);
163
164         // System.err.println("Init attribute : " + decl.getName());
165

166         // if type is null, it's simple ur-type definition
167
if (decl.getType() != null) {
168             initType(decl);
169             if (!decl.getType().isSimpleType()) // attribute type must be simpleType
170
throw new SchemaException("src-attribute.3.2", decl);
171
172             // it's an error for NOTATION to be used directly in a schema
173
if (decl.getType() == decl.getManager().getType(XMLSCHEMA_URI, "NOTATION")) {
174                 throw new SchemaException("enumeration-required-notation", decl);
175             }
176         } else {
177             SimpleType type = new SimpleType(decl.getSchema(), SIMPLE_UR_TYPE, null);
178             type.setPrimitive(PrimitiveType.createType(SIMPLE_UR_TYPE));
179             decl.setType(type);
180         }
181
182         try {
183             // validate default value if there is any
184
if (decl.getValueConstraint() != null) {
185                 ValidationContextProvider vcp = null;
186                 if (contextProviders != null) {
187                     vcp = (ValidationContextProvider) contextProviders.get(decl);
188                 }
189                 decl.setValueConstraint(decl.getType().validateDefault(decl.getValueConstraint(), vcp));
190             }
191         } catch (SchemaException e) {
192             throw new SchemaException("a-props-correct.2", decl, e);
193         }
194     }
195
196     public void visit(SimpleType type) throws SchemaException {
197         if (type.getSchema() != schema || initialized.contains(type))
198             return;
199         initialized.add(type);
200
201         //System.err.println("Init simpleType : " + type.getName());
202
PrimitiveType primitive = null;
203         switch (type.getVariety()) {
204             // This is a hack. Atomic means that we have a restriction
205
case SimpleType.VARIETY_ATOMIC :
206                 SimpleType base = (SimpleType) initBaseType(type);
207                 if (base != null) {
208                     type.setVariety(base.getVariety());
209                     type.setItemType(base.getItemType());
210                     List memberTypes = base.getMemberTypes();
211                     if (memberTypes != null)
212                         type.addMemberTypes(memberTypes);
213                     try {
214                         primitive = (PrimitiveType) base.getPrimitive().clone();
215                     } catch (CloneNotSupportedException JavaDoc e) {
216                         // it's vide
217
}
218                 } else if (!XMLSCHEMA_URI.equals(type.getNamespace())) {
219                     // "Either it must have a base [attribute] or a <simpleType> among its [children], but not both";
220
throw new SchemaException("src-simple-type.2", type);
221                 }
222                 break;
223             case SimpleType.VARIETY_LIST :
224                 SimpleType item = initItemType(type);
225                 if (item != null) {
226                     if (item.getVariety() == SimpleType.VARIETY_LIST) {
227                         // "The {item type definition} must have a {variety} of atomic or union";
228
throw new SchemaException("cos-st-restricts.2.1", type);
229                     }
230                     primitive = PrimitiveType.createListType(item.getPrimitive());
231                 } else {
232                     // "Either it must have an itemType [attribute] or a <simpleType> among its [children], but not both";
233
throw new SchemaException("src-simple-type.3", type);
234                 }
235                 break;
236
237             case SimpleType.VARIETY_UNION :
238                 primitive = initMemberTypes(type);
239                 break;
240         }
241
242         if (primitive != null) {
243             type.setPrimitive(primitive);
244             // Add new facets to primitive type
245
Iterator it = type.getAllFacets().iterator();
246             while (it.hasNext()) {
247                 Facet facet = (Facet) it.next();
248                 ContextLocatorImpl vcp = null;
249                 if (contextProviders != null) {
250                     vcp = (ContextLocatorImpl) contextProviders.get(facet);
251                     vcp.setNotationDeclarations(schema.getNotationDeclarationMap());
252                 }
253                 primitive.setFacet(facet, vcp);
254             }
255         }
256
257         checkNotationType(type);
258     }
259
260     public void visit(ComplexType type) throws SchemaException {
261         if (type.getSchema() != schema || initialized.contains(type)) {
262             return;
263         }
264         initialized.add(type);
265
266         // Complex types used in elements of this complex type are buffered
267
// to avoid recursive graph traversal
268
ArrayList localPendingTypes = null;
269         if (pendingTypes == null) {
270             localPendingTypes = new ArrayList();
271             pendingTypes = localPendingTypes;
272         }
273
274         // System.err.println("Init complexType : " + type.getName());
275

276         // If content model not initialized, set it to empty.
277
if (type.getContentModel() == null) {
278             type.setContentModel(new ContentModel());
279         }
280
281         Type base = initBaseType(type);
282
283         if (type.isExtension()) {
284             if (base == null) {
285                 // @@ should not occur
286
} else if (base.isSimpleType()) {
287                 if (type.getContentModel().getContentType() == TEXT_ONLY) {
288                     type.getContentModel().setModel((SimpleType) base);
289                 } else {
290                     // "Complex content complex type cannot derive from a simple type";
291
throw new SchemaException("src-ct.1", type);
292                 }
293                 initAttributes(type, null);
294             } else {
295                 initAttributes(type, (ComplexType) base);
296                 if (type.getContentModel().getContentType() == TEXT_ONLY) {
297                     if (((ComplexType) base).getContentModel().getContentType() != TEXT_ONLY) {
298                         // "Simple content complex type cannot derive from a complex type";
299
throw new SchemaException("src-ct.2", type);
300                     }
301                     type.getContentModel().setModel(((ComplexType) base).getContentModel().getModel());
302                 } else if (((ComplexType) base).getContentModel().getContentType() == EMPTY) {
303                     initContent(type, null);
304                 } else if (type.getContentModel().getContentType() == EMPTY) {
305                     type.getContentModel().setContentType(((ComplexType) base).getContentModel().getContentType());
306                     initContent(type, (ComplexType) base);
307                 } else {
308                     if (type.getContentModel().getContentType()
309                         != ((ComplexType) base).getContentModel().getContentType()) {
310                         // "Both {content type}s must be mixed or both must be element-only";
311
throw new SchemaException("cos-ct-extends.1.4.2.2.2.1", type);
312                     }
313                     initContent(type, (ComplexType) base);
314                 }
315             }
316         } else {
317             // Restriction
318
if (base == null) {
319                 // Restriction from the ur-type
320
initAttributes(type, null);
321                 initContent(type, null);
322             } else if (base.isSimpleType()) {
323                 if (type.getContentModel().getContentType() == TEXT_ONLY) {
324                     // "Simple content complex type cannot restrict a simple base type";
325
throw new SchemaException("src-ct.2", type);
326                 } else {
327                     // "Complex content complex type cannot derive from a simple base type";
328
throw new SchemaException("src-ct.1", type);
329                 }
330             } else {
331                 initAttributes(type, (ComplexType) base);
332                 if (type.getContentModel().getContentType() == TEXT_ONLY) {
333                     if (type.getContentModel().getModel() == null)
334                         type.getContentModel().setModel(((ComplexType) base).getContentModel().getModel());
335                     else
336                          ((SimpleType) type.getContentModel().getModel()).accept(this);
337                 } else {
338                     initContent(type, null);
339                 }
340                 type.checkDerivationValidRestriction(loader);
341             }
342         }
343
344         type.checkUniqueParticleAttribution();
345
346         if (localPendingTypes != null) {
347             // This will allow types to be initialized to store
348
// their own pending type list
349
pendingTypes = null;
350             Iterator it = localPendingTypes.iterator();
351             while (it.hasNext()) {
352                 ((SchemaVisitable) it.next()).accept(this);
353             }
354         }
355     }
356
357     private Type initType(Declaration decl) throws SchemaException {
358         Type type = decl.getType();
359         if (type != null) {
360             type = (Type) refResolver.resolve(type);
361             if (type.isSimpleType() || pendingTypes == null) {
362                 type.accept(this);
363             } else {
364                 resolveDerivationHierarchy(type);
365                 pendingTypes.add(type);
366             }
367             decl.setType(type);
368         }
369         if (!type.isSimpleType() && type.getName() == null) {
370             type.accept(this);
371         }
372         return type;
373     }
374
375     private void resolveDerivationHierarchy(Type type) throws SchemaException {
376         Type previous = type;
377         Type base = type.getBaseType();
378         while (base != null) {
379             base = (Type) refResolver.resolve(base);
380             previous.setBaseType(base);
381             if (base == type) {
382                 String JavaDoc errCode = null;
383                 if (type.isSimpleType())
384                     errCode = "st-props-correct.2";
385                 else
386                     errCode = "ct-props-correct.3";
387                 // "circular definitions are disallowed";
388
throw new SchemaException(errCode, type);
389             }
390             previous = base;
391             base = base.getBaseType();
392         }
393     }
394
395     private void propagateSubstitution(ElementDeclaration subst, ElementDeclaration decl) {
396         for (subst = (ElementDeclaration) subst.getSubstitutionGroup();
397             subst != null;
398             subst = (ElementDeclaration) subst.getSubstitutionGroup()) {
399             String JavaDoc errCode = decl.getType().checkTypeDerivationOK(subst.getType(), subst.getBlock(), true);
400             if (errCode != null)
401                 return;
402             List list = subst.getSubstitutionElementList();
403             if (list.indexOf(decl) != -1)
404                 return;
405             subst.addSubstitutionMember(decl);
406         }
407     }
408
409     private Type initBaseType(Type type) throws SchemaException {
410         Type base = type.getBaseType();
411         // base is primitive
412
if (base != null) {
413             if (SIMPLE_UR_TYPE.equals(base.getName())) {
414                 if (XMLSCHEMA_URI.equals(schema.getNamespace())) {
415                     base = null;
416                     ((SimpleType) type).setPrimitive(PrimitiveType.createType(type.getName()));
417                     type.setBaseType(base);
418                 } else {
419                     // "Base type defintion must be an atomic simple type or a built-in primitive datatype";
420
throw new SchemaException("cos-st-restricts.1.1", type);
421                 }
422             } else {
423                 // base is SimpleType or ComplexType
424
base = (Type) refResolver.resolve(base);
425                 base.accept(this);
426                 type.setBaseType(base);
427             }
428         }
429
430         return base;
431     }
432
433     private Type initBaseType(SimpleType type) throws SchemaException {
434         Type base = initBaseType((Type) type);
435         if (base != null) {
436             if (!base.isSimpleType()) {
437                 throw new SchemaException("derivation-ok-restriction.5.1.1", base);
438             }
439             SimpleType simpleBase = (SimpleType) base;
440             SimpleType current = simpleBase;
441             while (current != null) {
442                 if (current == type) {
443                     // "circular definitions are disallowed";
444
throw new SchemaException("st-props-correct.2", type);
445                 }
446                 current = (SimpleType) current.getBaseType();
447             }
448             int exclusions = base.getFinal();
449             if ((exclusions & RESTRICTION) != 0) {
450                 // "Base type final must not contain restriction";
451
throw new SchemaException("st-props-correct.3", type);
452             } else if (simpleBase.getVariety() == SimpleType.VARIETY_LIST && (exclusions & LIST) != 0) {
453                 // "Base type final must not contain list";
454
throw new SchemaException("st-props-correct.4.2.1", type);
455             } else if (simpleBase.getVariety() == SimpleType.VARIETY_LIST && (exclusions & LIST) != 0) {
456                 // "Base type final must not contain union";
457
throw new SchemaException("st-props-correct.4.2.2", type);
458             }
459         }
460         return base;
461     }
462
463     private Type initBaseType(ComplexType type) throws SchemaException {
464         Type base = initBaseType((Type) type);
465         if (base != null) {
466             Type current = base;
467             while (current != null) {
468                 if (current == type) {
469                     // "circular definitions are disallowed";
470
throw new SchemaException("ct-props-correct.3", type);
471                 }
472                 current = current.getBaseType();
473             }
474             int exclusions = base.getFinal();
475             if (type.isRestriction() && (exclusions & RESTRICTION) != 0) {
476                 // "Base type final must not contain restriction";
477
throw new SchemaException("derivation-ok-restriction.1", type);
478             } else if (type.isExtension() && (exclusions & EXTENSION) != 0) {
479                 String JavaDoc errCode = null;
480                 if (base.isSimpleType())
481                     errCode = "cos-ct-extends.2.2";
482                 else
483                     errCode = "cos-ct-extends.1.1";
484                 // "Base type final must not contain extension";
485
throw new SchemaException(errCode, type);
486             }
487         }
488         return base;
489     }
490
491     private SimpleType initItemType(SimpleType type) throws SchemaException {
492         Type itemType = type.getItemType();
493         if (itemType != null) {
494             itemType = (Type) refResolver.resolve(itemType);
495             itemType.accept(this);
496             type.setItemType(itemType);
497         }
498         return (SimpleType) itemType;
499     }
500
501     private PrimitiveType initMemberTypes(Type type) throws SchemaException {
502         ArrayList primitiveTypes = new ArrayList();
503         String JavaDoc primitiveName = "union of ";
504         ListIterator it = ((SimpleType) type).getMemberTypes().listIterator();
505         while (it.hasNext()) {
506             // init memberType
507
// resolve TypeRef
508
Type memberType = (Type) it.next();
509             memberType = (Type) refResolver.resolve(memberType);
510             memberType.accept(this);
511             if (!memberType.isSimpleType()) {
512                 // "Member type must have a variety of atomic or list";
513
throw new SchemaException("cos-st-restricts.3.1", memberType);
514             } else if (memberType == type) {
515                 // "Circular union definition is disallowed";
516
throw new SchemaException("src-simple-type.4", type);
517             } else if (((SimpleType) memberType).getVariety() == SimpleType.VARIETY_UNION) {
518                 it.remove();
519                 Iterator it2 = ((SimpleType) memberType).getMemberTypes().iterator();
520                 while (it2.hasNext()) {
521                     SimpleType m = (SimpleType) it2.next();
522                     if (m == type) {
523                         // "Circular union definition is disallowed";
524
throw new SchemaException("src-simple-type.4", type);
525                     }
526                     it.add(m);
527                     primitiveTypes.add(m.getPrimitive());
528                     if (m.getName() != null)
529                         primitiveName += memberType.getName() + " ";
530                     else
531                         primitiveName += m.getPrimitive().getName() + " ";
532                 }
533             } else {
534                 it.set(memberType);
535                 PrimitiveType primitive = ((SimpleType) memberType).getPrimitive();
536                 primitiveTypes.add(primitive);
537                 if (memberType.getName() != null)
538                     primitiveName += memberType.getName() + " ";
539                 else
540                     primitiveName += primitive.getName() + " ";
541             }
542         }
543         return PrimitiveType.createUnionType(primitiveTypes, primitiveName);
544     }
545
546     private void initAttributes(ComplexType type, ComplexType base) throws SchemaException {
547         ArrayList requiredAndDefaultAttributes = new ArrayList();
548         // groupContent is used for attributegroup
549
ArrayList groupContent = new ArrayList();
550         ArrayList prohibited = new ArrayList();
551
552         Iterator it = type.getAttributeEntries().iterator();
553         while (it.hasNext()) {
554             Map.Entry entry = (Map.Entry) it.next();
555             SchemaComponent comp = refResolver.resolve((SchemaComponent) entry.getValue());
556             // check if it's an AttributeDeclaration
557
if (comp instanceof AttributeDeclaration) {
558                 AttributeDeclaration decl = (AttributeDeclaration) comp;
559                 entry.setValue(decl);
560                 decl.accept(this);
561                 if (decl.getUse() == PROHIBITED) {
562                     it.remove();
563                     prohibited.add(decl);
564                 } else {
565                     checkIDAttribute(type, decl);
566                     checkNotationAttribute(type, decl);
567                     if (decl.getUse() == REQUIRED || decl.getValueConstraint() != null)
568                         requiredAndDefaultAttributes.add(decl);
569                 }
570             }
571             // it's an AttributeGroupDefinition
572
else {
573                 // comp.accept(this); // AttributeGroupDefinition is visited below
574
appendContent(type, (AttributeGroupDefinition) comp, groupContent, null);
575                 it.remove();
576             }
577         }
578
579         // handle included AttributeGroupDefinition
580
it = groupContent.iterator();
581         while (it.hasNext()) {
582             AttributeDeclaration decl = (AttributeDeclaration) it.next();
583             decl = (AttributeDeclaration) importInScope(decl, type);
584             decl.accept(this);
585             if (decl.getUse() == PROHIBITED)
586                 prohibited.add(decl);
587             else {
588                 type.register(decl);
589                 checkIDAttribute(type, decl);
590                 checkNotationAttribute(type, decl);
591                 if (decl.getUse() == REQUIRED || decl.getValueConstraint() != null)
592                     requiredAndDefaultAttributes.add(decl);
593             }
594         }
595
596         // if base != null, add base attributes to this
597
if (base != null) {
598             it = base.getAttributeDeclarations().iterator();
599             while (it.hasNext()) {
600                 AttributeDeclaration decl = (AttributeDeclaration) it.next();
601                 AttributeDeclaration tDecl = type.getAttributeDeclaration(decl.getNamespace(), decl.getName());
602                 if (tDecl == null) {
603                     boolean authorized = true;
604                     Iterator it2 = prohibited.iterator();
605                     while (authorized && it2.hasNext()) {
606                         AttributeDeclaration p = (AttributeDeclaration) it2.next();
607                         if (p.hasName(decl.getNamespace(), decl.getName()))
608                             authorized = false;
609                     }
610                     if (authorized) {
611                         // @@Scope
612
//decl = (AttributeDeclaration)importInScope(decl, type);
613
type.register((AttributeDeclaration) decl);
614                         checkIDAttribute(type, decl);
615                         checkNotationAttribute(type, decl);
616                         if (decl.getUse() == REQUIRED || decl.getValueConstraint() != null)
617                             requiredAndDefaultAttributes.add(decl);
618                     }
619                 } else if (type.isExtension()) {
620                     // "Two distinct attribute declarations should not have identical names";
621
throw new SchemaException("ct-props-correct.4", tDecl);
622                 }
623             }
624             if (type.isExtension())
625                 type.setAttributeWildcard(wildcardUnion(type.getAttributeWildcard(), base.getAttributeWildcard()));
626             else
627                 type.setAttributeWildcard(
628                     wildcardIntersection(type.getAttributeWildcard(), base.getAttributeWildcard()));
629
630         }
631         type.setRequiredAndDefaultAttributes(requiredAndDefaultAttributes);
632     }
633
634     void checkIDAttribute(ComplexType type, AttributeDeclaration decl) throws SchemaException {
635         Type attrType = decl.getType();
636         if (attrType.isDerivedFrom(type.getManager().getType(XMLSCHEMA_URI, "ID"))) {
637             if (type.getIDAttribute() != null) {
638                 // "Two distinct attribute declarations must not have types which are or are derived from ID.";
639
throw new SchemaException("ct-props-correct.5", type);
640             }
641             type.setIDAttribute(decl);
642         }
643     }
644
645     void checkNotationAttribute(ComplexType type, AttributeDeclaration decl) {
646         Type attrType = decl.getType();
647         if (attrType.isDerivedFrom(type.getManager().getType(XMLSCHEMA_URI, "NOTATION"))) {
648             type.setNotationAttribute(decl);
649         }
650     }
651
652     void checkNotationType(SimpleType type) throws SchemaException {
653         if (type.isDerivedFrom(type.getManager().getType(XMLSCHEMA_URI, "NOTATION"))) {
654             Facet enumFacet = (Facet) type.getFacets().get(ENUMERATION_TAG);
655             if (enumFacet == null) {
656                 // enumeration facet is mandatory
657
throw new SchemaException("enumeration-required-notation", type);
658             }
659         }
660     }
661
662     private void appendContent(ComplexType type, AttributeGroupDefinition def, ArrayList content, ArrayList expanded)
663         throws SchemaException {
664         if (expanded == null)
665             expanded = new ArrayList();
666         if (expanded.indexOf(def) != -1) {
667             // "Circular attribute group definition";
668
throw new SchemaException("src-attribute_group.3", def);
669         } else {
670             expanded.add(def);
671             type.setAttributeWildcard(wildcardIntersection(type.getAttributeWildcard(), def.getAttributeWildcard()));
672             Iterator it = def.getContents().iterator();
673             while (it.hasNext()) {
674                 SchemaComponent comp = refResolver.resolve((SchemaComponent) it.next());
675                 if (comp instanceof AttributeDeclaration) {
676                     content.add(comp);
677                 } else {
678                     appendContent(type, (AttributeGroupDefinition) comp, content, expanded);
679                 }
680             }
681         }
682     }
683
684     private Wildcard wildcardIntersection(Wildcard wc1, Wildcard wc2) throws SchemaException {
685         if (wc1 == null || wc1.isAny())
686             return wc2;
687         return wc1.wildcardIntersection(wc2);
688     }
689
690     private Wildcard wildcardUnion(Wildcard wc1, Wildcard wc2) throws SchemaException {
691         if (wc1 == null)
692             return wc2;
693         return wc1.wildcardUnion(wc2);
694     }
695
696     private void initContent(ComplexType type, ComplexType base) throws SchemaException {
697         // first, get and init particle
698
Particle particle = (Particle) type.getContentModel().getModel();
699         if (particle != null) {
700             particle = initParticle(particle, type, false, null);
701             type.getContentModel().setModel(particle);
702         }
703
704         // then, get and init base particle
705
if (base != null) {
706             Iterator decls = base.getElementDeclarations().iterator();
707             while (decls.hasNext()) {
708                 ElementDeclaration decl = (ElementDeclaration) decls.next();
709                 type.register(decl);
710             }
711             ModelGroup group = null;
712
713             // if the type particle is null, create a empty particle
714
if (particle == null) {
715                 group = new SequenceModelGroup();
716                 particle = new Particle(group);
717                 type.getContentModel().setModel(particle);
718             }
719             // else, get particle's term and check if it's a sequence model
720
else if (
721                 particle.getMinOccurs() == 1
722                     && particle.getMaxOccurs() == 1
723                     && particle.getTerm() instanceof SequenceModelGroup) {
724                 group = (ModelGroup) particle.getTerm();
725             }
726             // the particle's term isn't a sequence model, create a sequence model
727
else {
728                 group = new SequenceModelGroup();
729                 group.add(particle);
730                 particle = new Particle(group);
731                 type.getContentModel().setModel(particle);
732             }
733
734             // init base particle
735
// @@Scope
736
//Particle basePart = initParticle((Particle)base.getContentModel().getModel(), type, true, null);
737
Particle basePart = (Particle) base.getContentModel().getModel();
738             if (basePart != null) {
739                 if (basePart.getTerm() instanceof ModelGroup) {
740                     ModelGroup baseGroup = (ModelGroup) basePart.getTerm();
741                     if (baseGroup.size() != 0) {
742                         if (basePart.getMinOccurs() == 1
743                             && basePart.getMaxOccurs() == 1
744                             && baseGroup.getCompositor() == ModelGroup.SEQUENCE) {
745                             Iterator it = baseGroup.iterator();
746                             int i = 0;
747                             while (it.hasNext())
748                                 group.add(i++, it.next());
749                         } else {
750                             group.add(0, basePart);
751                         }
752                     }
753                 } else {
754                     group.add(0, basePart);
755                 }
756             }
757
758             if (particle == null) {
759                 type.getContentModel().setContentType(EMPTY);
760             } else {
761                 particle.setTerm(group);
762                 new ValidationInfoInitializer(particle).initialize();
763             }
764         }
765     }
766
767     private Particle initParticle(Particle p, SchemaScope scope, boolean duplicate, ArrayList expanded)
768         throws SchemaException {
769         ModelGroup group = null;
770         if (p.getMaxOccurs() == 0)
771             return null;
772
773         try {
774             if (duplicate) {
775                 Particle newP = (Particle) p.clone();
776                 if (loader != null)
777                     loader.addComp2ComponentContextLocators(newP, p);
778                 p = newP;
779             }
780         } catch (CloneNotSupportedException JavaDoc ex) {
781             // should not happen
782
throw new SchemaException(null, p);
783         }
784
785         if (p.getTerm() instanceof SchemaComponent) {
786             SchemaComponent comp = refResolver.resolve((SchemaComponent) p.getTerm());
787             if (comp instanceof ElementDeclaration) {
788                 comp = importInScope((ElementDeclaration) comp, scope);
789                 comp.accept(this);
790                 scope.register((ElementDeclaration) comp);
791                 p.setTerm(comp);
792             } else if (comp instanceof ModelGroupDefinition) {
793                 group = (ModelGroup) ((ModelGroupDefinition) comp).getModelGroup();
794                 // @@@ This does not work when the ALL group is first in model
795
// Should be checked afterwards instead
796
if (group.getCompositor() == ModelGroup.ALL && expanded != null) {
797                     // "All group can only appear as main group in a content model";
798
// throw new SchemaException("cos-all-limited.1", p);
799
}
800                 if (expanded == null)
801                     expanded = new ArrayList();
802                 else if (expanded.indexOf(comp) != -1) {
803                     // "Circular model group definition";
804
throw new SchemaException("mg-props-correct.2", p);
805                 }
806                 expanded.add(comp);
807                 duplicate = true;
808             }
809         } else if (p.getTerm() instanceof ModelGroup) {
810             group = (ModelGroup) p.getTerm();
811         }
812
813         if (group != null) {
814             if (expanded == null)
815                 expanded = new ArrayList();
816             group = initGroup(group, scope, duplicate, expanded);
817             if (group.size() == 0 && (group.getCompositor() != ModelGroup.CHOICE || p.getMinOccurs() == 0))
818                 return null;
819             p.setTerm(group);
820             if (group.size() == 1 && p.getMinOccurs() == 1 && p.getMaxOccurs() == 1) {
821                 p = (Particle) group.get(0);
822             }
823         }
824
825         new ValidationInfoInitializer(p).initialize();
826         return p;
827     }
828
829     private ModelGroup initGroup(ModelGroup group, SchemaScope scope, boolean duplicate, ArrayList expanded)
830         throws SchemaException {
831         if (duplicate)
832             group = (ModelGroup) group.clone();
833         // System.err.println("group = " + group);
834
ListIterator it = group.listIterator();
835         while (it.hasNext()) {
836             Particle p = initParticle((Particle) it.next(), scope, duplicate, expanded);
837             it.set(p);
838             if (p == null)
839                 it.remove();
840             else if (p.getTerm() instanceof ModelGroup) {
841                 ModelGroup subgroup = (ModelGroup) p.getTerm();
842                 if (p.getMinOccurs() == 1
843                     && p.getMaxOccurs() == 1
844                     && subgroup.getCompositor() == group.getCompositor()) {
845                     it.remove();
846                     Iterator it2 = subgroup.iterator();
847                     while (it2.hasNext())
848                         it.add(it2.next());
849                 }
850             }
851         }
852
853         return group;
854     }
855
856     private Declaration importInScope(Declaration decl, SchemaScope scope) throws SchemaException {
857         if (decl.getScope() != null)
858             return decl;
859         // @@Scope: used to be
860
// if (decl.getScope() == scope) return decl;
861
Declaration result = null;
862         try {
863             result = (Declaration) decl.clone();
864             if (loader != null)
865                 loader.addComp2ComponentContextLocators(result, decl);
866         } catch (CloneNotSupportedException JavaDoc ex) {
867             // should not happen
868
throw new SchemaException(null, decl);
869         }
870         result.setScope(scope);
871         return result;
872     }
873
874     class ReferenceResolver extends DefaultSchemaVisitor {
875         private static final String JavaDoc RCSRevision = "$Revision: 1.5 $";
876         private static final String JavaDoc RCSName = "$Name: $";
877
878         SchemaComponent result = null;
879
880         SchemaComponent resolve(SchemaComponent ref) throws SchemaException {
881             result = ref;
882             ref.accept(this);
883             if (result == null) {
884                 // "Unresolved reference";
885
throw new SchemaException("src-resolve.3", ref);
886             }
887             return result;
888         }
889
890         public void visit(SchemaComponentRef ref) {
891             result = ref.getSchema().getSchemaComponent(ref.getName(), ref.getType());
892         }
893
894         public void visit(TypeRef ref) {
895             result = ref.getSchema().getType(ref.getName());
896         }
897
898         public void visit(ElementDeclarationRef ref) throws SchemaException {
899             result = ref.getSchema().getElementDeclaration(ref.getName());
900         }
901
902         public void visit(AttributeDeclarationRef ref) throws SchemaException {
903             AttributeDeclaration decl = ref.getSchema().getAttributeDeclaration(ref.getName());
904             if (decl != null) {
905                 try {
906                     AttributeDeclaration newDecl = (AttributeDeclaration) decl.clone();
907                     if (loader != null)
908                         loader.addComp2ComponentContextLocators(newDecl, decl);
909                     decl = newDecl;
910                 } catch (CloneNotSupportedException JavaDoc e) {
911                     // should not happen
912
throw new SchemaException(null, decl);
913                 }
914                 decl.setUse(ref.getUse());
915                 String JavaDoc def = ref.getDefaultValue();
916                 String JavaDoc fix = ref.getFixedValue();
917                 String JavaDoc fixDecl = decl.getFixedValue();
918                 if (fixDecl != null) {
919                     if (def != null || (fix != null && !fix.equals(fixDecl))) {
920                         // "Attribute ref must have same fixed value as original";
921
throw new SchemaException("au-props-correct.2", decl);
922                     }
923                 } else if (fix != null) {
924                     decl.setFixedValue(fix);
925                     decl.setDefaultValue(null);
926                 } else if (def != null) {
927                     decl.setDefaultValue(def);
928                 }
929             }
930             result = decl;
931         }
932
933         public void visit(SimpleBaseTypeRef ref) throws SchemaException {
934             Type base = ref.getType().getBaseType();
935             if (base.isSimpleType() == false) {
936                 ContentModel model = ((ComplexType) base).getContentModel();
937                 if (model.getContentType() == TEXT_ONLY) {
938                     result = (SchemaComponent) model.getModel();
939                     return;
940                 }
941             }
942             // "Base content type must be a simple type";
943
throw new SchemaException("derivation-ok-restriction.5.1.1", base);
944         }
945
946         public void visit(IdentityConstraintRef ref) throws SchemaException {
947             result = ref.getSchema().getIdentityConstraint(ref.getName());
948             if (result != null && ((IdentityConstraint) result).getCategory() == IdentityConstraint.CATEGORY_KEYREF)
949                 result = null;
950         }
951     }
952
953     class ValidationInfoInitializer extends DefaultSchemaVisitor {
954         private static final String JavaDoc RCSRevision = "$Revision: 1.5 $";
955         private static final String JavaDoc RCSName = "$Name: $";
956
957         private Particle particle;
958
959         ValidationInfoInitializer(Particle p) {
960             particle = p;
961         }
962
963         void initialize() throws SchemaException {
964             if (particle.getFirstElements().isEmpty() && particle.getFirstWildcards() == null) {
965                 ((SchemaVisitable) particle.getTerm()).accept(this);
966             }
967         }
968
969         public void visit(ElementDeclaration decl) {
970             particle.addFirstElement(decl);
971             particle.setMinExtent(particle.getMinOccurs());
972             particle.setMaxExtent(particle.getMaxOccurs());
973         }
974
975         public void visit(AllModelGroup group) {
976             Iterator it = group.iterator();
977             long minExtent = 0;
978             long maxExtent = 0;
979             while (it.hasNext()) {
980                 Particle p = (Particle) it.next();
981                 minExtent += p.getMinExtent();
982                 maxExtent += p.getMaxExtent();
983                 particle.addFirstElements(p.getFirstElements());
984                 particle.addFirstWildcards(p.getFirstWildcards());
985             }
986             if (maxExtent > Integer.MAX_VALUE)
987                 maxExtent = Integer.MAX_VALUE;
988             minExtent *= particle.getMinOccurs();
989             maxExtent *= particle.getMaxOccurs();
990             if (maxExtent > Integer.MAX_VALUE)
991                 maxExtent = Integer.MAX_VALUE;
992             particle.setMinExtent((int) minExtent);
993             particle.setMaxExtent((int) maxExtent);
994         }
995
996         public void visit(ChoiceModelGroup group) {
997             Iterator it = group.iterator();
998             long minExtent = Integer.MAX_VALUE;
999             long maxExtent = 0;
1000            while (it.hasNext()) {
1001                Particle p = (Particle) it.next();
1002                if (p.getMinExtent() < minExtent)
1003                    minExtent = p.getMinExtent();
1004                if (p.getMaxExtent() > maxExtent)
1005                    maxExtent = p.getMaxExtent();
1006                particle.addFirstElements(p.getFirstElements());
1007                particle.addFirstWildcards(p.getFirstWildcards());
1008            }
1009            minExtent *= particle.getMinOccurs();
1010            maxExtent *= particle.getMaxOccurs();
1011            if (maxExtent > Integer.MAX_VALUE)
1012                maxExtent = Integer.MAX_VALUE;
1013            particle.setMinExtent((int) minExtent);
1014            particle.setMaxExtent((int) maxExtent);
1015        }
1016
1017        public void visit(SequenceModelGroup group) {
1018            Iterator it = group.iterator();
1019            long minExtent = 0;
1020            long maxExtent = 0;
1021            boolean optional = true;
1022            while (it.hasNext()) {
1023                Particle p = (Particle) it.next();
1024                minExtent += p.getMinExtent();
1025                maxExtent += p.getMaxExtent();
1026                if (optional) {
1027                    particle.addFirstElements(p.getFirstElements());
1028                    particle.addFirstWildcards(p.getFirstWildcards());
1029                }
1030                if (p.getMinExtent() > 0)
1031                    optional = false;
1032            }
1033            if (maxExtent > Integer.MAX_VALUE)
1034                maxExtent = Integer.MAX_VALUE;
1035            minExtent *= particle.getMinOccurs();
1036            maxExtent *= particle.getMaxOccurs();
1037            if (maxExtent > Integer.MAX_VALUE)
1038                maxExtent = Integer.MAX_VALUE;
1039            particle.setMinExtent((int) minExtent);
1040            particle.setMaxExtent((int) maxExtent);
1041        }
1042
1043        public void visit(Wildcard wildcard) {
1044            particle.addFirstWildcard(wildcard);
1045            particle.setMinExtent(particle.getMinOccurs());
1046            particle.setMaxExtent(particle.getMaxOccurs());
1047        }
1048    }
1049
1050}
1051
Popular Tags