org.compass.gps.device.jpa.entities.DefaultJpaEntitiesLocator.java Source code

Java tutorial

Introduction

Here is the source code for org.compass.gps.device.jpa.entities.DefaultJpaEntitiesLocator.java

Source

/*
 * Copyright 2004-2009 the original author or authors.
 *
 * 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.
 */

package org.compass.gps.device.jpa.entities;

import java.util.ArrayList;
import javax.persistence.Entity;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Inheritance;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.compass.core.mapping.ResourceMapping;
import org.compass.core.mapping.osem.ClassMapping;
import org.compass.core.spi.InternalCompass;
import org.compass.core.util.ClassUtils;
import org.compass.core.util.StringUtils;
import org.compass.gps.device.jpa.JpaGpsDevice;
import org.compass.gps.device.jpa.JpaGpsDeviceException;
import org.compass.gps.spi.CompassGpsInterfaceDevice;

/**
 * The default {@link org.compass.gps.device.jpa.entities.JpaEntitiesLocator} implementations. Should work with all different
 * JPA implementations, with the only caveat that it is based on Annotations only. So, any
 * applications that uses a combination of both annotations and xml definitions (or any other
 * type), will probably loose some information during the index process (providing that the
 * xml definitions are ones that collide with Compass definitions). Please check if a
 * JPA actual implementation is provided with compass in such cases, and if not, writing
 * one should be simple (and should probably use the actual JPA implementation APIs).
 *
 * @author kimchy
 */
public class DefaultJpaEntitiesLocator implements JpaEntitiesLocator {

    protected Log log = LogFactory.getLog(getClass());

    public EntityInformation[] locate(EntityManagerFactory entityManagerFactory, JpaGpsDevice device)
            throws JpaGpsDeviceException {
        CompassGpsInterfaceDevice gps = (CompassGpsInterfaceDevice) device.getGps();
        final ResourceMapping[] resourceMappings = ((InternalCompass) gps.getIndexCompass()).getMapping()
                .getRootMappings();

        ArrayList<EntityInformation> entitiesList = new ArrayList<EntityInformation>(resourceMappings.length);
        for (ResourceMapping resourceMapping : resourceMappings) {
            if (!(resourceMapping instanceof ClassMapping)) {
                continue;
            }
            ClassMapping classMapping = (ClassMapping) resourceMapping;
            if (!classMapping.isRoot()) {
                continue;
            }
            EntityInformation entityInformation = createEntityInformation(classMapping.getClazz(), resourceMapping);
            if (entityInformation == null) {
                continue;
            }
            if (shouldFilter(entityInformation, device)) {
                continue;
            }
            entitiesList.add(entityInformation);
        }
        return entitiesList.toArray(new EntityInformation[entitiesList.size()]);
    }

    /**
     * Creates the {@link org.compass.gps.device.jpa.entities.EntityInformation} for a given class. If return <code>null</code>
     * the class will be filtered out.
     * <p/>
     * Implementation filters out classes that do not have the {@link javax.persistence.Entity} annotation (i.e.
     * return <code>null</code> for such a case).
     *
     * @param clazz           The class to create the {@link org.compass.gps.device.jpa.entities.EntityInformation} for
     * @param resourceMapping The Compass resource mapping (used for sub indexes extraction)
     * @return The entity information, or <code>null</code> to filter it out
     * @throws JpaGpsDeviceException
     */
    protected EntityInformation createEntityInformation(Class<?> clazz, ResourceMapping resourceMapping)
            throws JpaGpsDeviceException {
        Entity entity = clazz.getAnnotation(Entity.class);
        if (entity == null) {
            return null;
        }
        String name;
        if (StringUtils.hasLength(entity.name())) {
            name = entity.name();
        } else {
            name = ClassUtils.getShortName(clazz);
        }
        return new EntityInformation(clazz, name, resourceMapping.getSubIndexHash().getSubIndexes());
    }

    /**
     * Return <code>true</code> if the entity should be filtered out from the index operation.
     * <p/>
     * Implementation filters out classes that one of the super classes has the {@link javax.persistence.Inheritance}
     * annotation and the super class has compass mappings.
     *
     * @param entityInformation The entity information to check if it should be filtered
     * @param device            The Jpa gps device
     * @return <code>true</code> if the entity should be filtered from the index process
     */
    protected boolean shouldFilter(EntityInformation entityInformation, JpaGpsDevice device) {
        Class<?> clazz = entityInformation.getEntityClass().getSuperclass();
        while (true) {
            if (clazz == null || clazz.equals(Object.class)) {
                break;
            }
            if (clazz.isAnnotationPresent(Inheritance.class)
                    && ((CompassGpsInterfaceDevice) device.getGps()).hasMappingForEntityForIndex(clazz)) {
                if (log.isDebugEnabled()) {
                    log.debug("Entity [" + entityInformation.getName() + "] is inherited and super class [" + clazz
                            + "] has compass mapping, filtering it out");
                }
                return true;
            }
            clazz = clazz.getSuperclass();
        }
        return false;
    }
}