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;
019:
020: import java.util.Vector;
021:
022: import org.apache.xerces.xs.StringList;
023: import org.apache.xerces.xs.XSAttributeDeclaration;
024: import org.apache.xerces.xs.XSAttributeGroupDefinition;
025: import org.apache.xerces.xs.XSConstants;
026: import org.apache.xerces.xs.XSElementDeclaration;
027: import org.apache.xerces.xs.XSModel;
028: import org.apache.xerces.xs.XSModelGroupDefinition;
029: import org.apache.xerces.xs.XSNamedMap;
030: import org.apache.xerces.xs.XSNamespaceItemList;
031: import org.apache.xerces.xs.XSNotationDeclaration;
032: import org.apache.xerces.xs.XSObjectList;
033: import org.apache.xerces.xs.XSTypeDefinition;
034: import org.apache.xerces.impl.xs.util.NSItemListImpl;
035: import org.apache.xerces.impl.xs.util.StringListImpl;
036: import org.apache.xerces.impl.xs.util.XSNamedMap4Types;
037: import org.apache.xerces.impl.xs.util.XSNamedMapImpl;
038: import org.apache.xerces.impl.xs.util.XSObjectListImpl;
039: import org.apache.xerces.util.SymbolHash;
040: import org.apache.xerces.util.XMLSymbols;
041:
042: /**
043: * Implements XSModel: a read-only interface that represents an XML Schema,
044: * which could be components from different namespaces.
045: *
046: * @xerces.internal
047: *
048: * @author Sandy Gao, IBM
049: *
050: * @version $Id: XSModelImpl.java 446734 2006-09-15 20:51:23Z mrglavas $
051: */
052: public class XSModelImpl implements XSModel {
053:
054: // the max index / the max value of XSObject type
055: private static final short MAX_COMP_IDX = XSTypeDefinition.SIMPLE_TYPE;
056: private static final boolean[] GLOBAL_COMP = { false, // null
057: true, // attribute
058: true, // element
059: true, // type
060: false, // attribute use
061: true, // attribute group
062: true, // group
063: false, // model group
064: false, // particle
065: false, // wildcard
066: false, // idc
067: true, // notation
068: false, // annotation
069: false, // facet
070: false, // multi value facet
071: true, // complex type
072: true // simple type
073: };
074:
075: // number of grammars/namespaces stored here
076: private int fGrammarCount;
077: // all target namespaces
078: private String[] fNamespaces;
079: // all schema grammar objects (for each namespace)
080: private SchemaGrammar[] fGrammarList;
081: // a map from namespace to schema grammar
082: private SymbolHash fGrammarMap;
083: // a map from element declaration to its substitution group
084: private SymbolHash fSubGroupMap;
085:
086: // store a certain kind of components from all namespaces
087: private XSNamedMap[] fGlobalComponents;
088: // store a certain kind of components from one namespace
089: private XSNamedMap[][] fNSComponents;
090:
091: // store all annotations
092: private XSObjectListImpl fAnnotations = null;
093:
094: // whether there is any IDC in this XSModel
095: private boolean fHasIDC = false;
096:
097: /**
098: * Construct an XSModelImpl, by storing some grammars and grammars imported
099: * by them to this object.
100: *
101: * @param grammars the array of schema grammars
102: */
103: public XSModelImpl(SchemaGrammar[] grammars) {
104: // copy namespaces/grammars from the array to our arrays
105: int len = grammars.length;
106: fNamespaces = new String[Math.max(len + 1, 5)];
107: fGrammarList = new SchemaGrammar[Math.max(len + 1, 5)];
108: boolean hasS4S = false;
109: for (int i = 0; i < len; i++) {
110: fNamespaces[i] = grammars[i].getTargetNamespace();
111: fGrammarList[i] = grammars[i];
112: if (fNamespaces[i] == SchemaSymbols.URI_SCHEMAFORSCHEMA)
113: hasS4S = true;
114: }
115: // If a schema for the schema namespace isn't included, include it here.
116: if (!hasS4S) {
117: fNamespaces[len] = SchemaSymbols.URI_SCHEMAFORSCHEMA;
118: fGrammarList[len++] = SchemaGrammar.SG_SchemaNS;
119: }
120:
121: SchemaGrammar sg1, sg2;
122: Vector gs;
123: int i, j, k;
124: // and recursively get all imported grammars, add them to our arrays
125: for (i = 0; i < len; i++) {
126: // get the grammar
127: sg1 = fGrammarList[i];
128: gs = sg1.getImportedGrammars();
129: // for each imported grammar
130: for (j = gs == null ? -1 : gs.size() - 1; j >= 0; j--) {
131: sg2 = (SchemaGrammar) gs.elementAt(j);
132: // check whether this grammar is already in the list
133: for (k = 0; k < len; k++) {
134: if (sg2 == fGrammarList[k])
135: break;
136: }
137: // if it's not, add it to the list
138: if (k == len) {
139: // ensure the capacity of the arrays
140: if (len == fGrammarList.length) {
141: String[] newSA = new String[len * 2];
142: System.arraycopy(fNamespaces, 0, newSA, 0, len);
143: fNamespaces = newSA;
144: SchemaGrammar[] newGA = new SchemaGrammar[len * 2];
145: System
146: .arraycopy(fGrammarList, 0, newGA, 0,
147: len);
148: fGrammarList = newGA;
149: }
150: fNamespaces[len] = sg2.getTargetNamespace();
151: fGrammarList[len] = sg2;
152: len++;
153: }
154: }
155: }
156:
157: // establish the mapping from namespace to grammars
158: fGrammarMap = new SymbolHash(len * 2);
159: for (i = 0; i < len; i++) {
160: fGrammarMap.put(null2EmptyString(fNamespaces[i]),
161: fGrammarList[i]);
162: // update the idc field
163: if (fGrammarList[i].hasIDConstraints())
164: fHasIDC = true;
165: }
166:
167: fGrammarCount = len;
168: fGlobalComponents = new XSNamedMap[MAX_COMP_IDX + 1];
169: fNSComponents = new XSNamedMap[len][MAX_COMP_IDX + 1];
170:
171: // build substitution groups
172: buildSubGroups();
173: }
174:
175: private void buildSubGroups() {
176: SubstitutionGroupHandler sgHandler = new SubstitutionGroupHandler(
177: null);
178: for (int i = 0; i < fGrammarCount; i++) {
179: sgHandler.addSubstitutionGroup(fGrammarList[i]
180: .getSubstitutionGroups());
181: }
182:
183: XSNamedMap elements = getComponents(XSConstants.ELEMENT_DECLARATION);
184: int len = elements.getLength();
185: fSubGroupMap = new SymbolHash(len * 2);
186: XSElementDecl head;
187: XSElementDeclaration[] subGroup;
188: for (int i = 0; i < len; i++) {
189: head = (XSElementDecl) elements.item(i);
190: subGroup = sgHandler.getSubstitutionGroup(head);
191: fSubGroupMap.put(head,
192: subGroup.length > 0 ? new XSObjectListImpl(
193: subGroup, subGroup.length)
194: : XSObjectListImpl.EMPTY_LIST);
195: }
196: }
197:
198: /**
199: * Convenience method. Returns a list of all namespaces that belong to
200: * this schema.
201: * @return A list of all namespaces that belong to this schema or
202: * <code>null</code> if all components don't have a targetNamespace.
203: */
204: public StringList getNamespaces() {
205: // REVISIT: should the type of fNamespace be StringListImpl?
206: return new StringListImpl(fNamespaces, fGrammarCount);
207: }
208:
209: public XSNamespaceItemList getNamespaceItems() {
210:
211: // REVISIT: should the type of fGrammarList be NSItemListImpl?
212: return new NSItemListImpl(fGrammarList, fGrammarCount);
213: }
214:
215: /**
216: * Returns a list of top-level components, i.e. element declarations,
217: * attribute declarations, etc.
218: * @param objectType The type of the declaration, i.e.
219: * <code>ELEMENT_DECLARATION</code>. Note that
220: * <code>XSTypeDefinition.SIMPLE_TYPE</code> and
221: * <code>XSTypeDefinition.COMPLEX_TYPE</code> can also be used as the
222: * <code>objectType</code> to retrieve only complex types or simple
223: * types, instead of all types.
224: * @return A list of top-level definitions of the specified type in
225: * <code>objectType</code> or an empty <code>XSNamedMap</code> if no
226: * such definitions exist.
227: */
228: public synchronized XSNamedMap getComponents(short objectType) {
229: if (objectType <= 0 || objectType > MAX_COMP_IDX
230: || !GLOBAL_COMP[objectType]) {
231: return XSNamedMapImpl.EMPTY_MAP;
232: }
233:
234: SymbolHash[] tables = new SymbolHash[fGrammarCount];
235: // get all hashtables from all namespaces for this type of components
236: if (fGlobalComponents[objectType] == null) {
237: for (int i = 0; i < fGrammarCount; i++) {
238: switch (objectType) {
239: case XSConstants.TYPE_DEFINITION:
240: case XSTypeDefinition.COMPLEX_TYPE:
241: case XSTypeDefinition.SIMPLE_TYPE:
242: tables[i] = fGrammarList[i].fGlobalTypeDecls;
243: break;
244: case XSConstants.ATTRIBUTE_DECLARATION:
245: tables[i] = fGrammarList[i].fGlobalAttrDecls;
246: break;
247: case XSConstants.ELEMENT_DECLARATION:
248: tables[i] = fGrammarList[i].fGlobalElemDecls;
249: break;
250: case XSConstants.ATTRIBUTE_GROUP:
251: tables[i] = fGrammarList[i].fGlobalAttrGrpDecls;
252: break;
253: case XSConstants.MODEL_GROUP_DEFINITION:
254: tables[i] = fGrammarList[i].fGlobalGroupDecls;
255: break;
256: case XSConstants.NOTATION_DECLARATION:
257: tables[i] = fGrammarList[i].fGlobalNotationDecls;
258: break;
259: }
260: }
261: // for complex/simple types, create a special implementation,
262: // which take specific types out of the hash table
263: if (objectType == XSTypeDefinition.COMPLEX_TYPE
264: || objectType == XSTypeDefinition.SIMPLE_TYPE) {
265: fGlobalComponents[objectType] = new XSNamedMap4Types(
266: fNamespaces, tables, fGrammarCount, objectType);
267: } else {
268: fGlobalComponents[objectType] = new XSNamedMapImpl(
269: fNamespaces, tables, fGrammarCount);
270: }
271: }
272:
273: return fGlobalComponents[objectType];
274: }
275:
276: /**
277: * Convenience method. Returns a list of top-level component declarations
278: * that are defined within the specified namespace, i.e. element
279: * declarations, attribute declarations, etc.
280: * @param objectType The type of the declaration, i.e.
281: * <code>ELEMENT_DECLARATION</code>.
282: * @param namespace The namespace to which the declaration belongs or
283: * <code>null</code> (for components with no target namespace).
284: * @return A list of top-level definitions of the specified type in
285: * <code>objectType</code> and defined in the specified
286: * <code>namespace</code> or an empty <code>XSNamedMap</code>.
287: */
288: public synchronized XSNamedMap getComponentsByNamespace(
289: short objectType, String namespace) {
290: if (objectType <= 0 || objectType > MAX_COMP_IDX
291: || !GLOBAL_COMP[objectType]) {
292: return XSNamedMapImpl.EMPTY_MAP;
293: }
294:
295: // try to find the grammar
296: int i = 0;
297: if (namespace != null) {
298: for (; i < fGrammarCount; ++i) {
299: if (namespace.equals(fNamespaces[i]))
300: break;
301: }
302: } else {
303: for (; i < fGrammarCount; ++i) {
304: if (fNamespaces[i] == null)
305: break;
306: }
307: }
308: if (i == fGrammarCount)
309: return XSNamedMapImpl.EMPTY_MAP;
310:
311: // get the hashtable for this type of components
312: if (fNSComponents[i][objectType] == null) {
313: SymbolHash table = null;
314: switch (objectType) {
315: case XSConstants.TYPE_DEFINITION:
316: case XSTypeDefinition.COMPLEX_TYPE:
317: case XSTypeDefinition.SIMPLE_TYPE:
318: table = fGrammarList[i].fGlobalTypeDecls;
319: break;
320: case XSConstants.ATTRIBUTE_DECLARATION:
321: table = fGrammarList[i].fGlobalAttrDecls;
322: break;
323: case XSConstants.ELEMENT_DECLARATION:
324: table = fGrammarList[i].fGlobalElemDecls;
325: break;
326: case XSConstants.ATTRIBUTE_GROUP:
327: table = fGrammarList[i].fGlobalAttrGrpDecls;
328: break;
329: case XSConstants.MODEL_GROUP_DEFINITION:
330: table = fGrammarList[i].fGlobalGroupDecls;
331: break;
332: case XSConstants.NOTATION_DECLARATION:
333: table = fGrammarList[i].fGlobalNotationDecls;
334: break;
335: }
336:
337: // for complex/simple types, create a special implementation,
338: // which take specific types out of the hash table
339: if (objectType == XSTypeDefinition.COMPLEX_TYPE
340: || objectType == XSTypeDefinition.SIMPLE_TYPE) {
341: fNSComponents[i][objectType] = new XSNamedMap4Types(
342: namespace, table, objectType);
343: } else {
344: fNSComponents[i][objectType] = new XSNamedMapImpl(
345: namespace, table);
346: }
347: }
348:
349: return fNSComponents[i][objectType];
350: }
351:
352: /**
353: * Convenience method. Returns a top-level simple or complex type
354: * definition.
355: * @param name The name of the definition.
356: * @param namespace The namespace of the definition, otherwise null.
357: * @return An <code>XSTypeDefinition</code> or null if such definition
358: * does not exist.
359: */
360: public XSTypeDefinition getTypeDefinition(String name,
361: String namespace) {
362: SchemaGrammar sg = (SchemaGrammar) fGrammarMap
363: .get(null2EmptyString(namespace));
364: if (sg == null)
365: return null;
366: return (XSTypeDefinition) sg.fGlobalTypeDecls.get(name);
367: }
368:
369: /**
370: * Convenience method. Returns a top-level attribute declaration.
371: * @param name The name of the declaration.
372: * @param namespace The namespace of the definition, otherwise null.
373: * @return A top-level attribute declaration or null if such declaration
374: * does not exist.
375: */
376: public XSAttributeDeclaration getAttributeDeclaration(String name,
377: String namespace) {
378: SchemaGrammar sg = (SchemaGrammar) fGrammarMap
379: .get(null2EmptyString(namespace));
380: if (sg == null)
381: return null;
382: return (XSAttributeDeclaration) sg.fGlobalAttrDecls.get(name);
383: }
384:
385: /**
386: * Convenience method. Returns a top-level element declaration.
387: * @param name The name of the declaration.
388: * @param namespace The namespace of the definition, otherwise null.
389: * @return A top-level element declaration or null if such declaration
390: * does not exist.
391: */
392: public XSElementDeclaration getElementDeclaration(String name,
393: String namespace) {
394: SchemaGrammar sg = (SchemaGrammar) fGrammarMap
395: .get(null2EmptyString(namespace));
396: if (sg == null)
397: return null;
398: return (XSElementDeclaration) sg.fGlobalElemDecls.get(name);
399: }
400:
401: /**
402: * Convenience method. Returns a top-level attribute group definition.
403: * @param name The name of the definition.
404: * @param namespace The namespace of the definition, otherwise null.
405: * @return A top-level attribute group definition or null if such
406: * definition does not exist.
407: */
408: public XSAttributeGroupDefinition getAttributeGroup(String name,
409: String namespace) {
410: SchemaGrammar sg = (SchemaGrammar) fGrammarMap
411: .get(null2EmptyString(namespace));
412: if (sg == null)
413: return null;
414: return (XSAttributeGroupDefinition) sg.fGlobalAttrGrpDecls
415: .get(name);
416: }
417:
418: /**
419: * Convenience method. Returns a top-level model group definition.
420: *
421: * @param name The name of the definition.
422: * @param namespace The namespace of the definition, otherwise null.
423: * @return A top-level model group definition definition or null if such
424: * definition does not exist.
425: */
426: public XSModelGroupDefinition getModelGroupDefinition(String name,
427: String namespace) {
428: SchemaGrammar sg = (SchemaGrammar) fGrammarMap
429: .get(null2EmptyString(namespace));
430: if (sg == null)
431: return null;
432: return (XSModelGroupDefinition) sg.fGlobalGroupDecls.get(name);
433: }
434:
435: /**
436: * @see org.apache.xerces.xs.XSModel#getNotationDeclaration(String, String)
437: */
438: public XSNotationDeclaration getNotationDeclaration(String name,
439: String namespace) {
440: SchemaGrammar sg = (SchemaGrammar) fGrammarMap
441: .get(null2EmptyString(namespace));
442: if (sg == null)
443: return null;
444: return (XSNotationDeclaration) sg.fGlobalNotationDecls
445: .get(name);
446: }
447:
448: /**
449: * {annotations} A set of annotations.
450: */
451: public synchronized XSObjectList getAnnotations() {
452: if (fAnnotations != null)
453: return fAnnotations;
454:
455: // do this in two passes to avoid inaccurate array size
456: int totalAnnotations = 0;
457: for (int i = 0; i < fGrammarCount; i++) {
458: totalAnnotations += fGrammarList[i].fNumAnnotations;
459: }
460: XSAnnotationImpl[] annotations = new XSAnnotationImpl[totalAnnotations];
461: int currPos = 0;
462: for (int i = 0; i < fGrammarCount; i++) {
463: SchemaGrammar currGrammar = fGrammarList[i];
464: if (currGrammar.fNumAnnotations > 0) {
465: System.arraycopy(currGrammar.fAnnotations, 0,
466: annotations, currPos,
467: currGrammar.fNumAnnotations);
468: currPos += currGrammar.fNumAnnotations;
469: }
470: }
471: fAnnotations = new XSObjectListImpl(annotations,
472: annotations.length);
473: return fAnnotations;
474: }
475:
476: private static final String null2EmptyString(String str) {
477: return str == null ? XMLSymbols.EMPTY_STRING : str;
478: }
479:
480: /**
481: * REVISIT: to expose identity constraints from XSModel.
482: * For now, we only expose whether there are any IDCs.
483: * We also need to add these methods to the public
484: * XSModel interface.
485: */
486: public boolean hasIDConstraints() {
487: return fHasIDC;
488: }
489:
490: public XSObjectList getSubstitutionGroup(XSElementDeclaration head) {
491: return (XSObjectList) fSubGroupMap.get(head);
492: }
493:
494: } // class XSModelImpl
|