001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/metaobj/tags/sakai_2-4-1/metaobj-impl/api-impl/src/java/org/sakaiproject/metaobj/utils/xml/impl/SchemaNodeImpl.java $
003: * $Id: SchemaNodeImpl.java 21196 2007-02-09 18:57:43Z john.ellis@rsmart.com $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.metaobj.utils.xml.impl;
021:
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.Hashtable;
025: import java.util.Iterator;
026: import java.util.List;
027: import java.util.Map;
028:
029: import org.jdom.Attribute;
030: import org.jdom.Document;
031: import org.jdom.Element;
032: import org.jdom.Namespace;
033: import org.sakaiproject.metaobj.utils.xml.ElementType;
034: import org.sakaiproject.metaobj.utils.xml.NormalizationException;
035: import org.sakaiproject.metaobj.utils.xml.SchemaFactory;
036: import org.sakaiproject.metaobj.utils.xml.SchemaInvalidException;
037: import org.sakaiproject.metaobj.utils.xml.SchemaNode;
038: import org.sakaiproject.metaobj.utils.xml.ValidatedNode;
039:
040: /**
041: * Created by IntelliJ IDEA.
042: * User: John Ellis
043: * Date: Apr 15, 2004
044: * Time: 12:21:47 PM
045: * To change this template use File | Settings | File Templates.
046: */
047: public class SchemaNodeImpl implements SchemaNode {
048:
049: protected Namespace xsdNamespace = Namespace.getNamespace("xs",
050: "http://www.w3.org/2001/XMLSchema");
051:
052: private SchemaFactory factory = null;
053: private Object path = null;
054: private Element schemaElement;
055:
056: private GlobalMaps globalMaps;
057:
058: private Map globalElements;
059: private Map globalCustomTypes;
060:
061: private Map documentAnnotations;
062: private Map appAnnotations;
063:
064: private boolean documentNode = false;
065: private int maxOccurs = 1;
066: private int minOccurs = 1;
067: private String elementName = "document";
068: private Namespace targetNamespace;
069:
070: public SchemaNodeImpl(Element schemaElement, GlobalMaps globalMaps)
071: throws SchemaInvalidException {
072:
073: this .globalElements = globalMaps.globalElements;
074: this .globalCustomTypes = globalMaps.globalCustomTypes;
075: this .globalMaps = globalMaps;
076: this .schemaElement = schemaElement;
077: elementName = schemaElement.getAttributeValue("name");
078:
079: setupNamespaces(schemaElement);
080:
081: initSchemaElement();
082: }
083:
084: public SchemaNodeImpl(Document shemaDoc, SchemaFactory factory,
085: Object path) throws SchemaInvalidException {
086:
087: this .factory = factory;
088: this .path = path;
089:
090: globalMaps = new GlobalMaps();
091:
092: globalElements = new Hashtable();
093: globalMaps.globalElements = globalElements;
094: globalCustomTypes = new Hashtable();
095: globalMaps.globalCustomTypes = globalCustomTypes;
096: documentNode = true;
097:
098: Element rootElement = shemaDoc.getRootElement();
099: schemaElement = rootElement;
100:
101: setupNamespaces(schemaElement);
102:
103: processAnnotations(rootElement.getChild("annotation",
104: xsdNamespace));
105: processIncludes(rootElement
106: .getChildren("include", xsdNamespace));
107:
108: List rootSchemaElements = rootElement.getChildren("element",
109: xsdNamespace);
110:
111: for (Iterator i = rootSchemaElements.iterator(); i.hasNext();) {
112: Element schemaElement = (Element) i.next();
113:
114: globalElements.put(schemaElement.getAttributeValue("name"),
115: createNode(schemaElement));
116: }
117:
118: rootSchemaElements = rootElement.getChildren("attribute",
119: xsdNamespace);
120:
121: for (Iterator i = rootSchemaElements.iterator(); i.hasNext();) {
122: Element schemaElement = (Element) i.next();
123:
124: globalElements.put(schemaElement.getAttributeValue("name"),
125: createNode(schemaElement, true));
126: }
127:
128: rootSchemaElements = rootElement.getChildren("attributeGroup",
129: xsdNamespace);
130:
131: for (Iterator i = rootSchemaElements.iterator(); i.hasNext();) {
132: Element schemaElement = (Element) i.next();
133:
134: processAttributeGroup(schemaElement);
135: }
136:
137: List rootTypes = rootElement.getChildren("complexType",
138: xsdNamespace);
139:
140: for (Iterator i = rootTypes.iterator(); i.hasNext();) {
141: Element schemaElement = (Element) i.next();
142:
143: globalCustomTypes.put(schemaElement
144: .getAttributeValue("name"),
145: createTypeNode(schemaElement));
146: }
147:
148: rootTypes = rootElement.getChildren("simpleType", xsdNamespace);
149:
150: for (Iterator i = rootTypes.iterator(); i.hasNext();) {
151: Element schemaElement = (Element) i.next();
152:
153: globalCustomTypes.put(schemaElement
154: .getAttributeValue("name"),
155: createTypeNode(schemaElement));
156: }
157: }
158:
159: protected void setupNamespaces(Element schemaElement) {
160:
161: Element rootElement = null;
162: if (schemaElement.getDocument() == null) {
163: rootElement = schemaElement;
164: } else {
165: rootElement = schemaElement.getDocument().getRootElement();
166: }
167:
168: xsdNamespace = rootElement.getNamespace();
169:
170: if (rootElement.getAttribute("targetNamespace") != null) {
171: targetNamespace = Namespace.getNamespace(rootElement
172: .getAttributeValue("targetNamespace"));
173: } else {
174: targetNamespace = Namespace.NO_NAMESPACE;
175: }
176:
177: }
178:
179: protected void processAttributeGroup(Element groupElement) {
180: List attributes = groupElement.getChildren("attribute",
181: xsdNamespace);
182: SchemaNode[] attributeGroup = new SchemaNode[attributes.size()];
183:
184: for (int i = 0; i < attributeGroup.length; i++) {
185: attributeGroup[i] = createNode((Element) attributes.get(i),
186: true);
187: }
188:
189: getGlobalMaps().globalAttributeGroups.put(groupElement
190: .getAttributeValue("name"), attributeGroup);
191: }
192:
193: protected void processIncludes(List includes) {
194: for (Iterator i = includes.iterator(); i.hasNext();) {
195: Element include = (Element) i.next();
196: SchemaNodeImpl includedSchema = (SchemaNodeImpl) factory
197: .getRelativeSchema(include
198: .getAttributeValue("schemaLocation"), path);
199: GlobalMaps maps = includedSchema.getGlobalMaps();
200: this .getGlobalMaps().globalCustomTypes
201: .putAll(maps.globalCustomTypes);
202: this .getGlobalMaps().globalElements
203: .putAll(maps.globalElements);
204: this .getGlobalMaps().globalAttributeGroups
205: .putAll(maps.globalAttributeGroups);
206: }
207: }
208:
209: protected SchemaNode createTypeNode(Element schemaElement) {
210:
211: Element fakeRoot = new Element("element", xsdNamespace);
212: fakeRoot.setAttribute("name", schemaElement
213: .getAttributeValue("name"));
214:
215: if (getTargetNamespace() != Namespace.NO_NAMESPACE) {
216: fakeRoot.setAttribute("targetNamespace",
217: getTargetNamespace().getURI());
218: }
219:
220: fakeRoot.addContent((Element) schemaElement.clone());
221: if (schemaElement.getName().equals("complexType")) {
222: return new ComplexSchemaNodeImpl(fakeRoot, globalMaps);
223: } else {
224: return new SimpleSchemaNodeImpl(fakeRoot, globalMaps, false);
225: }
226: }
227:
228: protected void processAnnotations(Element child) {
229: documentAnnotations = new Hashtable();
230: appAnnotations = new Hashtable();
231:
232: if (child == null) {
233: return;
234: }
235:
236: processAnnotationList(appAnnotations, child.getChildren(
237: "appinfo", xsdNamespace));
238: processAnnotationList(documentAnnotations, child.getChildren(
239: "documentation", xsdNamespace));
240: }
241:
242: protected void processAnnotationList(Map annotationMap,
243: List children) {
244: for (Iterator i = children.iterator(); i.hasNext();) {
245: Element elem = (Element) i.next();
246: if (elem.getAttribute("source") != null) {
247: annotationMap.put(elem.getAttributeValue("source"),
248: elem.getText());
249: }
250: }
251: }
252:
253: protected void initSchemaElement() {
254:
255: processAnnotations(schemaElement.getChild("annotation",
256: xsdNamespace));
257:
258: if (schemaElement.getAttribute("maxOccurs") != null) {
259: String maxOccursValue = schemaElement
260: .getAttributeValue("maxOccurs");
261:
262: if (maxOccursValue.equals("unbounded")) {
263: maxOccurs = -1;
264: } else {
265: maxOccurs = Integer.parseInt(maxOccursValue);
266: }
267: }
268:
269: if (schemaElement.getAttribute("minOccurs") != null) {
270: String minOccursValue = schemaElement
271: .getAttributeValue("minOccurs");
272: minOccurs = Integer.parseInt(minOccursValue);
273: }
274: }
275:
276: protected SchemaNode createNode(Element schemaElement) {
277: return createNode(schemaElement, false);
278: }
279:
280: protected SchemaNode createNode(Element schemaElement,
281: boolean isAttribute) {
282: if (schemaElement.getAttribute("ref") != null) {
283: if (isAttribute) {
284: return new RefAttributeSchemaNodeImpl(schemaElement
285: .getAttributeValue("ref"), schemaElement,
286: globalMaps);
287: } else {
288: return new RefSchemaNodeImpl(schemaElement
289: .getAttributeValue("ref"), schemaElement,
290: globalMaps);
291: }
292: } else if (schemaElement.getAttribute("type") != null
293: && !schemaElement.getAttributeValue("type").startsWith(
294: xsdNamespace.getPrefix())) {
295: return new CustomTypeSchemaNodeImpl(schemaElement,
296: globalMaps,
297: schemaElement.getAttributeValue("type"),
298: isAttribute);
299: } else if (schemaElement.getChild("complexType", xsdNamespace) != null) {
300: return new ComplexSchemaNodeImpl(schemaElement, globalMaps);
301: } else if (isAttribute) {
302: return new AttributeSchemaNodeImpl(schemaElement,
303: globalMaps, isAttribute);
304: } else {
305: return new SimpleSchemaNodeImpl(schemaElement, globalMaps,
306: isAttribute);
307: }
308: }
309:
310: public Namespace getTargetNamespace() {
311: return targetNamespace;
312: }
313:
314: public void setTargetNamespace(Namespace targetNamespace) {
315: this .targetNamespace = targetNamespace;
316: }
317:
318: /**
319: * Validates the passed in node and all children.
320: * Will also normalize any values.
321: *
322: * @param node a jdom element to validate
323: * @return the validated Element wrapped
324: * in a ValidatedNode class
325: */
326: public ValidatedNode validateAndNormalize(Element node) {
327:
328: if (documentNode) {
329: SchemaNode schemaNode = (SchemaNode) globalElements
330: .get(node.getName());
331:
332: return schemaNode.validateAndNormalize(node);
333: }
334:
335: throw new UnsupportedOperationException(
336: "Cannot call this without this being the document node.");
337: }
338:
339: public ValidatedNode validateAndNormalize(Attribute node) {
340: throw new UnsupportedOperationException(
341: "Cannot call this without this being an attribute node.");
342: }
343:
344: /**
345: * Gets the schema object for the named child node.
346: *
347: * @param elementName the name of the schema node to retrive.
348: * @return
349: */
350: public SchemaNode getChild(String elementName) {
351: if (documentNode) {
352: return (SchemaNode) globalElements.get(elementName);
353: }
354:
355: return null;
356: }
357:
358: public Collection getRootChildren() {
359: if (documentNode) {
360: return globalElements.keySet();
361: }
362:
363: throw new UnsupportedOperationException(
364: "Cannot call this without this being the document node.");
365: }
366:
367: /**
368: * Retuns the max number of times the element
369: * defined by this node can occur in its parent.
370: * The root schema will always return 1 here.
371: *
372: * @return
373: */
374: public int getMaxOccurs() {
375: return maxOccurs;
376: }
377:
378: /**
379: * Returns the min number of times the element
380: * defined by this node can occur in its parent.
381: * The root schema will always return 1 here.
382: *
383: * @return
384: */
385: public int getMinOccurs() {
386: return minOccurs;
387: }
388:
389: public String getSchemaNormalizedValue(Object value)
390: throws NormalizationException {
391: throw new UnsupportedOperationException(
392: "Cannot call this without this being the document node.");
393: }
394:
395: public Object getActualNormalizedValue(String value)
396: throws NormalizationException {
397: throw new UnsupportedOperationException(
398: "Cannot call this without this being the document node.");
399: }
400:
401: // public Object getActualNormalizedValue(String value) throws NormalizationException {
402: // throw new UnsupportedOperationException("Cannot call this without this being the document node.");
403: // }
404:
405: public String getName() {
406: return elementName;
407: }
408:
409: public Class getObjectType() {
410: return Map.class;
411: }
412:
413: public List getChildren() {
414: return new ArrayList();
415: }
416:
417: public String getDocumentAnnotation(String source) {
418: return (String) getDocumentAnnotations().get(source);
419: }
420:
421: public String getAppAnnotation(String source) {
422: return (String) getAppAnnotations().get(source);
423: }
424:
425: public Map getDocumentAnnotations() {
426: return documentAnnotations;
427: }
428:
429: public Map getAppAnnotations() {
430: return appAnnotations;
431: }
432:
433: public List getEnumeration() {
434: return null;
435: }
436:
437: public boolean hasEnumerations() {
438: return (getEnumeration() != null);
439: }
440:
441: public boolean isAttribute() {
442: return false;
443: }
444:
445: public boolean isDataNode() {
446: return false;
447: }
448:
449: public Element getSchemaElement() {
450: return schemaElement;
451: }
452:
453: public ElementType getType() {
454: return null;
455: }
456:
457: public String getLabel() {
458: String label = null;
459: // todo i18n label
460:
461: label = getDocumentAnnotation("sakai.label");
462: if (label == null) {
463: label = getDocumentAnnotation("ospi.label");
464: }
465:
466: if (label == null) {
467: label = getName();
468: }
469:
470: return label;
471: }
472:
473: public GlobalMaps getGlobalMaps() {
474: return globalMaps;
475: }
476:
477: protected class GlobalMaps {
478: public Map globalElements = new Hashtable();
479: public Map globalCustomTypes = new Hashtable();
480: public Map globalAttributeGroups = new Hashtable();
481: }
482:
483: }
|