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

org.plasma.xml.schema.SchemaModelAssembler 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.xml.schema;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

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.metamodel.Class;
import org.plasma.metamodel.ClassAppInfo;
import org.plasma.metamodel.DataTypeRef;
import org.plasma.metamodel.Documentation;
import org.plasma.metamodel.Model;
import org.plasma.metamodel.ModelAppInfo;
import org.plasma.metamodel.Property;
import org.plasma.metamodel.PropertyAppInfo;
import org.plasma.metamodel.VisibilityType;
import org.plasma.provisioning.ProvisioningConstants;
import org.plasma.provisioning.adapter.ModelAdapter;
import org.plasma.provisioning.adapter.ProvisioningModel;
import org.plasma.provisioning.adapter.TypeAdapter;
import org.plasma.sdo.DataFlavor;
import org.plasma.sdo.DataType;
import org.plasma.sdo.PlasmaProperty;
import org.plasma.sdo.PlasmaType;
import org.plasma.sdo.ValueConstraint;
import org.plasma.sdo.helper.PlasmaTypeHelper;
import org.plasma.sdo.helper.PlasmaXSDHelper;
import org.plasma.sdo.repository.Comment;
import org.plasma.xml.sdox.BaseDataGraphType;
import org.plasma.xml.sdox.SDOXConstants;

/**
 * Creates an XML Schema model. 
 * @see org.plasma.query.PathNode
 * @see org.plasma.query.PathNode#getSelectClause
 * @see org.plasma.query.Select
 */
//FIXME: this class needs to work with only provisioning structures
public class SchemaModelAssembler {
	
    private static Log log = LogFactory.getLog(
    		SchemaModelAssembler.class); 
	
	private String destNamespaceURI;
	private String destNamespacePrefix;
	private Model model;
	private Schema schema;
	private boolean createNonContainmentReferenceTypes = true;
	private ProvisioningModel helper;
    private Map topLevelTypes = new HashMap();
	
	@SuppressWarnings("unused")
	private SchemaModelAssembler() {}
    
    /**
     * Creates and XML Schema model based on the given PlasmaSDO#8482; Provisioning
     * Model. All class properties within the given model are expected to contain 
     * ordering or sequence information, such that XSD Element sequences can be
     * created with the expected ordering. 
     * 
     * @param model the PlasmaSDO#8482; Provisioning Model
     * @param destNamespaceURI the target namespace URI
     * @param destNamespacePrefix the target namespace prefix
     * @see org.plasma.provisioning.Sequence
     */
    public SchemaModelAssembler(Model model, 
    		String destNamespaceURI, String destNamespacePrefix) 
    {
		super();
		this.model = model;
		this.destNamespaceURI = destNamespaceURI;
		this.destNamespacePrefix = destNamespacePrefix;
	}
    
	public Schema getSchema() {
		construct(this.model,
			this.destNamespaceURI, 
			this.destNamespacePrefix);
		return this.schema;
	}
	
	public boolean isCreateNonContainmentReferenceTypes() {
		return createNonContainmentReferenceTypes;
	}

	public void setCreateNonContainmentReferenceTypes(
			boolean createNonContainmentReferenceTypes) {
		this.createNonContainmentReferenceTypes = createNonContainmentReferenceTypes;
	}

	private void construct(Model model, 
    		String destNamespaceURI, String destNamespacePrefix) 
    {
		if (destNamespaceURI == null || destNamespaceURI.trim().length() == 0)
			throw new IllegalArgumentException("expected 'destNamespaceURI' argument");
		if (destNamespacePrefix == null || destNamespacePrefix.trim().length() == 0)
			throw new IllegalArgumentException("expected 'destNamespacePrefix' argument");
		
		if (log.isDebugEnabled())
		    log.debug("constructing schema for model: " + model.getName());
		this.helper = 
			new ModelAdapter(model);
		
		this.schema = buildSchema(model); 
		
		//buildDatagraphEnvelopeType(model);
		
		ComplexType serializationBaseType = buildSerializationBaseType();
		
		TypeAdapter[] types = helper.getTypesArray();
		if (log.isDebugEnabled())
		    log.debug("processing " + types.length + " types");

		for (TypeAdapter adapter : types)
		{	
			if (!(adapter.getType() instanceof Class)) {
	    		if (log.isDebugEnabled())
	    		    log.debug("ignoring type: " + adapter.getType().getName());
				continue;
			}
			Class clss = (Class)adapter.getType();
            PlasmaType sdoType = (PlasmaType)PlasmaTypeHelper.INSTANCE.getType(
            		adapter.getUri(), adapter.getName());
    		if (log.isDebugEnabled())
    		    log.debug("processing class: " + clss.getName());
                        
            ComplexType complexType = null;
            if (clss.getSuperClasses().size() == 0) {            	
            	ComplexType baseType = serializationBaseType;
        		complexType = buildComplexType(adapter, baseType);
        		if (log.isDebugEnabled())
        		    log.debug("created complex type: " + complexType.getName());
                addDatatypeAttributesAndElements(complexType, baseType, adapter, sdoType);
            }
            else {
            	if (clss.getSuperClasses().size() > 1)
            		throw new IllegalStateException("cannot process multiple base classes for type, " 
            				+ adapter.getKey());
            	complexType = buildComplexType(adapter, clss.getSuperClasses().get(0).getName());
        		if (log.isDebugEnabled())
        		    log.debug("created complex type: " + complexType.getName());
                addDatatypeAttributesAndElements(complexType, null, adapter, sdoType);
            }            
            
            addReferenceElements(complexType, adapter, sdoType);
		}
    }	
	
	private void addDatatypeAttributesAndElements(ComplexType complexType, 
			ComplexType baseType,
			TypeAdapter adapter, PlasmaType sdoType) {
        
		
		// add datatype attributes and elements
        for (Property prop : adapter.getDeclaredPropertiesArray()) {
        	PlasmaProperty property = (PlasmaProperty)sdoType.getProperty(prop.getName());
        	if (!(prop.getType() instanceof DataTypeRef))
        		continue; // datatype prop
        	
        	// ignore properties provisioned as private 
        	//if (prop.getVisibility() != null && 
        	//	prop.getVisibility().ordinal() == VisibilityType.PRIVATE.ordinal()) {
        	//	continue;
        	//}
        	
        	//currentType = complexType;
        	//if (this.createNonContainmentReferenceTypes) {
	        //	if (property.isKey(KeyType.external) && nonContainmentReferenceType != null) {
	        //		currentType = nonContainmentReferenceType;
	        //	}
        	//}
        	// FIXME: this should be provisioned as 
        	if (property.isXMLAttribute()) { 
            	Attribute attr = buildDataAttributeModel(adapter, sdoType, prop, property, schema);
            	if (complexType.getComplexContent() == null) { // no base type
            		complexType.getAttributesAndAttributeGroups().add(attr);  
            	}
            	else {
            		complexType.getComplexContent().getExtension().getAttributesAndAttributeGroups().add(attr);
            	}
            }
        	else {
                // link the element
        		ExplicitGroup group = null;
            	if (complexType.getComplexContent() == null) { // no base type
            		group = complexType.getSequence();
                    if (group == null) {
                    	group = new ExplicitGroup();
                    	complexType.setSequence(group);
                    }
            	}
            	else {
            		group = complexType.getComplexContent().getExtension().getSequence();
                    if (group == null) {
                    	group = new ExplicitGroup();
                    	complexType.getComplexContent().getExtension().setSequence(group);
                    }
            	}                   
                
                Element element = buildDataElementModel(adapter, sdoType, prop, property, schema);
                group.getElementsAndGroupsAndAlls().add(element);
        	}
        }		
	}
	
	private void addReferenceElements(ComplexType complexType, TypeAdapter adapter, PlasmaType sdoType) {
        // add reference elements
        for (Property prop : adapter.getDeclaredPropertiesArray()) {
        	PlasmaProperty property = (PlasmaProperty)sdoType.getProperty(prop.getName());
        	if (prop.getType() instanceof DataTypeRef)
        		continue; // datatype prop
        	
        	// ignore properties provisioned as private 
        	if (prop.getVisibility() != null && 
        		prop.getVisibility().ordinal() == VisibilityType.PRIVATE.ordinal()) {
        		continue;
        	}
        	
    		ExplicitGroup group = null;
        	if (complexType.getComplexContent() == null) { // no base type
        		group = complexType.getSequence();
                if (group == null) {
                	group = new ExplicitGroup();
                    complexType.setSequence(group);
                }
        	}
        	else {
        		group = complexType.getComplexContent().getExtension().getSequence();
                if (group == null) {
                	group = new ExplicitGroup();
                	complexType.getComplexContent().getExtension().setSequence(group);
                }
        	}                   
            
            Element element = buildReferenceElementModel(adapter,
            		sdoType, prop, property, schema);
            
            // link the element
            group.getElementsAndGroupsAndAlls().add(element);                    
        }
	}

	private Schema buildSchema(Model model) {
		Schema schema = new Schema();
        schema.setId(model.getName());
        schema.setTargetNamespace(this.destNamespaceURI);
        
        Annotation annotation = new Annotation();
    	schema.getIncludesAndImportsAndRedefines().add(annotation);
        if (model.getDocumentations() != null && model.getDocumentations().size() > 0) {
            org.plasma.xml.schema.Documentation docum = new org.plasma.xml.schema.Documentation();
            docum.getContent().add(model.getDocumentations().get(0).getBody().getValue());
            annotation.getAppinfosAndDocumentations().add(docum);
        }
        
        ModelAppInfo modelAppInfo = new ModelAppInfo();
        modelAppInfo.setId(model.getId());
        modelAppInfo.setName(model.getName());
        modelAppInfo.setUri(model.getUri());
        modelAppInfo.setDerivation(model.getDerivation());
        		
        Appinfo appinfo = new Appinfo();
        appinfo.getContent().add(modelAppInfo);
        annotation.getAppinfosAndDocumentations().add(appinfo);
        
        QName plasmaNamespace = new QName(ProvisioningConstants.PROVISIONING_NAMESPACE_URI, 
        		"plasma");
        schema.getOtherAttributes().put(plasmaNamespace, 
        		ProvisioningConstants.PROVISIONING_NAMESPACE_URI);
        
        QName appNamespace = new QName(schema.getTargetNamespace(), this.destNamespacePrefix, 
        		this.destNamespacePrefix); // use query name as namespace-prefix
        schema.getOtherAttributes().put(appNamespace, schema.getTargetNamespace());

        QName sdoxNamespace = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
        		SDOXConstants.SDOX_NAMESPACE_PREFIX, SDOXConstants.SDOX_NAMESPACE_PREFIX);
        schema.getOtherAttributes().put(sdoxNamespace, 
        		SDOXConstants.SDOX_NAMESPACE_URI);
        
        // for xs:documentation xml:lang attrib, etc 
        QName xmlNamespace = new QName(SchemaConstants.XML_NAMESPACE_URI, 
        		"xml", "xml");
        schema.getOtherAttributes().put(xmlNamespace, 
        		SchemaConstants.XML_NAMESPACE_URI);
		return schema;
	}
	
	private ComplexType buildDatagraphEnvelopeType(Model model)
	{
		String name = model.getRootClass().getName() + "Datagraph";
		
        Element topLevelElement = new Element();
        topLevelElement.setName(name);
        QName topLevelType = new QName(schema.getTargetNamespace(), 
        		name, destNamespacePrefix); 
        topLevelElement.setType(topLevelType);
        schema.getSimpleTypesAndComplexTypesAndGroups().add(topLevelElement);
        
        // add a complex type
        ComplexType complexType = new ComplexType();
        complexType.setName(name);
        addAnnotation("SDO Data Graph root type",
        	complexType);
        schema.getSimpleTypesAndComplexTypesAndGroups().add(complexType);

        ComplexContent complexContent = new ComplexContent();
        complexType.setComplexContent(complexContent);	        
        ExtensionType extension = new ExtensionType(); 
        complexContent.setExtension(extension);
        QName base = new QName("commonj.sdo", BaseDataGraphType.class.getSimpleName(), 
        		"sdo");
        extension.setBase(base);

        Element element = new Element();
        element.setName(model.getRootClass().getName());        
        
        QName elementType = new QName(schema.getTargetNamespace(),
        		model.getRootClass().getName());       
        
        element.setType(elementType);
        element.setMinOccurs(new BigInteger("1"));
        element.setMaxOccurs("1");
 
		ExplicitGroup group = new ExplicitGroup();
    	complexType.getComplexContent().getExtension().setSequence(group);
        group.getElementsAndGroupsAndAlls().add(element);        
        
        return complexType;
	}
	
	private ComplexType buildSerializationBaseType()
	{
        
		// add a top level element referencing the below
        // complex type to keep JAXB happy
        Element topLevelElement = new Element();
        topLevelElement.setName(SchemaUtil.getSerializationBaseTypeName());
        QName topLevelType = new QName(schema.getTargetNamespace(), 
        		SchemaUtil.getSerializationBaseTypeName(), destNamespacePrefix); 
        topLevelElement.setType(topLevelType);
        schema.getSimpleTypesAndComplexTypesAndGroups().add(topLevelElement);
        
        // add a complex type
        ComplexType complexType = new ComplexType();
        complexType.setName(SchemaUtil.getSerializationBaseTypeName());
        addAnnotation("default XML serialization common base type used to "
        	+ "generalize any type within a Data Graph for use in an XML "
        	+ "document as either a containment or non-containment reference",
        	complexType);
        schema.getSimpleTypesAndComplexTypesAndGroups().add(complexType);

    	Attribute attr = new Attribute();
    	complexType.getAttributesAndAttributeGroups().add(attr);  
        attr.setName(SchemaUtil.getSerializationAttributeName());
        attr.setUse("required");
        QName attrType = new QName(SchemaConstants.XMLSCHEMA_NAMESPACE_URI,
                getSchemaDatatype(DataType.String));                    
        attr.setType(attrType);
       
        return complexType;
	}

	private ComplexType buildComplexType(TypeAdapter type)
	{
		return buildComplexType(type, (String)null);
	}
	
	private ComplexType buildComplexType(TypeAdapter type, ComplexType baseType)
	{
		return buildComplexType(type, baseType != null ? baseType.getName() : null);
	}
	
	private ComplexType buildComplexType(TypeAdapter type, String baseType)
	{
        // add a top level element referencing the below
        // complex type to keep JAXB happy
        Element topLevelElement = new Element();
        topLevelElement.setName(type.getLocalName());
        QName topLevelType = new QName(schema.getTargetNamespace(), 
        		type.getName(), destNamespacePrefix); // use query name as namespace-prefix
        topLevelElement.setType(topLevelType);
        schema.getSimpleTypesAndComplexTypesAndGroups().add(topLevelElement);
        
        // add a complex type
        ComplexType complexType = new ComplexType();
        complexType.setName(type.getLocalName());
        List docs = type.getDocumentation();
        for (Documentation doc : docs) {
            addAnnotation(doc, complexType);
        }
        schema.getSimpleTypesAndComplexTypesAndGroups().add(complexType);
        
        // add sdox open attributes
        addSDOXTypeAttributes(type, complexType); 
        
        if (baseType != null) {
	        ComplexContent complexContent = new ComplexContent();
	        complexType.setComplexContent(complexContent);	        
	        ExtensionType extension = new ExtensionType(); 
	        complexContent.setExtension(extension);
	        QName base = new QName(this.destNamespaceURI, baseType, 
	        		this.destNamespacePrefix);
	        extension.setBase(base);
        }

        Class clss = (Class)type.getType();
        ClassAppInfo classAppInfo = new ClassAppInfo();
        classAppInfo.setId(clss.getId());
        classAppInfo.setName(clss.getName());
        classAppInfo.setUri(clss.getUri());
        classAppInfo.setAlias(clss.getAlias());
        classAppInfo.setDerivation(clss.getDerivation());
        		
        Appinfo appinfo = new Appinfo();
        appinfo.getContent().add(classAppInfo);
        Annotation annotation = complexType.getAnnotation();
        if (annotation == null) {
            annotation = new Annotation();
            complexType.setAnnotation(annotation);
        }
        annotation.getAppinfosAndDocumentations().add(appinfo);
        
        return complexType;
	}

	private ComplexType buildNonContainmentReferenceComplexType(TypeAdapter type)
	{	
		String name = getNonContainmentReferenceComplexTypeName(type);
        // add a top level element referencing the below
        // complex type to keep JAXB happy
        Element topLevelElement = new Element();
        topLevelElement.setName(name);
        QName topLevelType = new QName(schema.getTargetNamespace(), 
        		name, destNamespacePrefix); // use query name as namespace-prefix
        topLevelElement.setType(topLevelType);
        schema.getSimpleTypesAndComplexTypesAndGroups().add(topLevelElement);
        
        // add a complex type
        ComplexType complexType = new ComplexType();
        complexType.setName(name);
        addAnnotation("non-containment reference type for,  "
        		+ type.getLocalName(),
        		complexType);
        schema.getSimpleTypesAndComplexTypesAndGroups().add(complexType);
        
        // add sdox open attributes
        addSDOXTypeAttributes(type, complexType); 
		
        return complexType;
	}
	
	private String getNonContainmentReferenceComplexTypeName(TypeAdapter type) {
		
	    return SchemaUtil.getNonContainmentReferenceName(type);	
	}
	
    private Element buildReferenceElementModel(TypeAdapter adapter, PlasmaType type, 
    		Property prop, PlasmaProperty property, Schema schema) {
        Element element = new Element();
        element.setName(PlasmaXSDHelper.INSTANCE.getLocalName(property));        
        
        // build the element type based on opposite type
        PlasmaType oppositeType = (PlasmaType)property.getType();
        QName elementType = new QName(schema.getTargetNamespace(),
        		PlasmaXSDHelper.INSTANCE.getLocalName(oppositeType));
        // set every reference to the serial base type
        // use XSI type in the XML to specific subtypes
        elementType = new QName(schema.getTargetNamespace(),
        		SchemaUtil.getSerializationBaseTypeName());       
        
        element.setType(elementType);
        
        if (property.isNullable())
            element.setMinOccurs(new BigInteger("0"));
        else
            element.setMinOccurs(new BigInteger("1"));
        
        if (!property.isMany())
            element.setMaxOccurs("1");
        else
            element.setMaxOccurs("unbounded");

        if (property.getDescription() != null && property.getDescription().size() > 0) {
            addAnnotation(property.getDescription(),
            		element);
        }
        
        // add sdox open attributes
        addSDOXPropertyAttributes(property, element);

        commonj.sdo.Property oppositeProp = property.getOpposite();
        if (oppositeProp != null) {
	        QName qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
	        		SDOXConstants.LOCAL_NAME_OPPOSITE_PROPERTY, 
	        		SDOXConstants.SDOX_NAMESPACE_PREFIX);
	        element.getOtherAttributes().put(qname, 
	        		PlasmaXSDHelper.INSTANCE.getLocalName(oppositeProp));
	        qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
	        		SDOXConstants.LOCAL_NAME_PROPERTY_TYPE, 
	        		SDOXConstants.SDOX_NAMESPACE_PREFIX);
        }
        
    	return element;
    }
 
    private Element buildDataElementModel(TypeAdapter adapter, PlasmaType type, 
    		Property prop, PlasmaProperty property, Schema schema) {
        Element element = new Element();
        element.setName(PlasmaXSDHelper.INSTANCE.getLocalName(property));
        if (property.getRestriction() == null) {
            QName elementType = new QName(SchemaConstants.XMLSCHEMA_NAMESPACE_URI,
                    getSchemaDatatype(DataType.valueOf(
                    		PlasmaXSDHelper.INSTANCE.getLocalName(property.getType()))));                    
            element.setType(elementType);
        }
        else {
            //LocalSimpleType simpleType = buildLocalSimpleTypeRestriction(property);
            //element.setSimpleType(simpleType);
            SimpleType simpleType = buildTopLevelSimpleTypeEnumerationRestriction(property);
            QName topLevelType = new QName(schema.getTargetNamespace(), 
            		simpleType.getName(), destNamespacePrefix); 
            element.setType(topLevelType);
        }    
        
        if (property.isNullable())
            element.setMinOccurs(new BigInteger("0"));
        else
            element.setMinOccurs(new BigInteger("1"));        
        
        if (!property.isMany())
            element.setMaxOccurs("1");
        else
            element.setMaxOccurs("unbounded");

        if (property.getDescription() != null && property.getDescription().size() > 0) {
            addAnnotation(property.getDescription(),
            		element);
        }
        
        // add sdox open attributes
        addSDOXPropertyAttributes(property, element);

    	return element;
    }
    
    private Attribute buildDataAttributeModel(TypeAdapter adapter, PlasmaType type, 
    		Property prop, PlasmaProperty property, Schema schema) 
    {
    	Attribute attr = new Attribute();
        attr.setName(PlasmaXSDHelper.INSTANCE.getLocalName(property));
        
        if (property.getRestriction() == null) {
        	// value constraint below will specify XSD data type
        	if (property.getValueConstraint() == null) {
                QName attrType = new QName(SchemaConstants.XMLSCHEMA_NAMESPACE_URI,
                    getSchemaDatatype(DataType.valueOf(
                    		PlasmaXSDHelper.INSTANCE.getLocalName(
                    				property.getType()))));                    
                attr.setType(attrType);
        	}
        }
        else { // has an enum restriction
            SimpleType simpleType = buildTopLevelSimpleTypeEnumerationRestriction(property);
            QName topLevelType = new QName(schema.getTargetNamespace(), 
            		simpleType.getName(), destNamespacePrefix); 
            attr.setType(topLevelType);
        } 
        
        if (property.getValueConstraint() != null) {
        	if (property.getRestriction() == null) {
        	    ValueConstraint vc = property.getValueConstraint();
        	    LocalSimpleType simpleType = buildLocalSimpleTypeValueRestriction(property, vc);
        	    attr.setSimpleType(simpleType);
        	}
        	else
        		log.warn("both value constraint and enumeration constraint found for property, "
        			+ type.getURI() + "#" + type.getName() + "." + property.getName() 
        			+ " - ignoring value constraint");
        }
        
        if (!prop.isNullable())
            attr.setUse("required");
        else
            attr.setUse("optional");
        
        if (property.getDescription() != null)
            addAnnotation(property.getDescription(),
            		attr);
         
        // add sdox open attributes
        addSDOXPropertyAttributes(property, attr);
        
        PropertyAppInfo attribAppInfo = new PropertyAppInfo();
        attribAppInfo.setId(prop.getId());
        attribAppInfo.setName(prop.getName());
        attribAppInfo.setAlias(prop.getAlias());
        attribAppInfo.setDerivation(prop.getDerivation());
        attribAppInfo.setKey(prop.getKey());
        attribAppInfo.setConcurrent(prop.getConcurrent());
        attribAppInfo.setUniqueConstraint(prop.getUniqueConstraint());
        attribAppInfo.setValueConstraint(prop.getValueConstraint());
        attribAppInfo.setEnumerationConstraint(prop.getEnumerationConstraint());
        attribAppInfo.setValueSetConstraint(prop.getValueSetConstraint());
        attribAppInfo.setSort(prop.getSort());
        attribAppInfo.setXmlProperty(prop.getXmlProperty());
        		
        Appinfo appinfo = new Appinfo();
        appinfo.getContent().add(attribAppInfo);
        Annotation annotation = attr.getAnnotation();
        if (annotation == null) {
            annotation = new Annotation();
            attr.setAnnotation(annotation);
        }
        annotation.getAppinfosAndDocumentations().add(appinfo);
    	
        return attr;
    }

    /**
     * Adds SDO XML (sdox) attributes for SDO Type to the given superclass 
     * properties to the given OpenAttrs superclass. 
     * @param type the SDO Type
     * @param annotated
     */
    private void addSDOXTypeAttributes(TypeAdapter type, 
    		OpenAttrs openAttributes) 
    {
    	QName qname = null;
    	if (type.getPhysicalName() != null) {
	    	qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
	            SDOXConstants.LOCAL_NAME_ALIAS_NAME, 
	        	SDOXConstants.SDOX_NAMESPACE_PREFIX);
	        openAttributes.getOtherAttributes().put(qname, 
	        		type.getPhysicalName()); 
    	}
        
    	qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
                SDOXConstants.LOCAL_NAME_NAME, 
            	SDOXConstants.SDOX_NAMESPACE_PREFIX);
            openAttributes.getOtherAttributes().put(qname, 
            		type.getName());    	
    }
    
    /**
     * Adds SDO XML (sdox) attributes common to both reference and data
     * properties to the given OpenAttrs superclass. 
     * @param property the SDO property
     * @param openAttributes
     */
    private void addSDOXPropertyAttributes(PlasmaProperty property, 
    		OpenAttrs openAttributes) {
    	QName qname = null;
        // name
        qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
        		SDOXConstants.LOCAL_NAME_NAME, 
        		SDOXConstants.SDOX_NAMESPACE_PREFIX);
        openAttributes.getOtherAttributes().put(qname, 
        		property.getName());
    	
    	if (!property.getType().isDataType()) {
            qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
        		SDOXConstants.LOCAL_NAME_PROPERTY_TYPE, 
        		SDOXConstants.SDOX_NAMESPACE_PREFIX);
            openAttributes.getOtherAttributes().put(qname, 
            		destNamespacePrefix + ":" 
            		+ PlasmaXSDHelper.INSTANCE.getLocalName(property.getType()));
    	}
    	
    	// alias
    	if (property.getAliasNames() != null && property.getAliasNames().size() > 0) {
            qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
        		SDOXConstants.LOCAL_NAME_ALIAS_NAME, 
        		SDOXConstants.SDOX_NAMESPACE_PREFIX);
            openAttributes.getOtherAttributes().put(qname, property.getAliasNames().get(0));
    	}
    	else {
    		if (!property.isMany()) {
    			log.warn("no aliases found for singular property "
    					+ property.getContainingType().getURI() + "#"
    					+ property.getContainingType().getName() + "."
    					+ property.getName());
    		}
    		
    	}
    	
        qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
        		SDOXConstants.LOCAL_NAME_DATATYPE, 
        		SDOXConstants.SDOX_NAMESPACE_PREFIX);
        if (property.getType().isDataType())
        	openAttributes.getOtherAttributes().put(qname, 
        			PlasmaXSDHelper.INSTANCE.getLocalName(property.getType()));
        else
        	openAttributes.getOtherAttributes().put(qname, 
            	this.destNamespaceURI 
            	+ "#" + PlasmaXSDHelper.INSTANCE.getLocalName(property.getType()));

    	if (property.isKey()) {
    		
            qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
            		SDOXConstants.LOCAL_NAME_KEY, 
            		SDOXConstants.SDOX_NAMESPACE_PREFIX);
            openAttributes.getOtherAttributes().put(qname, 
            		"true");
            qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
            		SDOXConstants.LOCAL_NAME_KEY_TYPE, 
            		SDOXConstants.SDOX_NAMESPACE_PREFIX);
            openAttributes.getOtherAttributes().put(qname, 
            		property.getKey().getType().name().toLowerCase());
    	}
        
        // many
        qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
        		SDOXConstants.LOCAL_NAME_MANY, 
        		SDOXConstants.SDOX_NAMESPACE_PREFIX);
        openAttributes.getOtherAttributes().put(qname, 
        		String.valueOf(property.isMany()));
        // readonly
        qname = new QName(SDOXConstants.SDOX_NAMESPACE_URI, 
        		SDOXConstants.LOCAL_NAME_READ_ONLY, 
        		SDOXConstants.SDOX_NAMESPACE_PREFIX);
        openAttributes.getOtherAttributes().put(qname, 
        		String.valueOf(property.isReadOnly()));
    }
    
    private SimpleType buildTopLevelSimpleTypeEnumerationRestriction(PlasmaProperty property) {
    	SimpleType simpleType = topLevelTypes.get(property.getRestriction().getName());
    	if (simpleType == null) {
    		simpleType = new SimpleType();
    		org.plasma.sdo.repository.Enumeration enumeration = property.getRestriction();
            simpleType.setName(enumeration.getName());
            Restriction restriction = buildStringEnumerationRestriction(property);        
            simpleType.setRestriction(restriction);
            
            Annotation annotation = addAnnotation(property.getRestriction().getComments(),
            		simpleType);
            
        	// add the logical enum value as an XSD appinfo
            Appinfo appinfo = new Appinfo();
            appinfo.getContent().add(enumeration.getName());
            annotation.getAppinfosAndDocumentations().add(appinfo);
            
            
            
            topLevelTypes.put(property.getRestriction().getName(), simpleType);
            this.schema.getSimpleTypesAndComplexTypesAndGroups().add(simpleType);
    	}
        return simpleType;
    }

    private LocalSimpleType buildLocalSimpleTypeEnumerationRestriction(PlasmaProperty property) {
        LocalSimpleType simpleType = new LocalSimpleType();
        Restriction restriction = buildStringEnumerationRestriction(property);        
        simpleType.setRestriction(restriction);
        return simpleType;
    }

    private LocalSimpleType buildLocalSimpleTypeValueRestriction(PlasmaProperty property,
    		ValueConstraint valueConstrint) {
        LocalSimpleType simpleType = new LocalSimpleType();
        
        Restriction restriction = null;
        DataFlavor flavor = property.getDataFlavor();
        if (flavor.ordinal() == DataFlavor.string.ordinal()) {
            restriction = buildStringValueRestriction(property, valueConstrint);        
        }
        else if (flavor.ordinal() == DataFlavor.integral.ordinal()) {
            restriction = buildNumericValueRestriction(property, valueConstrint);        
        }
        else
        	throw new IllegalStateException("value constraint found for " 
        		+ "unsupported data flavor '" 
        		+ flavor.name() + "' on property "
        		+ property.getContainingType().getURI() + "#" 
				+ property.getContainingType().getName() + "." + property.getName());
    
        simpleType.setRestriction(restriction);
        return simpleType;
    }

    private Restriction buildNumericValueRestriction(PlasmaProperty property,
    		ValueConstraint valueConstrint)
    {
        Restriction restriction = new Restriction();
        QName stringType = new QName(SchemaConstants.XMLSCHEMA_NAMESPACE_URI,
                "string");                    
        restriction.setBase(stringType); 
        
        // NOTE: having primitive types here introduces ambiguity, i.e. is null intended??
        if (valueConstrint.getMaxInclusive() != null) {
        	JAXBElement maxIncl = createNumberFacet("maxInclusive", 
        			valueConstrint.getMaxInclusive());
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(maxIncl);
        }
        else if (valueConstrint.getMinInclusive() != null) {
        	JAXBElement minIncl = createNumberFacet("minInclusive", 
        			valueConstrint.getMinInclusive());
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(minIncl);
        }
        else if (valueConstrint.getMinExclusive() != null) {
        	JAXBElement minExcl = createNumberFacet("minExclusive", 
        			valueConstrint.getMinExclusive());
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(minExcl);
        }
        else if (valueConstrint.getMaxExclusive() != null) {
        	JAXBElement maxExcl = createNumberFacet("maxExclusive", 
        			valueConstrint.getMaxExclusive());
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(maxExcl);
        }
        
        if (valueConstrint.getTotalDigits() != null) {
        	JAXBElement totDig = createNumberFacet("totalDigits", 
        			valueConstrint.getTotalDigits());
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(totDig);
        }
        if (valueConstrint.getFractionDigits() != null) {
        	JAXBElement fracDig = createNumberFacet("fractionDigits", 
        			valueConstrint.getFractionDigits());
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(fracDig);
        }
        
        return restriction;
    }
    
    private Restriction buildStringValueRestriction(PlasmaProperty property,
    		ValueConstraint valueConstrint)
    {
        Restriction restriction = new Restriction();
        QName stringType = new QName(SchemaConstants.XMLSCHEMA_NAMESPACE_URI,
                "string");                    
        restriction.setBase(stringType); 
        if (valueConstrint.getMaxLength() != null) {
        	JAXBElement maxLen = createNumberFacet("maxLength", 
        			valueConstrint.getMaxLength());
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(maxLen);
        }
        else if (valueConstrint.getMinLength() != null) {
        	JAXBElement minLen = createNumberFacet("minLength", 
        			valueConstrint.getMinLength());
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(minLen);
        }
        else if (valueConstrint.getPattern() != null) {
        	Pattern pattern = new Pattern();
        	pattern.setValue(valueConstrint.getPattern());
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(pattern);
        }
        
        return restriction;
    }
    
    private JAXBElement createNumberFacet(String name, int value)
    {
    	NumFacet facet = new NumFacet();
    	facet.setValue(String.valueOf(value));
        QName qname = new QName(SchemaConstants.XMLSCHEMA_NAMESPACE_URI, name);
        return new JAXBElement(qname, Facet.class, null, facet);       	        	
    }
    
    private JAXBElement createNumberFacet(String name, String value)
    {
    	NumFacet facet = new NumFacet();
    	facet.setValue(String.valueOf(value));
        QName qname = new QName(SchemaConstants.XMLSCHEMA_NAMESPACE_URI, name);
        return new JAXBElement(qname, Facet.class, null, facet);       	        	
    }
    
    private Restriction buildStringEnumerationRestriction(PlasmaProperty property)
    {
        Restriction restriction = new Restriction();
        QName stringType = new QName(SchemaConstants.XMLSCHEMA_NAMESPACE_URI,
                "string");                    
        restriction.setBase(stringType);        

        org.plasma.sdo.repository.Enumeration propertyRestriction = property.getRestriction();
        
        for (org.plasma.sdo.repository.EnumerationLiteral literal : propertyRestriction.getOwnedLiteral()) {
            Enumeration enumeration = new Enumeration();
            enumeration.setValue(literal.getPhysicalName());
            
            Annotation annotation = addAnnotation(literal.getComments(), enumeration);
            
        	// add the logical enum value as an XSD appinfo
            Appinfo appinfo = new Appinfo();
            appinfo.getContent().add(literal.getName());
            annotation.getAppinfosAndDocumentations().add(appinfo);
            
            restriction.getMinExclusivesAndMinInclusivesAndMaxExclusives().add(enumeration);
        }
        
        return restriction;
    }
    
    private Annotation addAnnotation(Documentation doc, Annotated annotated)
    {
        Annotation annotation = new Annotation();
        annotated.setAnnotation(annotation);
        org.plasma.xml.schema.Documentation docum = new org.plasma.xml.schema.Documentation();
        // fails with below even though XML namespace declared
        // "org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'xml:lang' to a(n) 'attribute declaration component'"
        //docum.setLang("en");
        docum.getContent().add(""+doc.getBody().getValue());
        annotation.getAppinfosAndDocumentations().add(docum);
        
     	// add appinfo
        //Appinfo appinfo = new Appinfo();
        //appinfo.getContent().add("");
        //annotation.getAppinfosAndDocumentations().add(appinfo);
        
    	return annotation;
    }
    
    private Annotation addAnnotation(List description, Annotated annotated)
    {
        Annotation annotation = new Annotation();
        annotated.setAnnotation(annotation);
        org.plasma.xml.schema.Documentation docum = new org.plasma.xml.schema.Documentation();
        // fails with below even though XML namespace declared
        // "org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'xml:lang' to a(n) 'attribute declaration component'"
        //docum.setLang("en");
        for (Comment comment : description)
            docum.getContent().add(""+comment.getBody());
        annotation.getAppinfosAndDocumentations().add(docum);
        
     	// add appinfo
        //Appinfo appinfo = new Appinfo();
        //appinfo.getContent().add("");
        //annotation.getAppinfosAndDocumentations().add(appinfo);
        
    	return annotation;
    }
    
    private Annotation addAnnotation(String content, Annotated annotated)
    {
        Annotation annotation = new Annotation();
        annotated.setAnnotation(annotation);
        org.plasma.xml.schema.Documentation docum = new org.plasma.xml.schema.Documentation();
        // fails with below even though XML namespace declared
        // "org.xml.sax.SAXParseException: src-resolve: Cannot resolve the name 'xml:lang' to a(n) 'attribute declaration component'"
        //docum.setLang("en");
        docum.getContent().add(content);
        annotation.getAppinfosAndDocumentations().add(docum);
    	return annotation;
    }
    
    private String getSchemaDatatype(DataType datatype) {
        switch (datatype) {
        case Boolean:   return "boolean";
        case Byte:      return "byte";
        case Bytes:     return "hexBinary";
        case Character: return "string";
        case DateTime:  return "dateTime";
        case Date:      return "date";
        case Day:       return "gDay";
        case Decimal:   return "decimal";
        case Duration:  return "duration";
        case Float:     return "float";
        case Double:    return "double";
        case Int:       return "int";
        case Integer:   return "integer";
        case Long:      return "long";
        case Month:     return "gMonth";
        case MonthDay:  return "gMonthDay";
        case Short:     return "short";
        case String:    return "string";
        case Time:      return "dateTime";
        case URI:       return "anyURI";
        case Year:      return "gYear";
        case YearMonth: return "gYearMonth";
        case YearMonthDay: return "date";
        case Object:	return "anySimpleType";
        default:
            throw new IllegalArgumentException("unknown datatype, "
                    + datatype.toString());
        }
    }
 
    private List sort(List list) {
    	String[] values = new String[list.size()];
    	list.toArray(values);
    	Arrays.sort(values);
    	List result = new ArrayList(list.size());
    	for (String s : values)
    		result.add(s);
    	return result;
    }
    
/*
SDO Type		XSD Type
Boolean			boolean
Byte			byte
Bytes			hexBinary
Character		string
DataObject		anyType
Date 			dateTime 
DateTime		dateTime
Day				gDay
Decimal			decimal
Double			double
Duration		duration
Float			float
Int				int
Integer			integer
Long			long
Month			gMonth
MonthDay		gMonthDay
Object			anySimpleType
Short			short
String			string
Strings			string
Time			time
Year			gYear
YearMonth		gYearMonth
YearMonthDay	date
URI				anyURI
    
 */
    
    
/*
XSD Simple Type	 	/ SDO Type
anySimpleType			Object
anyType					DataObject
anyURI					URI   (override with sdox:propertyType)
base64Binary			Bytes
boolean					Boolean
byte					Byte
date					YearMonthDay
dateTime				DateTime
decimal					Decimal
double					Double
duration				Duration
ENTITIES				Strings
ENTITY					String
float					Float
gDay					Day
gMonth					Month
gMonthDay				MonthDay
gYear					Year
gYearMonth				YearMonth
hexBinary				Bytes
ID						String (signifies the field is a sdo:key field)
IDREF					String   (override with sdox: propertyType)
IDREFS					Strings  (override with sdox: propertyType) 
int						Int
integer					Integer
language				String
long					Long
Name					String
NCName					String
negativeInteger			Integer
NMTOKEN					String
NMTOKENS				Strings
nonNegativeInteger		Integer
nonPositiveInteger		Integer
normalizedString		String
NOTATION				String
positiveInteger			Integer
QName					URI 
short					Short
string					String
time					Time
token					String
unsignedByte			UnsignedByte
unsignedInt				UnsignedInt
unsignedLong			UnsignedLong
unsignedShort			UnsignedShort
 
 */
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy