Package tcg.scada.da

Source Code of tcg.scada.da.xxxDataPoint

package tcg.scada.da;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.concurrent.Semaphore;

import org.apache.log4j.Logger;

import tcg.common.LoggerManager;
import tcg.common.util.ExpressionParser;
import tcg.scada.cos.CosDpQualityEnum;
import tcg.scada.cos.CosDpValueStruct;
import tcg.scada.cos.CosDpValueTypeEnum;
import tcg.scada.cos.CosDpValueUnion;

public class xxxDataPoint
{
  public int keyId = 0;
  public String name = "";
  public int wordAddress = 0;
  public int bitAddress = 0;
  public int byteLength = 0;

  //with some protocol, different function code might have overlapping address
  //thus, we require this to distinguish possible mix of addressing
  public int functionCode = 0;
 
  public EDataPointType type = EDataPointType.TYPE_REAL;

  public IEquipment equipment = null;
  public DataPointServer dpServer = null;

  public ISubsystem subsystem = null;

  private static String KEYWORD_START = "{";
  private static String KEYWORD_END = "}";
  private static Logger logger_ = LoggerManager.getLogger(xxxDataPoint.class.toString());
 
  // expression value for calculated datapoint
  private String          expression_ = "";
  private ExpressionParser    expressionParser_ = null;
  private CosDpQualityEnum    expressionQuality_ = CosDpQualityEnum.QualityGood;
  private ArrayList<xxxDataPoint> expressionParams_ = null;
 
  private boolean       isEvaluated_ = false;    //used to prevent multiple recursive evaluation

  // launching condition for control point
  private String          lccExpression_ = "";
  private ExpressionParser    lccParser_ = null;
  private ArrayList<xxxDataPoint> lccParams_ = null;
 
  // return condition for control point
  private String          rccExpression_ = "";
  private ExpressionParser    rccParser_ = null;
  private ArrayList<xxxDataPoint> rccParams_ = null;

  // expression for engineering conversion
  // for linear conversion: y = mx + b
  @SuppressWarnings("unused")
  private String        engExpression_ = "";
  @SuppressWarnings("unused")
  private ExpressionParser  engParser_ = null;
 
  // data type
  private EDataPointDataType dataType_ = EDataPointDataType.TYPE_NUMBER;
  // output value
  private CosDpValueStruct outputValue_ = new CosDpValueStruct();
  // source value
  private CosDpValueStruct sourceValue_ = new CosDpValueStruct();

  // datapoint timestamp. (>< value timestamp)
  // this is used mostly to check for updates
  private long updateTimestamp_ = 0;

  // various datapoint flag
  private boolean isOverride_ = false;
  private boolean isInhibit_ = false;
  private boolean isAlarmInhibit_ = false;
  private boolean isAlarmNotAck_ = false;
  private boolean isAlarmNotNorm_ = false;

  // list of calculated points which use this datapoint as parameter
  private ArrayList<xxxDataPoint> relatedDataPoints_ = new ArrayList<xxxDataPoint>();

  // flag to prevent infinite recursive calculation
  private final Semaphore semaphore_ = new Semaphore(1, true);

  // flag to prevent multiple notification over several modification steps
  //private boolean isInModification_ = false;
 
  /**
   * Default constructor
   */
  public xxxDataPoint()
  {
    // expression quality. default to good quality. this way, we do not need to do
    // specific processing for non calculated point i.e. real point or virtual point
    expressionQuality_ = CosDpQualityEnum.QualityGood;
  }

//  public void startModification()
//  {
//    //start modification mode. in this mode, no notification or synchronization is done
//    // until endModification() is called.
//    isInModification_ = true;
//  }
// 
//  public void endModification()
//  {
//    //synchronize the value
//    int status1 = synchronizeValue();
//   
//    //update the quality
//    int status2 = updateQuality();
//   
//    //if either the value/timestamp has changed or quality has changed, send notification
//    if (status1 > 0 || status2 > 0)
//    {
//      // update the dp timestamp
//      updateTimestamp_ = Calendar.getInstance().getTimeInMillis();
//      // update notify the datapoint server
//      if (dpServer != null)
//      {
//        dpServer.onDataPointChange(this);
//      }
//      // re-evaluate all related datapoints
//      for (int i = 0; i < relatedDataPoints_.size(); i++)
//      {
//        relatedDataPoints_.get(i).evaluate();
//      }     
//    }
//   
//    isInModification_ = false;
//  }
 
  /**
   * Preferred constructor. Set the data type.
   *
   * @param dataType
   *            - the datapoint data type
   */
  public xxxDataPoint(EDataPointDataType dataType)
  {
    setDataType(dataType);
    // expression quality. default to good quality. this way, we do not need to do
    // specific processing for non calculated point i.e. real point or virtual point
    expressionQuality_ = CosDpQualityEnum.QualityGood;
  }

  /**
   * Set the data type of this datapoint
   *
   * @param dataType
   *            - the data type
   */
  public synchronized void setDataType(EDataPointDataType dataType)
  {
    dataType_ = dataType;
    // initialize the value
    switch (dataType_)
    {
      case TYPE_BOOLEAN:
        outputValue_.value.boolValue(false);
        break;
      case TYPE_NUMBER:
        outputValue_.value.longValue(0);
        break;
      case TYPE_UNSIGNED:
        outputValue_.value.unsignedValue(0);
        break;
      case TYPE_DOUBLE:
        outputValue_.value.dblValue(0.0);
        break;
      case TYPE_STRING:
        outputValue_.value.charValue("");
        break;
      case TYPE_BCD:
        // internally, BCD type is represented as number
        outputValue_.value.longValue(0);
        break;
    }
    outputValue_.timestamp = 0;
    outputValue_.quality = CosDpQualityEnum.QualityBad;
    // source value
    sourceValue_.value = outputValue_.value;
    sourceValue_.timestamp = 0;
    // source quality. default to good quality.
    // only if it is bad quality should this parameter has affect/meaning
    sourceValue_.quality = CosDpQualityEnum.QualityGood;
  }

  // get the datapoint internal data type
  public EDataPointDataType getDataType()
  {
    return dataType_;
  }

  /**
   * Helper function to initialize the datapoint state
   *
   * @param isInhibit
   *            - last known inhibit flag
   * @param isOverride
   *            - last known override flag
   * @param isAlarmInhibit
   *            - last known alarm inhibit flag
   * @param isAlarmNotAck
   *            - last known alarm not-ack flag
   * @param isAlarmNotNorm
   *            - last known alarm not-norm flag
   */
  protected synchronized void setInitialState(boolean isInhibit, boolean isOverride,
      boolean isAlarmInhibit, boolean isAlarmNotAck, boolean isAlarmNotNorm)
  {
    isInhibit_ = isInhibit;
    isOverride_ = isOverride;
    isAlarmInhibit_ = isAlarmInhibit;
    isAlarmNotAck_ = isAlarmNotAck;
    isAlarmNotNorm_ = isAlarmNotNorm;
  }

  // get the update timestamp
  public long getUpdateTimestamp()
  {
    return updateTimestamp_;
  }

  // get datapoint value timestamp
  public long getTimestamp()
  {
    return outputValue_.timestamp;
  }

  // get datapoint quality
  public CosDpQualityEnum getQuality()
  {
    return outputValue_.quality;
  }

  /**
   * Calculate the datapoint quality.
   *
   * Generally a client should never call this function. This should be triggered
   * automatically upon changes on related attributes/parameters.
   *
   * @return   - +1 if there is an updates, 0 if no updates, -1 if there is an error
   */
  protected synchronized int updateQuality()
  {
    int status = update_quality();

    if (status > 0)
    {
      // update the timestamp
      updateTimestamp_ = Calendar.getInstance().getTimeInMillis();
      // notify the datastore
      if (dpServer != null)
      {
        dpServer.onDataPointChange(this);
     
      // because, the quality of parameters affects the quality of a calculated point,
      // we need to re-evaluate all related datapoints
      for (int i = 0; i < relatedDataPoints_.size(); i++)
      {
        relatedDataPoints_.get(i).evaluate();
      }
    }
   
    return status;
  }

  /**
   * Synchronize source value and output value.
   *
   * Generally a client should never call this function. This should be triggered
   * automatically upon changes on related attributes/parameters.
   *
   * @return   - +1 if there is an updates, 0 if no updates, -1 if there is an error
   */
  protected synchronized int synchronizeValue()
  {
    int status = synchronize_value();

    if (status > 0)
    {
      // update the timestamp
      updateTimestamp_ = Calendar.getInstance().getTimeInMillis();
      // notify the datastore
      if (dpServer != null)
      {
        dpServer.onDataPointChange(this);
     
      // re-evaluate related point
      for (int i = 0; i < relatedDataPoints_.size(); i++)
      {
        relatedDataPoints_.get(i).evaluate();
      }
    }

    return status;
  }

  // get stringified datapoint value
  public String getStringifiedValue()
  {
    return CosDpValueUnion2String(outputValue_.value);
  }

  // set datapoint value with a stringified value
  protected synchronized int setStringifiedValue(String value)
  {
    // TODO: might not want to use setValue() because setValue() will create an associated event
    // whereas this function most probably is used during the initialization
    return setValue(String2CosDpValueUnion(outputValue_.value.discriminator(), value));
  }

  // get datapoint value
  public CosDpValueUnion getValue()
  {
    return outputValue_.value;
  }

  /**
   * Set the datapoint value with a value of another datapoint.
   *
   * @param value
   *            - the new data point value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  public synchronized int setValue(CosDpValueUnion value)
  {
    // pass the set-value to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceSetValue()
        && type == EDataPointType.TYPE_REAL)
    {
      if (subsystem.setValue(this, value))
      {
        return +1;
      }
      return -1;
    }
    else
    {
      int status = copy(outputValue_.value, value);

      if (status > 0)
      {
        // update the output value timestamp. if necessary we can override it later
        outputValue_.timestamp = Calendar.getInstance().getTimeInMillis();
        // update the dp timestamp
        updateTimestamp_ = outputValue_.timestamp;
        // update notify the datapoint server
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }  //if (status > 0)

      return status;
    }
  }

  /**
   * Set the datapoint value using the native type of the value.
   *
   * @param value
   *            - the new boolean value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  public synchronized int setBooleanValue(boolean value)
  {
    // pass the set-value to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceSetValue()
        && type == EDataPointType.TYPE_REAL)
    {
      // convert to associated structure
      CosDpValueUnion myValue = new CosDpValueUnion();
      myValue.boolValue(value);
      // pass to subsystem
      if (subsystem.setValue(this, myValue))
      {
        return +1;
      }
      return -1;
    }
    else
    {
      int status = setBooleanValue(outputValue_.value, value);

      if (status > 0)
      {
        // update the output value timestamp. if necessary we can override it later
        outputValue_.timestamp = Calendar.getInstance().getTimeInMillis();
        // update the dp timestamp
        updateTimestamp_ = outputValue_.timestamp;
        // update notify the datapoint server
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }  //if (status > 0)

      return status;
    }
  }

  /**
   * Set the datapoint value using the native type of the value.
   *
   * @param value
   *            - the new corba::long value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  public synchronized int setNumberValue(int value)
  {
    // pass the set-value to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceSetValue()
        && type == EDataPointType.TYPE_REAL)
    {
      // convert to associated structure
      CosDpValueUnion myValue = new CosDpValueUnion();
      myValue.longValue(value);
      // pass to subsystem
      if (subsystem.setValue(this, myValue))
      {
        return +1;
      }
      return -1;
    }
    else
    {
      int status = setNumberValue(outputValue_.value, value);

      if (status > 0)
      {
        // update the source value timestamp. if necessary we can override it later
        outputValue_.timestamp = Calendar.getInstance().getTimeInMillis();
        // update the dp timestamp
        updateTimestamp_ = outputValue_.timestamp;
        // update notify the datapoint server
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }  //if (status > 0)

      return status;
    }
  }

  /**
   * Set the datapoint value using the native type of the value.
   *
   * @param value
   *            - the new corba::unsigned value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  public synchronized int setUnsignedValue(int value)
  {
    // pass the set-value to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceSetValue()
        && type == EDataPointType.TYPE_REAL)
    {
      // convert to associated structure
      CosDpValueUnion myValue = new CosDpValueUnion();
      myValue.unsignedValue(value);
      // pass to subsystem
      if (subsystem.setValue(this, myValue))
      {
        return +1;
      }
      return -1;
    }
    else
    {
      int status = setUnsignedValue(outputValue_.value, value);

      if (status > 0)
      {
        // update the source value timestamp. if necessary we can override it later
        outputValue_.timestamp = Calendar.getInstance().getTimeInMillis();
        // update the dp timestamp
        updateTimestamp_ = outputValue_.timestamp;
        // update notify the datapoint server
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }  //if (status > 0)

      return status;
    }
  }

  /**
   * Set the datapoint value using the native type of the value.
   *
   * @param value
   *            - the new double value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  public synchronized int setDoubleValue(double value)
  {
    // pass the set-value to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceSetValue()
        && type == EDataPointType.TYPE_REAL)
    {
      // convert to associated structure
      CosDpValueUnion myValue = new CosDpValueUnion();
      myValue.dblValue(value);
      // pass to subsystem
      if (subsystem.setValue(this, myValue))
      {
        return +1;
      }
      return -1;
    }
    else
    {
      int status = setDoubleValue(outputValue_.value, value);

      if (status > 0)
      {
        // update the source value timestamp. if necessary we can override it later
        outputValue_.timestamp = Calendar.getInstance().getTimeInMillis();
        // update the dp timestamp
        updateTimestamp_ = outputValue_.timestamp;
        // update notify the datapoint server
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }  //if (status > 0)

      return status;
    }
  }

  /**
   * Set the datapoint value using the native type of the value.
   *
   * @param value
   *            - the new string value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  public synchronized int setStringValue(String value)
  {
    // pass the set-value to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceSetValue()
        && type == EDataPointType.TYPE_REAL)
    {
      // convert to associated structure
      CosDpValueUnion myValue = new CosDpValueUnion();
      myValue.charValue(value);
      // pass to subsystem
      if (subsystem.setValue(this, myValue))
      {
        return +1;
      }
      return -1;
    }
    else
    {
      int status = setStringValue(outputValue_.value, value);

      if (status > 0)
      {
        // update the source value timestamp. if necessary we can override it later
        outputValue_.timestamp = Calendar.getInstance().getTimeInMillis();
        // update the dp timestamp
        updateTimestamp_ = outputValue_.timestamp;
        // update notify the datapoint server
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }  //if (status > 0)

      return status;
    }
  }

  // get source timestamp
  public long getSourceTimestamp()
  {
    return sourceValue_.timestamp;
  }

  // set source timestamp
  public synchronized int setSourceTimestamp(long timestamp)
  {
    if (sourceValue_.timestamp == timestamp)
    {
      return 0;
    }

    // copy the timestamp
    sourceValue_.timestamp = timestamp;
    //synchronize the timestamp
    if (outputValue_.timestamp != sourceValue_.timestamp)
    {
      outputValue_.timestamp = sourceValue_.timestamp;
      // notify the dpServer
      if (dpServer != null)
      {
        dpServer.onDataPointChange(this);
      }
    }
    // update the dp timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();
    // notify the dpServer
    if (dpServer != null)
    {
      dpServer.onDataPointSourceChange(this);
    }

    return +1;
  }

  public CosDpQualityEnum getSourceQuality()
  {
    return sourceValue_.quality;
  }
 
  /**
   * Set the datapoint source quality
   *
   * @param quality
   *            - the new source quality
   */
  public synchronized int setSourceQuality(CosDpQualityEnum quality)
  {
    if (sourceValue_.quality == quality)
    {
      return 0;
    }

    // update the source quality
    sourceValue_.quality = quality;
    // recalculate the datapoint quality
    if (update_quality() > 0)
    {
      //notify dpserver
      if (dpServer != null)
      {
        dpServer.onDataPointChange(this);
      }
      // because, the quality of parameters affects the quality of a calculated point,
      // we need to re-evaluate all related datapoints
      for (int i = 0; i < relatedDataPoints_.size(); i++)
      {
        relatedDataPoints_.get(i).evaluate();
      }
    }
    // update the dp timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();
    // notify the dpServer
    if (dpServer != null)
    {
      dpServer.onDataPointSourceChange(this);
    }
   
    return +1;
  }

  // get stringified datapoint source value
  public String getStringifiedSourceValue()
  {
    return CosDpValueUnion2String(sourceValue_.value);
  }

  // set datapoint source value with a stringified value
  protected synchronized int setStringifiedSourceValue(String value)
  {
    // TODO: might not want to use setSourceValue() because setSourceValue() will create an
    // associated event
    // whereas this function most probably is used during the initialization
    return setSourceValue(String2CosDpValueUnion(sourceValue_.value.discriminator(), value));
  }

  // get source value
  public CosDpValueUnion getSourceValue()
  {
    return sourceValue_.value;
  }

  /**
   * Set the datapoint source value, quality and timestamp with a value, quality, and timestamp
   * of another datapoint. To ignore the timestamp paremeter, set the timestamp to 0.
   *
   * @param value
   *            - the new data point value/quality/timestamp
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  public synchronized int setSourceValue(CosDpValueStruct value)
  {
    int retval = -1;
   
    //if there is engineering conversion, do it here
    if (engParser_ != null && engParser_.isValid())
    {
      value.value = perform_eng_conversion(value.value);
    }
   
    //update the source value
    int status1 = copy(sourceValue_.value, value.value);
    if (status1 < 0)
    {
      //invalid value
      return retval;
    }
   
    // update the source quality
    int status2 = 0;
    if (sourceValue_.quality != value.quality)
    {
      status2 = 1;
      sourceValue_.quality = value.quality;
    }

    //update the source timestamp
    int status3 = 0;
    if (value.timestamp > 0 && sourceValue_.timestamp != value.timestamp)
    {
      status3 = 1;
      sourceValue_.timestamp = value.timestamp;
    }

    // any changes?
    if (status1 > 0 || status2 > 0 || status3 > 0)
    {
      retval = 1;
      //notify the dpserver
      if (dpServer != null)
      {
        dpServer.onDataPointSourceChange(this);
      }
      //synchronize the value
      status1 = synchronize_value();
      //update the quality
      status2 = update_quality();
      //any changes in output value?
      if (status1 > 0 || status2 > 0)
      {
        //notify dpserver
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }       
      }  //if (status1 > 0 || status2 > 0)
      //update the dp timestamp
      updateTimestamp_ = Calendar.getInstance().getTimeInMillis();
    }
    else if (status1 == 0 && status2 == 0 && status3 == 0)
    {
      retval = 0;
    }
   
    return retval;
  }

  /**
   * Set the datapoint source value with a value of another datapoint.
   *
   * @param value
   *            - the new data point value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected synchronized int setSourceValue(CosDpValueUnion value)
  {
    //if there is engineering conversion, do it here
    if (engParser_ != null && engParser_.isValid())
    {
      value = perform_eng_conversion(value);
    }
   
    int status = copy(sourceValue_.value, value);

    if (status > 0)
    {
      // update the source value timestamp. if necessary we can override it later
      sourceValue_.timestamp = Calendar.getInstance().getTimeInMillis();
      // synchronize
      if (synchronize_value() > 0)
      {
        //notify dpserver
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }
      // update the dp timestamp
      updateTimestamp_ = sourceValue_.timestamp;
      // we still need to notify the dpServer
      if (dpServer != null)
      {
        dpServer.onDataPointSourceChange(this);
      }
    }

    return status;
  }

  /**
   * Set the datapoint source value using the native type of the value.
   *
   * @param value
   *            - the new boolean value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected synchronized int setBooleanSourceValue(boolean value)
  {
    //if there is engineering conversion, do it here
    if (engParser_ != null && engParser_.isValid())
    {
      value = perform_eng_conversion(value);
    }
   
    //copy the value
    int status = setBooleanValue(sourceValue_.value, value);

    if (status > 0)
    {
      // update the source value timestamp. if necessary we can override it later
      sourceValue_.timestamp = Calendar.getInstance().getTimeInMillis();
      // synchronize
      if (synchronize_value() > 0)
      {
        //notify dpserver
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }
      // update the dp timestamp
      updateTimestamp_ = sourceValue_.timestamp;
      // we still need to notify the dpServer
      if (dpServer != null)
      {
        dpServer.onDataPointSourceChange(this);
      }
    }

    return status;
  }

  /**
   * Set the datapoint source value using the native type of the value.
   *
   * @param value
   *            - the new corba::long value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected synchronized int setNumberSourceValue(int value)
  {
    //if there is engineering conversion, do it here
    if (engParser_ != null && engParser_.isValid())
    {
      value = perform_eng_conversion(value);
    }
   
    //copy the value
    int status = setNumberValue(sourceValue_.value, value);

    if (status > 0)
    {
      // update the source value timestamp. if necessary we can override it later
      sourceValue_.timestamp = Calendar.getInstance().getTimeInMillis();
      // synchronize
      if (synchronize_value() > 0)
      {
        //notify dpserver
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }
      // update the dp timestamp
      updateTimestamp_ = sourceValue_.timestamp;
      // we still need to notify the dpServer
      if (dpServer != null)
      {
        dpServer.onDataPointSourceChange(this);
      }
    }

    return status;
  }

  /**
   * Set the datapoint source value using the native type of the value.
   *
   * @param value
   *            - the new corba::unsigned value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected synchronized int setUnsignedSourceValue(int value)
  {
    //if there is engineering conversion, do it here
    if (engParser_ != null && engParser_.isValid())
    {
      value = perform_eng_conversion(value);
    }
   
    //copy the value
    int status = setUnsignedValue(sourceValue_.value, value);

    if (status > 0)
    {
      // update the source value timestamp. if necessary we can override it later
      sourceValue_.timestamp = Calendar.getInstance().getTimeInMillis();
      // synchronize
      if (synchronize_value() > 0)
      {
        //notify dpserver
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }
      // update the dp timestamp
      updateTimestamp_ = sourceValue_.timestamp;
      // we still need to notify the dpServer
      if (dpServer != null)
      {
        dpServer.onDataPointSourceChange(this);
      }
    }

    return status;
  }

  /**
   * Set the datapoint source value using the native type of the value.
   *
   * @param value
   *            - the new double value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected synchronized int setDoubleSourceValue(double value)
  {
    //if there is engineering conversion, do it here
    if (engParser_ != null && engParser_.isValid())
    {
      value = perform_eng_conversion(value);
    }
   
    //copy the value
    int status = setDoubleValue(sourceValue_.value, value);

    if (status > 0)
    {
      // update the source value timestamp. if necessary we can override it later
      sourceValue_.timestamp = Calendar.getInstance().getTimeInMillis();
      // synchronize
      if (synchronize_value() > 0)
      {
        //notify dpserver
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }
      // update the dp timestamp
      updateTimestamp_ = sourceValue_.timestamp;
      // we still need to notify the dpServer
      if (dpServer != null)
      {
        dpServer.onDataPointSourceChange(this);
      }
    }

    return status;
  }

  /**
   * Set the datapoint source value using the native type of the value.
   *
   * @param value
   *            - the new string value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected synchronized int setStringSourceValue(String value)
  {
    //if there is engineering conversion, do it here
    if (engParser_ != null && engParser_.isValid())
    {
      value = perform_eng_conversion(value);
    }
   
    //copy the value
    int status = setStringValue(sourceValue_.value, value);

    if (status > 0)
    {
      // update the source value timestamp. if necessary we can override it later
      sourceValue_.timestamp = Calendar.getInstance().getTimeInMillis();
      // synchronize
      if (synchronize_value() > 0)
      {
        //notify dpserver
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }
      }
      // update the dp timestamp
      updateTimestamp_ = sourceValue_.timestamp;
      // we still need to notify the dpServer
      if (dpServer != null)
      {
        dpServer.onDataPointSourceChange(this);
      }
    }

    return status;
  }

  /**
   * Check inhibit state.
   *
   * @return the inhibit flag
   */
  public boolean isInhibit()
  {
    return isInhibit_;
  }

  /**
   * Set inhibit flag. The same as setInhibit(true)
   */
  public synchronized boolean setInhibit()
  {
    // pass the inhibit to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceInhibit()
        && type == EDataPointType.TYPE_REAL)
    {
      return subsystem.setInhibit(this);
    }
    else
    {
      // inhibit is local. store it here
      setInhibit(true);
      return true;
    }
  }

  /**
   * Remove inhibit flag. The same as setInhibit(false)
   */
  public synchronized boolean removeInhibit()
  {
    // pass the inhibit to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceInhibit()
        && type == EDataPointType.TYPE_REAL)
    {
      return subsystem.removeInhibit(this);
    }
    else
    {
      // inhibit is local. store it here
      setInhibit(false);
      return true;
    }
  }

  /**
   * Set/clear inhibit flag.
   *
   * @param value
   *            - the new inhibit flag
   */
  private synchronized void setInhibit(boolean value)
  {
    // ignore if already set
    if (isInhibit_ == value)
    {
      return;
    }

    // set the inhibit flag including the equipment level flag
    isInhibit_ = value;
    if (equipment != null)
    {
      equipment.setInhibit(value);
    }

    // if we remove the inhibit, synchronize the source value to the output value
    if (!value && synchronize_value() > 0)
    {
      //notify dpserver
      if (dpServer != null)
      {
        dpServer.onDataPointChange(this);
      }
      // re-evaluate all related datapoints
      for (int i = 0; i < relatedDataPoints_.size(); i++)
      {
        relatedDataPoints_.get(i).evaluate();
      }
    }

    // update dp timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // notify the dpServer
    if (dpServer != null)
    {
      dpServer.onDataPointChange(this);
    }
  }

  // check override state
  public boolean isOverride()
  {
    return isOverride_;
  }

  // set override flag. the same as setOverride(true)
  public synchronized boolean setOverride(CosDpValueUnion value)
  {
    // pass the override to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceOverride()
        && type == EDataPointType.TYPE_REAL)
    {
      return subsystem.setOverride(this, value);
    }
    else
    {
      // update the data point value
      if (setValue(value) < 0)
      {
        return false;
      }
      // set the override flag
      setOverride(true);
      return true;
    }
  }

  // remove override flag. the same as setOverride(false)
  public synchronized boolean removeOverride()
  {
    // pass the override to underlying subsystem if necessary
    if (subsystem != null && subsystem.isSourceOverride()
        && type == EDataPointType.TYPE_REAL)
    {
      return subsystem.removeOverride(this);
    }
    else
    {
      setOverride(false);
      return true;
    }
  }

  // set/clear override flag
  private synchronized void setOverride(boolean value)
  {
    // ignore if it is already overriden
    if (isOverride_ == value)
    {
      return;
    }

    // set the override flag including the equipment level flag
    isOverride_ = value;
    if (equipment != null)
    {
      equipment.setOverride(value);
    }

    // if we remove the overrude, synchronize the value
    if (!value && synchronize_value() > 0)
    {
      //notify dpserver
      if (dpServer != null)
      {
        dpServer.onDataPointChange(this);
      }
      // re-evaluate all related datapoints
      for (int i = 0; i < relatedDataPoints_.size(); i++)
      {
        relatedDataPoints_.get(i).evaluate();
      }
    }

    // update dp timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // notify the dpServer
    if (dpServer != null)
    {
      dpServer.onDataPointChange(this);
    }
  }

  /**
   * Check the alarm state. The alarm state is represented by two flags: not-acknowledged and
   * not-normalized. On creation of new alarm, both alarm flags are set.
   *
   * @return true if the datapoint is in alarm, false otherwise
   */
  public boolean isAlarm()
  {
    return (isAlarmNotAck_ || isAlarmNotNorm_);
  }

  /**
   * Set the alarm state. It is the same as setAlarm(true) <br>
   * The alarm state is represented by two flags: not-acknowledged and not-normalized. It is
   * essentially the same as create a new alarm.
   */
  public synchronized void setAlarm()
  {
    setAlarm(true);
  }

  /**
   * Set/clear the alarm state. <br>
   * The alarm state is represented by two flags: not-acknowledged and not-normalized. If status =
   * true, it is essentially the same as create a new alarm.
   *
   * @param status
   *            - the new alarm state
   */
  public synchronized void setAlarm(boolean status)
  {
    if (status)
    {
      // if alarm inhibit is set, ignore the creation
      if (isAlarmInhibit_) return;
      // set the alarm state
      // a new alarm has both not-ack and not-norm flag set
      isAlarmNotAck_ = true;
      isAlarmNotNorm_ = true;
      if (equipment != null)
      {
        equipment.setAlarmNotAck(true);
        equipment.setAlarmNotNorm(true);
      }
    }
    else
    {
      // clear the alarm state
      isAlarmNotAck_ = false;
      isAlarmNotNorm_ = false;
      if (equipment != null)
      {
        // remove equipment's alarm not ack and alarm not norm is necessary
        equipment.setAlarmNotAck(false);
        equipment.setAlarmNotNorm(false);
      }
    }

    // update dp timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // notify the dpServer
    if (dpServer != null)
    {
      dpServer.onDataPointChange(this);
    }
  }

  // check the alarm inhibit flag
  public boolean isAlarmInhibit()
  {
    return isAlarmInhibit_;
  }

  // Set the alarm inhibit flag. The same as setAlarmInhibit(true)
  public synchronized void setAlarmInhibit()
  {
    setAlarmInhibit(true);
  }

  // Set/clear the alarm inhibit flag
  public synchronized void setAlarmInhibit(boolean value)
  {
    // ignore if it is already set
    if (isAlarmInhibit_ == value)
    {
      return;
    }

    // set the alarm inhibit
    isAlarmInhibit_ = value;
    if (value)
    {
      // if alarm state is set, clear the alarm state
      isAlarmNotAck_ = false;
      isAlarmNotNorm_ = false;
      // update the equipment
      if (equipment != null)
      {
        equipment.setAlarmInhibit(true);
        // remove equipment's alarm not ack and alarm not norm is necessary
        equipment.setAlarmNotAck(false);
        equipment.setAlarmNotNorm(false);
      }
    }
    else
    {
      if (equipment != null)
      {
        // remove equipment's alarm inhibit if necessary
        equipment.setAlarmInhibit(false);
      }
    }

    // update dp timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // notify the dpServer
    if (dpServer != null)
    {
      dpServer.onDataPointChange(this);
    }
  }

  // Check the alarm not ack flag
  public boolean isAlarmNotAck()
  {
    return isAlarmNotAck_;
  }

  // Set the alarm not-acknowledged flag. The same as setAlarmNotAck(true)
  public synchronized void setAlarmNotAck()
  {
    setAlarmNotAck(true);
  }

  // set/clear alarm not acknowledged flag
  public synchronized void setAlarmNotAck(boolean value)
  {
    // ignore if it is already set
    if (isAlarmNotAck_ == value)
    {
      return;
    }

    isAlarmNotAck_ = value;
    if (equipment != null)
    {
      equipment.setAlarmNotAck(value);
    }

    // update dp timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // notify the dpServer
    if (dpServer != null)
    {
      dpServer.onDataPointChange(this);
    }
  }

  // check the alarm not normalized flag
  public boolean isAlarmNotNorm()
  {
    return isAlarmNotNorm_;
  }

  // Set the alarm not-normalized flag. The same as setAlarmNotNorm(true)
  public synchronized void setAlarmNotNorm()
  {
    setAlarmNotAck(true);
  }

  // set/clear alarm not normalized flag
  public synchronized void setAlarmNotNorm(boolean value)
  {
    // ignore if it is already set
    if (isAlarmNotNorm_ == value)
    {
      // ignore
      return;
    }

    isAlarmNotNorm_ = value;
    if (equipment != null)
    {
      equipment.setAlarmNotNorm(value);
    }

    // update dp timestamp
    updateTimestamp_ = Calendar.getInstance().getTimeInMillis();

    // notify the dpServer
    if (dpServer != null)
    {
      dpServer.onDataPointChange(this);
    }
  }

  // create expression parser and parse the expression.
  public synchronized void setExpression(String expression)
  {
    if (expression == null || expression.length() == 0)
    {
      return;
    }

    //copy locally
    expression_ = expression;
   
    //get the expression type
    //first of all get the return type
    Class<?> type = int.class;    //default is int
    switch(outputValue_.value.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        type = boolean.class;
        break;
      case CosDpValueTypeEnum._TypeDouble:
        type = double.class;
        break;
      case CosDpValueTypeEnum._TypeNumber:
        type = int.class;
        break;
      case CosDpValueTypeEnum._TypeString:
        type = String.class;
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        type = int.class;
        break;
    }
   
    //parse the expression. this must be done after all datapoints have been created
    //otherwise, invalid/non-existent datapoints will be just marked as 0.
    ArrayList<xxxDataPoint> params = new ArrayList<xxxDataPoint>();
    ArrayList<String> varnames = new ArrayList<String>();
    ArrayList<Class<?>> vartypes = new ArrayList<Class<?>>()
    ArrayList<Object> varvalues = new ArrayList<Object>()
   
    //create the parser
    String str = parse_expression(expression_, params, varnames, vartypes, varvalues);
    expressionParser_ = new ExpressionParser(str, type);
   
    //create all the variables
    for (int i=0; i<varnames.size(); i++)
    {
      expressionParser_.createVariable(varnames.get(i), vartypes.get(i), varvalues.get(i));
    }
   
    //for each datapoint params, add to the related dp
    xxxDataPoint dp = null;
    for (int i=0; i<params.size(); i++)
    {
      dp = params.get(i);
      if (dp != null)
      {
        dp.addRelatedPoint(this);
      }
    }
    expressionParams_ = params;
  }

  public synchronized void setEvaluatedStatus(boolean value)
  {
    isEvaluated_ = value;
  }
 
  public boolean isEvaluated()
  {
    return isEvaluated_;
  }
 
  // if it is a calculated point, calculate the expression
  public synchronized int evaluate()
  {
    // ignore non-calculated datapoints
    if (type != EDataPointType.TYPE_CALCULATED || expressionParser_ == null)
      return -1;

    // check for invalid expression
    if (!expressionParser_.isValid())
    {
      //it has been parsed and found invalid. prevent re-parsing
      logger_.error("Invalid expression. Check the first thime this happens for error.");
      ////set quality to bad. should only need to set it first time after parsing.
      //expressionQuality_ = CosDpQualityEnum.QualityBad;
      return -1;
    }
   
    // prevent infinite recursive calls because we call evaluate() of parameter datapoints.
    if (!semaphore_.tryAcquire())
    {
      return 0;
    }
       
    int retval = 0;     
   
    //this is not a try-catch block but instead try-finally block.
    //the purpose is so that the semaphore is automatically released at the end of the block
    try
    {
      // update the value of expression parameters
      xxxDataPoint dp = null;
      Object value = null;
      for (int i=0; i<expressionParams_.size(); i++)
      {
        dp = expressionParams_.get(i);
        if (dp == null)
        {
           logger_.trace("DP parameter : UNKNOWN");
          //this, in theory, should never happens
          expressionQuality_  = CosDpQualityEnum.QualityBad;
          value = new Integer(0);      //default value
        }
        else
        {
           logger_.trace("DP parameter : " + dp.name);
          
          //check for bad quality, in which case the expression quality will also
          //be set to bad
          switch(dp.type)
          {
            case TYPE_REAL:
              if (dp.getQuality() == CosDpQualityEnum.QualityBad)
              {
                expressionQuality_  = CosDpQualityEnum.QualityBad;
              }
              break;
            case TYPE_VIRTUAL:
              if (dp.getQuality() == CosDpQualityEnum.QualityBad)
              {
                expressionQuality_  = CosDpQualityEnum.QualityBad;
              }
              break;
            case TYPE_CALCULATED:
              //try to re-evaluate the value, just in case
              //NOTE: this is the reason we need the semaphore.
              //      otherwise, we might get into infinite recursive calls
              if (dp.evaluate() < 0 || dp.getQuality() == CosDpQualityEnum.QualityBad)
              {
                expressionQuality_  = CosDpQualityEnum.QualityBad;
              }
              break;
          }
          //calculate the parameter value
          value = CosDpValueUnion2Object(dp.getValue());
        }
       
        //set the parameter
        expressionParser_.set(i, value);
       
        //verbose
        logger_.trace("DP parameter value : " + value.toString());
      }
     
      //evaluate the expression value
      Object obj = null;
      try
      {
        obj = expressionParser_.evaluate();
      }
      catch(Exception ex)
      {
        logger_.warn("Can not evaluate expression. Exception: " + ex.toString());
      }
     
      //convert it to CosDpValueUnion
      CosDpValueUnion expValue = Object2CosDpValueUnion(outputValue_.value.discriminator(), obj);
     
      // update the output value with the expression value
      int status1 = copy(outputValue_.value, expValue);;
     
      // recalculate the datapoint quality
      int status2 = update_quality();
     
      // return value
      if (status1 > 0 || status2 > 0)
      {
        //notify dpserver
        if (dpServer != null)
        {
          dpServer.onDataPointChange(this);
        }
        // re-evaluate all related datapoints
        for (int i = 0; i < relatedDataPoints_.size(); i++)
        {
          relatedDataPoints_.get(i).evaluate();
        }       
        //update the dp timestamp
        updateTimestamp_ = Calendar.getInstance().getTimeInMillis();
        retval = +1;
      }
      else if (status1 == 0 || status2 == 0)
      {
        retval = 0;    //no updates or changes
      }
      else
      {
        retval = -1//failure
      }
    }
    finally
    {
      semaphore_.release();     
    }
   
    isEvaluated_ = true;
    return retval;
  }

  // create launching condition parser and parse the expression
  public synchronized void setLaunchCondition(String expression) throws Exception
  {
    if (expression == null || expression.length() == 0)
    {
      return;
    }

    //copy locally
    lccExpression_ = expression;
   
    //get the expression type
    //first of all get the return type
    Class<?> type = boolean.class;   
   
    //parse the expression. this must be done after all datapoints have been created
    //otherwise, invalid/non-existent datapoints will be just marked as 0.
    ArrayList<xxxDataPoint> params = new ArrayList<xxxDataPoint>();
    ArrayList<String> varnames = new ArrayList<String>();
    ArrayList<Class<?>> vartypes = new ArrayList<Class<?>>()
    ArrayList<Object> varvalues = new ArrayList<Object>()
   
    //create the parser
    String str = parse_expression(lccExpression_, params, varnames, vartypes, varvalues);
    lccParser_ = new ExpressionParser(str, type);
   
    //create all the variables
    for (int i=0; i<varnames.size(); i++)
    {
      lccParser_.createVariable(varnames.get(i), vartypes.get(i), varvalues.get(i));
    }
   
    lccParams_ = params;
  }

  /**
   * Check the launching condition for this control datapoint.
   *
   * @return true if the launching condition is OK, false otherwise
   */
  public boolean checkLaunchCondition() throws Exception
  {
    if (lccParser_ == null)
    {
      return false;
    }

    // check for invalid expression
    if (!lccParser_.isValid())
    {
      //it has been parsed and found invalid. prevent re-parsing
      logger_.error("Invalid launching condition expression. "
              + "Check the first thime this happens for error.");
      return false;
    }

    // update the value of expression parameters
    xxxDataPoint dp = null;
    Object value = null;
    for (int i=0; i<lccParams_.size(); i++)
    {
      dp = lccParams_.get(i);
      if (dp == null)
      {
         logger_.trace("LCC parameter : UNKNOWN");
        value = new Integer(0);      //default value
      }
      else
      {
         logger_.trace("LCC parameter : " + dp.name);
        //calculate the parameter value
        value = CosDpValueUnion2Object(dp.getValue());
      }
     
      //set the parameter
      lccParser_.set(i, value);
     
      //verbose
      logger_.trace("LCC parameter value : " + value.toString());
    }
   
    //evaluate the expression value
    Boolean status = null;
    try
    {
      status = (Boolean)lccParser_.evaluate();
    }
    catch(Exception ex)
    {
      logger_.warn("Can not evaluate LCC expression. Exception: " + ex.toString());
    }
   
    //return value
    if (status == null)
    {
      return false;
    }
    else
    {
      return status.booleanValue();
    }
  }

  // create return condition parser and parse the expression
  public synchronized void setReturnCondition(String expression)
  {
    if (expression == null || expression.length() == 0)
    {
      return;
    }

    //copy locally
    rccExpression_ = expression;
   
    //first of all get the return type
    Class<?> type = boolean.class;   
   
    //parse the expression. this must be done after all datapoints have been created
    //otherwise, invalid/non-existent datapoints will be just marked as 0.
    ArrayList<xxxDataPoint> params = new ArrayList<xxxDataPoint>();
    ArrayList<String> varnames = new ArrayList<String>();
    ArrayList<Class<?>> vartypes = new ArrayList<Class<?>>()
    ArrayList<Object> varvalues = new ArrayList<Object>()
   
    //create the parser
    String str = parse_expression(rccExpression_, params, varnames, vartypes, varvalues);
    rccParser_ = new ExpressionParser(str, type);
   
    //create all the variables
    for (int i=0; i<varnames.size(); i++)
    {
      rccParser_.createVariable(varnames.get(i), vartypes.get(i), varvalues.get(i));
    }
   
    rccParams_ = params;
  }

  /**
   * Check the return condition for this control datapoint.
   *
   * @return true if the return condition is OK, false otherwise
   */
  public boolean checkReturnCondition() throws Exception
  {
    if (rccParser_ == null)
    {
      return false;
    }

    // check for invalid expression
    if (!rccParser_.isValid())
    {
      //it has been parsed and found invalid. prevent re-parsing
      logger_.error("Invalid return condition expression. "
              + "Check the first thime this happens for error.");
      return false;
    }
   
    // update the value of expression parameters
    xxxDataPoint dp = null;
    Object value = null;
    for (int i=0; i<rccParams_.size(); i++)
    {
      dp = rccParams_.get(i);
      if (dp == null)
      {
         logger_.trace("RCC parameter : UNKNOWN");
        value = new Integer(0);      //default value
      }
      else
      {
         logger_.trace("RCC parameter : " + dp.name);
        //calculate the parameter value
        value = CosDpValueUnion2Object(dp.getValue());
      }
     
      //set the parameter
      rccParser_.set(i, value);
     
      //verbose
      logger_.trace("RCC parameter value : " + value.toString());
    }
   
    //evaluate the expression value
    Boolean status = null;
    try
    {
      status = (Boolean)rccParser_.evaluate();
    }
    catch(Exception ex)
    {
      logger_.warn("Can not evaluate RCC expression. Exception: " + ex.toString());
    }
   
    //return value
    if (status == null)
    {
      return false;
    }
    else
    {
      return status.booleanValue();
    }
  }

  // create return condition parser and parse the expression
  public synchronized void setEngineeringConversion(String expression)
  {
    if (expression == null || expression.length() == 0)
    {
      return;
    }

    //copy locally
    engExpression_ = expression;
   
    //first of all get the return type. this will also be the input value's type
    Class<?> type = boolean.class;   
    Object initInputValue = null;
    switch(sourceValue_.value.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        type = boolean.class;
        initInputValue = new Boolean(false);
        break;
      case CosDpValueTypeEnum._TypeNumber:
        type = int.class;
        initInputValue = new Integer(0);
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        type = int.class;
        initInputValue = new Integer(0);
        break;
      case CosDpValueTypeEnum._TypeDouble:
        type = double.class;
        initInputValue = new Double(0);
        break;
      case CosDpValueTypeEnum._TypeString:
        type = String.class;
        initInputValue = new String("");
        break;
    }

    //create the parser
    rccParser_ = new ExpressionParser(engExpression_, type);
   
    //create the input variable
    rccParser_.createVariable("x", type, initInputValue);
  }

  public synchronized void addRelatedPoint(xxxDataPoint datapoint)
  {
    if (datapoint == null)
    {
      return;
    }
   
    //check for circular dependecy!
    //NOTE: To do this imposes too much overload compares to the benefits.
    //      Besides, we can only check a direct circular dependency between 2 datapoints
    //      which is very very rare, can be easily spotted by manual checking and, if anything,
    //      amount to configuration error.
    //      So, just do the checking on runtime.
   
    relatedDataPoints_.add(datapoint);
  }

 
  protected boolean isRelatedPoint(xxxDataPoint datapoint)
  {
    for (int i=0; i<relatedDataPoints_.size(); i++)
    {
      if (datapoint == relatedDataPoints_.get(i))
      {
        return true;
      }
    }
    return false;
  }
 
  /**
   * Set a datapoint value with a value of another datapoint. Do a value translation if necessary.
   *
   * @param value
   *            - the data point to set the value
   * @param newValue
   *            - the source data point
   * @return +1 if successful, 0 if the value is already the target value, -1 if the source value
   *         is invalid
   */
  protected static int copy(CosDpValueUnion value, final CosDpValueUnion newValue)
  {
    switch (value.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        {
          boolean boolVal = false;
          switch (newValue.discriminator().value())
          {
            case CosDpValueTypeEnum._TypeBoolean:
              boolVal = newValue.boolValue();
              break;
            case CosDpValueTypeEnum._TypeNumber:
              boolVal = (newValue.longValue() != 0);
              break;
            case CosDpValueTypeEnum._TypeUnsigned:
              boolVal = (newValue.unsignedValue() != 0);
              break;
            default:
              return -1;
          }
          // ONLY copy if the new value is really different with the current value
          if (boolVal != value.boolValue())
          {
            value.boolValue(boolVal);
          }
          else
          {
            return 0;
          }
        }
        break;
      case CosDpValueTypeEnum._TypeNumber:
        {
          int longVal = 0;
          switch (newValue.discriminator().value())
          {
            case CosDpValueTypeEnum._TypeNumber:
              longVal = newValue.longValue();
              break;
            case CosDpValueTypeEnum._TypeUnsigned:
              longVal = newValue.unsignedValue();
              break;
            default:
              return -1;
          }
          // ONLY copy if the new value is really different with the current value
          if (longVal != value.longValue())
          {
            value.longValue(longVal);
          }
          else
          {
            return 0;
          }
        }
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        {
          int unsignedVal = 0;
          switch (newValue.discriminator().value())
          {
            case CosDpValueTypeEnum._TypeNumber:
              unsignedVal = newValue.longValue();
              break;
            case CosDpValueTypeEnum._TypeUnsigned:
              unsignedVal = newValue.unsignedValue();
              break;
            default:
              return -1;
          }
          // ONLY copy if the new value is really different with the current value
          if (unsignedVal != value.unsignedValue())
          {
            value.unsignedValue(unsignedVal);
          }
          else
          {
            return 0;
          }
        }
        break;
      case CosDpValueTypeEnum._TypeDouble:
        {
          double dblVal = 0.0;
          switch (newValue.discriminator().value())
          {
            case CosDpValueTypeEnum._TypeNumber:
              dblVal = (double) newValue.longValue();
              break;
            case CosDpValueTypeEnum._TypeUnsigned:
              dblVal = (double) newValue.unsignedValue();
              break;
            case CosDpValueTypeEnum._TypeDouble:
              dblVal = newValue.dblValue();
              break;
            default:
              return -1;
          }
          // ONLY copy if the new value is really different with the current value
          if (dblVal != value.dblValue())
          {
            value.dblValue(dblVal);
          }
          else
          {
            return 0;
          }
        }
        break;
      case CosDpValueTypeEnum._TypeString:
        {
          String strValue;
          switch (newValue.discriminator().value())
          {
            case CosDpValueTypeEnum._TypeBoolean:
              strValue = Boolean.toString(newValue.boolValue());
              break;
            case CosDpValueTypeEnum._TypeNumber:
              strValue = Integer.toString(newValue.longValue());
              break;
            case CosDpValueTypeEnum._TypeUnsigned:
              strValue = Integer.toString(newValue.unsignedValue());
              break;
            case CosDpValueTypeEnum._TypeDouble:
              strValue = Double.toString(newValue.dblValue());
              break;
            case CosDpValueTypeEnum._TypeString:
              strValue = newValue.charValue();
              break;
            default:
              return -1;
          } // end of switch (srcDpValue._d())
          // ONLY copy if the new value is really different with the current value
          // must take care truncation!!
          if (strValue.length() != value.charValue().length())
          {
            // (in which case strncmp will give 0 eventhough the string is not actually
            // the same!)
            value.charValue(strValue);
          }
          else if (value.charValue().compareTo(strValue) != 0)
          {
            value.charValue(strValue);
          }
          else
          {
            return 0;
          }
        }
        break;
      default:
        // unknown datatype
        return -1;
    } // end of switch (dpValue._d())

    return 1;
  }

  /**
   * Compare 2 datapoint value
   *
   * @param value1
   *            - the first data point
   * @param value2
   *            - the second data point
   * @return +1 if first < second or if different boolean value, 0 if first = second, -1 if first
   *         > second or different data type
   */
  protected static int compare(CosDpValueUnion value1, final CosDpValueUnion value2)
  {
    if (value1.discriminator() != value2.discriminator())
    {
      return -1;
    }

    switch (value1.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        // return 1 if not the same
        if (value1.boolValue() != value2.boolValue())
        {
          return +1;
        }
        else
        {
          return 0;
        }
      case CosDpValueTypeEnum._TypeNumber:
        if (value1.longValue() < value2.longValue())
        {
          return -1;
        }
        else if (value1.longValue() > value2.longValue())
        {
          return +1;
        }
        else
        {
          return 0;
        }
      case CosDpValueTypeEnum._TypeUnsigned:
        if (value1.unsignedValue() < value2.unsignedValue())
        {
          return -1;
        }
        else if (value1.unsignedValue() > value2.unsignedValue())
        {
          return +1;
        }
        else
        {
          return 0;
        }
      case CosDpValueTypeEnum._TypeDouble:
        if (value1.dblValue() < value2.dblValue())
        {
          return -1;
        }
        else if (value1.dblValue() > value2.dblValue())
        {
          return +1;
        }
        else
        {
          return 0;
        }
      case CosDpValueTypeEnum._TypeString:
        if (value1.charValue().length() < value2.charValue().length())
        {
          return -1;
        }
        else if (value1.charValue().length() > value2.charValue().length())
        {
          return +1;
        }
        else
        {
          return value1.charValue().compareTo(value2.charValue());
        }
    } // end of switch (dpValue._d())

    // if we get here, it is unknown datatype
    return -1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param value
   *            - the datapoint value
   * @param boolValue
   *            - the new boolean value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected static int setBooleanValue(CosDpValueUnion value, boolean boolValue)
  {
    // we can do a value translation here. but I think it is not worth the effort.
    // instead, just return with error with the value type is not boolean
    if (value.discriminator() != CosDpValueTypeEnum.TypeBoolean)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (value.boolValue() == boolValue)
    {
      return 0;
    }

    // set the value
    value.boolValue(boolValue);

    return +1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param value
   *            - the datapoint value
   * @param lngValue
   *            - the new corba::long value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected static int setNumberValue(CosDpValueUnion value, int lngValue)
  {
    // we can do a value translation here. but I think it is not worth the effort.
    // instead, just return with error with the value type is not number
    if (value.discriminator() != CosDpValueTypeEnum.TypeNumber)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (value.longValue() == lngValue)
    {
      return 0;
    }

    // set the value
    value.longValue(lngValue);

    return +1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param value
   *            - the datapoint value
   * @param unsignedValue
   *            - the new corba::unsigned value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected static int setUnsignedValue(CosDpValueUnion value, int unsignedValue)
  {
    // we can do a value translation here. but I think it is not worth the effort.
    // instead, just return with error with the value type is not unsigned
    if (value.discriminator() != CosDpValueTypeEnum.TypeUnsigned)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (value.unsignedValue() == unsignedValue)
    {
      return 0;
    }

    // set the value
    value.unsignedValue(unsignedValue);

    return +1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param value
   *            - the datapoint value
   * @param dblValue
   *            - the new double value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected static int setDoubleValue(CosDpValueUnion value, double dblValue)
  {
    // we can do a value translation here. but I think it is not worth the effort.
    // instead, just return with error with the value type is not double
    if (value.discriminator() != CosDpValueTypeEnum.TypeDouble)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (value.dblValue() == dblValue)
    {
      return 0;
    }

    // set the value
    value.dblValue(dblValue);

    return +1;
  }

  /**
   * Set a value using the native type of the value.
   *
   * @param value
   *            - the datapoint value
   * @param strValue
   *            - the new string value
   * @return +1 if successful, 0 if the value is already the target value, -1 if the new value is
   *         invalid
   */
  protected static int setStringValue(CosDpValueUnion value, String strValue)
  {
    // we can do a value translation here. but I think it is not worth the effort.
    // instead, just return with error with the value type is not double
    if (value.discriminator() != CosDpValueTypeEnum.TypeString)
    {
      return -1;
    }

    // validation
    if (strValue == null)
    {
      return -1;
    }

    // set the value if and only if the new value is different
    if (value.charValue().length() == strValue.length()
        && 0 == value.charValue().compareTo(strValue))
    {
      return 0;
    }

    // set the value
    value.charValue(strValue);

    return +1;
  }

  protected static String CosDpValueUnion2String(CosDpValueUnion value)
  {
    // validation
    if (value == null)
    {
      return "";
    }

    switch (value.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        if (value.boolValue())
        {
          return "1";
        }
        else
        {
          return "0";
        }
      case CosDpValueTypeEnum._TypeNumber:
        return Integer.toString(value.longValue());
      case CosDpValueTypeEnum._TypeUnsigned:
        return Integer.toString(value.unsignedValue());
      case CosDpValueTypeEnum._TypeDouble:
        return Double.toString(value.dblValue());
      case CosDpValueTypeEnum._TypeString:
        return value.charValue();
      default:
        return "";
    }
  }

  protected static CosDpValueUnion String2CosDpValueUnion(CosDpValueTypeEnum type, String str)
  {
    // validation is performed as part of the conversion

    CosDpValueUnion value = new CosDpValueUnion();

    switch (type.value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        if (str != null && str.compareToIgnoreCase("1") == 0)
        {
          value.boolValue(true);
        }
        else
        {
          value.boolValue(false);
        }
        break;
      case CosDpValueTypeEnum._TypeNumber:
        value.longValue(parse_int(str));
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        value.unsignedValue(parse_int(str));
        break;
      case CosDpValueTypeEnum._TypeDouble:
        value.dblValue(parse_dbl(str));
        break;
      case CosDpValueTypeEnum._TypeString:
        value.charValue(str);
        break;
      default:
        value.longValue(0);
    }

    return value;
  }

  protected static Object CosDpValueUnion2Object(CosDpValueUnion value)
  {
    // validation
    if (value == null)
    {
      return null;
    }

    switch (value.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        return new Boolean(value.boolValue());
      case CosDpValueTypeEnum._TypeNumber:
        return new Integer(value.longValue());
      case CosDpValueTypeEnum._TypeUnsigned:
        return new Integer(value.unsignedValue());
      case CosDpValueTypeEnum._TypeDouble:
        return new Double(value.dblValue());
      case CosDpValueTypeEnum._TypeString:
        return value.charValue();
    }
   
    return null;
  }

  protected static CosDpValueUnion Object2CosDpValueUnion(CosDpValueTypeEnum type, Object obj)
  {
    // validation is performed as part of the conversion

    CosDpValueUnion value = new CosDpValueUnion();

    Boolean boolObj = null;
    Integer intObj = null;
    Double dblObj = null;
    String strObj = null;
   
    switch (type.value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        //cast it
        boolObj = null;
        try
        {
          boolObj = (Boolean) obj;
        }
        catch (Exception ex)
        {
          //ignore
        }
        //set the value
        if (obj == null)
        {
          value.boolValue(false);    //default value
        }
        else
        {
          value.boolValue(boolObj.booleanValue());
        }
        break;
      case CosDpValueTypeEnum._TypeNumber:
        //cast it
        intObj = null;
        try
        {
          intObj = (Integer) obj;
        }
        catch (Exception ex)
        {
          //ignore
        }
        //set the value
        if (obj == null)
        {
          value.longValue(0);    //default value
        }
        else
        {
          value.longValue(intObj.intValue());
        }
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        //cast it
        intObj = null;
        try
        {
          intObj = (Integer) obj;
        }
        catch (Exception ex)
        {
          //ignore
        }
        //set the value
        if (obj == null)
        {
          value.unsignedValue(0);    //default value
        }
        else
        {
          value.unsignedValue(intObj.intValue());
        }
        break;
      case CosDpValueTypeEnum._TypeDouble:
        //cast it
        dblObj = null;
        try
        {
          dblObj = (Double) obj;
        }
        catch (Exception ex)
        {
          //ignore
        }
        //set the value
        if (obj == null)
        {
          value.dblValue(0);    //default value
        }
        else
        {
          value.dblValue(dblObj.doubleValue());
        }
        break;
      case CosDpValueTypeEnum._TypeString:
        //cast it
        strObj = null;
        try
        {
          strObj = (String) obj;
        }
        catch (Exception ex)
        {
          //ignore
        }
        //set the value
        if (obj == null)
        {
          value.charValue("");    //default value
        }
        else
        {
          value.charValue(strObj);
        }
        break;
    }

    return value;
  }

  private static int parse_int(String str)
  {
    int value = 0;
    try
    {
      value = Integer.parseInt(str);
    }
    catch (NumberFormatException nfe)
    {
      // ignore
    }
    return value;
  }

  private static double parse_dbl(String str)
  {
    double value = 0;
    try
    {
      value = Double.parseDouble(str);
    }
    catch (NumberFormatException nfe)
    {
      // ignore
    }
    return value;
  }

  // calculate the datapoint quality
  // this is protected because generally the client should never call this function.
  // this should be triggered automatically upon changes on related attributes/parameters
  private int update_quality()
  {
    CosDpQualityEnum newQuality = CosDpQualityEnum.QualityBad;

    // determine the datapoint quality. store the new quality in newQuality
    if (sourceValue_.quality == CosDpQualityEnum.QualityBad)
    {
      // if source quality is bad, always set to bad.
      newQuality = CosDpQualityEnum.QualityBad;
    }
    else
    {
      // get the subsystem quality, if any
      newQuality = CosDpQualityEnum.QualityGood;
      if (subsystem != null)
      {
        newQuality = subsystem.getQuality();
      }
      else if (type == EDataPointType.TYPE_REAL)
      {
        // modbus datapoint must have subsystem associated to it. otherwise set to bad
        newQuality = CosDpQualityEnum.QualityBad;
      }

      // if any of the subsystem quality and expression quality is bad, set quality to bad
      if (newQuality == CosDpQualityEnum.QualityBad
          || expressionQuality_ == CosDpQualityEnum.QualityBad)
      {
        newQuality = CosDpQualityEnum.QualityBad;
      }
      else
      {
        newQuality = CosDpQualityEnum.QualityGood;
      }
    }

    // set the new quality, only if it is different
    if (outputValue_.quality == newQuality)
    {
      return 0;
    }
    outputValue_.quality = newQuality;

    return 1;
  }

  // synchronize source value and output value
  private int synchronize_value()
  {
    if (isInhibit() || isOverride() || type != EDataPointType.TYPE_REAL)
    {
      return -1;
    }

    // try to copy over the value
    int status = copy(outputValue_.value, sourceValue_.value);

    // if the value is the same but the timestamp is different
    // reset the status. consider it as a successful sync
    if (outputValue_.timestamp != sourceValue_.timestamp)
    {
      status = +1;
      // synchronize the timestamp
      outputValue_.timestamp = sourceValue_.timestamp;
    }

    return status;
  }
 
//  /**
//   * Prepare the expression.
//   * <br>
//   * This includes parsing the expression and compiling the parser. If the expression contains
//   * datapoint name, it is converted into a variable and the datapoint reference inserted into
//   * the list of parameters
//   * <br>
//   * Only when the parsing/compiling is successful, the isValid flag is set to true.
//   * (Default value is false.)
//   *
//   * @param  datapoint - reference to parent datapoint
//   * @param  dpServer - datapoint server where the datapoint is hosted.
//   *                     This will be used to retrieve reference to datapoint in the expression.
//   * @throws  Exception - when the parsing/compiling fails, exception is thrown. otherwise,
//   *             the function returns normally.
//   */
//  public void prepare(DataPoint datapoint, DataPointServer dpServer) throws Exception
//  {
//    final String KEYWORD_START = "{";
//    final String KEYWORD_END = "}";
//
//    //first of all get the return type
//    Class<?> rettype = int.class;    //default is int
//    if (datapoint != null)
//    {
//      switch(datapoint.getValue().discriminator().value())
//      {
//        case CosDpValueTypeEnum._TypeBoolean:
//          rettype = boolean.class;
//          break;
//        case CosDpValueTypeEnum._TypeDouble:
//          rettype = double.class;
//          break;
//        case CosDpValueTypeEnum._TypeNumber:
//          rettype = int.class;
//          break;
//        case CosDpValueTypeEnum._TypeString:
//          rettype = String.class;
//          break;
//        case CosDpValueTypeEnum._TypeUnsigned:
//          rettype = int.class;
//          break;
//      }
//    }
//   
//    //parse the expression. replace datapoint keyword with simplified name
//    if (!parseExpression(dpServer))
//    {
//      //set the invalid flag to prevent re-parsing next time
//      errorString_ = "prepare(): can not parse the expression!";
//      isValidExpression_ = false;
//      throw new Exception(errorString_);
//    }
//   
//    //create the parser
//    try
//    {
//      parser_ = new ExpressionEvaluator(
//                    shortExpression_,                   // expression
//                    rettype,                             // expressionType
//                    varnames_.toArray(new String[0]),   // parameterNames
//                    vartypes_.toArray(new Class<?>[0])   // parameterTypes
//                );
//    }
//    catch(Exception ex)
//    {
//      //set the invalid flag to prevent re-parsing next time
//      errorString_ = "prepare(): " + ex.toString();
//      isValidExpression_ = false;
//      throw new Exception(errorString_);
//    }
//   
//    isValidExpression_ = true;
//    return;
//  }
// 
  private String parse_expression(String expression,
                  ArrayList<xxxDataPoint> params, ArrayList<String> varnames,
                  ArrayList<Class<?>> vartypes, ArrayList<Object> varvalues)
  {
    StringBuffer strExpr = new StringBuffer(expression);
    String dpname = "";
    String varname = "";
    Class<?> vartype = int.class;
    Object varvalue = null;
    xxxDataPoint datapoint = null;
   
    //prepare list of variables
    params.clear();
    varnames.clear();
    vartypes.clear();
    varvalues.clear();

    //replace all datapoint name with equivalent variable name
    //datapoint name is in the format '{data_point_name}'
    int loc1 = strExpr.indexOf(KEYWORD_START, 0);
    int loc2 = 0;
    while (loc1 >= 0)
    {
      //reset just in case
      varname = "";
      //get the end of the datapoint name
      loc2 = strExpr.indexOf(KEYWORD_END, loc1);
      //if it is unterminated name
      if (loc2 < 1)
      {
        //delete the unterminated name
        strExpr.replace(loc1, strExpr.length(), "0");
      }
      else
      {
        //find a data point name
        dpname = strExpr.substring(loc1+1, loc2).trim();
        //parse the datapoint keyword
        if (dpServer == null)
        {
          //delete the datapoint keyword.
          strExpr.replace(loc1, loc2+KEYWORD_END.length(), "0");
        }
        else
        {
          //get the datapoint reference from dpserver
          datapoint = dpServer.getDataPoint(dpname);
          if ( datapoint == null )
          {
            //can not find the handle for the name -> invalid datapoint
            //verbose
            //__LOG_INFO(logger, "can not get handle!");
            //delete the invalid datapoint
            strExpr.replace(loc1, loc2+KEYWORD_END.length(), "0");   
          }
          else
          {
            //can find the handle. replace the keyword with a var name
            varname = "var" + params.size();
            strExpr.replace(loc1, loc2+KEYWORD_END.length(), varname);
            //add the handle into the list of handle for this data point
            params.add(datapoint);
            //store the var name
            varnames.add(varname);
            //determine the var type and initial value
            vartype = int.class;
            varvalue = null;
            switch(datapoint.getValue().discriminator().value())
            {
              case CosDpValueTypeEnum._TypeBoolean:
                vartype = boolean.class;
                varvalue = new Boolean(datapoint.getValue().boolValue());
                break;
              case CosDpValueTypeEnum._TypeDouble:
                vartype = double.class;
                varvalue = new Double(datapoint.getValue().dblValue());
                break;
              case CosDpValueTypeEnum._TypeNumber:
                vartype = int.class;
                varvalue = new Integer(datapoint.getValue().longValue());
                break;
              case CosDpValueTypeEnum._TypeString:
                vartype = String.class;
                varvalue = new String(datapoint.getValue().charValue());
                break;
              case CosDpValueTypeEnum._TypeUnsigned:
                vartype = int.class;
                varvalue = new Integer(datapoint.getValue().unsignedValue());
                break;
            }
            //store the var type and initial value
            vartypes.add(vartype);
            varvalues.add(varvalue);
          }
        }  //if (dpServer != null)
      //if find KEYWORD_START

      //try to find next datapoint name
      loc1 = strExpr.indexOf(KEYWORD_END, loc1+varname.length());
    //while (loc1 >= 0)
   
    //store the expression
    return strExpr.toString();
  }
 
  private CosDpValueUnion perform_eng_conversion(CosDpValueUnion value)
  {
    switch(value.discriminator().value())
    {
      case CosDpValueTypeEnum._TypeBoolean:
        value.boolValue( perform_eng_conversion(value.boolValue()) );
        break;
      case CosDpValueTypeEnum._TypeDouble:
        value.dblValue( perform_eng_conversion(value.dblValue()) );
        break;
      case CosDpValueTypeEnum._TypeNumber:
        value.longValue( perform_eng_conversion(value.longValue()) );
        break;
      case CosDpValueTypeEnum._TypeUnsigned:
        value.unsignedValue( perform_eng_conversion(value.unsignedValue()) );
        break;
      case CosDpValueTypeEnum._TypeString:
        value.charValue( perform_eng_conversion(value.charValue()) );
      break;
    }
   
    return value;
  }
 
  private boolean perform_eng_conversion(boolean value)
  {
    // update the input value parameter
    Boolean objVal = new Boolean(value);
    engParser_.set(0, objVal);
   
    //perform the conversion
    try
    {
      objVal = (Boolean)engParser_.evaluate();
      return objVal.booleanValue();
    }
    catch(Exception ex)
    {
      logger_.warn("Can not evaluate engineering conversion. Exception: " + ex.toString());
    }
   
    //return the original value
    return value;
  }

  private int perform_eng_conversion(int value)
  {
    // update the input value parameter
    Integer objVal = new Integer(value);
    engParser_.set(0, objVal);
   
    //perform the conversion
    try
    {
      objVal = (Integer)engParser_.evaluate();
      return objVal.intValue();
    }
    catch(Exception ex)
    {
      logger_.warn("Can not evaluate engineering conversion. Exception: " + ex.toString());
    }
   
    //return the original value
    return value;
  }
 
  private double perform_eng_conversion(double value)
  {
    // update the input value parameter
    Double objVal = new Double(value);
    engParser_.set(0, objVal);
   
    //perform the conversion
    try
    {
      objVal = (Double)engParser_.evaluate();
      return objVal.doubleValue();
    }
    catch(Exception ex)
    {
      logger_.warn("Can not evaluate engineering conversion. Exception: " + ex.toString());
    }
   
    //return the original value
    return value;
  }
 
  private String perform_eng_conversion(String value)
  {
    // update the input value parameter
    engParser_.set(0, value);
   
    //perform the conversion
    try
    {
      value = (String)engParser_.evaluate();
    }
    catch(Exception ex)
    {
      logger_.warn("Can not evaluate engineering conversion. Exception: " + ex.toString());
    }
   
    //return the original value
    return value;
  }
}
TOP

Related Classes of tcg.scada.da.xxxDataPoint

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.