package fr.openwide.core.jpa.business.generic.model; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.List; import javax.persistence.Column; import javax.persistence.Entity; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.ToStringBuilder; import org.apache.commons.lang3.builder.ToStringStyle; import org.hibernate.search.annotations.Analyzer; import org.hibernate.search.annotations.Field; import org.springframework.util.Assert; import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import fr.openwide.core.jpa.search.util.HibernateSearchAnalyzer; public class GenericEntityCollectionReference<K extends Comparable<K> & Serializable, E extends GenericEntity<K, ?>> implements Serializable { private static final long serialVersionUID = 1357434247523209721L; @Column(nullable = true) private final Class<? extends E> entityClass; @Column(nullable = true) @Field(analyzer = @Analyzer(definition = HibernateSearchAnalyzer.KEYWORD)) private final List<K> entityIdList; public static <K extends Comparable<K> & Serializable, E extends GenericEntity<K, ?>> GenericEntityCollectionReference<K, E> of(Class<E> entityClass, Collection<? extends E> entityCollection) { List<K> entityIdCollection = Lists.newArrayListWithExpectedSize(entityCollection.size()); for (E entity : entityCollection) { Assert.state(!entity.isNew(), "None of the referenced entities must be transient"); entityIdCollection.add(entity.getId()); } return new GenericEntityCollectionReference<>(entityClass, entityIdCollection); } @SuppressWarnings({ "unchecked", "rawtypes" }) public static <E extends GenericEntity<?, ?>> GenericEntityCollectionReference<?, E> ofUnknownIdType( Class<E> entityClass, Collection<? extends E> entityCollection) { List<Object> entityIdCollection = Lists.newArrayListWithExpectedSize(entityCollection.size()); for (E entity : entityCollection) { Assert.state(!entity.isNew(), "None of the referenced entities must be transient"); entityIdCollection.add(entity.getId()); } return new GenericEntityCollectionReference(entityClass, entityIdCollection); } public GenericEntityCollectionReference(E object) { this(GenericEntityReference.of(object)); } public GenericEntityCollectionReference(GenericEntityReference<K, E> reference) { this(reference.getType(), ImmutableList.of(reference.getId())); } public GenericEntityCollectionReference(Class<? extends E> entityClass) { this(entityClass, ImmutableList.<K>of()); } public GenericEntityCollectionReference(Class<? extends E> entityClass, Collection<K> entityIdCollection) { super(); Assert.notNull(entityClass, "entityClass must not be null"); Assert.notNull(entityIdCollection, "entityIdCollection must not be null"); this.entityClass = entityClass; this.entityIdList = Collections.unmodifiableList(Lists.newArrayList(entityIdCollection)); } public Class<? extends E> getEntityClass() { return entityClass; } public List<K> getEntityIdList() { return entityIdList; } @SuppressWarnings("unchecked") protected static <K extends Comparable<K> & Serializable> Class<? extends GenericEntity<K, ?>> getUpperEntityClass(Class<? extends GenericEntity<K, ?>> entityClass) { Class<?> currentClass = entityClass; while (currentClass != null && currentClass.getAnnotation(Entity.class) == null) { currentClass = currentClass.getSuperclass(); } return (Class<? extends GenericEntity<K, ?>>) currentClass; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (obj == this) { return true; } if (!(obj instanceof GenericEntityCollectionReference)) { return false; } GenericEntityCollectionReference<?, ? extends GenericEntity<?, ?>> other = (GenericEntityCollectionReference<?, ?>) obj; return new EqualsBuilder() .append(getEntityIdList(), other.getEntityIdList()) .append(getUpperEntityClass(getEntityClass()), getUpperEntityClass(other.getEntityClass())) .build(); } @Override public int hashCode() { return new HashCodeBuilder() .append(getEntityIdList()) .append(getUpperEntityClass(getEntityClass())) .build(); } @Override public String toString() { return new ToStringBuilder(ToStringStyle.SHORT_PREFIX_STYLE) .append("class", getEntityClass()) .append("id", getEntityIdList()) .build(); } public GenericEntityCollectionReference<K, E> subset(int offset, int limit) { if (offset < 0) { throw new IllegalArgumentException("offset = " + offset); } if (limit < 0) { throw new IllegalArgumentException("limit = " + limit); } int size = entityIdList.size(); if (offset >= size) { return new GenericEntityCollectionReference<>(getEntityClass(), Collections.<K>emptyList()); } else { int toIndex = Math.min(size, offset + limit); List<K> sublist = entityIdList.subList(offset, toIndex); return new GenericEntityCollectionReference<>(getEntityClass(), sublist); } } }