The Java EE 7 Tutorial

Previous
Next

55.8 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.

55.8.1 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.

55.8.1.1 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.

55.8.1.2 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.

55.8.1.3 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();
    }
}

55.8.1.4 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);
    }
    ...
}

55.8.1.5 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 */
    ...
}

55.8.1.6 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>

55.8.1.7 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.

55.8.2 Running the webserverlog Example Application

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

55.8.2.1 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/
    

55.8.2.2 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/
    
Previous
Next