/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/metaobj/trunk/metaobj-impl/api-impl/src/java/org/sakaiproject/metaobj/utils/xml/impl/SchemaNodeImpl.java $ * $Id: SchemaNodeImpl.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2004, 2005, 2006, 2007, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.opensource.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.metaobj.utils.xml.impl; import java.util.ArrayList; import java.util.Collection; import java.util.Hashtable; import java.util.Iterator; import java.util.List; import java.util.Map; import org.jdom.Attribute; import org.jdom.Document; import org.jdom.Element; import org.jdom.Namespace; import org.sakaiproject.metaobj.utils.xml.ElementType; import org.sakaiproject.metaobj.utils.xml.NormalizationException; import org.sakaiproject.metaobj.utils.xml.SchemaFactory; import org.sakaiproject.metaobj.utils.xml.SchemaInvalidException; import org.sakaiproject.metaobj.utils.xml.SchemaNode; import org.sakaiproject.metaobj.utils.xml.ValidatedNode; /** * Created by IntelliJ IDEA. * User: John Ellis * Date: Apr 15, 2004 * Time: 12:21:47 PM * To change this template use File | Settings | File Templates. */ public class SchemaNodeImpl implements SchemaNode { protected Namespace xsdNamespace = Namespace.getNamespace("xs", "http://www.w3.org/2001/XMLSchema"); private SchemaFactory factory = null; private Object path = null; private Element schemaElement; private GlobalMaps globalMaps; private Map globalElements; private Map globalCustomTypes; private Map documentAnnotations; private Map appAnnotations; private boolean documentNode = false; private int maxOccurs = 1; private int minOccurs = 1; private String elementName = "document"; private Namespace targetNamespace; public SchemaNodeImpl(Element schemaElement, GlobalMaps globalMaps) throws SchemaInvalidException { this.globalElements = globalMaps.globalElements; this.globalCustomTypes = globalMaps.globalCustomTypes; this.globalMaps = globalMaps; this.schemaElement = schemaElement; elementName = schemaElement.getAttributeValue("name"); // try and create an element to test the name try { new Element(elementName); } catch (Exception e) { throw new SchemaInvalidException("illegal element name", e); } setupNamespaces(schemaElement); initSchemaElement(); } public SchemaNodeImpl(Document shemaDoc, SchemaFactory factory, Object path) throws SchemaInvalidException { this.factory = factory; this.path = path; globalMaps = new GlobalMaps(); globalElements = new Hashtable(); globalMaps.globalElements = globalElements; globalCustomTypes = new Hashtable(); globalMaps.globalCustomTypes = globalCustomTypes; documentNode = true; Element rootElement = shemaDoc.getRootElement(); schemaElement = rootElement; setupNamespaces(schemaElement); processAnnotations(rootElement.getChild("annotation", xsdNamespace)); processIncludes(rootElement.getChildren("include", xsdNamespace)); List rootSchemaElements = rootElement.getChildren("element", xsdNamespace); for (Iterator i = rootSchemaElements.iterator(); i.hasNext();) { Element schemaElement = (Element) i.next(); globalElements.put(schemaElement.getAttributeValue("name"), createNode(schemaElement)); } rootSchemaElements = rootElement.getChildren("attribute", xsdNamespace); for (Iterator i = rootSchemaElements.iterator(); i.hasNext();) { Element schemaElement = (Element) i.next(); globalElements.put(schemaElement.getAttributeValue("name"), createNode(schemaElement, true)); } rootSchemaElements = rootElement.getChildren("attributeGroup", xsdNamespace); for (Iterator i = rootSchemaElements.iterator(); i.hasNext();) { Element schemaElement = (Element) i.next(); processAttributeGroup(schemaElement); } List rootTypes = rootElement.getChildren("complexType", xsdNamespace); for (Iterator i = rootTypes.iterator(); i.hasNext();) { Element schemaElement = (Element) i.next(); globalCustomTypes.put(schemaElement.getAttributeValue("name"), createTypeNode(schemaElement)); } rootTypes = rootElement.getChildren("simpleType", xsdNamespace); for (Iterator i = rootTypes.iterator(); i.hasNext();) { Element schemaElement = (Element) i.next(); globalCustomTypes.put(schemaElement.getAttributeValue("name"), createTypeNode(schemaElement)); } } protected void setupNamespaces(Element schemaElement) { Element rootElement = null; if (schemaElement.getDocument() == null) { rootElement = schemaElement; } else { rootElement = schemaElement.getDocument().getRootElement(); } xsdNamespace = rootElement.getNamespace(); if (rootElement.getAttribute("targetNamespace") != null) { targetNamespace = Namespace.getNamespace(rootElement.getAttributeValue("targetNamespace")); } else { targetNamespace = Namespace.NO_NAMESPACE; } } protected void processAttributeGroup(Element groupElement) { List attributes = groupElement.getChildren("attribute", xsdNamespace); SchemaNode[] attributeGroup = new SchemaNode[attributes.size()]; for (int i = 0; i < attributeGroup.length; i++) { attributeGroup[i] = createNode((Element) attributes.get(i), true); } getGlobalMaps().globalAttributeGroups.put(groupElement.getAttributeValue("name"), attributeGroup); } protected void processIncludes(List includes) { for (Iterator i = includes.iterator(); i.hasNext();) { Element include = (Element) i.next(); SchemaNodeImpl includedSchema = (SchemaNodeImpl) factory.getRelativeSchema(include.getAttributeValue("schemaLocation"), path); GlobalMaps maps = includedSchema.getGlobalMaps(); this.getGlobalMaps().globalCustomTypes.putAll(maps.globalCustomTypes); this.getGlobalMaps().globalElements.putAll(maps.globalElements); this.getGlobalMaps().globalAttributeGroups.putAll(maps.globalAttributeGroups); } } protected SchemaNode createTypeNode(Element schemaElement) { Element fakeRoot = new Element("element", xsdNamespace); fakeRoot.setAttribute("name", schemaElement.getAttributeValue("name")); if (getTargetNamespace() != Namespace.NO_NAMESPACE) { fakeRoot.setAttribute("targetNamespace", getTargetNamespace().getURI()); } fakeRoot.addContent((Element) schemaElement.clone()); if (schemaElement.getName().equals("complexType")) { return new ComplexSchemaNodeImpl(fakeRoot, globalMaps); } else { return new SimpleSchemaNodeImpl(fakeRoot, globalMaps, false); } } protected void processAnnotations(Element child) { documentAnnotations = new Hashtable(); appAnnotations = new Hashtable(); if (child == null) { return; } processAnnotationList(appAnnotations, child.getChildren("appinfo", xsdNamespace)); processAnnotationList(documentAnnotations, child.getChildren("documentation", xsdNamespace)); } protected void processAnnotationList(Map annotationMap, List children) { for (Iterator i = children.iterator(); i.hasNext();) { Element elem = (Element) i.next(); if (elem.getAttribute("source") != null) { annotationMap.put(elem.getAttributeValue("source"), elem.getText()); } } } protected void initSchemaElement() { processAnnotations(schemaElement.getChild("annotation", xsdNamespace)); if (schemaElement.getAttribute("maxOccurs") != null) { String maxOccursValue = schemaElement.getAttributeValue("maxOccurs"); if (maxOccursValue.equals("unbounded")) { maxOccurs = -1; } else { maxOccurs = Integer.parseInt(maxOccursValue); } } if (schemaElement.getAttribute("minOccurs") != null) { String minOccursValue = schemaElement.getAttributeValue("minOccurs"); minOccurs = Integer.parseInt(minOccursValue); } } protected SchemaNode createNode(Element schemaElement) { return createNode(schemaElement, false); } protected SchemaNode createNode(Element schemaElement, boolean isAttribute) { if (schemaElement.getAttribute("ref") != null) { if (isAttribute) { return new RefAttributeSchemaNodeImpl(schemaElement.getAttributeValue("ref"), schemaElement, globalMaps); } else { return new RefSchemaNodeImpl(schemaElement.getAttributeValue("ref"), schemaElement, globalMaps); } } else if (schemaElement.getAttribute("type") != null && !schemaElement.getAttributeValue("type").startsWith(xsdNamespace.getPrefix())) { return new CustomTypeSchemaNodeImpl(schemaElement, globalMaps, schemaElement.getAttributeValue("type"), isAttribute); } else if (schemaElement.getChild("complexType", xsdNamespace) != null) { return new ComplexSchemaNodeImpl(schemaElement, globalMaps); } else if (isAttribute) { return new AttributeSchemaNodeImpl(schemaElement, globalMaps, isAttribute); } else { return new SimpleSchemaNodeImpl(schemaElement, globalMaps, isAttribute); } } public Namespace getTargetNamespace() { return targetNamespace; } public void setTargetNamespace(Namespace targetNamespace) { this.targetNamespace = targetNamespace; } /** * Validates the passed in node and all children. * Will also normalize any values. * * @param node a jdom element to validate * @return the validated Element wrapped * in a ValidatedNode class */ public ValidatedNode validateAndNormalize(Element node) { if (documentNode) { SchemaNode schemaNode = (SchemaNode) globalElements.get(node.getName()); return schemaNode.validateAndNormalize(node); } throw new UnsupportedOperationException("Cannot call this without this being the document node."); } public ValidatedNode validateAndNormalize(Attribute node) { throw new UnsupportedOperationException("Cannot call this without this being an attribute node."); } /** * Gets the schema object for the named child node. * * @param elementName the name of the schema node to retrive. * @return */ public SchemaNode getChild(String elementName) { if (documentNode) { return (SchemaNode) globalElements.get(elementName); } return null; } public Collection getRootChildren() { if (documentNode) { return globalElements.keySet(); } throw new UnsupportedOperationException("Cannot call this without this being the document node."); } /** * Retuns the max number of times the element * defined by this node can occur in its parent. * The root schema will always return 1 here. * * @return */ public int getMaxOccurs() { return maxOccurs; } /** * Returns the min number of times the element * defined by this node can occur in its parent. * The root schema will always return 1 here. * * @return */ public int getMinOccurs() { return minOccurs; } public String getSchemaNormalizedValue(Object value) throws NormalizationException { throw new UnsupportedOperationException("Cannot call this without this being the document node."); } public Object getActualNormalizedValue(String value) throws NormalizationException { throw new UnsupportedOperationException("Cannot call this without this being the document node."); } // public Object getActualNormalizedValue(String value) throws NormalizationException { // throw new UnsupportedOperationException("Cannot call this without this being the document node."); // } public String getName() { return elementName; } public Class getObjectType() { return Map.class; } public List getChildren() { return new ArrayList(); } public String getDocumentAnnotation(String source) { return (String) getDocumentAnnotations().get(source); } public String getAppAnnotation(String source) { return (String) getAppAnnotations().get(source); } public Map getDocumentAnnotations() { return documentAnnotations; } public Map getAppAnnotations() { return appAnnotations; } public List getEnumeration() { return null; } public boolean hasEnumerations() { return (getEnumeration() != null); } public boolean isAttribute() { return false; } public boolean isDataNode() { return false; } public Element getSchemaElement() { return schemaElement; } public ElementType getType() { return null; } public String getLabel() { String label = null; // todo i18n label label = getDocumentAnnotation("sakai.label"); if (label == null) { label = getDocumentAnnotation("ospi.label"); } if (label == null) { label = getName(); } return label; } public GlobalMaps getGlobalMaps() { return globalMaps; } protected class GlobalMaps { public Map globalElements = new Hashtable(); public Map globalCustomTypes = new Hashtable(); public Map globalAttributeGroups = new Hashtable(); } }