Package org.datanucleus.api.jpa.metadata

Source Code of org.datanucleus.api.jpa.metadata.JPAMetaDataManager

/**********************************************************************
Copyright (c) 2006 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.api.jpa.metadata;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.PostLoad;
import javax.persistence.PostPersist;
import javax.persistence.PostRemove;
import javax.persistence.PostUpdate;
import javax.persistence.PrePersist;
import javax.persistence.PreRemove;
import javax.persistence.PreUpdate;

import org.datanucleus.ClassLoaderResolver;
import org.datanucleus.NucleusContext;
import org.datanucleus.metadata.AbstractClassMetaData;
import org.datanucleus.metadata.ClassMetaData;
import org.datanucleus.metadata.DiscriminatorMetaData;
import org.datanucleus.metadata.DiscriminatorStrategy;
import org.datanucleus.metadata.EventListenerMetaData;
import org.datanucleus.metadata.FileMetaData;
import org.datanucleus.metadata.MetaDataManager;
import org.datanucleus.metadata.MetadataFileType;
import org.datanucleus.metadata.PackageMetaData;
import org.datanucleus.metadata.xml.MetaDataParser;
import org.datanucleus.util.NucleusLogger;

/**
* Manager of JPA MetaData information in DataNucleus.
* Manages the MetaData for a particular "persistence-unit".
*/
public class JPAMetaDataManager extends MetaDataManager
{
    /** EventListeners. Use a list to preserve ordering. */
    protected List eventListeners = new ArrayList();

    /**
     * Constructor.
     * @param ctxt ObjectManagerFactory Context that this metadata manager operates in
     */
    public JPAMetaDataManager(NucleusContext ctxt)
    {
        super(ctxt);

        // log the configuration
        if (NucleusLogger.METADATA.isDebugEnabled())
        {
            NucleusLogger.METADATA.debug(
                "MetaDataManager : Input=(XML, Annotations), XML-Validation=" + validateMetaData);
        }
    }

    /**
     * Get the event listeners
     * @return the event listeners
     */
    public List getEventListeners()
    {
        return eventListeners;
    }

    /**
     * Utility to parse a file, using the "jpa" MetaData handler.
     * @param fileURL URL of the file
     * @return The FileMetaData for this file
     */
    protected FileMetaData parseFile(URL fileURL)
    {
        if (metaDataParser == null)
        {
            metaDataParser = new MetaDataParser(this, validateMetaData);
        }
        return (FileMetaData)metaDataParser.parseMetaDataURL(fileURL, "jpa");
    }

    /**
     * Method that will perform any necessary post-processing on metadata.
     * In the case of JPA we need to populate all event listener methods against the listener.
     * @param cmd Metadata for the class
     * @param clr ClassLoader resolver
     */
    protected void postProcessClassMetaData(AbstractClassMetaData cmd, ClassLoaderResolver clr)
    {
        if (cmd.getListeners() != null)
        {
            List classListeners = cmd.getListeners();

            for (int k=0; k<classListeners.size(); k++)
            {
                EventListenerMetaData elmd = (EventListenerMetaData) classListeners.get(k);

                // Load up all listener methods of the listener
                // If the metadata had defined some methods then the annotated method definition will be ignored
                populateListenerMethodsForEventListener(elmd, clr);
            }
        }
    }

    /**
     * Method to take the FileMetaData and register the relevant parts of it with the various
     * convenience collections/maps that we use for access.
     * @param fileURLString URL of the metadata file
     * @param filemd The File MetaData
     */
    @SuppressWarnings("unchecked")
    public void registerFile(String fileURLString, FileMetaData filemd, ClassLoaderResolver clr)
    {
        if (fileURLString == null)
        {
            // Null file
            return;
        }
        if (fileMetaDataByURLString.get(fileURLString) != null)
        {
            // Already registered!
            return;
        }

        fileMetaDataByURLString.put(fileURLString, filemd);

        registerQueriesForFile(filemd);
        registerSequencesForFile(filemd);
        registerTableGeneratorsForFile(filemd);
        registerQueryResultMetaDataForFile(filemd);

        if (filemd.getListeners() != null)
        {
            List fileListeners = filemd.getListeners();
            eventListeners.addAll(fileListeners);
            for (int i=0; i<fileListeners.size(); i++)
            {
                EventListenerMetaData elmd = (EventListenerMetaData) fileListeners.get(i);

                // Load up all listener methods of the listener
                // If the metadata had defined some methods then the annotated method definition will be ignored
                populateListenerMethodsForEventListener(elmd, clr);
            }
        }

        // Register the classes and interfaces for later use
        if (filemd.getType() == MetadataFileType.JPA_MAPPING_FILE ||
            filemd.getType() == MetadataFileType.ANNOTATIONS)
        {
            for (int i = 0; i < filemd.getNoOfPackages(); i++)
            {
                PackageMetaData pmd = filemd.getPackage(i);

                // Register all classes into the respective lookup maps
                for (int j = 0; j < pmd.getNoOfClasses(); j++)
                {
                    ClassMetaData cmd = pmd.getClass(j);
                    if (classesWithoutPersistenceInfo.contains(cmd.getFullClassName()))
                    {
                        // Remove from unknown classes now that we have some metadata
                        classesWithoutPersistenceInfo.remove(cmd.getFullClassName());
                    }
                    if (cmd.getEntityName() != null)
                    {
                        // Register the metadata under the entity name
                        classMetaDataByEntityName.put(cmd.getEntityName(), cmd);
                    }
                    if (cmd.getInheritanceMetaData() != null)
                    {
                        // Register the metadata under the discriminator name
                        DiscriminatorMetaData dismd = cmd.getInheritanceMetaData().getDiscriminatorMetaData();
                        if (dismd != null)
                        {
                            if (dismd.getStrategy() == DiscriminatorStrategy.CLASS_NAME)
                            {
                                classMetaDataByDiscriminatorName.put(cmd.getFullClassName(), cmd);
                            }
                            else if (dismd.getStrategy() == DiscriminatorStrategy.VALUE_MAP)
                            {
                                classMetaDataByDiscriminatorName.put(dismd.getValue(), cmd);
                            }
                        }
                    }
                    registerMetaDataForClass(cmd.getFullClassName(), cmd);

                    postProcessClassMetaData(cmd, clr);
                }
            }
        }
    }

    /**
     * Method to populate the methods of the listener class into the EventListenerMetaData.
     * Checks the annotations of the listener class itself and adds them in to the definition that
     * the EventListener uses.
     * @param elmd EventListenerMetaData (updated by this method)
     * @param clr ClassLoader resolver
     */
    private void populateListenerMethodsForEventListener(EventListenerMetaData elmd, ClassLoaderResolver clr)
    {
        Class listenerClass = clr.classForName(elmd.getClassName());
        populateListenerMethodsForClassInEventListener(elmd, listenerClass, clr);
    }

    /**
     * Convenience method to process the specified class for listener callback methods adding them to
     * the EventListener. Proceeds up to the superclass if there is one.
     * @param elmd EventListenerMetaData to add the methods to.
     * @param cls The class to process for callback-annotated methods
     * @param clr ClassLoader resolver
     */
    private void populateListenerMethodsForClassInEventListener(EventListenerMetaData elmd, Class cls,
        ClassLoaderResolver clr)
    {
        Method[] methods = cls.getDeclaredMethods();
        if (methods != null)
        {
            for (int i=0;i<methods.length;i++)
            {
                Annotation[] methodAnnots = methods[i].getAnnotations();
                if (methodAnnots != null)
                {
                    for (int j=0;j<methodAnnots.length;j++)
                    {
                        if (methodAnnots[j].annotationType() == PrePersist.class ||
                            methodAnnots[j].annotationType() == PostPersist.class ||
                            methodAnnots[j].annotationType() == PreRemove.class ||
                            methodAnnots[j].annotationType() == PostRemove.class ||
                            methodAnnots[j].annotationType() == PreUpdate.class ||
                            methodAnnots[j].annotationType() == PostUpdate.class ||
                            methodAnnots[j].annotationType() == PostLoad.class)
                        {
                            elmd.addCallback(methodAnnots[j].annotationType().getName(),
                                methods[i].getDeclaringClass().getName(), methods[i].getName());
                        }
                    }
                }
            }
        }

        // Go up to superclass if there is one
        if (cls.getSuperclass() == null || cls.getSuperclass() == Object.class)
        {
            return;
        }
        populateListenerMethodsForClassInEventListener(elmd, cls.getSuperclass(), clr);
    }

    /**
     * Accessor for the JPA MetaData for a class.
     * With JPA we either register the classes in "persistence.xml" (via "class", "jar-file"
     * or "mapping-file") or we have them annotated. If they havent been loaded when we
     * loaded "persistence.xml" then we only check for annotations in that class.
     * @param c The class to find MetaData for
     * @return The ClassMetaData for this class (or null if not found)
     **/
    @SuppressWarnings("unchecked")
    public synchronized AbstractClassMetaData getMetaDataForClassInternal(Class c, ClassLoaderResolver clr)
    {
        if (c.isArray())
        {
            // Only particular classes can have metadata
            return null;
        }

        // If we know that this class/interface has no MetaData/annotations don't bother searching
        if (isClassWithoutPersistenceInfo(c.getName()))
        {
            return null;
        }

        // Check for MetaData loaded when we loaded the "persistence-unit"
        AbstractClassMetaData acmd = (AbstractClassMetaData)classMetaDataByClass.get(c.getName());
        if (acmd != null)
        {
            return acmd;
        }

        if (!allowMetaDataLoad)
        {
            // Not allowing further metadata load so just return
            return null;
        }

        // No MetaData so check for annotations
        FileMetaData annFilemd = loadAnnotationsForClass(c, clr, true, true);
        if (annFilemd != null)
        {
            // No MetaData but annotations present so use that
            return annFilemd.getPackage(0).getClass(0);
        }

        // Not found, so add to known classes/interfaces without MetaData
        if (NucleusLogger.METADATA.isDebugEnabled())
        {
            NucleusLogger.METADATA.debug(LOCALISER.msg("044043", c.getName()));
        }
        classesWithoutPersistenceInfo.add(c.getName());

        return null;
    }
}
TOP

Related Classes of org.datanucleus.api.jpa.metadata.JPAMetaDataManager

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.