/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/metaobj/trunk/metaobj-impl/api-impl/src/java/org/sakaiproject/metaobj/utils/xml/impl/ComplexSchemaNodeImpl.java $
* $Id: ComplexSchemaNodeImpl.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $
***********************************************************************************
*
* Copyright (c) 2004, 2005, 2006, 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.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.jdom.Attribute;
import org.jdom.Element;
import org.sakaiproject.metaobj.utils.xml.NormalizationException;
import org.sakaiproject.metaobj.utils.xml.SchemaInvalidException;
import org.sakaiproject.metaobj.utils.xml.SchemaNode;
import org.sakaiproject.metaobj.utils.xml.ValidatedNode;
import org.sakaiproject.metaobj.utils.xml.ValidationError;
/**
* Created by IntelliJ IDEA.
* User: John Ellis
* Date: Apr 15, 2004
* Time: 3:47:11 PM
* To change this template use File | Settings | File Templates.
*/
public class ComplexSchemaNodeImpl extends SchemaNodeImpl {
private String[] childrenElements;
private Map childrenMap;
private String[] childrenAttributes;
private Map childrenAttributeMap;
private String[] attributeGroupNames;
private boolean orderDependant = false;
private boolean attributeGroupsSetup = false;
private SchemaNode extensionType;
public ComplexSchemaNodeImpl(Element schemaElement, GlobalMaps globalMaps) throws SchemaInvalidException {
super(schemaElement, globalMaps);
}
protected void initSchemaElement() {
super.initSchemaElement();
childrenMap = new Hashtable();
childrenAttributeMap = new Hashtable();
Element sequenceElement = null;
Element attributeParentElement = null;
Element complexTypeElement =
getSchemaElement().getChild("complexType", xsdNamespace);
attributeParentElement = complexTypeElement;
sequenceElement = complexTypeElement.getChild("sequence", xsdNamespace);
if (sequenceElement == null) {
sequenceElement = complexTypeElement.getChild("choice", xsdNamespace);
}
if (sequenceElement == null) {
Element content = complexTypeElement.getChild("complexContent", xsdNamespace);
if (content == null) {
content = complexTypeElement.getChild("simpleContent", xsdNamespace);
}
Element extension = content.getChild("extension", xsdNamespace);
sequenceElement = extension.getChild("sequence", xsdNamespace);
attributeParentElement = extension;
String baseType = extension.getAttributeValue("base");
if (baseType.startsWith(xsdNamespace.getPrefix())) {
extensionType = new SimpleSchemaNodeImpl(complexTypeElement, getGlobalMaps(), false);
}
else {
extensionType = new CustomTypeSchemaNodeImpl(complexTypeElement, getGlobalMaps(), baseType, false);
}
}
if (sequenceElement != null) {
processSequence(sequenceElement);
}
else {
childrenElements = new String[0];
}
processAttributes(attributeParentElement.getChildren("attribute", xsdNamespace));
processAttributeGroups(attributeParentElement.getChildren("attributeGroup", xsdNamespace));
}
private void processAttributeGroups(List childList) {
attributeGroupNames = new String[childList.size()];
for (int i = 0; i < attributeGroupNames.length; i++) {
Element currentElement = (Element) childList.get(i);
attributeGroupNames[i] = currentElement.getAttributeValue("ref");
}
}
protected void processAttributes(List childList) {
childrenAttributes = new String[childList.size()];
for (int i = 0; i < childrenAttributes.length; i++) {
Element currentElement = (Element) childList.get(i);
childrenAttributes[i] = currentElement.getAttributeValue("name");
if (childrenAttributes[i] == null) {
childrenAttributes[i] = currentElement.getAttributeValue("ref");
}
childrenAttributeMap.put(childrenAttributes[i],
createNode(currentElement, true));
}
}
protected void processSequence(Element sequenceElement) {
List childList = sequenceElement.getChildren("element", xsdNamespace);
childrenElements = new String[childList.size()];
for (int i = 0; i < childrenElements.length; i++) {
Element currentElement = (Element) childList.get(i);
childrenElements[i] = currentElement.getAttributeValue("name");
if (childrenElements[i] == null) {
childrenElements[i] = currentElement.getAttributeValue("ref");
}
childrenMap.put(childrenElements[i],
createNode(currentElement));
}
// looking for sequence or all
if (sequenceElement.getName().equals("sequence")) {
orderDependant = true;
}
}
/**
* 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) {
setupAttributeGroups();
ValidatedNodeImpl validatedNode =
new ValidatedNodeImpl(this, node);
for (int i = 0; i < childrenElements.length; i++) {
SchemaNode currentSchemaNode =
(SchemaNode) childrenMap.get(childrenElements[i]);
int actualNumberOfElements = node.getChildren(childrenElements[i]).size();
if (actualNumberOfElements == 0 && currentSchemaNode.getMinOccurs() == 1) {
ValidatedNodeImpl validatedChildNode =
new ValidatedNodeImpl(currentSchemaNode, null);
validatedChildNode.getErrors().add(new ValidationError(validatedChildNode, "Required field: {0}",
new Object[]{childrenElements[i]}));
validatedNode.getChildren().add(validatedChildNode);
}
else if (actualNumberOfElements > currentSchemaNode.getMaxOccurs() &&
currentSchemaNode.getMaxOccurs() != -1) {
ValidatedNodeImpl validatedChildNode =
new ValidatedNodeImpl(currentSchemaNode, null);
validatedChildNode.getErrors().add(new ValidationError(validatedChildNode, "Too many elements {0}, {1}",
new Object[]{childrenElements[i],
new Integer(getMaxOccurs())}));
validatedNode.getChildren().add(validatedChildNode);
}
else if (actualNumberOfElements < currentSchemaNode.getMinOccurs()) {
ValidatedNodeImpl validatedChildNode =
new ValidatedNodeImpl(currentSchemaNode, null);
validatedChildNode.getErrors().add(new ValidationError(validatedChildNode, "Too few elements {0}, {1}",
new Object[]{childrenElements[i],
new Integer(getMinOccurs())}));
validatedNode.getChildren().add(validatedChildNode);
}
}
List children = node.getChildren();
for (Iterator i = children.iterator(); i.hasNext();) {
Element currentElement = (Element) i.next();
SchemaNode currentSchemaNode = (SchemaNode) childrenMap.get(currentElement.getName());
if (currentSchemaNode == null) {
validatedNode.getErrors().add(new ValidationError("Unkown node {0}",
new Object[]{currentElement.getName()}));
}
else {
validatedNode.getChildren().add(currentSchemaNode.validateAndNormalize(currentElement));
}
}
children = node.getAttributes();
for (Iterator i = children.iterator(); i.hasNext();) {
Attribute currentAttribute = (Attribute) i.next();
SchemaNode currentSchemaNode = (SchemaNode) childrenAttributeMap.get(currentAttribute.getName());
if (currentSchemaNode == null) {
validatedNode.getErrors().add(new ValidationError("Unkown node {0}",
new Object[]{currentAttribute.getName()}));
}
else {
validatedNode.getChildren().add(currentSchemaNode.validateAndNormalize(currentAttribute));
}
}
return validatedNode;
}
protected synchronized void setupAttributeGroups() {
if (attributeGroupsSetup) {
return;
}
attributeGroupsSetup = true;
List newAttributes = new ArrayList();
for (int i = 0; i < attributeGroupNames.length; i++) {
SchemaNode[] nodes = (SchemaNode[]) getGlobalMaps().globalAttributeGroups.get(attributeGroupNames[i]);
for (int j = 0; j < nodes.length; j++) {
newAttributes.add(nodes[j]);
}
}
String[] newAttributeNames = new String[childrenAttributes.length + newAttributes.size()];
System.arraycopy(childrenAttributes, 0, newAttributeNames, 0, childrenAttributes.length);
int index = childrenAttributes.length;
for (Iterator i = newAttributes.iterator(); i.hasNext();) {
SchemaNode node = (SchemaNode) i.next();
newAttributeNames[index] = node.getName();
childrenAttributeMap.put(node.getName(), node);
index++;
}
childrenAttributes = newAttributeNames;
}
/**
* 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 (childrenMap.get(elementName) != null) {
return (SchemaNode) childrenMap.get(elementName);
}
else if (this.getClass().isInstance(extensionType)) {
return extensionType.getChild(elementName);
}
setupAttributeGroups();
return (SchemaNode) childrenAttributeMap.get(elementName);
}
public String getSchemaNormalizedValue(Object value) throws NormalizationException {
if (extensionType != null) {
return extensionType.getSchemaNormalizedValue(value);
}
throw new UnsupportedOperationException("Cannot call this without this being the document node.");
}
public Class getObjectType() {
if (this.getMaxOccurs() > 1) {
return List.class;
}
else {
return Map.class;
}
}
public List getChildren() {
setupAttributeGroups();
List returnedList = new ArrayList();
if (extensionType != null && extensionType.getChildren() != null) {
returnedList.addAll(extensionType.getChildren());
}
for (int i = 0; i < childrenElements.length; i++) {
returnedList.add(childrenMap.get(childrenElements[i]));
}
for (int i = 0; i < childrenAttributes.length; i++) {
returnedList.add(childrenAttributeMap.get(childrenAttributes[i]));
}
return returnedList;
}
public boolean isDataNode() {
if (extensionType != null) {
return extensionType.isDataNode();
}
else {
return false;
}
}
public boolean hasEnumerations() {
if (extensionType != null) {
return extensionType.hasEnumerations();
}
else {
return false;
}
}
public List getEnumeration() {
if (extensionType != null) {
return extensionType.getEnumeration();
}
else {
return super.getEnumeration();
}
}
public Object getActualNormalizedValue(String value) throws NormalizationException {
if (extensionType != null) {
return extensionType.getActualNormalizedValue(value);
}
else {
return super.getActualNormalizedValue(value);
}
}
}