내용 목차
This section provides an example of a JBatch application developed in JEUS.
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 figure below shows the structure of the WAR file of a Java batch application.
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".
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.
[예 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>
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".
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.
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.
[예 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>
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.
[예 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
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.
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.
[예 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; } }
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.
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.
[예 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; } }
An ItemProcessor processes items that have been read in by an ItemReader.
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.
[예 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.
[예 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; } }