| /* |
| * Copyright (c) 2007-2011, Rickard Öberg. All Rights Reserved. |
| * Copyright (c) 2007-2012, Niclas Hedhman. All Rights Reserved. |
| * Copyright (c) 2013-2015, Paul Merlin. 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.apache.zest.api.unitofwork; |
| |
| import java.util.Map; |
| import org.apache.zest.api.association.AssociationDescriptor; |
| import org.apache.zest.api.composite.AmbiguousTypeException; |
| import org.apache.zest.api.entity.EntityBuilder; |
| import org.apache.zest.api.entity.EntityReference; |
| import org.apache.zest.api.entity.Identity; |
| import org.apache.zest.api.entity.LifecycleException; |
| import org.apache.zest.api.property.PropertyDescriptor; |
| import org.apache.zest.api.query.Query; |
| import org.apache.zest.api.query.QueryBuilder; |
| import org.apache.zest.api.structure.MetaInfoHolder; |
| import org.apache.zest.api.usecase.Usecase; |
| import org.apache.zest.functional.Function; |
| |
| /** |
| * 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> |
| * <p> |
| * A UoW can be associated with a Usecase. A Usecase describes the metainformation about the process |
| * to be performed by the UoW. |
| * </p> |
| * <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: |
| * </p> |
| * <pre> |
| * UnitOfWork uow = module.newUnitOfWork(); |
| * try |
| * { |
| * ... |
| * uow.complete(); |
| * } |
| * finally |
| * { |
| * uow.discard(); |
| * } |
| * </pre> |
| * <p> |
| * 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. |
| * </p> |
| * <p> |
| * Since 2.1 you can leverage Java 7 Automatic Resource Management (ie. Try With Resources) and use the following |
| * template instead: |
| * </p> |
| * <pre> |
| * try( UnitOfWork uow = module.newUnitOfWork() ) |
| * { |
| * ... |
| * uow.complete(); |
| * } |
| * </pre> |
| * <p> |
| * It has the very same effect than the template above but is shorter.</p> |
| */ |
| public interface UnitOfWork extends MetaInfoHolder, AutoCloseable |
| { |
| |
| /** |
| * 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. |
| * <p> |
| * 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> |
| * <p> |
| * The identity of the Entity will be generated by the IdentityGenerator of the Module of the EntityComposite. |
| * </p> |
| * |
| * @param type the mixin type that the EntityComposite must implement |
| * |
| * @return a new Entity |
| * |
| * @throws EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered |
| * @throws AmbiguousTypeException If several mixins implement the given type |
| * @throws LifecycleException if the entity cannot be created |
| */ |
| <T> T newEntity( Class<T> type ) |
| throws EntityTypeNotFoundException, AmbiguousTypeException, 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 EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered |
| * @throws AmbiguousTypeException If several mixins implement the given type |
| * @throws LifecycleException if the entity cannot be created |
| */ |
| <T> T newEntity( Class<T> type, String identity ) |
| throws EntityTypeNotFoundException, AmbiguousTypeException, 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 EntityBuilder |
| * |
| * @throws EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered |
| * @throws AmbiguousTypeException If several mixins implement the given type |
| */ |
| <T> EntityBuilder<T> newEntityBuilder( Class<T> type ) |
| throws EntityTypeNotFoundException, AmbiguousTypeException; |
| |
| /** |
| * 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 EntityBuilder |
| * |
| * @throws EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered |
| * @throws AmbiguousTypeException If several mixins implement the given type |
| */ |
| <T> EntityBuilder<T> newEntityBuilder( Class<T> type, String identity ) |
| throws EntityTypeNotFoundException, AmbiguousTypeException; |
| |
| /** |
| * Create a new EntityBuilder for an EntityComposite wich implements the given mixin type starting with the given |
| * state. |
| * <p> |
| * An EntityComposite will be chosen according to what has been registered and the visibility rules for Modules and |
| * Layers will be considered. |
| * |
| * @param <T> Entity type |
| * @param type Entity type |
| * @param propertyFunction a function providing the state of properties |
| * @param associationFunction a function providing the state of associations |
| * @param manyAssociationFunction a function providing the state of many associations |
| * @param namedAssociationFunction a function providing the state of named associations |
| * |
| * @return a new EntityBuilder starting with the given state |
| * |
| * @throws EntityTypeNotFoundException if no EntityComposite type of the given mixin type has been registered |
| * @throws AmbiguousTypeException If several mixins implement the given type |
| */ |
| <T> EntityBuilder<T> newEntityBuilderWithState( Class<T> type, |
| Function<PropertyDescriptor, Object> propertyFunction, |
| Function<AssociationDescriptor, EntityReference> associationFunction, |
| Function<AssociationDescriptor, Iterable<EntityReference>> manyAssociationFunction, |
| Function<AssociationDescriptor, Map<String, EntityReference>> namedAssociationFunction ) |
| throws EntityTypeNotFoundException, AmbiguousTypeException; |
| |
| /** |
| * Create a new EntityBuilder for an EntityComposite wich implements the given mixin type starting with the given |
| * state. |
| * <p> |
| * An EntityComposite will be chosen according to what has been registered and the visibility rules for Modules and |
| * Layers will be considered. |
| * |
| * @param <T> Entity type |
| * @param type Entity type |
| * @param identity the identity of the new Entity |
| * @param propertyFunction a function providing the state of properties |
| * @param associationFunction a function providing the state of associations |
| * @param manyAssociationFunction a function providing the state of many associations |
| * @param namedAssociationFunction a function providing the state of named associations |
| * |
| * @return a new EntityBuilder starting with the given state |
| * |
| * @throws EntityTypeNotFoundException If no mixins implements the given type |
| * @throws AmbiguousTypeException If several mixins implement the given type |
| */ |
| <T> EntityBuilder<T> newEntityBuilderWithState( Class<T> type, String identity, |
| Function<PropertyDescriptor, Object> propertyFunction, |
| Function<AssociationDescriptor, EntityReference> associationFunction, |
| Function<AssociationDescriptor, Iterable<EntityReference>> manyAssociationFunction, |
| Function<AssociationDescriptor, Map<String, EntityReference>> namedAssociationFunction ) |
| throws EntityTypeNotFoundException, AmbiguousTypeException; |
| |
| /** |
| * 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 if the entity could not be found |
| */ |
| <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 this 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(); |
| |
| /** |
| * Discard this 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. This simply call the {@link #discard()} method and is an |
| * implementation of the {@link AutoCloseable} interface providing Try With Resources |
| * support for UnitOfWork. |
| */ |
| @Override |
| public void close(); |
| |
| /** |
| * 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 ); |
| |
| /** |
| * Converts the provided Entity to a Value of the same type. |
| * This is a convenience method to convert an EntityComposite to a ValueComposite. |
| * <p> |
| * All Property values are transferred across as-is, and the Association, ManyAssociation |
| * and NamedAssociatino values are kept in the ValueComposite as EntityReferences |
| * until they are dereferenced (get() and other methods), and IF a UnitOfWork is |
| * present at dereferencing the corresponding EntityCompoiste is retrieved from the |
| * EntityStore. If there is not an UnitOfWork present, an exception is thrown. |
| * </p> |
| * <p> |
| * For this to work, the Composites (both Entity and Value) must not declare the |
| * EntityComposite and ValueComposite super types, but rely on the declaration in |
| * the assembly, and also extend the Identity supertype. |
| * </p> |
| * Example; |
| * <pre><code> |
| * public interface Person extends Identity { ... }; |
| * public class MyAssembler |
| * { |
| * public void assemble( ModuleAssembly module ) |
| * { |
| * module.values( Person.class ); |
| * module.entities( Person.class ); |
| * } |
| * } |
| * </code></pre> |
| * |
| * @param primaryType The shared type for which the properties and associations will |
| * be converted. Properties outside this type will be ignored. |
| * @param entityComposite The entity to be convered. |
| */ |
| <T extends Identity> T toValue( Class<T> primaryType, T entityComposite ); |
| |
| /** |
| * Converts the provided Value to an Entity of the same type. |
| * This is a convenience method to convert a ValueComposite to an EntityComposite. |
| * <p> |
| * All Property values are transferred across as-is (no deep copy in case mutable |
| * types (DISCOURAGED!) are used), and the Association, ManyAssociation |
| * and NamedAssociatino that were in the ValueComposite as EntityReferences are |
| * transferred into the EntityComposite correctly, and can be dereferenced. |
| * </p> |
| * <p> |
| * This method MUST be called within a UnitOfWork. |
| * </p> |
| * <p> |
| * If an Entity with the Identity in the ValueComposite already exists, then that |
| * Entity is updated with the values from the ValueComposite. If an Entity of |
| * that Identity doesn't exist and new one is created. |
| * </p> |
| * <p> |
| * For this to work, the Composites (both Entity and Value) must not declare the |
| * EntityComposite and ValueComposite super types, but rely on the declaration in |
| * the assembly, and also extend the Identity supertype. |
| * </p> |
| * Example; |
| * <pre><code> |
| * public interface Person extends Identity { ... }; |
| * public class MyAssembler |
| * { |
| * public void assemble( ModuleAssembly module ) |
| * { |
| * module.values( Person.class ); |
| * module.entities( Person.class ); |
| * } |
| * } |
| * </code></pre> |
| * |
| * @param primaryType The shared type for which the properties and associations will |
| * be converted. Properties outside this type will be ignored. |
| * @param valueComposite The Value to be convered into an Entity. |
| */ |
| <T extends Identity> T toEntity( Class<T> primaryType, T valueComposite ); |
| |
| |
| } |