Package tcg.scada.event

Source Code of tcg.scada.event.EventMessage

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]);
  }

}
TOP

Related Classes of tcg.scada.event.EventMessage

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.