001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.xml.impl;
017:
018: import java.util.ArrayList;
019: import java.util.Collection;
020: import java.util.Collections;
021: import java.util.HashMap;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025:
026: import javax.xml.namespace.QName;
027:
028: import org.apache.commons.collections.OrderedMap;
029: import org.apache.commons.collections.map.ListOrderedMap;
030: import org.eclipse.emf.common.notify.Adapter;
031: import org.eclipse.emf.common.notify.Notification;
032: import org.eclipse.emf.common.notify.Notifier;
033: import org.eclipse.xsd.XSDAttributeDeclaration;
034: import org.eclipse.xsd.XSDAttributeGroupDefinition;
035: import org.eclipse.xsd.XSDComplexTypeDefinition;
036: import org.eclipse.xsd.XSDElementDeclaration;
037: import org.eclipse.xsd.XSDImport;
038: import org.eclipse.xsd.XSDInclude;
039: import org.eclipse.xsd.XSDNamedComponent;
040: import org.eclipse.xsd.XSDPackage;
041: import org.eclipse.xsd.XSDParticle;
042: import org.eclipse.xsd.XSDSchema;
043: import org.eclipse.xsd.XSDSimpleTypeDefinition;
044: import org.eclipse.xsd.XSDTypeDefinition;
045: import org.eclipse.xsd.util.XSDSchemaBuildingTools;
046: import org.eclipse.xsd.util.XSDUtil;
047: import org.geotools.xml.SchemaIndex;
048: import org.geotools.xml.Schemas;
049:
050: public class SchemaIndexImpl implements SchemaIndex {
051: /**
052: * The schemas
053: */
054: XSDSchema[] schemas;
055:
056: /**
057: * Indexes
058: */
059: HashMap elementIndex;
060: HashMap attributeIndex;
061: HashMap attributeGroupIndex;
062: HashMap complexTypeIndex;
063: HashMap simpleTypeIndex;
064:
065: /**
066: * Cache of elements to children
067: */
068: HashMap/*<XSDElementDeclaration,OrderedMap>*/element2children = new HashMap();
069: /**
070: * Cache of elemnets to attributes
071: */
072: HashMap/*<XSDElementDeclaratoin,List>*/element2attributes = new HashMap();
073:
074: public SchemaIndexImpl(XSDSchema[] schemas) {
075: this .schemas = new XSDSchema[schemas.length + 1];
076:
077: //set the schemas passed in
078: for (int i = 0; i < schemas.length; i++) {
079: this .schemas[i] = schemas[i];
080: this .schemas[i].eAdapters().add(new SchemaAdapter());
081: }
082:
083: //add the schema for xml schema itself
084: this .schemas[schemas.length] = schemas[0].getSchemaForSchema();
085: }
086:
087: public XSDSchema[] getSchemas() {
088: return schemas;
089: }
090:
091: public XSDImport[] getImports() {
092: Collection imports = find(XSDImport.class);
093:
094: return (XSDImport[]) imports.toArray(new XSDImport[imports
095: .size()]);
096: }
097:
098: public XSDInclude[] getIncludes() {
099: Collection includes = find(XSDInclude.class);
100:
101: return (XSDInclude[]) includes.toArray(new XSDInclude[includes
102: .size()]);
103: }
104:
105: public XSDElementDeclaration getElementDeclaration(QName qName) {
106: return (XSDElementDeclaration) lookup(getElementIndex(), qName);
107: //return (XSDElementDeclaration) getElementIndex().get(qName);
108: }
109:
110: public XSDAttributeDeclaration getAttributeDeclaration(QName qName) {
111: return (XSDAttributeDeclaration) lookup(getAttributeIndex(),
112: qName);
113: //return (XSDAttributeDeclaration) getAttributeIndex().get(qName);
114: }
115:
116: public XSDAttributeGroupDefinition getAttributeGroupDefinition(
117: QName qName) {
118: return (XSDAttributeGroupDefinition) lookup(
119: getAttributeGroupIndex(), qName);
120: //return (XSDAttributeGroupDefinition) getAttributeGroupIndex().get(qName);
121: }
122:
123: public XSDComplexTypeDefinition getComplexTypeDefinition(QName qName) {
124: return (XSDComplexTypeDefinition) lookup(getComplexTypeIndex(),
125: qName);
126: //return (XSDComplexTypeDefinition) getComplexTypeIndex().get(qName);
127: }
128:
129: public XSDSimpleTypeDefinition getSimpleTypeDefinition(QName qName) {
130: return (XSDSimpleTypeDefinition) lookup(getSimpleTypeIndex(),
131: qName);
132: //return (XSDSimpleTypeDefinition) getSimpleTypeIndex().get(qName);
133: }
134:
135: public XSDTypeDefinition getTypeDefinition(QName qName) {
136: XSDTypeDefinition type = getComplexTypeDefinition(qName);
137:
138: if (type == null) {
139: type = getSimpleTypeDefinition(qName);
140: }
141:
142: return type;
143: }
144:
145: protected XSDNamedComponent lookup(Map index, QName qName) {
146: XSDNamedComponent component = (XSDNamedComponent) index
147: .get(qName);
148: if (component != null) {
149: return component;
150: }
151:
152: //check for namespace wildcard
153: if ("*".equals(qName.getNamespaceURI())) {
154: ArrayList matches = new ArrayList();
155: for (Iterator e = index.entrySet().iterator(); e.hasNext();) {
156: Map.Entry entry = (Map.Entry) e.next();
157: QName name = (QName) entry.getKey();
158:
159: if (name.getLocalPart().equals(qName.getLocalPart())) {
160: matches.add(entry.getValue());
161: }
162: }
163:
164: if (matches.size() == 1) {
165: return (XSDNamedComponent) matches.get(0);
166: }
167: }
168:
169: return null;
170: }
171:
172: protected OrderedMap children(XSDElementDeclaration parent) {
173: OrderedMap children = (OrderedMap) element2children.get(parent);
174: if (children == null) {
175: synchronized (this ) {
176: if (children == null) {
177: children = new ListOrderedMap();
178: for (Iterator i = Schemas.getChildElementParticles(
179: parent.getType(), true).iterator(); i
180: .hasNext();) {
181: XSDParticle particle = (XSDParticle) i.next();
182: XSDElementDeclaration child = (XSDElementDeclaration) particle
183: .getContent();
184: if (child.isElementDeclarationReference()) {
185: child = child
186: .getResolvedElementDeclaration();
187: }
188:
189: QName childName = null;
190: if (child.getTargetNamespace() != null) {
191: childName = new QName(child
192: .getTargetNamespace(), child
193: .getName());
194: } else if (parent.getTargetNamespace() != null) {
195: childName = new QName(parent
196: .getTargetNamespace(), child
197: .getName());
198: } else if (parent.getType()
199: .getTargetNamespace() != null) {
200: childName = new QName(parent.getType()
201: .getTargetNamespace(), child
202: .getName());
203: } else {
204: childName = new QName(null, child.getName());
205: }
206:
207: children.put(childName, particle);
208:
209: }
210: element2children.put(parent, children);
211: }
212: }
213: }
214:
215: return children;
216: }
217:
218: public XSDElementDeclaration getChildElement(
219: XSDElementDeclaration parent, QName childName) {
220: OrderedMap children = (OrderedMap) children(parent);
221: XSDParticle particle = (XSDParticle) children.get(childName);
222: if (particle != null) {
223: XSDElementDeclaration child = (XSDElementDeclaration) particle
224: .getContent();
225: if (child.isElementDeclarationReference()) {
226: child = child.getResolvedElementDeclaration();
227: }
228:
229: return child;
230: }
231:
232: if ("*".equals(childName.getNamespaceURI())) {
233: //do a check just on local name
234: ArrayList matches = new ArrayList();
235: for (Iterator e = children.entrySet().iterator(); e
236: .hasNext();) {
237: Map.Entry entry = (Map.Entry) e.next();
238: QName name = (QName) entry.getKey();
239:
240: if (name.getLocalPart()
241: .equals(childName.getLocalPart())) {
242: matches.add(entry.getValue());
243: }
244: }
245:
246: if (matches.size() == 1) {
247: particle = (XSDParticle) matches.get(0);
248: XSDElementDeclaration child = (XSDElementDeclaration) particle
249: .getContent();
250: if (child.isElementDeclarationReference()) {
251: child = child.getResolvedElementDeclaration();
252: }
253:
254: return child;
255: }
256: }
257:
258: return null;
259: }
260:
261: public List getChildElementParticles(XSDElementDeclaration parent) {
262: return new ArrayList(children(parent).values());
263: }
264:
265: public List getAttributes(XSDElementDeclaration element) {
266: List attributes = (List) element2attributes.get(element);
267: if (attributes == null) {
268: attributes = Schemas.getAttributeDeclarations(element);
269: element2attributes.put(element, attributes);
270: }
271:
272: return Collections.unmodifiableList(attributes);
273: }
274:
275: protected Collection find(Class c) {
276: ArrayList found = new ArrayList();
277:
278: for (int i = 0; i < schemas.length; i++) {
279: XSDSchema schema = schemas[i];
280:
281: List content = schema.getContents();
282:
283: for (Iterator itr = content.iterator(); itr.hasNext();) {
284: Object o = itr.next();
285:
286: if (c.isAssignableFrom(o.getClass())) {
287: found.add(o);
288: }
289: }
290: }
291:
292: return found;
293: }
294:
295: protected HashMap getElementIndex() {
296: if (elementIndex == null) {
297: synchronized (this ) {
298: if (elementIndex == null) {
299: buildElementIndex();
300: }
301: }
302:
303: }
304:
305: return elementIndex;
306: }
307:
308: protected HashMap getAttributeIndex() {
309: if (attributeIndex == null) {
310: synchronized (this ) {
311: if (attributeIndex == null) {
312: buildAttriubuteIndex();
313: }
314: }
315: }
316:
317: return attributeIndex;
318: }
319:
320: protected HashMap getAttributeGroupIndex() {
321: if (attributeGroupIndex == null) {
322: synchronized (this ) {
323: if (attributeGroupIndex == null) {
324: buildAttributeGroupIndex();
325: }
326: }
327:
328: }
329:
330: return attributeGroupIndex;
331: }
332:
333: protected HashMap getComplexTypeIndex() {
334: if (complexTypeIndex == null) {
335: synchronized (this ) {
336: if (complexTypeIndex == null) {
337: buildComplexTypeIndex();
338: }
339: }
340: }
341:
342: return complexTypeIndex;
343: }
344:
345: protected HashMap getSimpleTypeIndex() {
346: if (simpleTypeIndex == null) {
347: synchronized (this ) {
348: if (simpleTypeIndex == null) {
349: buildSimpleTypeIndex();
350: }
351: }
352: }
353:
354: return simpleTypeIndex;
355: }
356:
357: protected void buildElementIndex() {
358: elementIndex = new HashMap();
359:
360: for (int i = 0; i < schemas.length; i++) {
361: XSDSchema schema = schemas[i];
362:
363: for (Iterator e = schema.getElementDeclarations()
364: .iterator(); e.hasNext();) {
365: XSDElementDeclaration element = (XSDElementDeclaration) e
366: .next();
367:
368: QName qName = new QName(element.getTargetNamespace(),
369: element.getName());
370: elementIndex.put(qName, element);
371: }
372: }
373: }
374:
375: protected void buildAttriubuteIndex() {
376: attributeIndex = new HashMap();
377:
378: for (int i = 0; i < schemas.length; i++) {
379: XSDSchema schema = schemas[i];
380:
381: for (Iterator a = schema.getAttributeDeclarations()
382: .iterator(); a.hasNext();) {
383: XSDAttributeDeclaration attribute = (XSDAttributeDeclaration) a
384: .next();
385:
386: QName qName = new QName(attribute.getTargetNamespace(),
387: attribute.getName());
388: attributeIndex.put(qName, attribute);
389: }
390: }
391: }
392:
393: protected void buildAttributeGroupIndex() {
394: attributeGroupIndex = new HashMap();
395:
396: for (int i = 0; i < schemas.length; i++) {
397: XSDSchema schema = schemas[i];
398:
399: for (Iterator g = schema.getAttributeGroupDefinitions()
400: .iterator(); g.hasNext();) {
401: XSDAttributeGroupDefinition group = (XSDAttributeGroupDefinition) g
402: .next();
403:
404: QName qName = new QName(group.getTargetNamespace(),
405: group.getName());
406: attributeGroupIndex.put(qName, group);
407: }
408: }
409: }
410:
411: protected void buildComplexTypeIndex() {
412: complexTypeIndex = new HashMap();
413:
414: for (int i = 0; i < schemas.length; i++) {
415: XSDSchema schema = schemas[i];
416:
417: for (Iterator t = schema.getTypeDefinitions().iterator(); t
418: .hasNext();) {
419: XSDTypeDefinition type = (XSDTypeDefinition) t.next();
420:
421: if (type instanceof XSDComplexTypeDefinition) {
422: QName qName = new QName(type.getTargetNamespace(),
423: type.getName());
424: complexTypeIndex.put(qName, type);
425: }
426: }
427: }
428: }
429:
430: protected void buildSimpleTypeIndex() {
431: simpleTypeIndex = new HashMap();
432:
433: for (int i = 0; i < schemas.length; i++) {
434: XSDSchema schema = schemas[i];
435:
436: for (Iterator t = schema.getTypeDefinitions().iterator(); t
437: .hasNext();) {
438: XSDTypeDefinition type = (XSDTypeDefinition) t.next();
439:
440: if (type instanceof XSDSimpleTypeDefinition) {
441: QName qName = new QName(type.getTargetNamespace(),
442: type.getName());
443: simpleTypeIndex.put(qName, type);
444: }
445: }
446: }
447: }
448:
449: class SchemaAdapter implements Adapter {
450:
451: Notifier target;
452:
453: Notification last;
454:
455: public Notifier getTarget() {
456: return target;
457: }
458:
459: public void setTarget(Notifier target) {
460: this .target = target;
461: }
462:
463: public boolean isAdapterForType(Object object) {
464: return object instanceof XSDSchema;
465: }
466:
467: public void notifyChanged(Notification notification) {
468: if (notification.getEventType() == Notification.ADD) {
469: switch (notification.getFeatureID(XSDSchema.class)) {
470: case XSDPackage.XSD_SCHEMA__ATTRIBUTE_DECLARATIONS:
471: synchronized (SchemaIndexImpl.this) {
472: attributeIndex = null;
473: }
474: break;
475:
476: case XSDPackage.XSD_SCHEMA__ELEMENT_DECLARATIONS:
477: synchronized (SchemaIndexImpl.this) {
478: elementIndex = null;
479: }
480: break;
481:
482: case XSDPackage.XSD_SCHEMA__TYPE_DEFINITIONS:
483: synchronized (SchemaIndexImpl.this) {
484: complexTypeIndex = null;
485: simpleTypeIndex = null;
486: }
487: break;
488:
489: case XSDPackage.XSD_SCHEMA__ATTRIBUTE_GROUP_DEFINITIONS:
490: synchronized (SchemaIndexImpl.this) {
491: attributeGroupIndex = null;
492: }
493: break;
494: }
495: }
496: }
497: }
498: }
|