/*
* Copyright 2012 Christopher Pheby
*
* 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 org.jadira.usertype.spi.repository;
import java.io.Serializable;
import javax.persistence.LockModeType;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.metadata.ClassMetadata;
import org.jadira.usertype.spi.utils.reflection.TypeHelper;
/**
* Base implementation of a Repository / type-safe DAO using Hibernate JPA
*
* @param <T> Entity type that this Repository handles
* @param <ID> The type that identifies the ID column for the supported entity type
*/
public abstract class JpaBaseRepository<T extends Serializable, ID extends Serializable> extends JpaSearchRepository<T, ID> implements BaseRepository<T, ID> {
protected JpaBaseRepository() {
}
/**
* Determines the ID for the entity
*
* @param entity The entity to retrieve the ID for
* @return The ID
*/
@SuppressWarnings("deprecation") // No good alternative in the Hibernate API yet
protected ID extractId(T entity) {
final Class<?> entityClass = TypeHelper.getTypeArguments(JpaBaseRepository.class, this.getClass()).get(0);
final SessionFactory sf = ((HibernateEntityManagerFactory) getEntityManager().getEntityManagerFactory()).getSessionFactory();
final ClassMetadata cmd = sf.getClassMetadata(entityClass);
final SessionImplementor si = (SessionImplementor)(getEntityManager().getDelegate());
@SuppressWarnings("unchecked")
final ID result = (ID) cmd.getIdentifier(entity, si);
return result;
}
/**
* {@inheritDoc}
*/
@Override
public T persist(T entity) {
// Case of new, non-persisted entity
if (extractId(entity) == null) {
getEntityManager().persist(entity);
}
else if (!getEntityManager().contains(entity)) {
// In the case of an attached entity, we do nothing (it
// will be persisted automatically on synchronisation)
// But... in the case of an unattached, but persisted entity
// we perform a merge to re-attach and persist it
entity = getEntityManager().merge(entity);
}
return entity;
}
/**
* {@inheritDoc}
*/
@Override
public void remove(ID entityId) {
T entity = getEntityManager().find(getEntityClass(), entityId);
// Case of attached entity - simply remove it
if (getEntityManager().contains(entity)) {
getEntityManager().remove(entity);
}
// Case of unattached entity, first it is necessary to perform
// a merge, before doing the remove
else {
entity = getEntityManager().merge(entity);
getEntityManager().remove(entity);
}
}
/**
* {@inheritDoc}
*/
@Override
public T refresh(T entity) {
// Attempting to refresh a non-persisted entity
// will result in an exception
if (extractId(entity) == null) {
// causes exception
getEntityManager().refresh(entity);
}
// Case of attached empty - this gets refreshed
else if (getEntityManager().contains(entity)) {
getEntityManager().refresh(entity);
}
// Case of unattached entity, first it is necessary to perform
// a merge, before doing the refresh
else {
entity = getEntityManager().merge(entity);
getEntityManager().refresh(entity);
}
return entity;
}
/**
* {@inheritDoc}
*/
@Override
public T evict(T entity) {
Session session = (Session) getEntityManager().getDelegate();
session.evict(entity);
return entity;
}
/**
* {@inheritDoc}
*/
@Override
public void flush() {
getEntityManager().flush();
}
/**
* {@inheritDoc}
*/
@Override
public void lock(T entity, LockModeType lockMode) {
getEntityManager().lock(entity, lockMode);
}
}