/* * 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 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 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 Entity} annotation (i.e. * return <code>null</code> for such a case). * * @param clazz The class to create the {@link 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 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; } }