Skip to content

Template facility

In Chapter 6, Flat File Writer was presented. Among other properties to set, for LineAggregator Summer.Batch.Extra.Template.AbstractTemplateLineAggregator<T> is dedicated to format the output to an external format file. The class must be extended by implementing IEnumerable<object> GetParameters(T obj) that converts the business object used in the batch into an enumeration of values.

The template file must have a content like this: Key:Format, with the Format in C# fashion. Multiple lines of this form can appear with multiple keys and a format can be multi line by repeating colon.

Example 7.23. Example format file

EMPLOYEE: EMPID:{0} EMPNAME:{1}

Example 7.24. More advanced example format file

EMPLOYEE: EMPID:{0} EMPNAME:{1}
HEADER  :=====================================
        := Employee List for Date {0:MM/dd/yyyy} =
        :=====================================
FOOTER  :=====================================
        := End Employee List                 =
        :=====================================

In this example, there are three formats, and two of them span on three lines each.

The following properties are mandatory (need to be set at initialization time):

  • Template : Reference to resource file containing format;

  • TemplateId : key to the correct format in file.

Optional properties (Default value is provided, however can set at initialization time):

  • InputEncoding : template file encoding, defaults to Encoding.Default;

  • Culture : template file culture, default to CultureInfo.CurrentCulture;

  • LineSeparator : line separator to be used for multi line formats, defaults to Environment.NewLine.

Configuring the AbstractTemplateLineAggregator:

Example 7.25. Typical AbstractTemplateLineAggregator usage


// Writer - step1/WriteTemplateLine
container
    .StepScopeRegistration<IItemWriter<EmployeeBO>, FlatFileItemWriter<EmployeeBO>>("step1/WriteTemplateLine")
    .Property("Resource").Resource("#{settings['BA_TEMPLATE_LINE_WRITER.step1.WriteTemplateLine.FILENAME_OUT']}")
    .Property("Encoding").Value(Encoding.GetEncoding("ASCII"))
    .Property("LineAggregator")
        .Reference<ITemplateLineAggregator<EmployeeBO>>("step1/WriteTemplateLine/LineAggregator")
    .Register();

// Template Line aggregator
container.StepScopeRegistration
        <ITemplateLineAggregator<EmployeeBO>, MyTemplateLineAggregator>("step1/WriteTemplateLine/LineAggregator")
    .Property("Template")
        .Resource("#{settings['BA_TEMPLATE_LINE_WRITER.step1.WriteTemplateLine.TEMPLATE.FILENAME_IN']}")
    .Property("TemplateId").Value("EMPLOYEE")
    .Register();

With a MyTemplateLineAggregator such as:

Example 7.26. Typical TemplateLineAggregator class

public class MyTemplateLineAggregator : AbstractTemplateLineAggregator<EmployeeBO>
    {
        protected override IEnumerable<object> GetParameters(EmployeeBO employee)
        {
            // Compute a list of the values in EmployeeBO
            IList<object> parameters = new List<object>();
            parameters.Add(employee.Id);
            parameters.Add(employee.Name);
            return parameters;
        }
    }

Note

The template line aggregator will be useful with a way to switch between one template Id and another depending on the line to write. This requires a ProcessWriterAdapter, which enables to call the writer in a processor code and have a full control on its use. More details just below.

Controlling Template ID

With a simple use of the ItemplateLineAggregator in a writer, as explained above, the TemplateId is set once and for all in the Unity Loader. This means a multi-format template file would be useful only if several writers are used in the job, and each have a format, all the formats being stored in same template file. However, If a file to write must have several formats depending on the line, a more accurate control on the Template Id must be used. First, the writer with an aggregator must be declared in a process adapter, as explained above in this chapter.

Example 7.27. TemplateLineAggregator unity setup with a ProcessAdapter


// Process adapter
container.StepScopeRegistration<IProcessWriter<object>, ProcessWriterAdapter<object>>("AdapterKey")
    .Property("StepContextManager").Reference<IContextManager>(BatchConstants.StepContextManagerName)
    .Property("Adaptee").Reference<IItemWriter<EmployeeBO>>("WriterKey")
    .Register();

// Template line writer
container.StepScopeRegistration<IItemWriter<object>, FlatFileItemWriter<object>>("WriterKey")
    .Property("Resource").Resource("#{settings['…']}")
    .Property("Encoding").Value(Encoding.GetEncoding("ASCII"))
    .Property("LineAggregator").Reference<ITemplateLineAggregator<object>>("AggregatorKey")
    .Register();

// Template Line aggregator
container.StepScopeRegistration<ITemplateLineAggregator<object>, MyTemplateLineAggregator>("AggregatorKey")
    .Property("Template").Resource("#{settings['…']}")
    .Property("TemplateId").Value("EMPLOYEE")
    .Register();

With such a setup, even though a default TemplateId is assigned, it becomes possible to change it programmatically and to drive writer at will.

Example 7.28. TemplateLineAggregator usage in a process


[Dependency("AggregatorKey")]
public ITemplateLineAggregator<object> WriteTemplateLineAggregator { get; set; }

[Dependency("AdapterKey")]
public IProcessWriter<object> WriteTemplateLineWriter { get; set; }

public EmployeeBO Process(EmployeeBO employee)
{
    
    WriteTemplateLineAggregator.TemplateId = "HEADER";
    WriteTemplateLineWriter.WriteInProcess(DateTime.Now);
    WriteTemplateLineAggregator.TemplateId = "EMPLOYEE";
    WriteTemplateLineWriter.WriteInProcess(employee);
    WriteTemplateLineAggregator.TemplateId = "FOOTER";
    WriteTemplateLineWriter.WriteInProcess(null);
    
}

Please note that GetParameters method of the aggregator class must be adapted to handle different types of input objects.

Example 7.29. GetParameters method for heterogeneous inputs


protected override IEnumerable<object> GetParameters(object obj)
{
    IList<object> parameters = new List<object>();

    if ("HEADER".Equals(TemplateId))
    {
        parameters.Add((DateTime)obj);
    }
    else if ("EMPLOYEE".Equals(TemplateId))
    {
        var employee = (EmployeeBO)obj;
        parameters.Add(employee.Id);
        parameters.Add(employee.Name);
    }

    // Returns an empty list if FOOTER
    return parameters;
}