Java Platform, Enterprise Edition (Java EE) 8 The Java EE Tutorial

## The webserverlog Example Application

The `webserverlog` example application, located in the tut-install`/examples/batch/webserverlog/` directory, demonstrates how to use the batch framework in Java EE to analyze the log file from a web server. This example application reads a log file and finds what percentage of page views from tablet devices are product sales.

The following topics are addressed here:

- Architecture of the webserverlog Example Application

- Running the webserverlog Example Application

### Architecture of the webserverlog Example Application

The `webserverlog` example application consists of the following elements:

- A job definition file (`webserverlog.xml`) that uses the Job Specification Language (JSL) to define a batch job with a chunk step and a task step. The chunk step acts as a filter, and the task step calculates statistics on the remaining entries.

- A log file (`log1.txt`) that serves as input data to the batch job.

- Two Java classes (`LogLine` and `LogFilteredLine`) that represent input items and output items for the chunk step.

- Three batch artifacts (`LogLineReader`, `LogLineProcessor`, and `LogFilteredLineWriter`) that implement the chunk step of the application. This step reads items from the web server log file, filters them by the web browser used by the client, and writes the results to a text file.

- Two batch artifacts (`InfoJobListener` and `InfoItemProcessListener`) that implement two simple listeners.

- A batch artifact (`MobileBatchlet.java`) that calculates statistics on the filtered items.

- Two Facelets pages (`index.xhtml` and `jobstarted.xhtml`) that provide the front end of the batch application. The first page shows the log file that will be processed by the batch job, and the second page enables the user to check on the status of the job and shows the results.

- A managed bean (`JsfBean`) that is accessed from the Facelets pages. The bean submits the job to the batch runtime, checks on the status of the job, and reads the results from a text file.

#### The Job Definition File

The `webserverlog.xml` job definition file is located in the `WEB-INF/classes/META-INF/batch-jobs/` directory. The file specifies seven job-level properties and two steps:

    <?xml version="1.0" encoding="UTF-8"?>
    <job id="webserverlog" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         version="1.0">
        <properties>
            <property name="log_file_name" value="log1.txt"/>
            <property name="filtered_file_name" value="filtered1.txt"/>
            <property name="num_browsers" value="2"/>
            <property name="browser_1" value="Tablet Browser D"/>
            <property name="browser_2" value="Tablet Browser E"/>
            <property name="buy_page" value="/auth/buy.html"/>
            <property name="out_file_name" value="result1.txt"/>
        </properties>
        <listeners>
            <listener ref="InfoJobListener"/>
        </listeners>
        <step id="mobilefilter" next="mobileanalyzer"> ... </step>
        <step id="mobileanalyzer"> ... </step>
    </job>

The first step is defined as follows:

    <step id="mobilefilter" next="mobileanalyzer">
        <listeners>
            <listener ref="InfoItemProcessListeners"/>
        </listeners>
        <chunk checkpoint-policy="item" item-count="10">
            <reader ref="LogLineReader"></reader>
            <processor ref="LogLineProcessor"></processor>
            <writer ref="LogFilteredLineWriter"></writer>
        </chunk>
    </step>

This step is a normal chunk step that specifies the batch artifacts that implement each phase of the step. The batch artifact names are not fully qualified class names, so the batch artifacts are CDI beans annotated with `@Named`.

The second step is defined as follows:

    <step id="mobileanalyzer">
        <batchlet ref="MobileBatchlet"></batchlet>
        <end on="COMPLETED"/>
    </step>

This step is a task step that specifies the batch artifact that implements it. This is the last step of the job.

#### The LogLine and LogFilteredLine Items

The `LogLine` class represents entries in the web server log file and it is defined as follows:

    public class LogLine {
        private final String datetime;
        private final String ipaddr;
        private final String browser;
        private final String url;

        /* ... Constructor, getters, and setters ... */
    }

The `LogFileteredLine` class is similar to this class but only has two fields: the IP address of the client and the URL.

#### The Chunk Step Batch Artifacts

The first step is composed of the `LogLineReader`, `LogLineProcessor`, and `LogFilteredLineWriter` batch artifacts.

The `LogLineReader` artifact reads records from the web server log file:

    @Dependent
    @Named("LogLineReader")
    public class LogLineReader implements ItemReader {
        private ItemNumberCheckpoint checkpoint;
        private String fileName;
        private BufferedReader breader;
        @Inject
        private JobContext jobCtx;

        public LogLineReader() { }

        /* ... Override the open, close, readItem, and
         *     checkpointInfo methods ... */
    }

The `open` method reads the `log_file_name` property and opens the log file with a buffered reader. In this example, the log file has been included with the application under `webserverlog/WEB-INF/classes/log1.txt`:

    fileName = jobCtx.getProperties().getProperty("log_file_name");
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    InputStream iStream = classLoader.getResourceAsStream(fileName);
    breader = new BufferedReader(new InputStreamReader(iStream));

If a checkpoint object is provided, the `open` method advances the reader up to the last checkpoint. Otherwise, this method creates a new checkpoint object. The checkpoint object keeps track of the line number from the last committed chunk.

The `readItem` method returns a new `LogLine` object or null at the end of the log file:

    @Override
    public Object readItem() throws Exception {
        String entry = breader.readLine();
        if (entry != null) {
            checkpoint.nextLine();
            return new LogLine(entry);
        } else {
            return null;
        }
    }

The `LogLineProcessor` artifact obtains a list of browsers from the job properties and filters the log entries according to the list:

    @Override
    public Object processItem(Object item) {
        /* Obtain a list of browsers we are interested in */
        if (nbrowsers == 0) {
            Properties props = jobCtx.getProperties();
            nbrowsers = Integer.parseInt(props.getProperty("num_browsers"));
            browsers = new String[nbrowsers];
            for (int i = 1; i < nbrowsers + 1; i++)
                browsers[i - 1] = props.getProperty("browser_" + i);
        }

        LogLine logline = (LogLine) item;
        /* Filter for only the mobile/tablet browsers as specified */
        for (int i = 0; i < nbrowsers; i++) {
            if (logline.getBrowser().equals(browsers[i])) {
                return new LogFilteredLine(logline);
            }
        }
        return null;
    }

The `LogFilteredLineWriter` artifact reads the name of the output file from the job properties. The `open` method opens the file for writing. If a checkpoint object is provided, the artifact continues writing at the end of the file; otherwise, it overwrites the file if it exists. The `writeItems` method writes filtered items to the output file:

    @Override
    public void writeItems(List<Object> items) throws Exception {
        /* Write the filtered lines to the output file */
        for (int i = 0; i < items.size(); i++) {
            LogFilteredLine filtLine = (LogFilteredLine) items.get(i);
            bwriter.write(filtLine.toString());
            bwriter.newLine();
        }
    }

#### The Listener Batch Artifacts

The `InfoJobListener` batch artifact implements a simple listener that writes log messages when the job starts and when it ends:

    @Dependent
    @Named("InfoJobListener")
    public class InfoJobListener implements JobListener {
        ...
        @Override
        public void beforeJob() throws Exception {
            logger.log(Level.INFO, "The job is starting");
        }

        @Override
        public void afterJob() throws Exception { ... }
    }

The `InfoItemProcessListener` batch artifact implements the `ItemProcessListener` interface for chunk steps:

    @Dependent
    @Named("InfoItemProcessListener")
    public class InfoItemProcessListener implements ItemProcessListener {
        ...
        @Override
        public void beforeProcess(Object o) throws Exception {
            LogLine logline = (LogLine) o;
            llogger.log(Level.INFO, "Processing entry {0}", logline);
        }
        ...
    }

#### The Task Step Batch Artifact

The task step is implemented by the `MobileBatchlet` artifact, which computes what percentage of the filtered log entries are purchases:

    @Override
    public String process() throws Exception {
        /* Get properties from the job definition file */
        ...
        /* Count from the output of the previous chunk step */
        breader = new BufferedReader(new FileReader(fileName));
        String line = breader.readLine();
        while (line != null) {
            String[] lineSplit = line.split(", ");
            if (buyPage.compareTo(lineSplit[1]) == 0)
                pageVisits++;
            totalVisits++;
            line = breader.readLine();
        }
        breader.close();
        /* Write the result */
        ...
    }

#### The JavaServer Faces Pages

The `index.xhtml` page contains a text area that shows the web server log. The page provides a button for the user to submit the batch job and navigate to the next page:

    <body>
        ...
        <textarea cols="90" rows="25"
                  readonly="true">#{jsfBean.getInputLog()}</textarea>
        <p> </p>
        <h:form>
            <h:commandButton value="Start Batch Job"
                             action="#{jsfBean.startBatchJob()}" />
        </h:form>
    </body>

This page calls the methods of the managed bean to show the log file and submit the batch job.

The `jobstarted.xhtml` page provides a button to check the current status of the batch job and displays the results when the job finishes:

    <p>Current Status of the Job: <b>#{jsfBean.jobStatus}</b></p>
    <p>#{jsfBean.showResults()}</p>
    <h:form>
        <h:commandButton value="Check Status"
                         action="jobstarted"
                         rendered="#{jsfBean.completed==false}" />
    </h:form>

#### The Managed Bean

The `JsfBean` managed bean submits the job to the batch runtime, checks on the status of the job, and reads the results from a text file.

The `startBatchJob` method submits the job to the batch runtime:

    /* Submit the batch job to the batch runtime.
     * JSF Navigation method (return the name of the next page) */
    public String startBatchJob() {
        jobOperator = BatchRuntime.getJobOperator();
        execID = jobOperator.start("webserverlog", null);
        return "jobstarted";
    }

The `getJobStatus` method checks the status of the job:

    /* Get the status of the job from the batch runtime */
    public String getJobStatus() {
        return jobOperator.getJobExecution(execID).getBatchStatus().toString();
    }

The `showResults` method reads the results from a text file.

### Running the webserverlog Example Application

You can use either NetBeans IDE or Maven to build, package, deploy, and run the `webserverlog` example application.

The following topics are addressed here:

- To Run the webserverlog Example Application Using NetBeans IDE

- To Run the webserverlog Example Application Using Maven

#### To Run the webserverlog Example Application Using NetBeans IDE

1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

2. From the File menu, choose Open Project.

3. In the Open Project dialog box, navigate to:

       tut-install/examples/batch

4. Select the `webserverlog` folder.

5. Click Open Project.

6. In the Projects tab, right-click the `webserverlog` project and select Run.

   This command builds and packages the application into a WAR file, `webserverlog.war`, located in the `target/` directory; deploys it to the server; and launches a web browser window at the following URL:

       http://localhost:8080/webserverlog/

#### To Run the webserverlog Example Application Using Maven

1. Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).

2. In a terminal window, go to:

       tut-install/examples/batch/webserverlog/

3. Enter the following command to deploy the application:

       mvn install

4. Open a web browser window at the following URL:

       http://localhost:8080/webserverlog/

Copyright © 2017, Oracle and/or its affiliates. All rights reserved.