A batch in three steps

This tutorial shows the creation of a batch in three steps.

Step 1: the task class

Here the job of the tasks is just to wait 2 seconds.

  public class MyTask implements ITask {
        
    private static final Log log = LogFactory.getLog(MyTask.class);
    
    private int id = 0;

    public MyTask(int i) {
      id = i;
    }

    public String getId() {
      return Integer.toString(id);
    }

    public void run() {
      log.info("[Task '" + getId() + "'] begin of execution");
      if (id == 3) {
        throw new TaskExecutionException("error of execution");
      }
      try {
        Thread.sleep(2000);
      } catch (InterruptedException e) {
        throw new TaskExecutionException(e);
      }
      log.info("[Task '" + getId() + "'] execution done");
    }
  }

Step 2: the batch class

Here is a simple batch that creates three tasks and prints an execution report once all tasks have been executed.

public class BatchTest implements IBatch {
        
        private static final Log log = LogFactory.getLog(BatchTest.class);

        public void init(BatchConfiguration config) throws BatchException {
                log.info("###> init");
        }

        public void execute(ITaskExecutor executor) throws BatchException {
                log.info("###> begin execute");
                int i = 0;
                while ((i++ < 5) && (executor.isRunning())) {
                        executor.execute(new MyTask(i));
                }
                log.info("###> end execute");
        }

        public void stop() throws BatchException {
                log.info("###> stop");
                
        }

        public void pause() throws BatchException {
                log.info("###> pause");
                
        }

        public void resume() throws BatchException {
                log.info("###> resume");
                
        }

        public void end(ExecutionReport report) throws BatchException {
                log.info("###> end");
                log.info("###> " + "---Execution report---");
                log.info("Begin date: " + report.getBeginDate());
                log.info("End date: " + report.getEndDate());
            log.info("Number of completed tasks: " + report.getNumberOfCompletedTasks());
            Iterator it = report.completedTasksIdIterator();
            if (it != null) {
                log.info("Completed tasks: " + buildCsvString(it));
            }
            log.info("Number of failed tasks: " + report.getNumberOfFailedTasks());
            it = report.failedTasksIdIterator();
            if (it != null) {
                log.info("Failed tasks: " + buildCsvString(it));
            }
                log.info("###> " + "----------------------");
        }
        
    public void endOfExecution(ITask task, Throwable e) {
        if (e == null) {
                log.info("task execution success: id='" + task.getId() + "'");
        } else {
                log.error("task execution failure: id='" + task.getId() + "'", e);
        }
    }

        public void manageFatalError(ExecutionReport report, Throwable throwable) {
                log.fatal("fatal error, end of the batch execution", throwable);
        }
        
        private String buildCsvString(Iterator it) {
                StringBuffer buffer = new StringBuffer("");
                boolean first = true;
                while (it.hasNext()) {
                        if (!first) {
                                buffer.append(", ");
                        }
                        buffer.append(it.next());
                        first = false;
                }
                return buffer.toString();
        }
}

Step 3: the configuration

In the configuration we just notice the batch class name, and fixing a maximum of two task executions in parallel. Please note that the configuration file is 'my-batch-fwk.properties'.

# MyBatchFramework configuration file (v. 1.0)

mbf.batch.className = net.sf.mybatchfwk.test.BatchTest

mbf.threadPool.minSize = 1
mbf.threadPool.maxSize = 2
mbf.threadPool.blockingQueueCapacity = 2

Launch & results

To launch the batch, all dependancies must be into the classpath and the configuration file so. Log4j can been used to print the logs.

java net.sf.mybatchfwk.BatchService

Here the execution logs:

12:26:33,125 INFO  [BatchTest.init] ###> init
12:26:33,140 INFO  [BatchTest.execute] ###> begin execute
12:26:33,156 INFO  [MyTask.run] [Task '1'] begin of execution
12:26:33,156 INFO  [MyTask.run] [Task '2'] begin of execution
12:26:35,156 INFO  [MyTask.run] [Task '1'] execution done
12:26:35,156 INFO  [BatchTest.endOfExecution] task execution success: id='1'
12:26:35,156 INFO  [BatchTest.execute] ###> end execute
12:26:35,156 INFO  [MyTask.run] [Task '3'] begin of execution
12:26:35,156 ERROR [BatchTest.endOfExecution] task execution failure: id='3'
net.sf.mybatchfwk.TaskExecutionException: error of execution
        at net.sf.mybatchfwk.test.MyTask.run(MyTask.java:30)
        at net.sf.mybatchfwk.PausableThreadPoolExecutor$Worker.runTask(PausableThreadPoolExecutor.java:400)
        at net.sf.mybatchfwk.PausableThreadPoolExecutor$Worker.run(PausableThreadPoolExecutor.java:421)
        at java.lang.Thread.run(Unknown Source)
12:26:35,156 INFO  [MyTask.run] [Task '4'] begin of execution
12:26:35,156 INFO  [MyTask.run] [Task '2'] execution done
12:26:35,156 INFO  [BatchTest.endOfExecution] task execution success: id='2'
12:26:35,156 INFO  [MyTask.run] [Task '5'] begin of execution
12:26:37,156 INFO  [MyTask.run] [Task '4'] execution done
12:26:37,156 INFO  [BatchTest.endOfExecution] task execution success: id='4'
12:26:37,156 INFO  [MyTask.run] [Task '5'] execution done
12:26:37,171 INFO  [BatchTest.endOfExecution] task execution success: id='5'
12:26:37,171 INFO  [BatchTest.end] ###> end
12:26:37,171 INFO  [BatchTest.end] ###> ---Execution report---
12:26:37,187 INFO  [BatchTest.end] Begin date: Sun Oct 22 12:26:33 CEST 2006
12:26:37,187 INFO  [BatchTest.end] End date: Sun Oct 22 12:26:37 CEST 2006
12:26:37,187 INFO  [BatchTest.end] Number of completed tasks: 4
12:26:37,187 INFO  [BatchTest.end] Number of failed tasks: 1
12:26:37,187 INFO  [BatchTest.end] ###> ----------------------

We can see that the tasks 1 and 2 are executed in parallel. The execution of the task 3 begins after the end of the execution of the task 1, due to the size of the thread pool.