Package org.apache.cayenne.jpa.conf

Source Code of org.apache.cayenne.jpa.conf.EntityMapLoader

/*****************************************************************
*   Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you 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.cayenne.jpa.conf;

import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.persistence.spi.PersistenceUnitInfo;

import org.apache.cayenne.jpa.JpaProviderException;
import org.apache.cayenne.jpa.map.JpaClassDescriptor;
import org.apache.cayenne.jpa.map.JpaEntityMap;

/**
* Loads JPA mapping information from all sources per JPA specification.
* <h3>Specification Documentation, Chapter 6.2.1.6</h3>
* <p>
* The set of managed persistence classes that are managed by a persistence unit is
* defined by using one or more of the following:
* <ul>
* <li>One or more object/relational mapping XML files
* <li>One or more jar files that will be searched for classes
* <li>An explicit list of the classes
* <li>The annotated managed persistence classes contained in the root of the persistence
* unit (unless the exclude-unlisted-classes element is specified) [Java SE doesn't have
* to support that].
* </ul>
* <p>
* The result is undefined if multiple mapping files (including any orm.xml file)
* referenced within a single persistence unit contain overlapping mapping information for
* any given class.
* </p>
* <p>
* The resulting set of entities managed by the persistence unit [and contained in the
* returned entity map] is the union of these sources, with the mapping metadata
* annotations (or annotation defaults) for any given class being overridden by the XML
* mapping information file if there are both annotations as well as XML mappings for that
* class. The minimum portable level of overriding is at the level of the persistent field
* or property.
* </p>
*
* @author Andrus Adamchik
*/
public class EntityMapLoader {

    static final String DESCRIPTOR_LOCATION = "META-INF/orm.xml";

    protected EntityMapLoaderContext context;
    protected Map<String, JpaClassDescriptor> descriptors;

    /**
     * Creates an EntityMapLoader for the persistence unit, merging entity information
     * from all locations supported by the JPA specification.
     */
    public EntityMapLoader(PersistenceUnitInfo persistenceUnit) {
        loadEntityMap(persistenceUnit);
    }

    /**
     * Returns an entity map with entity
     */
    public JpaEntityMap getEntityMap() {
        return context.getEntityMap();
    }

    /**
     * Loads a combined entity map including managed class descriptors from all supported
     * locations.
     */
    protected void loadEntityMap(PersistenceUnitInfo persistenceUnit)
            throws JpaProviderException {

        this.context = new EntityMapLoaderContext(persistenceUnit);

        try {
            loadFromAnnotations(persistenceUnit);
            updateFromXML(persistenceUnit);
            updateFromDefaults();
        }
        catch (JpaProviderException e) {
            throw e;
        }
        catch (Exception e) {
            throw new JpaProviderException("Error loading ORM descriptors", e);
        }
    }

    /**
     * Updates missing values with spec-compilant defaults.
     */
    protected void updateFromDefaults() {
        new EntityMapDefaultsProcessor().applyDefaults(context);
    }

    /**
     * Updates mapping with data loaded from XML. JPA specification gives some leeway in
     * processing conflicting mapping files. Cayenne provider strategy is "last mapping
     * file overrides all".
     * <h3>Specification Documentation, Chapter 6.2.1.6</h3>
     * <p>
     * An <em>orm.xml</em> file may be specified in the META-INF directory in the root
     * of the persistence unit or in the META-INF directory of any jar file referenced by
     * the persistence.xml. Alternatively, or in addition, other mapping files maybe
     * referenced by the mapping-file elements of the persistence-unit element, and may be
     * present anywhere on the classpath. An orm.xml file or other mapping file is loaded
     * as a resource by the persistence provider.
     */
    protected void updateFromXML(PersistenceUnitInfo unit) throws IOException {

        EntityMapMergeProcessor merger = new EntityMapMergeProcessor(context);

        Set loadedLocations = new HashSet();
        EntityMapXMLLoader loader = new EntityMapXMLLoader(
                context.getTempClassLoader(),
                false);

        // 1. load from the standard file called orm.xml
        loadedLocations.add(DESCRIPTOR_LOCATION);
        Enumeration<URL> standardDescriptors = context.getTempClassLoader().getResources(
                DESCRIPTOR_LOCATION);

        while (standardDescriptors.hasMoreElements()) {
            JpaEntityMap map = loader.getEntityMap(standardDescriptors.nextElement());
            merger.mergeOverride(map);
        }

        // 2. load from orm.xml within the jars
        // TODO: andrus, 4/20/2006 - load from the jar files

        // 3. load from explicitly specified descriptors
        for (String descriptor : unit.getMappingFileNames()) {

            // avoid loading duplicates, such as META-INF/orm.xml that is also explicitly
            // mentioned in the unit...
            if (loadedLocations.add(descriptor)) {

                Enumeration<URL> mappedDescriptors = context
                        .getTempClassLoader()
                        .getResources(descriptor);
                while (mappedDescriptors.hasMoreElements()) {
                    JpaEntityMap map = loader.getEntityMap(mappedDescriptors
                            .nextElement());
                    merger.mergeOverride(map);
                }
            }
        }
    }

    /**
     * Loads JpaEntityMap based on metadata annotations of persistent classes.
     */
    protected void loadFromAnnotations(PersistenceUnitInfo persistenceUnit) {

        if (!persistenceUnit.getManagedClassNames().isEmpty()) {

            // must use Unit class loader to prevent loading an un-enahnced class in the
            // app ClassLoader.
            ClassLoader loader = context.getTempClassLoader();
            EntityMapAnnotationLoader annotationLoader = new EntityMapAnnotationLoader(
                    context);

            for (String className : persistenceUnit.getManagedClassNames()) {

                Class managedClass;
                try {
                    managedClass = Class.forName(className, true, loader);
                }
                catch (ClassNotFoundException e) {
                    throw new JpaProviderException("Class not found: " + className, e);
                }

                annotationLoader.loadClassMapping(managedClass);
            }
        }
    }

    public EntityMapLoaderContext getContext() {
        return context;
    }
}
TOP

Related Classes of org.apache.cayenne.jpa.conf.EntityMapLoader

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.