/* * Copyright (c) 2007, Rickard Öberg. All Rights Reserved. * Copyright (c) 2007, Niclas Hedhman. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package org.qi4j.api.unitofwork; import org.qi4j.api.entity.EntityBuilder; import org.qi4j.api.entity.LifecycleException; import org.qi4j.api.query.Query; import org.qi4j.api.query.QueryBuilder; import org.qi4j.api.structure.MetaInfoHolder; import org.qi4j.api.usecase.Usecase; /** * All operations on entities goes through an UnitOfWork. * <p>A UnitOfWork allows you to access * Entities and work with them. All modifications to Entities are recorded by the UnitOfWork, * and at the end they may be sent to the underlying EntityStore by calling complete(). If the * UoW was read-only you may instead simply discard() it. * </p> * <p> * A UoW differs from a traditional Transaction in the sense that it is not tied at all to the underlying * storage resource. Because of this there is no timeout on a UoW. It can be very short or very long. * Another difference is that if a call to complete() fails, and the cause is validation errors in the * Entities of the UoW, then these can be corrected and the UoW retried. By contrast, when a Transaction * commit fails, then the whole transaction has to be done from the beginning again. * <p> * A UoW can be associated with a Usecase. A Usecase describes the metainformation about the process * to be performed by the UoW. * </p> * If a code block that uses a UoW throws an exception you need to ensure that this is handled properly, * and that the UoW is closed before returning. Because discard() is a no-op if the UoW is closed, we therefore * recommend the following template to be used: * <pre> * UnitOfWork uow = uowf.newUnitOfWork(); * try * { * ... * uow.complete(); * } finally * { * uow.discard(); * } * </pre> * This ensures that in the happy case the UoW is completed, and if any exception is thrown the UoW is discarded. After * the UoW has completed the discard() method doesn't do anything, and so has no effect. You can choose to either add * catch blocks for any exceptions, including exceptions from complete(), or skip them. */ public interface UnitOfWork extends MetaInfoHolder { /** * Get the UnitOfWorkFactory that this UnitOfWork was created from. * * @return The UnitOfWorkFactory instance that was used to create this UnitOfWork. */ UnitOfWorkFactory unitOfWorkFactory(); long currentTime(); /** * Get the Usecase for this UnitOfWork * * @return the Usecase */ Usecase usecase(); void setMetaInfo( Object metaInfo ); <T> Query<T> newQuery( QueryBuilder<T> queryBuilder ); // DataSet newDataSetBuilder(Specification<?>... constraints); /** * Create a new Entity which implements the given mixin type. An EntityComposite * will be chosen according to what has been registered and the visibility rules * for Modules and Layers will be considered. If several * EntityComposites implement the type then an AmbiguousTypeException will be thrown. * <p/> * The identity of the Entity will be generated by the IdentityGenerator of the Module of the EntityComposite. * * @param type the mixin type that the EntityComposite must implement * * @return a new Entity * * @throws NoSuchEntityException if no EntityComposite type of the given mixin type has been registered * @throws org.qi4j.api.entity.LifecycleException * if the entity cannot be created * @throws EntityTypeNotFoundException */ <T> T newEntity( Class<T> type ) throws EntityTypeNotFoundException, LifecycleException; /** * Create a new Entity which implements the given mixin type. An EntityComposite * will be chosen according to what has been registered and the visibility rules * for Modules and Layers will be considered. If several * EntityComposites implement the type then an AmbiguousTypeException will be thrown. * * @param type the mixin type that the EntityComposite must implement * @param identity the identity of the new Entity * * @return a new Entity * * @throws NoSuchEntityException if no EntityComposite type of the given mixin type has been registered * @throws LifecycleException if the entity cannot be created * @throws EntityTypeNotFoundException */ <T> T newEntity( Class<T> type, String identity ) throws EntityTypeNotFoundException, LifecycleException; /** * Create a new EntityBuilder for an EntityComposite which implements the given mixin type. An EntityComposite * will be chosen according to what has been registered and the visibility rules * for Modules and Layers will be considered. If several * EntityComposites implement the type then an AmbiguousTypeException will be thrown. * * @param type the mixin type that the EntityComposite must implement * * @return a new Entity * * @throws NoSuchEntityException if no EntityComposite type of the given mixin type has been registered * @throws LifecycleException * @throws EntityTypeNotFoundException */ <T> EntityBuilder<T> newEntityBuilder( Class<T> type ) throws EntityTypeNotFoundException; /** * Create a new EntityBuilder for an EntityComposite which implements the given mixin type. An EntityComposite * will be chosen according to what has been registered and the visibility rules * for Modules and Layers will be considered. If several * mixins implement the type then an AmbiguousTypeException will be thrown. * * @param type the mixin type that the EntityComposite must implement * @param identity the identity of the new Entity * * @return a new Entity * * @throws NoSuchEntityException if no EntityComposite type of the given mixin type has been registered * @throws LifecycleException * @throws EntityTypeNotFoundException */ <T> EntityBuilder<T> newEntityBuilder( Class<T> type, String identity ) throws EntityTypeNotFoundException; /** * Find an Entity of the given mixin type with the give identity. This * method verifies that it exists by asking the underlying EntityStore. * * @param type of the entity * @param identity of the entity * * @return the entity * * @throws EntityTypeNotFoundException if no entity type could be found * @throws NoSuchEntityException */ <T> T get( Class<T> type, String identity ) throws EntityTypeNotFoundException, NoSuchEntityException; /** * If you have a reference to an Entity from another * UnitOfWork and want to create a reference to it in this * UnitOfWork, then call this method. * * @param entity the Entity to be dereferenced * * @return an Entity from this UnitOfWork * * @throws EntityTypeNotFoundException if no entity type could be found */ <T> T get( T entity ) throws EntityTypeNotFoundException; /** * Remove the given Entity. * * @param entity the Entity to be removed. * * @throws LifecycleException if the entity could not be removed */ void remove( Object entity ) throws LifecycleException; /** * Complete this UnitOfWork. This will send all the changes down to the underlying * EntityStore's. * * @throws UnitOfWorkCompletionException if the UnitOfWork could not be completed * @throws ConcurrentEntityModificationException * if entities have been modified by others */ void complete() throws UnitOfWorkCompletionException, ConcurrentEntityModificationException; /** * Discard thie UnitOfWork. Use this if a failure occurs that you cannot handle, * or if the usecase was of a read-only character. This is a no-op of the UnitOfWork * is already closed. */ void discard(); /** * Check if the UnitOfWork is open. It is closed after either complete() or discard() * methods have been called successfully. * * @return true if the UnitOfWork is open. */ boolean isOpen(); /** * Check if the UnitOfWork is paused. It is not paused after it has been create through the * UnitOfWorkFactory, and it can be paused by calling {@link #pause()} and then resumed by calling * {@link #resume()}. * * @return true if this UnitOfWork has been paused. */ boolean isPaused(); /** * Pauses this UnitOfWork. * <p> * Calling this method will cause the underlying UnitOfWork to become the current UnitOfWork until the * the resume() method is called. It is the client's responsibility not to drop the reference to this * UnitOfWork while being paused. * </p> */ void pause(); /** * Resumes this UnitOfWork to again become the current UnitOfWork. */ void resume(); /** * Register a callback. Callbacks are invoked when the UnitOfWork * is completed or discarded. * * @param callback a callback to be registered with this UnitOfWork */ void addUnitOfWorkCallback( UnitOfWorkCallback callback ); /** * Unregister a callback. Callbacks are invoked when the UnitOfWork * is completed or discarded. * * @param callback a callback to be unregistered with this UnitOfWork */ void removeUnitOfWorkCallback( UnitOfWorkCallback callback ); }