org.apache.cayenne.map.MappingCache.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cayenne.map.MappingCache.java

Source

/*****************************************************************
 *   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.map;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.apache.cayenne.CayenneRuntimeException;
import org.apache.cayenne.ObjectId;
import org.apache.cayenne.Persistent;
import org.apache.commons.collections.collection.CompositeCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @since 4.0
 */
class MappingCache implements MappingNamespace {

    private static final ObjEntity OBJ_DUPLICATE_MARKER = new ObjEntity();

    protected static final Logger logger = LoggerFactory.getLogger(MappingCache.class);

    protected Collection<DataMap> maps;
    protected Map<String, QueryDescriptor> queryDesriptors;
    protected Map<String, Embeddable> embeddables;
    protected Map<String, SQLResult> results;
    protected Map<String, DbEntity> dbEntities;
    protected Map<String, ObjEntity> objEntities;
    protected Map<String, ObjEntity> objEntitiesByClassName;
    protected Map<String, Procedure> procedures;
    protected Map<String, EntityInheritanceTree> entityInheritanceCache;

    MappingCache(Collection<DataMap> maps) {

        this.maps = maps;

        this.embeddables = new HashMap<>();
        this.queryDesriptors = new HashMap<>();
        this.dbEntities = new HashMap<>();
        this.objEntities = new HashMap<>();
        this.objEntitiesByClassName = new HashMap<>();
        this.procedures = new HashMap<>();
        this.entityInheritanceCache = new HashMap<>();
        this.results = new HashMap<>();

        index();
    }

    private void index() {

        // index DbEntities separately and before ObjEntities to avoid infinite
        // loops when looking up DbEntities during ObjEntity index op
        for (DataMap map : maps) {
            dbEntities.putAll(map.getDbEntityMap());
        }

        for (DataMap map : maps) {
            // index ObjEntities by name
            objEntities.putAll(map.getObjEntityMap());

            // index ObjEntities by class name
            for (ObjEntity oe : map.getObjEntities()) {
                // use class name as a key to avoid class loading here...
                String className = oe.getJavaClassName();
                if (className == null) {
                    continue;
                }

                // allow duplicates, but put a special marker indicating
                // that this entity can't be looked up by class
                Object existing = objEntitiesByClassName.get(className);
                if (existing != null && existing != OBJ_DUPLICATE_MARKER) {
                    objEntitiesByClassName.put(className, OBJ_DUPLICATE_MARKER);
                } else {
                    objEntitiesByClassName.put(className, oe);
                }
            }

            // index stored procedures
            procedures.putAll(map.getProcedureMap());

            // index embeddables
            embeddables.putAll(map.getEmbeddableMap());

            // index query descriptors
            queryDesriptors.putAll(map.getQueryDescriptorMap());
        }

        // restart the map iterator to index inheritance
        for (DataMap map : maps) {

            // index ObjEntity inheritance
            for (ObjEntity oe : map.getObjEntities()) {

                // build inheritance tree
                EntityInheritanceTree node = entityInheritanceCache.get(oe.getName());
                if (node == null) {
                    node = new EntityInheritanceTree(oe);
                    entityInheritanceCache.put(oe.getName(), node);
                }

                String superOEName = oe.getSuperEntityName();
                if (superOEName != null) {
                    EntityInheritanceTree superNode = entityInheritanceCache.get(superOEName);

                    if (superNode == null) {
                        // do direct entity lookup to avoid recursive cache
                        // rebuild
                        ObjEntity superOE = objEntities.get(superOEName);
                        if (superOE != null) {
                            superNode = new EntityInheritanceTree(superOE);
                            entityInheritanceCache.put(superOEName, superNode);
                        } else {
                            // bad mapping? Or most likely some classloader
                            // issue
                            logger.warn("No super entity mapping for '" + superOEName + "'");
                            continue;
                        }
                    }

                    superNode.addChildNode(node);
                }
            }
        }
    }

    public Embeddable getEmbeddable(String className) {
        return embeddables.get(className);
    }

    public SQLResult getResult(String name) {
        return results.get(name);
    }

    public EntityInheritanceTree getInheritanceTree(String entityName) {
        return entityInheritanceCache.get(entityName);
    }

    public Procedure getProcedure(String procedureName) {
        return procedures.get(procedureName);
    }

    public QueryDescriptor getQueryDescriptor(String queryName) {
        return queryDesriptors.get(queryName);
    }

    public DbEntity getDbEntity(String name) {
        return dbEntities.get(name);
    }

    public ObjEntity getObjEntity(Class<?> entityClass) {
        ObjEntity entity = objEntitiesByClassName.get(entityClass.getName());

        if (entity == OBJ_DUPLICATE_MARKER) {
            throw new CayenneRuntimeException("Can't perform lookup. There is more than one ObjEntity mapped to %s",
                    entityClass.getName());
        }

        return entity;
    }

    public ObjEntity getObjEntity(Persistent object) {
        ObjectId id = object.getObjectId();
        if (id != null) {
            return getObjEntity(id.getEntityName());
        } else {
            return getObjEntity(object.getClass());
        }
    }

    public ObjEntity getObjEntity(String name) {
        return objEntities.get(name);
    }

    public Collection<DbEntity> getDbEntities() {
        // TODO: LEGACY SUPPORT:
        // some downstream code (like Modeler and merge framework) expect
        // always fresh list here, so instead of doing the right thing of
        // refreshing the cache and returning cache.entries(), we are scanning
        // the list of DataMaps.

        if (maps.size() == 0) {
            return Collections.emptyList();
        }

        if (maps.size() == 1) {
            return maps.iterator().next().getDbEntities();
        }

        CompositeCollection c = new CompositeCollection();
        for (DataMap map : maps) {
            c.addComposited(map.getDbEntities());
        }

        return c;
    }

    public Collection<Procedure> getProcedures() {
        // TODO: LEGACY SUPPORT:
        // some downstream code (like Modeler and merge framework) expect
        // always fresh list here, so instead of doing the right thing of
        // refreshing the cache and returning cache.entries(), we are scanning
        // the list of DataMaps.
        if (maps.size() == 0) {
            return Collections.emptyList();
        }

        if (maps.size() == 1) {
            return maps.iterator().next().getProcedures();
        }

        CompositeCollection c = new CompositeCollection();
        for (DataMap map : maps) {
            c.addComposited(map.getProcedures());
        }

        return c;
    }

    public Collection<QueryDescriptor> getQueryDescriptors() {
        // TODO: LEGACY SUPPORT:
        // some downstream code (like Modeler and merge framework) expect
        // always fresh list here, so instead of doing the right thing of
        // refreshing the cache and returning cache.entries(), we are scanning
        // the list of DataMaps.
        if (maps.size() == 0) {
            return Collections.emptyList();
        }

        if (maps.size() == 1) {
            return maps.iterator().next().getQueryDescriptors();
        }

        CompositeCollection c = new CompositeCollection();
        for (DataMap map : maps) {
            c.addComposited(map.getQueryDescriptors());
        }

        return c;
    }

    public Collection<ObjEntity> getObjEntities() {
        // TODO: LEGACY SUPPORT:
        // some downstream code (like Modeler and merge framework) expect
        // always fresh list here, so instead of doing the right thing of
        // refreshing the cache and returning cache.entries(), we are scanning
        // the list of DataMaps.
        if (maps.size() == 0) {
            return Collections.emptyList();
        }

        if (maps.size() == 1) {
            return maps.iterator().next().getObjEntities();
        }

        CompositeCollection c = new CompositeCollection();
        for (DataMap map : maps) {
            c.addComposited(map.getObjEntities());
        }

        return c;
    }

    public Collection<Embeddable> getEmbeddables() {
        // TODO: LEGACY SUPPORT:
        // some downstream code (like Modeler and merge framework) expect
        // always fresh list here, so instead of doing the right thing of
        // refreshing the cache and returning cache.entries(), we are scanning
        // the list of DataMaps.
        if (maps.size() == 0) {
            return Collections.emptyList();
        }

        if (maps.size() == 1) {
            return maps.iterator().next().getEmbeddables();
        }

        CompositeCollection c = new CompositeCollection();
        for (DataMap map : maps) {
            c.addComposited(map.getEmbeddables());
        }

        return c;
    }

    public Collection<SQLResult> getResults() {
        // TODO: LEGACY SUPPORT:
        // some downstream code (like Modeler and merge framework) expect
        // always fresh list here, so instead of doing the right thing of
        // refreshing the cache and returning cache.entries(), we are scanning
        // the list of DataMaps.

        if (maps.size() == 0) {
            return Collections.emptyList();
        }

        if (maps.size() == 1) {
            return maps.iterator().next().getResults();
        }

        CompositeCollection c = new CompositeCollection();
        for (DataMap map : maps) {
            c.addComposited(map.getResults());
        }

        return c;
    }
}