Package org.apache.geronimo.axis.builder

Source Code of org.apache.geronimo.axis.builder.HeavyweightTypeInfoBuilder$TypeMappingLookup

/**
*
* Copyright 2005 The Apache Software Foundation
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/
package org.apache.geronimo.axis.builder;

import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.rpc.encoding.DeserializerFactory;
import javax.xml.rpc.encoding.SerializerFactory;

import org.apache.axis.description.AttributeDesc;
import org.apache.axis.description.ElementDesc;
import org.apache.axis.description.FieldDesc;
import org.apache.axis.description.OperationDesc;
import org.apache.axis.description.ParameterDesc;
import org.apache.axis.encoding.DefaultJAXRPC11TypeMappingImpl;
import org.apache.axis.encoding.DefaultSOAPEncodingTypeMappingImpl;
import org.apache.axis.encoding.TypeMappingImpl;
import org.apache.axis.encoding.XMLType;
import org.apache.axis.encoding.ser.ArrayDeserializerFactory;
import org.apache.axis.encoding.ser.ArraySerializerFactory;
import org.apache.axis.encoding.ser.BeanDeserializerFactory;
import org.apache.axis.encoding.ser.BeanSerializerFactory;
import org.apache.axis.encoding.ser.EnumDeserializerFactory;
import org.apache.axis.encoding.ser.EnumSerializerFactory;
import org.apache.axis.encoding.ser.SimpleListDeserializerFactory;
import org.apache.axis.encoding.ser.SimpleListSerializerFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geronimo.axis.client.ArrayTypeInfo;
import org.apache.geronimo.axis.client.TypeInfo;
import org.apache.geronimo.common.DeploymentException;
import org.apache.geronimo.kernel.ClassLoading;
import org.apache.geronimo.xbeans.j2ee.JavaWsdlMappingType;
import org.apache.geronimo.xbeans.j2ee.JavaXmlTypeMappingType;
import org.apache.geronimo.xbeans.j2ee.VariableMappingType;
import org.apache.xmlbeans.SchemaLocalAttribute;
import org.apache.xmlbeans.SchemaParticle;
import org.apache.xmlbeans.SchemaProperty;
import org.apache.xmlbeans.SchemaType;
import org.apache.xmlbeans.soap.SOAPArrayType;
import org.apache.xmlbeans.soap.SchemaWSDLArrayType;

/**
* @version $Rev: 356022 $ $Date: 2005-12-11 21:58:34 +0100 (Sun, 11 Dec 2005) $
*/
public class HeavyweightTypeInfoBuilder implements TypeInfoBuilder {
    private static final String SOAP_ENCODING_NS = "http://schemas.xmlsoap.org/soap/encoding/";
    private static final String XML_SCHEMA_NS = "http://www.w3.org/2001/XMLSchema";
   
    private static final Log log = LogFactory.getLog(HeavyweightTypeInfoBuilder.class);

    private final ClassLoader cl;
    private final Map schemaTypeKeyToSchemaTypeMap;
    private final Set wrapperElementQNames;
    private final Collection operations;
    private final boolean hasEncoded;

    public HeavyweightTypeInfoBuilder(ClassLoader cl, Map schemaTypeKeyToSchemaTypeMap, Set wrapperElementQNames, Collection operations, boolean hasEncoded) {
        this.cl = cl;
        this.schemaTypeKeyToSchemaTypeMap = schemaTypeKeyToSchemaTypeMap;
        this.wrapperElementQNames = wrapperElementQNames;
        this.operations = operations;
        this.hasEncoded = hasEncoded;
    }

    public List buildTypeInfo(JavaWsdlMappingType mapping) throws DeploymentException {
        List typeInfoList = new ArrayList();

        Set mappedTypeQNames = new HashSet();

        JavaXmlTypeMappingType[] javaXmlTypeMappings = mapping.getJavaXmlTypeMappingArray();
        for (int j = 0; j < javaXmlTypeMappings.length; j++) {
            JavaXmlTypeMappingType javaXmlTypeMapping = javaXmlTypeMappings[j];

            SchemaTypeKey key;
            boolean isElement = javaXmlTypeMapping.getQnameScope().getStringValue().equals("element");
            boolean isSimpleType = javaXmlTypeMapping.getQnameScope().getStringValue().equals("simpleType");
            if (javaXmlTypeMapping.isSetRootTypeQname()) {
                QName typeQName = javaXmlTypeMapping.getRootTypeQname().getQNameValue();
                key = new SchemaTypeKey(typeQName, isElement, isSimpleType, false, null);

                // Skip the wrapper elements.
                if (wrapperElementQNames.contains(typeQName)) {
                    continue;
                }
            } else if (javaXmlTypeMapping.isSetAnonymousTypeQname()) {
                String anonTypeQNameString = javaXmlTypeMapping.getAnonymousTypeQname().getStringValue();
                int pos = anonTypeQNameString.lastIndexOf(":");
                if (pos == -1) {
                    throw new DeploymentException("anon QName is invalid, no final ':' " + anonTypeQNameString);
                }

                //this appears to be ignored...
                QName typeQName = new QName(anonTypeQNameString.substring(0, pos), anonTypeQNameString.substring(pos + 1));
                key = new SchemaTypeKey(typeQName, isElement, isSimpleType, true, null);

                // Skip the wrapper elements.
                if (wrapperElementQNames.contains(new QName(anonTypeQNameString.substring(0, pos), anonTypeQNameString.substring(pos + 2)))) {
                    continue;
                }
            } else {
                throw new DeploymentException("either root type qname or anonymous type qname must be set");
            }

            SchemaType schemaType = (SchemaType) schemaTypeKeyToSchemaTypeMap.get(key);
            if (schemaType == null) {
                // if it is a built-in type, then one assumes a redundant mapping.
                if (null != TypeMappingLookup.getFactoryPair(key.getqName())) {
                    continue;
                }
//              throw new DeploymentException("Schema type key " + key + " not found in analyzed schema: " + schemaTypeKeyToSchemaTypeMap);
                log.warn("Schema type key " + key + " not found in analyzed schema: " + schemaTypeKeyToSchemaTypeMap);
                continue;
            }
            mappedTypeQNames.add(key.getqName());

            String className = javaXmlTypeMapping.getJavaType().getStringValue().trim();
            Class clazz = null;
            try {
                clazz = ClassLoading.loadClass(className, cl);
            } catch (ClassNotFoundException e2) {
                throw new DeploymentException("Could not load java type", e2);
            }

            TypeInfo.UpdatableTypeInfo internalTypeInfo = defineSerializerPair(schemaType, clazz);

            populateInternalTypeInfo(clazz, key, schemaType, javaXmlTypeMapping, internalTypeInfo);

            typeInfoList.add(internalTypeInfo.buildTypeInfo());
        }

        Map qNameToKey = new HashMap();
        for (Iterator iter = schemaTypeKeyToSchemaTypeMap.keySet().iterator(); iter.hasNext();) {
            SchemaTypeKey key = (SchemaTypeKey) iter.next();
            qNameToKey.put(key.getqName(), key);
        }

        for (Iterator iter = operations.iterator(); iter.hasNext();) {
            OperationDesc operationDesc = (OperationDesc) iter.next();
            ArrayList parameters = new ArrayList(operationDesc.getParameters());
            ParameterDesc returnParameterDesc = operationDesc.getReturnParamDesc();
            if (null != returnParameterDesc.getTypeQName() &&
                    false == returnParameterDesc.getTypeQName().equals(XMLType.AXIS_VOID)) {
                parameters.add(returnParameterDesc);
            }
            for (Iterator iterator = parameters.iterator(); iterator.hasNext();) {
                ParameterDesc parameterDesc = (ParameterDesc) iterator.next();
                QName typeQName = parameterDesc.getTypeQName();
                if (null == typeQName) {
                    continue;
                } else if (mappedTypeQNames.contains(typeQName)) {
                    continue;
                } else if (typeQName.getNamespaceURI().equals(XML_SCHEMA_NS) ||
                        typeQName.getNamespaceURI().equals(SOAP_ENCODING_NS)) {
                    continue;
                }

                SchemaTypeKey key = (SchemaTypeKey) qNameToKey.get(typeQName);
                if (null == key) {
                    log.warn("Type QName [" + typeQName + "] defined by operation [" +
                            operationDesc + "] has not been found in schema: " + schemaTypeKeyToSchemaTypeMap);
                    continue;
                }
                SchemaType schemaType = (SchemaType) schemaTypeKeyToSchemaTypeMap.get(key);
                mappedTypeQNames.add(key.getqName());

                if (false == schemaType.isSimpleType()) {
                    if (false == parameterDesc.getJavaType().isArray()) {
                        if (false == mappedTypeQNames.contains(schemaType.getName())) {
                            // TODO: this lookup is not enough: the jaxrpc mapping file may define an anonymous
                            // mapping.
                            log.warn("Operation [" + operationDesc + "] uses XML type [" + schemaType +
                                    "], whose mapping is not declared by the jaxrpc mapping file.\n Continuing deployment; " +
                                    "yet, the deployment is not-portable.");
                        }
                        continue;
                    }
                }

                Class clazz = parameterDesc.getJavaType();
                TypeInfo.UpdatableTypeInfo internalTypeInfo =  defineSerializerPair(schemaType, clazz);
                setTypeQName(internalTypeInfo, key);
                internalTypeInfo.setFields(new FieldDesc[0]);

                typeInfoList.add(internalTypeInfo.buildTypeInfo());
            }
        }

        return typeInfoList;
    }

    private TypeInfo.UpdatableTypeInfo defineSerializerPair(SchemaType schemaType, Class clazz)
            throws DeploymentException {
        TypeInfo.UpdatableTypeInfo internalTypeInfo = new TypeInfo.UpdatableTypeInfo();
        Class serializerFactoryClass = null;
        Class deserializerFactoryClass = null;
        if (schemaType.isSimpleType()) {
            if (SchemaType.ATOMIC == schemaType.getSimpleVariety()) {
                if (clazz.isArray()) {
                    internalTypeInfo = new ArrayTypeInfo.UpdatableArrayTypeInfo();
                    serializerFactoryClass = ArraySerializerFactory.class;
                    deserializerFactoryClass = ArrayDeserializerFactory.class;
                    //TODO set componentType, componentQName
                } else if (null != schemaType.getEnumerationValues()) {
                    serializerFactoryClass = EnumSerializerFactory.class;
                    deserializerFactoryClass = EnumDeserializerFactory.class;
                } else {
                    QName typeQName = schemaType.getPrimitiveType().getName();
                    FactoryPair pair = (FactoryPair) TypeMappingLookup.getFactoryPair(typeQName);
                    if (null == pair) {
                        throw new DeploymentException("Primitive type [" + typeQName + "] is not registered.");
                    }
                    serializerFactoryClass = pair.serializerFactoryClass;
                    deserializerFactoryClass = pair.deserializerFactoryClass;
                }
            } else if (SchemaType.LIST == schemaType.getSimpleVariety()) {
                serializerFactoryClass = SimpleListSerializerFactory.class;
                deserializerFactoryClass = SimpleListDeserializerFactory.class;
            } else {
                throw new DeploymentException("Schema type [" + schemaType + "] is invalid.");
            }
        } else {
            if (clazz.isArray()) {
                internalTypeInfo = new ArrayTypeInfo.UpdatableArrayTypeInfo();
                serializerFactoryClass = ArraySerializerFactory.class;
                deserializerFactoryClass = ArrayDeserializerFactory.class;
                QName componentType = null;
                //First, handle case that looks like this:
//                <complexType name="ArrayOfstring">
//                    <complexContent>
//                        <restriction base="soapenc:Array">
//                            <attribute ref="soapenc:arrayType" wsdl:arrayType="xsd:string[]"/>
//                        </restriction>
//                    </complexContent>
//                </complexType>
                SchemaLocalAttribute arrayTypeAttribute =  schemaType.getAttributeModel().getAttribute(new QName(SOAP_ENCODING_NS, "arrayType"));
                if (arrayTypeAttribute != null) {
                    SchemaWSDLArrayType wsdlArrayType = (SchemaWSDLArrayType) arrayTypeAttribute;
                    SOAPArrayType soapArrayType = wsdlArrayType.getWSDLArrayType();
                    if (soapArrayType != null) {
                        componentType = soapArrayType.getQName();
                        log.debug("extracted componentType " + componentType + " from schemaType " + schemaType);
                    } else {
                        log.info("no SOAPArrayType for component from schemaType " + schemaType);
                    }
                } else {
                    log.warn("No soap array info for schematype: " + schemaType);
                }
                if (componentType == null) {
                    //If that didn't work, try to handle case like this:
//                    <complexType name="ArrayOfstring1">
//                        <complexContent>
//                            <restriction base="soapenc:Array">
//                                <sequence>
//                                    <element name="string1" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
//                                </sequence>
//                            </restriction>
//                        </complexContent>
//                    </complexType>
                    //todo consider if we should check for maxOccurs > 1
                    if (schemaType.getBaseType().getName().equals(new QName(SOAP_ENCODING_NS, "Array"))) {
                        SchemaProperty[] properties = schemaType.getDerivedProperties();
                        if (properties.length != 1) {
                            throw new DeploymentException("more than one element inside array definition: " + schemaType);
                        }
                        componentType = properties[0].getType().getName();
                        log.debug("determined component type from element type");
                    }

                }

                ((ArrayTypeInfo.UpdatableArrayTypeInfo)internalTypeInfo).setComponentType(componentType);
                //If we understand the axis comments correctly, componentQName is never set for j2ee ws.
            } else {
                QName typeQName;
                if (SchemaType.SIMPLE_CONTENT == schemaType.getContentType()) {
                    typeQName = schemaType.getBaseType().getName();
                } else if (SchemaType.EMPTY_CONTENT == schemaType.getContentType() ||
                        SchemaType.ELEMENT_CONTENT == schemaType.getContentType() ||
                        SchemaType.MIXED_CONTENT == schemaType.getContentType()) {
                    typeQName = schemaType.getName();
                } else {
                    throw new DeploymentException("Schema type [" + schemaType + "] is invalid.");
                }
                FactoryPair pair = (FactoryPair) TypeMappingLookup.getFactoryPair(typeQName);
                if (null != pair) {
                    serializerFactoryClass = pair.serializerFactoryClass;
                    deserializerFactoryClass = pair.deserializerFactoryClass;
                } else {
                    serializerFactoryClass = BeanSerializerFactory.class;
                    deserializerFactoryClass = BeanDeserializerFactory.class;
                }
            }
        }

        internalTypeInfo.setClazz(clazz);
        internalTypeInfo.setSerializerClass(serializerFactoryClass);
        internalTypeInfo.setDeserializerClass(deserializerFactoryClass);
        return internalTypeInfo;
    }

    private void setTypeQName(TypeInfo.UpdatableTypeInfo typeInfo, SchemaTypeKey key) {
        //figure out the name axis expects to look up under.
        QName axisKey = key.getElementQName();
        if (axisKey == null) {
            axisKey = key.getqName();
        }
        typeInfo.setQName(axisKey);
    }

    private void populateInternalTypeInfo(Class javaClass, SchemaTypeKey key, SchemaType schemaType, JavaXmlTypeMappingType javaXmlTypeMapping, TypeInfo.UpdatableTypeInfo typeInfo) throws DeploymentException {
        String ns = key.getqName().getNamespaceURI();
        typeInfo.setCanSearchParents(schemaType.getDerivationType() == SchemaType.DT_RESTRICTION);

        setTypeQName(typeInfo, key);

        Map paramNameToType = new HashMap();
        if (null == schemaType.getContentModel()) {
            ;
        } else if (SchemaParticle.SEQUENCE == schemaType.getContentModel().getParticleType()
                || SchemaParticle.ALL == schemaType.getContentModel().getParticleType()) {
            SchemaParticle[] properties = schemaType.getContentModel().getParticleChildren();
            for (int i = 0; i < properties.length; i++) {
                SchemaParticle parameter = properties[i];
                paramNameToType.put(parameter.getName(), parameter);
            }
        } else if (SchemaParticle.ELEMENT == schemaType.getContentModel().getParticleType()) {
            SchemaParticle parameter = schemaType.getContentModel();
            paramNameToType.put(parameter.getName(), parameter);
        } else {
            throw new DeploymentException("Only element, sequence, and all particle types are supported." +
                    " SchemaType name =" + schemaType.getName());
        }

        Map attNameToType = new HashMap();
        if (null != schemaType.getAttributeModel()) {
            SchemaLocalAttribute[] attributes = schemaType.getAttributeModel().getAttributes();
            for (int i = 0; i < attributes.length; i++) {
                SchemaLocalAttribute attribute = attributes[i];
                Object old = attNameToType.put(attribute.getName().getLocalPart(), attribute);
                if (old != null) {
                    throw new DeploymentException("Complain to your expert group member, spec does not support attributes with the same local name and differing namespaces: original: " + old + ", duplicate local name: " + attribute);
                }
            }
        }
       
        VariableMappingType[] variableMappings = javaXmlTypeMapping.getVariableMappingArray();

        // short-circuit the processing of arrays as they should not define variable-mapping elements.
        if (javaClass.isArray()) {
            if (0 != variableMappings.length) {
                // for portability reason we simply warn and not fail.
                log.warn("Ignoring variable-mapping defined for class " + javaClass + " which is an array.");
            }
            typeInfo.setFields(new FieldDesc[0]);
            return;
        }

        FieldDesc[] fields = new FieldDesc[variableMappings.length];
        typeInfo.setFields(fields);

        PropertyDescriptor[] propertyDescriptors = new PropertyDescriptor[0];
        try {
            propertyDescriptors = Introspector.getBeanInfo(javaClass).getPropertyDescriptors();
        } catch (IntrospectionException e) {
            throw new DeploymentException("Class " + javaClass + " is not a valid javabean", e);
        }
        Map properties = new HashMap();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
            properties.put(propertyDescriptor.getName(), propertyDescriptor.getPropertyType());
        }
        for (int i = 0; i < variableMappings.length; i++) {
            VariableMappingType variableMapping = variableMappings[i];
            String fieldName = variableMapping.getJavaVariableName().getStringValue().trim();

            if (variableMapping.isSetXmlAttributeName()) {
                AttributeDesc attributeDesc = new AttributeDesc();
                attributeDesc.setFieldName(fieldName);
                Class javaType = (Class) properties.get(fieldName);
                if (javaType == null) {
                    throw new DeploymentException("field name " + fieldName + " not found in " + properties);
                }
                String attributeLocalName = variableMapping.getXmlAttributeName().getStringValue().trim();
                QName xmlName = new QName("", attributeLocalName);
                attributeDesc.setXmlName(xmlName);

                SchemaLocalAttribute attribute = (SchemaLocalAttribute) attNameToType.get(attributeLocalName);
                if (null == attribute) {
                    throw new DeploymentException("attribute " + xmlName + " not found in schema " + schemaType.getName());
                }
                attributeDesc.setXmlType(attribute.getType().getName());

                fields[i] = attributeDesc;
            } else {
                ElementDesc elementDesc = new ElementDesc();
                elementDesc.setFieldName(fieldName);
                Class javaType = (Class) properties.get(fieldName);
                if (javaType == null) {
                    //see if it is a public field
                    try {
                        Field field = javaClass.getField(fieldName);
                        javaType = field.getType();
                    } catch (NoSuchFieldException e) {
                        throw new DeploymentException("field name " + fieldName + " not found in " + properties);
                    }
                }
                QName xmlName = new QName("", variableMapping.getXmlElementName().getStringValue().trim());
                SchemaParticle particle = (SchemaParticle) paramNameToType.get(xmlName);
                if (null == particle) {
                    xmlName = new QName(ns, variableMapping.getXmlElementName().getStringValue().trim());
                    particle = (SchemaParticle) paramNameToType.get(xmlName);
                    if (null == particle) {
                        throw new DeploymentException("element " + xmlName + " not found in schema " + schemaType.getName());
                    }
                } else if (SchemaParticle.ELEMENT != particle.getParticleType()) {
                    throw new DeploymentException(xmlName + " is not an element in schema " + schemaType.getName());
                }
                elementDesc.setNillable(particle.isNillable() || hasEncoded);
                elementDesc.setXmlName(xmlName);
                if (null != particle.getType().getName()) {
                    elementDesc.setXmlType(particle.getType().getName());
                } else {
                    QName anonymousName;
                    if (key.isAnonymous()) {
                        anonymousName = new QName(key.getqName().getNamespaceURI(), key.getqName().getLocalPart() +
                                ">" + particle.getName().getLocalPart());
                    } else {
                        anonymousName = new QName(key.getqName().getNamespaceURI(),
                                ">" + key.getqName().getLocalPart() + ">" + particle.getName().getLocalPart());
                    }
                    elementDesc.setXmlType(anonymousName);
                }

                if (javaType.isArray()) {
                    elementDesc.setMinOccurs(particle.getIntMinOccurs());
                    elementDesc.setMaxOccurs(particle.getIntMaxOccurs());
                    //TODO axis seems to have the wrong name for this property based on how it is used
                    elementDesc.setMaxOccursUnbounded(particle.getIntMaxOccurs() > 1);
                }

                fields[i] = elementDesc;
            }
        }
    }

    private static class TypeMappingLookup {
        private static final TypeMappingImpl SOAP_TM = DefaultSOAPEncodingTypeMappingImpl.getSingleton();
        private static final TypeMappingImpl JAXRPC_TM = DefaultJAXRPC11TypeMappingImpl.getSingleton();

        public static FactoryPair getFactoryPair(QName xmlType) {
            Class clazz = SOAP_TM.getClassForQName(xmlType, null, null);
            SerializerFactory sf;
            DeserializerFactory df;
            if (null != clazz) {
                sf = SOAP_TM.getSerializer(clazz, xmlType);
                df = SOAP_TM.getDeserializer(clazz, xmlType, null);
            } else {
                clazz = JAXRPC_TM.getClassForQName(xmlType, null, null);
                if (null == clazz) {
                    return null;
                }
                sf = JAXRPC_TM.getSerializer(clazz, xmlType);
                df = JAXRPC_TM.getDeserializer(clazz, xmlType, null);
            }
            return new FactoryPair(sf.getClass(), df.getClass());
        }
    }

    private static class FactoryPair {
        private final Class serializerFactoryClass;
        private final Class deserializerFactoryClass;

        private FactoryPair(Class serializerFactoryClass, Class deserializerFactoryClass) {
            this.serializerFactoryClass = serializerFactoryClass;
            this.deserializerFactoryClass = deserializerFactoryClass;
        }
    }
}
TOP

Related Classes of org.apache.geronimo.axis.builder.HeavyweightTypeInfoBuilder$TypeMappingLookup

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.