Chapter 3. Example

Table of Contents

3.1. Overview
3.2. Configuring Data Source
3.3. Configuring jeus-web-dd.xml
3.4. Configuring a Job
3.5. JBatchServlet
3.6. ItemReader
3.7. ItemWriter
3.8. ItemProcessor

This section provides an example of a JBatch application developed in JEUS.

3.1. Overview

The example provided in this section describes a simple application that executes a batch job requested from a JEUS servlet and returns the results to the client.

The following figure shows the structure of the WAR file of a Java batch application.

[Figure 3.1] WAR File Structure of a Java Batch Application

WAR File Structure of a Java Batch Application

3.2. Configuring Data Source

Before running a JBatch application on JEUS, you should define a data source used to execute JBatch jobs. Currently, JEUS supports Apache Derby, which can be connected to by using JEUS_HOME/bin/startderby.cmd in Windows, and JEUS_HOME/bin/startderby in Linux. Specify the export name of the data source as "jdbc/batch".

Note

Only Apache Derby is supported now. Other databases have not been verified yet, and thus are not recommended for use.

The following is an example of a data source defined in the domain.xml file.

[Example 3.1] Configuring a DataSource: <<domain.xml>>

<domain>
  <data-source>
  ...
    <database>
      <data-source-id>jdbc/batch</data-source-id>
      <data-source-class-name>
           org.apache.derby.jdbc.ClientConnectionPoolDataSource
      </data-source-class-name>
      <data-source-type>ConnectionPoolDataSource</data-source-type>
      <server-name>localhost</server-name>
      <port-number>1527</port-number>
      <database-name>derbyDB</database-name>
      <user>app</user>
      <password>app</password>
      <property>
        <name>ConnectionAttributes</name>
        <type>java.lang.String</type>
        <value>;create=true</value>
      </property>
    </database>
  </data-source>
</domain>

3.3. Configuring jeus-web-dd.xml

A thread pool can be configured with the batch-thread-pool element in jeus-web-dd to execute a job. If it is not specified, it is set to the default thread pool. For details, refer to "2.2.1. Configuring Thread Pools in Component DD".

3.4. Configuring a Job

Job specifications are defined in an XML file including the name, steps, ItemReader, ItemWriter, and ItemProcessor. The XML file should be located in the META-INF/batch-jobs/ directory.

Note

For a WAR file, a META-INF directory should be placed in the /WEB-INF/classes directory for successful operation.

The following is an example of configuring the /WEB-INF/classes/META-INF/batch-jobs/simple_file_batch.xml file.

[Example 3.2] Configuring a Job: <<simple_file_batch.xml>>

<job id="demo" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
    <step id="step1">
        <chunk>
            <reader ref="tmaxsoft.bhkim.test.filebatch.FileItemReader">
                <properties>
                    <property name="filePath" value="#{jobParameters['filePath']}" />
                </properties>
            </reader>
            <processor ref="tmaxsoft.bhkim.test.filebatch.StringToPersonProcessor" />
            <writer ref="tmaxsoft.bhkim.test.filebatch.LogWriter" />
        </chunk>
    </step>
</job>

3.5. JBatchServlet

The JBatchServlet hands the job configuration file (.xml) as well as the JobParameters to the JobOperator.

The following is an example of passing the path to the personList.txt file that contains data used for processing a filePath into a key.

[Example 3.3] JBatchServlet Example

@WebServlet("/JBatchServlet")
public class JBatchServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private final String FILE_PATH = "META-INF/task/personList.txt";

    public JBatchServlet() {
        super();
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        Properties jobParams = new Properties();
        URL personListURL = Thread.currentThread().getContextClassLoader().getResource(FILE_PATH);
        jobParams.setProperty("filePath", personListURL.getPath());

        JobOperator operator = BatchRuntime.getJobOperator();
        // xml file name without format
        long id = operator.start("simple_file_batch", jobParams);

        waitForEnd(operator, id);

        response.getWriter().println("File Batch is successfully precessed.");
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

    public static void waitForEnd(final JobOperator jobOperator, final long id) {
        final Collection<BatchStatus> endStatuses = Arrays.asList(BatchStatus.COMPLETED, BatchStatus.FAILED);
        do {
            try {
                Thread.sleep(100);
            } catch (final InterruptedException e) {
                return;
            }
        } while (!endStatuses.contains(jobOperator.getJobExecution(id).getBatchStatus()));
    }
}

FILE_PATH contains the following definitions:

Name1,27,Computer Science
Name2,22,English Education
Name3,23,Electronic Engineering

3.6. ItemReader

An ItemReader reads an item in. Below is an example of FileItemReader, an ItemReader with four functions--open, close, readtem, and checkpointinfo. In the following example, the ItemReader reads a line of data as an item.

Serializable, a parameter variable of the open function, verifies a checkpoint so that when a job is abnormally terminated, an ItemReader can begin at the last checkpoint.

Note

Injections may not work for pure batch logic except when made into a servlet or an EJB.

The following is an example of a FileItemReader with the open function implemented to bookmark a recordNumber after every readltem so that the FileItemReader can begin from the last recordNumber in case the job has been abnormally terminated.

[Example 3.4] FileItemReader Example

public class FileItemReader implements ItemReader {

    @Inject
    @BatchProperty
    private String filePath; // JobProperties in xml setting is injected to the field

    private BufferedReader reader = null;

    private int recordNumber;

    @Override
    public void open(Serializable checkpoint) throws Exception {
        if (filePath == null)
            throw new RuntimeException("Can't find any input");

        final File file = new File(filePath);
        if (!file.exists())
            throw new RuntimeException("A file '" + filePath + "' doesn't exist");

        reader = new BufferedReader(new FileReader(file));

        if (checkpoint != null) {
            assert (checkpoint instanceof Integer);
            recordNumber = (Integer) checkpoint;

            // Pass over latest checkpoint record
            for (int i = 1; i < recordNumber; i++)
                reader.readLine();
        }
    }

    @Override
    public void close() throws Exception {
        if (reader != null)
            reader.close();
    }

    @Override
    public Object readItem() throws Exception {
        Object item = reader.readLine();

        // checkpoint line update
        recordNumber++;
        return item;
    }

    @Override
    public Serializable checkpointInfo() throws Exception {
        return recordNumber;
    }

}


3.7. ItemWriter

Below is an example of a LogWriter, which is an ItemWriter with four functions--open, close, wirteItems, and checkpointInfo. The list of items to be processed by writeItem is handed.

Note

Injections may not work for pure batch logic except when made into a servlet or an EJB.

The following is an example of using an internally defined logger to write out a list of items received.

[Example 3.5] ItemWriter Example

public class LogWriter implements ItemWriter {
    private static final Logger logger = Logger.getLogger(LogWriter.class.getSimpleName());
    int writeRecordNumber; //

    @Override
    public void open(Serializable checkpoint) throws Exception {
    }

    @Override
    public void close() throws Exception {
    }


    @Override
    public void writeItems(List<Object> items) throws Exception {
        // simply print passed item to logger
        for (Object o: items) {
            logger.info("writeItems > " + o.toString());
        }
    }

    @Override
    public Serializable checkpointInfo() throws Exception {
        return null;
    }
}

3.8. ItemProcessor

An ItemProcessor processes items that have been read in by an ItemReader.

Note

Injections may not work for pure batch logic except when made into a servlet or an EJB.

The following is an example of an ItemProcessor that receives as item parameter each line of a file and processes the character strings into the form of a Person object. The objects are passed to an ItemWriter after a phase.

[Example 3.6] ItemProcessor Example

public class StringToPersonProcessor implements ItemProcessor {

    @Override
    public Object processItem(Object item) throws Exception {
        final String[] line = String.class.cast(item).split(",");

        if (line == null || line.length != 3)
            return null;

        // name, age, department
        return new Person(line[0], Integer.parseInt(line[1]), line[2]);
    }
}

The following is the definition of the Person object to use in the ItemProcessor above.

[Example 3.7] Person Object

public class Person {
    private String name;
    private int age;
    private String department;

    public Person(String name, int age, String department) {
        this.name = name;
        this.age = age;
        this.department = department;
    }

    @Override
    public String toString() {
        return name + "," + age + "," + department;
    }
}