/*
* Copyright (C) 2009-2010 Open Wide
* Contact: contact@openwide.fr
*
* 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 fr.openwide.core.jpa.business.generic.model;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.Collator;
import java.util.Locale;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.hibernate.Hibernate;
import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.SortableField;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.google.common.collect.Ordering;
import com.querydsl.core.annotations.PropertyType;
import com.querydsl.core.annotations.QueryType;
import fr.openwide.core.commons.util.ordering.SerializableCollator;
/**
* <p>Entité racine pour la persistence des objets via JPA.</p>
*
* @author Open Wide
*
* @param <E> type de l'entité
*/
@MappedSuperclass
public abstract class GenericEntity<K extends Comparable<K> & Serializable, E extends GenericEntity<K, ?>>
implements Serializable, Comparable<E>, IReferenceable<E>, IGenericEntityBindingInterface {
private static final long serialVersionUID = -3988499137919577054L;
private static final Logger LOGGER = LoggerFactory.getLogger(GenericEntity.class);
public static final String ID_SORT = "idSort";
@SuppressWarnings("rawtypes")
private static final Ordering<Comparable> DEFAULT_KEY_ORDERING = Ordering.natural().nullsLast();
public static final Ordering<String> DEFAULT_STRING_COLLATOR;
static {
// On n'utilise PAS la classe Collator directement, car elle n'est pas Serializable.
SerializableCollator collator = new SerializableCollator(Locale.FRENCH);
collator.setStrength(Collator.PRIMARY);
DEFAULT_STRING_COLLATOR = collator.nullsLast();
}
@Override
@Transient
@SuppressWarnings("unchecked")
public GenericEntityReference<K, E> asReference() {
return GenericEntityReference.of((E)this);
}
/**
* Retourne la valeur de l'identifiant unique.
*
* @return id
*/
@Override
@QueryType(PropertyType.COMPARABLE)
@Field(name = ID_SORT, analyze = Analyze.NO)
@SortableField(forField = ID_SORT)
public abstract K getId();
/**
* Définit la valeur de l'identifiant unique.
*
* @param id id
*/
public abstract void setId(K id);
/**
* Indique si l'objet a déjà été persisté ou non
*
* @return vrai si l'objet n'a pas encore été persisté
*/
@Override
@JsonIgnore
@Transient
public boolean isNew() {
return getId() == null;
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object object) {
if (object == null) {
return false;
}
if (object == this) {
return true;
}
// l'objet peut être proxyfié donc on utilise Hibernate.getClass() pour sortir la vraie classe
if (Hibernate.getClass(object) != Hibernate.getClass(this)) {
return false;
}
GenericEntity<K, E> entity = (GenericEntity<K, E>) object; // NOSONAR : traité au-dessus mais wrapper Hibernate
K id = getId();
if (id == null) {
return false;
}
return id.equals(entity.getId());
}
@Override
public int hashCode() {
int hash = 7;
K id = getId();
hash = 31 * hash + ((id == null) ? 0 : id.hashCode());
return hash;
}
@Override
public int compareTo(E right) {
if (this == right) {
return 0;
}
K leftId = getId();
K rightId = right.getId();
if (leftId == null && rightId == null) {
throw new IllegalArgumentException("Cannot compare two different entities with null IDs");
}
return DEFAULT_KEY_ORDERING.compare(leftId, rightId);
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append("entity.");
builder.append(Hibernate.getClass(this).getSimpleName());
builder.append("<");
builder.append(getId());
builder.append("-");
builder.append(getNameForToString());
builder.append(">");
return builder.toString();
}
/**
* Retourne l'élément de chaîne qui va être injecté dans le toString() de l'objet : faire en sorte que cela permette
* de l'identifier.
*
* @return chaîne à injecter dans le toString()
*/
@JsonIgnore
public abstract String getNameForToString();
/**
* Retourne le nom à afficher.
*
* @return nom à afficher
*/
@JsonIgnore
public abstract String getDisplayName();
/**
* Add a simple way to track unwanted entity serializations.
* <p>Note that, in some cases we <strong>do</strong> want to serialize persisted entities, for instance
* when they are values of attributes of an entity which is in the process of being created in a web form.
*/
private void writeObject(ObjectOutputStream out) throws IOException {
if (LOGGER.isDebugEnabled() && !isNew()) {
LOGGER.debug(
"Serializing a persisted entity (class = {} and id = {})",
getClass(), getId()
);
}
out.defaultWriteObject();
}
}