Package org.eclipse.persistence.jaxb.compiler

Source Code of org.eclipse.persistence.jaxb.compiler.SchemaGenerator

/*******************************************************************************
* Copyright (c) 1998, 2009 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0
* which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html
* and the Eclipse Distribution License is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* Contributors:
*     Oracle - initial API and implementation from Oracle TopLink
******************************************************************************/
package org.eclipse.persistence.jaxb.compiler;

import java.beans.Introspector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;

import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlElementDecl.GLOBAL;
import javax.xml.namespace.QName;

import org.eclipse.persistence.jaxb.javamodel.Helper;
import org.eclipse.persistence.jaxb.javamodel.JavaClass;
import org.eclipse.persistence.jaxb.xmlmodel.XmlElementWrapper;

import org.eclipse.persistence.internal.descriptors.Namespace;
import org.eclipse.persistence.internal.jaxb.many.MapValue;
import org.eclipse.persistence.internal.oxm.schema.model.*;
import org.eclipse.persistence.oxm.XMLConstants;

/**
* INTERNAL:
* <p><b>Purpose:</b>To generate Schema objects based on a map of TypeInfo objects, and some
* additional information gathered by the AnnotationsProcessing phase.
* <p><b>Responsibilities:</b><ul>
* <li>Create and maintain a collection of Schema objects based on the provided TypeInfo objects</li>
* <li>Add additional global elements to the schema based on an optional map (for WS integration)</li>
* <li>Should create a schema for each namespace encountered during generation.</li>
* </ul>
* <p>This class is used by the Generator to handle the generation of Schemas. The
* Generator passes in a map of TypeInfo objects, generated by the Annotations processor.
* The generated Schemas are stored in a map of keyed on Target Namespace.
* @see org.eclipse.persistence.jaxb.compiler.TypeInfo
* @see org.eclipse.persistence.jaxb.compiler.AnnotationsProcessor
* @see org.eclipse.persistence.jaxb.compiler.Generator
* @since Oracle TopLink 11.1.1.0.0
* @author mmacivor
*/
public class SchemaGenerator {
    private HashMap<String, Schema> schemaForNamespace;
    private java.util.List<Schema> allSchemas;
    private Schema schema;
    private int schemaCount;
    private Helper helper;
    private HashMap<String, TypeInfo> typeInfo;
    private HashMap<String, NamespaceInfo> packageToNamespaceMappings;
    private HashMap<String, SchemaTypeInfo> schemaTypeInfo;
    private HashMap<String, QName> userDefinedSchemaTypes;

    public SchemaGenerator(Helper helper) {
        this.helper = helper;
    }

    public Schema generateSchema(ArrayList<JavaClass> typeInfoClasses, HashMap<String, TypeInfo> typeInfo, HashMap<String, QName> userDefinedSchemaTypes, HashMap<String, NamespaceInfo> packageToNamespaceMappings, HashMap<QName, ElementDeclaration> additionalGlobalElements) {
        this.typeInfo = typeInfo;
        this.userDefinedSchemaTypes = userDefinedSchemaTypes;
        this.packageToNamespaceMappings = packageToNamespaceMappings;
        this.schemaCount = 0;
        this.schemaTypeInfo = new HashMap<String, SchemaTypeInfo>(typeInfo.size());

        for (JavaClass javaClass : typeInfoClasses) {
            addSchemaComponents(javaClass);
        }
        populateSchemaTypes();
        if (additionalGlobalElements != null) {
            addGlobalElements(additionalGlobalElements);
        }
        return schema;
    }

    public void addSchemaComponents(JavaClass myClass) {
        // first check for type
        String myClassName = myClass.getQualifiedName();
        Element rootElement = null;
        TypeInfo info = (TypeInfo) typeInfo.get(myClassName);
        if (info.isTransient()) {
            return;
        }
        SchemaTypeInfo schemaTypeInfo = new SchemaTypeInfo();
        schemaTypeInfo.setSchemaTypeName(new QName(info.getClassNamespace(), info.getSchemaTypeName()));
        this.schemaTypeInfo.put(myClass.getQualifiedName(), schemaTypeInfo);
        NamespaceInfo namespaceInfo = this.packageToNamespaceMappings.get(myClass.getPackageName());
        if (namespaceInfo.getLocation() != null && !namespaceInfo.getLocation().equals("##generate")) {
            return;
        }
        Schema schema = getSchemaForNamespace(info.getClassNamespace());
        info.setSchema(schema);

        String typeName = info.getSchemaTypeName();
        String pfx = "";

        Property valueField = null;
        if (info.isSetXmlRootElement()) {
            //Create the root element and add it to the schema
            org.eclipse.persistence.jaxb.xmlmodel.XmlRootElement xmlRE = info.getXmlRootElement();
            rootElement = new Element();
            String elementName = xmlRE.getName();
            if (elementName.equals("##default") || elementName.equals("")) {
                if (myClassName.indexOf("$") != -1) {
                    elementName = Introspector.decapitalize(myClassName.substring(myClassName.lastIndexOf('$') + 1));
                } else {
                    elementName = Introspector.decapitalize(myClassName.substring(myClassName.lastIndexOf('.') + 1));
                }

                // the following satisfies a TCK requirement
                if (elementName.length() >= 3) {
                    int idx = elementName.length() - 1;
                    char ch = elementName.charAt(idx - 1);
                    if (Character.isDigit(ch)) {
                        char lastCh = Character.toUpperCase(elementName.charAt(idx));
                        elementName = elementName.substring(0, idx) + lastCh;
                    }
                }
            }
            rootElement.setName(elementName);
            String rootNamespace = xmlRE.getNamespace();
            if (rootNamespace.equals("##default")) {
                Schema rootElementSchema = getSchemaForNamespace(namespaceInfo.getNamespace());
                if (rootElementSchema != null) {
                    rootElementSchema.addTopLevelElement(rootElement);
                }
                schemaTypeInfo.getGlobalElementDeclarations().add(new QName(namespaceInfo.getNamespace(), rootNamespace));
                rootNamespace = namespaceInfo.getNamespace();
            } else {
                Schema rootElementSchema = getSchemaForNamespace(rootNamespace);
                if (rootElementSchema != null) {
                    rootElementSchema.addTopLevelElement(rootElement);
                }
                schemaTypeInfo.getGlobalElementDeclarations().add(new QName(rootNamespace, elementName));
            }

            // handle root-level imports/includes [schema = the type's schema]           
            Schema rootSchema = getSchemaForNamespace(rootNamespace);
            addImportIfRequired(rootSchema, schema, schema.getTargetNamespace());

            // setup a prefix, if necessary
            if (rootSchema != null && !info.getClassNamespace().equals("")) {
                pfx = getOrGeneratePrefixForNamespace(info.getClassNamespace(), rootSchema);
                pfx += ":";
            }
        }

        ArrayList<String> propertyNames = info.getPropertyNames();
        Property xmlValueProperty = info.getXmlValueProperty();
        if (info.isEnumerationType() || (propertyNames.size() == 1 && xmlValueProperty != null)) {
            SimpleType type = new SimpleType();
            //simple type case, we just need the name and namespace info
            if (typeName.equals("")) {
                //In this case, it should be a type under
                //A root elem or locally defined whenever used
                if (rootElement != null) {
                    rootElement.setSimpleType(type);
                }
            } else {
                type.setName(typeName);
                schema.addTopLevelSimpleTypes(type);
                if (rootElement != null) {
                    rootElement.setType(pfx + type.getName());
                }
            }
            //Figure out schema type and set it as Restriction
            QName restrictionType = null;
            Restriction restriction = new Restriction();
            if (info.isEnumerationType()) {
                restrictionType = ((EnumTypeInfo) info).getRestrictionBase();
                restriction.setEnumerationFacets(this.getEnumerationFacetsFor((EnumTypeInfo) info));
                restriction.setBaseType(XMLConstants.SCHEMA_PREFIX + ":" + restrictionType.getLocalPart());
                type.setRestriction(restriction);
            } else {
                valueField = info.getProperties().get(propertyNames.get(0));
                JavaClass javaType = valueField.getActualType();
                QName baseType = getSchemaTypeFor(javaType);
                String prefix = null;
                if (baseType.getNamespaceURI() != null && !baseType.getNamespaceURI().equals("")) {
                    if (baseType.getNamespaceURI().equals(XMLConstants.SCHEMA_URL)) {
                        prefix = XMLConstants.SCHEMA_PREFIX;
                    } else {
                        prefix = getPrefixForNamespace(baseType.getNamespaceURI(), schema.getNamespaceResolver());
                    }
                }
                String baseTypeName = baseType.getLocalPart();
                if (prefix != null) {
                    baseTypeName = prefix + ":" + baseTypeName;
                }
                if (valueField.isXmlList() || (valueField.getGenericType() != null)) {
                    //generate a list instead of a restriction
                    List list = new List();
                    list.setItemType(baseTypeName);
                    type.setList(list);
                } else {
                    if (helper.isAnnotationPresent(valueField.getElement(), XmlSchemaType.class)) {
                        XmlSchemaType schemaType = (XmlSchemaType) helper.getAnnotation(valueField.getElement(), XmlSchemaType.class);
                        baseType = new QName(schemaType.namespace(), schemaType.name());
                    }
                    restriction.setBaseType(baseTypeName);
                    type.setRestriction(restriction);
                }
            }
            info.setSimpleType(type);
        } else if ((valueField = this.getXmlValueFieldForSimpleContent(info)) != null) {
            ComplexType type = new ComplexType();
            SimpleContent content = new SimpleContent();
            if (typeName.equals("")) {
                if (rootElement != null) {
                    rootElement.setComplexType(type);
                }
                info.setComplexType(type);
            } else {
                type.setName(typeName);
                schema.addTopLevelComplexTypes(type);
                if (rootElement != null) {
                    rootElement.setType(pfx + type.getName());
                }
            }
            QName extensionType = getSchemaTypeFor(valueField.getType());
            if (helper.isAnnotationPresent(valueField.getElement(), XmlSchemaType.class)) {
                XmlSchemaType schemaType = (XmlSchemaType) helper.getAnnotation(valueField.getElement(), XmlSchemaType.class);
                extensionType = new QName(schemaType.namespace(), schemaType.name());
            }
            String prefix = null;
            if (extensionType.getNamespaceURI() != null && !extensionType.getNamespaceURI().equals("")) {
                if (extensionType.getNamespaceURI().equals(XMLConstants.SCHEMA_URL)) {
                    prefix = XMLConstants.SCHEMA_PREFIX;
                } else {
                    prefix = getPrefixForNamespace(extensionType.getNamespaceURI(), schema.getNamespaceResolver());
                }
            }
            String extensionTypeName = extensionType.getLocalPart();
            if (prefix != null) {
                extensionTypeName = prefix + ":" + extensionTypeName;
            }
            Extension extension = new Extension();
            extension.setBaseType(extensionTypeName);
            content.setExtension(extension);
            type.setSimpleContent(content);
            info.setComplexType(type);
        } else {
            ComplexType type = new ComplexType();
            JavaClass superClass = helper.getNextMappedSuperClass(myClass);

            // Handle mixed content
            if (info.isMixed()) {
                type.setMixed(true);
            }

            // Handle abstract class
            if (myClass.isAbstract()) {
                type.setAbstractValue(true);
            }

            Extension extension = null;
            if (superClass != null) {
                TypeInfo parentTypeInfo = this.typeInfo.get(superClass.getQualifiedName());
                if (parentTypeInfo != null) {
                    extension = new Extension();
                    // may need to qualify the type
                    String parentPrefix = getPrefixForNamespace(parentTypeInfo.getClassNamespace(), schema.getNamespaceResolver());
                    if (parentPrefix != null) {
                        extension.setBaseType(parentPrefix + ":" + parentTypeInfo.getSchemaTypeName());
                    } else {
                        extension.setBaseType(parentTypeInfo.getSchemaTypeName());
                    }
                    ComplexContent content = new ComplexContent();
                    content.setExtension(extension);
                    type.setComplexContent(content);
                }
            }
            TypeDefParticle compositor = null;
            String[] propOrder = null;
            if (info.isSetPropOrder()) {
                propOrder = info.getPropOrder();
            }
           
            if (propOrder != null && propOrder.length == 0) {
                // Note that the spec requires an 'all' to be generated
                // in cases where propOrder == 0, however, the TCK
                // requires the extension case to use sequences
                if (info.hasElementRefs()) {
                    // generate a sequence to satisfy TCK
                    compositor = new Sequence();
                    if (extension != null) {
                        extension.setSequence((Sequence) compositor);
                    } else {
                        type.setSequence((Sequence) compositor);
                    }
                } else if (extension != null) {
                    compositor = new All();
                    extension.setAll((All) compositor);
                } else {
                    compositor = new All();
                    type.setAll((All) compositor);
                }
            } else {
                // generate a sequence to satisfy TCK
                compositor = new Sequence();
                if (extension != null) {
                    extension.setSequence((Sequence) compositor);
                } else {
                    type.setSequence((Sequence) compositor);
                }
            }
            if (typeName.equals("")) {
                if (rootElement != null) {
                    rootElement.setComplexType(type);
                }
                info.setComplexType(type);
                info.setCompositor(compositor);
            } else {
                type.setName(typeName);
                if (rootElement != null) {
                    rootElement.setType(pfx + type.getName());
                }
                schema.addTopLevelComplexTypes(type);
                info.setComplexType(type);
                info.setCompositor(compositor);
            }
        }
    }

    public void addToSchemaType(TypeInfo ownerTypeInfo, java.util.List<Property> properties, TypeDefParticle compositor, ComplexType type, Schema schema) {
        Property xmlValueProperty = ownerTypeInfo.getXmlValueProperty();

        for (Property next : properties) {
            if (next == null) { continue; }

            TypeDefParticle parentCompositor = compositor;
            boolean isChoice = (parentCompositor instanceof Choice);
            ComplexType parentType = type;
            if (!helper.isAnnotationPresent(next.getElement(), XmlTransient.class)) {
                // deal with the XmlElementWrapper case
                if (!isChoice && next.isSetXmlElementWrapper()) {
                    XmlElementWrapper wrapper = next.getXmlElementWrapper();
                    Element wrapperElement = new Element();
                    String name = wrapper.getName();
                    if (name.equals("##default")) {
                        name = next.getPropertyName();
                    }
                    // handle nillable
                    wrapperElement.setNillable(wrapper.isNillable());

                    // namespace in not the target or ##default, create a ref with min/max = 1
                    String wrapperNS = wrapper.getNamespace();
                    if (!wrapperNS.equals("##default") && !wrapperNS.equals(schema.getTargetNamespace())) {
                        wrapperElement.setMinOccurs(Occurs.ONE);
                        wrapperElement.setMaxOccurs(Occurs.ONE);

                        String prefix = getOrGeneratePrefixForNamespace(wrapperNS, schema);
                        wrapperElement.setRef(prefix + ":" + name);
                        compositor.addElement(wrapperElement);
                        // assume that the element exists and does not need to be created
                        continue;
                    } else {
                        wrapperElement.setName(name);
                        if (wrapper.isRequired()) {
                            wrapperElement.setMinOccurs(Occurs.ONE);
                        } else {
                            wrapperElement.setMinOccurs(Occurs.ZERO);
                        }
                        compositor.addElement(wrapperElement);
                        ComplexType wrapperType = new ComplexType();
                        Sequence wrapperSequence = new Sequence();
                        wrapperType.setSequence(wrapperSequence);
                        wrapperElement.setComplexType(wrapperType);
                        parentType = wrapperType;
                        parentCompositor = wrapperSequence;
                    }
                }
                if (next.isAttribute() && !next.isAnyAttribute()) {
                    Attribute attribute = new Attribute();
                    QName attributeName = next.getSchemaName();
                    attribute.setName(attributeName.getLocalPart());
                    if (next.isRequired()) {
                        attribute.setUse(Attribute.REQUIRED);
                    }
                    //Check to see if it's a collection.
                    //Should assume XmlList on any collection?
                    JavaClass javaType = next.getType();
                    if (next.getGenericType() != null) {
                        javaType = (JavaClass) next.getGenericType();
                    }
                    TypeInfo info = (TypeInfo) typeInfo.get(next.getType().getQualifiedName());
                    String typeName = null;
                    if (next.isXmlId()) {
                        typeName = XMLConstants.SCHEMA_PREFIX + ":ID";
                    } else if (next.isXmlIdRef()) {
                        typeName = XMLConstants.SCHEMA_PREFIX + ":IDREF";
                    } else if (info != null && !info.isComplexType()) {
                        typeName = info.getSimpleType().getName();
                    } else {
                        QName schemaType = next.getSchemaType();
                        if (schemaType == null) {
                            schemaType = getSchemaTypeFor(javaType);
                        }
                        if (schemaType != null) {
                            if (schemaType.getNamespaceURI() == null) {
                                typeName = schemaType.getLocalPart();
                            } else {
                                String prefix = getOrGeneratePrefixForNamespace(schemaType.getNamespaceURI(), schema);
                                typeName = prefix + ":" + schemaType.getLocalPart();
                            }
                        } else {
                            typeName = XMLConstants.SCHEMA_PREFIX + ":anySimpleType";
                        }
                    }

                    if (isCollectionType(next)) {
                        // assume XmlList for an attribute collection
                        SimpleType localType = new SimpleType();
                        org.eclipse.persistence.internal.oxm.schema.model.List list = new org.eclipse.persistence.internal.oxm.schema.model.List();
                        list.setItemType(typeName);
                        localType.setList(list);
                        attribute.setSimpleType(localType);
                    } else {
                        // may need to qualify the type
                        if (typeName != null && !typeName.contains(":")) {
                            if (info.getSchema() == schema) {
                                String prefix = getPrefixForNamespace(schema.getTargetNamespace(), schema.getNamespaceResolver());
                                if (prefix != null) {
                                    typeName = prefix + ":" + typeName;
                                }
                            }
                        }
                        attribute.setType(typeName);
                    }
                    String lookupNamespace = schema.getTargetNamespace();
                    if (lookupNamespace == null) {
                        lookupNamespace = "";
                    }
                    NamespaceInfo namespaceInfo = getNamespaceInfoForNamespace(lookupNamespace);

                    boolean isAttributeFormQualified = true;

                    if (namespaceInfo != null) {
                        isAttributeFormQualified = namespaceInfo.isAttributeFormQualified();
                    }

                    if ((isAttributeFormQualified && !attributeName.getNamespaceURI().equals(lookupNamespace))
                            || (!namespaceInfo.isAttributeFormQualified() && !attributeName.getNamespaceURI().equals(""))) {

                        Schema attributeSchema = this.getSchemaForNamespace(attributeName.getNamespaceURI());
                        if (attributeSchema != null && attributeSchema.getTopLevelAttributes().get(attribute.getName()) == null) {
                            //don't overwrite existing global elements and attributes.
                            attributeSchema.getTopLevelAttributes().put(attribute.getName(), attribute);
                        }

                        addImportIfRequired(schema, attributeSchema, attributeName.getNamespaceURI());

                        Attribute reference = new Attribute();
                        //add an import here
                        String prefix = getPrefixForNamespace(attributeName.getNamespaceURI(), schema.getNamespaceResolver());
                        if (prefix == null) {
                            reference.setRef(attribute.getName());
                        } else {
                            reference.setRef(prefix + ":" + attribute.getName());
                        }
                        if (parentType.getSimpleContent() != null) {
                            parentType.getSimpleContent().getExtension().getOrderedAttributes().add(reference);
                        } else {
                            parentType.getOrderedAttributes().add(reference);
                        }
                    } else {
                        if (parentType.getSimpleContent() != null) {
                            parentType.getSimpleContent().getExtension().getOrderedAttributes().add(attribute);
                        } else if (parentType.getComplexContent() != null) {
                            parentType.getComplexContent().getExtension().getOrderedAttributes().add(attribute);
                        } else {
                            parentType.getOrderedAttributes().add(attribute);
                        }
                    }
                } else if (next.isAnyAttribute()) {
                    AnyAttribute anyAttribute = new AnyAttribute();
                    anyAttribute.setProcessContents("skip");
                    anyAttribute.setNamespace("##other");
                    if (type.getSimpleContent() != null) {
                        SimpleContent content = type.getSimpleContent();
                        content.getRestriction().setAnyAttribute(anyAttribute);
                    } else {
                        type.setAnyAttribute(anyAttribute);
                    }
                } else if (next.isChoice()) {
                    Choice choice = new Choice();
                    ArrayList<Property> choiceProperties = (ArrayList<Property>) ((ChoiceProperty) next).getChoiceProperties();
                    addToSchemaType(ownerTypeInfo, choiceProperties, choice, parentType, schema);
                    if (next.getGenericType() != null) {
                        choice.setMaxOccurs(Occurs.UNBOUNDED);
                    }
                    if (parentCompositor instanceof Sequence) {
                        ((Sequence) parentCompositor).addChoice(choice);
                    } else if (parentCompositor instanceof Choice) {
                        ((Choice) parentCompositor).addChoice(choice);
                    }
                } else if (next.isAny()) {
                    Any any = new Any();
                    any.setNamespace("##other");
                    if (next.isLax()) {
                        any.setProcessContents(Any.LAX);
                    } else {
                        any.setProcessContents("skip");
                    }

                    if (isCollectionType(next)) {
                        any.setMinOccurs(Occurs.ZERO);
                        any.setMaxOccurs(Occurs.UNBOUNDED);
                    }

                    if (parentCompositor instanceof Sequence) {
                        ((Sequence) parentCompositor).addAny(any);
                    } else if (parentCompositor instanceof Choice) {
                        ((Choice) parentCompositor).addAny(any);
                    }

                } else if (next.isReference()) {
                    ReferenceProperty refProp = (ReferenceProperty) next;
                    java.util.List<ElementDeclaration> referencedElements = refProp.getReferencedElements();
                    if (referencedElements.size() == 1) {
                        //if only a single reference, just add the element.
                        Element element = new Element();
                        ElementDeclaration decl = referencedElements.get(0);
                        String localName = decl.getElementName().getLocalPart();
                        Schema referencedSchema = this.getSchemaForNamespace(decl.getElementName().getNamespaceURI());

                        addImportIfRequired(schema, referencedSchema, decl.getElementName().getNamespaceURI());

                        String prefix = this.getPrefixForNamespace(decl.getElementName().getNamespaceURI(), schema.getNamespaceResolver());
                        if (prefix == null || prefix.equals("")) {
                            element.setRef(localName);
                        } else {
                            element.setRef(prefix + ":" + localName);
                        }

                        if (next.getGenericType() != null) {
                            element.setMinOccurs(Occurs.ZERO);
                            element.setMaxOccurs(Occurs.UNBOUNDED);
                        }
                        parentCompositor.addElement(element);
                    } else {
                        // otherwise, add a choice of referenced elements.
                        Choice choice = new Choice();
                        if (next.getGenericType() != null) {
                            choice.setMaxOccurs(Occurs.UNBOUNDED);
                        }
                        for (ElementDeclaration elementDecl : referencedElements) {
                            Element element = new Element();
                            String localName = elementDecl.getElementName().getLocalPart();
                            Schema referencedSchema = this.getSchemaForNamespace(elementDecl.getElementName().getNamespaceURI());

                            addImportIfRequired(schema, referencedSchema, elementDecl.getElementName().getNamespaceURI());

                            String prefix = this.getPrefixForNamespace(elementDecl.getElementName().getNamespaceURI(), schema.getNamespaceResolver());
                            if (prefix == null || prefix.equals("")) {
                                element.setRef(localName);
                            } else {
                                element.setRef(prefix + ":" + localName);
                            }
                            choice.addElement(element);
                        }
                        if (parentCompositor instanceof Sequence) {
                            ((Sequence) parentCompositor).addChoice(choice);
                        } else if (parentCompositor instanceof Choice) {
                            ((Choice) parentCompositor).addChoice(choice);
                        }
                    }
                } else if (!(xmlValueProperty != null && xmlValueProperty == next)) {
                    Element element = new Element();
                    // Set minOccurs based on the 'required' flag
                    if (!(parentCompositor instanceof All)) {
                        element.setMinOccurs(next.isRequired() ? Occurs.ONE : Occurs.ZERO);
                    }
                    // handle nillable
                    element.setNillable(next.isNillable());
                    // handle defaultValue
                    if (next.isSetDefaultValue()) {
                        element.setDefaultValue(next.getDefaultValue());
                    }
                    // handle mime-type
                    if (next.getMimeType() != null) {
                        element.getAttributesMap().put(XMLConstants.EXPECTED_CONTENT_TYPES_QNAME, next.getMimeType());
                    }

                    QName elementName = next.getSchemaName();
                    JavaClass javaType = next.getActualType();                   
                    boolean isComplexType = false;

                    element.setName(elementName.getLocalPart());

                    String typeName = null;
                    if (next.isXmlId()) {
                        typeName = XMLConstants.SCHEMA_PREFIX + ":ID";
                    } else if (next.isXmlIdRef()) {
                        typeName = XMLConstants.SCHEMA_PREFIX + ":IDREF";
                    } else {
                        TypeInfo info = (TypeInfo) typeInfo.get(javaType.getQualifiedName());
                        if (info != null) {
                            isComplexType = info.isComplexType();
                            if (isComplexType) {
                                typeName = info.getComplexType().getName();
                            } else if (info.getSimpleType() != null) {
                                typeName = info.getSimpleType().getName();
                            } else {
                                typeName = info.getSchemaTypeName();
                            }

                            if (typeName == null) {
                                //need to add complex-type locally, or reference global element
                                if (!info.hasRootElement()) {
                                    if (info.isComplexType()) {
                                        element.setComplexType(info.getComplexType());
                                    } else {
                                        element.setSimpleType(info.getSimpleType());
                                    }
                                }
                            }

                            // check to see if we need to add an import
                            if (addImportIfRequired(schema, info.getSchema(), info.getClassNamespace())) {
                                String prefix = schema.getNamespaceResolver().resolveNamespaceURI(info.getClassNamespace());
                                if (prefix != null && !typeName.equals("")) {
                                    typeName = prefix + ":" + typeName;
                                }
                            }
                        } else if (!next.isMap()) {
                            QName schemaType = next.getSchemaType();
                            if (schemaType == null) {
                                schemaType = getSchemaTypeFor(javaType);
                            }
                            if (schemaType != null) {
                                if (schemaType.getNamespaceURI() == null) {
                                    typeName = schemaType.getLocalPart();
                                } else {
                                    String prefix = getOrGeneratePrefixForNamespace(schemaType.getNamespaceURI(), schema);
                                    typeName = prefix + ":" + schemaType.getLocalPart();
                                }
                            }
                        }

                        // may need to qualify the type
                        if (typeName != null && !typeName.contains(":")) {
                            String prefix = getPrefixForNamespace(info.getSchema().getTargetNamespace(), schema.getNamespaceResolver());
                            if (prefix != null) {
                                typeName = prefix + ":" + typeName;
                            }
                        }
                    }

                    if (next.getGenericType() != null) {
                        if (next.isXmlList()) {
                            SimpleType localSimpleType = new SimpleType();
                            org.eclipse.persistence.internal.oxm.schema.model.List list = new org.eclipse.persistence.internal.oxm.schema.model.List();
                            list.setItemType(typeName);
                            localSimpleType.setList(list);
                            element.setSimpleType(localSimpleType);
                        } else {
                            element.setMaxOccurs(Occurs.UNBOUNDED);
                            element.setType(typeName);
                        }
                    } else if (next.isMap()) {
                                           
                        ComplexType entryComplexType = new ComplexType();
                        Sequence entrySequence = new Sequence();

                        Element keyElement = new Element();
                        keyElement.setName(Property.DEFAULT_KEY_NAME);
                        keyElement.setMinOccurs(Occurs.ZERO);

                        JavaClass keyType = next.getKeyType();
                        JavaClass valueType = next.getValueType();
                                         
                        if(keyType == null){
                          keyType = helper.getJavaClass(Object.class);
                        }
                       
                        if(valueType == null){
                          valueType = helper.getJavaClass(Object.class);
                        }
                       
                        QName keySchemaType = getSchemaTypeFor(keyType);
                        if (keySchemaType != null) {
                            TypeInfo targetInfo = this.typeInfo.get(keyType.getQualifiedName());
                            if (targetInfo != null) {
                                Schema keyElementSchema = this.getSchemaForNamespace(keySchemaType.getNamespaceURI());
                                //add an import here
                                addImportIfRequired(schema, keyElementSchema, keySchemaType.getNamespaceURI());
                            }
                            String prefix;
                            if (keySchemaType.getNamespaceURI().equals(XMLConstants.SCHEMA_URL)) {
                                prefix = XMLConstants.SCHEMA_PREFIX;
                            } else {
                                prefix = getPrefixForNamespace(keySchemaType.getNamespaceURI(), schema.getNamespaceResolver());
                            }
                            if (prefix != null && !prefix.equals("")) {
                                typeName = prefix + ":" + keySchemaType.getLocalPart();
                            } else {
                                typeName = keySchemaType.getLocalPart();
                            }
                            keyElement.setType(typeName);
                        }

                        entrySequence.addElement(keyElement);

                        Element valueElement = new Element();
                        valueElement.setName(Property.DEFAULT_VALUE_NAME);
                        valueElement.setMinOccurs(Occurs.ZERO);
                        QName valueSchemaType = getSchemaTypeFor(valueType);
                        if (valueSchemaType != null) {
                            TypeInfo targetInfo = this.typeInfo.get(valueType.getQualifiedName());
                            if (targetInfo != null) {
                                Schema valueElementSchema = this.getSchemaForNamespace(valueSchemaType.getNamespaceURI());
                                //add an import here
                                addImportIfRequired(schema, valueElementSchema, valueSchemaType.getNamespaceURI());
                            }
                            String prefix;
                            if (valueSchemaType.getNamespaceURI().equals(XMLConstants.SCHEMA_URL)) {
                                prefix = XMLConstants.SCHEMA_PREFIX;
                            } else {
                                prefix = getPrefixForNamespace(valueSchemaType.getNamespaceURI(), schema.getNamespaceResolver());
                            }
                            if (prefix != null && !prefix.equals("")) {
                                typeName = prefix + ":" + valueSchemaType.getLocalPart();
                            } else {
                                typeName = valueSchemaType.getLocalPart();
                            }
                            valueElement.setType(typeName);
                        }

                        entrySequence.addElement(valueElement);
                        entryComplexType.setSequence(entrySequence);

                        JavaClass descriptorClass = helper.getJavaClass(ownerTypeInfo.getDescriptor().getJavaClassName());
                        JavaClass mapValueClass = helper.getJavaClass(MapValue.class);

                        if (mapValueClass.isAssignableFrom(descriptorClass)) {
                            element.setComplexType(entryComplexType);
                            element.setMaxOccurs(Occurs.UNBOUNDED);
                        } else {
                            ComplexType complexType = new ComplexType();
                            Sequence sequence = new Sequence();
                            complexType.setSequence(sequence);

                            Element entryElement = new Element();
                            entryElement.setName("entry");
                            entryElement.setMinOccurs(Occurs.ZERO);
                            entryElement.setMaxOccurs(Occurs.UNBOUNDED);
                            sequence.addElement(entryElement);
                            entryElement.setComplexType(entryComplexType);

                            element.setComplexType(complexType);
                        }
                    } else {
                        element.setType(typeName);
                    }

                    String lookupNamespace = schema.getTargetNamespace();
                    if (lookupNamespace == null) {
                        lookupNamespace = "";
                    }
                    NamespaceInfo namespaceInfo = getNamespaceInfoForNamespace(lookupNamespace);
                    boolean isElementFormQualified = false;
                    if (namespaceInfo != null) {
                        isElementFormQualified = namespaceInfo.isElementFormQualified();
                    }
                        if ((isElementFormQualified && !elementName.getNamespaceURI().equals(lookupNamespace))
                            || (!isElementFormQualified && !elementName.getNamespaceURI().equals(""))){
                        Element reference = new Element();
                        reference.setMinOccurs(element.getMinOccurs());
                        reference.setMaxOccurs(element.getMaxOccurs());
                        Schema attributeSchema = this.getSchemaForNamespace(elementName.getNamespaceURI());
                        if (attributeSchema != null && attributeSchema.getTopLevelElements().get(element.getName()) == null) {
                            // reset min/max occurs as they aren't applicable for global elements
                            element.setMinOccurs(null);
                            element.setMaxOccurs(null);
                            //don't overwrite global elements. May have been defined by a type.
                            attributeSchema.getTopLevelElements().put(element.getName(), element);
                        }

                        //add an import here
                        addImportIfRequired(schema, attributeSchema, elementName.getNamespaceURI());

                        String prefix = getPrefixForNamespace(elementName.getNamespaceURI(), schema.getNamespaceResolver());
                        if (prefix == null) {
                            reference.setRef(element.getName());
                        } else {
                            reference.setRef(prefix + ":" + element.getName());
                        }
                        parentCompositor.addElement(reference);
                    } else {
                        parentCompositor.addElement(element);
                    }
                }
            }
        }
    }

    public QName getSchemaTypeFor(JavaClass javaClass) {
        // check user defined types first
        QName schemaType = (QName) userDefinedSchemaTypes.get(javaClass.getQualifiedName());
        if (schemaType == null) {
            schemaType = (QName) helper.getXMLToJavaTypeMap().get(javaClass.getRawName());
        }
        if (schemaType == null) {
            TypeInfo targetInfo = this.typeInfo.get(javaClass.getQualifiedName());
            if (targetInfo != null) {
                schemaType = new QName(targetInfo.getClassNamespace(), targetInfo.getSchemaTypeName());
            }
        }
        if (schemaType == null) {
            if (javaClass.getQualifiedName().equals("java.lang.Object")) {
                return XMLConstants.ANY_TYPE_QNAME;
            }
            return XMLConstants.ANY_SIMPLE_TYPE_QNAME;
        }
        return schemaType;
    }

    public void populateSchemaTypes() {
        Iterator<String> classNames = typeInfo.keySet().iterator();
        while (classNames.hasNext()) {
            String javaClassName = classNames.next();
            TypeInfo info = (TypeInfo) typeInfo.get(javaClassName);
            if (info.isComplexType()) {
                if (info.getSchema() != null) {
                    addToSchemaType(info, info.getNonTransientPropertiesInPropOrder(), info.getCompositor(), info.getComplexType(), info.getSchema());
                }
            }
        }
    }

    public String getSchemaTypeNameForClassName(String className) {
        String typeName = Introspector.decapitalize(className.substring(className.lastIndexOf('.') + 1));
        return typeName;
    }

    public ArrayList<String> getEnumerationFacetsFor(EnumTypeInfo info) {
        return (ArrayList<String>) info.getFieldValues();
    }

    public Property getXmlValueFieldForSimpleContent(TypeInfo info) {
        ArrayList<Property> properties = info.getPropertyList();
        Property xmlValueProperty = info.getXmlValueProperty();
        boolean foundValue = false;
        boolean foundNonAttribute = false;
        Property valueField = null;

        for (Property prop : properties) {
            if (xmlValueProperty != null && xmlValueProperty == prop) {
                foundValue = true;
                valueField = prop;
            } else if (!prop.isAttribute() && !helper.isAnnotationPresent(prop.getElement(), XmlTransient.class) && !prop.isAnyAttribute()) {
                foundNonAttribute = true;
            }
        }
        if (foundValue && !foundNonAttribute) {
            return valueField;
        }
        return null;
    }

    public boolean isCollectionType(Property field) {
        JavaClass type = field.getType();
        return (helper.getJavaClass(java.util.Collection.class).isAssignableFrom(type)
                || helper.getJavaClass(java.util.List.class).isAssignableFrom(type)
                || helper.getJavaClass(java.util.Set.class).isAssignableFrom(type));
    }

    private Schema getSchemaForNamespace(String namespace) {
        if (schemaForNamespace == null) {
            schemaForNamespace = new HashMap<String, Schema>();
            allSchemas = new ArrayList<Schema>();
        }
        Schema schema = schemaForNamespace.get(namespace);
        if (schema == null) {

            NamespaceInfo namespaceInfo = getNamespaceInfoForNamespace(namespace);

            schema = new Schema();
            schema.setName("schema" + schemaCount + ".xsd");

            if (namespaceInfo != null) {
                if (namespaceInfo.getLocation() != null && !namespaceInfo.getLocation().equals("##generate")) {
                    return null;
                }
                java.util.Vector namespaces = namespaceInfo.getNamespaceResolver().getNamespaces();
                for (int i = 0; i < namespaces.size(); i++) {
                    Namespace nextNamespace = (Namespace) namespaces.get(i);
                    schema.getNamespaceResolver().put(nextNamespace.getPrefix(), nextNamespace.getNamespaceURI());
                }
            }
            schemaCount++;

            if (!namespace.equals("")) {
                schema.setTargetNamespace(namespace);
                String prefix = null;
                if (namespaceInfo != null) {
                    prefix = namespaceInfo.getNamespaceResolver().resolveNamespaceURI(namespace);
                }
                if (prefix == null) {
                    prefix = schema.getNamespaceResolver().generatePrefix();
                }
                schema.getNamespaceResolver().put(prefix, namespace);
            }

            if (namespaceInfo != null) {
                schema.setAttributeFormDefault(namespaceInfo.isAttributeFormQualified());
                schema.setElementFormDefault(namespaceInfo.isElementFormQualified());
            }
            schemaForNamespace.put(namespace, schema);
            allSchemas.add(schema);
        }
        return schema;
    }

    public Collection<Schema> getAllSchemas() {
        if (allSchemas == null) {
            allSchemas = new ArrayList<Schema>();
        }
        return allSchemas;
    }

    public NamespaceInfo getNamespaceInfoForNamespace(String namespace) {
        Collection<NamespaceInfo> namespaceInfo = packageToNamespaceMappings.values();
        for (NamespaceInfo info : namespaceInfo) {
            if (info.getNamespace().equals(namespace)) {
                return info;
            }
        }
        return null;
    }

    public String getPrefixForNamespace(String URI, org.eclipse.persistence.oxm.NamespaceResolver namespaceResolver) {
        Enumeration keys = namespaceResolver.getPrefixes();
        while (keys.hasMoreElements()) {
            String next = (String) keys.nextElement();
            String nextUri = namespaceResolver.resolveNamespacePrefix(next);
            if (nextUri.equals(URI)) {
                return next;
            }
        }
        return null;
    }

    /**
     * Attempt to resolve the given URI to a prefix.  If this is unsuccessful, one
     * will be generated and added to the resolver.
     *
     * @param URI
     * @param schema
     * @return
     */
    public String getOrGeneratePrefixForNamespace(String URI, Schema schema) {
        String prefix = schema.getNamespaceResolver().resolveNamespaceURI(URI);
        if (prefix == null) {
            if (URI.equals(XMLConstants.SCHEMA_URL)) {
                prefix = schema.getNamespaceResolver().generatePrefix(XMLConstants.SCHEMA_PREFIX);
            } else if (URI.equals(XMLConstants.REF_URL)) {
                prefix = schema.getNamespaceResolver().generatePrefix(XMLConstants.REF_PREFIX);
            } else {
                prefix = schema.getNamespaceResolver().generatePrefix();
            }
            schema.getNamespaceResolver().put(prefix, URI);
        }
        return prefix;
    }

    public void addGlobalElements(HashMap<QName, ElementDeclaration> additionalElements) {
        for (QName next : additionalElements.keySet()) {
            if (next != null) {

                ElementDeclaration nextElement = additionalElements.get(next);
                if (nextElement.getScopeClass() == GLOBAL.class) {

                    String namespaceURI = next.getNamespaceURI();
                    Schema targetSchema = getSchemaForNamespace(namespaceURI);
                    if (targetSchema == null) {
                        break;
                    }

                    if (targetSchema.getTopLevelElements().get(next.getLocalPart()) == null) {
                        Element element = new Element();
                        element.setName(next.getLocalPart());

                        JavaClass javaClass = nextElement.getJavaType();

                        //First check for built in type
                        QName schemaType = (QName) helper.getXMLToJavaTypeMap().get(javaClass.getRawName());
                        if (schemaType != null) {
                            element.setType(XMLConstants.SCHEMA_PREFIX + ":" + schemaType.getLocalPart());
                        } else {
                            TypeInfo type = (TypeInfo) this.typeInfo.get(javaClass.getQualifiedName());
                            if (type != null) {
                                String typeName = null;
                                if (type.isComplexType()) {
                                    typeName = type.getComplexType().getName();
                                } else {
                                    typeName = type.getSimpleType().getName();
                                }
                                //  check namespace of schemaType
                                if (type.getClassNamespace().equals(namespaceURI)) {
                                    //no need to prefix here
                                    element.setType(typeName);
                                } else {
                                    Schema complexTypeSchema = getSchemaForNamespace(type.getClassNamespace());

                                    String complexTypeSchemaNS = type.getClassNamespace();
                                    if (complexTypeSchemaNS == null) {
                                        complexTypeSchemaNS = "";
                                    }
                                    addImportIfRequired(targetSchema, complexTypeSchema, type.getClassNamespace());

                                    String prefix = targetSchema.getNamespaceResolver().resolveNamespaceURI(complexTypeSchemaNS);
                                    if (prefix != null) {
                                        element.setType(prefix + ":" + typeName);
                                    } else {
                                        element.setType(typeName);
                                    }
                                }
                            }

                        }
                        if (nextElement.getSubstitutionHead() != null) {
                            String subLocal = nextElement.getSubstitutionHead().getLocalPart();
                            String subNamespace = nextElement.getSubstitutionHead().getNamespaceURI();
                            String prefix = getPrefixForNamespace(subNamespace, targetSchema.getNamespaceResolver());
                            if (prefix == null || prefix.equals("")) {
                                element.setSubstitutionGroup(subLocal);
                            } else {
                                element.setSubstitutionGroup(prefix + ":" + subLocal);
                            }
                        }
                        targetSchema.addTopLevelElement(element);
                        SchemaTypeInfo info = this.schemaTypeInfo.get(javaClass.getQualifiedName());
                        if (info == null) {
                            // probably for a simple type, not generated
                            info = new SchemaTypeInfo();
                            info.setSchemaTypeName(schemaType);
                            schemaTypeInfo.put(javaClass.getQualifiedName(), info);
                        }
                        info.getGlobalElementDeclarations().add(next);
                    }
                }
            }
        }
    }

    public HashMap<String, SchemaTypeInfo> getSchemaTypeInfo() {
        return this.schemaTypeInfo;
    }

    private boolean importExists(Schema schema, String schemaName) {
        java.util.List imports = schema.getImports();
        for (int i = 0; i < imports.size(); i++) {
            Import nextImport = (Import) imports.get(i);
            if (nextImport.getSchemaLocation() != null && nextImport.getSchemaLocation().equals(schemaName)) {
                return true;
            }
        }
        return false;
    }

    private boolean addImportIfRequired(Schema sourceSchema, Schema importSchema, String importNamespace) {
        if (importSchema != sourceSchema) {
            String schemaName = null;
            if (importSchema != null) {
                schemaName = importSchema.getName();
            } else if (importNamespace != null) {
                NamespaceInfo nInfo = getNamespaceInfoForNamespace(importNamespace);
                schemaName = nInfo.getLocation();
            }

            if (schemaName != null && !importExists(sourceSchema, schemaName)) {
                Import schemaImport = new Import();
                schemaImport.setSchemaLocation(schemaName);
                if (importNamespace != null && !importNamespace.equals("")) {
                    schemaImport.setNamespace(importNamespace);
                }
                sourceSchema.getImports().add(schemaImport);
                if (schemaImport.getNamespace() != null) {
                    String prefix = sourceSchema.getNamespaceResolver().resolveNamespaceURI(importNamespace);
                    //Don't need to generate prefix for default namespace
                    if (prefix == null && !importNamespace.equals("")) {
                        sourceSchema.getNamespaceResolver().put(sourceSchema.getNamespaceResolver().generatePrefix(), importNamespace);
                    }
                }
                return true;
            }
        }
        return false;
    }
}
TOP

Related Classes of org.eclipse.persistence.jaxb.compiler.SchemaGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.