/*******************************************************************************
$Source: /cvs/repositories/openii3/project/java/examples/org/any_openeai_enterprise/services/egs/commands/GreetingGenerationCommand.java,v $
$Revision: 1.2 $
*******************************************************************************/
/**********************************************************************
This file is part of the OpenEAI sample, reference implementation,
and deployment management suite created by Tod Jackson
(tod@openeai.org) and Steve Wheat (steve@openeai.org).
Copyright (C) 2003 The OpenEAI Software Foundation
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For specific licensing details and examples of how this software
can be used to implement integrations for your enterprise, visit
http://www.OpenEai.org/licensing.
*/
package org.any_openeai_enterprise.services.egs.commands;
// Core Java and utilities
import java.io.*;
import java.util.*;
import javax.jms.*;
// Log4j
import org.apache.log4j.*;
// General OpenEAI Foundation
import org.openeai.afa.*;
import org.openeai.config.*;
import org.openeai.dbpool.*;
import org.openeai.jms.producer.*;
import org.openeai.threadpool.*;
import org.openeai.moa.*;
// OpenEAI Implementations Message Objects
import org.any_openeai_enterprise.moa.objects.resources.v1_0.Greetee;
import org.any_openeai_enterprise.moa.jmsobjects.coreapplication.v1_0.Greeting;
/**
* This is an OpenEAI implementation of the classic "Hello, World" example.
* This command demonstrates the example service called the
* EnterpriseGreetingService by reading a file with the names of people or
* things to greet and using those names to send requests to the
* EnterpriseGreetingService to generate greetings for these names.
* <P>
* 1. org.any-openeai-enterprise.CoreApplication.Greeting.Generate-Request
* <P>
* Specifically, this command reads an input file specified in the deployment
* descriptor. The format of the expected input file is one name of a person
* or thing to be greeted per line of the input file. The command uses the
* names in the file as the FullName for Greetee objects required to build
* the Greeting.Generate-Request. The command logs runtime events and
* maintains some basic runtime statistics for demonstration purposes.
* <P>
* <TABLE BORDER=2 CELLPADDING=5 CELLSPACING=2>
* <TR>
* <TH>Name</TH>
* <TH>Required</TH>
* <TH>Description</TH>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>inputFileName</TD>
* <TD>yes</TD>
* <TD>The path and name of the input file to read containing names of the
* people or things to greet.</TD>
* </TR>
* <TR HALIGN="left" VALIGN="top">
* <TD>useThreads</TD>
* <TD>no (default is 'false')</TD>
* <TD>Send the generate requests in a single thread or use a thread pool
* as configured in the deployment descriptor. The default value is false,
* indicating not to use threads, if this property is not specified in the
* deployment descriptor.</TD>
* </TR>
* </TABLE>
* <P>
* @author Steve Wheat (steve@openeai.org)
* @version 1.0 - 27 September 2003
*/
public class GreetingGenerationCommand extends ScheduledCommandImpl implements
ScheduledCommand {
private boolean m_useThreads = false;
private ProducerPool m_egsProducerPool = null;
private ThreadPool m_threadPool = null;
private int m_successCount = 0;
private int m_errorCount = 0;
private String m_inputFileName = null;
private int m_sleepInterval = 500;
private Date m_applicationStartTime = null;
/**
* @param CommandConfig
* @throws InstantiationException
* <P>
* This constructor initializes the command using a CommandConfig object. It
* invokes the constructor of the ancestor, ScheduledCommandImpl, and then
* gets the value of the application start time, gets and sets genernal
* properties for the command, gets and sets the value of the inputFileName,
* and gets and sets the value of the useThreads indicator. Note that if
* the useThreads property is not specified in the configuration,
* its default value is false.
*/
public GreetingGenerationCommand(CommandConfig cConfig) throws
InstantiationException {
super(cConfig);
logger.info("[GreetingGenerationCommand] Initializing...");
// Get the application start time.
setApplicationStartTime(getCurrentTime());
// Set the properties for this command.
try {
PropertyConfig pConfig = (PropertyConfig)getAppConfig()
.getObject("GreetingGenerationCommandProperties");
setProperties(pConfig.getProperties());
}
catch (EnterpriseConfigurationObjectException ecoe) {
// An error occurred retrieving a property config from AppConfig. Log it
// and throw an exception.
String errMsg = "An error occurred retrieving a property config from " +
"AppConfig. The exception is: " + ecoe.getMessage();
logger.fatal("[GreetingGenerationCommand] " + errMsg);
throw new InstantiationException(errMsg);
}
// Get the value of the useThreads property, so we can determine whether
// or not to use threads.
if (getProperties().getProperty("useThreads", "false")
.equalsIgnoreCase("true")) {
setUseThreads(true);
}
logger.info("[GreetingGenerationCommand] The value of useThreads is: " +
getUseThreads());
// Get the value of the inputFileName property.
String inputFileName = getProperties().getProperty("inputFileName");
if (inputFileName == null) {
String errMsg = "Missing 'inputFileName' property in the " +
"deployment descriptor. Can't continue.";
logger.fatal("[GreetingGenerationCommand] " + errMsg);
throw new InstantiationException(errMsg);
}
setInputFileName(inputFileName);
logger.info("[GreetingGenerationCommand] Using input file located at: " +
getInputFileName());
// If we are going to use threads, get a thread pool from AppConfig to use.
if (getUseThreads() == true) {
try {
ThreadPool threadPool = null;
threadPool = (ThreadPool)getAppConfig()
.getObject("GreetingGenerationThreadPool");
setThreadPool(threadPool);
}
catch (EnterpriseConfigurationObjectException ecoe) {
// An error occurred retrieving a thread pool from AppConfig. Log it and
// throw an exception.
String errMsg = "An error occurred retrieving a thread pool from " +
"AppConfig. The exception is: " + ecoe.getMessage();
logger.fatal("[GreetingGenerationCommand] " + errMsg);
throw new InstantiationException(errMsg);
}
}
// Get the producer pool we specified in the deployment descriptor from
// AppConfig. There should be one producer pool for messaging with
// the EnterpriseGreetingService named P2pEgsProducer.
try {
// Get the producer pool to use for communicating with EGS.
ProducerPool egsProducerPool = (ProducerPool)getAppConfig()
.getObject("P2pEgsProducer");
setEgsProducerPool(egsProducerPool);
}
catch(EnterpriseConfigurationObjectException ecoe) {
// An error occurred retrieving a required producer pool from AppConfig.
// Log it and throw an exception.
String errMsg = "An error occurred retrieving a producer pool from " +
"AppConfig. The exception is: " + ecoe.getMessage();
logger.fatal("[GreetingGenerationCommand] " + errMsg);
throw new InstantiationException(errMsg);
}
logger.info("[GreetingGenerationCommand] Initialization complete.");
}
/**
* @return int, a return code for the command execution
* @throws ScheduledCommandException
* <P>
* This execute method gets the start time for this execution and resets
* execution specific counters, which are used in the execution summary
* statistics. It then attempts to read the input file specified into a list.
* If the input file does not exist or if there is an error reading the input
* file, the command throws a ScheduledCommandException with details of the
* error.
* <P>
* If the file has been read into memory successfully, the command pulls the
* file lines out of the list for processing ignoring any blank lines. The
* command gets a point-to-point producer for sending requests to use in
* processing each line. If the command is supposed to use threads, it
* instantiates a ProcessInputLine transaction for each line and adds them to
* the thread pool. In adding jobs to the thread pool, the command must
* attempt to add each job until it is successfully added to the pool. If the
* thread pool is throttled to check before processing, it is possible that
* jobs cannot be accepted by the pool at any given point in time. If the
* command is not supposed to use threads, it instatiates a ProcessInputLine
* transaction for each line and executes them in sequence in the main
* execution thread of the command. If threads were used to process the input
* file, the command waits for all threads to complete, then calculates and
* outputs summary statistics for the current execution, and then returns.
*/
public int execute() throws ScheduledCommandException {
logger.info("[GreetingGenerationCommand] Executing...");
// Get the start time for this execution.
java.util.Date executionStartTime = getCurrentTime();
// Reset counters for this execution.
resetCounters();
// Read the input file into a vector.
logger.info("[GreetingGenerationCommand.execute] Reading file " +
getInputFileName());
String inputFileLine;
Reader reader = null;
try { reader = new FileReader(getInputFileName()); }
catch (FileNotFoundException fnfe) {
// The input file does not exist. Log it and throw an exception.
String errMsg = "The input file " + getInputFileName() + " does not " +
"exist.";
logger.fatal("[GreetingGenerationCommand.exectue] " + errMsg);
throw new ScheduledCommandException(errMsg);
}
BufferedReader br = new BufferedReader(reader);
Vector vLines = new Vector();
logger.debug("[GreetingGenerationCommand.execute] Started reading the " +
"input file into memory.");
try {
while (br.ready()) {
inputFileLine = br.readLine();
if (inputFileLine != null && inputFileLine.trim().length() > 0) {
vLines.add(inputFileLine);
}
}
}
catch (IOException ioe) {
// An error occurred reading the input file. Log it and throw an
// exception.
String errMsg = "An error occurred reading the input file. The " +
"exception is: " + ioe.getMessage();
logger.fatal("[GreetingGenerationCommand.exectue] " + errMsg);
throw new ScheduledCommandException(errMsg);
}
logger.debug("[GreetingGenerationCommand.execute] Finished reading the " +
"input file into memory.");
logger.info("[GreetingGenerationCommand.execute] There are " + vLines.size()
+ " lines in the input file.");
// Pull the inputFileLines back out of the vector for processing.
int numberOfLines = vLines.size();
for (int lineNumber=1; lineNumber <= numberOfLines; ++lineNumber) {
String currentLine = (String)vLines.elementAt(0);
vLines.removeElementAt(0);
// Skip any blank lines.
if (currentLine == null || currentLine.length() == 0) {
logger.debug("[GreetingGenerationCommand.execute] Skipping line " +
lineNumber + ", because it is blank.");
continue;
}
// Get a producer from the producer pool to use in processing this line.
PointToPointProducer p2p = null;
try {
p2p = (PointToPointProducer)getEgsProducerPool().getProducer();
}
catch (JMSException jmse) {
// An error occurred getting a producer from the producer pool. Log it
// and throw an exception.
String errMsg = "An error occurred getting a producer from the " +
"producer pool. The exception is: " + jmse.getMessage();
logger.fatal("[GreetingGenerationCommand.execute] " + errMsg);
throw new ScheduledCommandException(errMsg);
}
// If we are using threads, the delegate the processing of this input line
// to the threadpool.
if (getUseThreads()) {
// If this thread pool is set to check for available threads before
// adding jobs to the pool, it may throw an exception indicating it
// is busy when we try to add a job. We need to catch that exception
// and try to add the job until we are successful.
boolean jobAdded = false;
while (jobAdded == false) {
try {
getThreadPool().addJob(new ProcessInputLine(lineNumber, currentLine,
p2p));
jobAdded = true;
}
catch (ThreadPoolException tpe) {
// The thread pool is busy. Log it and sleep briefly to try to add
// the job again later.
String msg = "The thread pool is busy. Sleeping for " +
getSleepInterval() + " milliseconds.";
logger.debug("[GreetingGenerationCommand.execute] " + msg);
try { Thread.sleep(getSleepInterval()); }
catch (InterruptedException ie) {
// An error occurred while sleeping to allow threads in the pool
// to clear for processing. Log it and throw and exception.
String errMsg = "An error occurred while sleeping to allow " +
"threads in the pool to clear for processing. The exception " +
"is " + ie.getMessage();
logger.fatal("[GreetingGenerationCommand.execute] " + errMsg);
throw new ScheduledCommandException(errMsg);
}
}
}
}
// Otherwise, if we are not using threads, just process the current line
// in the current command execution thread.
else {
new ProcessInputLine(lineNumber, currentLine, p2p).run();
}
}
// If we are using threads, wait for all threads to complete.
if (getUseThreads()) {
while (getThreadPool().getJobsInProgress() > 0) {
try { Thread.sleep(getSleepInterval()); }
catch (InterruptedException ie) {
// An error occurred while sleeping to allow threads in the pool
// to complete. Log it and throw and exception.
String errMsg = "An error occurred while sleeping to allow " +
"threads in the pool to complete. The exception " +
"is " + ie.getMessage();
logger.fatal("[GreetingGenerationCommand.execute] " + errMsg);
throw new ScheduledCommandException(errMsg);
}
}
}
logger.info("[GreetingGenerationCommand.execute] All lines in the input " +
"file have been processed, summarizing...");
// Get the end time and summarize run-time statistics.
java.util.Date executionEndTime = getCurrentTime();
long executionTime =
((executionEndTime.getTime() - executionStartTime.getTime()) / 1000);
long totalTime =
((executionEndTime.getTime() - getApplicationStartTime().getTime()) /
1000);
logger.info("[GreetingGenerationCommand] Application start time: " +
getApplicationStartTime());
logger.info("[GreetingGenerationCommand] Execution start time: " +
executionStartTime);
logger.info("[GreetingGenerationCommand] Execution end time: " +
executionEndTime);
logger.info("[GreetingGenerationCommand] Execution time: " +
executionTime + " seconds");
logger.info("[GreetingGenerationCommand] Application run time: " +
totalTime + " seconds");
logger.info("[GreetingGenerationCommand] Greeting successes: " +
getSuccessCount());
logger.info("[GreetingGenerationCommand] Greeting failures: " +
getErrorCount());
logger.info("[GreetingGenerationCommand] Exiting.");
return 0;
}
/**
* @return java.util.Date, the current time as a date.
* <P>
* Returns the current time as a date.
*/
private final java.util.Date getCurrentTime() {
Calendar myCal = new GregorianCalendar();
return myCal.getTime();
}
/**
* @param boolean, indicates whether or not to use threads.
* <P>
* Sets the use threads indicator.
*/
private void setUseThreads(boolean useThreads) {
m_useThreads = useThreads;
}
/**
* @return boolean, indicates whether or not to use threads.
* <P>
* Returns the use threads indicator.
*/
private boolean getUseThreads() {
return m_useThreads;
}
/**
* @param int, the sleep interval or number of milliseconds to sleep for
* thread operations such as waiting to add jobs or waiting for jobs
* to complete.
* <P>
* Sets the sleep interval.
*/
private void setSleepInterval(int sleepInterval) {
m_sleepInterval = sleepInterval;
}
/**
* @return int, the sleep interval or number of milliseconds to sleep for
* thread operations such as waiting to add jobs or waiting for jobs
* to complete.
* <P>
* Returns the sleep interval.
*/
private int getSleepInterval() {
return m_sleepInterval;
}
/**
* @param String, the input file name.
* <P>
* Sets the input file name.
*/
private void setInputFileName(String inputFileName) {
m_inputFileName = inputFileName;
}
/**
* @return String, the input file name.
* <P>
* Returns the input file name.
*/
private String getInputFileName() {
return m_inputFileName;
}
/**
* @param ThreadPool, the thread pool for the command to use.
* <P>
* Sets the thread pool for the command to use.
*/
private void setThreadPool(ThreadPool threadPool) {
m_threadPool = threadPool;
}
/**
* @return ThreadPool, the thread pool for the command to use.
* <P>
* Returns the thread pool for the command to use.
*/
private ThreadPool getThreadPool() {
return m_threadPool;
}
/**
* @param ProducerPool, the producer pool for the command to use to
* communicate with EGS.
* <P>
* Sets the producer pool for the command to use to communicate with EGS.
*/
private void setEgsProducerPool(ProducerPool producerPool) {
m_egsProducerPool = producerPool;
}
/**
* @return ProducerPool, the producer pool for the command to use to
* communicate with EGS.
* <P>
* Returns the producer pool for the command to use to communicate with EGS.
*/
private ProducerPool getEgsProducerPool() {
return m_egsProducerPool;
}
/**
* @param Date, the application start time.
* <P>
* Sets the application start time.
*/
private void setApplicationStartTime(java.util.Date applicationStartTime) {
m_applicationStartTime = applicationStartTime;
}
/**
* @return Date, the application start time.
* <P>
* Returns the application start time.
*/
private Date getApplicationStartTime() {
return m_applicationStartTime;
}
/**
* Resets the error count for a command execution to zero.
*/
private synchronized void resetCounters() {
m_errorCount = 0;
m_successCount = 0;
}
/**
* @return int, the error count for a command execution.
* <P>
* Returns the error count for a command execution.
*/
private int getErrorCount() {
return m_errorCount;
}
/**
* @return int, the error count for a command execution.
* <P>
* Increments the error count for a command execution.
*/
private synchronized int incrementErrorCount() {
return ++m_errorCount;
}
/**
* @return int, the success count for a command execution.
* <P>
* Returns the success count for a command execution.
*/
private int getSuccessCount() {
return m_successCount;
}
/**
* @return int, the success count for a command execution.
* <P>
* Increments the success count for a command execution.
*/
private synchronized int incrementSuccessCount() {
return ++m_successCount;
}
/**
* A runnable class for processing input file lines.
*/
private class ProcessInputLine implements java.lang.Runnable {
private int m_lineNumber = 0;
private String m_line = null;
private PointToPointProducer m_p2p = null;
/**
* @param int, the line number from the input file to processed.
* @param String, the line from the input file to process.
* @param PointToPointProducer, producer to use to send generate requests.
* <P>
* This constructor sets the values of the line number, line, and point-
* to-point producer fields that will be used when this transaction runs.
*/
public ProcessInputLine(int lineNumber, String line, PointToPointProducer
p2p) {
m_lineNumber = lineNumber;
m_line = line;
m_p2p = p2p;
}
/**
* This method processes the input file line by getting a configured
* greetee object and greeting object from AppConfig. If an error occurs
* getting these object from AppConfig, it logs the error, increments the
* error counter, and returns. This sample application does not attempt to
* track and reattempt failed lines like any production application should.
* Then this method sets the value of the greetee's full name to be the
* trimmed value of the input line. If an error occurs setting this value,
* the it logs the error, increments the error counter, and returns.
* Then the method sends a Greeting.Generate-Request to generate a
* greeting using the greetee. If an error occurs generating the greeting,
* it logs the error, increments the error counter, and returns. Finally,
* this method logs the greeting that was generated for the input file line,
* increments the success counter and returns.
*/
public void run() {
logger.debug("[ProcessInputLine] Processing line " + m_lineNumber + ": " +
m_line);
// Get a greeting and a greetee object from AppConfig to use in
// processing this line.
Greeting greeting = null;
Greetee greetee = null;
try {
greeting = (Greeting)getAppConfig().getObject("Greeting");
greetee = (Greetee)getAppConfig().getObject("Greetee");
}
catch (EnterpriseConfigurationObjectException ecoe) {
// An error occurred retrieving an object from AppConfig. Log it,
// increment the error count, and return.
String errMsg = "An error occurred retrieving an object from " +
"AppConfig. The exception is: " + ecoe.getMessage();
logger.fatal("[ProcessInputLine.run] An error occurred processing " +
"line number " + m_lineNumber + ": " + errMsg);
incrementErrorCount();
return;
}
// Set the full name of the greetee.
try { greetee.setFullName(m_line.trim()); }
catch (EnterpriseFieldException efe) {
// An error occurred setting the value of the full name for the
// greetee. Log it, increment the error count, and return.
String errMsg = "An error occurred setting the value of the full name "
+ "of the greetee. The exception is: " + efe.getMessage();
logger.fatal("[ProcessInputLine.run] An error occurred processing " +
"line number " + m_lineNumber + ": " + errMsg);
incrementErrorCount();
return;
}
// Generate the greeting.
List results = null;
try {
logger.info("[ProcessInputLine.run] Sending a Greeting.Generate-" +
"Request for: " + greetee.getFullName());
results = greeting.generate(greetee, m_p2p);
}
catch (EnterpriseObjectGenerateException eoge) {
if (eoge.getMessage().toLowerCase().indexOf("time") != -1) {
// The error was a timeout error. Log it.
String errMsg = "Timed out waiting for reply.";
logger.fatal("[ProcessInputLine.run] " + errMsg);
}
else {
// An error occurred generating the greeting. Log it.
String errMsg = "An error occurred generating the greeting. The " +
"exception is: " + eoge.getMessage();
logger.fatal("[ProcessInputLine.run] " + errMsg);
eoge.printStackTrace();
}
// Increment the error count and return.
incrementErrorCount();
return;
}
// Display the greeting that was generated by EGS.
for (int i=0; i < results.size(); i++) {
greeting = (Greeting)results.get(i);
logger.info("[ProcessInputLine.run] Greeting returned for '" +
greetee.getFullName() + "' is: " + greeting.getText());
}
logger.debug("[ProcessInputLine.run] Completed processing line " +
m_lineNumber + ": " + m_line);
// Increment the success counter and return.
incrementSuccessCount();
return;
}
}
}