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

org.datanucleus.metadata.MetaDataUtils Maven / Gradle / Ivy

Go to download

DataNucleus Core provides the primary components of a heterogenous Java persistence solution. It supports persistence API's being layered on top of the core functionality. Also includes the JDO API.

There is a newer version: 5.2.0-release
Show newest version
/**********************************************************************
Copyright (c) 2004 Andy Jefferson and others. All rights reserved.
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.
 

Contributors:
    ...
**********************************************************************/
package org.datanucleus.metadata;

import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.ClassNameConstants;
import org.datanucleus.ExecutionContext;
import org.datanucleus.exceptions.NucleusException;
import org.datanucleus.exceptions.NucleusUserException;
import org.datanucleus.metadata.xml.MetaDataParser;
import org.datanucleus.plugin.PluginManager;
import org.datanucleus.util.ClassUtils;
import org.datanucleus.util.Localiser;
import org.datanucleus.util.NucleusLogger;
import org.datanucleus.util.StringUtils;

/**
 * Utilities needed for the processing of MetaData.
 */
public class MetaDataUtils
{
    private static MetaDataUtils instance;

    /**
     * Gets an instance of MetaDataUtils
     * @return a singleton instance of MetaDataUtils
     */
    public static synchronized MetaDataUtils getInstance()
    {
        if (instance == null)
        {
            instance = new MetaDataUtils();
        }
        return instance;
    }

    /**
     * Protected constructor to prevent outside instantiation
     */
    protected MetaDataUtils()
    {
    }

    /**
     * Convenience method to determine if an array is storable in a single column as a byte
     * array.
     * @param fmd The field
     * @return Whether this is an array that can be stored in a single column as non-serialised
     */
    public boolean arrayStorableAsByteArrayInSingleColumn(AbstractMemberMetaData fmd)
    {
        if (fmd == null || !fmd.hasArray())
        {
            return false;
        }

        String arrayComponentType = fmd.getType().getComponentType().getName();
        if (arrayComponentType.equals(ClassNameConstants.BOOLEAN) ||
            arrayComponentType.equals(ClassNameConstants.BYTE) ||
            arrayComponentType.equals(ClassNameConstants.CHAR) ||
            arrayComponentType.equals(ClassNameConstants.DOUBLE) ||
            arrayComponentType.equals(ClassNameConstants.FLOAT) ||
            arrayComponentType.equals(ClassNameConstants.INT) ||
            arrayComponentType.equals(ClassNameConstants.LONG) ||
            arrayComponentType.equals(ClassNameConstants.SHORT) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_LANG_BOOLEAN) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_LANG_BYTE) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_LANG_CHARACTER) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_LANG_DOUBLE) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_LANG_FLOAT) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_LANG_INTEGER) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_LANG_LONG) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_LANG_SHORT) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_MATH_BIGDECIMAL) ||
            arrayComponentType.equals(ClassNameConstants.JAVA_MATH_BIGINTEGER))
        {
            // These types can be stored as a single-column but setting the bytes only
            return true;
        }

        // All other arrays must be serialised into a single column
        return false;
    }

    /**
     * Convenience method that returns if a field stores a persistable object.
     * Doesn't care if the persistable object is serialised or embedded, just that it is persistable.
     * @param fmd MetaData for the field
     * @param ec ExecutionContext
     * @return Whether it stores a persistable object
     */
    public boolean storesPersistable(AbstractMemberMetaData fmd, ExecutionContext ec)
    {
        if (fmd == null)
        {
            return false;
        }

        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        MetaDataManager mmgr = ec.getMetaDataManager();
        if (fmd.hasCollection())
        {
            if (fmd.getCollection().elementIsPersistent())
            {
                // Collection of PC elements
                return true;
            }

            String elementType = fmd.getCollection().getElementType();
            Class elementCls = clr.classForName(elementType);
            if (mmgr.getMetaDataForImplementationOfReference(elementCls, null, clr) != null)
            {
                // Collection of reference type for FCOs
                return true;
            }
            if (elementCls != null && ClassUtils.isReferenceType(elementCls))
            {
                try
                {
                    String[] impls = getImplementationNamesForReferenceField(fmd, FieldRole.ROLE_COLLECTION_ELEMENT, clr, mmgr);
                    if (impls != null)
                    {
                        elementCls = clr.classForName(impls[0]);
                        if (ec.getApiAdapter().isPersistable(elementCls))
                        {
                            // Collection of reference type for FCOs
                            return true;
                        }
                    }
                }
                catch (NucleusUserException nue)
                {
                    // No implementations found so not persistable
                }
            }
        }
        else if (fmd.hasMap())
        {
            if (fmd.getMap().keyIsPersistent())
            {
                // Map of PC keys
                return true;
            }

            String keyType = fmd.getMap().getKeyType();
            Class keyCls = clr.classForName(keyType);
            if (mmgr.getMetaDataForImplementationOfReference(keyCls, null, clr) != null)
            {
                // Map with keys of reference type for FCOs
                return true;
            }
            if (keyCls != null && ClassUtils.isReferenceType(keyCls))
            {
                try
                {
                    String[] impls = getImplementationNamesForReferenceField(fmd, FieldRole.ROLE_MAP_KEY, clr, mmgr);
                    if (impls != null)
                    {
                        keyCls = clr.classForName(impls[0]);
                        if (ec.getApiAdapter().isPersistable(keyCls))
                        {
                            // Map with keys of reference type for FCOs
                            return true;
                        }
                    }
                }
                catch (NucleusUserException nue)
                {
                    // No implementations found so not persistable
                }
            }

            if (fmd.getMap().valueIsPersistent())
            {
                // Map of PC values
                return true;
            }

            String valueType = fmd.getMap().getValueType();
            Class valueCls = clr.classForName(valueType);
            if (mmgr.getMetaDataForImplementationOfReference(valueCls, null, clr) != null)
            {
                // Map with values of reference type for FCOs
                return true;
            }
            if (valueCls != null && ClassUtils.isReferenceType(valueCls))
            {
                try
                {
                    String[] impls = getImplementationNamesForReferenceField(fmd, FieldRole.ROLE_MAP_VALUE, clr, mmgr);
                    if (impls != null)
                    {
                        valueCls = clr.classForName(impls[0]);
                        if (ec.getApiAdapter().isPersistable(valueCls))
                        {
                            // Map with values of reference type for FCOs
                            return true;
                        }
                    }
                }
                catch (NucleusUserException nue)
                {
                    // No implementations found so not persistable
                }
            }
        }
        else if (fmd.hasArray())
        {
            if (mmgr.getApiAdapter().isPersistable(fmd.getType().getComponentType()))
            {
                // persistable[]
                return true;
            }

            String elementType = fmd.getArray().getElementType();
            Class elementCls = clr.classForName(elementType);
            if (mmgr.getApiAdapter().isPersistable(elementCls))
            {
                // Array of reference type for FCOs
                return true;
            }
            else if (mmgr.getMetaDataForImplementationOfReference(elementCls, null, clr) != null)
            {
                // Array of reference type for FCOs
                return true;
            }
            else if (elementCls != null && ClassUtils.isReferenceType(elementCls))
            {
                try
                {
                    String[] impls = getImplementationNamesForReferenceField(fmd, FieldRole.ROLE_ARRAY_ELEMENT, clr, mmgr);
                    if (impls != null)
                    {
                        elementCls = clr.classForName(impls[0]);
                        if (ec.getApiAdapter().isPersistable(elementCls))
                        {
                            // Array of reference type for FCOs
                            return true;
                        }
                    }
                }
                catch (NucleusUserException nue)
                {
                    // No implementations found so not persistable
                }
            }
        }
        else
        {
            // 1-1 relation with PC
            if (ClassUtils.isReferenceType(fmd.getType()) &&
                mmgr.getMetaDataForImplementationOfReference(fmd.getType(), null, clr) != null)
            {
                // Reference type for an FCO
                return true;
            }
            if (mmgr.getMetaDataForClass(fmd.getType(), clr) != null)
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Convenience method that returns if a field stores a First-Class object (FCO).
     * If a field object is serialised/embedded then doesn't count the object as FCO - use
     * storesPersistable() if you want that not checking.
     * @param fmd MetaData for the field
     * @param ec ExecutionContext
     * @return Whether it stores a FCO
     */
    public boolean storesFCO(AbstractMemberMetaData fmd, ExecutionContext ec)
    {
        if (fmd == null)
        {
            return false;
        }

        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        MetaDataManager mgr = ec.getMetaDataManager();
        if (fmd.isSerialized() || fmd.isEmbedded())
        {
            // Serialised or embedded fields have no FCO
            return false;
        }
        else if (fmd.hasCollection() && !fmd.getCollection().isSerializedElement() && !fmd.getCollection().isEmbeddedElement())
        {
            if (fmd.getCollection().elementIsPersistent())
            {
                // Collection of PC elements
                return true;
            }

            String elementType = fmd.getCollection().getElementType();
            Class elementCls = clr.classForName(elementType);
            if (elementCls != null && ClassUtils.isReferenceType(elementCls) &&
                    mgr.getMetaDataForImplementationOfReference(elementCls, null, clr) != null)
            {
                // Collection of reference type for FCOs
                return true;
            }
        }
        else if (fmd.hasMap())
        {
            if (fmd.getMap().keyIsPersistent() && !fmd.getMap().isEmbeddedKey() && !fmd.getMap().isSerializedKey())
            {
                // Map of PC keys
                return true;
            }

            String keyType = fmd.getMap().getKeyType();
            Class keyCls = clr.classForName(keyType);
            if (keyCls != null && ClassUtils.isReferenceType(keyCls) &&
                    mgr.getMetaDataForImplementationOfReference(keyCls, null, clr) != null)
            {
                // Map with keys of reference type for FCOs
                return true;
            }
                
            if (fmd.getMap().valueIsPersistent() && !fmd.getMap().isEmbeddedValue() && !fmd.getMap().isSerializedValue())
            {
                // Map of PC values
                return true;
            }

            String valueType = fmd.getMap().getValueType();
            Class valueCls = clr.classForName(valueType);
            if (valueCls != null && ClassUtils.isReferenceType(valueCls) &&
                    mgr.getMetaDataForImplementationOfReference(valueCls, null, clr) != null)
            {
                // Map with values of reference type for FCOs
                return true;
            }
        }
        else if (fmd.hasArray() && !fmd.getArray().isSerializedElement() && !fmd.getArray().isEmbeddedElement())
        {
            if (mgr.getApiAdapter().isPersistable(fmd.getType().getComponentType()))
            {
                // persistable[]
                return true;
            }
        }
        else
        {
            // 1-1 relation with PC
            if (ClassUtils.isReferenceType(fmd.getType()) &&
                mgr.getMetaDataForImplementationOfReference(fmd.getType(), null, clr) != null)
            {
                // Reference type for an FCO
                return true;
            }
            if (mgr.getMetaDataForClass(fmd.getType(), clr) != null)
            {
                return true;
            }
        }
        return false;
    }

    /**
     * Convenience method that splits a comma-separated list of values into a String array (removing whitespace).
     * @param attr The attribute value
     * @return The string components
     */
    public String[] getValuesForCommaSeparatedAttribute(String attr)
    {
        if (attr == null || attr.length() == 0)
        {
            return null;
        }

        String[] values=StringUtils.split(attr, ",");

        // Remove any whitespace around the values
        if (values != null)
        {
            for (int i=0;i definition to get some types
            String type = null;
            if (fmd.hasCollection() && fieldRole == FieldRole.ROLE_COLLECTION_ELEMENT)
            {
                type = fmd.getCollection().getElementType();
            }
            else if (fmd.hasMap() && fieldRole == FieldRole.ROLE_MAP_KEY)
            {
                type = fmd.getMap().getKeyType();
            }
            else if (fmd.hasMap() && fieldRole == FieldRole.ROLE_MAP_VALUE)
            {
                type = fmd.getMap().getValueType();
            }
            else if (fmd.hasArray() && fieldRole == FieldRole.ROLE_ARRAY_ELEMENT)
            {
                type = fmd.getArray().getElementType();
                if (type == null)
                {
                    type = fmd.getType().getComponentType().getName();
                }
            }
            else
            {
                type = fmd.getTypeName();
            }

            if (!type.equals(ClassNameConstants.Object))
            {
                implTypes = mmgr.getClassesImplementingInterface(type,clr);
            }

            if (implTypes == null)
            {
                // Generate error since no implementations available
                throw new InvalidMemberMetaDataException("044161", fmd.getClassName(), fmd.getName(), type);
            }
        }

        // Remove all duplicates from the list but retain the original ordering
        int noOfDups = 0;
        for (int i=0;i getMetaDataForCandidates(Class cls, boolean subclasses, 
        ExecutionContext ec)
    {
        ClassLoaderResolver clr = ec.getClassLoaderResolver();
        List cmds = new ArrayList();
        if (cls.isInterface())
        {
            // Query of interface(+subclasses)
            AbstractClassMetaData icmd = ec.getMetaDataManager().getMetaDataForInterface(cls, clr);
            if (icmd == null)
            {
                throw new NucleusUserException("Attempting to query an interface yet it is not declared 'persistent'." +
                    " Define the interface in metadata as being persistent to perform this operation, and make sure" +
                " any implementations use the same identity and identity member(s)");
            }

            String[] impls = ec.getMetaDataManager().getClassesImplementingInterface(cls.getName(), clr);
            for (int i=0;i 0)
                    {
                        for (int j=0;j 0)
                {
                    for (int j=0;j metadataFiles = new HashSet();
            Set classNames = new HashSet();
            for (int i=0;i definition?
            embedded = true;
        }
        else if (RelationType.isRelationMultiValued(relationType))
        {
            // Is this an embedded element/key/value?
            if (mmd.hasCollection() && mmd.getElementMetaData() != null && mmd.getElementMetaData().getEmbeddedMetaData() != null)
            {
                // Embedded collection element
                embedded = true;
            }
            else if (mmd.hasArray() && mmd.getElementMetaData() != null && mmd.getElementMetaData().getEmbeddedMetaData() != null)
            {
                // Embedded array element
                embedded = true;
            }
            else if (mmd.hasMap() && 
                    ((mmd.getKeyMetaData() != null && mmd.getKeyMetaData().getEmbeddedMetaData() != null) || 
                    (mmd.getValueMetaData() != null && mmd.getValueMetaData().getEmbeddedMetaData() != null)))
            {
                // Embedded map key/value
                embedded = true;
            }
        }
        else
        {
            // Observe "embeddedOnly" of the persisted type
            if (RelationType.isRelationSingleValued(relationType))
            {
                AbstractClassMetaData mmdCmd = mmgr.getMetaDataForClass(mmd.getType(), clr);
                if (mmdCmd != null && mmdCmd.isEmbeddedOnly())
                {
                    embedded = true;
                }
            }
            else if (RelationType.isRelationMultiValued(relationType))
            {
                // TODO Check this too
            }
        }
        return embedded;
    }

    /**
     * Convenience method to return if the specified member is embedded.
     * Only applies to relation fields, since all other fields are always "embedded".
     * TODO Likely ought to change last arg to List<AbstractMemberMetaData> for multilevel of embedded
     * @param mmgr Metadata manager
     * @param clr ClassLoader resolver
     * @param mmd Metadata for the member we are interested in
     * @param relationType Relation type of the member we are interested in
     * @param ownerMmd Optional metadata for the owner member (for nested embeddeds only. Set to null if not relevant to the member in question).
     * @return Whether the member is embedded
     */
    public boolean isMemberEmbedded(MetaDataManager mmgr, ClassLoaderResolver clr, AbstractMemberMetaData mmd, RelationType relationType, AbstractMemberMetaData ownerMmd)
    {
        boolean embedded = false;
        if (relationType != RelationType.NONE)
        {
            // Determine if this relation field is embedded
            if (RelationType.isRelationSingleValued(relationType))
            {
                AbstractClassMetaData mmdCmd = mmgr.getMetaDataForClass(mmd.getType(), clr);
                if (mmdCmd != null && mmdCmd.isEmbeddedOnly())
                {
                    // Member type is embedded-only, so has to be embedded
                    return true;
                }
            }
            if (mmd.isEmbedded() || mmd.getEmbeddedMetaData() != null)
            {
                // Does this field have @Embedded definition?
                return true;
            }
            else if (RelationType.isRelationMultiValued(relationType))
            {
                // Is this an embedded element/key/value?
                if (mmd.hasCollection() && mmd.getElementMetaData() != null && mmd.getElementMetaData().getEmbeddedMetaData() != null)
                {
                    // Embedded collection element
                    return true;
                }
                else if (mmd.hasArray() && mmd.getElementMetaData() != null && mmd.getElementMetaData().getEmbeddedMetaData() != null)
                {
                    // Embedded array element
                    return true;
                }
                else if (mmd.hasMap() && 
                        ((mmd.getKeyMetaData() != null && mmd.getKeyMetaData().getEmbeddedMetaData() != null) || 
                        (mmd.getValueMetaData() != null && mmd.getValueMetaData().getEmbeddedMetaData() != null)))
                {
                    // Embedded map key/value
                    return true;
                }
            }

            if (RelationType.isRelationSingleValued(relationType) && ownerMmd != null)
            {
                // Maybe part of a nested embedded?
                if (ownerMmd.hasCollection())
                {
                    // This is a field of the element of the collection, so check for any metadata spec for it
                    EmbeddedMetaData embmd = ownerMmd.getElementMetaData().getEmbeddedMetaData();
                    if (embmd != null)
                    {
                        AbstractMemberMetaData[] embMmds = embmd.getMemberMetaData();
                        if (embMmds != null)
                        {
                            for (AbstractMemberMetaData embMmd : embMmds)
                            {
                                if (embMmd.getName().equals(mmd.getName()))
                                {
                                    if (embMmd.isEmbedded() || embMmd.getEmbeddedMetaData() != null)
                                    {
                                        // Embedded Field is marked in nested embedded definition as embedded
                                        return true;
                                    }
                                }
                            }
                        }
                    }
                }
                else if (ownerMmd.getEmbeddedMetaData() != null)
                {
                    // Is this a nested embedded (from JDO definition) with specification for this field?
                    AbstractMemberMetaData[] embMmds = ownerMmd.getEmbeddedMetaData().getMemberMetaData();
                    if (embMmds != null)
                    {
                        for (int i=0;i block?
                                return embMmds[i].getEmbeddedMetaData() != null;
                            }
                        }
                    }
                }
            }
        }

        return embedded;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy