code
docs
tests
The UoWFile Library provides an easy way to bind file operations to UnitOfWorks.
In other words, using this library you can easily attach files to your Composites, mostly EntityComposites, so that if the UoW gets discarded, changes to files are discarded too. Concurrent modifications are properly handled.
Note that it has a performance impact relative to the files size as it duplicates the file to keep a backup for eventual rollback. However, the API provides a way to get non-managed handles on the attached files to keep your read-only operations fast.
The location of files is left to the developer using a private mixin.
Let’s say you have the following Entity:
public interface TestedEntity [...snip...] { Property<String> name(); }
To add an attached file to it you first need to extends HasUoWFileLifecycle:
public interface TestedEntity , Identity { Property<String> name(); }
This provides you with the following contract:
public interface HasUoWFile { /** * IMPORTANT Use this {@link File} inside read-only {@link UnitOfWork}s only * @return The file that is attached. */ File attachedFile(); File managedFile(); [...snip...] }
Next you need to write the UoWFileLocator mixin:
public static class TestedFileLocatorMixin implements UoWFileLocator { @This private Identity meAsIdentity; @Override public File locateAttachedFile() { return new File( baseTestDir, meAsIdentity.identity().get() ); } }
Assemble all this as follow:
public void assemble( ModuleAssembly module ) throws AssemblyException { new UoWFileAssembler().assemble( module ); module.entities( TestedEntity.class ).withMixins( TestedFileLocatorMixin.class ); [...snip...] }
You can now use the following methods on your EntityComposite:
File attachedFile = entity.attachedFile(); File managedFile = entity.managedFile();
Now if you want to attach several files to one entity, this library provides a simple mechanism allowing you to use any enum as discriminator.
Let’s say you have the following Entity:
public interface TestedEntity [...snip...] { Property<String> name(); }
It’s the very same as the one used to start the singular file support described above.
To add an attached file to it you first need to write an enum and extends HasUoWFilesLifecycle:
public enum MyEnum { fileOne, fileTwo } public interface TestedEntity , Identity { Property<String> name(); }
This provides you with the following contract:
public interface HasUoWFiles<T extends Enum<T>> { /** * IMPORTANT Use this {@link File} only inside read-only {@link UnitOfWork}s */ File attachedFile( T key ); /** * IMPORTANT Use these {@link File}s only inside read-only {@link UnitOfWork}s */ Iterable<File> attachedFiles(); File managedFile( T key ); Iterable<File> managedFiles(); [...snip...] }
Next you need to write the UoWFileLocator mixin:
public static abstract class TestedFilesLocatorMixin implements UoWFilesLocator<MyEnum> { @This private Identity meAsIdentity; @Override public Iterable<File> locateAttachedFiles() { List<File> list = new ArrayList<>(); for( MyEnum eachValue : MyEnum.values() ) { list.add( new File( baseTestDir, meAsIdentity.identity().get() + "." + eachValue.name() ) ); } return list; } @Override public File locateAttachedFile( MyEnum key ) { return new File( baseTestDir, meAsIdentity.identity().get() + "." + key.name() ); } }
Assemble all this as follow:
public void assemble( ModuleAssembly module ) throws AssemblyException { new UoWFileAssembler().assemble( module ); module.entities( TestedEntity.class ).withMixins( TestedFilesLocatorMixin.class ); [...snip...] }
You can now use the following methods on your EntityComposite:
File attachedFileTwo = entity.attachedFile( MyEnum.fileTwo ); File managedFileOne = entity.managedFile( MyEnum.fileOne );