Package org.jpox.jpa.metadata

Source Code of org.jpox.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.jpox.jpa.metadata;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URL;
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.jpox.ClassLoaderResolver;
import org.jpox.OMFContext;
import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.ClassMetaData;
import org.jpox.metadata.EventListenerMetaData;
import org.jpox.metadata.FileMetaData;
import org.jpox.metadata.MetaDataManager;
import org.jpox.metadata.PackageMetaData;
import org.jpox.metadata.SequenceMetaData;
import org.jpox.metadata.TableGeneratorMetaData;
import org.jpox.metadata.xml.MetaDataParser;
import org.jpox.util.JPOXLogger;

/**
* Manager of JPA MetaData information in JPOX.
* Manages the MetaData for a particular "persistence-unit".
*
* @version $Revision: 1.1 $
*/
public class JPAMetaDataManager extends MetaDataManager
{
    /**
     * Constructor.
     * @param ctxt ObjectManagerFactory Context that this metadata manager operates in
     */
    public JPAMetaDataManager(OMFContext ctxt)
    {
        super(ctxt);

        // log the configuration
        if (JPOXLogger.METADATA.isDebugEnabled())
        {
            logConfiguration();
        }
    }

    /**
     * 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 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();
            listeners.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() == FileMetaData.JPA_FILE ||
            filemd.getType() == FileMetaData.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 (cmd.getEntityName() != null)
                    {
                        // Register the ClassMetaData for the implementation
                        classMetaDataByEntityName.put(cmd.getEntityName(), cmd);
                    }
                    registerMetaDataForClass(cmd.getFullClassName(), cmd);

                    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 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);
    }

    /**
     * Convenience method to register all sequences found in the passed file.
     * @param filemd MetaData for the file
     */
    @SuppressWarnings("unchecked")
    protected void registerSequencesForFile(FileMetaData filemd)
    {
        // Register all sequences for the packages in this file
        for (int i=0;i<filemd.getNoOfPackages();i++)
        {
            PackageMetaData pmd = filemd.getPackage(i);
            SequenceMetaData[] seqmds = pmd.getSequences();
            if (seqmds != null)
            {
                for (int j=0;j<seqmds.length;j++)
                {
                    // Register using its basic sequence name
                    sequenceMetaDataByPackageSequence.put(seqmds[j].getName(), seqmds[j]);
                }
            }
        }
    }

    /**
     * Convenience method to register all table generators found in the passed file.
     * @param filemd MetaData for the file
     */
    @SuppressWarnings("unchecked")
    protected void registerTableGeneratorsForFile(FileMetaData filemd)
    {
        // Register all table generators for the packages in this file
        for (int i=0;i<filemd.getNoOfPackages();i++)
        {
            PackageMetaData pmd = filemd.getPackage(i);
            TableGeneratorMetaData[] tgmds = pmd.getTableGenerators();
            if (tgmds != null)
            {
                for (int j=0;j<tgmds.length;j++)
                {
                    // Register using its basic sequence name
                    tableGeneratorMetaDataByPackageSequence.put(tgmds[j].getName(), tgmds[j]);
                }
            }
        }
    }

    /**
     * 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 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;
        }

        // 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 (JPOXLogger.METADATA.isDebugEnabled())
        {
            JPOXLogger.METADATA.debug(LOCALISER.msg("044043", c.getName()));
        }
        classesWithoutPersistenceInfo.add(c.getName());

        return null;
    }
}
TOP

Related Classes of org.jpox.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.