All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sourceforge.jbizmo.commons.jpa.AbstractRepository Maven / Gradle / Ivy

/*
 * This file is part of JBizMo, a set of tools, libraries and plug-ins
 * for modeling and creating Java-based enterprise applications.
 * For more information visit:
 *
 * http://sourceforge.net/projects/jbizmo/
 *
 * This software is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this software; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
 */
package net.sourceforge.jbizmo.commons.jpa;

import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import net.sourceforge.jbizmo.commons.jpa.util.JPAConstructorQueryStatementGenerator;
import net.sourceforge.jbizmo.commons.jpa.util.JPAQueryStatementGenerator;
import net.sourceforge.jbizmo.commons.search.dto.SearchDTO;
import net.sourceforge.jbizmo.commons.search.exception.GeneralSearchException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 

* Abstract base class for all repositories. This class can be used in managed and unmanaged environments! *

*

* Copyright 2019 (C) by Martin Ganserer *

* @author Martin Ganserer * @version 1.0.0 * @param the type of an entity a specific repository should work with * @param

the type of the primary key attribute */ public abstract class AbstractRepository { // The default number of returned items for small lists public static final int SMALL_LIST_SIZE = 50; // The default number of returned items public static final int DEFAULT_LIST_SIZE = 1000; // The maximum number of returned items if no upper limit has been defined public static final int MAX_LIST_SIZE = 10000; public static final String WILDCARD = "%"; private static final Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass()); protected @PersistenceContext EntityManager em; protected Class entityType; /** * Default constructor */ @SuppressWarnings("unchecked") protected AbstractRepository() { Type type = getClass().getGenericSuperclass(); if (!(type instanceof ParameterizedType)) type = getClass().getSuperclass().getGenericSuperclass(); this.entityType = (Class) ((ParameterizedType) type).getActualTypeArguments()[0]; } /** * Constructor * @param em */ protected AbstractRepository(EntityManager em) { this(); this.em = em; } /** * @return the entity manager */ public EntityManager getEntityManager() { return em; } /** * Find and attach an entity that has the provided ID * @param id the ID of the entity to search for * @return the entity or null if it could not be found */ public T findById(P id) { return em.find(entityType, id); } /** * Find and attach an entity that has the provided ID * @param id the ID of the entity to search for * @param mustExist * @throws EntityNotFoundException if the entity could not be found and the parameter mustExist is true * @return the entity with the provided ID or null if it could not be found */ public T findById(P id, boolean mustExist) { final T entity = findById(id); if (entity != null) return entity; if (mustExist) throw new EntityNotFoundException("An entity of type '" + entityType.getName() + "' with ID '" + id + "' doesn't exist!"); return null; } /** * Find and attach an entity by using the given type and the primary key * @param the type of the entity to be returned * @param type defines the expected return type * @param id the ID of the entity to search for * @return the attached entity or null if it could not be found */ public X findById(Class type, Object id) { return em.find(type, id); } /** * Get all entities * @return a list that contains all entities */ public List findAll() { final CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(entityType); final Root root = criteriaQuery.from(entityType); final CriteriaQuery query = criteriaQuery.select(root); return em.createQuery(query).getResultList(); } /** * Check if an entity with the provided ID exists * @param id the ID of the entity to search for * @return true if the entity with this ID could be found */ public boolean existsById(P id) { return findById(id) != null; } /** * Get an entity instance whose state may be lazily fetched * @param id the ID to search for * @throws EntityNotFoundException if the entity doesn't exist * @return the entity reference */ public T getReference(P id) { return em.getReference(entityType, id); } /** * Get an entity instance whose state may be lazily fetched * @param the type of the entity to be returned * @param type defines the expected return type * @param id the ID of the entity to search for * @throws EntityNotFoundException if the entity doesn't exist * @return the entity reference */ public X getReference(Class type, Object id) { return em.getReference(type, id); } /** * Persist the given entity * @param entity the entity to be persisted */ public void persist(T entity) { em.persist(entity); } /** * Persist the given entity * @param entity the entity to be persisted * @param performFlush flag that controls if the database synchronization should be performed immediately * @param performRefresh flag that controls if a refresh operation should be performed after persist * @return the persisted entity */ public T persist(T entity, boolean performFlush, boolean performRefresh) { em.persist(entity); if (performFlush) em.flush(); if (performRefresh) em.refresh(entity); return entity; } /** * Persist a list of entities * @param entities a list of entities to be persisted */ public void persist(List entities) { entities.stream().forEach(this::persist); } /** * Merge the given entity * @param entity the entity to be merged * @return the merged entity instance */ public T merge(T entity) { return em.merge(entity); } /** * Merge the given entity * @param entity the entity to be merged * @param performFlush flag that controls if the database synchronization should be performed immediately * @return the merged entity instance */ public T merge(T entity, boolean performFlush) { em.merge(entity); if (performFlush) em.flush(); return entity; } /** * Merge a list of entities * @param entities a list of entities to be merged * @return the list of merged entities */ public List merge(List entities) { return entities.stream().map(this::merge).toList(); } /** * Delete the given entity * @param entity the entity to be deleted */ public void deleteEntity(T entity) { em.remove(entity); } /** * Delete the given entity * @param id the ID of the entity to be deleted * @throws EntityNotFoundException if the entity doesn't exist */ public void delete(P id) { final T entityToDelete = findById(id, true); em.remove(entityToDelete); } /** * Delete a list of entities * @param entities a list of entities that should be deleted * @throws EntityNotFoundException if at least one entity in the list doesn't exist */ public void delete(Collection entities) { entities.forEach(this::deleteEntity); } /** * Delete all persistent entities */ public void deleteAll() { final CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); final CriteriaDelete criteriaDelete = criteriaBuilder.createCriteriaDelete(entityType); criteriaDelete.from(entityType); em.createQuery(criteriaDelete).executeUpdate(); } /** * Search for entities by using the given query statement * @param statement the query statement to be executed * @return a list of entities that match the filter criteria */ public List search(String statement) { return search(statement, MAX_LIST_SIZE); } /** * Search for entities by using the given query statement and limit the number of results * @param statement the query statement to be executed * @param maxResults the maximum number of entities to be returned * @return a list of entities that match the filter criteria */ public List search(String statement, int maxResults) { return search(statement, maxResults, 0, null); } /** * Search for entities by using the given query statement with paging and parameters * @param statement the query statement to be executed * @param maxResults the maximum number of entities to be returned * @param startIndex the position of the first result to retrieve * @param addParams a map that contains the values for all named query parameters * @return a list of entities that match the filter criteria */ public List search(String statement, int maxResults, int startIndex, Map addParams) { final TypedQuery query = em.createQuery(statement, entityType); query.setMaxResults(maxResults); query.setFirstResult(startIndex); if (addParams != null) addParams.keySet().forEach(param -> query.setParameter(param, addParams.get(param))); return query.getResultList(); } /** * Search for entities by using the given query statement * @param the type parameter * @param statement the query statement to be executed * @param type defines the expected return type * @return a list of entities that match the filter criteria */ public List search(String statement, Class type) { return search(statement, MAX_LIST_SIZE, 0, null, type); } /** * Search for entities by using the given query statement * @param the type parameter * @param statement the query statement to be executed * @param maxResults the maximum number of entities to be returned * @param type defines the expected return type * @return a list of entities that match the filter criteria */ public List search(String statement, int maxResults, Class type) { return search(statement, maxResults, 0, null, type); } /** * Search for entities * @param the type parameter * @param statement the query statement to be executed * @param maxResults the maximum number of entities to be returned * @param startIndex the position of the first result to retrieve * @param addParams a map that contains the values for all named query parameters * @param type defines the expected return type * @return a list of entities that match the filter criteria */ public List search(String statement, int maxResults, int startIndex, Map addParams, Class type) { final TypedQuery query = em.createQuery(statement, type); query.setMaxResults(maxResults); query.setFirstResult(startIndex); if (addParams != null) addParams.forEach(query::setParameter); return query.getResultList(); } /** * Search for entities by using the given {@link SearchDTO} * @param the type parameter * @param searchObj an object that contains all information for building the query statement * @param type defines the expected return type * @return a list of entities that match the filter criteria * @throws GeneralSearchException if the search operation has failed */ public List search(SearchDTO searchObj, Class type) { return search(searchObj, type, null); } /** * Search for entities by using the given {@link SearchDTO} * @param the type parameter * @param searchObj an object that contains all information for building the query statement * @param type defines the expected return type * @param selectTokens an optional list with select tokens that is used to create a JPA constructor query * @return a list of entities that match the filter criteria * @throws GeneralSearchException if the search operation has failed */ public List search(SearchDTO searchObj, Class type, List selectTokens) { if (selectTokens != null) { final var queryGenerator = new JPAConstructorQueryStatementGenerator(); queryGenerator.setClassName(type.getName()); queryGenerator.setSelectTokens(selectTokens); searchObj.setFromClause(queryGenerator.createStatement() + searchObj.getFromClause().trim()); } final String statement = JPAQueryStatementGenerator.createStatement(searchObj); try { final Map addParams = JPAQueryStatementGenerator.createParameters(searchObj); return search(statement, searchObj.getMaxResult(), searchObj.getStartIndex(), addParams, type); } catch (final Exception e) { logger.error("Error while performing query with statement '{}'!", statement, e); throw new GeneralSearchException(e, true); } } /** * Count the number of all persistent entities * @return the count result */ public long count() { final CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder(); final CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class); criteriaQuery.select(criteriaBuilder.count(criteriaQuery.from(entityType))); return em.createQuery(criteriaQuery).getSingleResult(); } /** * Perform a count operation by using the given {@link SearchDTO} * @param searchObj an object that contains all information for building the query statement * @return the count result * @throws IllegalStateException if the values of the named query parameters could not be parsed */ public long count(SearchDTO searchObj) { final String statement = JPAQueryStatementGenerator.createCountStatement(searchObj); final var errorMsg = "Error while parsing additional query parameters!"; Map addParams = null; try { addParams = JPAQueryStatementGenerator.createParameters(searchObj); } catch (final Exception e) { logger.error(errorMsg, e); } if (addParams == null) throw new IllegalStateException(errorMsg); final TypedQuery query = em.createQuery(statement, Long.class); addParams.forEach(query::setParameter); return query.getSingleResult(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy