/* * Copyright [2014] [Christian Loehnert, krampenschiesser@gmail.com] * 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 de.ks.idnadrev.expimp; import de.ks.persistence.entity.IdentifyableEntity; import de.ks.reflection.ReflectionUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.inject.Inject; import javax.persistence.AssociationOverride; import javax.persistence.AssociationOverrides; import javax.persistence.EntityManagerFactory; import javax.persistence.JoinTable; import javax.persistence.metamodel.EntityType; import javax.persistence.metamodel.PluralAttribute; import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.Type; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class DependencyGraph { private static final Logger log = LoggerFactory.getLogger(DependencyGraph.class); private final Map<Class<?>, String> class2IdentifierPropertyName = new ConcurrentHashMap<>(); @Inject EntityManagerFactory factory; protected final List<Collection<EntityType<?>>> importOrder = new ArrayList<>(); public List<Collection<EntityType<?>>> getImportOrder() { if (importOrder.isEmpty()) { Set<EntityType<?>> entities = new HashSet<>(factory.getMetamodel().getEntities()); while (!entities.isEmpty()) { List<EntityType<?>> rootEntites = getNextEntities(entities, importOrder); importOrder.add(rootEntites); } log.debug("Found {} waves to import", importOrder.size()); for (int i = 0; i < importOrder.size(); i++) { log.debug("Found import wave {} objects {}", i, importOrder.get(i).stream().map(t -> t.getJavaType().getName()).collect(Collectors.toList())); } } ArrayList<Collection<EntityType<?>>> retval = new ArrayList<>(importOrder.size()); importOrder.forEach(i -> retval.add(new ArrayList<>(i))); return retval; } public int getStage(Class<?> entity) { List<Collection<EntityType<?>>> order = getImportOrder(); for (int i = 0; i < order.size(); i++) { Optional<EntityType<?>> first = order.get(i).stream().filter(t -> t.getJavaType().equals(entity)).findFirst(); if (first.isPresent()) { return i; } } throw new IllegalArgumentException(entity.getName() + " is not contained in any stage"); } public EntityType<?> getEntityType(Class<?> entity) { List<Collection<EntityType<?>>> order = getImportOrder(); for (int i = 0; i < order.size(); i++) { Optional<EntityType<?>> first = order.get(i).stream().filter(t -> t.getJavaType().equals(entity)).findFirst(); if (first.isPresent()) { return first.get(); } } throw new IllegalArgumentException(entity.getName() + " is not contained in any stage"); } private List<EntityType<?>> getNextEntities(Set<EntityType<?>> entities, List<Collection<EntityType<?>>> importOrder) { List<EntityType<?>> roots = entities.stream()// .filter(e -> { @SuppressWarnings("unchecked") Optional mandatoryRelation = e.getSingularAttributes().stream().filter(a -> a.isAssociation() && !a.isOptional()).findFirst(); if (!mandatoryRelation.isPresent()) { return true; } else { @SuppressWarnings("unchecked") SingularAttribute relation = (SingularAttribute) mandatoryRelation.get(); boolean entityContained = importOrder.stream().filter(l -> l.stream().filter(type -> type.getJavaType().equals(relation.getJavaType())).findFirst().isPresent()).findFirst().isPresent(); return entityContained; } }).collect(Collectors.toList()); entities.removeAll(roots); return roots; } public String getIdentifierProperty(Class<?> clazz) { return class2IdentifierPropertyName.computeIfAbsent(clazz, c -> { if (IdentifyableEntity.class.isAssignableFrom(c)) { @SuppressWarnings("unchecked") IdentifyableEntity entity = ReflectionUtil.newInstance((Class<? extends IdentifyableEntity>) c); return entity.getIdPropertyName(); } return null; }); } public Set<String> getJoinTables() { Set<String> retval = new HashSet<>(); for (EntityType<?> entityType : factory.getMetamodel().getEntities()) { retval.addAll(getOverridenJoinTables(entityType)); for (PluralAttribute<?, ?, ?> pluralAttribute : entityType.getPluralAttributes()) { if (pluralAttribute.isAssociation()) { Member javaMember = pluralAttribute.getJavaMember(); if (javaMember instanceof Field) { JoinTable annotation = ((Field) javaMember).getAnnotation(JoinTable.class); if (annotation != null) { String name = annotation.name(); if (name != null && !name.isEmpty()) { retval.add(name); } } } } } } return retval; } private HashSet<String> getOverridenJoinTables(EntityType<?> entityType) { HashSet<String> retval = new HashSet<>(); AssociationOverrides collection = entityType.getJavaType().getAnnotation(AssociationOverrides.class); if (collection != null) { for (AssociationOverride associationOverride : collection.value()) { JoinTable joinTable = associationOverride.joinTable(); if (joinTable != null) { String name = joinTable.name(); if (name != null && !name.isEmpty()) { retval.add(joinTable.name()); } } } } return retval; } public List<ToOneRelation> getOptionalToOneRelations() { List<ToOneRelation> retval = new LinkedList<>(); for (EntityType<?> entityType : factory.getMetamodel().getEntities()) { if (entityType.getPersistenceType() == Type.PersistenceType.ENTITY) { List<ToOneRelation> optionalRelations = entityType.getSingularAttributes().stream()// .filter(a -> a.isAssociation() && a.isOptional())// .map(r -> new ToOneRelation(entityType, r))// .collect(Collectors.toList()); retval.addAll(optionalRelations); } } return retval; } }