package io.oasp.module.jpa.dataaccess.api;
import java.util.List;
import net.sf.mmm.util.entity.api.PersistenceEntity;
import net.sf.mmm.util.exception.api.ObjectNotFoundUserException;
/**
* This is the interface for a <em>Data Access Object</em> (DAO). It acts as a manager responsible for the persistence
* operations on a specific {@link PersistenceEntity entity} {@literal <E>}.<br/>
* This is base interface contains the CRUD operations:
* <ul>
* <li>Create: call {@link #save(PersistenceEntity)} on a new entity.</li>
* <li>Retrieve: use <code>find*</code> methods such as {@link #findOne(Object)}. More specific queries will be added in
* dedicated DAO interfaces.</li>
* <li>Update: done automatically by JPA vendor (hibernate) on commit or call {@link #save(PersistenceEntity)} to
* {@link javax.persistence.EntityManager#merge(Object) merge} an entity.</li>
* <li>Delete: call {@link #delete(PersistenceEntity)} or {@link #delete(Object)}.</li>
* </ul>
* For each (non-abstract) implementation of {@link PersistenceEntity entity} <code>MyEntity</code> you should create an
* interface interface <code>MyEntityDao</code> that inherits from this {@link GenericDao} interface. Also you create an
* implementation of that interface <code>MyEntityDaoImpl</code> that you derive from
* {@link io.oasp.module.jpa.dataaccess.base.AbstractGenericDao}.
*
* @param <ID> is the generic type if the {@link PersistenceEntity#getId() primary key}.
* @param <E> is the generic type of the {@link PersistenceEntity}.
*
*/
public interface GenericDao<ID, E extends PersistenceEntity<ID>> {
/**
* Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
* entity instance completely.
*
* @param entity the {@link PersistenceEntity entity} to save
* @return the saved entity
*/
E save(E entity);
/**
* Saves all given entities.
*
* @param entities the {@link PersistenceEntity entities} to save
*/
void save(Iterable<? extends E> entities);
/**
* Retrieves an entity by its id.
*
* @param id must not be {@literal null}.
* @return the entity with the given id or {@literal null} if none found
* @throws ObjectNotFoundUserException if the requested entity does not exists (use {@link #findOne(Object)} to
* prevent).
*/
E find(ID id) throws ObjectNotFoundUserException;
/**
* Retrieves an entity by its id.
*
* @param id must not be {@literal null}.
* @return the entity with the given id or {@literal null} if none found
* @throws IllegalArgumentException if {@code id} is {@code null}
*/
E findOne(ID id) throws IllegalArgumentException;
/**
* Returns whether an entity with the given id exists.
*
* @param id must not be {@literal null}.
* @return true if an entity with the given id exists, {@literal false} otherwise
*/
boolean exists(ID id);
/**
* Returns all instances of the type with the given IDs.
*
* @param ids are the IDs of all entities to retrieve e.g. as {@link java.util.List}.
* @return an {@link Iterable} with all {@link PersistenceEntity entites} for the given <code>ids</code>.
*/
List<E> findAll(Iterable<ID> ids);
/**
* Deletes the entity with the given id.
*
* @param id must not be {@literal null}.
* @throws IllegalArgumentException in case the given {@code id} is {@code null}
*/
void delete(ID id) throws IllegalArgumentException;
/**
* Deletes a given entity.
*
* @param entity the {@link PersistenceEntity entity} to delete
*/
void delete(E entity);
/**
* Deletes the given entities.
*
* @param entities the {@link PersistenceEntity entities} to delete
*/
void delete(Iterable<? extends E> entities);
/**
* Enforces to increment the {@link PersistenceEntity#getModificationCounter() modificationCounter} e.g. to enforce
* that a parent object gets locked when its children are modified.<br>
* As an example we assume that we have the two optimistic locked entities {@code Order} and its contained
* {@code OrderPosition}. By default the users can modify an {@code Order} and each of its {@code OrderPosition}s in
* parallel without getting a locking conflict. This can be desired. However, it can also be a demand that an
* {@code Order} gets approved and the user doing that is responsible for the total price as the sum of the prices of
* each {@code OrderPosition}. Now if another user is adding or changing an {@code OrderPostion} belonging to that
* {@code Order} in parallel the {@code Order} will get approved but the approved total price will differ from what
* the user has actually seen when he clicked on approve. To prevent this the use-case to modify an
* {@code OrderPosition} can use this method to trigger a locking on the associated {@code Order}. The implication is
* also that two users changing an {@code OrderPosition} associated with the same {@code Order} in parallel will get a
* conflict.
*
* @param entity that is getting checked.
*/
void forceIncrementModificationCounter(E entity);
}