package de.skuzzle.polly.sdk; import java.util.Arrays; import java.util.Collection; import java.util.List; import de.skuzzle.polly.sdk.exceptions.DatabaseException; public interface PersistenceManagerV2 { /** * Encapsulates parameters for a database query. * * @author Simon Taddiken */ public final static class Param { private final Object[] params; public Param(Object...params) { this.params = params; } public Param(String[] params) { this.params = new Object[params.length]; for (int i = 0; i < params.length; ++i) { this.params[i] = params[i]; } } public Object[] getParams() { return this.params; } @Override public String toString() { return Arrays.toString(this.params); } } /** * This represents an atomic database write operation. Instances of this interface * can be used to perform multiple write operations to the database within a single * transaction. * * <p>The great advantage of using this class to perform multiple operations at once * is, that you may decide to perform all the changes asynchronously without having * to change a single line of code.</p> * * @author Simon Taddiken */ @FunctionalInterface public interface Atomic { /** * This method is called to perform all the write operations to the database. The * provided {@link Write} instance will always support the * {@link Write#read() read} operation. * * @param write Instance to write to the database. * @throws DatabaseException If a database error occurred */ public void perform(Write write) throws DatabaseException; } /** * The Write interface provides access to insert or remove entries from the database. * Optionally, a Write instance may support reading values by providing a * {@link Read} instance via {@link #read()}. * * <p>All modifications made using this class will first be submitted when calling * the {@link #close()} method. Instances of this class must always be used within * a try-resources block, otherwise deadlocks or database corruption may occur.</p> * @author Simon Taddiken */ public interface Write extends AutoCloseable { /** * Marks each of the provided elements to be persisted upon closing this Write * instance. * * @param elements The elements to persist. * @return This instance for method chaining. */ public <T> Write all(Iterable<T> elements); /** * Marks a single element to be persisted upon closing this Write instance. * * @param obj The object to persist. * @return This instance for method chaining. */ public <T> Write single(T obj); /** * Marks a single element to be removed upon closing this Write instance. * * @param obj The object to persist. * @return This instance for method chaining. */ public <T> Write remove(T obj); /** * Marks each of the provided elements to be removed upon closing this Write * instance. * * @param elements The elements to remove. * @return This instance for method chaining. */ public <T> Write removeAll(Iterable<T> elements); /** * Provides a Read instance to read values from the database within the current * lock scope. The returned Read instance does not need to be closed as it will * be closed automatically when this instance is closed. * * <p>This operation is optional and may throw an * {@link UnsupportedOperationException}. Methods returning a Write instance are * required to document whether the returned instance supports reading or not.</p> * * @return A Read instance to read values from the database. */ public Read read(); /** * Closes this Write instance and submits all changes to the database. Also, all * locks are released, even if an error occurred. * * @throws DatabaseException If submitting the changes to the database failed. */ @Override public void close() throws DatabaseException; } /** * Provides API to read objects from the database. * * @author Simon Taddiken */ public interface Read extends AutoCloseable { /** * Finds an entity using its primary key. * * Usage: * <pre> * find(Employee.class, employeeId); * </pre> * @param type The entities type. * @param key The primary key of the entity to find. * @return The found entity or <code>null</code> of the primary key was not found. */ public <T> T find(Class<T> type, Object key); /** * Retrieves a whole list of entities from the database using a named query. * * @param type The entities type. * @param query The name of the named query. The query may only use numbered * parameters. * @return A list of entities matching the query. The list may be empty if no * entity was found. */ public <T> List<T> findList(Class<T> type, String query); /** * Retrieves a whole list of entities from the database using a named query. * * @param type The entities type. * @param query The name of the named query. The query may1 only use numbered * parameters. * @param params The parameter values for the query in order they appear in the * query string. * @return A list of entities matching the query. The list may be empty if no * entity was found. */ public <T> List<T> findList(Class<T> type, String query, Param params); /** * Retrieves a whole list of entities from the database using a named query. * * @param type The entities type. * @param query The name of the named query. The query may only use numbered * parameters. * @param limit The maximum amount of entities to retrieve. * @return A list of entities matching the query. The list may be empty if no * entity was found. */ public <T> List<T> findList(Class<T> type, String query, int limit); /** * Retrieves a whole list of entities from the database using a named query. * * @param type The entities type. * @param query The name of the named query. The query may only use numbered * parameters. * @param limit The maximum amount of entities to retrieve. * @param params The parameter values for the query in order they appear in the * query string. * @return A list of entities matching the query. The list may be empty if no * entity was found. */ public <T> List<T> findList(Class<T> type, String query, int limit, Param params); /** * Retrieves a whole list of entities from the database using a named query. * * @param type The entities type. * @param query The name of the named query. The query may only use numbered * parameters. * @param first Number of the first entry to retrieve. * @param limit The maximum amount of entities to retrieve. * @return A list of entities matching the query. The list may be empty if no * entity was found. */ public <T> List<T> findList(Class<T> type, String query, int first, int limit); /** * Retrieves a whole list of entities from the database using a named query. * * @param type The entities type. * @param query The name of the named query. The query may only use numbered * parameters. * @param first Number of the first entry to retrieve. * @param limit The maximum amount of entities to retrieve. * @param params The parameter values for the query in order they appear in the * query string. * @return A list of entities matching the query. The list may be empty if no * entity was found. */ public <T> List<T> findList(Class<T> type, String query, int first, int limit, Param params); /** * Finds a single entity using a named query. This method may throw an * Exception if the query returns more than one item. * * @param type The entities type. * @param query The name of the named query. The query may only use numbered * parameters. * @return The entity found or <code>null</code> if it was not found. */ public <T> T findSingle(Class<T> type, String query); /** * Finds a single entity using a named query. This method may throw an * Exception if the query returns more than one item. * * @param type The entities type. * @param query The name of the named query. The query may only use numbered * parameters. * @param params The parameter values for the query in order they appear in the * query string. * @return The entity found or <code>null</code> if it was not found. */ public <T> T findSingle(Class<T> type, String query, Param params); /** * Closes this Read instance and releases all database locks. */ @Override public void close(); } /** * Callback interface which is used in conjunction with the asynchronous methods to * submit database changes. * * @author Simon Taddiken */ @FunctionalInterface public interface TransactionCallback { /** * This method is called when a database transaction could be committed without * any errors. */ public void success(); /** * This method is called when committing a database transaction failed. * * @param e The exception which caused the transaction to fail. */ public default void fail(DatabaseException e) { e.printStackTrace(); } } /** * Detaches all given objects from the current persistence context. * @param entities Entities to detach. */ public void detachAll(Collection<? extends Object> entities); /** * Creates a new {@link Read} object to read values from the database. Upon calling * this method, the database will be locked for read access and upon closing the * returned Read instance this lock will be released. The returned object should * always be used within a try-resources block like this: * <pre> * try (final Read read = persistence.read()) { * final MyEntity me = read.find(MyEntity.class, 1); * } * </pre> * This ensures that the lock created by this method is released correctly. * * @return Read access to the database. */ public Read read(); /** * Returns a {@link Read} Object which can be used to perform single queries without * the need of external synchronization. This, the returned Object must not * necessarily be used within a try-resource block. * * @return Synchronized read access to the database */ public Read atomic(); /** * Creates a new {@link Write} object to add, modify or delete entities from the * database. Upon calling this method, the database will be locked for write access * and a new transaction will be initiated. The transaction will be submitted to the * database when the returned Write instance is being closed. Also, the lock will be * released when closing the instance. You should always use this method within a * try-resources block like this: * <pre> * try (final Write write = persistence.write()) { * write.single(myObject); * // ... * } * </pre> * This ensures that the lock and transaction created by this method are released * correctly. * * <p>The Write instance returned by this method also supports reading using * {@link Write#read()}.</p> * * @return Write access to the database. * @throws DatabaseException If obtaining write access to the database failed. */ public Write write() throws DatabaseException; /** * This method atomically creates a new write-locked transaction, * {@link Atomic#perform(Write) executes} the passed {@link Atomic} and submits all * changes to the database. All this is done within the current thread. * * @param a The Atomic instance to execute. * @throws DatabaseException If submitting the transaction failed. */ public void writeAtomic(Atomic a) throws DatabaseException; /** * Executes the changes performed by the passed {@link Atomic} instance within a new * thread. Information about whether the operation was successful are simply * discarded by this method. * * @param a The Atomic instance to execute. */ public void writeAtomicParallel(Atomic a); /** * Executes the changes performed by the passed {@link Atomic} instance within a new * thread. Using a {@link TransactionCallback} the caller can be notified about * whether the changes could be submitted to the database or an error occurred. * * @param a The atomic instance to execute within a new thread. * @param cb Callback which is notified about the success of the parallel transaction. */ public void writeAtomicParallel(Atomic a, TransactionCallback cb); /** * Gets a Write instance to perform add- and delete tasks within a new thread. Unlike * the {@link #write()} method, this method does not lock the database nor does it * create a new transaction when being called. Instead, all changes to be performed * are collected and are submitted within a new thread when the returned Write * instance is being closed. You should always use this method within a * try-resources block like this: * <pre> * try (final Write write = persistence.writeParallel()) { * write.single(myObject); * // ... * } * </pre> * <p>The Write instance returned by this method does <b>not</b> support the * {@link Write#read() read} operation.</p> * * @return Write access to the database. */ public Write writeParallel(); public Write write(TransactionCallback cb); public Write writeParallel(TransactionCallback cb); public void registerEntity(Class<?> clazz); public void registerEntityConverter(EntityConverter ec); public void refresh(Object obj); }