public interface UnitOfWork extends MetaInfoHolder, AutoCloseable
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.
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.
A UoW can be associated with a Usecase. A Usecase describes the metainformation about the process to be performed by the UoW.
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:
UnitOfWork uow = module.newUnitOfWork(); try { ... uow.complete(); } finally { uow.discard(); }
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.
Since 2.1 you can leverage Java 7 Automatic Resource Management (ie. Try With Resources) and use the following template instead:
try( UnitOfWork uow = module.newUnitOfWork() ) { ... uow.complete(); }
It has the very same effect than the template above but is shorter.
Modifier and Type | Method and Description |
---|---|
void |
addUnitOfWorkCallback(UnitOfWorkCallback callback)
Register a callback.
|
void |
close()
Discard this UnitOfWork.
|
void |
complete()
Complete this UnitOfWork.
|
long |
currentTime() |
void |
discard()
Discard this UnitOfWork.
|
<T> T |
get(Class<T> type,
String identity)
Find an Entity of the given mixin type with the give identity.
|
<T> T |
get(T entity)
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.
|
boolean |
isOpen()
Check if the UnitOfWork is open.
|
boolean |
isPaused()
Check if the UnitOfWork is paused.
|
<T> T |
newEntity(Class<T> type)
Create a new Entity which implements the given mixin type.
|
<T> T |
newEntity(Class<T> type,
String identity)
Create a new Entity which implements the given mixin type.
|
<T> EntityBuilder<T> |
newEntityBuilder(Class<T> type)
Create a new EntityBuilder for an EntityComposite which implements the given mixin type.
|
<T> EntityBuilder<T> |
newEntityBuilder(Class<T> type,
String identity)
Create a new EntityBuilder for an EntityComposite which implements the given mixin 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)
Create a new EntityBuilder for an EntityComposite wich implements the given mixin type starting with the given
state.
|
<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)
Create a new EntityBuilder for an EntityComposite wich implements the given mixin type starting with the given
state.
|
<T> Query<T> |
newQuery(QueryBuilder<T> queryBuilder) |
void |
pause()
Pauses this UnitOfWork.
|
void |
remove(Object entity)
Remove the given Entity.
|
void |
removeUnitOfWorkCallback(UnitOfWorkCallback callback)
Unregister a callback.
|
void |
resume()
Resumes this UnitOfWork to again become the current UnitOfWork.
|
void |
setMetaInfo(Object metaInfo) |
<T extends Identity> |
toEntity(Class<T> primaryType,
T valueComposite)
Converts the provided Value to an Entity of the same type.
|
<T extends Identity> |
toValue(Class<T> primaryType,
T entityComposite)
Converts the provided Entity to a Value of the same type.
|
UnitOfWorkFactory |
unitOfWorkFactory()
Get the UnitOfWorkFactory that this UnitOfWork was created from.
|
Usecase |
usecase()
Get the Usecase for this UnitOfWork
|
metaInfo
UnitOfWorkFactory unitOfWorkFactory()
long currentTime()
Usecase usecase()
void setMetaInfo(Object metaInfo)
<T> Query<T> newQuery(QueryBuilder<T> queryBuilder)
<T> T newEntity(Class<T> type) throws EntityTypeNotFoundException, AmbiguousTypeException, LifecycleException
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.
The identity of the Entity will be generated by the IdentityGenerator of the Module of the EntityComposite.
type
- the mixin type that the EntityComposite must implementEntityTypeNotFoundException
- if no EntityComposite type of the given mixin type has been registeredAmbiguousTypeException
- If several mixins implement the given typeLifecycleException
- if the entity cannot be created<T> T newEntity(Class<T> type, String identity) throws EntityTypeNotFoundException, AmbiguousTypeException, LifecycleException
type
- the mixin type that the EntityComposite must implementidentity
- the identity of the new EntityEntityTypeNotFoundException
- if no EntityComposite type of the given mixin type has been registeredAmbiguousTypeException
- If several mixins implement the given typeLifecycleException
- if the entity cannot be created<T> EntityBuilder<T> newEntityBuilder(Class<T> type) throws EntityTypeNotFoundException, AmbiguousTypeException
type
- the mixin type that the EntityComposite must implementEntityTypeNotFoundException
- if no EntityComposite type of the given mixin type has been registeredAmbiguousTypeException
- If several mixins implement the given type<T> EntityBuilder<T> newEntityBuilder(Class<T> type, String identity) throws EntityTypeNotFoundException, AmbiguousTypeException
type
- the mixin type that the EntityComposite must implementidentity
- the identity of the new EntityEntityTypeNotFoundException
- if no EntityComposite type of the given mixin type has been registeredAmbiguousTypeException
- 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
An EntityComposite will be chosen according to what has been registered and the visibility rules for Modules and Layers will be considered.
T
- Entity typetype
- Entity typepropertyFunction
- a function providing the state of propertiesassociationFunction
- a function providing the state of associationsmanyAssociationFunction
- a function providing the state of many associationsnamedAssociationFunction
- a function providing the state of named associationsEntityTypeNotFoundException
- if no EntityComposite type of the given mixin type has been registeredAmbiguousTypeException
- 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
An EntityComposite will be chosen according to what has been registered and the visibility rules for Modules and Layers will be considered.
T
- Entity typetype
- Entity typeidentity
- the identity of the new EntitypropertyFunction
- a function providing the state of propertiesassociationFunction
- a function providing the state of associationsmanyAssociationFunction
- a function providing the state of many associationsnamedAssociationFunction
- a function providing the state of named associationsEntityTypeNotFoundException
- If no mixins implements the given typeAmbiguousTypeException
- If several mixins implement the given type<T> T get(Class<T> type, String identity) throws EntityTypeNotFoundException, NoSuchEntityException
type
- of the entityidentity
- of the entityEntityTypeNotFoundException
- if no entity type could be foundNoSuchEntityException
- if the entity could not be found<T> T get(T entity) throws EntityTypeNotFoundException
entity
- the Entity to be dereferencedEntityTypeNotFoundException
- if no entity type could be foundvoid remove(Object entity) throws LifecycleException
entity
- the Entity to be removed.LifecycleException
- if the entity could not be removedvoid complete() throws UnitOfWorkCompletionException, ConcurrentEntityModificationException
UnitOfWorkCompletionException
- if the UnitOfWork could not be completedConcurrentEntityModificationException
- if entities have been modified by othersvoid discard()
void close()
discard()
method and is an
implementation of the AutoCloseable
interface providing Try With Resources
support for UnitOfWork.close
in interface AutoCloseable
boolean isOpen()
boolean isPaused()
pause()
and then resumed by calling
resume()
.void pause()
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.
void resume()
void addUnitOfWorkCallback(UnitOfWorkCallback callback)
callback
- a callback to be registered with this UnitOfWorkvoid removeUnitOfWorkCallback(UnitOfWorkCallback callback)
callback
- a callback to be unregistered with this UnitOfWork<T extends Identity> T toValue(Class<T> primaryType, T entityComposite)
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.
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.
Example;
public interface Person extends Identity { ... };
public class MyAssembler
{
public void assemble( ModuleAssembly module )
{
module.values( Person.class );
module.entities( Person.class );
}
}
primaryType
- The shared type for which the properties and associations will
be converted. Properties outside this type will be ignored.entityComposite
- The entity to be convered.<T extends Identity> T toEntity(Class<T> primaryType, T valueComposite)
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.
This method MUST be called within a UnitOfWork.
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.
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.
Example;
public interface Person extends Identity { ... };
public class MyAssembler
{
public void assemble( ModuleAssembly module )
{
module.values( Person.class );
module.entities( Person.class );
}
}
primaryType
- The shared type for which the properties and associations will
be converted. Properties outside this type will be ignored.valueComposite
- The Value to be convered into an Entity.