/* * 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.deltaspike.data.impl.meta; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.persistence.FlushModeType; import org.apache.deltaspike.core.api.provider.BeanManagerProvider; import org.apache.deltaspike.data.api.EntityManagerConfig; import org.apache.deltaspike.data.api.EntityManagerResolver; import org.apache.deltaspike.data.api.Repository; /** * Stores information about a specific Repository. Extracts information about: * <ul> * <li>The Repository class</li> * <li>The target entity the Repository is for</li> * <li>The primary key class</li> * <li>All methods of the Repository.</li> * </ul> */ public class RepositoryComponent { private static final Logger log = Logger.getLogger(RepositoryComponent.class.getName()); private volatile Boolean entityManagerResolverIsNormalScope; private final Class<?> repoClass; private final RepositoryEntity repositoryEntity; private final Class<? extends EntityManagerResolver> entityManagerResolver; private final FlushModeType entityManagerFlushMode; private final Map<Method, RepositoryMethod> methods = new HashMap<Method, RepositoryMethod>(); public RepositoryComponent(Class<?> repoClass, RepositoryEntity repositoryEntity) { if (repositoryEntity == null) { throw new IllegalArgumentException("repositoryEntity cannot be null"); } this.repoClass = repoClass; this.repositoryEntity = repositoryEntity; this.entityManagerResolver = extractEntityManagerResolver(repoClass); this.entityManagerFlushMode = extractEntityManagerFlushMode(repoClass); } //don't trigger this lookup during ProcessAnnotatedType private void lazyInit() { if (entityManagerResolverIsNormalScope == null) { init(BeanManagerProvider.getInstance().getBeanManager()); } } private synchronized void init(BeanManager beanManager) { if (entityManagerResolverIsNormalScope != null) { return; } initialize(); if (entityManagerResolver != null && beanManager != null) { final Set<Bean<?>> beans = beanManager.getBeans(entityManagerResolver); final Class<? extends Annotation> scope = beanManager.resolve(beans).getScope(); entityManagerResolverIsNormalScope = beanManager.isNormalScope(scope); } else { entityManagerResolverIsNormalScope = false; } } public boolean isEntityManagerResolverIsNormalScope() { lazyInit(); return entityManagerResolverIsNormalScope; } public String getEntityName() { return repositoryEntity.getEntityName(); } /** * Looks up method meta data by a Method object. * * @param method The Repository method. * @return Method meta data. */ public RepositoryMethod lookupMethod(Method method) { lazyInit(); return methods.get(method); } /** * Looks up the method type by a Method object. * * @param method The Repository method. * @return Method meta data. */ public MethodType lookupMethodType(Method method) { return lookupMethod(method).getMethodType(); } /** * Gets the entity class related the Repository. * * @return The class of the entity related to the Repository. */ public Class<?> getEntityClass() { return repositoryEntity.getEntityClass(); } /** * Gets the entity primary key class related the Repository. * * @return The class of the entity primary key related to the Repository. */ public Class<? extends Serializable> getPrimaryKey() { return repositoryEntity.getPrimaryKeyClass(); } public RepositoryEntity getRepositoryEntity() { return repositoryEntity; } /** * Returns the original Repository class this meta data is related to. * * @return The class of the Repository. */ public Class<?> getRepositoryClass() { return repoClass; } public boolean hasEntityManagerResolver() { return getEntityManagerResolverClass() != null; } public Class<? extends EntityManagerResolver> getEntityManagerResolverClass() { return entityManagerResolver; } public boolean hasEntityManagerFlushMode() { return entityManagerFlushMode != null; } public FlushModeType getEntityManagerFlushMode() { return entityManagerFlushMode; } private void initialize() { Collection<Class<?>> allImplemented = collectClasses(); for (Class<?> implemented : allImplemented) { Method[] repoClassMethods = implemented.getDeclaredMethods(); for (Method repoClassMethod : repoClassMethods) { RepositoryMethod repoMethod = new RepositoryMethod(repoClassMethod, this); methods.put(repoClassMethod, repoMethod); } } } private Set<Class<?>> collectClasses() { Set<Class<?>> result = new HashSet<Class<?>>(); collectClasses(repoClass, result); log.log(Level.FINER, "collectClasses(): Found {0} for {1}", new Object[] { result, repoClass }); return result; } private void collectClasses(Class<?> cls, Set<Class<?>> result) { if (cls == null || cls == Object.class) { return; } result.add(cls); for (Class<?> child : cls.getInterfaces()) { collectClasses(child, result); } collectClasses(cls.getSuperclass(), result); } private Class<? extends EntityManagerResolver> extractEntityManagerResolver(Class<?> clazz) { EntityManagerConfig config = extractEntityManagerConfig(clazz); if (config != null && !EntityManagerResolver.class.equals(config.entityManagerResolver())) { return config.entityManagerResolver(); } return null; } private FlushModeType extractEntityManagerFlushMode(Class<?> clazz) { EntityManagerConfig config = extractEntityManagerConfig(clazz); if (config != null) { return config.flushMode(); } return null; } private EntityManagerConfig extractEntityManagerConfig(Class<?> clazz) { if (clazz.isAnnotationPresent(EntityManagerConfig.class)) { return clazz.getAnnotation(EntityManagerConfig.class); } return null; } public String getCustomMethodPrefix() { return repoClass.getAnnotation(Repository.class).methodPrefix(); } }