Package org.apache.axis.description

Source Code of org.apache.axis.description.TypeDesc

/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2002 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Axis" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

package org.apache.axis.description;

import org.apache.axis.utils.ClassUtils;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.utils.BeanUtils;
import org.apache.axis.utils.BeanPropertyDescriptor;

import org.apache.axis.components.logger.LogFactory;
import org.apache.commons.logging.Log;

import javax.xml.namespace.QName;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

/**
* A TypeDesc represents a Java<->XML data binding.  It is essentially
* a collection of FieldDescs describing how to map each field in a Java
* class to XML.
*
* @author Glen Daniels (gdaniels@apache.org)
*/
public class TypeDesc {
    public static final Class [] noClasses = new Class [] {};
    public static final Object[] noObjects = new Object[] {};

    /** Have we already introspected for the special "any" property desc? */
    private boolean lookedForAny = false;

    public TypeDesc(Class javaClass) {
        this.javaClass = javaClass;
    }

    /**
     * Static function for centralizing access to type metadata for a
     * given class. 
     *
     * This checks for a static getTypeDesc() method on the
     * class or _Helper class.
     * Eventually we may extend this to provide for external
     * metadata config (via files sitting in the classpath, etc).
     *
     * (Could introduce a cache here for speed as an optimization)
     */
    public static TypeDesc getTypeDescForClass(Class cls)
    {
        try {
            Method getTypeDesc = null;
            try {
                getTypeDesc =
                    cls.getMethod("getTypeDesc", noClasses);
            } catch (NoSuchMethodException e) {}
            if (getTypeDesc == null) {
                // Look for a Helper Class
                Class helper = ClassUtils.forName(cls.getName() + "_Helper");
                try {
                    getTypeDesc =
                        helper.getMethod("getTypeDesc", noClasses);
                } catch (NoSuchMethodException e) {}
            }
            if (getTypeDesc != null) {
                return (TypeDesc)getTypeDesc.invoke(null,
                                                    noObjects);
            }
        } catch (Exception e) {
        }
        return null;
    }

    /** The Java class for this type */
    private Class javaClass = null;

    /** The XML type QName for this type */
    private QName xmlType = null;

    /** The various fields in here */
    private FieldDesc [] fields;

    /** A cache of FieldDescs by name */
    private HashMap fieldNameMap = new HashMap();
   
    /** A cache of FieldDescs by Element QName */
    private HashMap fieldElementMap = null;
   
    /** Are there any fields which are serialized as attributes? */
    private boolean _hasAttributes = false;

    /** Introspected property descriptors */
    private BeanPropertyDescriptor[] propertyDescriptors = null;
    /** Map with key = property descriptor name, value = descriptor */
    private Map propertyMap = null;

    /**
     * Indication if this type has support for xsd:any.
     */
    private BeanPropertyDescriptor anyDesc = null;

    public BeanPropertyDescriptor getAnyDesc() {
        return anyDesc;
    }

    /**
     * Obtain the current array of FieldDescs
     */
    public FieldDesc[] getFields() {
        return fields;
    }

    public FieldDesc[] getFields(boolean searchParents) {
        if (searchParents) {
            // check superclasses if they exist
            Class cls = javaClass.getSuperclass();
            if (cls != null && !cls.getName().startsWith("java.")) {
                TypeDesc superDesc = getTypeDescForClass(cls);
                if (superDesc != null) {
                    FieldDesc [] parentFields = superDesc.getFields(true);
                    FieldDesc [] ret = new FieldDesc[parentFields.length + fields.length];
                    System.arraycopy(fields, 0, ret, 0, fields.length);
                    System.arraycopy(parentFields, 0, ret, fields.length, parentFields.length);
                }
            }
        }

        return fields;
    }

    /**
     * Replace the array of FieldDescs, making sure we keep our convenience
     * caches in sync.
     */
    public void setFields(FieldDesc [] newFields)
    {
        fieldNameMap = new HashMap();
        fields = newFields;
        _hasAttributes = false;
        fieldElementMap = null;
       
        for (int i = 0; i < newFields.length; i++) {
            FieldDesc field = newFields[i];
            if (field.isElement()) {
                fieldNameMap.put(field.getFieldName(), field);
            } else {
                _hasAttributes = true;
            }
        }
    }

    /**
     * Add a new FieldDesc, keeping the convenience fields in sync.
     */
    public void addFieldDesc(FieldDesc field)
    {
        if (field == null) {
            throw new IllegalArgumentException(
                    JavaUtils.getMessage("nullFieldDesc"));
        }
       
        int numFields = 0;
        if (fields != null) {
            numFields = fields.length;
        }
        FieldDesc [] newFields = new FieldDesc[numFields + 1];
        if (fields != null) {
            System.arraycopy(fields, 0, newFields, 0, numFields);
        }
        newFields[numFields] = field;
        fields = newFields;
       
        // Keep track of the field by name for fast lookup
        fieldNameMap.put(field.getFieldName(), field);
       
        if (!_hasAttributes && !field.isElement())
            _hasAttributes = true;
    }

    /**
     * Get the QName associated with this field, but only if it's
     * marked as an element.
     */
    public QName getElementNameForField(String fieldName)
    {
        FieldDesc desc = (FieldDesc)fieldNameMap.get(fieldName);
        if (desc == null) {
            // check superclasses if they exist
            Class cls = javaClass.getSuperclass();
            if (cls != null && !cls.getName().startsWith("java.")) {
                TypeDesc superDesc = getTypeDescForClass(cls);
                if (superDesc != null) {
                    return superDesc.getElementNameForField(fieldName);
                }
            }
        } else if (!desc.isElement()) {
            return null;
        }
        return desc.getXmlName();
    }
   
    /**
     * Get the QName associated with this field, but only if it's
     * marked as an attribute.
     */
    public QName getAttributeNameForField(String fieldName)
    {
        FieldDesc desc = (FieldDesc)fieldNameMap.get(fieldName);
        if (desc == null) {
            // check superclasses if they exist
            Class cls = javaClass.getSuperclass();
            if (cls != null && !cls.getName().startsWith("java.")) {
                TypeDesc superDesc = getTypeDescForClass(cls);
                if (superDesc != null) {
                    return superDesc.getAttributeNameForField(fieldName);
                }
            }
        } else if (desc.isElement()) {
            return null;
        }
        QName ret = desc.getXmlName();
        if (ret == null) {
            ret = new QName("", fieldName);
        }
        return ret;
    }

    /**
     * Get the field name associated with this QName, but only if it's
     * marked as an element.
     *
     * If the "ignoreNS" argument is true, just compare localNames.
     */
    public String getFieldNameForElement(QName qname, boolean ignoreNS)
    {
        if (fields == null)
            return null;

        // have we already computed the answer to this question?
        if (fieldElementMap != null) {
            String cached = (String) fieldElementMap.get(qname);
            if (cached != null) return cached;
        }

        String result = null;

        String localPart = qname.getLocalPart();

        // check fields in this class
        for (int i = 0; i < fields.length; i++) {
            FieldDesc field = fields[i];
            if (field.isElement()) {
                QName xmlName = field.getXmlName();
                if (localPart.equals(xmlName.getLocalPart())) {
                    if (ignoreNS || qname.getNamespaceURI().
                                        equals(xmlName.getNamespaceURI())) {
                        result = field.getFieldName();
                    }
                }
            }
        }
       
        // check superclasses if they exist
        if (result == null) {
            Class cls = javaClass.getSuperclass();
            if (cls != null && !cls.getName().startsWith("java.")) {
                TypeDesc superDesc = getTypeDescForClass(cls);
                if (superDesc != null) {
                    result = superDesc.getFieldNameForElement(qname, ignoreNS);
                }
            }
        }

        // cache the answer away for quicker retrieval next time.
        if (result != null) {
            if (fieldElementMap == null) fieldElementMap = new HashMap();
            fieldElementMap.put(qname, result);
        }

        return result;
    }
   
    /**
     * Get the field name associated with this QName, but only if it's
     * marked as an attribute.
     */
    public String getFieldNameForAttribute(QName qname)
    {
        if (fields == null)
            return null;

        String possibleMatch = null;

        for (int i = 0; i < fields.length; i++) {
            FieldDesc field = fields[i];
            if (!field.isElement()) {
                // It's an attribute, so if we have a solid match, return
                // its name.
                if (qname.equals(field.getXmlName())) {
                    return field.getFieldName();
                }
                // Not a solid match, but it's still possible we might match
                // the default (i.e. QName("", fieldName))
                if (qname.getNamespaceURI().equals("") &&
                    qname.getLocalPart().equals(field.getFieldName())) {
                    possibleMatch = field.getFieldName();
                }
            }
        }
       
        if (possibleMatch == null) {
            // check superclasses if they exist
            Class cls = javaClass.getSuperclass();
            if (cls != null && !cls.getName().startsWith("java.")) {
                TypeDesc superDesc = getTypeDescForClass(cls);
                if (superDesc != null) {
                    possibleMatch = superDesc.getFieldNameForAttribute(qname);
                }
            }
        }
       
        return possibleMatch;
    }

    /**
     * Get a FieldDesc by field name.
     */
    public FieldDesc getFieldByName(String name)
    {
        FieldDesc ret = (FieldDesc)fieldNameMap.get(name);
        if (ret == null) {
            Class cls = javaClass.getSuperclass();
            if (cls != null && !cls.getName().startsWith("java.")) {
                TypeDesc superDesc = getTypeDescForClass(cls);
                if (superDesc != null) {
                    ret = superDesc.getFieldByName(name);
                }
            }
        }
        return ret;
    }

    /**
     * Do we have any FieldDescs marked as attributes?
     */
    public boolean hasAttributes() {
        return _hasAttributes;
    }

    public QName getXmlType() {
        return xmlType;
    }

    public void setXmlType(QName xmlType) {
        this.xmlType = xmlType;
    }

    /**
     * Get/Cache the property descriptors
     * @return PropertyDescriptor
     */
    public BeanPropertyDescriptor[] getPropertyDescriptors() {
        // Return the propertyDescriptors if already set.
        // If not set, use BeanUtils.getPd to get the property descriptions.
        //
        // Since javaClass is a generated class, there
        // may be a faster way to set the property descriptions than
        // using BeanUtils.getPd.  But for now calling getPd is sufficient.
        if (propertyDescriptors == null) {
            propertyDescriptors = BeanUtils.getPd(javaClass, this);
            if (!lookedForAny) {
                anyDesc = BeanUtils.getAnyContentPD(javaClass);
                lookedForAny = true;
            }
        }
        return propertyDescriptors;
    }

    public BeanPropertyDescriptor getAnyContentDescriptor() {
        if (!lookedForAny) {
            anyDesc = BeanUtils.getAnyContentPD(javaClass);
            lookedForAny = true;
        }
        return anyDesc;
    }

    /**
     * Get/Cache the property descriptor map
     * @return Map with key=propertyName, value=descriptor
     */
    public Map getPropertyDescriptorMap() {
        // Return map if already set.
        if (propertyMap != null) {
            return propertyMap;
        }

        // Make sure properties exist
        if (propertyDescriptors == null) {
            getPropertyDescriptors()
        }

        // Build the map
        propertyMap = new HashMap();
        for (int i = 0; i < propertyDescriptors.length; i++) {
            BeanPropertyDescriptor descriptor = propertyDescriptors[i];
            propertyMap.put(descriptor.getName(), descriptor);
        }
        return propertyMap;
    }
}
TOP

Related Classes of org.apache.axis.description.TypeDesc

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.