package org.oregami.data;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.persist.Transactional;
import org.hibernate.envers.AuditReader;
import org.hibernate.envers.AuditReaderFactory;
import org.joda.time.LocalDateTime;
import org.oregami.entities.BaseEntityUUID;
import org.oregami.entities.CustomRevisionEntity;
import org.oregami.entities.CustomRevisionListener;
import org.oregami.entities.TopLevelEntity;
import org.oregami.service.ServiceCallContext;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
public abstract class GenericDAOUUIDImpl<E extends BaseEntityUUID, P> implements
GenericDAOUUID<E, P> {
private final Provider<EntityManager> emf;
@Inject
public GenericDAOUUIDImpl(Provider<EntityManager> emf) {
this.emf=emf;
}
Class<E> entityClass;
@Override
@Transactional
@SuppressWarnings("unchecked")
public P save(E entity) {
entity.setChangeTime(new LocalDateTime());
emf.get().persist(entity);
updateRevisionListener(entity);
return (P) entity.getId();
}
@Override
public E findOne(P id) {
return emf.get().find(getEntityClass(), id);
}
@Override
@Transactional
public void update(E entity) {
updateRevisionListener(entity);
entity.setChangeTime(new LocalDateTime());
emf.get().merge(entity);
}
@Override
@Transactional
public void delete(E entity) {
emf.get().remove(entity);
}
@Override
public EntityManager getEntityManager() {
return emf.get();
}
@Override
@SuppressWarnings("unchecked")
public Class<E> getEntityClass() {
if (entityClass == null) {
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) type;
entityClass = (Class<E>) paramType.getActualTypeArguments()[0];
} else {
throw new IllegalArgumentException(
"Could not guess entity class by reflection");
}
}
return entityClass;
}
@SuppressWarnings("unchecked")
@Override
public List<E> findAll() {
return this.emf.get().createNamedQuery(
getEntityClass().getSimpleName() + ".GetAll").getResultList();
}
public EntityTransaction getTransaction() {
return getEntityManager().getTransaction();
}
protected void updateRevisionListener(BaseEntityUUID entity) {
if (entity.getClass().isAnnotationPresent(TopLevelEntity.class)) {
ServiceCallContext context = CustomRevisionListener.context.get();
if (context != null) {
context.setEntityDiscriminator(entity.getClass().getAnnotation(TopLevelEntity.class).discriminator());
context.setEntityId(entity.getId());
}
}
}
public List<RevisionInfo> findRevisions(String id) {
List<RevisionInfo> list = new ArrayList<>();
AuditReader reader = AuditReaderFactory.get(getEntityManager());
List<Number> revisions = reader.getRevisions(getEntityClass(), id);
for (Number n : revisions) {
CustomRevisionEntity revEntity = reader.findRevision(CustomRevisionEntity.class, n);
list.add(new RevisionInfo(n, revEntity));
}
return list;
}
public E findRevision(String id, Number revision) {
AuditReader reader = AuditReaderFactory.get(getEntityManager());
List<Number> revisions = reader.getRevisions(getEntityClass(), id);
if (!revisions.contains(revision)) {
return null;
}
E entity = reader.find(getEntityClass(), id, revision);
return entity;
}
}