it.unibas.spicy.persistence.xml.operators.GenerateXSDNodeTree.java Source code

Java tutorial

Introduction

Here is the source code for it.unibas.spicy.persistence.xml.operators.GenerateXSDNodeTree.java

Source

/*
Copyright (C) 2007-2011  Database Group - Universita' della Basilicata
Giansalvatore Mecca - giansalvatore.mecca@unibas.it
Salvatore Raunich - salrau@gmail.com
Alessandro Pappalardo - pappalardo.alessandro@gmail.com
Gianvito Summa - gianvito.summa@gmail.com
    
This file is part of ++Spicy - a Schema Mapping and Data Exchange Tool
    
++Spicy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
any later version.
    
++Spicy is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with ++Spicy.  If not, see <http://www.gnu.org/licenses/>.
 */

package it.unibas.spicy.persistence.xml.operators;

import it.unibas.spicy.persistence.Types;
import it.unibas.spicy.persistence.xml.IllegalSchemaException;
import it.unibas.spicy.persistence.xml.model.AttributeDeclaration;
import it.unibas.spicy.persistence.xml.model.ElementDeclaration;
import it.unibas.spicy.persistence.xml.model.IXSDNode;
import it.unibas.spicy.persistence.xml.model.PCDATA;
import it.unibas.spicy.persistence.xml.model.Particle;
import it.unibas.spicy.persistence.xml.model.SimpleType;
import it.unibas.spicy.persistence.xml.model.TypeCompositor;
import it.unibas.spicy.persistence.xml.model.XSDSchema;
import java.util.HashMap;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.xerces.impl.xs.XSAttributeUseImpl;
import org.apache.xerces.impl.xs.XSComplexTypeDecl;
import org.apache.xerces.impl.xs.XSElementDecl;
import org.apache.xerces.impl.xs.XSModelGroupImpl;
import org.apache.xerces.impl.xs.XSParticleDecl;
import org.apache.xerces.xs.XSComplexTypeDefinition;
import org.apache.xerces.xs.XSConstants;
import org.apache.xerces.xs.XSImplementation;
import org.apache.xerces.xs.XSLoader;
import org.apache.xerces.xs.XSModel;
import org.apache.xerces.xs.XSNamedMap;
import org.apache.xerces.xs.XSObject;
import org.apache.xerces.xs.XSObjectList;
import org.apache.xerces.xs.XSSimpleTypeDefinition;
import org.apache.xerces.xs.XSTerm;
import org.apache.xerces.xs.XSTypeDefinition;
import org.apache.xerces.xs.XSWildcard;
import org.w3c.dom.DOMConfiguration;
import org.w3c.dom.bootstrap.DOMImplementationRegistry;

public class GenerateXSDNodeTree {

    private static Log logger = LogFactory.getLog(GenerateXSDNodeTree.class);

    private Map<String, IXSDNode> globalElements = new HashMap<String, IXSDNode>();
    private XSDSchema xsdSchema;

    private LoadXsdConstraints constraintLoader = new LoadXsdConstraints();

    public XSDSchema generateXSDNodeTree(String fileName) throws Exception {
        this.xsdSchema = new XSDSchema();
        XSModel model = initModel(fileName);
        XSNamedMap elements = model.getComponents(XSConstants.ELEMENT_DECLARATION);
        for (int i = 0; i < elements.getLength(); i++) {
            XSElementDecl element = (XSElementDecl) elements.item(i);
            analyzeElement(null, null, element);
        }
        IXSDNode rootNode = findRoot();
        xsdSchema.setRoot(rootNode);
        return xsdSchema;
    }

    private XSModel initModel(String fileName) throws Exception {
        System.setProperty(DOMImplementationRegistry.PROPERTY,
                "org.apache.xerces.dom.DOMXSImplementationSourceImpl");
        DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
        XSImplementation impl = (XSImplementation) registry.getDOMImplementation("XS-Loader");
        XSLoader schemaLoader = impl.createXSLoader(null);
        DOMConfiguration config = schemaLoader.getConfig();
        config.setParameter("validate", Boolean.TRUE);
        return schemaLoader.loadURI(fileName);
    }

    private void analyzeElement(IXSDNode currentNode, XSParticleDecl fatherParticle,
            XSElementDecl elementDeclaration) {
        if (logger.isDebugEnabled())
            logger.debug("analyzeElement: " + elementDeclaration.getName());
        String elementName = elementDeclaration.getName();
        IXSDNode element = null;
        if (elementDeclaration.getScope() == XSConstants.SCOPE_GLOBAL) {
            if (logger.isDebugEnabled())
                logger.debug(elementName + " has GLOBAL SCOPE");
            element = globalElements.get(elementName);
            if (element == null) {
                element = createNewElement(elementDeclaration);
                globalElements.put(elementName, element);
                analyzeType(element, fatherParticle, elementDeclaration);
            } else {
                element.setNested(true);
                element = element.clone();
                setCardinality(element, fatherParticle);
            }
        } else {
            element = createNewElement(elementDeclaration);
            analyzeType(element, fatherParticle, elementDeclaration);
        }
        if (currentNode != null) {
            currentNode.addChild(element);
        }
    }

    private IXSDNode createNewElement(XSElementDecl elementDeclaration) {
        String elementName = elementDeclaration.getName();
        IXSDNode element = new ElementDeclaration(elementName);
        constraintLoader.checkElementConstraints(xsdSchema, elementDeclaration);
        element.setNullable(elementDeclaration.getNillable());
        return element;
    }

    private void analyzeType(IXSDNode currentNode, XSParticleDecl fatherParticle,
            XSElementDecl currentElementDeclaration) {
        if (currentElementDeclaration.getTypeDefinition().getTypeCategory() == XSTypeDefinition.SIMPLE_TYPE) {
            manageSimpleTypeElement(currentNode, fatherParticle, currentElementDeclaration);
        } else {
            manageComplexTypeElement(currentNode, fatherParticle, currentElementDeclaration);
        }
    }

    //// SIMPLE TYPE
    private void manageSimpleTypeElement(IXSDNode currentNode, XSParticleDecl fatherParticle,
            XSElementDecl currentElementDeclaration) {
        XSSimpleTypeDefinition simpleTypeDefinition = (XSSimpleTypeDefinition) currentElementDeclaration
                .getTypeDefinition();
        if (logger.isDebugEnabled())
            logger.debug("Found a simple type: " + currentElementDeclaration.getName() + " with type: "
                    + simpleTypeDefinition.getBuiltInKind());
        SimpleType simpleType = new SimpleType(getLeafType(simpleTypeDefinition.getBuiltInKind()));
        currentNode.addChild(simpleType);
        setCardinality(currentNode, fatherParticle);
    }

    private String getLeafType(int value) {
        switch (value) {
        case XSConstants.BOOLEAN_DT:
            return Types.BOOLEAN;
        case XSConstants.STRING_DT:
            return Types.STRING;
        case XSConstants.BYTE_DT:
        case XSConstants.SHORT_DT:
        case XSConstants.INTEGER_DT:
        case XSConstants.INT_DT:
        case XSConstants.POSITIVEINTEGER_DT:
        case XSConstants.NEGATIVEINTEGER_DT:
        case XSConstants.NONPOSITIVEINTEGER_DT:
        case XSConstants.NONNEGATIVEINTEGER_DT:
            return Types.INTEGER;
        case XSConstants.LONG_DT:
            return Types.LONG;
        case XSConstants.DECIMAL_DT:
        case XSConstants.FLOAT_DT:
        case XSConstants.DOUBLE_DT:
            //return Types.DOUBLE;
            return Types.FLOAT;
        case XSConstants.DATE_DT:
            return Types.DATE;
        case XSConstants.TIME_DT:
        case XSConstants.DATETIME_DT:
            return Types.DATETIME;
        default:
            return Types.STRING;
        }
    }

    //// COMPLEX TYPE
    private void manageComplexTypeElement(IXSDNode currentNode, XSParticleDecl fatherParticle,
            XSElementDecl currentElementDeclaration) {
        if (logger.isDebugEnabled())
            logger.debug("Found a complex type: " + currentElementDeclaration.getName());
        setCardinality(currentNode, fatherParticle);
        XSComplexTypeDecl complexTypeDefinition = (XSComplexTypeDecl) currentElementDeclaration.getTypeDefinition();
        if (checkContentTypeMixed(complexTypeDefinition)) {
            currentNode.setMixedContent(true);
            if (logger.isDebugEnabled())
                logger.debug("Current node: " + currentNode + " with father particle: " + fatherParticle
                        + " and current element declaration: " + currentElementDeclaration);
        }
        XSParticleDecl currentParticle = (XSParticleDecl) complexTypeDefinition.getParticle();
        analyzeAttributes(currentNode, currentElementDeclaration);
        if (currentParticle == null) {
            return;
        }
        analyzeParticle(currentNode, fatherParticle, currentParticle);
    }

    private boolean checkContentTypeMixed(XSComplexTypeDecl complexTypeDefinition) {
        if (logger.isDebugEnabled())
            logger.debug("ContentType = " + complexTypeDefinition.getContentType());
        if (complexTypeDefinition.getContentType() == XSComplexTypeDecl.CONTENTTYPE_MIXED) {
            return true;
        } else {
            return false;
        }
    }

    private void analyzeParticle(IXSDNode currentNode, XSParticleDecl fatherParticle,
            XSParticleDecl currentParticle) {
        if (logger.isDebugEnabled())
            logger.debug("analyzing particle: " + currentParticle);
        XSTerm currentTerm = currentParticle.getTerm();
        if (currentTerm instanceof XSWildcard) {
            throw new IllegalSchemaException("Term is a wildcard: " + currentParticle + " - Current node: "
                    + currentNode + " - Father particle: " + fatherParticle);
        }
        if (currentTerm instanceof XSElementDecl) {
            if (logger.isDebugEnabled())
                logger.debug("Found an element: " + currentTerm.toString() + " with scope "
                        + ((XSElementDecl) currentTerm).getScope());
            analyzeElement(currentNode, currentParticle, (XSElementDecl) currentTerm);
        }
        if (currentTerm instanceof XSModelGroupImpl) {
            if (logger.isDebugEnabled())
                logger.debug("Found a nested group in: " + currentTerm);
            analyzeModelGroup(currentNode, currentParticle, (XSModelGroupImpl) currentTerm);
        }
    }

    private void analyzeAttributes(IXSDNode currentNode, XSElementDecl currentElementDeclaration) {
        XSComplexTypeDefinition complexTypeDefinition = (XSComplexTypeDefinition) currentElementDeclaration
                .getTypeDefinition();
        XSObjectList listOfAttributes = complexTypeDefinition.getAttributeUses();
        if (listOfAttributes.getLength() != 0) {
            TypeCompositor attList = new TypeCompositor(TypeCompositor.ATTLIST);
            for (int i = 0; i < listOfAttributes.getLength(); i++) {
                XSAttributeUseImpl xsdAttribute = (XSAttributeUseImpl) listOfAttributes.item(i);
                AttributeDeclaration attribute = new AttributeDeclaration(
                        xsdAttribute.getAttrDeclaration().getName());
                if (logger.isDebugEnabled())
                    logger.debug(" --- AttributeName: " + xsdAttribute.getAttrDeclaration().getName() + " type: "
                            + xsdAttribute.getType());
                if (xsdAttribute.getRequired()) {
                    attribute.setMinCardinality(1);
                }
                int leafType = xsdAttribute.getAttrDeclaration().getTypeDefinition().getBuiltInKind();
                attribute.addChild(new SimpleType(getLeafType(leafType)));
                attList.addChild(attribute);
            }
            currentNode.addChild(attList);
        }
    }

    private void analyzeModelGroup(IXSDNode currentNode, XSParticleDecl fatherParticle,
            XSModelGroupImpl currentTerm) {
        IXSDNode typeCompositor = createTypeCompositor(currentTerm);
        setCardinality(typeCompositor, fatherParticle);
        currentNode.addChild(typeCompositor);
        XSObjectList childrenParticles = currentTerm.getParticles();
        if (logger.isDebugEnabled())
            logger.debug("Particles size = " + childrenParticles.getLength());
        for (int i = 0; i < childrenParticles.getLength(); i++) {
            XSObject xsObject = childrenParticles.item(i);
            if (logger.isDebugEnabled())
                logger.debug("Particle object: " + xsObject);
            XSParticleDecl particle = (XSParticleDecl) xsObject;
            analyzeParticle(typeCompositor, fatherParticle, particle);
        }
        checkMixedContent(typeCompositor);
    }

    private IXSDNode createTypeCompositor(XSModelGroupImpl currentTerm) {
        IXSDNode typeCompositor = null;
        switch (currentTerm.getCompositor()) {
        case XSModelGroupImpl.COMPOSITOR_ALL:
            typeCompositor = new TypeCompositor(TypeCompositor.ALL);
            break;
        case XSModelGroupImpl.COMPOSITOR_CHOICE:
            typeCompositor = new TypeCompositor(TypeCompositor.CHOICE);
            break;
        case XSModelGroupImpl.COMPOSITOR_SEQUENCE:
            typeCompositor = new TypeCompositor(TypeCompositor.SEQUENCE);
            break;
        }
        if (logger.isDebugEnabled())
            logger.debug(currentTerm.getCompositor());
        return typeCompositor;
    }

    private void checkMixedContent(IXSDNode currentNode) {
        if (currentNode.getFather().isMixedContent()) {
            PCDATA pcdata = new PCDATA();
            currentNode.addChild(pcdata);
        }
    }

    private void setCardinality(IXSDNode currentNode, XSParticleDecl fatherParticle) {
        if (fatherParticle == null) {
            currentNode.setMinCardinality(1);
            currentNode.setMaxCardinality(1);
        } else {
            currentNode.setMinCardinality(fatherParticle.getMinOccurs());
            if (fatherParticle.getMaxOccursUnbounded()) {
                currentNode.setMaxCardinality(Particle.UNBOUNDED);
            } else {
                assert (fatherParticle.getMaxOccurs() > 0) : "Negative cardinalities are not allowed";
                currentNode.setMaxCardinality(fatherParticle.getMaxOccurs());
            }
            if (logger.isDebugEnabled())
                logger.debug("Analyzing cardinality of: " + currentNode.getDescription() + " with particle "
                        + fatherParticle);
        }
    }

    private IXSDNode findRoot() {
        int counter = 0;
        IXSDNode rootNode = null;
        for (IXSDNode node : globalElements.values()) {
            if (!node.isNested()) {
                counter++;
                rootNode = node;
            }
        }
        if (counter != 1) {
            logger.error("Schema is not a tree:");
            for (IXSDNode node : globalElements.values()) {
                if (!node.isNested())
                    logger.error(node.getLabel());
            }
            throw new IllegalSchemaException("Schema is not a tree... counter of NOT nested = " + counter);
        }
        return rootNode;
    }

}