org.eurekaclinical.standardapis.dao.DatabaseSupport Maven / Gradle / Ivy
package org.eurekaclinical.standardapis.dao;
/*-
* #%L
* Eureka! Clinical Standard APIs
* %%
* Copyright (C) 2016 Emory University
* %%
* 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.
* #L%
*/
import java.util.Date;
import java.util.List;
import javax.inject.Provider;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.metamodel.SingularAttribute;
import org.eurekaclinical.standardapis.entity.HistoricalEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
*
* @author Andrew Post
*/
public final class DatabaseSupport {
private static Logger LOGGER
= LoggerFactory.getLogger(DatabaseSupport.class);
/**
* Comparators for constructing where clauses that set a threshold on a
* numerical value.
*/
public static enum SqlComparator {
LESS_THAN_OR_EQUAL_TO,
LESS_THAN,
EQUAL_TO,
NOT_EQUAL_TO,
GREATER_THAN,
GREATER_THAN_OR_EQUAL_TO
}
/**
* Wraps an entity manager in an implementation of the {@link Provider}
* interface.
*/
private static class EntityManagerProvider
implements Provider {
private final EntityManager entityManager;
/**
* Creates a provider of the given entity manager.
*
* @param inEntityManager the entity manager. Cannot be
* null
.
*/
EntityManagerProvider(EntityManager inEntityManager) {
assert inEntityManager != null : "inEntityManager cannot be null";
this.entityManager = inEntityManager;
}
@Override
public EntityManager get() {
return this.entityManager;
}
}
/**
* The entity manager used in creating queries.
*/
private final Provider entityManagerProvider;
/**
* Creates a database support instance that uses the provided entity manager
* to construct queries.
*
* @param entityManager the entity manager to use. Cannot be
* null
.
*/
public DatabaseSupport(EntityManager entityManager) {
if (entityManager == null) {
throw new IllegalArgumentException("entityManager cannot be null");
}
this.entityManagerProvider = new EntityManagerProvider(entityManager);
}
/**
* Creates a database support instance that uses the provided entity manager
* provider to construct queries.
*
* @param entityManagerProvider the entity manager provider to use. Cannot
* be null
.
*/
public DatabaseSupport(Provider entityManagerProvider) {
if (entityManagerProvider == null) {
throw new IllegalArgumentException(
"entityManagerProvider cannot be null");
}
this.entityManagerProvider = entityManagerProvider;
}
/**
* Gets every instance of the specified entity in the database.
*
* @param the type of the entity.
* @param entityCls the class of the specified entity. Cannot be
* null
.
* @return the instances requested. Guaranteed not null
.
*/
@SuppressWarnings("unchecked")
public List getAll(Class entityCls) {
if (entityCls == null) {
throw new IllegalArgumentException("entityCls cannot be null");
}
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery
= builder.createQuery(entityCls);
criteriaQuery.from(entityCls);
TypedQuery typedQuery
= entityManager.createQuery(criteriaQuery);
List results = typedQuery.getResultList();
return results;
}
/**
* Gets every instance of the specified historical entity in the database.
*
* @param the type of the entity.
* @param historicalEntityCls the class of the specified historical entity.
* The entity must be a subtype of {@link HistoricalEntity}. Cannot be
* null
.
* @return the instances requested. Guaranteed not null
.
*/
public List getCurrent(Class historicalEntityCls) {
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(historicalEntityCls);
Root root = criteriaQuery.from(historicalEntityCls);
criteriaQuery.where(expiredAt(root, builder));
TypedQuery typedQuery = entityManager.createQuery(criteriaQuery);
return typedQuery.getResultList();
}
/**
* Gets the instance of the specified historical entity in the database
* that has the given value of the given attribute.
*
* @param the type of the entity.The entity must be a subtype of
* {@link HistoricalEntity}. Cannot be null
.
* @param the attribute's type.
* @param historicalEntityCls the class of the specified historical entity.
* @param attribute the attribute. Cannot be null
.
* @param value the value. Cannot be null
.
*
* @return the instance requested. Guaranteed not null
.
*/
public T getCurrentUniqueByAttribute(
Class historicalEntityCls,
SingularAttribute attribute, Y value) {
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(historicalEntityCls);
Root root = criteriaQuery.from(historicalEntityCls);
Predicate whereClause = builder.and(
builder.equal(root.get(attribute), value),
expiredAt(root, builder));
criteriaQuery.where(whereClause);
TypedQuery query = entityManager.createQuery(criteriaQuery);
T result = null;
try {
result = query.getSingleResult();
} catch (NonUniqueResultException nure) {
LOGGER.warn("Result not unique for {}: {} = {}",
historicalEntityCls.getName(), attribute.getName(), value);
result = query.getResultList().get(0);
} catch (NoResultException nre) {
LOGGER.debug("Result not existant for {}: {} = {}",
historicalEntityCls.getName(), attribute.getName(), value);
}
return result;
}
/**
* Gets every instance of the specified historical entity in the database
* that has the given value of the given attribute.
*
* @param the type of the entity.The entity must be a subtype of
* {@link HistoricalEntity}. Cannot be null
.
* @param the attribute's type.
* @param historicalEntityCls the class of the specified historical entity.
* @param attribute the attribute. Cannot be null
.
* @param value the value. Cannot be null
.
*
* @return the instance requested. Guaranteed not null
.
*/
public List getCurrentListByAttribute(
Class historicalEntityCls,
SingularAttribute attribute, Y value) {
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(historicalEntityCls);
Root root = criteriaQuery.from(historicalEntityCls);
Predicate whereClause = builder.and(
builder.equal(root.get(attribute), value),
expiredAt(root, builder));
criteriaQuery.where(whereClause);
TypedQuery typedQuery = entityManager.createQuery(criteriaQuery);
return typedQuery.getResultList();
}
private Predicate expiredAt(Root root, CriteriaBuilder builder) {
Path expiredAt = root.get("expiredAt");
return builder.or(
builder.isNull(root.get("expiredAt")),
builder.greaterThanOrEqualTo(expiredAt, new Date()));
}
/**
* Gets the entity that has the specified value of an attribute. This method
* assumes that at most one instance of the given entity will be a match.
* This typically is used with attributes with a uniqueness constraint.
*
* @param the type of the entity.
* @param the type of the attribute.
* @param entityCls the entity class. Cannot be null
.
* @param attribute the attribute. Cannot be null
.
* @param value the value. If there is more than one matching instance, only
* the first will be returned, and a warning will be logged.
*
* @return the matching instance, or null
if there is none.
*/
public T getUniqueByAttribute(Class entityCls,
SingularAttribute attribute, Y value) {
if (entityCls == null) {
throw new IllegalArgumentException("entityCls cannot be null");
}
if (attribute == null) {
throw new IllegalArgumentException("attribute cannot be null");
}
TypedQuery query = createTypedQuery(entityCls, attribute, value);
T result = null;
try {
result = query.getSingleResult();
} catch (NonUniqueResultException nure) {
LOGGER.warn("Result not unique for {}: {} = {}",
entityCls.getName(), attribute.getName(), value);
result = query.getResultList().get(0);
} catch (NoResultException nre) {
LOGGER.debug("Result not existant for {}: {} = {}",
entityCls.getName(), attribute.getName(), value);
}
return result;
}
/**
* Executes a query for the entity with the given attribute value. This
* method assumes that at most one instance of the given entity will be a
* match. This typically is used with attributes with a uniqueness
* constraint.
*
* @param the type of the entity.
* @param the type of the attribute.
* @param entityCls the entity class. Cannot be null
.
* @param attributeName the name of the attribute. Cannot be
* null
.
* @param value the value. If there is more than one matching instance, only
* the first will be returned, and a warning will be logged.
*
* @return the matching instance, or null
if there is none.
*/
public T getUniqueByAttribute(Class entityCls,
String attributeName, Y value) {
if (entityCls == null) {
throw new IllegalArgumentException("entityCls cannot be null");
}
if (attributeName == null) {
throw new IllegalArgumentException("attributeName cannot be null");
}
TypedQuery query = createTypedQuery(entityCls, attributeName, value);
T result = null;
try {
result = query.getSingleResult();
} catch (NonUniqueResultException nure) {
LOGGER.warn("Result not unique for {}: {} = {}",
entityCls.getName(), attributeName, value);
result = query.getResultList().get(0);
} catch (NoResultException nre) {
LOGGER.debug("Result not existant for {}: {} = {}",
entityCls.getName(), attributeName, value);
}
return result;
}
/**
* Executes a query for the entities that have the specified value of the
* given attribute.
*
* @param the type of the entity.
* @param the type of the attribute.
* @param entityCls the entity class. Cannot be null
.
* @param attribute the attribute. Cannot be null
.
* @param value the value.
*
* @return the matching entities. Guaranteed not null
.
*/
public List getListByAttribute(
Class entityCls, SingularAttribute attribute, Y value) {
if (entityCls == null) {
throw new IllegalArgumentException("entityCls cannot be null");
}
if (attribute == null) {
throw new IllegalArgumentException("attribute cannot be null");
}
TypedQuery query = createTypedQuery(entityCls, attribute, value);
return query.getResultList();
}
/**
* Executes a query for the entities that have the specified values of the
* given numerical attribute.
*
* @param the type of the entity.
* @param the type of the numerical attribute.
* @param entityCls the entity class. Cannot be null
.
* @param attribute the attribute. Cannot be null
.
* @param comparator the comparator to use. Cannot be null
.
* @param value the value.
*
* @return the matching entities. Guaranteed not null
.
*/
public List getListByAttribute(Class entityCls,
SingularAttribute attribute, SqlComparator comparator,
Y value) {
if (entityCls == null) {
throw new IllegalArgumentException("entityCls cannot be null");
}
if (attribute == null) {
throw new IllegalArgumentException("attribute cannot be null");
}
if (comparator == null) {
throw new IllegalArgumentException("comparator cannot be null");
}
TypedQuery query = createTypedQuery(entityCls, attribute,
comparator, value);
return query.getResultList();
}
/**
* Executes a query for entities that have any of the given attribute
* values.
*
* @param the type of the entity.
* @param the type of the attribute.
* @param entityCls the entity class. Cannot be null
.
* @param attribute the attribute. Cannot be null
.
* @param values the values.
*
* @return the matching entities. Guaranteed not null
.
*/
public List getListByAttributeIn(Class entityCls,
SingularAttribute attribute, List values) {
if (entityCls == null) {
throw new IllegalArgumentException("entityCls cannot be null");
}
if (attribute == null) {
throw new IllegalArgumentException("attribute cannot be null");
}
TypedQuery query
= createTypedQueryIn(entityCls, attribute, values);
return query.getResultList();
}
/**
* Executes a query for entities that match the given path value. The path
* may traverse one or more entity relationships, and is followed through to
* get the resulting attribute. That attribute's value is compared to the
* given target value.
*
* @param the type of the entity class.
* @param the type of the target value and resulting attribute/column
* value.
* @param entityCls the entity class. Cannot be null
.
* @param provider provides the path from the entity to the target
* attribute/column. Cannot be null
.
* @param value the target value to compare with the resulting attribute
* value.
* @return the matching entities. Guaranteed not null
.
*/
public List getListByAttribute(Class entityCls,
QueryPathProvider provider, Y value) {
if (entityCls == null) {
throw new IllegalArgumentException("entityCls cannot be null");
}
if (provider == null) {
throw new IllegalArgumentException("provider cannot be null");
}
TypedQuery typedQuery
= createTypedQuery(entityCls, provider, value);
return typedQuery.getResultList();
}
/**
* Executes a query for entities that match the given path value. The path
* may traverse one or more entity relationships, and is followed through to
* get the resulting attribute. That attribute's value is compared to the
* given target value.
*
* @param the type of the entity class.
* @param the type of the target value and resulting attribute/column
* value.
* @param entityCls the entity class. Cannot be null
.
* @param provider provides the path from the entity to the target
* attribute/column. Cannot be null
.
* @param values the target value to compare with the resulting attribute
* value.
* @return the matching entities. Guaranteed not null
.
*/
public List getListByAttributeIn(Class entityCls,
QueryPathProvider provider, List values) {
if (entityCls == null) {
throw new IllegalArgumentException("entityCls cannot be null");
}
if (provider == null) {
throw new IllegalArgumentException("provider cannot be null");
}
TypedQuery typedQuery
= createTypedQueryIn(entityCls, provider, values);
return typedQuery.getResultList();
}
/**
* Creates a typed query for entities that match any of the specified values
* of the resulting attribute.
*
* @param the type of the entity class.
* @param the type of the target value and resulting attribute/column
* value.
* @param entityCls the entity class. Cannot be null
.
* @param provider provides the path from the entity to the target
* attribute/column. Cannot be null
.
* @param values the target value to compare with the resulting attribute
* value.
* @return
*/
private TypedQuery createTypedQueryIn(Class entityCls,
QueryPathProvider provider, List values) {
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(entityCls);
Root root = criteriaQuery.from(entityCls);
Path path = provider.getPath(root, builder);
CriteriaBuilder.In in = builder.in(path);
if (values != null) {
for (Y val : values) {
in.value(val);
}
}
return entityManager.createQuery(criteriaQuery.where(in));
}
/**
* Creates a typed query for entities that have the resulting attribute
* value.
*
* @param the type of the entity class.
* @param the type of the target attribute and target value.
* @param entityCls the entity class. Cannot be null
.
* @param provider the attribute to compare.
* @param value the target value for the given attribute.
* @return a typed query that contains the given criteria.
*/
private TypedQuery createTypedQuery(Class entityCls,
QueryPathProvider provider, Y value) {
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(entityCls);
Root root = criteriaQuery.from(entityCls);
Path path = provider.getPath(root, builder);
return entityManager.createQuery(criteriaQuery.where(
builder.equal(path, value)));
}
/**
* Creates a typed query for entities that match any of the specified values
* of the given attribute.
*
* @param the type of the entity class.
* @param
* @param entityCls
* @param attribute
* @param values
* @return
*/
private TypedQuery createTypedQueryIn(Class entityCls,
SingularAttribute attribute, List values) {
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(entityCls);
Root root = criteriaQuery.from(entityCls);
Path path = root.get(attribute);
CriteriaBuilder.In in = builder.in(path);
if (values != null) {
for (Y val : values) {
in.value(val);
}
}
return entityManager.createQuery(criteriaQuery.where(in));
}
/**
* Creates a typed query for entities that have the given attribute value.
*
* @param the type of the entity class.
* @param the type of the target attribute and target value.
* @param attribute the attribute to compare.
* @param value the target value for the given attribute.
* @return a typed query that contains the given criteria.
*/
private TypedQuery createTypedQuery(Class entityCls,
SingularAttribute attribute, Y value) {
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(entityCls);
Root root = criteriaQuery.from(entityCls);
Path path = root.get(attribute);
return entityManager.createQuery(criteriaQuery.where(
builder.equal(path, value)));
}
/**
* Creates a typed query for entities that have the given attribute value.
*
* @param the type of the entity to return.
* @param the type of the attribute.
* @param attribute the attribute.
* @param value the target value for the given attribute.
* @return a typed query that contains the given criteria.
*/
private TypedQuery createTypedQuery(Class entityCls,
String attributeName, Y value) {
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(entityCls);
Root root = criteriaQuery.from(entityCls);
Path path = root.get(attributeName);
return entityManager.createQuery(criteriaQuery.where(
builder.equal(path, value)));
}
/**
* Creates a typed query for entities with the given numerical attribute
* value.
*
* @param the type of the entity to return.
* @param the type of the attribute.
* @param entityCls the entity's class.
* @param attribute the attribute.
* @param comparator the comparator.
* @param value the value or value threshold.
* @return a typed query with the given criteria.
*/
private TypedQuery createTypedQuery(
Class entityCls, SingularAttribute attribute,
SqlComparator comparator, Y value) {
EntityManager entityManager = this.entityManagerProvider.get();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = builder.createQuery(entityCls);
Root root = criteriaQuery.from(entityCls);
Path path = root.get(attribute);
Predicate pred;
switch (comparator) {
case LESS_THAN:
pred = builder.lt(path, value);
break;
case LESS_THAN_OR_EQUAL_TO:
pred = builder.le(path, value);
break;
case EQUAL_TO:
pred = builder.equal(path, value);
break;
case NOT_EQUAL_TO:
pred = builder.notEqual(path, value);
break;
case GREATER_THAN_OR_EQUAL_TO:
pred = builder.ge(path, value);
break;
case GREATER_THAN:
pred = builder.gt(path, value);
break;
default:
throw new AssertionError("Invalid SQLComparator: "
+ comparator);
}
return entityManager.createQuery(criteriaQuery.where(pred));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy