Artifacts referenced in the JSL (using the ref
attribute) must be registered in a Unity container using the UnityLoader
class. It has two protected methods that can be overriden: LoadConfiguration(IUnityContainer)
, which makes the registrations for the base configuration of the batch, and LoadArtifacts(IUnityContainer)
, which registers the artifacts of the job (e.g., readers, writers).
The implementation of LoadConfiguration
in UnityLoader
does the required registrations by default, thus it is not required to override it unless this default configuration is not appropriate for the current batch.
The only mandatory interface to register is IJobOperator
, but the default implementation, SimpleJobOperator
does require registrations of interfaces IJobExplorer
, IJobRepository
, IJobLauncher
, and IListableJobLocator
. If using splits or partitioned steps, it is also required to register a task executor (ITaskExecutor
).
The job operator offers a basic interface to manage job executions (e.g., starting, restarting jobs). It is recommended to use the default implementation, SimpleJobOperator
, but users are free to provide their own implementation.
The job explorer manages the persistence of the batch entities while the job repository holds all the associated meta-information. Both can either be persisted in a database or stored in memory. The database persistence is required to restart a job but the in-memory explorer and repository are useful during development.
For the job repository to be persisted in a database, an ad hoc list of tables must be created in a database schema. The creation (and drop) sql scripts are being provided for the three supported rdbms (MS Sql Server, Oracle database and IBM DB2): see the corresponding appendix section:
When using the default implementation of UnityLoader.LoadConfiguration
, one can override the PersistenceSupport
property to choose whether to use database or memory explorer and repository. By default the property returns false
.
Example 4.13. Setting Database Persistence of Job Explorer and Job Repository
protected override bool PersistenceSupport { get { return true; } }
When using database persistence, an instance of ConnectionStringSettings
with name “Default” must be registered in the Unity container.
The job launcher is responsible for launching a job. By default, UnityLoader
uses an instance of SimpleJobLauncher
with a instance of SyncTaskExecutor
as a task executor.
The job locator, which implements IListableJobLocator
, is used to retrieve a job configuration from its name. If it also implements IJobRegistry
, UnityLoader
will register in it all the jobs that have been registered in the Unity container. By default an instance of MapJobRegistry
is used.
The task executor determines how splits and partitioned steps are executed. The default implementation registered by UnityLoader
, SimpleAsyncTaskExecutor
, executes the tasks in parallel. Summer Batch also provides the SyncTaskExecutor
which executes the tasks synchronously, in sequence.
To have a fine grained control over the task execution, users can define their own task executor. A task executor must implement the ITaskExecutor
interface. It has one method, void Execute(Task)
, which is responsible for executing the task passed as parameter. It is not required that the task finishes before Execute
returns, thus multiple tasks can be executed at the same time.
The UnityLoader.LoadArtifacts
method is responsible for registering all the artifacts required for the job in the unity container. In particular these artifacts must be registered: readers, processors, writers, tasklets, job listeners, and step listeners.
Readers must implement the IItemReader<T>
interface. The “T Read()
” method returns the next read items or null
if there are more items. The type of the returned items, T
, must thus be a reference type.
Processors must implement the IItemProcessor<TIn, TOut>
interface. The “TOut Process(TIn)
” method transforms the item returned by the reader (of type TIn
) to an item of type TOut
for the writer. If the current item must be skipped, the processor can return null
. The type of the returned items, TOut
, must thus be a reference type.
Writers must implement the IItemWriter<T>
interface. The “void Write(IList<T>)
” method writes the items returned by the processor or the reader if there are no processor.
Takslets must implement the ITasklet
interface. The “RepeatStatus Execute(StepContribution, ChunkContext)
” method must implement a batchlet step and is repeatedly executed until it returns RepeatStatus.Finished
.
Job listeners must implement the IJobExecutionListener
interface. The “void BeforeJob(JobExecution)
” method is called before the job starts and the “void AfterJob(JobExecution)
” method is called after the job ends.
Step listeners must implement the IStepExecutionListener
interface. The “void BeforeStep(StepExecution)
” method is called before the step starts and the “ExitStatus AfterStep(StepExecution)
” method is called after the step ends. The AfterStep
method return an exit status that can be used for conditional step control flow in the XML configuration (see section Batch Control Flow)
Batch artifacts can be defined in two different scopes: the singleton scope and the step scope. A scope determines the lifetime of an instance during the execution of the batch and is critical when executing steps in parallel or when sharing artifacts between different steps.
Artifacts defined in the singleton scope use the Microsoft.Practices.Unity.ContainerControlledLifetimeManager
lifetime manager, which means that only one instance will be created during the whole job execution.
The singleton scope is the default scope; when a resolution is made and no lifetime manager has been defined, the ContainerControlledLifetimeManager
lifetime manager is used.
Artifacts defined in the step scope use the Summer.Batch.Core.Unity.StepScope.StepScopeLifetimeManager
lifetime manager. One instance will be created for each step execution where the artifact is used. It means that if a step is executed several times (e.g., with a partitioner), the artifacts defined in the step scope (like the reader or the writer) will not be shared by the different executions.
Note | |
---|---|
When an artifact in the singleton scope references an artifact in the step scope, a proxy is created. When the proxy is used it will retrieve the appropriate instance of the artifact, depending on the current step execution. The proxy creation is only possible with interfaces, which means that the reference in the singleton scope artifact must use an interface. |
To add new features and simplify the syntax, several additions to Unity have been made.
Two Unity extensions are used to manage scopes (see section Scopes), Summer.Batch.Core.Unity.Singleton.SingletonExtension
and Summer.Batch.Core.Unity.StepScope.StepScopeExtension
. Both are automatically added to the Unity container by UnityLoader
. SingletonExtension
ensures that the default lifetime manager is ContainerControlledLifetimeManager
instead of PerResolveLifetimeManager
. StepScopeExtension
manages references between non step scope artifacts and step scope artifacts, as described in section Step Scope.
A third extension is added to the container by UnityLoader
: Summer.Batch.Core.Unity.PostprocessingUnityExtension
. It is used to execute a callback method once an instance of a class has been initialized. If an instance created by the Unity container implements the Summer.Batch.Common.Factory.IInitializationPostOperations
interface, the AfterPropertiesSet
method will be called after the initialization is completed and successful. This is used to ensure an artifact is correctly configured (e.g., to make sure a reader has been given a resource to read).
Unity uses injection parameter values to compute at resolve time the value that are injected. Four new types of injection parameter values have been introduced.
Summer.Batch.Core.Unity.Injection.JobContextValue<T>
Injects a value from the job context. The constructor takes the key of the job context value to get as parameter. It the value is not of type T
, it converts it using its string representation.
Summer.Batch.Core.Unity.Injection.StepContextValue<T>
Injects a value from the step context. The constructor takes the key of the step context value to get as parameter. It the value is not of type T
, it converts it using its string representation.
Summer.Batch.Core.Unity.Injection.LateBindingInjectionValue<T>
Injects a value computed from a string given as a constructor parameter. First it computes a string value from the original string parameter by replacing any late binding sequence (i.e., “#{…}”) by a value computed at resolve time. Then the string value is converted into the required type.
The late binding injection parameter value currently supports three sources for the late binding sequence: (1) jobExecutionContext
, which injects a value from the job context using JobContextValue
, (2) stepExecutionContext
, which injects a value from the step context using StepContextValue
, and (3) settings
, which injects a string value read from the application settings, in “App.config
”. For each source, a string key must be provided using the following syntax: #{source['key']}
.
For instance the string "#{jobExecutionContext['output']}\result.txt"
with "C:\output"
as the job context value for "output"
would be replaced by "C:\output\result.txt"
.
Summer.Batch.Core.Unity.Injection.ResourceInjectionValue
Injects a resource. Resources represent files that can be read or written and are used by the readers and writers in Summer Batch. This injection parameter value takes a string an converts it to a file system resource that is injected. The string can contain late binding and is resolved using LateBindingInjectionValue
.
The constructor takes a boolean optional parameter, many
. If many
is true, a list or resources will be returned instead of a single resource. There are two ways to specify several resources in the input string: (1) separating different paths with “;”, and (2) using ant-style paths with “?”, “*”, and “**” wildcards.
The Summer.Batch.Core.Unity.Registration<TFrom, TTo>
class simplifies the use of injection members and injection parameter values. An instance of Registration
represents a registration of a type to a Unity container. Several methods allows the configuration of the registration, and the Register()
method performs the actual registration.
There are two ways to create an instance of Registration
: to use a constructor or to use one of the extension methods for Unity containers (defined in Summer.Batch.Core.Unity.RegistrationExtension). For instance in Example 4.14, “Creating a New Registration”, registration1
and registration2
are equivalent and registration3
and registration4
are equivalent.
Example 4.14. Creating a New Registration
var registration1 = new Registration<IInterface, ConcreteClass>( new ContainerControlledLifetimeManager(), container); var registration2 = container.SingletonRegistration<IInterface, ConcreteClass>(); var registration3 = new Registration<ConcreteClass, ConcreteClass>( "name", new StepScopeLifetimeManager(), container); var registration4 = container.StepScopeRegistration<ConcreteClass>("name");
The Registration
class has several methods to configure a registration, which all return the current registration to allow chained calls. This configuration methods are separated in two types: injection member methods and injection parameter value methods. Injection member methods specify a type of injection (e.g., constructor injection) and injection parameter value methods specify a value to inject. When an injection parameter value method is called, the correcponding parameter value is added to the injection member specified by the last injection member method called. In Example 4.15, “Registration of a List of Character Strings” a list of character strings is registered using the Constructor
injection member method and the Value
injection parameter value method.
Example 4.15. Registration of a List of Character Strings
container.SingletonRegistration<IList<string>, List<string>>("names") .Constructor().Value(new []{ "name1", "name2" }) .Register();
Constructor()
Specifies constructor injection. All the following injection parameter values will be used as parameter for the constructor. The actual constructor is inferred from the parameter values at resolve time. There can only be one constructor injection per registration.
Method(string)
Specifies method injection. The parameter is the name of the method to call and all the following injection parameter values will be used as parameter for the method. The actual method is inferred from the name and the parameter values at resolve time. There may be several method injections per registration (even for the same method).
Property(string)
Specifies property injection. The parameter is the name of the property to set and the following injection parameter value is the set value. There may be several property injections per registration.
Instance(object)
or Value(object)
Injects the object passed as parameter. Both methods are identical and the distinction is merely semantical (Instance
for reference types and Value
for value types).
Reference<T>(string)
Injects an object that is resolved from the Unity container at resolve time. The injected object is resolved using the type passed as generic parameter and the name passed as parameter. The name is optional. Since the resolution of the injected object is done at resolve time, it does not need to already be registered.
References<T>(params Type[])
Injects an array of objects that are resolved from the unity container at resolve time. The objects are resolved using the types passed as parameter.
References<T>(params string[])
Injects an array of objects that are resolved from the unity container at resolve time. The objects are resolved using the type passed as generic parameter and the names passed as parameter.
References<T>(params Reference[])
Injects an array of objects that are resolved from the unity container at resolve time. The objects are resolved using the Reference
instances passed as parameter. The structure Summer.Batch.Core.Unity.Reference
contains a type (Type
property) and a name (Name
property).
LateBinding<T>(string)
Injects an object using the late binding injection parameter value, LateBindingInjectionValue<T>
. See section New Injection Parameter Values for more information on late binding.
Resource<T>(string)
Injects a resource using the resource injection parameter value, ResourceInjectionValue
. See section New Injection Parameter Values for more information on resource injection.
Resources<T>(string)
Injects a list of resources using the resource injection parameter value, ResourceInjectionValue
. See section New Injection Parameter Values for more information on resource injection.