gt:     boolean hasIfIndex() {
context: /*******************************************************************************
   * This file is part of OpenNMS(R).
   *
   * Copyright (C) 2006-2012 The OpenNMS Group, Inc.
   * OpenNMS(R) is Copyright (C) 1999-2012 The OpenNMS Group, Inc.
   *
   * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
   *
   * OpenNMS(R) is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published
   * by the Free Software Foundation, either version 3 of the License,
   * or (at your option) any later version.
   *
   * OpenNMS(R) is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with OpenNMS(R).  If not, see:
   *      http://www.gnu.org/licenses/
   *
   * For more information contact:
   *     OpenNMS(R) Licensing <license@opennms.org>
   *     http://www.opennms.org/
   *     http://www.opennms.com/
   *******************************************************************************/
  
  package org.opennms.netmgt.capsd;
  
  import java.net.InetAddress;
  import java.sql.Connection;
  import java.sql.PreparedStatement;
  import java.sql.ResultSet;
  import java.sql.SQLException;
  import java.sql.Timestamp;
  import java.sql.Types;
  import java.text.ParseException;
  import java.util.ArrayList;
  import java.util.Date;
  import java.util.List;
  
  import org.opennms.core.utils.DBUtils;
  import org.opennms.core.utils.InetAddressUtils;
  import org.opennms.core.utils.ThreadCategory;
  import org.opennms.netmgt.EventConstants;
  import org.opennms.netmgt.config.DataSourceFactory;
  
  /**
   *
   * <p>
   * Once loaded or create, the class tracks any changes and will write those
   * changes to the database whenever the <code>store</code> method is invoked.
   * If a database connection is not passed to the store method, then a temporary
   * one is allocated to write the results.
   * </p>
   *
   * <p>
   * NOTE: if the connection is passed in and is not in auto commit mode, then the
   * caller must call <code>commit</code> to inform the database that the
   * transaction is complete.
   *
   * @author <a href="mailto:jamesz@opennms.com">James Zuo </a>
   * @author <a href="mailto:weave@oculan.com">Weave </a>
   */
  public final class DbIpInterfaceEntry {
      /** Constant <code>SNMP_PRIMARY='P'</code> */
      public final static char SNMP_PRIMARY = 'P';
  
      /** Constant <code>SNMP_SECONDARY='S'</code> */
      public final static char SNMP_SECONDARY = 'S';
  
      /** Constant <code>SNMP_NOT_ELIGIBLE='N'</code> */
      public final static char SNMP_NOT_ELIGIBLE = 'N';
  
      /** Constant <code>SNMP_UNKNOWN=' '</code> */
      public final static char SNMP_UNKNOWN = ' ';
  
      /** Constant <code>STATE_MANAGED='M'</code> */
      public final static char STATE_MANAGED = 'M';
  
      /** Constant <code>STATE_UNMANAGED='U'</code> */
      public final static char STATE_UNMANAGED = 'U';
  
      /** Constant <code>STATE_ALIAS='A'</code> */
      public final static char STATE_ALIAS = 'A';
  
      /** Constant <code>STATE_DELETED='D'</code> */
      public final static char STATE_DELETED = 'D';
  
      /** Constant <code>STATE_FORCED='F'</code> */
      public final static char STATE_FORCED = 'F';
  
      /** Constant <code>STATE_NOT_POLLED='N'</code> */
      public final static char STATE_NOT_POLLED = 'N';
      
      /** Constant <code>STATE_REMOTE='X'</code> */
      public final static char STATE_REMOTE = 'X';
  
      /** Constant <code>STATE_UNKNOWN=' '</code> */
      public final static char STATE_UNKNOWN = ' ';
  
      /**
       * The SQL statement used to read a node from the database. This record is
       * keyed by the node identifier and distributed poller name.
       */
      private static final String SQL_LOAD_REC = "SELECT ifIndex, ipHostname, isManaged, ipStatus, ipLastCapsdPoll, isSnmpPrimary FROM ipInterface WHERE nodeID = ? AND ipAddr = ? AND isManaged != 'D'";
  
      /**
       * This is the SQL statement used to load the list of service identifiers
       * associated with this interface. Once the identifiers are known then a
       * list of DbIfServiceEntry(s) can be returned to the caller.
       */
      private static final String SQL_LOAD_IFSVC_LIST = "SELECT serviceID FROM ifServices WHERE nodeID = ? AND ipAddr = ? AND status != 'D'";
  
      /**
       * This is the SQL statement used to load a record when the ifIndex is
       * involved as part of the key lookup. This is mainly used when a node has
       * multiple <em>unnamed</em> interfaces (i.e. 0.0.0.0) but each has a
       * different ifIndex.
       */
      private static final String SQL_LOAD_REC_IFINDEX = "SELECT ifIndex, ipHostname, isManaged, ipStatus, ipLastCapsdPoll, isSnmpPrimary FROM ipInterface WHERE nodeID = ? AND ipAddr = ? AND ifIndex = ? AND isManaged != 'D'";
  
      /**
       * True if this recored was loaded from the database. False if it's new.
       */
      private boolean m_fromDb;
  
      /**
       * The node identifier
       */
      private long m_nodeId;
  
      /**
       * The IP address.
       */
      private InetAddress m_ipAddr;
  
      /**
       * The SNMP ifIndex
       */
      private int m_ifIndex;
      private int m_originalIfIndex;
  
      /**
       * The hostname string, if any
       */
      private String m_hostname;
  
      /**
       * The status of the interface
       */
      private int m_status;
  
      /**
       * The managed status, if any
       */
      private char m_managedState;
  
      /**
       * The last time the interface was checked.
       */
      private Timestamp m_lastPoll;
  
      /**
       * The SNMP primary status.
       */
      private char m_primaryState;
  
      /**
       * The bit map used to determine which elements have changed since the
       * record was created.
       */
      private int m_changed;
  
      // Mask fields
      //
      private static final int CHANGED_IFINDEX = 1 << 0;
  
      private static final int CHANGED_HOSTNAME = 1 << 1;
  
      private static final int CHANGED_MANAGED = 1 << 2;
  
      private static final int CHANGED_STATUS = 1 << 3;
  
      private static final int CHANGED_POLLTIME = 1 << 4;
  
      private static final int CHANGED_PRIMARY = 1 << 5;
  
      // Indicates that the ifIndex is to be used as database key for this entry
      private boolean m_useIfIndexAsKey;
  
      /**
       * Inserts the new interface into the ipInterface table of the OpenNMS
       * databasee.
       * 
       * @param c
       *            The connection to the database.
       * 
       * @throws java.sql.SQLException
       *             Thrown if an error occurs with the connection
       */
      private void insert(Connection c) throws SQLException {
          if (m_fromDb) {
              throw new IllegalStateException("The record already exists in the database");
          }
  
          // first extract the next node identifier
          StringBuffer names = new StringBuffer("INSERT INTO ipInterface (nodeID,ipAddr");
          StringBuffer values = new StringBuffer("?,?");
  
          if ((m_changed & CHANGED_IFINDEX) == CHANGED_IFINDEX) {
              values.append(",?");
              names.append(",ifIndex");
          }
  
          if ((m_changed & CHANGED_HOSTNAME) == CHANGED_HOSTNAME) {
              values.append(",?");
              names.append(",ipHostname");
          }
  
          if ((m_changed & CHANGED_MANAGED) == CHANGED_MANAGED) {
              values.append(",?");
              names.append(",isManaged");
          }
  
          if ((m_changed & CHANGED_STATUS) == CHANGED_STATUS) {
              values.append(",?");
              names.append(",ipStatus");
          }
  
          if ((m_changed & CHANGED_POLLTIME) == CHANGED_POLLTIME) {
              values.append(",?");
              names.append(",ipLastCapsdPoll");
          }
  
          if ((m_changed & CHANGED_PRIMARY) == CHANGED_PRIMARY) {
              values.append(",?");
              names.append(",isSnmpPrimary");
          }
  
          names.append(") VALUES (").append(values).append(')');
          if (log().isDebugEnabled()) {
              log().debug("DbIpInterfaceEntry.insert: SQL insert statement for interface [" + m_nodeId + "," + m_ipAddr + "] = " + names.toString());
          }
  
          // create the Prepared statement and then start setting the result values
          PreparedStatement stmt = null;
          final DBUtils d = new DBUtils(getClass());
  
          try {
              stmt = c.prepareStatement(names.toString());
              d.watch(stmt);
              names = null;
              int ndx = 1;
              stmt.setLong(ndx++, m_nodeId);
              stmt.setString(ndx++, InetAddressUtils.str(m_ipAddr));
              if ((m_changed & CHANGED_IFINDEX) == CHANGED_IFINDEX) {
                  stmt.setInt(ndx++, m_ifIndex);
              }
              if ((m_changed & CHANGED_HOSTNAME) == CHANGED_HOSTNAME) {
                  stmt.setString(ndx++, m_hostname);
              }
              if ((m_changed & CHANGED_MANAGED) == CHANGED_MANAGED) {
                  stmt.setString(ndx++,
                                 new String(new char[] { m_managedState }));
              }
              if ((m_changed & CHANGED_STATUS) == CHANGED_STATUS) {
                  stmt.setInt(ndx++, m_status);
              }
              if ((m_changed & CHANGED_POLLTIME) == CHANGED_POLLTIME) {
                  stmt.setTimestamp(ndx++, m_lastPoll);
              }
              if ((m_changed & CHANGED_PRIMARY) == CHANGED_PRIMARY) {
                  stmt.setString(ndx++,
                                 new String(new char[] { m_primaryState }));
              }
              // Run the insert
              int rc = stmt.executeUpdate();
              log().debug("DbIpInterfaceEntry.insert: SQL update result = " + rc);
          } finally {
              d.cleanUp();
          }
  
          // clear the mask and mark as backed by the database
          m_fromDb = true;
          m_changed = 0;
      }
      
      /**
       * Updates an existing record in the OpenNMS ipInterface table.
       * 
       * @param c
       *            The connection used for the update.
       * 
       * @throws java.sql.SQLException
       *             Thrown if an error occurs with the connection
       */
      private void update(Connection c) throws SQLException {
          if (!m_fromDb) {
              throw new IllegalStateException("The record does not exists in the database");
          }
  
          // first extract the next node identifier
          StringBuffer sqlText = new StringBuffer("UPDATE ipInterface SET ");
  
          char comma = ' ';
          if ((m_changed & CHANGED_IFINDEX) == CHANGED_IFINDEX) {
              sqlText.append(comma).append("ifIndex = ?");
              comma = ',';
          }
  
          if ((m_changed & CHANGED_HOSTNAME) == CHANGED_HOSTNAME) {
              sqlText.append(comma).append("ipHostname = ?");
              comma = ',';
          }
  
          if ((m_changed & CHANGED_MANAGED) == CHANGED_MANAGED) {
              sqlText.append(comma).append("isManaged = ?");
              comma = ',';
          }
  
          if ((m_changed & CHANGED_STATUS) == CHANGED_STATUS) {
              sqlText.append(comma).append("ipStatus = ?");
              comma = ',';
          }
  
          if ((m_changed & CHANGED_POLLTIME) == CHANGED_POLLTIME) {
              sqlText.append(comma).append("ipLastCapsdPoll = ?");
              comma = ',';
          }
  
          if ((m_changed & CHANGED_PRIMARY) == CHANGED_PRIMARY) {
              sqlText.append(comma).append("isSnmpPrimary = ?");
              comma = ',';
          }
  
          if (m_useIfIndexAsKey) {
              sqlText.append(" WHERE nodeID = ? AND ipAddr = ? AND ifIndex = ?");
          } else {
              sqlText.append(" WHERE nodeID = ? AND ipAddr = ?");
          }
  
          if ((m_changed & CHANGED_PRIMARY) == CHANGED_PRIMARY && m_primaryState == 'N') {
              sqlText.append(" AND isSnmpPrimary != 'C'");
          }
  
          sqlText.append(" AND isManaged <> 'D'");
  
          log().debug("DbIpInterfaceEntry.update: SQL update statment = " + sqlText.toString());
  
          // create the Prepared statement and then start setting the result values
          PreparedStatement stmt = null;
          final DBUtils d = new DBUtils(getClass());
  
          try {
              stmt = c.prepareStatement(sqlText.toString());
              d.watch(stmt);
              sqlText = null;
              int ndx = 1;
              if ((m_changed & CHANGED_IFINDEX) == CHANGED_IFINDEX) {
                  if (m_ifIndex == -1) {
                      stmt.setNull(ndx++, Types.INTEGER);
                  } else {
                      stmt.setInt(ndx++, m_ifIndex);
                  }
              }
              if ((m_changed & CHANGED_HOSTNAME) == CHANGED_HOSTNAME) {
                  if (m_hostname != null) {
                      stmt.setString(ndx++, m_hostname);
                  } else {
                      stmt.setNull(ndx++, Types.VARCHAR);
                  }
              }
              if ((m_changed & CHANGED_MANAGED) == CHANGED_MANAGED) {
                  if (m_managedState == STATE_UNKNOWN) {
                      stmt.setString(ndx++, "N");
                  } else {
                      stmt.setString(ndx++,
                                     new String(new char[] { m_managedState }));
                  }
              }
              if ((m_changed & CHANGED_STATUS) == CHANGED_STATUS) {
                  if (m_status == -1) {
                      stmt.setNull(ndx++, Types.INTEGER);
                  } else {
                      stmt.setInt(ndx++, m_status);
                  }
              }
              if ((m_changed & CHANGED_POLLTIME) == CHANGED_POLLTIME) {
                  if (m_lastPoll != null) {
                      stmt.setTimestamp(ndx++, m_lastPoll);
                  } else {
                      stmt.setNull(ndx++, Types.TIMESTAMP);
                  }
              }
              if ((m_changed & CHANGED_PRIMARY) == CHANGED_PRIMARY) {
                  if (m_primaryState == SNMP_UNKNOWN) {
                      stmt.setNull(ndx++, Types.CHAR);
                  } else {
                      stmt.setString(ndx++,
                                     new String(new char[] { m_primaryState }));
                  }
              }
              stmt.setLong(ndx++, m_nodeId);
              stmt.setString(ndx++, InetAddressUtils.str(m_ipAddr));
              if (m_useIfIndexAsKey) {
                  if (m_ifIndex == -1) {
                      stmt.setNull(ndx++, Types.INTEGER);
                  } else {
                      stmt.setInt(ndx++, m_originalIfIndex);
                  }
              }
              // Run the insert
              int rc = stmt.executeUpdate();
              log().debug("DbIpInterfaceEntry.update: update result = " + rc);
          } finally {
              d.cleanUp();
          }
  
          // clear the mask and mark as backed by the database
          m_changed = 0;
      }
  
      /**
       * Load the current interface from the database. If the interface was
       * modified, the modifications are lost. The nodeid and ip address must be
       * set prior to this call.
       * 
       * @param c
       *            The connection used to load the data.
       * 
       * @throws java.sql.SQLException
       *             Thrown if an error occurs with the connection
       */
      private boolean load(Connection c) throws SQLException {
          if (!m_fromDb) {
              throw new IllegalStateException("The record does not exists in the database");
          }
  
          // create the Prepared statement and then start setting the query values
          PreparedStatement stmt = null;
          ResultSet rset = null;
          final DBUtils d = new DBUtils(getClass());
    
          try {
              if (m_useIfIndexAsKey) {
                  stmt = c.prepareStatement(SQL_LOAD_REC_IFINDEX);
                  d.watch(stmt);
                  stmt.setLong(1, m_nodeId);
                  stmt.setString(2, InetAddressUtils.str(m_ipAddr));
                  stmt.setInt(3, m_ifIndex);
              } else {
                  stmt = c.prepareStatement(SQL_LOAD_REC);
                  d.watch(stmt);
                  stmt.setLong(1, m_nodeId);
                  stmt.setString(2, InetAddressUtils.str(m_ipAddr));
              }
  
              // Execute the query
              rset = stmt.executeQuery();
              d.watch(rset);
              if (!rset.next()) {
                  return false;
              }
  
              // extract the values
              int ndx = 1;
  
              // get the ifIndex
              m_ifIndex = rset.getInt(ndx++);
              if (rset.wasNull()) {
                  m_ifIndex = -1;
              }
  
              // get the host name
              m_hostname = rset.getString(ndx++);
              if (rset.wasNull()) {
                  m_hostname = null;
              }
  
              // get the managed status
              String str = rset.getString(ndx++);
              if (str != null && rset.wasNull() == false) {
                  m_managedState = str.charAt(0);
              } else {
                  m_managedState = STATE_UNKNOWN;
              }
  
              // get the status
              m_status = rset.getInt(ndx++);
              if (rset.wasNull()) {
                  m_status = -1;
              }
  
              // get the time
              m_lastPoll = rset.getTimestamp(ndx++);
  
              // get the SNMP primary state
              str = rset.getString(ndx++);
              if (str != null && rset.wasNull() == false) {
                  m_primaryState = str.charAt(0);
              } else {
                  m_primaryState = STATE_UNKNOWN;
              }
          } finally {
              d.cleanUp();
          }
  
          // clear the mask and mark as backed by the database
          m_changed = 0;
          return true;
      }
  
      /**
       * Default constructor.
       * 
       */
      private DbIpInterfaceEntry() {
          throw new UnsupportedOperationException("Default constructor not supported!");
      }
  
      /**
       * Constructs a new interface.
       * 
       * @param nid
       *            The node identifier.
       * @param address
       *            The target interface address.
       * @param exists
       *            True if the interface already exists.
       * 
       */
      private DbIpInterfaceEntry(long nid, InetAddress address, boolean exists) {
          m_fromDb = exists;
          m_nodeId = nid;
          m_ipAddr = address;
          m_ifIndex = -1;
          m_originalIfIndex = -1;
          m_managedState = STATE_UNKNOWN;
          m_status = -1;
          m_lastPoll = null;
          m_primaryState = SNMP_UNKNOWN;
          m_changed = 0;
          m_useIfIndexAsKey = false;
      }
  
      /**
       * Constructs a new interface, this constructor will only work for entries
       * loaded from the database!
       * 
       * @param nid
       *            The node identifier.
       * @param address
       *            The target interface address.
       * @param ifIndex
       *            The target ifIndex of the node/address pair
       * @param exists
       *            True if the interface already exists.
       * 
       */
      private DbIpInterfaceEntry(long nid, InetAddress address, int ifIndex, boolean exists) {
          m_fromDb = exists;
          m_nodeId = nid;
          m_ipAddr = address;
          m_ifIndex = ifIndex;
          m_originalIfIndex = ifIndex;
          m_status = -1;
          m_lastPoll = null;
          m_managedState = STATE_UNKNOWN;
          m_primaryState = SNMP_UNKNOWN;
          m_changed = 0;
          m_useIfIndexAsKey = true;
      }
  
      /**
       * Returns the node entry's unique identifier. This is a non-mutable
       * element. If the record does not yet exist in the database then a -1 is
       * returned.
       * 
       */
      long getNodeId() {
          return m_nodeId;
      }
  
      /**
       * Returns the name of the distributed poller for the entry. This is a
       * non-mutable element of the record.
       * 
       */
      InetAddress getIfAddress() {
          return m_ipAddr;
      }
  
      /**
       * Gets the last poll time of the record
       */
      String getLastPollString() {
          String result = null;
          if (m_lastPoll != null) {
              result = m_lastPoll.toString();
          }
          return result;
      }
  
      /**
       * Gets the last poll time of the record
       */
      Timestamp getLastPoll() {
          return m_lastPoll;
      }
  
      /**
       * Sets the current creation time.
       * 
       * @param time
       *            The creation time.
       * 
       */
      void setLastPoll(String time) throws ParseException {
          if (time == null) {
              m_lastPoll = null;
          } else {
              Date tmpDate = EventConstants.parseToDate(time);
              m_lastPoll = new Timestamp(tmpDate.getTime());
          }
          m_changed |= CHANGED_POLLTIME;
      }
  
      /**
       * Sets the current creation time.
       * 
       * @param time
       *            The creation time.
       * 
       */
      void setLastPoll(Date time) {
          m_lastPoll = new Timestamp(time.getTime());
          m_changed |= CHANGED_POLLTIME;
      }
  
      /**
       * Sets the current creation time.
       * 
       * @param time
       *            The creation time.
       * 
       */
      void setLastPoll(Timestamp time) {
          m_lastPoll = time;
          m_changed |= CHANGED_POLLTIME;
      }
  
      /**
       * Returns true if the ifIndex is defined.
       */
  