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
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 (
LogLineandLogFilteredLine) that represent input items and output items for the chunk step. -
Three batch artifacts (
LogLineReader,LogLineProcessor, andLogFilteredLineWriter) 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 (
InfoJobListenerandInfoItemProcessListener) that implement two simple listeners. -
A batch artifact (
MobileBatchlet.java) that calculates statistics on the filtered items. -
Two Facelets pages (
index.xhtmlandjobstarted.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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
From the File menu, choose Open Project.
-
In the Open Project dialog box, navigate to:
tut-install/examples/batch -
Select the
webserverlogfolder. -
Click Open Project.
-
In the Projects tab, right-click the
webserverlogproject and select Run.This command builds and packages the application into a WAR file,
webserverlog.war, located in thetarget/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
-
Make sure that GlassFish Server has been started (see Starting and Stopping GlassFish Server).
-
In a terminal window, go to:
tut-install/examples/batch/webserverlog/ -
Enter the following command to deploy the application:
-
Open a web browser window at the following URL:
http://localhost:8080/webserverlog/