package org.eclipse.emf.texo.server.store;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.metamodel.EmbeddableType;
import javax.persistence.metamodel.EntityType;
import javax.persistence.metamodel.Metamodel;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.texo.model.ModelResolver;
import org.eclipse.emf.texo.store.ObjectStore;
/**
* An {@link ObjectStore} backed by an EntityManager.
*
* @author <a href="mtaal@elver.org">Martin Taal</a>
*/
public class EntityManagerObjectStore extends ObjectStore {
private static final String COUNT = "count("; //$NON-NLS-1$
private static final String FROM = " from "; //$NON-NLS-1$
private static final String START_FROM = "from "; //$NON-NLS-1$
private static final int FROM_LENGTH = FROM.length();
private static final int START_FROM_LENGTH = START_FROM.length();
private boolean embeddablesDetermined = false;
private List<Class<?>> embeddables = new ArrayList<Class<?>>();
@PersistenceContext
private EntityManager entityManager;
public EntityManager getEntityManager() {
if (entityManager == null) {
entityManager = EntityManagerProvider.getInstance().getEntityManager();
}
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.store.ObjectStore#get(org.eclipse.emf.ecore.EClass, java.lang.Object)
*/
@Override
public Object get(EClass eClass, Object id) {
final Class<?> clz = ModelResolver.getInstance().getImplementationClass(eClass);
return getDao(clz).get(id);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.server.store.ObjectStore#get(java.lang.Class, java.lang.Object)
*/
@Override
public <T extends Object> T get(Class<T> clz, Object id) {
return getDao(clz).get(id);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.store.ObjectStore#update(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public <T extends Object> T update(T object) {
// can happen when the objectstore is used as part
// of persisting for a resource
if (isEmbeddable(object)) {
return object;
}
return ((BaseDao<T>) getDao(object.getClass())).update(object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.store.ObjectStore#delete(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public <T extends Object> void remove(T object) {
// can happen when the objectstore is used as part
// of persisting for a resource
if (isEmbeddable(object)) {
return;
}
((BaseDao<T>) getDao(object.getClass())).remove(object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.server.store.ObjectStore#refresh(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public <T extends Object> void refresh(T object) {
// can happen when the objectstore is used as part
// of persisting for a resource
if (isEmbeddable(object)) {
return;
}
((BaseDao<T>) getDao(object.getClass())).refresh(object);
}
@Override
public boolean isNew(Object o) {
// can happen when the objectstore is used as part
// of persisting for a resource
if (isEmbeddable(o)) {
return true;
}
return super.isNew(o);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.store.ObjectStore#insert(java.lang.Object)
*/
@SuppressWarnings("unchecked")
@Override
public <T extends Object> void insert(T object) {
// can happen when the objectstore is used as part
// of persisting for a resource
if (isEmbeddable(object)) {
return;
}
((BaseDao<T>) getDao(object.getClass())).insert(object);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.store.ObjectStore#query(java.lang.String, java.util.Map)
*/
@Override
public List<?> query(String qryStr, Map<String, Object> namedParameters, int firstResult, int maxResults) {
final Query qry = getEntityManager().createQuery(qryStr);
if (firstResult != -1) {
qry.setFirstResult(firstResult);
}
if (maxResults > 0) {
qry.setMaxResults(maxResults);
}
for (String key : namedParameters.keySet()) {
qry.setParameter(key, namedParameters.get(key));
}
return qry.getResultList();
}
@Override
public List<?> namedQuery(String name, Map<String, Object> namedParameters, int firstResult, int maxResults) {
final Query qry = getEntityManager().createNamedQuery(name);
if (firstResult != -1) {
qry.setFirstResult(firstResult);
}
if (maxResults != -1) {
qry.setMaxResults(maxResults);
}
for (String key : namedParameters.keySet()) {
qry.setParameter(key, namedParameters.get(key));
}
return qry.getResultList();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.store.ObjectStore#count(java.lang.String, java.util.Map)
*/
@Override
public long count(String qryStr, Map<String, Object> namedParameters) {
final String subQryStr;
String prefix = "select count(e) from "; //$NON-NLS-1$
if (qryStr.toLowerCase().contains(COUNT)) {
subQryStr = qryStr;
prefix = ""; //$NON-NLS-1$
} else if (qryStr.toLowerCase().contains(FROM)) {
final int index = qryStr.toLowerCase().indexOf(FROM);
subQryStr = qryStr.substring(index + FROM_LENGTH);
} else if (qryStr.toLowerCase().startsWith(START_FROM)) {
subQryStr = qryStr.substring(START_FROM_LENGTH);
} else {
subQryStr = qryStr;
}
final Query qry = getEntityManager().createQuery(prefix + subQryStr);
for (String key : namedParameters.keySet()) {
qry.setParameter(key, namedParameters.get(key));
}
return ((Number) qry.getSingleResult()).longValue();
}
@Override
public long countNamedQuery(String name, Map<String, Object> namedParameters) {
final Query qry = getEntityManager().createNamedQuery(name);
for (String key : namedParameters.keySet()) {
qry.setParameter(key, namedParameters.get(key));
}
return ((Number) qry.getSingleResult()).longValue();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.store.ObjectStore#query(org.eclipse.emf.ecore.EClass)
*/
@Override
public List<?> query(EClass eClass, int firstResult, int maxResults) {
final Class<?> clz = ModelResolver.getInstance().getImplementationClass(eClass);
final CriteriaBuilder queryBuilder = getEntityManager().getCriteriaBuilder();
final CriteriaQuery<?> qdef = queryBuilder.createQuery(clz);
qdef.from(clz);
final Query query = getEntityManager().createQuery(qdef);
if (firstResult > -1) {
query.setFirstResult(firstResult);
}
if (maxResults > -1) {
query.setMaxResults(maxResults);
}
return query.getResultList();
}
/**
* Calls EntityManager#getTransaction#begin}.
*/
@Override
public void begin() {
if (getEntityManager().getTransaction().isActive()) {
// already begun
return;
}
getEntityManager().getTransaction().begin();
}
/**
* Calls EntityManager#getTransaction#commit.
*/
@Override
public void commit() {
getEntityManager().getTransaction().commit();
}
/**
* Calls {@link EntityManager#flush()}.
*/
@Override
public void flush() {
getEntityManager().flush();
}
/**
* Calls EntityManager#getTransaction#rollback.
*/
@Override
public void rollback() {
if (getEntityManager().getTransaction() != null && getEntityManager().getTransaction().isActive()) {
getEntityManager().getTransaction().rollback();
}
}
/**
* Calls {@link EntityManager#close()}.
*/
@Override
public void close() {
EntityManagerProvider.getInstance().releaseEntityManager(getEntityManager());
}
/**
* @return the {@link EntityManager}
*/
@Override
public Object getDelegate() {
return getEntityManager();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.server.store.ObjectStore#getReferingObjects(java.lang.Object, int, boolean)
*/
@SuppressWarnings("unchecked")
@Override
public <T extends Object> List<Object> getReferingObjects(T target, int maxResult,
boolean includeContainerReferences) {
return ((BaseDao<T>) getDao(target.getClass())).getReferingObjects(target, maxResult, includeContainerReferences);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.server.store.ObjectStore#isReferenced(java.lang.Object, boolean)
*/
@SuppressWarnings("unchecked")
@Override
public <T extends Object> boolean isReferenced(T target, boolean includeContainerReferences) {
return ((BaseDao<T>) getDao(target.getClass())).isReferenced(target, includeContainerReferences);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.texo.server.store.ObjectStore#getEntityName(org.eclipse.emf.ecore.EClass)
*/
@Override
public String getEntityName(EClass eClass) {
final Metamodel metaModel = getEntityManager().getMetamodel();
final EntityType<?> entityType = metaModel.entity(ModelResolver.getInstance().getImplementationClass(eClass));
return entityType.getName();
}
private <T extends Object> BaseDao<T> getDao(Class<T> entityClass) {
final BaseDao<T> dao = DaoRegistry.getInstance().getDaoForEntity(entityClass);
dao.setEntityManager(getEntityManager());
return dao;
}
protected boolean isEmbeddable(Object object) {
if (!embeddablesDetermined) {
determineEmbeddables();
}
if (embeddables.isEmpty()) {
return false;
}
if (embeddables.contains(object.getClass())) {
return true;
}
return false;
}
protected synchronized void determineEmbeddables() {
if (embeddablesDetermined) {
return;
}
for (EmbeddableType<?> embeddable : entityManager.getEntityManagerFactory().getMetamodel().getEmbeddables()) {
embeddables.add(embeddable.getJavaType());
}
}
}