All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.plasma.provisioning.xsd.XSDSchemaConverter Maven / Gradle / Ivy

There is a newer version: 1.3.3
Show newest version
/**
 *         PlasmaSDO™ License
 * 
 * This is a community release of PlasmaSDO™, a dual-license 
 * Service Data Object (SDO) 2.1 implementation. 
 * This particular copy of the software is released under the 
 * version 2 of the GNU General Public License. PlasmaSDO™ was developed by 
 * TerraMeta Software, Inc.
 * 
 * Copyright (c) 2013, TerraMeta Software, Inc. All rights reserved.
 * 
 * General License information can be found below.
 * 
 * This distribution may include materials developed by third
 * parties. For license and attribution notices for these
 * materials, please refer to the documentation that accompanies
 * this distribution (see the "Licenses for Third-Party Components"
 * appendix) or view the online documentation at 
 * .
 *  
 */
package org.plasma.provisioning.xsd;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.plasma.provisioning.Class;
import org.plasma.provisioning.ClassRef;
import org.plasma.provisioning.DataTypeRef;
import org.plasma.provisioning.Documentation;
import org.plasma.provisioning.DocumentationType;
import org.plasma.provisioning.Enumeration;
import org.plasma.provisioning.Model;
import org.plasma.provisioning.Property;
import org.plasma.provisioning.SchemaConverter;
import org.plasma.xml.schema.AbstractComplexType;
import org.plasma.xml.schema.Annotated;
import org.plasma.xml.schema.Annotation;
import org.plasma.xml.schema.Any;
import org.plasma.xml.schema.Attribute;
import org.plasma.xml.schema.AttributeGroup;
import org.plasma.xml.schema.AttributeGroupRef;
import org.plasma.xml.schema.ComplexRestrictionType;
import org.plasma.xml.schema.ComplexType;
import org.plasma.xml.schema.Element;
import org.plasma.xml.schema.ExplicitGroup;
import org.plasma.xml.schema.ExtensionType;
import org.plasma.xml.schema.LocalElement;
import org.plasma.xml.schema.OpenAttrs;
import org.plasma.xml.schema.Schema;
import org.plasma.xml.schema.SchemaConstants;
import org.plasma.xml.schema.SchemaUtil;
import org.plasma.xml.schema.SimpleExtensionType;
import org.plasma.xml.schema.SimpleType;


public class XSDSchemaConverter 
    implements SchemaConverter 
{
	private static Log log = LogFactory.getLog(
			   XSDSchemaConverter.class); 
	private ConverterSupport support;   
	private QName appNamespaceQName;
    protected String destNamespaceURI;
    protected String destNamespacePrefix;
    protected PropertyAssembler propertyAssembler;
    protected ClassAssembler classAssembler;
	
    public XSDSchemaConverter(Schema schema, 
    	String destNamespaceURI,
    	String destNamespacePrefix) {
    	this.destNamespaceURI = destNamespaceURI;
    	this.destNamespacePrefix = destNamespacePrefix;
    	this.support = new ConverterSupport(schema, 
    			destNamespaceURI, destNamespacePrefix);
        this.appNamespaceQName = this.support.findOpenAttributeQNameByValue(
        		this.support.getSchema().getTargetNamespace(), 
        		this.support.getSchema()); 
    	this.propertyAssembler = new PropertyAssembler(
    			this.support, this.appNamespaceQName);    	
    	this.classAssembler = new ClassAssembler(this.support,
    			this.destNamespaceURI,
        		this.destNamespacePrefix);
	}
	
    @SuppressWarnings("unchecked")
	public Model buildModel()
    {
        Model model = new Model();
    	model.setName(this.support.getSchema().getId());
        model.setId(UUID.randomUUID().toString());
        model.setUri(this.support.getDestNamespaceURI());
        
        for (OpenAttrs attrs : this.support.getSchema().getIncludesAndImportsAndRedefines()) {
        	if (attrs instanceof Annotation) {
        		String doc = this.support.getDocumentationContent((Annotation)attrs);
        		if (doc != null && doc.length() > 0) {
        			Documentation documentation = this.support.createDocumentation(
        	            	DocumentationType.DEFINITION, doc);
        			model.getDocumentations().add(documentation);
        		}
        	}
        }
        
        // map top-level objects (process attributes/properties on another pass)
        for (Annotated annotated : this.support.getSchema().getSimpleTypesAndComplexTypesAndGroups()) {
        	if (annotated instanceof ComplexType)
        	{
        	    ComplexType complexType = (ComplexType)annotated;	
        	    if (complexType.getName().equals(SchemaUtil.getSerializationBaseTypeName()))
        	    	continue; // skip the serialization base type
        	    this.support.getComplexTypeMap().put(complexType.getName(), complexType);
        	}
        	else if (annotated instanceof SimpleType) {
        		SimpleType simpleType = (SimpleType)annotated;	
        		if (simpleType.getName() == null || simpleType.getName().trim().length() == 0)
        			throw new IllegalStateException("expected name for top level simple type");
        		this.support.getSimpleTypeMap().put(simpleType.getName(), simpleType);
        	}
        	else if (annotated instanceof Element) {
        		Element element = (Element)annotated;
        		if (element.getName() == null || element.getName().trim().length() == 0)
        			throw new IllegalStateException("expected name for top level element");
        		this.support.getElementMap().put(element.getName(), element);
        	}
        	else if (annotated instanceof AttributeGroup) {
        		AttributeGroup attrGroup = (AttributeGroup)annotated;
        		this.support.getAttributeGroupMap().put(attrGroup.getName(), attrGroup);
        		this.support.getAttributeGroupMap().put(attrGroup.getId(), attrGroup);
        	}
        	else
        		log.warn("unknown annotated class, " 
        				+ annotated.getClass().getName());
        }

        // collect local enumerations from type hierarchies
        // starting with each top-level simple type
        EnumerationAssembler enumerationAssembler = new EnumerationAssembler(
        		this.support,
        		this.destNamespaceURI, this.destNamespacePrefix);
        for (Annotated annotated : this.support.getSchema().getSimpleTypesAndComplexTypesAndGroups()) {
        	if (annotated instanceof SimpleType) {
        		SimpleType simpleType = (SimpleType)annotated;
        		EnumerationCollector collector = 
        			new EnumerationCollector(this.support.getSchema(), 
        				this.support.getSimpleTypeMap(), enumerationAssembler);
        		simpleType.accept(collector);
        		for (Enumeration enumeration : collector.getResult())
        			model.getEnumerations().add(enumeration);
        	}
        }
        
        // create classes
        // FIXME: can we not have top level elements as well as classes?
        if (this.support.getElementMap().size() > 0) {
        	for (Element element : this.support.getElementMap().values()) {
        		ComplexType complexType = this.support.getComplexTypeMap().get(element.getName());
        		if (complexType != null) { // element has type
            	    Class cls = classAssembler.buildClass(complexType);
            	    model.getClazzs().add(cls);
            	    this.support.getClassQualifiedNameMap().put(destNamespaceURI + "#" + cls.getName(), cls);        	
            	    this.support.getClassLocalNameMap().put(cls.getAlias().getLocalName(), cls); 
            	    if (log.isDebugEnabled())
            	    	log.debug("created class, " + cls.getName());
        		}
        		else {
            	    Class cls = classAssembler.buildClass(element);
            	    model.getClazzs().add(cls);
            	    this.support.getClassQualifiedNameMap().put(destNamespaceURI + "#" + cls.getName(), cls);        	
            	    this.support.getClassLocalNameMap().put(cls.getAlias().getLocalName(), cls);        	
            	    if (log.isDebugEnabled())
            	    	log.debug("created class, " + cls.getName());
        		}
        	}
        }
        else {
        	for (ComplexType complexType : this.support.getComplexTypeMap().values()) {
        	    Class cls = classAssembler.buildClass(complexType);
        	    model.getClazzs().add(cls);
        	    this.support.getClassQualifiedNameMap().put(destNamespaceURI + "#" + cls.getName(), cls);        	
        	    this.support.getClassLocalNameMap().put(cls.getAlias().getLocalName(), cls);        	
        	    if (log.isDebugEnabled())
        	    	log.debug("created class, " + cls.getName());
        	}        	
        }
        
        // build a map of classes to their subclasses
        // so we can process properties while doing a breadth-first
        // traversal across the class lattice
        this.support.collectSubclasses();
        
        // create properties in class lattice order
        // starting w/each root
        ClassVisitor visitor = new ClassVisitor() {
			public void visit(Class target, Class source) {
	    	    if (log.isDebugEnabled())
	    	    	log.debug("creating properties for class, " + target.getName());
	        	String localName = target.getAlias().getLocalName();
	        	if (localName == null || localName.trim().length() == 0)
	        		throw new IllegalStateException("expected local name apias for class, " 
	        				+ target.getName());
	        	ComplexType complexType = support.getComplexTypeMap().get(localName);
	        	if (complexType != null) {
	        		buildProperties(target, complexType);
	        	}
	        	else {
	        		Element element = support.getElementMap().get(localName);
	        		if (element != null) 
	            		buildProperties(target, element);
	        		else
	        			throw new IllegalStateException("expected top level conplex type or element for local name, "
	        					+ localName);
	        	}
			}        	
        };
        
        // traverse each root and any subclass hierarchy
        for (Class root : this.support.getRootClasses()) {
    	    if (log.isDebugEnabled())
    	    	log.debug("traversing 'root' class, " + root.getName());
        	this.support.accept(root, visitor);
        }

        // add derived target properties
        for (Class cls : this.support.getClassQualifiedNameMap().values())
        {
        	Property[] props = new Property[cls.getProperties().size()];
        	cls.getProperties().toArray(props); // avoid concurrent mods for recursive relationships
        	for (Property prop : props) {
        		if (prop.getType() == null)
        			throw new IllegalStateException("property "
        				+ cls.getName() + "." + prop.getName() 
        				+ " has no datatype");
        		if (prop.getType() instanceof DataTypeRef) 
        			continue;
        		ClassRef classRef = (ClassRef)prop.getType();
        		String qualifiedName = classRef.getUri() 
				    + "#" + classRef.getName();
        		Class targetClass = this.support.getClassQualifiedNameMap().get(qualifiedName);
        		if (targetClass == null)
        			throw new IllegalStateException("no class definition found for qualified name '"
        					+ qualifiedName + "'");
        		Property targetProperty = null;
        		Property[] pdefs2 = new Property[targetClass.getProperties().size()];
        		targetClass.getProperties().toArray(pdefs2);
        		for (Property pdef2 : pdefs2) {
        			if (pdef2.getName().equals(prop.getOpposite())) {
        				targetProperty = pdef2;
        				break;
        			}
        		}
        		if (targetProperty == null) {
        			if (prop.getOpposite() != null) {
        			    targetProperty = this.propertyAssembler.createDerivedPropertyOpposite(cls, prop);
        			    targetClass.getProperties().add(targetProperty);
        			}
        		}
        	}
        }

        return model;
    }  
    
    private boolean hasBase(ComplexType complexType) {
    	if (complexType.getComplexContent() != null) {
			ExtensionType extension = complexType.getComplexContent().getExtension(); 
			if (extension != null) {
				QName base = extension.getBase();
	    	    if (base != null && !base.getLocalPart().equals(SchemaUtil.getSerializationBaseTypeName()))
	    	       return true;	
			}
			ComplexRestrictionType restriction = complexType.getComplexContent().getRestriction(); 
			if (restriction != null) {
				QName base = restriction.getBase();
	    	    if (base != null && !base.getLocalPart().equals(SchemaUtil.getSerializationBaseTypeName()))
	    	    	return true;		
			}
    	}
		return false;
    }
    
    private boolean hasBase(Element element) {
		if (element.getComplexType() != null && element.getComplexType().getComplexContent() != null) { // has a base type
			ExtensionType baseType = element.getComplexType().getComplexContent().getExtension(); 
			if (baseType != null) {
			    QName base = baseType.getBase();
    	        if (!base.getLocalPart().equals(SchemaUtil.getSerializationBaseTypeName()))
    	    	    return true;
			}
		}     	
		else if (element.getSubstitutionGroup() != null) {
			QName base = element.getSubstitutionGroup();
    	    if (!base.getLocalPart().equals(SchemaUtil.getSerializationBaseTypeName()))
	    	    return true;
		}
    	return false;
    }
    
    private void buildProperties(Class cls, Element element) {
    	if (element.getComplexType() != null) {
    		buildProperties(cls, element.getComplexType());
    	}
    	else {
    	    log.warn("ignoring element w/o local complex type, "
    	    		+ element.getName());	
    	}
    }    
    
    private void buildProperties(Class cls, AbstractComplexType complexType) {
    	
    	// get attributes and build datatype properties
    	List annotatedList = null;
    	if (complexType.getComplexContent() == null) {      		
    		// must be either complex or simple content
    		if (complexType.getSimpleContent() == null) {
    		    annotatedList = complexType.getAttributesAndAttributeGroups();  
    		}
    		else {
    			if (complexType.getSimpleContent().getExtension() != null) {
    				SimpleExtensionType extension = complexType.getSimpleContent().getExtension();
    				annotatedList = extension.getAttributesAndAttributeGroups();
    				QName base = extension.getBase();
    				if (base != null)
	    				if (base.getNamespaceURI().equals(SchemaConstants.XMLSCHEMA_NAMESPACE_URI)) {
	    				    // create a synthetic datatype property to accommodate
	    					// the value of this element or type
	    					Property property = this.propertyAssembler.buildElementContentDatatypeProperty(cls,
	    				    		base);
	            		    cls.getProperties().add(property);
	            	        Map classProps = this.support.getClassPropertyMap().get(cls);
	            	        if (classProps == null) {
	            	        	classProps = new HashMap();
	            	        	this.support.getClassPropertyMap().put(cls, classProps);
	            	        }
	        	        	classProps.put(property.getName(), property);
	    				}
	    				else
	    					log.warn("expected XML Schema namespace " 
	    				        + SchemaConstants.XMLSCHEMA_NAMESPACE_URI
	    				        + " as extension base for simple type - ignoring");
    			}
    		}
        }
    	else { //complexType.getComplexContent() != null
    		if (complexType.getComplexContent().getExtension() != null)
    		    annotatedList = complexType.getComplexContent().getExtension().getAttributesAndAttributeGroups();
    		else if (complexType.getComplexContent().getRestriction() != null)
    		    annotatedList = complexType.getComplexContent().getRestriction().getAttributesAndAttributeGroups();
    	}    	
    	
    	if (annotatedList != null)
    	    buildProperties(cls, complexType, annotatedList);
    	        
        // get sequences and build properties
        // from elements
    	ExplicitGroup sequence = null;
    	if (complexType.getComplexContent() == null) { // no base type
    		sequence = complexType.getSequence();
    	}
    	else { // complexType.getComplexContent() != null
    		if (complexType.getComplexContent().getExtension() != null)
    		    sequence = complexType.getComplexContent().getExtension().getSequence();
    		else if (complexType.getComplexContent().getRestriction() != null)
    			sequence = complexType.getComplexContent().getRestriction().getSequence();
    	} 
    	if (sequence != null)
    	    buildProperties(cls, complexType, sequence); 
    	
    	

        // get choice and build properties
        // from elements
    	ExplicitGroup choice = null;
    	if (complexType.getComplexContent() == null) { // no base type
    		choice = complexType.getChoice();
    	}
    	else { // complexType.getComplexContent() != null
    		if (complexType.getComplexContent().getExtension() != null)
    		    choice = complexType.getComplexContent().getExtension().getChoice();
    		else if (complexType.getComplexContent().getRestriction() != null)
    			choice = complexType.getComplexContent().getRestriction().getChoice();
    	}   
    	if (choice != null)
    	    buildProperties(cls, complexType, choice);  
    	
    }
    
    private void buildProperties(Class cls, AbstractComplexType complexType, ExplicitGroup explicitGroup)
    {
        for (int i = 0; i < explicitGroup.getElementsAndGroupsAndAlls().size(); i++) {
        	Object obj = explicitGroup.getElementsAndGroupsAndAlls().get(i);
        	if (obj instanceof JAXBElement) {
        		JAXBElement element = (JAXBElement)obj;
        		if (element.getValue() instanceof LocalElement) {
        		    LocalElement localElement = (LocalElement)element.getValue();
        		    Property property = this.propertyAssembler.buildProperty(cls, complexType, explicitGroup, null, localElement, i);
        		    cls.getProperties().add(property);
        	        Map classProps = this.support.getClassPropertyMap().get(cls);
        	        if (classProps == null) {
        	        	classProps = new HashMap();
        	        	this.support.getClassPropertyMap().put(cls, classProps);
        	        }
    	        	classProps.put(property.getName(), property);
        		}
        		else if (element.getValue() instanceof ExplicitGroup) {
        			ExplicitGroup childGroup = (ExplicitGroup)element.getValue();
        	        for (int j = 0; j < childGroup.getElementsAndGroupsAndAlls().size(); j++) {
        	        	Object obj2 = childGroup.getElementsAndGroupsAndAlls().get(j);
        	        	if (obj2 instanceof JAXBElement) {
        	        		JAXBElement element2 = (JAXBElement)obj2;
        	        		if (element2.getValue() instanceof LocalElement) {
        	        		    LocalElement localElement = (LocalElement)element2.getValue();
        	        		    Property property = this.propertyAssembler.buildProperty(cls, complexType, 
        	        		    		explicitGroup, childGroup, localElement, j);
        	        		    cls.getProperties().add(property);
        	        	        Map classProps = this.support.getClassPropertyMap().get(cls);
        	        	        if (classProps == null) {
        	        	        	classProps = new HashMap();
        	        	        	this.support.getClassPropertyMap().put(cls, classProps);
        	        	        }
        	    	        	classProps.put(property.getName(), property);
        	        		}
        	        		else if (element2.getValue() instanceof ExplicitGroup) {
        	        			ExplicitGroup grandChildGroup = (ExplicitGroup)element2.getValue();
        	        	        for (int k = 0; k < grandChildGroup.getElementsAndGroupsAndAlls().size(); k++) {
        	        	        	Object obj3 = grandChildGroup.getElementsAndGroupsAndAlls().get(k);
        	        	        	if (obj3 instanceof JAXBElement) {
        	        	        		JAXBElement element3 = (JAXBElement)obj3;
        	        	        		if (element3.getValue() instanceof LocalElement) {
        	        	        		    LocalElement localElement = (LocalElement)element3.getValue();
        	        	        		    Property property = this.propertyAssembler.buildProperty(cls, complexType, 
        	        	        		    		childGroup, grandChildGroup, localElement, k);
        	        	        		    cls.getProperties().add(property);
        	        	        	        Map classProps = this.support.getClassPropertyMap().get(cls);
        	        	        	        if (classProps == null) {
        	        	        	        	classProps = new HashMap();
        	        	        	        	this.support.getClassPropertyMap().put(cls, classProps);
        	        	        	        }
        	        	    	        	classProps.put(property.getName(), property);
        	        	        		}
        	        	        		else
        	                         	    log.warn("unexpected sequence/choice great-grandchild JAXBElement value class, " 
        	                              			+ element3.getValue().getClass().getName());
        	        	        	} // 
        	        	        } // for
        	    		
        	        		}
            	        	else
                         	    log.warn("unexpected sequence/choice grandchild JAXBElement value class, " 
                          			+ element2.getValue().getClass().getName());
        	        	}
        	        }
        		}
            	else {
            		log.warn("unexpected choice child JAXBElement value class, " 
            			+ element.getValue().getClass().getName());
            	}
        	}
        	else if (obj instanceof Any) {
        		log.debug("ignoring sequence/choice child class, " 
            			+ obj.getClass().getName());
        	}
        	else
        		log.warn("unexpected child class, " 
        			+ obj.getClass().getName());
        }   
    }
    
    private void buildProperties(Class cls, AbstractComplexType complexType, List annotatedList) {
        
    	for (Annotated annot : annotatedList) {
        	if (annot instanceof Attribute) {
        		Attribute attribute = (Attribute)annot;
        		Property property = this.propertyAssembler.buildDatatypeProperty(cls, complexType, attribute);
        		cls.getProperties().add(property);
    	        Map classProps = this.support.getClassPropertyMap().get(cls);
    	        if (classProps == null) {
    	        	classProps = new HashMap();
    	        	this.support.getClassPropertyMap().put(cls, classProps);
    	        }
	        	classProps.put(property.getName(), property);
        	}
        	else if (annot instanceof AttributeGroupRef) {
        		AttributeGroupRef ref = (AttributeGroupRef)annot;
        		AttributeGroup attrGroup = this.support.getAttributeGroupMap().get(ref.getRef().getLocalPart());
        		if (attrGroup == null)
            		throw new IllegalStateException("no top level attribute group found for, " 
                			+ ref.getRef().getLocalPart());
        		for (Annotated annot2 : attrGroup.getAttributesAndAttributeGroups()) {
        			if (annot2 instanceof Attribute) {
                		Attribute attribute = (Attribute)annot2;
           				Property property = this.propertyAssembler.buildDatatypeProperty(cls, complexType, attribute);
                		cls.getProperties().add(property);
            	        Map classProps = this.support.getClassPropertyMap().get(cls);
            	        if (classProps == null) {
            	        	classProps = new HashMap();
            	        	this.support.getClassPropertyMap().put(cls, classProps);
            	        }
        	        	classProps.put(property.getName(), property);
        			}
        			else
            		    throw new IllegalStateException("unexpected AttributeGroup child class, " 
                			+ annot2.getClass().getName());
        		}
        	}
        	else
        		throw new IllegalStateException("unexpected ComplexType child class, " 
            			+ annot.getClass().getName());
        }
    }           
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy