package de.flower.rmt.repository.impl; import com.google.common.collect.Lists; import com.mysema.query.support.Expressions; import com.mysema.query.types.Ops; import com.mysema.query.types.OrderSpecifier; import com.mysema.query.types.Path; import com.mysema.query.types.Predicate; import com.mysema.query.types.expr.BooleanExpression; import de.flower.common.model.db.entity.AbstractBaseEntity; import de.flower.common.model.db.entity.AbstractBaseEntity_; import de.flower.common.model.db.entity.QAbstractBaseEntity; import de.flower.common.model.db.type.ObjectStatus; import de.flower.common.repository.ExtendedQueryDslJpaRepository; import de.flower.common.util.Check; import de.flower.rmt.model.db.entity.AbstractClubRelatedEntity; import de.flower.rmt.model.db.entity.AbstractClubRelatedEntity_; import de.flower.rmt.model.db.entity.Club; import de.flower.rmt.repository.IRepository; import de.flower.rmt.repository.Specs; import de.flower.rmt.security.ISecurityService; import org.apache.commons.lang3.StringUtils; import org.hibernate.LockOptions; import org.hibernate.Session; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specifications; import org.springframework.data.jpa.repository.support.JpaEntityInformation; import javax.persistence.EntityManager; import java.io.Serializable; import java.util.List; /** * @author flowerrrr */ public class BaseRepository<T extends AbstractBaseEntity, ID extends Serializable> extends ExtendedQueryDslJpaRepository<T, ID> implements IRepository<T, ID> { private EntityManager em; private JpaEntityInformation<T, ID> entityInformation; private ISecurityService securityService; public BaseRepository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager, final ISecurityService securityService) { super(entityInformation, entityManager); this.em = entityManager; this.entityInformation = entityInformation; this.securityService = securityService; } public void reattach(T entity) { Check.notNull(entity); Session session = (Session) em.getDelegate(); session.buildLockRequest(LockOptions.NONE).lock(entity); } public void detach(T entity) { Check.notNull(entity); Session session = (Session) em.getDelegate(); session.evict(entity); } public void softDelete(T entity) { entity.setObjectStatus(ObjectStatus.DELETED); save(entity); } //*************************************************************** // Filtering of database reads. // Filters out all deleted entities. // Multi tenancy support. // Add club of currently logged in user to query where clause. // Filtering is still suboptimal, as only findAll calls gets filtered. //*************************************************************** @Override public T findOne(final Predicate predicate, final Path<?>... attributes) { // TODO (flowerrrr - 29.04.12) use paging call with setMaxresult = 2 List<T> list = super.findAll(predicate, attributes); if (list.isEmpty()) { return null; } else if (list.size() > 1) { throw new IllegalArgumentException("Query returned more then one record."); } else { return list.get(0); } } @Override public List<T> findAll(final Predicate predicate) { return Lists.newArrayList(super.findAll(getDefaultPredicate().and(predicate))); } @Override public List<T> findAll() { return super.findAll(getDefaultPredicate()); } @Override public List<T> findAll(final Specification<T> spec) { Specifications<T> defaultFilter = getDefaultFilter(); return super.findAll(defaultFilter.and(spec)); } @Override @Deprecated // use querydsl predicates if possible public Page<T> findAll(final Specification<T> spec, final Pageable pageable) { Specifications<T> defaultFilter = getDefaultFilter(); return super.findAll(defaultFilter.and(spec), pageable); } @Override public Page<T> findAll(Predicate predicate, Pageable pageable) { return super.findAll(getDefaultPredicate().and(predicate), pageable); } @Override public List<T> findAll(final Predicate predicate, final Path<?>... fetchAttributes) { return super.findAll(getDefaultPredicate().and(predicate), fetchAttributes); } @Override public Page<T> findAll(final Predicate predicate, final Pageable pageable, final Path<?>... fetchAttributes) { return super.findAll(getDefaultPredicate().and(predicate), pageable, fetchAttributes); } @Override public List<T> findAll(final Predicate predicate, final OrderSpecifier<?> order, final Path<?>... fetchAttributes) { return super.findAll(getDefaultPredicate().and(predicate), order, fetchAttributes); } @Override public Page<T> findAll(final Pageable pageable) { return super.findAll(getDefaultPredicate(), pageable); } @Override public List<T> findAll(final Sort sort) { throw new UnsupportedOperationException("Feature not implemented!"); } @Override @Deprecated // use querydsl predicates if possible public List<T> findAll(final Specification<T> spec, final Sort sort) { throw new UnsupportedOperationException("Feature not implemented!"); } @Override public long count() { return super.count(getDefaultPredicate()); } @Override public long count(final Predicate predicate) { return super.count(getDefaultPredicate().and(predicate)); } private BooleanExpression getDefaultPredicate() { BooleanExpression predicate = isNotDeleted(); Class<T> domainClass = entityInformation.getJavaType(); if (AbstractClubRelatedEntity.class.isAssignableFrom(domainClass)) { predicate = predicate.and(hasClub()); } return predicate; } @Deprecated // use querydsl predicates if possible private Specifications<T> getDefaultFilter() { Specifications<T> specs = Specifications.where(getNotDeleted()); Class<T> domainClass = entityInformation.getJavaType(); if (AbstractClubRelatedEntity.class.isAssignableFrom(domainClass)) { specs = specs.and(getHasClub()); } return specs; } private BooleanExpression isNotDeleted() { // next line does not work, will cause runtime error // QAbstractBaseEntity.abstractBaseEntity.objectStatus.ne(ObjectStatus.DELETED); String variable = StringUtils.uncapitalize(entityInformation.getEntityName()); Path<? extends AbstractBaseEntity> root = Expressions.path(entityInformation.getJavaType(), variable); return new QAbstractBaseEntity(root).objectStatus.ne(ObjectStatus.DELETED); } @Deprecated // use querydsl predicates if possible private Specification<T> getNotDeleted() { Specification notDeleted = Specifications.not(Specs.eq(AbstractBaseEntity_.objectStatus, ObjectStatus.DELETED)); return notDeleted; } private BooleanExpression hasClub() { String variable = StringUtils.uncapitalize(entityInformation.getEntityName()); Path<?> root = Expressions.path(entityInformation.getJavaType(), variable); Path<Club> club = Expressions.path(Club.class, root, "club"); return Expressions.predicate(Ops.EQ_OBJECT, club, Expressions.constant(getClub())); } @Deprecated // use querydsl predicates if possible private Specification<T> getHasClub() { Specification hasClub = Specs.eq(AbstractClubRelatedEntity_.club, getClub()); return hasClub; } private Club getClub() { return securityService.getUser().getClub(); } }