Appendix A. ArgumentInterpreter

Table of Contents

Argument philosophy
Interpretation process
java.io.File (file or directory)
java.io.File (directory)
java.net.URL
FutureEntity
NamedReadableFile
ReadableFile
Existing WritableFile
New WritableFile
RandomlyAccessibleFile
Read only entity holder
Read only Entity (file or directory)
Read only Directory
Read/write Directory
Read/write Entity (file or directory)
Read/write EFile
XML Source
ReadableFile implementations
NamedReadableFile implementations
WritableFile implementations
RandomlyAccessibleFile implementations
EntityView implementations
FutureEntityStrategy implementations

Argument interpretation gives great flexibility in which kinds of arguments that can be used for setting task properties. Most tasks use ArgumentInterpreter together with an ArgumentInterpretationStrategy to interpret some of their properties. This appendix describes how the different strategies interpret properties into the expected types. It also lists useful implementations of the different argument types.

Tasks are implemented to use the simplest types of arguments possible. If a task needs a container for reading data from, it uses a ReadableFile. If it wants the container to have a name, it uses a NamedReadableFile, and so on.


Simple argument types, such as ReadableFile, come with many implementations. Some of ReadableFile's implementations are UrlReadableFile, CharSequenceReadableFile and EFile. A ReadableFile can always be turned into a NamedReadableFile by wrapping it in a NamedReadableFileAdapter. For more information, see the implementation sections below and Appendix B, EntityFS cookbook.

Unless a custom interpretation method or class is used, arguments are interpreted using the ArgumentInterpreter.interpret(Object, org.schmant.arg.ArgumentIntepretationStrategy) method. The first argument to that method is one object or an array or collection of objects. These objects are the objects to interpret. The second argument to the method is the ArgumentInterpretationStrategy to use

First the interpret method flattens the object collection (using FlatteningList), and all closures in the collection are run. Then the produced objects are fetched from all Producer:s in the collection. The resulting argument list is fed into the ArgumentInterpretationStrategy object, which interprets the list using its strategy and returns an ArgumentInterpretationResult object containing all interpreted objects and the objects that it was not able to interpret.

When it is created, the ArgumentInterpretationStrategy object can be configured to treat different situations as errors or not. If it encounters a situation that it has been configured to treat as an error it will throw an ArgumentInterpretationException. These two configuration modes are supported by all strategy objects:

ArgumentInterpretationStrategy.ALLOW_NOT_INTERPRETED

Tell the strategy object that it is not an error if it cannot interpret all objects. All objects that it cannot interpret along with their interpretation traces that describes how the strategy tried to interpret them are returned in the ArgumentInterpretationResult object.

ArgumentInterpretationStrategy.ALLOW_ONE_AND_ONLY_ONE_RESULT_OBJECT

Allow only one result object. If the argument list is interpreted into more than one object, this results in an error.

The following sections describe how the different ArgumentInterpretationStrategy objects interpret objects into different types.

InterpretAsFileStrategy is used to interpret objects into File:s (files and/or directories).

java.io.File are used by tasks that use modules that are not EntityFS-aware, i.e. mostly tasks that run external programs. The files returned by the interpretation methods may or may not exist. Their paths may be relative or absolute.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsFileDirectoryStrategy is used to interpret objects into directory File:s.

This method uses the results from a InterpretAsFileStrategy object, but throws an ArgumentInterpretationException if the result is not a directory.

InterpretAsUrlStrategy is used to interpret objects into URL objects.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsFutureEntityStrategy is used to interpret objects into FutureEntity objects.

The InterpretAsFutureEntityStrategy constructor takes an optional source value. It can be used as a hint to a FutureEntityStrategy object to help it decide what to call the entity it creates. It is up to each task that use future entities to decide if it should provide a hint. A process task uses the source property as a hint.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsNamedReadableFileStrategy is used to interpret objects into NamedReadableFile:s.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


See CopyTF examples for how to use an URL as a NamedReadableFile.

InterpretAsReadableFileStrategy is used to interpret objects into ReadableFile objects.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


See CopyTF examples for how to use an URL as a ReadableFile.

InterpretAsWritableFileStrategy is used to interpret objects into WritableFile objects representing existing files.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


The InterpretAsNewWritableFileStrategy interprets an object into a location for a new writable file, creates the file and then returns it. If there already is a file at the target location, it uses an OverwriteStrategy to decide what to do with it. If the strategy decides to keep the old file, most tasks will fail.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsRandomlyAccessibleFileStrategy is used to interpret objects into RandomlyAccessibleFile:s.

For some valid arguments, the returned file may be read only.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsEntityHolderStrategy is used to interpret objects into EntityHolder objects.

An entity holder is a very limited Directory.

The returned directory is wrapped in a DirectoryRepresentation object. It contains a DirectoryView and an optional EntityFilter. If the filter is set, the running task will only see the entities matching the filter. If the task is recursive, it will still propagate down into all subdirectories, even if they don't match the filter. This is how using a DirectoryRepresentation source differs from using a DirectoryView source; when using a DirectoryView source, only the subdirectories matching the filter will be processed.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsReadOnlyEntityStrategy is used to interpret objects as read only EntityView:s.

By calling this method, the client says that it does not require a entity that it can write to, only one it can read from. The returned entity is not required to be read only, it might just as well be read/write.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsReadOnlyDirectoryStrategy is used to interpret objects as read only DirectoryView:s.

By calling this method, the client says that it does not require a directory that it can write to, only one it can read from. The returned directory is not required to be read only, it might just as well be read/write.

The returned directory is wrapped in a DirectoryRepresentation object. It contains a DirectoryView and an optional EntityFilter. If the filter is set, the running task will only see the entities matching the filter. If the task is recursive, it will still propagate down into all subdirectories, even if they don't match the filter. This is how using a DirectoryRepresentation source differs from using a DirectoryView source; when using a DirectoryView source, only the subdirectories matching the filter will be processed.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsDirectoryStrategy is used to interpret objects as read/write DirectoryView:s.

The returned directory is wrapped in a DirectoryRepresentation object. It contains a DirectoryView and an optional EntityFilter. If the filter is set, the running task will only see the entities matching the filter. If the task is recursive, it will still propagate down into all subdirectories, even if they don't match the filter. This is how using a DirectoryRepresentation source differs from using a DirectoryView source; when using a DirectoryView source, only the subdirectories matching the filter will be processed.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsEntityStrategy is used to interpret objects as read/write EntityView:s.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsEFileStrategy is used to interpret objects as read/write EFile:s.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


InterpretAsXmlSourceStrategy is used to interpret objects as XML Source objects that can be used for XSL transformations.

First, ArgumentInterpreter preprocesses the argument list as described above. Then the strategy object tries to interpret each object in the preprocessed list by checking if each object is of any of the types listed below, in the order that they are listed. If it is, the algorithm listed at the matched type is used to create the object tor return. If there are objects for which there are no matches, the configuration of the ArgumentInterpretationStrategy decides what will happen.


A ReadableFile is a container for file data. It can be opened and read from any number of times.

The tree view below lists the type's inheritance hierarchy. The names of interfaces are written in italics.

ReadableFile                 -- container for file data that can be opened and read from
+ ByteArrayReadableFile      -- file that reads data from a byte array
+ CharSequenceReadableFile   -- file that reads data from a CharSequence
|                               (a String, for instance)
+ BZip2ReadableFile          -- file that transparently decompresses data when read.
+ GZipReadableFile           -- file that transparently decompresses data when read.
+ GZipReadableFileProxy      -- file that transparently decompresses data when read.
+ LzmaReadableFile           -- file that transparently decompresses data when read.
+ NamedReadableFile          -- a ReadableFile with a name
  + ReadWritableFile         -- a read/write file
  | + ReadWritableFileAdapter -- Adapter from a File to a ReadWritableFile
  | + EFile                  -- a file entity
  + ManualNamedReadableFile  -- named file that reads data from a byte array
  |                             or a CharSequence (such as a String)
  + NamedReadableFileAdapter -- adapter for turning a ReadableFile
  |                             into a NamedReadableFile
  + ReadWritableFileAdapter  -- adapter for turning a File into a
  |                             NamedReadableFile
  + UrlReadableFile          -- named file that reads data from the target of 
                                a URL

Since ReadableFile is a very small interface, it is easy to do a custom implementation of it if none of the already existing implementations suffice.

A NamedReadableFile is a ReadableFile with a name. Any ReadableFile can be adapted to a NamedReadableFile by using the NamedReadableFileAdapter.

The tree view below lists the type's inheritance hierarchy. The names of interfaces are written in italics.

NamedReadableFile           -- a ReadableFile with a name
+ ReadWritableFile          -- a read/write file
| + ReadWritableFileAdapter -- Adapter from a File to a ReadWritableFile
| + EFile                   -- a file entity
+ ManualNamedReadableFile   -- named file that reads data from a byte array
|                              or a CharSequence (such as a String)
+ NamedReadableFileAdapter  -- adapter for turning a ReadableFile
|                              into a NamedReadableFile
+ ReadWritableFileAdapter   -- adapter for turning a File into a
|                              NamedReadableFile
+ UrlReadableFile           -- named file that reads data from the target of 
                               a URL

Since NamedReadableFile is a very small interface, it is easy to do a custom implementation of it if none of the already existing implementations suffice.

A WritableFile is a sink for data. It can be opened for writing to or appending to any number of times.

WritableFile                            -- container for file data that can be opened and written to
+ BZip2ExistingWritableFileProxy        -- file that transparently compresses data written to it.
+ BZip2NewWritableFileProxy             -- file that transparently compresses data written to it.
+ BZip2WritableFile                     -- file that transparently compresses data written to it.
+ FileWritableFile                      -- adapter from a File to a WritableFile
+ GZipExistingWritableFileProxy         -- file that transparently compresses data written to it.
+ GZipNewWritableFileProxy              -- file that transparently compresses data written to it.
+ GZipWritableFile                      -- file that transparently compresses data written to it.
+ LzmaExistingWritableFileProxy         -- file that transparently compresses data written to it.
+ LzmaNewWritableFileProxy              -- file that transparently compresses data written to it.
+ LzmaWritableFile                      -- file that transparently compresses data written to it.
+ MultiplexingExistingWritableFileProxy -- file that writes to one or more proxied files.
+ MultiplexingNewWritableFileProxy      -- file that writes to one or more proxied files.
+ ReadWritableFile                      -- a read/write file
  + ReadWritableFileAdapter             -- Adapter from a File to a ReadWritableFile
  + EFile                               -- a file entity

Since WritableFile is a very small interface, it is easy to do a custom implementation of it if none of the already existing implementations suffice.

A RandomlyAccessibleFile is a data container that may a client may open for random access. It may be read/write or it may be read only.

RandomlyAccessibleFile      -- container for file data that can be opened for random access
+ ByteArrayReadableFile     -- Read only container for bytes.
+ ReadWritableFile          -- a read/write file
  + ReadWritableFileAdapter -- Adapter from a File to a ReadWritableFile
  + EFile                   -- a file entity

An EntityView is a file system entity, either a file or a directory. It has a unique location in a FileSystem.

The tree view below lists the type's inheritance hierarchy. The names of interfaces are written in italics.

EntityView      -- view of generic file system entity
+ Entity        -- generic file system entity
| + EFile       -- file entity
| + Directory   -- directory entity (no filters)
+ DirectoryView -- Directory with contents filtered by zero or more
  |                EntityFilter:s
  + Directory   -- directory entity (no filters)

The FutureEntityStrategy defines a strategy that uses a source object and creates a FutureEntity from it. Note that you can use a closure instead of a future entity strategy.

The tree view below lists the type's inheritance hierarchy. The names of interfaces are written in italics.

FutureEntityStrategy         -- future entity strategy
+ FutureEntityIndexStrategy  -- strategy that creates future entities on the
                                form [base_directory]/[prefix][index][suffix]
                                where index is incremented for each created
                                future entity