com.github.adminfaces.persistence.service.CrudService Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of admin-persistence Show documentation
Show all versions of admin-persistence Show documentation
Provides CRUD utilities for CDI, JPA and JSF based applications.
package com.github.adminfaces.persistence.service;
import com.github.adminfaces.persistence.model.AdminSort;
import com.github.adminfaces.persistence.model.Filter;
import com.github.adminfaces.persistence.model.PersistenceEntity;
import org.apache.deltaspike.data.api.criteria.Criteria;
import org.apache.deltaspike.data.api.criteria.CriteriaSupport;
import org.apache.deltaspike.data.impl.handler.CriteriaSupportHandler;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.criteria.JoinType;
import javax.persistence.metamodel.*;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.logging.Logger;
import org.apache.deltaspike.data.impl.criteria.QueryCriteria;
/**
* @author rmpestano
* Utility service for crud operations
*/
@Service
public class CrudService extends CriteriaSupportHandler implements CriteriaSupport, Serializable {
private static final Logger LOG = Logger.getLogger(CrudService.class.getName());
protected Class entityClass;
protected Class entityKey;
@Inject
protected EntityManager entityManager;
@Inject
protected void CrudService(InjectionPoint ip) {
if (ip != null && ip.getType() != null && ip.getMember() != null) {
try {
//Used for generic service injection, e.g: @Inject @Service CrudService
resolveEntity(ip);
} catch (Exception e) {
LOG.warning(String.format("Could not resolve entity type and entity key via injection point [%s]. Now trying to resolve via generic superclass of [%s].", ip.getMember().getName(), getClass().getName()));
}
}
if (entityClass == null) {
//Used on service inheritance, e.g: MyService extends CrudService
entityClass = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
entityKey = (Class) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[1];
}
}
private void resolveEntity(InjectionPoint ip) {
ParameterizedType type = (ParameterizedType) ip.getType();
Type[] typeArgs = type.getActualTypeArguments();
entityClass = (Class) typeArgs[0];
entityKey = (Class) typeArgs[1];
}
public List paginate(Filter filter) {
Criteria criteria = configRestrictions(filter);
String sortField = filter.getSortField();
if (sortField != null) {
SingularAttribute sortAttribute = entityManager.getMetamodel().entity(entityClass).getSingularAttribute(sortField);
if (filter.getAdminSort().equals(AdminSort.UNSORTED)) {
filter.setAdminSort(AdminSort.ASCENDING);
}
if (filter.getAdminSort().equals(AdminSort.ASCENDING)) {
criteria.orderAsc(sortAttribute);
} else {
criteria.orderDesc(sortAttribute);
}
}
return criteria.createQuery()
.setFirstResult(filter.getFirst())
.setMaxResults(filter.getPageSize())
.getResultList();
}
/**
* Called before pagination, should be overriden. By default there is no restrictions.
*
* @param filter used to create restrictions
* @return a criteria with configured restrictions
*/
protected Criteria configRestrictions(Filter filter) {
return criteria();
}
public void insert(T entity) {
if (entity == null) {
throw new RuntimeException("Record cannot be null");
}
beforeInsert(entity);
entityManager.persist(entity);
afterInsert(entity);
}
public void remove(T entity) {
if (entity == null) {
throw new RuntimeException("Record cannot be null");
}
if (entity.getId() == null) {
throw new RuntimeException("Record cannot be transient");
}
beforeRemove(entity);
if (!entityManager.contains(entity)) {
entity = entityManager.find(entityClass, entity.getId());
}
entityManager.remove(entity);
afterRemove(entity);
}
public void remove(List entities) {
if (entities == null) {
throw new RuntimeException("Entities cannot be null");
}
for (T t : entities) {
this.remove(t);
}
}
public T update(T entity) {
if (entity == null) {
throw new RuntimeException("Record cannot be null");
}
if (entity.getId() == null) {
throw new RuntimeException("Record cannot be transient");
}
beforeUpdate(entity);
entity = entityManager.merge(entity);
entityManager.flush();
afterUpdate(entity);
return entity;
}
public T saveOrUpdate(T entity) {
if (entity == null) {
throw new RuntimeException("Record cannot be null");
}
if (entity.getId() == null) {
insert(entity);
} else {
entity = update(entity);
}
return entity;
}
/**
* Count all
*/
public Long count() {
return count(criteria());
}
/**
* Count by filter using configRestrictions to count
*
* @param filter
* @return
*/
public Long count(Filter filter) {
return count(configRestrictions(filter));
}
/**
* Count using a pre populated criteria
*
* @param criteria
* @return
*/
public Long count(Criteria criteria) {
SingularAttribute super T, PK> id = getEntityManager().getMetamodel().entity(entityClass).getId(entityKey);
return criteria.select(Long.class, countDistinct(id))
.getSingleResult();
}
public T findById(Serializable id) {
T entity = entityManager.find(entityClass, id);
if (entity == null) {
LOG.warning(String.format("Record with id %s not found for entity %s.", id, entityClass.getName()));
}
return entity;
}
/**
* A 'criteria by example' will be created using an example entity. It will use eq
for comparing 'simple' attributes,
* for oneToOne
associations the entity PK will be compared and for oneToMany association an in
for comparing associated entities PKs.
*
* @param example An entity whose attribute's value will be used for creating a criteria
* @param usingAttributes attributes from example entity to consider.
* @return A criteria restricted by example.
* @throws RuntimeException If no attribute is provided.
*/
public Criteria example(T example, Attribute... usingAttributes) {
return example(criteria(), example, usingAttributes);
}
/**
* This example criteria will add restrictions to an existing criteria based on an example entity. It will use eq
for comparing 'simple' attributes,
* for oneToOne
associations the entity PK will be compared and for oneToMany association an in
for comparing associated entities PKs
*
* @param criteria a criteria to add restrictions based on the example entity.
* @param example An entity whose attribute's value will be used for creating a criteria
* @param usingAttributes attributes from example entity to consider.
* @return A criteria restricted by example.
* @throws RuntimeException If no attribute is provided.
*/
public Criteria example(Criteria criteria, T example, Attribute... usingAttributes) {
if (criteria == null) {
criteria = criteria();
}
if (usingAttributes == null || usingAttributes.length == 0) {
throw new RuntimeException("Please provide attributes to example criteria.");
}
for (Attribute usingAttribute : usingAttributes) {
if (usingAttribute instanceof SingularAttribute) {
addEqExampleRestriction(criteria, example, usingAttribute);
} else if (usingAttribute instanceof PluralAttribute) {
addInExampleRestriction(criteria, example, usingAttribute);
}
}
return criteria;
}
private void addEqExampleRestriction(Criteria criteria, T example, Attribute attribute) {
if (attribute.getJavaMember() instanceof Field) {
Field field = (Field) attribute.getJavaMember();
field.setAccessible(true);
try {
Object value = field.get(example);
if (value != null) {
LOG.fine(String.format("Adding an 'eq' restriction on attribute %s using value %s.", attribute.getName(), value));
criteria.eq((SingularAttribute) attribute, value);
}
} catch (IllegalAccessException e) {
LOG.warning(String.format("Could not get value from field %s of entity %s.", field.getName(), example.getClass().getName()));
}
}
}
private void addInExampleRestriction(Criteria criteria, T example, Attribute attribute) {
PluralAttribute listAttribute = (PluralAttribute) attribute;
Class joinClass = listAttribute.getElementType().getJavaType();
Criteria joinCriteria = where(joinClass, JoinType.LEFT);
if (listAttribute instanceof ListAttribute) {
criteria.join((ListAttribute) listAttribute, joinCriteria);
} else if (listAttribute instanceof SetAttribute) {
criteria.join((SetAttribute) listAttribute, joinCriteria);
} else if (listAttribute instanceof MapAttribute) {
criteria.join((MapAttribute) listAttribute, joinCriteria);
} else if (listAttribute instanceof CollectionAttribute) {
criteria.join((CollectionAttribute) listAttribute, joinCriteria);
}
if (attribute.getJavaMember() instanceof Field) {
Field field = (Field) attribute.getJavaMember();
field.setAccessible(true);
try {
Object value = field.get(example);
if (value != null) {
LOG.fine(String.format("Adding an ín'restriction on attribute %s using value %s.", attribute.getName(), value));
Collection association = (Collection) value;
SingularAttribute id = getEntityManager().getMetamodel().entity(listAttribute.getElementType().getJavaType()).getId(association.iterator().next().getId().getClass());
List ids = new ArrayList<>();
for (PersistenceEntity persistenceEntity : association) {
ids.add(persistenceEntity.getId());
}
joinCriteria.in(id, ids);
}
} catch (IllegalAccessException e) {
LOG.warning(String.format("Could not get value from field %s of entity %s.", field.getName(), example.getClass().getName()));
}
}
}
/**
* A 'criteria by example' will be created using an example entity. ONLY String
attributes will be considered.
* It will use 'likeIgnoreCase' for comparing STRING attributes of the example entity.
*
* @param example An entity whose attribute's value will be used for creating a criteria
* @param usingAttributes attributes from example entity to consider.
* @return A criteria restricted by example using 'likeIgnoreCase' for comparing attributes
* @throws RuntimeException If no attribute is provided.
*/
public Criteria exampleLike(T example, SingularAttribute... usingAttributes) {
return exampleLike(criteria(), example, usingAttributes);
}
/**
* @param criteria a pre populated criteria to add example based like
restrictions
* @param example An entity whose attribute's value will be used for creating a criteria
* @param usingAttributes attributes from example entity to consider.
* @return A criteria restricted by example using likeIgnoreCase
for comparing attributes
* @throws RuntimeException If no attribute is provided.
*/
public Criteria exampleLike(Criteria criteria, T example, SingularAttribute... usingAttributes) {
if (usingAttributes == null || usingAttributes.length == 0) {
throw new RuntimeException("Please provide attributes to example criteria.");
}
if (criteria == null) {
criteria = criteria();
}
for (SingularAttribute attribute : usingAttributes) {
if (attribute.getJavaMember() instanceof Field) {
Field field = (Field) attribute.getJavaMember();
field.setAccessible(true);
try {
Object value = field.get(example);
if (value != null) {
LOG.fine(String.format("Adding restriction by example on attribute %s using value %s.", attribute.getName(), value));
criteria.likeIgnoreCase(attribute, value.toString());
}
} catch (IllegalAccessException e) {
LOG.warning(String.format("Could not get value from field %s of entity %s.", field.getName(), example.getClass().getName()));
}
}
}
return criteria;
}
public Class getEntityKey() {
return entityKey;
}
@Override
public Class getEntityClass() {
return entityClass;
}
@Override
public EntityManager getEntityManager() {
return entityManager;
}
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
public void beforeInsert(T entity) {
}
public void afterInsert(T entity) {
}
public void beforeUpdate(T entity) {
}
public void afterUpdate(T entity) {
}
public void beforeRemove(T entity) {
}
public void afterRemove(T entity) {
}
/**
* Creates an array of Ids (pks) from a list of entities.
* It is useful when working with `in clauses` on DeltaSpike criteria
* because the API only support primitive arrays.
*
* @param entities list of entities to create
* @param idsType the type of the pk list, e.g new Long[0]
*
* @return primitive array containing entities pks.
*/
@SuppressWarnings("unchecked")
protected ID[] toListOfIds(Collection extends PersistenceEntity> entities, ID[] idsType) {
List ids = new ArrayList<>();
for (PersistenceEntity entity : entities) {
ids.add((ID) entity.getId());
}
return (ID[]) ids.toArray(idsType);
}
/**
*
* @param entityClass
* @return a criteria for underlying entityClass
*/
public Criteria criteria(Class entityClass) {
return new QueryCriteria<>(entityClass, entityClass, getEntityManager());
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy