/**
   * Returns a copy of this ThresholdEntity object.
   *
   * <p>NOTE: The m_lowThreshold and m_highThreshold member variables are not actually cloned...the
   * returned ThresholdEntity object will simply contain references to the same castor Threshold
   * objects as the original ThresholdEntity object.
   *
   * <p>All state will be lost, particularly instances, so it's not a true clone by any stretch of
   * the imagination
   *
   * @return a {@link org.opennms.netmgt.threshd.ThresholdEntity} object.
   */
  public ThresholdEntity clone() {
    ThresholdEntity clone = new ThresholdEntity();
    for (ThresholdEvaluatorState thresholdItem : getThresholdEvaluatorStates(null)) {
      clone.addThreshold(thresholdItem.getThresholdConfig());
    }

    return clone;
  }
  /**
   * Performs threshold checking on an directory which contains one or more RRD files containing
   * latency/response time information. ThresholdEntity objects are stored for performing threshold
   * checking.
   *
   * @param latIface TODO
   * @param latParms TODO
   * @param parameters
   * @param iface
   * @param directory RRD repository directory
   * @param m_nodeId Node identifier of interface being checked
   * @param ipAddr IP address of the interface being checked
   * @param interval Configured thresholding interval
   * @param date Source for timestamp to be used for all generated events
   * @param thresholdMap Map of configured interface level ThresholdEntity objects keyed by
   *     datasource name.
   * @param events Castor events object containing any events to be generated as a result of
   *     threshold checking.
   * @throws IllegalArgumentException if path parameter is not a directory.
   * @throws ThresholdingException
   */
  Events checkRrdDir(LatencyInterface latIface, LatencyParameters latParms)
      throws IllegalArgumentException, ThresholdingException {
    Map<String, ThresholdEntity> thresholdMap = latIface.getThresholdMap();

    // Sanity Check
    if (latIface.getInetAddress() == null || thresholdMap == null) {
      throw new ThresholdingException(
          "check: Threshold checking failed for " + m_svcName + "/" + latIface.getHostAddress(),
          THRESHOLDING_FAILED);
    }

    Events events = new Events();
    Date date = new Date();

    for (Iterator<String> it = thresholdMap.keySet().iterator(); it.hasNext(); ) {
      String datasource = it.next();
      ThresholdEntity threshold = thresholdMap.get(datasource);
      if (threshold != null) {
        Double dsValue = threshold.fetchLastValue(latIface, latParms);
        Map<String, Double> dsValues = new HashMap<String, Double>();
        dsValues.put(datasource, dsValue);
        List<Event> eventList = threshold.evaluateAndCreateEvents(dsValues, date);
        if (eventList.size() == 0) {
          // Nothing to do, so continue
          continue;
        }

        completeEventListAndAddToEvents(events, eventList, latIface);

        /*
        threshold.evaluateThreshold(dsValue, events, date, latIface);
        */
      }
    }

    return events;
  }
  /**
   * {@inheritDoc}
   *
   * <p>Responsible for performing all necessary initialization for the specified interface in
   * preparation for thresholding.
   */
  public void initialize(ThresholdNetworkInterface iface, Map<?, ?> parameters) {
    // Get interface address from NetworkInterface
    //
    if (iface.getType() != NetworkInterface.TYPE_INET)
      throw new RuntimeException("Unsupported interface type, only TYPE_INET currently supported");
    InetAddress ipAddr = (InetAddress) iface.getAddress();
    String groupName = ParameterMap.getKeyedString(parameters, "thresholding-group", "default");

    // Get the threshold group's RRD repository path
    //
    String repository = null;
    try {
      repository = ThresholdingConfigFactory.getInstance().getRrdRepository(groupName);
    } catch (IllegalArgumentException e) {
      throw new RuntimeException("Thresholding group '" + groupName + "' does not exist.");
    }

    // Add RRD repository as an attribute of the interface for retrieval
    // by the check() method.
    //
    iface.setAttribute(RRD_REPOSITORY_KEY, repository);

    // Get database connection in order to retrieve the nodeid and
    // ifIndex from the database for this interface.
    //
    java.sql.Connection dbConn = null;
    final DBUtils d = new DBUtils(getClass());
    try {
      dbConn = DataSourceFactory.getInstance().getConnection();
      d.watch(dbConn);
    } catch (SQLException sqlE) {
      if (log().isEnabledFor(ThreadCategory.Level.ERROR))
        log().error("initialize: Failed getting connection to the database.", sqlE);
      throw new UndeclaredThrowableException(sqlE);
    }

    // Use IP address to lookup the node id
    //
    // NOTE: All database calls wrapped in try/finally block so we make
    // certain that the connection will be closed when we are
    // finished.
    //
    int nodeId = -1;

    final String hostAddress = InetAddressUtils.str(ipAddr);
    try {
      // Prepare & execute the SQL statement to get the 'nodeid',
      // 'ifIndex' and 'isSnmpPrimary' fields from the ipInterface table.
      //
      PreparedStatement stmt = null;
      try {
        stmt = dbConn.prepareStatement(SQL_GET_NODEID);
        d.watch(stmt);
        stmt.setString(1, hostAddress); // interface address
        ResultSet rs = stmt.executeQuery();
        d.watch(rs);
        if (rs.next()) {
          nodeId = rs.getInt(1);
          if (rs.wasNull()) nodeId = -1;
        }
      } catch (SQLException sqle) {
        if (log().isDebugEnabled()) log().debug("initialize: SQL exception!!", sqle);
        throw new RuntimeException(
            "SQL exception while attempting to retrieve node id for interface " + hostAddress);
      }

      if (log().isDebugEnabled())
        log()
            .debug(
                "initialize: db retrieval info: nodeid = " + nodeId + ", address = " + hostAddress);

      if (nodeId == -1)
        throw new RuntimeException("Unable to retrieve node id for interface " + hostAddress);
    } finally {
      d.cleanUp();
    }

    // Add nodeId as an attribute of the interface for retrieval
    // by the check() method.
    //
    iface.setAttribute(NODE_ID_KEY, new Integer(nodeId));

    // Retrieve the collection of Threshold objects associated with
    // the defined thresholding group and build maps of
    // ThresholdEntity objects keyed by datasource name. The
    // datasource type of the threshold determines which
    // map the threshold entity is added to.
    //
    // Each ThresholdEntity can wrap one high Threshold and one low
    // Threshold castor-generated object for a single datasource.
    // If more than one high or more than one low threshold is defined
    // for a single datasource a warning messages is generated. Only
    // the first threshold in such a scenario will be used for thresholding.
    //

    // Create empty map for storing threshold entities
    Map<String, ThresholdEntity> thresholdMap = new HashMap<String, ThresholdEntity>();

    try {
      for (Basethresholddef thresh :
          ThresholdingConfigFactory.getInstance().getThresholds(groupName)) {
        // See if map entry already exists for this datasource
        // If not, create a new one.
        boolean newEntity = false;
        ThresholdEntity thresholdEntity = null;

        // All latency thresholds are per interface so confirm that
        // the datasource type is set to "if"
        //
        if (!thresh.getDsType().equals("if") && !thresh.getDsType().equals("expr")) {
          log()
              .warn(
                  "initialize: invalid datasource type, latency thresholder only supports interface level datasources.");
          continue; // continue with the next threshold...
        }
        try {
          BaseThresholdDefConfigWrapper wrapper =
              BaseThresholdDefConfigWrapper.getConfigWrapper(thresh);
          // First attempt to lookup the entry in the map
          thresholdEntity = thresholdMap.get(wrapper.getDatasourceExpression());

          // Found entry?
          if (thresholdEntity == null) {
            // Nope, create a new one
            newEntity = true;
            thresholdEntity = new ThresholdEntity();
          }

          try {
            thresholdEntity.addThreshold(wrapper);
          } catch (IllegalStateException e) {
            log()
                .warn(
                    "Encountered duplicate "
                        + thresh.getType()
                        + " for datasource "
                        + wrapper.getDatasourceExpression()
                        + ": "
                        + e,
                    e);
          }

          // Add new entity to the map
          if (newEntity) {
            thresholdMap.put(wrapper.getDatasourceExpression(), thresholdEntity);
          }
        } catch (ThresholdExpressionException e) {
          log().warn("Could not parse threshold expression: " + e.getMessage(), e);
        }
      }
    } catch (IllegalArgumentException e) {
      throw new RuntimeException("Thresholding group '" + groupName + "' does not exist.");
    }

    // Add threshold maps as attributes for retrieval by the check() method.
    //
    iface.setAttribute(THRESHOLD_MAP_KEY, thresholdMap);

    // Debug
    //
    if (log().isDebugEnabled()) {
      log()
          .debug(
              "initialize: dumping interface thresholds defined for "
                  + hostAddress
                  + "/"
                  + groupName
                  + ":");
      Iterator<ThresholdEntity> iter = thresholdMap.values().iterator();
      while (iter.hasNext()) log().debug(iter.next().toString());
    }

    if (log().isDebugEnabled())
      log().debug("initialize: initialization completed for " + hostAddress);
    return;
  }
 /**
  * Merges the configuration and update states using parameter entity as a reference.
  *
  * @param entity a {@link org.opennms.netmgt.threshd.ThresholdEntity} object.
  */
 public void merge(ThresholdEntity entity) {
   if (getThresholdConfig().equals(entity.getThresholdConfig()) == false) {
     sendRearmForTriggeredStates();
     getThresholdConfig().merge(entity.getThresholdConfig());
   }
 }