package tcg.scada.event;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import tcg.common.CorbaManager;
import tcg.common.DatabaseManager;
import tcg.common.LoggerManager;
import tcg.common.DatabaseManager.DatabaseType;
import tcg.scada.cos.CosInvalidEventContextException;
import tcg.scada.cos.ICosEventServerPOA;
import tcg.syscontrol.ManagedProcess;
import tcg.syscontrol.cos.CosOperationModeEnum;
import tcg.syscontrol.cos.CosPollException;
import tcg.syscontrol.cos.CosPollNotInModeException;
import tcg.syscontrol.cos.CosProcessStatusEnum;
import tcg.syscontrol.cos.CosProcessTypeEnum;
import tcg.syscontrol.cos.ICosProcessManager;
import tcg.syscontrol.cos.ICosProcessManagerHelper;
import tcg.syscontrol.cos.STR_EVENT_SERVER;
public class EventServer extends ICosEventServerPOA
{
// general error threshold
@SuppressWarnings("unused")
private static final int DEF_ERROR_THRESHOLD = 3;
// how many times I attempt to do failed corba operation
// NOTE: internally, jacorb has tried several times before reporting failure
// on a
// corba operation. so we do not need to try multiple times anymore
private static final int CORBA_ERROR_THRESHOLD = 1;
// private static final String HSQLDB_DRIVER = "org.hsqldb.jdbcDriver";
// private static final String HSQLDB_USER = "sa";
// private static final String HSQLDB_PASSWORD = "";
private static final String DATAPOINT_TABLE = "SCADA_DATAPOINT";
private static final String EQUIPMENT_TABLE = "SCADA_EQUIPMENT";
private static final String EVENT_TABLE = "SCADA_EVENT_CONFIG";
protected static Logger logger_ = LoggerManager.getLogger(EventServer.class
.toString());
private CosProcessStatusEnum state_ = CosProcessStatusEnum.StatUnstarted;
private ManagedProcess parent_ = null;
private ICosProcessManager procManager_ = null;
private String serverKey_ = "";
private int corbaPort_ = 0;
private long pid_ = 0;
private int managerPort_ = 0;
private boolean hasManager_ = true;
private Properties props_ = null;
// we use distinct database for events to one for configuration
// even if it actually point to the same database
// private DatabaseType dbType_ = DatabaseType.HSQLDB;
private String dbConnString_ = "";
private String dbUser_ = "";
private String dbPassword_ = "";
private Connection dbConn_ = null;
private Calendar calendar_ = new GregorianCalendar();
private int sequence_ = 1;
// peer name and port number if we are running stand-alone without process
// manager
private String peerName_ = "";
private int peerPort_ = 0;
private HashMap<Integer, EventContext> contexts_ = new HashMap<Integer, EventContext>();
private HashMap<Integer, EventMessage> sharedEvents_ = new HashMap<Integer, EventMessage>();
/**
* Constructor
*
* @param agent
* - the managed process (event agent)
*/
public EventServer(ManagedProcess agent)
{
parent_ = agent;
// workingDir_ = agent.getWorkingDirectory();
corbaPort_ = agent.getCorbaPort();
pid_ = agent.cosGetProcessId();
hasManager_ = agent.isManagedAgent();
managerPort_ = agent.getProcessManagerPort();
props_ = agent.getRuntimeProperties();
peerName_ = agent.getPeerName();
peerPort_ = agent.getPeerPort();
// server key to register with process manager
serverKey_ = STR_EVENT_SERVER.value;
}
/**
* Initialize event server
*
* @return true if initialization is successful
*/
public boolean initialize()
{
state_ = CosProcessStatusEnum.StatStartup;
// initialize the corba manager. if it is already initialize, this does
// nothing
if (!CorbaManager.initialize(corbaPort_))
{
logger_.error("Cannot initialize Corba Manager");
state_ = CosProcessStatusEnum.StatUnstarted;
return false;
}
// activate servant with this corba manager
logger_.debug("Activating corba servant...");
if (!CorbaManager.activate(this, serverKey_))
{
logger_.error("Cannot activate servant datapoint store.");
state_ = CosProcessStatusEnum.StatUnstarted;
return false;
}
if (hasManager_)
{
if (!register_with_process_manager())
{
logger_.error("Couldn't register with Process Manager!");
state_ = CosProcessStatusEnum.StatUnstarted;
return false;
}
}
else
{
// make sure reference to process manager is null. just in case
// somebody mess around with it.
procManager_ = null;
}
state_ = CosProcessStatusEnum.StatStarted;
return true;
}
/**
* Start CONTROL mode. It is called when we are going to control mode.
*/
protected boolean startControl()
{
// not initialized yet
if (state_ == CosProcessStatusEnum.StatUnstarted
|| state_ == CosProcessStatusEnum.StatStopped)
return false;
// already in the state
if (state_ == CosProcessStatusEnum.StatGoingToControl
|| state_ == CosProcessStatusEnum.StatRunningControl)
{
return true;
}
// open connection to event database. this is distinct than
// configuration database
// even if we actually point to the same database
if (!initialize_database_connection())
{
return false;
}
// //create internal sqldb connection to cache list of events,
// equipments, and datapoints.
// String dbUrl = "jdbc:hsqldb:file:" + workingDir_ + "/eventdb";
//
// //load the jdbc class
// try
// {
// Class.forName(HSQLDB_DRIVER);
// }
// catch (Exception ex)
// {
// logger_.error("Can not load jdbc driver: " + HSQLDB_DRIVER + ". " +
// ex.getMessage());
// return false;
// }
//
// hsqldb_ = null;
// for (int i = 0; i < DEF_ERROR_THRESHOLD && null == hsqldb_; i++)
// {
// try
// {
// hsqldb_ = DriverManager.getConnection(dbUrl, HSQLDB_USER,
// HSQLDB_PASSWORD);
// }
// catch (SQLException sqle)
// {
// logger_.warn("Can not open event database: " + dbUrl +
// ". Exception: "
// + sqle.getMessage().trim());
// //in case the file is still locked by previous active process
// try
// {
// Thread.sleep(100);
// }
// catch(InterruptedException ie)
// {
// //ignore
// }
// }
// }
//
// if (hsqldb_ == null)
// {
// return false;
// }
//
// //synchronize the cached event database
// if (!synchronize_hsqldb())
// {
// return false;
// }
// notify process manager
update_operation_mode(CosOperationModeEnum.OperControl);
logger_.info("Event Server is RUNNING CONTROL.");
state_ = CosProcessStatusEnum.StatRunningControl;
return true;
}
/**
* Stop CONTROL mode. It called when we are leaving control mode.
*/
protected boolean stopControl()
{
// close the event database if necessary
try
{
dbConn_.close();
dbConn_ = null;
}
catch (Exception ex)
{
// ignore
}
// notify process manager
update_operation_mode(CosOperationModeEnum.OperNotApplicable);
state_ = CosProcessStatusEnum.StatNotRunning;
return true;
}
/**
* Start MONITOR mode. It called when we are going to monitor mode. In
* MONITOR mode, we just idle happily.
*/
protected boolean startMonitor()
{
// not initialized yet
if (state_ == CosProcessStatusEnum.StatUnstarted
|| state_ == CosProcessStatusEnum.StatStopped)
return false;
// already in the state
if (state_ == CosProcessStatusEnum.StatGoingToMonitor
|| state_ == CosProcessStatusEnum.StatRunningMonitor)
{
return true;
}
// notify process manager
update_operation_mode(CosOperationModeEnum.OperMonitor);
logger_.info("Event Server is RUNNING MONITOR.");
state_ = CosProcessStatusEnum.StatRunningMonitor;
return true;
}
/**
* Stop MONITOR mode. It called when we are leaving monitor mode.
*/
protected boolean stopMonitor()
{
// since nothing is running in monitor mode, nothing need to be stopped
// notify process manager
update_operation_mode(CosOperationModeEnum.OperNotApplicable);
state_ = CosProcessStatusEnum.StatNotRunning;
return true;
}
/*
* (non-Javadoc)
*
* @see ste.plan.cos.ICosPlanServerOperations#cosGetOperationMode()
*/
public CosOperationModeEnum cosGetOperationMode()
{
CosOperationModeEnum retval = null;
if (state_ == CosProcessStatusEnum.StatRunningControl)
{
retval = CosOperationModeEnum.OperControl;
}
else if (state_ == CosProcessStatusEnum.StatRunningMonitor)
{
retval = CosOperationModeEnum.OperMonitor;
}
else
{
retval = CosOperationModeEnum.OperNotApplicable;
}
return retval;
}
/*
* (non-Javadoc)
*
* @see ste.plan.cos.ICosPlanServerOperations#cosGetProcessStatus()
*/
public CosProcessStatusEnum cosGetProcessStatus()
{
return state_;
}
/*
* (non-Javadoc)
*
* @see ste.syscontrol.cos.ICosMonitoredThreadOperations#cosGetProcessId()
*/
public long cosGetProcessId()
{
return pid_;
}
/*
* (non-Javadoc)
*
* @see ste.syscontrol.cos.ICosMonitoredThreadOperations#cosGetProcessType()
*/
public CosProcessTypeEnum cosGetProcessType()
{
return CosProcessTypeEnum.ProcThread;
}
/*
* (non-Javadoc)
*
* @see ste.syscontrol.cos.ICosMonitoredThreadOperations#cosPoll()
*/
public void cosPoll() throws CosPollException
{
return;
}
/*
* (non-Javadoc)
*
* @see ste.syscontrol.cos.ICosMonitoredThreadOperations#cosPollControl()
*/
public void cosPollControl() throws CosPollException,
CosPollNotInModeException
{
if (state_ != CosProcessStatusEnum.StatRunningControl)
{
throw new CosPollNotInModeException();
}
}
/*
* (non-Javadoc)
*
* @see ste.syscontrol.cos.ICosMonitoredThreadOperations#cosPollMonitor()
*/
public void cosPollMonitor() throws CosPollException,
CosPollNotInModeException
{
if (state_ != CosProcessStatusEnum.StatRunningMonitor)
{
throw new CosPollNotInModeException();
}
}
private boolean register_with_process_manager()
{
// build the corbaloc ior
String corbaloc = "corbaloc::localhost:" + managerPort_
+ "/ProcessManager";
// verbose
if (logger_.isTraceEnabled())
logger_.trace("corbaloc: " + corbaloc);
// get the reference
try
{
org.omg.CORBA.Object obj = CorbaManager.stringToObject(corbaloc);
procManager_ = ICosProcessManagerHelper.narrow(obj);
}
catch (Exception ex)
{
logger_.warn("Can not build reference to process manager: "
+ corbaloc);
return false;
}
for (int i = 0; i < CORBA_ERROR_THRESHOLD; i++)
{
try
{
procManager_.cosRegisterCorbaServer(serverKey_, this._this());
// succesful
return true;
}
catch (Exception ex)
{
logger_
.error("("
+ i
+ ") Couldn't register with Process Manager. Exception: "
+ ex.toString());
// ignore
}
}
return false;
}
private void update_operation_mode(CosOperationModeEnum mode)
{
if (procManager_ == null)
{
// not connected to a process manager
return;
}
// check connection to process manager
try
{
procManager_.cosPoll();
}
catch (Exception ex)
{
logger_.error("Cannot connect to Process Manager. Exception: "
+ ex.toString());
return;
}
// update operation mode
for (int i = 0; i < CORBA_ERROR_THRESHOLD; i++)
{
try
{
procManager_
.cosUpdateCorbaServerOperationMode(serverKey_, mode);
break;
}
catch (Exception ex)
{
logger_.error("(" + i
+ ") Cannot update operation mode of server. "
+ "Exception: " + ex.toString());
}
}
} // update_operation_mode()
private boolean initialize_database_connection()
{
// get configuration from runtime properties
boolean isEncrypted = false;
if (0 == props_.getProperty("tcg.event.db.encrypted", "")
.compareToIgnoreCase("true"))
{
isEncrypted = true;
}
// get connection parameter
String dbTnsname = props_.getProperty("tcg.event.db.name", "");
;
String dbUsername = props_.getProperty("tcg.event.db.user", "");
String dbPassword = props_.getProperty("tcg.event.db.password", "");
if (isEncrypted)
{
dbPassword = DatabaseManager.decrypt(dbUsername);
}
// get the database type
DatabaseType dbType = null;
String dbTypeString = props_.getProperty("tcg.event.db.type", "");
if (dbTypeString.equalsIgnoreCase("ORACLE"))
{
dbType = DatabaseType.ORACLE;
}
else if (dbTypeString.equalsIgnoreCase("MYSQL"))
{
dbType = DatabaseType.MYSQL;
}
else
{
dbType = DatabaseType.HSQLDB; // default
}
// set local parameters
// dbType_ = dbType;
dbConnString_ = DatabaseManager.buildJdbcUrl(dbType, dbTnsname,
dbUsername);
dbUser_ = dbUsername;
dbPassword_ = dbPassword;
// open the connection
dbConn_ = null;
try
{
dbConn_ = DriverManager.getConnection(dbConnString_, dbUser_,
dbPassword_);
}
catch (SQLException sqle)
{
logger_.warn("Can not open connection to event database: "
+ dbConnString_ + ". Exception: " + sqle.toString());
return false;
}
// open prepared statement for event writing
// TODO
return true;
}
// private boolean create_hsqldb_structure()
// {
// //TODO
// return true;
// }
//
// private boolean synchronize_hsqldb()
// {
// if (hsqldb_ == null)
// {
// return false;
// }
//
// //check the cache database structure
// //TODO
//
// if (!synchronize_datapoint_cache())
// {
// return false;
// }
//
// if (!synchronize_equipment_cache())
// {
// return false;
// }
//
// if (!synchronize_event_cache())
// {
// return false;
// }
//
// return true;
// }
//
// private boolean synchronize_datapoint_cache()
// {
// //compare the database timestamp and the cached events timestamp
// java.sql.Date cacheTimestamp = new java.sql.Date(0);
// java.sql.Date dbTimestamp = new java.sql.Date(0);
//
// //get database timestamp
// {
// DatabaseLock _lock = new DatabaseLock(logger_);
//
// if (!_lock.isConnected())
// {
// logger_.error("Can not get database connection.");
// }
// else
// {
// dbTimestamp = get_database_timestamp(_lock.conn, "DATAPOINT");
// }
//
// _lock.cleanup();
// } //end of database critical section
//
// //get cached timestamp
// cacheTimestamp = get_database_timestamp(hsqldb_, "DATAPOINT");
//
// //only synch it if database timestamp is more recent than cache timestamp
// if (!dbTimestamp.after(cacheTimestamp))
// {
// return true; //already recent
// }
//
// //update datapoint cache
// boolean status = true;
// {
// DatabaseLock _lock = new DatabaseLock(logger_);
// if (!_lock.isConnected())
// {
// logger_.error("Can not get database connection.");
// status = false;
// }
// else
// {
// try
// {
// String updQuery = "INSERT INTO " + DATAPOINT_TABLE + " VALUES(?,?,?,?)";
// PreparedStatement updStmt = hsqldb_.prepareStatement(updQuery);
//
// String getQuery =
// "SELECT KEYID, DT_PT_NAME, DT_PT_DESC, DT_PT_DESC_LOCAL"
// + " FROM " + DATAPOINT_TABLE;
// logger_.debug("Get Query: " + getQuery);
//
// Statement stmt = _lock.conn.createStatement();
// ResultSet rs = stmt.executeQuery(getQuery);
// while (rs.next())
// {
// updStmt.setLong(1, rs.getLong(1));
// updStmt.setString(2, rs.getString(2));
// updStmt.setString(3, rs.getString(3));
// updStmt.setString(4, rs.getString(4));
// updStmt.executeUpdate();
// }
// rs.close();
// stmt.close();
//
// updStmt.close();
// }
// catch (SQLException sqle)
// {
// logger_.error("Can not synchronize datapoint cache. Exception: "
// + sqle.getMessage());
// status = false;
// }
// }
//
// _lock.cleanup();
// } //end of database critical section
//
// //update cache timestamp
// update_database_timestamp(hsqldb_, "DATAPOINT", dbTimestamp);
//
// return status;
// }
//
// private boolean synchronize_equipment_cache()
// {
// //compare the database timestamp and the cached events timestamp
// java.sql.Date cacheTimestamp = new java.sql.Date(0);
// java.sql.Date dbTimestamp = new java.sql.Date(0);
//
// //get database timestamp
// {
// DatabaseLock _lock = new DatabaseLock(logger_);
//
// if (!_lock.isConnected())
// {
// logger_.error("Can not get database connection.");
// }
// else
// {
// dbTimestamp = get_database_timestamp(_lock.conn, "EQUIPMENT");
// }
//
// _lock.cleanup();
// } //end of database critical section
//
// //get cached timestamp
// cacheTimestamp = get_database_timestamp(hsqldb_, "EQUIPMENT");
//
// //only synch it if database timestamp is more recent than cache timestamp
// if (!dbTimestamp.after(cacheTimestamp))
// {
// return true; //already recent
// }
//
// //update datapoint cache
// boolean status = true;
// {
// DatabaseLock _lock = new DatabaseLock(logger_);
// if (!_lock.isConnected())
// {
// logger_.error("Can not get database connection.");
// status = false;
// }
// else
// {
// try
// {
// String updQuery = "INSERT INTO " + EQUIPMENT_TABLE +
// " VALUES(?,?,?,?,?)";
// PreparedStatement updStmt = hsqldb_.prepareStatement(updQuery);
//
// //only retrieve equipment with asset name!
// String getQuery =
// "SELECT KEYID, DT_NODE_NAME, ASSET_NAME, DT_NODE_DESC, DT_NODE_DESC_LOCAL"
// + " FROM " + EQUIPMENT_TABLE + " WHERE ASSET_NAME IS NOT NULL";
// logger_.debug("Get Query: " + getQuery);
//
// Statement stmt = _lock.conn.createStatement();
// ResultSet rs = stmt.executeQuery(getQuery);
// while (rs.next())
// {
// updStmt.setLong(1, rs.getLong(1));
// updStmt.setString(2, rs.getString(2));
// updStmt.setString(3, rs.getString(3));
// updStmt.setString(4, rs.getString(4));
// updStmt.setString(5, rs.getString(5));
// updStmt.executeUpdate();
// }
// rs.close();
// stmt.close();
//
// updStmt.close();
// }
// catch (SQLException sqle)
// {
// logger_.error("Can not synchronize equipment cache. Exception: "
// + sqle.getMessage());
// status = false;
// }
// }
//
// _lock.cleanup();
// } //end of database critical section
//
// //update cache timestamp
// update_database_timestamp(hsqldb_, "EQUIPMENT", dbTimestamp);
//
// return status;
// }
//
// private boolean synchronize_event_cache()
// {
// //compare the database timestamp and the cached events timestamp
// java.sql.Date cacheTimestamp = new java.sql.Date(0);
// java.sql.Date dbTimestamp = new java.sql.Date(0);
//
// //get database timestamp
// {
// DatabaseLock _lock = new DatabaseLock(logger_);
//
// if (!_lock.isConnected())
// {
// logger_.error("Can not get database connection.");
// }
// else
// {
// dbTimestamp = get_database_timestamp(_lock.conn, "EVENT");
// }
//
// _lock.cleanup();
// } //end of database critical section
//
// //get cached timestamp
// cacheTimestamp = get_database_timestamp(hsqldb_, "EVENT");
//
// //only synch it if database timestamp is more recent than cache timestamp
// if (!dbTimestamp.after(cacheTimestamp))
// {
// return true; //already recent
// }
//
// //update datapoint cache
// boolean status = true;
// {
// DatabaseLock _lock = new DatabaseLock(logger_);
// if (!_lock.isConnected())
// {
// logger_.error("Can not get database connection.");
// status = false;
// }
// else
// {
// try
// {
// String updQuery = "INSERT INTO " + EVENT_TABLE + " VALUES(?,?,?)";
// PreparedStatement updStmt = hsqldb_.prepareStatement(updQuery);
//
// String getQuery = "SELECT EVENTID, MESSAGE, MESSAGE_LOCAL"
// + " FROM " + EVENT_TABLE;
// logger_.debug("Get Query: " + getQuery);
//
// Statement stmt = _lock.conn.createStatement();
// ResultSet rs = stmt.executeQuery(getQuery);
// while (rs.next())
// {
// updStmt.setLong(1, rs.getLong(1));
// updStmt.setString(2, rs.getString(2));
// updStmt.setString(3, rs.getString(3));
// updStmt.executeUpdate();
// }
// rs.close();
// stmt.close();
//
// updStmt.close();
// }
// catch (SQLException sqle)
// {
// logger_.error("Can not synchronize event cache. Exception: "
// + sqle.getMessage());
// status = false;
// }
// }
//
// _lock.cleanup();
// } //end of database critical section
//
// //update cache timestamp
// update_database_timestamp(hsqldb_, "EVENT", dbTimestamp);
//
// return status;
// }
private java.sql.Date get_database_timestamp(Connection conn,
String category)
{
// use category in database version to fine tune what has changed in the
// database
java.sql.Date timestamp = new java.sql.Date(0);
try
{
String query = "SELECT DATETIME FROM SYS_VERSION WHERE CATEGORY='"
+ category + "'";
logger_.debug("Query: " + query);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
if (rs.next())
{
timestamp = rs.getDate(1);
}
rs.close();
stmt.close();
}
catch (SQLException sqle)
{
logger_.error("Can not get database timestamp. Exception: "
+ sqle.getMessage());
}
return timestamp;
}
private void update_database_timestamp(Connection conn, String category,
java.sql.Date date)
{
try
{
String query = "UPDATE SYS_VERSION SET DATETIME=? WHERE CATEGORY=?";
logger_.debug("Query: " + query);
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setDate(1, date);
stmt.setString(2, category);
stmt.executeUpdate();
stmt.close();
}
catch (SQLException sqle)
{
logger_.error("Can not update database timestamp. Exception: "
+ sqle.getMessage());
}
}
private int generate_unique_number()
{
return sequence_++;
}
private void write_event(EventContext ctx, int eventId, Date timestamp,
String message, String messageLocal)
{
// TODO
// dummy
logger_.info(timestamp.toString() + " [" + ctx.id + "-DEFAULT] "
+ message);
logger_.info(timestamp.toString() + " [" + ctx.id + "-LOCAL] "
+ messageLocal);
}
/*
* (non-Javadoc)
*
* @see
* ste.scada.cos.ICosEventServerOperations#cosCreateEventContext(java.lang
* .String, java.lang.String, java.lang.String, int)
*/
public int cosCreateEventContext(String operator, String machine,
String application, int timeout)
{
EventContext ctx = null;
synchronized (contexts_)
{
ctx = new EventContext(this, timeout);
ctx.operator = operator;
ctx.machine = machine;
ctx.application = application;
// get a unique id
ctx.id = generate_unique_number();
while (contexts_.containsKey(ctx.id))
{
ctx.id = generate_unique_number();
}
// insert into the list
contexts_.put(ctx.id, ctx);
}
return ctx.id;
}
/*
* (non-Javadoc)
*
* @see ste.scada.cos.ICosEventServerOperations#cosDeleteEventContext(int)
*/
public void cosDeleteEventContext(int ctxId)
{
synchronized (contexts_)
{
contexts_.remove(ctxId);
}
}
public void cosLoadEvents(int ctxId, int[] eventList)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// pass it to the context
ctx.loadEvents(eventList);
}
public void cosSetDatapointName(int ctxId, int keyId)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// pass it to the context
ctx.setDatapoint(keyId);
}
public void cosSetDatapointName2(int ctxId, String datapoint)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// pass it to the context
ctx.setDatapoint(datapoint);
}
public void cosSetEquipmentName(int ctxId, int keyId)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// pass it to the context
ctx.setEquipment(keyId);
}
public void cosSetEquipmentName2(int ctxId, String equipment)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// pass it to the context
ctx.setEquipment(equipment);
}
public void cosWriteEvent(int ctxId, String message)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// write the event
write_event(ctx, 0, calendar_.getTime(), message, message);
}
public void cosWriteEventLocal(int ctxId, String message,
String messageLocal) throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// write the event
write_event(ctx, 0, calendar_.getTime(), message, messageLocal);
}
public void cosWriteEventId(int ctxId, int eventId)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// build the message
String message = ctx.buildMessage(eventId, null);
String messageLocal = ctx.buildLocalMessage(eventId, null);
// write the event
write_event(ctx, eventId, calendar_.getTime(), message, messageLocal);
}
public void cosWriteEventIdParam(int ctxId, int eventId, String[] params)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// build the message
String message = ctx.buildMessage(eventId, params);
String messageLocal = ctx.buildLocalMessage(eventId, params);
// write the event
write_event(ctx, eventId, calendar_.getTime(), message, messageLocal);
}
public void cosWriteEventIdParamLocal(int ctxId, int eventId,
String[] params, String[] paramsLocal)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// build the message
String message = ctx.buildMessage(eventId, params);
String messageLocal = ctx.buildLocalMessage(eventId, paramsLocal);
// write the event
write_event(ctx, eventId, calendar_.getTime(), message, messageLocal);
}
public void cosHeartbeat(int ctxId) throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// pass to context
ctx.heartbeat();
}
public void cosSetCategory(int ctxId, String category)
throws CosInvalidEventContextException
{
// get the context
EventContext ctx = contexts_.get(ctxId);
if (ctx == null)
{
throw new CosInvalidEventContextException();
}
// pass to context
ctx.category = category;
}
/**
* Get the event message associated with an event id. If no event is found
* for this event id, a dummy event is created.
*
* @param eventId
* - the event id
* @return the event message if event id is valid, a dummy event message if
* it is not.
*/
protected EventMessage getEvent(int eventId)
{
// try to get from the shared list
EventMessage evt = sharedEvents_.get(eventId);
if (evt == null)
{
// get the info from database
String[] info = getEventInfo(eventId);
// create the event
evt = new EventMessage(eventId, info[0], info[1]);
}
// increase the reference counter
evt.refCounter++;
return evt;
}
/**
* Return an event message after the event context that using it terminates.
* If the reference counter for the event message is 0, then this event
* message will be deleted from the shared event list.
*
* @param evt
* - the event message
*/
protected void returnEvent(EventMessage evt)
{
// decrease the reference counter
evt.refCounter--;
// if refcounter == 0, destroy it.
sharedEvents_.remove(evt.eventId);
return;
}
/**
* Get equipment info
*
* @param equipment
* - the equipment name
* @return the equipment info as array of string {assetname, desc,
* localdesc}. if the equipment name is invalid, a dummy info is
* created.
*/
protected String[] getEquipmentInfo(String equipment)
{
String[] info = new String[3];
// get connection
Connection conn = DatabaseManager.getConnection();
if (conn == null)
return info;
boolean status = false;
int errorCode = 0;
try
{
String query = "SELECT ASSET_NAME, DESCRIPTION, DESCRIPTION_LOCAL"
+ " FROM " + EQUIPMENT_TABLE + " WHERE NAME='" + equipment
+ "'";
logger_.debug("Get Query: " + query);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
if (rs.next())
{
info[0] = rs.getString(1);
info[1] = rs.getString(2);
if (rs.wasNull())
{
info[1] = "no-description:" + info[0];
}
info[2] = rs.getString(3);
if (rs.wasNull())
{
info[2] = info[1];
}
status = true;
}
}
catch (SQLException sqle)
{
logger_.error("Can not get equipment info for " + equipment
+ ". Exception: " + sqle.toString());
errorCode = sqle.getErrorCode();
}
// if we fail to retrieve the info, create a default
if (!status)
{
info[0] = "invalid-equipment:" + equipment;
info[1] = info[0];
info[2] = info[0];
}
// return the connection
DatabaseManager.returnConnection(errorCode);
return info;
}
/**
* Get equipment info
*
* @param keyid
* - the equipment key id
* @return the equipment info as array of string {eqptname, assetname, desc,
* localdesc}. if the equipment id is invalid, a dummy info is
* created.
*/
protected String[] getEquipmentInfo(int keyid)
{
String[] info = new String[4];
// get connection
Connection conn = DatabaseManager.getConnection();
if (conn == null)
return info;
boolean status = false;
int errorCode = 0;
try
{
String query = "SELECT NAME, ASSET_NAME, DESCRIPTION, DESCRIPTION_LOCAL"
+ " FROM " + EQUIPMENT_TABLE + " WHERE KEYID=" + keyid;
logger_.debug("Get Query: " + query);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
if (rs.next())
{
info[0] = rs.getString(1);
info[1] = rs.getString(2);
if (rs.wasNull())
{
info[1] = "not-asset:" + info[0];
}
info[2] = rs.getString(3);
if (rs.wasNull())
{
info[2] = "no-description:" + info[0];
}
info[3] = rs.getString(4);
if (rs.wasNull())
{
info[3] = info[2];
}
status = true;
}
}
catch (SQLException sqle)
{
logger_.error("Can not get equipment info for " + keyid
+ ". Exception: " + sqle.toString());
errorCode = sqle.getErrorCode();
}
// if we fail to retrieve the info, create a default
if (!status)
{
info[0] = "invalid-equipment:" + keyid;
info[1] = info[0];
info[2] = info[0];
info[3] = info[0];
}
// return the connection
DatabaseManager.returnConnection(errorCode);
return info;
}
/**
* Get datapoint info
*
* @param datapoint
* - the datapoint name
* @return the datapoint info as array of string {desc, localdesc, eqptname,
* assetname, eqptdesc, eqptlocaldesc}. if the datapoint name is
* invalid, a dummy info is created.
*/
protected String[] getDatapointInfo(String datapoint)
{
String[] info = new String[6];
// get connection
Connection conn = DatabaseManager.getConnection();
if (conn == null)
return info;
boolean status = false;
int errorCode = 0;
int eqptKey = 0;
try
{
String query = "SELECT DESCRIPTION, DESCRIPTION_LOCAL, EQUIPMENT_ID"
+ " FROM "
+ DATAPOINT_TABLE
+ " WHERE NAME='"
+ datapoint
+ "'";
logger_.debug("Get Query: " + query);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
if (rs.next())
{
info[0] = rs.getString(1);
if (rs.wasNull())
{
info[0] = "no-description:" + datapoint;
}
info[1] = rs.getString(2);
if (rs.wasNull())
{
info[1] = info[0];
}
eqptKey = rs.getInt(3);
status = true;
}
}
catch (SQLException sqle)
{
logger_.error("Can not get datapoint info for " + datapoint
+ ". Exception: " + sqle.toString());
errorCode = sqle.getErrorCode();
}
// if we fail to retrieve the info, create a default
if (!status)
{
info[0] = "invalid-datapoint:" + datapoint; // desc
info[1] = info[0]; // local desc
info[2] = info[0]; // equipment name
info[3] = info[0]; // asset name
info[4] = info[0]; // equipment desc
info[5] = info[0]; // equipment local desc
}
else
{
// get the equipment info
String[] eqptinfo = getEquipmentInfo(eqptKey);
// copy over
info[2] = eqptinfo[0]; // equipment name
info[3] = eqptinfo[1]; // asset name
info[4] = eqptinfo[2]; // equipment desc
info[5] = eqptinfo[3]; // equipment local desc
}
// return the connection
DatabaseManager.returnConnection(errorCode);
return info;
}
/**
* Get datapoint info
*
* @param datapoint
* - the datapoint name
* @return the datapoint info as array of string {dpname, desc, localdesc,
* eqptname, assetname, eqptdesc, eqptlocaldesc}. if the datapoint
* name is invalid, a dummy info is created.
*/
protected String[] getDatapointInfo(int keyid)
{
String[] info = new String[7];
// get connection
Connection conn = DatabaseManager.getConnection();
if (conn == null)
return info;
boolean status = false;
int errorCode = 0;
int eqptKey = 0;
try
{
String query = "SELECT NAME, DESCRIPTION, DESCRIPTION_LOCAL, EQUIPMENT_ID"
+ " FROM " + DATAPOINT_TABLE + " WHERE KEYID=" + keyid;
logger_.debug("Get Query: " + query);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
if (rs.next())
{
info[0] = rs.getString(1);
info[1] = rs.getString(2);
if (rs.wasNull())
{
info[1] = "no-description:" + info[0];
}
info[2] = rs.getString(3);
if (rs.wasNull())
{
info[2] = info[1];
}
eqptKey = rs.getInt(4);
status = true;
}
}
catch (SQLException sqle)
{
logger_.error("Can not get datapoint info for " + keyid
+ ". Exception: " + sqle.toString());
errorCode = sqle.getErrorCode();
}
// if we fail to retrieve the info, create a default
if (!status)
{
info[0] = "invalid-datapoint:" + keyid; // desc
info[1] = info[0]; // dp name
info[2] = info[0]; // local desc
info[3] = info[0]; // equipment name
info[4] = info[0]; // asset name
info[5] = info[0]; // equipment desc
info[6] = info[0]; // equipment local desc
}
else
{
// get the equipment info
String[] eqptinfo = getEquipmentInfo(eqptKey);
// copy over
info[3] = eqptinfo[0]; // equipment name
info[4] = eqptinfo[1]; // asset name
info[5] = eqptinfo[2]; // equipment desc
info[6] = eqptinfo[3]; // equipment local desc
}
// return the connection
DatabaseManager.returnConnection(errorCode);
return info;
}
/**
* Get event info
*
* @param eventId
* - the event id
* @return the event info as array of string {expression, localexpression}.
* if the event if is invalid, a dummy info is created.
*/
protected String[] getEventInfo(int eventId)
{
String[] info = new String[2];
// get connection
Connection conn = DatabaseManager.getConnection();
if (conn == null)
return info;
boolean status = false;
int errorCode = 0;
try
{
String query = "SELECT EXPRESSION, EXPRESSION_LOCAL" + " FROM "
+ EVENT_TABLE + " WHERE KEYID=" + eventId;
logger_.debug("Get Query: " + query);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(query);
if (rs.next())
{
info[0] = rs.getString(1);
info[1] = rs.getString(2);
if (rs.wasNull())
{
info[1] = info[0];
}
status = true;
}
}
catch (SQLException sqle)
{
logger_.error("Can not get event info for " + eventId
+ ". Exception: " + sqle.toString());
errorCode = sqle.getErrorCode();
}
// if we fail to retrieve the info, create a default
if (!status)
{
info[0] = "invalid-event:" + eventId;
info[1] = info[0];
}
// return the connection
DatabaseManager.returnConnection(errorCode);
return info;
}
}
class EventContext
{
public int id = 0;
public String operator = "";
public String machine = "";
public String application = "";
public String category = "";
public String assetName_ = "";
@SuppressWarnings("unused")
private String equipment_ = "";
private String equipmentDesc_ = "";
private String equipmentDescLocal_ = "";
@SuppressWarnings("unused")
private String datapoint_ = "";
private String datapointDesc_ = "";
private String datapointDescLocal_ = "";
private int timeoutMillis_ = 0;
private Date timeout_ = new Date();
private HashMap<Integer, EventMessage> events_ = new HashMap<Integer, EventMessage>();
private EventServer parent_ = null;
/**
* Constructor.
*
* @param server
* - the event server
* @param timeoutMillis
* - the event context timeout, in milliseconds.
*/
public EventContext(EventServer server, int timeoutMillis)
{
parent_ = server;
timeoutMillis_ = timeoutMillis;
}
/**
* Cleanup this event context.
*/
public void cleanup()
{
// remove the refcounter for all loaded events
// if nobody else is using it, the events is deleted from the global
// shared events
Iterator<Entry<Integer, EventMessage>> it = events_.entrySet()
.iterator();
while (it.hasNext())
{
parent_.returnEvent(it.next().getValue());
}
}
/**
* Load and parse a list of events for usage later on. This speed up the
* write event because we would not need to load and parse the event
* anymore.
*
* @param eventList
* - list of event id to pre-load and pre-parse.
*/
public void loadEvents(int[] eventList)
{
// validation
if (eventList == null)
return;
// load a list of events
for (int i = 0; i < eventList.length; i++)
{
// get from parent. parent will create the event if necessary
parent_.logger_.info("Loading event-id: " + eventList[i]);
EventMessage evt = parent_.getEvent(eventList[i]);
if (evt == null)
{
continue;
}
events_.put(evt.eventId, evt);
}
}
/**
* Received a heartbeat from client. This will reset the timeout counter.
*/
public void heartbeat()
{
timeout_.setTime(Calendar.getInstance().getTime().getTime()
+ timeoutMillis_);
}
/**
* Check if the currect event context has timed out.
*
* @return true if it has already timed out.
*/
public boolean hasTimeout()
{
return Calendar.getInstance().getTime().after(timeout_);
}
/**
* Set the equipment name. We would then retrieve the asset name and
* description.
*
* @param equipment
* - the equipment name
*/
public void setEquipment(String equipment)
{
// input validation
if (equipment == null || equipment.length() == 0)
{
return;
}
equipment_ = equipment;
String[] info = parent_.getEquipmentInfo(equipment);
if (info != null)
{
assetName_ = info[0];
equipmentDesc_ = info[1];
equipmentDescLocal_ = info[2];
}
}
/**
* Set the equipment name using its keyiw. We would then retrieve the asset
* name and description.
*
* @param equipment
* - the equipment name
*/
public void setEquipment(int keyid)
{
// input validation
if (keyid == 0)
{
return;
}
String[] info = parent_.getEquipmentInfo(keyid);
if (info != null)
{
equipment_ = info[0];
assetName_ = info[1];
equipmentDesc_ = info[2];
equipmentDescLocal_ = info[3];
}
}
/**
* Set the datapoint name. We would then retrieve the datapoint description.
*
* @param datapoint
* - the datapoint name
*/
public void setDatapoint(String datapoint)
{
// input validation
if (datapoint == null || datapoint.length() == 0)
{
return;
}
datapoint_ = datapoint;
// since datapoint always belongs to equipment parent, set the equipment
// as well
String[] info = parent_.getDatapointInfo(datapoint);
if (info != null)
{
datapointDesc_ = info[0];
datapointDescLocal_ = info[1];
equipment_ = info[2];
assetName_ = info[3];
equipmentDesc_ = info[4];
equipmentDescLocal_ = info[5];
}
}
/**
* Set the datapoint name using its keyid. We would then retrieve the
* datapoint description.
*
* @param datapoint
* - the datapoint name
*/
public void setDatapoint(int keyid)
{
// input validation
if (keyid == 0)
{
return;
}
// since datapoint always belongs to equipment parent, set the equipment
// as well
String[] info = parent_.getDatapointInfo(keyid);
if (info != null)
{
datapoint_ = info[0];
datapointDesc_ = info[1];
datapointDescLocal_ = info[2];
equipment_ = info[3];
assetName_ = info[4];
equipmentDesc_ = info[5];
equipmentDescLocal_ = info[6];
}
}
/**
* Build an event message based on event template.
*
* @param eventId
* - the event id
* @param parameters
* - list of parameters
* @return the event message
*/
public String buildMessage(int eventId, String[] parameters)
{
// validation
if (eventId == 0)
{
return "";
}
EventMessage evt = events_.get(eventId);
if (evt == null)
{
// get from parent. parent will create the event if necessary
evt = parent_.getEvent(eventId);
if (evt == null)
{
return "";
}
events_.put(eventId, evt);
}
// make sure we do not get NullPointerException
String[] _params = null;
if (evt.messageSegments.size() > 0)
{
_params = new String[evt.messageSegments.size()];
for (int i = 0; i < _params.length; i++)
{
_params[i] = "";
}
}
// copy from the given param
if (parameters != null && parameters.length > 0)
{
for (int i = 0; i < parameters.length && i < _params.length; i++)
{
if (parameters[i] == null)
continue;
_params[i] = parameters[i];
}
}
return buildMessage(evt, _params);
}
/**
* Build a localized event message based on event template.
*
* @param eventId
* - the event id
* @param parameters
* - list of parameters
* @return the localized event message
*/
public String buildLocalMessage(int eventId, String[] parameters)
{
EventMessage evt = events_.get(eventId);
if (evt == null)
{
// get from parent. parent will create the event if necessary
evt = parent_.getEvent(eventId);
if (evt == null)
{
return "";
}
events_.put(eventId, evt);
}
// make sure we do not get NullPointerException
String[] _params = null;
if (evt.messageSegments.size() > 0)
{
_params = new String[evt.messageSegments.size()];
for (int i = 0; i < _params.length; i++)
{
_params[i] = "";
}
}
// copy from the given param
if (parameters != null && parameters.length > 0)
{
for (int i = 0; i < parameters.length && i < _params.length; i++)
{
if (parameters[i] == null)
continue;
_params[i] = parameters[i];
}
}
return buildLocalMessage(evt, _params);
}
/**
* Build an event message based on event template.
*
* @param event
* - the event structure
* @param parameters
* - list of parameters
* @return the event message
*/
private String buildMessage(EventMessage evt, String[] parameters)
{
// input validation.
if (evt == null || parameters == null)
{
return "";
}
// NOTE: assume that the number of parameters is sufficient and that no
// null inside the param list
// replace operator id
if (evt.operatorIdx >= 0 && parameters[evt.operatorIdx].length() == 0
&& operator.length() > 0)
{
parameters[evt.operatorIdx] = operator;
}
// replace machine name
if (evt.machineIdx >= 0 && parameters[evt.machineIdx].length() == 0
&& machine.length() > 0)
{
parameters[evt.machineIdx] = machine;
}
// replace application name
if (evt.applicationIdx >= 0
&& parameters[evt.applicationIdx].length() == 0
&& application.length() > 0)
{
parameters[evt.applicationIdx] = application;
}
// replace category name
if (evt.categoryIdx >= 0 && parameters[evt.categoryIdx].length() == 0
&& category.length() > 0)
{
parameters[evt.categoryIdx] = category;
}
// replace asset name
if (evt.assetIdx >= 0 && parameters[evt.assetIdx].length() == 0
&& equipmentDesc_.length() > 0)
{
parameters[evt.assetIdx] = equipmentDesc_;
}
// replace datapoint desc
if (evt.datapointIdx >= 0 && parameters[evt.datapointIdx].length() == 0
&& datapointDesc_.length() > 0)
{
parameters[evt.datapointIdx] = datapointDesc_;
}
// build the string
String message = "";
int i = 0;
for (i = 0; i < (evt.messageSegments.size() - 1); i++)
{
if (parameters.length > i && parameters[i] != null
&& parameters[i].length() > 0)
{
message += evt.messageSegments.get(i) + parameters[i];
}
else
{
message += evt.messageSegments.get(i)
+ evt.paramSegments.get(i);
}
}
message += evt.messageSegments.get(i);
return message;
}
/**
* Build a localized event message based on event template.
*
* @param event
* - the event id
* @param parameters
* - list of parameters
* @return the localized event message
*/
private String buildLocalMessage(EventMessage evt, String[] parameters)
{
// input validation.
if (evt == null || parameters == null)
{
return "";
}
// NOTE: assume that the number of parameters is sufficient and that no
// null inside the param list
// replace operator id
if (evt.localOperatorIdx >= 0
&& parameters[evt.localOperatorIdx].length() == 0
&& operator.length() > 0)
{
parameters[evt.localOperatorIdx] = operator;
}
// replace machine name
if (evt.localMachineIdx >= 0
&& parameters[evt.localMachineIdx].length() == 0
&& machine.length() > 0)
{
parameters[evt.localMachineIdx] = machine;
}
// replace application name
if (evt.localApplicationIdx >= 0
&& parameters[evt.localApplicationIdx].length() == 0
&& application.length() > 0)
{
parameters[evt.localApplicationIdx] = application;
}
// replace category name
if (evt.localCategoryIdx >= 0
&& parameters[evt.localCategoryIdx].length() == 0
&& category.length() > 0)
{
parameters[evt.localCategoryIdx] = category;
}
// replace asset name
if (evt.localAssetIdx >= 0
&& parameters[evt.localAssetIdx].length() == 0
&& equipmentDescLocal_.length() > 0)
{
parameters[evt.localAssetIdx] = equipmentDescLocal_;
}
// replace datapoint desc (local)
if (evt.localDatapointIdx >= 0
&& parameters[evt.localDatapointIdx].length() == 0
&& datapointDescLocal_.length() > 0)
{
parameters[evt.localDatapointIdx] = datapointDescLocal_;
}
// build the string
String message = "";
int i = 0;
for (i = 0; i < (evt.localMessageSegments.size() - 1); i++)
{
if (parameters.length > i)
{
message += evt.localMessageSegments.get(i) + parameters[i];
}
else
{
message += evt.localMessageSegments.get(i)
+ evt.localParamSegments.get(i);
}
}
message += evt.localMessageSegments.get(i);
return message;
}
}
class EventMessage
{
private static String OPERATOR_KEYWORD = "{{OPERATOR}}";
private static String MACHINE_KEYWORD = "{{MACHINE}}";
private static String APPLICATION_KEYWORD = "{{APPLICATION}}";
private static String CATEGORY_KEYWORD = "{{CATEGORY}}";
private static String ASSET_KEYWORD = "{{EQUIPMENT}}";
private static String DATAPOINT_KEYWORD = "{{DATAPOINT}}";
private static String KEYWORD_START = "{{";
private static String KEYWORD_END = "}}";
// because '{' and '}' are special char in regex, we need to escape it
private static String KEYWORD_START_REGEX = "\\{\\{";
private static String KEYWORD_END_REGEX = "\\}\\}";
public int eventId = 0;
public ArrayList<String> messageSegments = new ArrayList<String>();
public ArrayList<String> paramSegments = new ArrayList<String>();
public ArrayList<String> localMessageSegments = new ArrayList<String>();
public ArrayList<String> localParamSegments = new ArrayList<String>();
public short operatorIdx = -1; // position in the array for operator id
public short machineIdx = -1; // position in the array for machine name
public short applicationIdx = -1; // position in the array for application
// name
public short categoryIdx = -1; // position in the array for category
public short assetIdx = -1; // position in the array for asset name
public short datapointIdx = -1; // position in the array for datapoint desc
public short localOperatorIdx = -1; // position in the array for operator id
public short localMachineIdx = -1; // position in the array for machine name
public short localApplicationIdx = -1; // position in the array for
// application name
public short localCategoryIdx = -1; // position in the array for category
public short localAssetIdx = -1; // position in the array for asset name
public short localDatapointIdx = -1; // position in the array for datapoint
// name
// reference counter used for sharing instance of events across event
// contexts.
public short refCounter = 0;
public EventMessage(int id, String message, String localMessage)
{
// input validation
if (id == 0 || message == null || message.length() == 0)
{
return;
}
// copy locally
eventId = id;
// parse the string
parse_expression(message, messageSegments, paramSegments);
// search for internal keyword
for (short i = 0; i < paramSegments.size(); i++)
{
// operator name
if (0 == paramSegments.get(i).compareToIgnoreCase(OPERATOR_KEYWORD))
{
operatorIdx = i;
}
// machine name
if (0 == paramSegments.get(i).compareToIgnoreCase(MACHINE_KEYWORD))
{
machineIdx = i;
}
// application name
if (0 == paramSegments.get(i).compareToIgnoreCase(
APPLICATION_KEYWORD))
{
applicationIdx = i;
}
// category
if (0 == paramSegments.get(i).compareToIgnoreCase(CATEGORY_KEYWORD))
{
categoryIdx = i;
}
// asset name
if (0 == paramSegments.get(i).compareToIgnoreCase(ASSET_KEYWORD))
{
assetIdx = i;
}
// datapoint desc
if (0 == paramSegments.get(i)
.compareToIgnoreCase(DATAPOINT_KEYWORD))
{
datapointIdx = i;
}
}
// if local message not specified, use the generic message
if (localMessage == null || localMessage.length() == 0)
{
localMessageSegments = messageSegments;
localParamSegments = paramSegments;
localOperatorIdx = operatorIdx;
localMachineIdx = machineIdx;
localApplicationIdx = applicationIdx;
localCategoryIdx = categoryIdx;
localAssetIdx = assetIdx;
localDatapointIdx = datapointIdx;
}
else
{
// parse it also
parse_expression(localMessage, localMessageSegments,
localParamSegments);
// search for internal keyword
for (short i = 0; i < localParamSegments.size(); i++)
{
// operator name
if (0 == localParamSegments.get(i).compareToIgnoreCase(
OPERATOR_KEYWORD))
{
localOperatorIdx = i;
}
// machine name
if (0 == localParamSegments.get(i).compareToIgnoreCase(
MACHINE_KEYWORD))
{
localMachineIdx = i;
}
// application name
if (0 == localParamSegments.get(i).compareToIgnoreCase(
APPLICATION_KEYWORD))
{
localApplicationIdx = i;
}
// category
if (0 == localParamSegments.get(i).compareToIgnoreCase(
CATEGORY_KEYWORD))
{
localCategoryIdx = i;
}
// asset name
if (0 == localParamSegments.get(i).compareToIgnoreCase(
ASSET_KEYWORD))
{
localAssetIdx = i;
}
// datapoint name
if (0 == localParamSegments.get(i).compareToIgnoreCase(
DATAPOINT_KEYWORD))
{
localDatapointIdx = i;
}
}
} // end of parsing localMessage
} // end of ctor
private void parse_expression(String message, ArrayList<String> segments,
ArrayList<String> params)
{
if (message == null || segments == null || params == null)
return;
segments.clear();
params.clear();
String segmentStr = "";
String paramStr = "";
String str = "";
// look for end separator
String[] strArr = message.split(KEYWORD_END_REGEX);
for (short i = 0; i < (strArr.length - 1); i++)
{
// precautions
if (strArr[i].length() == 0)
{
continue;
}
// always reset the string as precautions
segmentStr = "";
paramStr = "";
// look for start separator
String[] strArr2 = strArr[i].split(KEYWORD_START_REGEX);
if (strArr2.length == 1)
{
// string -> {{param-name}}
segmentStr = "";
// trim param name. string constant should not be trimmed
str = strArr2[0].trim();
if (str.length() > 0)
{
paramStr = KEYWORD_START + str + KEYWORD_END;
}
}
else if (strArr2.length == 2)
{
// string -> some-string{{param-name}}
// string constant should not be trimmed
segmentStr = strArr2[0];
// trim param name
str = strArr2[1].trim();
if (str.length() > 0)
{
paramStr = KEYWORD_START + str + KEYWORD_END;
}
}
else
{
// string -> some-string{{another-string{{param-name}}
// string constant should not be trimmed
segmentStr = strArr2[0];
for (short k = 1; k < (strArr2.length - 1); k++)
{
segmentStr += KEYWORD_START + strArr2[k];
}
// trim param name
str = strArr2[strArr2.length - 1].trim();
if (str.length() > 0)
{
paramStr = KEYWORD_START
+ strArr2[strArr2.length - 1].trim() + KEYWORD_END;
}
}
// insert into the list
segments.add(segmentStr);
params.add(paramStr);
}
// last substring is special
segments.add(strArr[strArr.length - 1]);
}
}