Package tcg.plan.step

Source Code of tcg.plan.step.StepSendControl

/**
* StepSendControl.java
*
* A plan step to send a control (digital or analog) to FEP.
*
* @author    Wahyu Yoga Pratama (wahyu@stee.stengg.com)
*
* @created      Nov 12, 2009
* @version    $$
*
* HISTORY:
* - 2009/11/12  Created.
*
* TODO:
*
*/

package tcg.plan.step;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Calendar;

import org.apache.commons.cli.BasicParser;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;

import tcg.plan.PlanStep;
import tcg.common.CorbaHelper;
//import tcg.common.DatabaseLock;
import tcg.common.DatabaseManager;
import tcg.common.LoggerManager;
import tcg.scada.cos.CosBooleanSeqHolder;
import tcg.scada.cos.CosDpErrorEnum;
import tcg.scada.cos.CosDpErrorSeqHolder;
import tcg.scada.cos.CosDpQualityEnum;
import tcg.scada.cos.CosDpValueStruct;
import tcg.scada.cos.CosDpValueUnion;
import tcg.scada.cos.ICosDataPointServer;

public class StepSendControl extends PlanStep
{
  private static String VERSION = "01.01 (20091112)";
  private static int RCC_CHECK_INTERVAL_MSEC = 1000;
  //private static int ERROR_THRESHOLD = 3;
 
  private String datapointName = "";
  private int datapointValue = 0;
 
  private String datapointType = "";
  private int locationId = 0;
  private long rccTimeoutSec = 0;
  private boolean isDigitalControl = false;
 
  //we need to provide main class for two purposes:
  //- to print version no and usage
  //- to provide legacy way of running step, which is to execute the class on its own JVM
  public static void main(String[] args)
  {
    //if no argument is specified, print usage
    if (args.length == 0)
    {
      printUsage();
      return;
    }
   
    //if arguments has "--version" or "--help", print version number and quit
    for (int i=0; i<args.length; i++)
    {
      if (args[i].equalsIgnoreCase("--version") || args[i].equalsIgnoreCase("-V"))
      {
        printVersion();
        return;
      }
      else if (args[i].equalsIgnoreCase("--help") || args[i].equalsIgnoreCase("-h"))
      {
        printUsage();
        return;
      }
    }
       
    //create the step instance
    StepSendControl instance = new StepSendControl();
   
    //reset the logger
    instance.logger = LoggerManager.getLogger(instance.getClass().toString());
   
    //execute
    instance.execute(args);
  }
 
  @Override
  protected boolean parseArgument2(String[] args)
  {
    CommandLineParser cmdLnParser = new BasicParser();
    CommandLine cmdLn = null;
    Options optArgs = new Options();

    Option cmdLineArg1 =
        new Option("dataPointName", "Data Point Name (required)");
    cmdLineArg1.setRequired(true);
    cmdLineArg1.setArgs(1);
    cmdLineArg1.setArgName("data-point-name");
    Option cmdLineArg5 =
        new Option("dataPointValue", "Data Point Value (required)");
    cmdLineArg5.setRequired(true);
    cmdLineArg5.setArgs(1);
    cmdLineArg5.setArgName("data-point-value");
   
    optArgs.addOption(cmdLineArg1);
    optArgs.addOption(cmdLineArg5);

    //parse the arguments
    try
    {
      cmdLn = cmdLnParser.parse(optArgs, args);
    }
    catch (ParseException pe)
    {
      logger.error("Can not parse argument: " + pe.getLocalizedMessage());
      HelpFormatter formatter = new HelpFormatter();
      formatter.printHelp( "Parameters:", optArgs );
      return false;
    }
   
    //get the value
    datapointName = cmdLn.getOptionValue("dataPointName");
    //only support numeric value for send control
    try
    {
      datapointValue = Integer.parseInt(cmdLn.getOptionValue("dataPointValue"));
    }
    catch(NumberFormatException nfe)
    {
      logger.error("Invalid datapoint value: " + cmdLn.getOptionValue("dataPointValue")
              + ". We only support numeric control value.");
      return false;
    }

    return true;
  }

  @Override
  protected boolean init()
  {
    //initialize database manager
    if (null == DatabaseManager.getInstance())
    {
      logger.error("Can not initialize database manager!");
      return false;
    }
   
    //database critical section
    Connection conn = DatabaseManager.getConnection();
    if (conn == null)
    {
      logger.error("Can not get connection to database!");
      return false;
    }
   
    Statement stmt = null;
    ResultSet rs = null;
    String localSQL = "";
    long keyId = 0;
    //get location id for the datapoint
    try
    {
      localSQL = "SELECT KEYID, LOCATION_ID, RETURN_CONDITION_TIMEOUT, DATA_PT_TYPE " +
        " FROM OPC_DT_PT " +
        " WHERE FEP_DP_NAME = '" + datapointName + "' ";
      logger.debug("Query: " + localSQL);
     
      stmt = conn.createStatement();
      rs = stmt.executeQuery(localSQL);
      if (rs.next())
      {
        keyId = rs.getLong("KEYID");
        locationId = rs.getInt("LOCATION_ID");
        rccTimeoutSec = rs.getLong("RETURN_CONDITION_TIMEOUT");
        datapointType = rs.getString("DATA_PT_TYPE");
      }
      rs.close();
      stmt.close();
    }
    catch (SQLException sqle)
    {
      logger.error("Can not get datapoint location id. Exception: " + sqle.toString());
      //clean up
      try
      {
        rs.close();
        stmt.close();
      }
      catch(Exception ex) {}
      DatabaseManager.returnConnection(sqle.getErrorCode());
      return false;
    }
   
    //is it digital or analog control
    if (datapointType.equalsIgnoreCase("bool"))
    {
      isDigitalControl = true;
    }
   
    //validate the value
    if (!isDigitalControl)
    {
      try
      {
        localSQL = " SELECT ALARM_VALUE FROM ALARM_STATE_DEF "
                + "WHERE KEYID=" + keyId + " AND ALARM_VALUE=" + datapointValue;
        logger.debug("Query: " + localSQL);
       
        stmt = conn.createStatement();
        rs = stmt.executeQuery(localSQL);
        if (!rs.next())
        {
          logger.error("Invalid input value! " +
                  "Datapoint: " + datapointName + ". " +
                  "Value: "+ datapointValue + "." );
          throw new SQLException();
        }
        rs.close();
        stmt.close();
      }
      catch (SQLException sqle)
      {
        logger.error("Can not validate input value. Exception: " + sqle.toString());
        //clean up
        try
        {
          rs.close();
          stmt.close();
        }
        catch(Exception ex) {}
        DatabaseManager.returnConnection(sqle.getErrorCode());
        return false;
      }
    }  //if (!datapointType.equalsIgnoreCase("bool"))
   
    //return database connection
    DatabaseManager.returnConnection(0);
   
    //initialize corba
    if (null == CorbaHelper.getInstance())
    {
      logger.error("Can not initialize corba connection!");
      return false;
    }
 
    return true;
  }

  @Override
  protected boolean close()
  {
    //nothing to do here
    return true;
  }

  @Override
  protected boolean running()
  {
    ICosDataPointServer dpServer = CorbaHelper.getActiveDataPointServer(locationId);
    if (dpServer == null)
    {
      logger.error("Can not get datapoint server for location " + locationId);
      return false;
    }
     
    //get actual datapoint name
    String[] items = new String[1];
    items[0] = datapointName.replace(".Value", "");

    //get the actual value
    CosDpValueStruct[] values = new CosDpValueStruct[1];
    values[0] = new CosDpValueStruct();
    values[0].quality = CosDpQualityEnum.QualityGood;
    values[0].timestamp = 0;
    values[0].value = new CosDpValueUnion();
   
    //storage for error
    CosDpErrorSeqHolder errors = new CosDpErrorSeqHolder();
   
    if (isDigitalControl)
    {
      //for digital control, anything other than 0 is treated as true value
      //anyway we should never send digital control with value = false.
      if (datapointValue == 0)
      {
        values[0].value.boolValue(false);
      }
      else
      {
        values[0].value.boolValue(true);
      }
    }
    else
    {
      values[0].value.longValue(datapointValue);
    }
   
    //verbose
    logger.info("Sending control. Datapoint: " + items[0] + ". Value: " + datapointValue);

    //send the control
    try
    {
      dpServer.cosSetControlItem2(items, values, errors);
      //check the error code
      if (errors.value[0].value() != CosDpErrorEnum.ErrNoError.value())
      {
        logger.error("Fail to send control. Error: "
                + CorbaHelper.DpErrorCodeToString(errors.value[0]));
        return false;
      }
    }
    catch(Exception ex)
    {
      logger.error("Fail to send control. Exception: " + ex.getMessage());
      return false;
    }
   
    //check for return condition (only if it has return condition!)
    if (rccTimeoutSec > 0)
    {
      //rcc timeout in msec
      long timeoutMSec = (Calendar.getInstance().getTimeInMillis()) + (rccTimeoutSec * 1000);
     
      //storage for RCC status
      CosBooleanSeqHolder status = new CosBooleanSeqHolder();

      boolean rccStatus = false;
      int errorCounter = 0;
      while(timeoutMSec > Calendar.getInstance().getTimeInMillis())
      {
        //check the return condition status
        try
        {
          dpServer.cosGetItemReturnConditionStatus2(items, status, errors);
          //check the error code
          if (errors.value[0].value() != CosDpErrorEnum.ErrNoError.value())
          {
            logger.warn("Fail to get return condition status. Error: "
                    + CorbaHelper.DpErrorCodeToString(errors.value[0]));
          }
          else
          {
            //no error. check the returned value
            if (status.value[0])
            {
              rccStatus = true;
              break;
            }
          }
          //reset error counter
          errorCounter = 0;
        }
        catch (Exception ex)
        {
          logger.warn("Fail to get return condition status. Exception: "
              + ex.getMessage());
          errorCounter++;
        }
       
        //avoid waiting forever for timeout when there are persistent error
        if (errorCounter > ERROR_THRESHOLD)
        {
          //we should just quit here because most probably it is a persistent error.
          break;
        }
       
        //sleep for an interval so that we do not overload the FEP
        try
        {
          Thread.sleep(RCC_CHECK_INTERVAL_MSEC);
        }
        catch(Exception ex)
        {
          //ignore
        }
      }  //while not timeout
     
      //check the overall RCC status
      if (!rccStatus)
      {
        logger.error("Return condition check (RCC) failed.");
        return false;
      }
    }  //if rccTimeout > 0
   
    //verbose
    logger.info("Send control is successful.");

    return true;
  }

  @Override
  protected void terminate()
  {
    //This will be called when PlanMaster wants to abruptly terminate the step
    //TODO
  }
 
  private static void printVersion()
  {
    //print version here
    System.out.println("Plan Send Control Step Version " + VERSION);
  }
 
  private static void printUsage()
  {
    //print usage here
    System.out.println("Plan Send Control Step Version " + VERSION);
    System.out.println("");
    System.out.println("Command Line Parameters:  ");
    System.out.println(" --plan-execution-id <plan-id>      Plan Execution ID");
    System.out.println(" --executed-node-id <node-id>       Executed Node ID");
    System.out.println(" --port-no <port-no>             Plan Master Port No");
    System.out.println(" --agent-port-no <port-no>          Plan Agent Port No");
    System.out.println(" --data-point-name <datapoint>      Data Point Name");
    System.out.println(" --data-point-value <value>         Data Point Value");
    System.out.println(" -h | --help                        Print out this help");
    System.out.println(" -v | --version                     Print out program version");
    System.out.println("");
  }
 
}
TOP

Related Classes of tcg.plan.step.StepSendControl

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.