package fr.openwide.core.jpa.business.generic.model;
import java.io.Serializable;
import javax.persistence.Access;
import javax.persistence.AccessType;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
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.Hibernate;
import org.hibernate.annotations.Type;
import org.hibernate.search.annotations.Analyzer;
import org.hibernate.search.annotations.Field;
import org.springframework.util.Assert;
import fr.openwide.core.jpa.search.util.HibernateSearchAnalyzer;
@Embeddable
@MappedSuperclass
@Access(AccessType.FIELD)
public class GenericEntityReference<K extends Comparable<K> & Serializable, E extends GenericEntity<K, ?>>
implements IReference<E>, Serializable {
private static final long serialVersionUID = 1357434247523209721L;
private static final String CLASS_TYPE = "org.hibernate.type.ClassType";
@Column(nullable = true)
@Type(type = CLASS_TYPE)
private /* final */ Class<? extends E> type;
@Column(nullable = true)
@Field(analyzer = @Analyzer(definition = HibernateSearchAnalyzer.KEYWORD))
private /* final */ K id;
public static <K extends Comparable<K> & Serializable, E extends GenericEntity<K, ?>>
GenericEntityReference<K, E> of(E entity) {
return entity == null || entity.isNew() ? null : new GenericEntityReference<K, E>(entity);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <E extends GenericEntity<?, ?>> GenericEntityReference<?, E> ofUnknownIdType(E entity) {
return entity == null || entity.isNew() ? null : (GenericEntityReference<?, E>) new GenericEntityReference(entity);
}
public static <K extends Comparable<K> & Serializable, E extends GenericEntity<K, ?>> GenericEntityReference<K, E>
of(Class<? extends E> entityClass, K entityId) {
return new GenericEntityReference<K, E>(entityClass, entityId);
}
protected GenericEntityReference() { } // Pour Hibernate
@SuppressWarnings("unchecked")
public GenericEntityReference(E entity) {
Assert.notNull(entity, "The referenced entity must not be null");
Assert.state(!entity.isNew(), "The referenced entity must not be transient");
this.type = (Class<? extends E>)Hibernate.getClass(entity);
this.id = entity.getId();
}
public GenericEntityReference(Class<? extends E> entityClass, K entityId) {
super();
Assert.notNull(entityClass, "entityClass must not be null");
Assert.notNull(entityId, "entityId must not be null");
this.type = entityClass;
this.id = entityId;
}
@Override
public Class<? extends E> getType() {
return type;
}
@Override
public K getId() {
return id;
}
/**
* @deprecated Use {@link #getType()} instead.
*/
@Deprecated
public Class<? extends E> getEntityClass() {
return getType();
}
/**
* @deprecated Use {@link #getId()} instead.
*/
@Deprecated
public K getEntityId() {
return getId();
}
@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;
}
/* Caution here: we really need an instanceof, not a this.getClass() == other.getClass()
* because some subclasses may simply be workarounds (for instance HistoryEntityReference in JPA-More)
*/
if (!(obj instanceof GenericEntityReference)) {
return false;
}
GenericEntityReference<?, ? extends GenericEntity<?, ?>> other = (GenericEntityReference<?, ?>) obj;
return new EqualsBuilder()
.append(getId(), other.getId())
.append(getUpperEntityClass(getType()), getUpperEntityClass(other.getType()))
.build();
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(getId())
.append(getUpperEntityClass(getType()))
.build();
}
@Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
.append("class", getType())
.append("id", getId())
.build();
}
@Override
@Transient
public GenericEntityReference<K, E> asReference() {
return this;
}
@Override
@Transient
public boolean matches(E referenceable) {
return referenceable != null && equals(referenceable.asReference());
}
}