org.opennms.ng.services.capsd.JdbcCapsdDbSyncer.java Source code

Java tutorial

Introduction

Here is the source code for org.opennms.ng.services.capsd.JdbcCapsdDbSyncer.java

Source

/*******************************************************************************
 * This file is part of OpenNMS(R).
 *
 * Copyright (C) 2007-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.ng.services.capsd;

import java.net.InetAddress;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.opennms.core.utils.ConfigFileConstants;
import org.opennms.core.utils.DBUtils;
import org.opennms.core.utils.InetAddressUtils;
import org.opennms.netmgt.model.capsd.DbIfServiceEntry;
import org.opennms.netmgt.model.capsd.DbIpInterfaceEntry;
import org.opennms.ng.services.capsdconfig.CapsdConfig;
import org.opennms.ng.services.collectdconfig.CollectdConfig;
import org.opennms.ng.services.opennmsserverconfig.OpennmsServerConfig;
import org.opennms.ng.services.pollerconfig.PollerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.Assert;

/**
 * <p>JdbcCapsdDbSyncer class.</p>
 *
 * @author ranger
 * @version $Id: $
 */
public class JdbcCapsdDbSyncer implements CapsdDbSyncer {

    private static final Logger LOG = LoggerFactory.getLogger(JdbcCapsdDbSyncer.class);

    /**
     * <P>
     * LightWeightIfEntry is designed to hold specific information about an IP
     * interface in the database such as its IP address, its parent node id, and
     * its managed status and represents a lighter weight version of the
     * DbIpInterfaceEntry class.
     * </P>
     */
    protected static final class LightWeightIfEntry {
        /**
         * Represents NULL value for 'ifIndex' field in the ipInterface table
         */
        protected final static int NULL_IFINDEX = -1;

        protected final static int NULL_IFTYPE = -1;

        protected final static int LOOPBACK_IFTYPE = 24;

        private int m_nodeId;

        private int m_ifIndex;

        private int m_ifType;

        private String m_address;

        private char m_managementState;

        private char m_snmpPrimaryState;

        private boolean m_primaryStateChanged;

        /**
         * <P>
         * Constructs a new LightWeightIfEntry object.
         * </P>
         * 
         * @param nodeId
         *            Interface's parent node id
         * @param ifIndex
         *            Interface's index
         * @param address
         *            Interface's ip address
         * @param managementState
         *            Interface's management state
         * @param snmpPrimaryState
         *            Interface's primary snmp interface state
         * @param ifType
         *            Interface's type as determined via SNMP
         */
        public LightWeightIfEntry(int nodeId, int ifIndex, String address, char managementState,
                char snmpPrimaryState, int ifType) {
            m_nodeId = nodeId;
            m_ifIndex = ifIndex;
            m_address = address;
            m_managementState = managementState;
            m_snmpPrimaryState = snmpPrimaryState;
            m_ifType = ifType;
            m_primaryStateChanged = false;
        }

        /**
         * <P>
         * Returns the IP address of the interface.
         * </P>
         */
        public String getAddress() {
            return m_address;
        }

        /**
         * <P>
         * Returns the parent node id of the interface.
         * </P>
         */
        public int getNodeId() {
            return m_nodeId;
        }

        /**
         * <P>
         * Returns the ifIndex of the interface.
         * </P>
         */
        public int getIfIndex() {
            return m_ifIndex;
        }

        /**
         * <P>
         * Returns the ifType of the interface.
         * </P>
         */
        public int getIfType() {
            return m_ifType;
        }

        /**
         * 
         */
        public char getManagementState() {
            return m_managementState;
        }

        /**
         * 
         */
        public char getSnmpPrimaryState() {
            return m_snmpPrimaryState;
        }

        /**
         * 
         */
        public void setSnmpPrimaryState(char state) {
            if (state != m_snmpPrimaryState) {
                m_snmpPrimaryState = state;
                m_primaryStateChanged = true;
            }
        }

        /**
         * 
         */
        public boolean hasSnmpPrimaryStateChanged() {
            return m_primaryStateChanged;
        }
    }

    /**
     * The SQL statement used to retrieve all non-deleted/non-forced unamanaged
     * IP interfaces from the 'ipInterface' table.
     */
    private static final String SQL_DB_RETRIEVE_IP_INTERFACE = "SELECT ip.nodeid, ip.ipaddr, ip.ismanaged "
            + "FROM ipinterface as ip " + "JOIN node as n ON ip.nodeid = n.nodeid " + "WHERE ip.ipaddr!='0.0.0.0' "
            + "AND ip.isManaged!='D' " + "AND ip.isManaged!='F' " + "AND n.foreignSource is null";

    /**
     * The SQL statement used to retrieve all non-deleted/non-forced unamanaged
     * IP interfaces from the 'ipInterface' table with the local OpenNMS server
     * restriction.
     */
    private static final String SQL_DB_RETRIEVE_IP_INTERFACE_IN_LOCAL_SERVER = "SELECT ip.nodeid, ip.ipaddr, ip.ismanaged "
            + "FROM ipinterface as ip " + "JOIN node as n ON n.nodeid = ip.nodeid "
            + "JOIN servermap as s ON ip.ipaddr = s.ipaddr " + "WHERE ip.ipaddr!='0.0.0.0' "
            + "AND ip.isManaged!='D' " + "AND ip.isManaged!='F' " + "AND s.servername = ? "
            + "AND n.foreignSource is null";

    /**
     * SQL statement to retrieve all non-deleted IP addresses from the
     * ipInterface table which support SNMP.
     */
    private static final String SQL_DB_RETRIEVE_SNMP_IP_INTERFACES = "SELECT DISTINCT ipinterface.nodeid,ipinterface.ipaddr,ipinterface.ifindex,ipinterface.issnmpprimary,snmpinterface.snmpiftype,snmpinterface.snmpifindex "
            + "FROM ipinterface " + "JOIN node ON node.nodeid = ipinterface.nodeid "
            + "JOIN snmpinterface ON ipinterface.snmpinterfaceid = snmpinterface.id "
            + "JOIN ifservices ON ifservices.ipinterfaceid = ipinterface.id "
            + "JOIN service ON ifservices.serviceid = service.serviceid " + "WHERE ipinterface.ismanaged!='D' "
            + "AND ifservices.status != 'D' " + "AND service.servicename='SNMP' "
            + "AND node.foreignSource is null";

    /**
     * SQL statement used to update the 'isSnmpPrimary' field of the ipInterface
     * table.
     */
    private static final String SQL_DB_UPDATE_SNMP_PRIMARY_STATE = "UPDATE ipinterface SET issnmpprimary=? WHERE nodeid=? AND ipaddr=? AND ismanaged!='D'";

    /**
     * The SQL statement used to retrieve all non-deleted/non-forced unamanaged
     * services for a nodeid/ip from the 'ifservices' table.
     */
    private static final String SQL_DB_RETRIEVE_IF_SERVICES = "SELECT serviceid, status FROM ifservices WHERE nodeid=? AND ipaddr=? AND status!='D' AND status!='F'";

    /**
     * The SQL statement which updates the 'isManaged' field in the ipInterface
     * table for a specific node/ipAddr pair
     */
    private static final String SQL_DB_UPDATE_IP_INTERFACE = "UPDATE ipinterface SET ismanaged=? WHERE nodeid=? AND ipaddr=? AND isManaged!='D' AND isManaged!='F'";

    /**
     * The SQL statement which updates the 'status' field in the ifServices
     * table for a specific node/ipAddr pair
     */
    private static final String SQL_DB_UPDATE_ALL_SERVICES_FOR_NIP = "UPDATE ifservices SET status=? WHERE nodeid=? AND ipaddr=? AND status!='D' AND status!='F'";

    private static final String SQL_DB_UPDATE_SERVICE_FOR_NIP = "UPDATE ifservices SET status=? WHERE nodeid=? AND ipaddr=? AND serviceid=? AND status!='D' AND status!='F'";

    //    /**
    //     * The SQL statement used to determine if an IP address is already in the
    //     * ipInterface table and there is known.
    //     */
    //    private static final String RETRIEVE_IPADDR_SQL = 
    //        "SELECT ip.ipaddr " +
    //        "FROM ipinterface as ip " +
    //        "JOIN node as n ON ip.nodeid = n.nodeid " +
    //        "WHERE ip.ipaddr=? " +
    //        "AND ip.ismanaged!='D'" +
    //        "AND n.foreignSource is null";
    //
    //    /**
    //     * The SQL statement used to determine if an IP address is already in the
    //     * ipInterface table and if so what its parent nodeid is.
    //     */
    //    private static final String RETRIEVE_IPADDR_NODEID_SQL = 
    //        "SELECT ip.nodeid " +
    //        "FROM ipinterface as ip " +
    //        "JOIN node as n ON ip.nodeid = n.nodeid " +
    //        "WHERE ip.ipaddr=? " +
    //        "AND ip.ismanaged!='D' " +
    //        "AND n.foreignSource is null";

    /**
     * The SQL statement used to load the currenly defined service table.
     */
    private static final String SVCTBL_LOAD_SQL = "SELECT serviceID, serviceName FROM service";

    /**
     * The SQL statement used to add a new entry into the service table
     */
    private static final String SVCTBL_ADD_SQL = "INSERT INTO service (serviceID, serviceName) VALUES (?,?)";

    /**
     * The SQL statement used to mark all ifservices table entries which refer
     * to the specified serviceId as deleted.
     */
    private static final String DELETE_IFSERVICES_SQL = "update ifservices " + "   set status = 'D' "
            + " where serviceid = ?" + "   and id in (" + "   select svc.id" + "     from ifservices as svc"
            + "     join ipinterface as ip" + "       on (ip.id = svc.ipinterfaceid)" + "     join node as n"
            + "       on (n.nodeid = ip.nodeid)" + "    where n.foreignsource is null)";

    /**
     * The SQL statement used to get the next value for a service identifier.
     * This is a sequence defined in the database.
     */
    private static final String DEFAULT_NEXT_SVC_ID_SQL = "SELECT nextval('serviceNxtId')";

    /**
     * The SQL statement used to determine if an IP address is already in the
     * ipInterface table and if so what its parent nodeid is.
     */
    public static final String RETRIEVE_IPADDR_NODEID_SQL = "SELECT ip.nodeid " + "FROM ipinterface as ip "
            + "JOIN node as n ON ip.nodeid = n.nodeid " + "WHERE ip.ipaddr=? " + "AND ip.ismanaged!='D' "
            + "AND n.foreignSource is null";

    /**
     * The SQL statement used to determine if an IP address is already in the
     * ipInterface table and there is known.
     */
    public static final String RETRIEVE_IPADDR_SQL = "SELECT ip.ipaddr " + "FROM ipinterface as ip "
            + "JOIN node as n ON ip.nodeid = n.nodeid " + "WHERE ip.ipaddr=? " + "AND ip.ismanaged!='D'"
            + "AND n.foreignSource is null";

    private CapsdConfig m_capsdConfig;

    /**
     * The map of service identifiers, mapped by the service id to the service
     * name.
     */
    private Map<Integer, String> m_serviceIdToName = new HashMap<Integer, String>();

    /**
     * The map of service identifiers, mapped by the service name to the service
     * id.
     */
    private Map<String, Integer> m_serviceNameToId = new HashMap<String, Integer>();

    private OpennmsServerConfig m_opennmsServerConfig;

    private CollectdConfig m_collectdConfig;

    private PollerConfig m_pollerConfig;

    private String m_nextSvcIdSql = DEFAULT_NEXT_SVC_ID_SQL;

    private JdbcTemplate m_jdbcTemplate;

    /**
     * <p>Constructor for JdbcCapsdDbSyncer.</p>
     */
    public JdbcCapsdDbSyncer() {

    }

    /**
     * {@inheritDoc}
     *
     * Returns the service ID from the service table that was loaded
     * during class initialization for the specified name.
     */
    @Override
    public Integer getServiceId(String name) {
        Assert.notNull(name, "name argument must not be null");
        return m_serviceNameToId.get(name);
    }

    /**
     * {@inheritDoc}
     *
     * Returns the service name from the service table that was loaded
     * during class initialization for the specified ID.
     */
    @Override
    public String getServiceName(Integer id) {
        Assert.notNull(id, "id argument must not be null");
        return m_serviceIdToName.get(id);
    }

    /* (non-Javadoc)
     * @see org.opennms.netmgt.capsd.CapsdDbSyncerI#syncServices()
     */
    /**
     * <p>syncServices</p>
     */
    @Override
    public void syncServices() {
        m_jdbcTemplate.execute(new ConnectionCallback<Object>() {
            @Override
            public Object doInConnection(Connection con) throws SQLException, DataAccessException {
                syncServices(con);
                return null;
            }

        });
    }

    /**
     * <p>syncServices</p>
     *
     * @param conn a {@link java.sql.Connection} object.
     * @throws java.sql.SQLException if any.
     */
    public void syncServices(Connection conn) throws SQLException {

        List<String> serviceNames = syncServicesTable(conn);

        PreparedStatement delFromIfServicesStmt = null;
        final DBUtils d = new DBUtils(getClass());
        try {

            List<String> protocols = getCapsdConfig().getConfiguredProtocols();

            /*
             * now iterate over the services from the 'service' table
             * and determine if any no longer exist in the list of
             * configured protocols
             */
            for (String service : serviceNames) {
                if (!protocols.contains(service)) {
                    LOG.debug("syncServices: service {} exists in the database but not in the Capsd config file.",
                            service);

                    Integer id = m_serviceNameToId.get(service);

                    // Delete 'ifServices' table entries which refer to the
                    // service
                    LOG.debug("syncServices: deleting all references to service id {} from the IfServices table.",
                            id);
                    delFromIfServicesStmt = conn.prepareStatement(DELETE_IFSERVICES_SQL);
                    d.watch(delFromIfServicesStmt);
                    delFromIfServicesStmt.setInt(1, id.intValue());
                    delFromIfServicesStmt.executeUpdate();
                    LOG.info("syncServices: deleted service id {} for service '{}' from the IfServices table.", id,
                            service);
                }
            }
        } finally {
            d.cleanUp();
        }

    }

    /* (non-Javadoc)
     * @see org.opennms.netmgt.capsd.CapsdDbSyncerI#syncServicesTable()
     */
    /**
     * <p>syncServicesTable</p>
     *
     * @return a {@link java.util.List} object.
     */
    @Override
    public List<String> syncServicesTable() {
        return m_jdbcTemplate.execute(new ConnectionCallback<List<String>>() {

            @Override
            public List<String> doInConnection(Connection con) throws SQLException, DataAccessException {
                return syncServicesTable(con);
            }

        });
    }

    /**
     * <p>syncServicesTable</p>
     *
     * @param conn a {@link java.sql.Connection} object.
     * @return a {@link java.util.List} object.
     * @throws java.sql.SQLException if any.
     */
    public List<String> syncServicesTable(Connection conn) throws SQLException {
        LOG.debug("syncServicesTable: synchronizing services list with the database");

        List<String> serviceNames;
        final DBUtils d = new DBUtils(getClass());

        try {
            PreparedStatement insStmt = conn.prepareStatement(SVCTBL_ADD_SQL);
            d.watch(insStmt);
            PreparedStatement nxtStmt = conn.prepareStatement(getNextSvcIdSql());
            d.watch(nxtStmt);
            PreparedStatement loadStmt = conn.prepareStatement(SVCTBL_LOAD_SQL);
            d.watch(loadStmt);

            // go ahead and load the table first if it can be loaded
            serviceNames = new ArrayList<String>();
            ResultSet rs = loadStmt.executeQuery();
            d.watch(rs);
            while (rs.next()) {
                Integer id = Integer.valueOf(rs.getInt(1));
                String name = rs.getString(2);

                m_serviceIdToName.put(id, name);
                m_serviceNameToId.put(name, id);
                serviceNames.add(name);
            }

            /*
             * now iterate over the configured protocols
             * and make sure that each is represented in the database.
             */
            for (String protocol : getCapsdConfig().getConfiguredProtocols()) {
                LOG.debug("syncServicesTable: checking protocol '{}'.", protocol);
                if (!serviceNames.contains(protocol)) {
                    LOG.debug("syncServicesTable: protocol '{}' is not in the database... adding.", protocol);

                    // get the next identifier
                    rs = nxtStmt.executeQuery();
                    d.watch(rs);
                    rs.next();
                    int id = rs.getInt(1);
                    rs.close();

                    LOG.debug("syncServicesTable: using id {} for protocol '{}'.", id, protocol);

                    insStmt.setInt(1, id);
                    insStmt.setString(2, protocol);
                    insStmt.executeUpdate();

                    m_serviceIdToName.put(id, protocol);
                    m_serviceNameToId.put(protocol, id);

                    serviceNames.add(protocol);

                    LOG.info(
                            "syncServicesTable: added service entry to the database for protocol '{}' with id of {}",
                            protocol, id);
                }
            }
        } finally {
            d.cleanUp();
        }
        return serviceNames;
    }

    /* (non-Javadoc)
     * @see org.opennms.netmgt.capsd.CapsdDbSyncerI#syncManagementState()
     */
    /**
     * <p>syncManagementState</p>
     */
    @Override
    public void syncManagementState() {
        m_jdbcTemplate.execute(new ConnectionCallback<Object>() {

            @Override
            public Object doInConnection(Connection con) throws SQLException, DataAccessException {
                syncManagementState(con);
                return null;
            }

        });
    }

    /**
     * <p>syncManagementState</p>
     *
     * @param conn a {@link java.sql.Connection} object.
     * @throws java.sql.SQLException if any.
     */
    public void syncManagementState(Connection conn) throws SQLException {
        boolean verifyServer = getOpennmsServerConfig().verifyServer();
        String localServer = getOpennmsServerConfig().getServerName();

        LOG.debug("syncManagementState: local server: {} verify server: {}", localServer, verifyServer);

        if (conn == null) {
            LOG.error("CapsdConfigFactory.syncManagementState: Sync failed...must have valid database connection.");
            return;
        }

        // Get default management state.
        //
        String managementPolicy = getCapsdConfig().getConfiguration().getManagementPolicy();
        boolean managedByDefault = (managementPolicy == null || managementPolicy.equalsIgnoreCase("managed"));
        LOG.debug("syncManagementState: managed_by_default: {}", managedByDefault);

        //
        // Retrieve list of interfaces and their managed status from the
        // database
        // NOTE: Interfaces with an 'isManaged' field equal to 'D' (Deleted) or
        // 'F' (Forced Unmanaged) are
        // not eligible to be managed and will not be included in the interfaces
        // retrieved from the database. Likewise, interfaces with IP address of
        // '0.0.0.0' will also be excluded by the SQL query.
        //

        // prepare the SQL statement to query the database
        PreparedStatement ipRetStmt = null;
        final DBUtils d = new DBUtils(getClass());
        List<LightWeightIfEntry> ifList = new ArrayList<LightWeightIfEntry>();

        try {
            if (verifyServer) {
                ipRetStmt = conn.prepareStatement(SQL_DB_RETRIEVE_IP_INTERFACE_IN_LOCAL_SERVER);
                d.watch(ipRetStmt);
                ipRetStmt.setString(1, localServer);
            } else {
                ipRetStmt = conn.prepareStatement(SQL_DB_RETRIEVE_IP_INTERFACE);
                d.watch(ipRetStmt);
            }

            ResultSet result = null;

            // run the statement
            result = ipRetStmt.executeQuery();
            d.watch(result);

            // Build array list of CapsdInterface objects representing each
            // of the interfaces retrieved from the database
            while (result.next()) {
                // Node Id
                int nodeId = result.getInt(1);

                // IP address
                String address = result.getString(2);
                if (address == null) {
                    LOG.warn("invalid ipInterface table entry, no IP address, skipping...");
                    continue;
                }

                // Management State
                char managedState = DbIpInterfaceEntry.STATE_UNKNOWN;
                String str = result.getString(3);
                if (str != null) {
                    managedState = str.charAt(0);
                }

                ifList.add(new LightWeightIfEntry(nodeId, LightWeightIfEntry.NULL_IFINDEX, address, managedState,
                        DbIpInterfaceEntry.SNMP_UNKNOWN, LightWeightIfEntry.NULL_IFTYPE));
            }
        } finally {
            d.cleanUp();
        }

        try {
            // For efficiency, prepare the SQL statements in advance
            PreparedStatement ifUpdateStmt = conn.prepareStatement(SQL_DB_UPDATE_IP_INTERFACE);
            d.watch(ifUpdateStmt);
            PreparedStatement allSvcUpdateStmt = conn.prepareStatement(SQL_DB_UPDATE_ALL_SERVICES_FOR_NIP);
            d.watch(allSvcUpdateStmt);
            PreparedStatement svcRetStmt = conn.prepareStatement(SQL_DB_RETRIEVE_IF_SERVICES);
            d.watch(svcRetStmt);
            PreparedStatement svcUpdateStmt = conn.prepareStatement(SQL_DB_UPDATE_SERVICE_FOR_NIP);
            d.watch(svcUpdateStmt);

            /*
             * Loop through interface list and determine if there has been a
             * change in the managed status of the interface based on the
             * newly loaded package configuration data.
             */
            for (LightWeightIfEntry ifEntry : ifList) {
                String ipaddress = ifEntry.getAddress();

                // Convert to InetAddress object
                InetAddress ifAddress = null;
                ifAddress = InetAddressUtils.addr(ipaddress);
                if (ifAddress == null) {
                    LOG.warn("Failed converting ip address {} to InetAddress.", ipaddress);
                    continue;
                }

                // Check interface address against Capsd config information to
                // determine
                // if interface management state should be managed or unmanaged.
                boolean address_is_unmanaged = getCapsdConfig().isAddressUnmanaged(ifAddress);
                LOG.debug("syncManagementState: {} unmanaged based on capsd config?: {}", ipaddress,
                        address_is_unmanaged);

                if (address_is_unmanaged) {
                    // Interface not managed, check current
                    // management state for this interface.
                    if (ifEntry.getManagementState() != DbIpInterfaceEntry.STATE_UNMANAGED) {
                        // Update management state to unmanaged for the
                        // interface as well as for its services.

                        // Update the 'ipInterface' table
                        ifUpdateStmt.setString(1, new String(new char[] { DbIpInterfaceEntry.STATE_UNMANAGED }));
                        ifUpdateStmt.setInt(2, ifEntry.getNodeId());
                        ifUpdateStmt.setString(3, ipaddress);
                        ifUpdateStmt.executeUpdate();

                        // Update the 'ifServices' table
                        allSvcUpdateStmt.setString(1, new String(new char[] { DbIfServiceEntry.STATUS_UNMANAGED }));
                        allSvcUpdateStmt.setInt(2, ifEntry.getNodeId());
                        allSvcUpdateStmt.setString(3, ipaddress);
                        allSvcUpdateStmt.executeUpdate();

                        LOG.debug("syncManagementState: update completed for node/interface: {}/{} to unmanaged",
                                ifEntry.getNodeId(), ipaddress);
                    }
                } else {
                    /*
                     * Interface should be managed - check the status against
                     * poller config to see if interface will be polled
                     * 
                     * NOTE: Try to avoid re-evaluating the ip against filters
                     * for each service, try to get the first package here and
                     * for that for service evaluation
                     */
                    final PollerConfig pollerConfig = getPollerConfig();
                    pollerConfig.getReadLock().lock();
                    try {
                        org.opennms.netmgt.config.poller.Package ipPkg = pollerConfig
                                .getFirstPackageMatch(ipaddress);
                        boolean ipToBePolled = false;
                        if (ipPkg != null) {
                            ipToBePolled = true;
                        }

                        LOG.debug("syncManagementState: {} to be polled based on poller config?: {}", ipaddress,
                                ipToBePolled);

                        if ((ifEntry.getManagementState() == DbIpInterfaceEntry.STATE_MANAGED && ipToBePolled)
                                || (ifEntry.getManagementState() == DbIpInterfaceEntry.STATE_NOT_POLLED
                                        && !ipToBePolled)) {
                            // current status is right
                            LOG.debug("syncManagementState: {} - no change in status", ipaddress);
                        } else {
                            if (ipToBePolled) {
                                ifUpdateStmt.setString(1,
                                        new String(new char[] { DbIpInterfaceEntry.STATE_MANAGED }));
                            } else {
                                ifUpdateStmt.setString(1,
                                        new String(new char[] { DbIpInterfaceEntry.STATE_NOT_POLLED }));
                            }

                            ifUpdateStmt.setInt(2, ifEntry.getNodeId());
                            ifUpdateStmt.setString(3, ipaddress);
                            ifUpdateStmt.executeUpdate();

                            LOG.debug("syncManagementState: update completed for node/interface: {}/{}",
                                    ifEntry.getNodeId(), ipaddress);
                        }

                        // get services for this nodeid/ip and update
                        svcRetStmt.setInt(1, ifEntry.getNodeId());
                        svcRetStmt.setString(2, ipaddress);

                        ResultSet svcRS = svcRetStmt.executeQuery();
                        d.watch(svcRS);
                        while (svcRS.next()) {
                            int svcId = svcRS.getInt(1);

                            char svcStatus = DbIfServiceEntry.STATUS_UNKNOWN;
                            String str = svcRS.getString(2);
                            if (str != null) {
                                svcStatus = str.charAt(0);
                            }

                            String svcName = getServiceName(svcId);
                            /*
                             * try the first package that had the ip first, if
                             * service is not enabled, try all packages
                             */
                            char oldStatus = svcStatus;
                            char newStatus = 'U';
                            boolean svcToBePolledLocally = isServicePolledLocally(ipaddress, svcName, ipPkg);
                            boolean svcToBePolledRemotely = isServicePolled(ipaddress, svcName, ipPkg);

                            LOG.debug("syncManagementState: {}/{} to be polled based on poller config?: {}",
                                    ipaddress, svcName, svcToBePolledLocally);

                            if ((svcStatus == DbIfServiceEntry.STATUS_ACTIVE && svcToBePolledLocally)
                                    || (svcStatus == DbIfServiceEntry.STATUS_NOT_POLLED && !ipToBePolled)) {
                                // current status is right
                                LOG.debug("syncManagementState: {}/{}/{} status = {} - no change in status",
                                        ifEntry.getNodeId(), ipaddress, svcName, svcStatus);
                            } else {
                                // Update the 'ifServices' table
                                if (svcStatus == DbIfServiceEntry.STATUS_SUSPEND && svcToBePolledLocally) {
                                    svcUpdateStmt.setString(1,
                                            new String(new char[] { DbIfServiceEntry.STATUS_FORCED }));
                                    newStatus = 'F';
                                } else if (svcToBePolledLocally) {
                                    svcUpdateStmt.setString(1,
                                            new String(new char[] { DbIfServiceEntry.STATUS_ACTIVE }));
                                    newStatus = 'A';
                                } else if (svcToBePolledRemotely) {
                                    svcUpdateStmt.setString(1,
                                            new String(new char[] { DbIfServiceEntry.STATUS_REMOTE }));
                                    newStatus = 'X';
                                } else {
                                    svcUpdateStmt.setString(1,
                                            new String(new char[] { DbIfServiceEntry.STATUS_NOT_POLLED }));
                                    newStatus = 'N';
                                }
                                svcUpdateStmt.setInt(2, ifEntry.getNodeId());
                                svcUpdateStmt.setString(3, ipaddress);
                                svcUpdateStmt.setInt(4, svcId);
                                svcUpdateStmt.executeUpdate();

                                LOG.debug(
                                        "syncManagementState: update completed for node/interface/svc: {}/{}/{} status changed from {} to {}",
                                        ifEntry.getNodeId(), ipaddress, svcName, oldStatus, newStatus);
                            }

                        } // end ifservices result
                    } finally {
                        pollerConfig.getReadLock().unlock();
                    }
                } // interface managed
            } // end while
        } finally {
            d.cleanUp();
        }
    }

    private boolean isServicePolled(final String ifAddr, final String svcName,
            final org.opennms.netmgt.config.poller.Package ipPkg) {
        boolean svcToBePolled = false;
        if (ipPkg != null) {
            final PollerConfig pollerConfig = getPollerConfig();
            pollerConfig.getReadLock().lock();
            try {
                svcToBePolled = pollerConfig.isPolled(svcName, ipPkg);
                if (!svcToBePolled)
                    svcToBePolled = pollerConfig.isPolled(ifAddr, svcName);
            } finally {
                pollerConfig.getReadLock().unlock();
            }
        }
        return svcToBePolled;
    }

    private boolean isServicePolledLocally(final String ifAddr, final String svcName,
            final org.opennms.netmgt.config.poller.Package ipPkg) {
        boolean svcToBePolled = false;
        if (ipPkg != null && !ipPkg.getRemote()) {
            final PollerConfig pollerConfig = getPollerConfig();
            pollerConfig.getReadLock().lock();
            try {
                svcToBePolled = pollerConfig.isPolled(svcName, ipPkg);
                if (!svcToBePolled)
                    svcToBePolled = pollerConfig.isPolledLocally(ifAddr, svcName);
            } finally {
                pollerConfig.getReadLock().unlock();
            }
        }
        return svcToBePolled;
    }

    /* (non-Javadoc)
     * @see org.opennms.netmgt.capsd.CapsdDbSyncerI#syncSnmpPrimaryState()
     */
    /**
     * <p>syncSnmpPrimaryState</p>
     */
    @Override
    public void syncSnmpPrimaryState() {
        m_jdbcTemplate.execute(new ConnectionCallback<Object>() {

            @Override
            public Object doInConnection(Connection con) throws SQLException, DataAccessException {
                syncSnmpPrimaryState(con);
                return null;
            }

        });
    }

    /**
     * <p>syncSnmpPrimaryState</p>
     *
     * @param conn a {@link java.sql.Connection} object.
     * @throws java.sql.SQLException if any.
     */
    public synchronized void syncSnmpPrimaryState(Connection conn) throws SQLException {
        if (conn == null) {
            throw new IllegalArgumentException("Sync failed...must have valid database connection.");
        }

        /*
         * Retrieve all non-deleted SNMP-supporting IP interfaces from the
         * ipInterface table and build a map of nodes to interface entry list
         */
        LOG.debug("syncSnmpPrimaryState: building map of nodes to interfaces...");

        Map<Integer, List<LightWeightIfEntry>> nodes = new HashMap<Integer, List<LightWeightIfEntry>>();

        final DBUtils d = new DBUtils(getClass());
        try {
            // prepare the SQL statement to query the database
            PreparedStatement ipRetStmt = conn.prepareStatement(SQL_DB_RETRIEVE_SNMP_IP_INTERFACES);
            d.watch(ipRetStmt);
            ResultSet result = ipRetStmt.executeQuery();
            d.watch(result);

            // Iterate over result set and build map of interface
            // entries keyed by node id.
            List<LightWeightIfEntry> ifList = new ArrayList<LightWeightIfEntry>();
            while (result.next()) {
                // Node Id
                int nodeId = result.getInt(1);

                // IP address
                String address = result.getString(2);
                if (address == null) {
                    LOG.warn("invalid ipInterface table entry, no IP address, skipping...");
                    continue;
                }

                // ifIndex
                int ifIndex = result.getInt(6);
                if (result.wasNull()) {
                    LOG.debug("ipInterface table entry for address {} does not have a valid ifIndex ", address);
                    ifIndex = LightWeightIfEntry.NULL_IFINDEX;
                } else if (ifIndex < 1) {
                    if (ifIndex == CapsdConfig.LAME_SNMP_HOST_IFINDEX) {
                        LOG.debug("Using ifIndex = {} for address {}", CapsdConfig.LAME_SNMP_HOST_IFINDEX, address);
                    } else {
                        LOG.debug("ipInterface table entry for address {} does not have a valid ifIndex ", address);
                        ifIndex = LightWeightIfEntry.NULL_IFINDEX;
                    }
                }

                // Primary SNMP State
                char primarySnmpState = DbIpInterfaceEntry.SNMP_UNKNOWN;
                String str = result.getString(4);
                if (str != null) {
                    primarySnmpState = str.charAt(0);
                }

                // ifType
                int ifType = result.getInt(5);
                if (result.wasNull()) {
                    LOG.debug("snmpInterface table entry for address {} does not have a valid ifType", address);
                    ifType = LightWeightIfEntry.NULL_IFTYPE;
                }

                // New node or existing node?
                ifList = nodes.get(Integer.valueOf(nodeId));
                if (ifList == null) {
                    // Create new interface entry list
                    ifList = new ArrayList<LightWeightIfEntry>();
                    ifList.add(new LightWeightIfEntry(nodeId, ifIndex, address, DbIpInterfaceEntry.STATE_UNKNOWN,
                            primarySnmpState, ifType));

                    // Add interface entry list to the map
                    nodes.put(nodeId, ifList);
                } else {
                    // Just add the current interface to the
                    // node's interface list
                    ifList.add(new LightWeightIfEntry(nodeId, ifIndex, address, DbIpInterfaceEntry.STATE_UNKNOWN,
                            primarySnmpState, ifType));
                }
            }
        } finally {
            d.cleanUp();
        }

        /*
         * Iterate over the nodes in the map and determine what the primary
         * SNMP interface for each node should be. Keep track of those
         * interfaces whose primary SNMP interface state has changed so that
         * the database can be updated accordingly.
         */
        LOG.debug(
                "syncSnmpPrimaryState: iterating over nodes in map and checking primary SNMP interface, node count: {}",
                nodes.size());
        Iterator<Integer> niter = nodes.keySet().iterator();
        while (niter.hasNext()) {
            // Get the nodeid (key)
            Integer nId = niter.next();
            LOG.debug("building SNMP address list for node {}", nId);

            // Lookup the interface list (value)
            List<LightWeightIfEntry> ifEntries = nodes.get(nId);

            /*
             * From the interface entries build a list of InetAddress objects
             * eligible to be the primary SNMP interface for the node, and a
             * list of loopback InetAddress objects eligible to be the primary
             * SNMP interface for the node.
             */
            List<InetAddress> addressList = new ArrayList<InetAddress>();
            List<InetAddress> lbAddressList = new ArrayList<InetAddress>();
            for (LightWeightIfEntry lwIf : ifEntries) {
                /*
                 * Skip interfaces which do not have a valid (non-null) ifIndex
                 * as they are not eligible to be the primary SNMP interface
                 */
                if (lwIf.getIfIndex() == LightWeightIfEntry.NULL_IFINDEX) {
                    LOG.debug("skipping address {}: does not have a valid ifIndex.", lwIf.getAddress());
                    continue;
                }

                InetAddress addr = InetAddressUtils.addr(lwIf.getAddress());
                addressList.add(addr);
                if (lwIf.getIfType() == LightWeightIfEntry.LOOPBACK_IFTYPE) {
                    lbAddressList.add(addr);
                }
            }

            /*
             * Determine primary SNMP interface from the lists of possible addresses
             * in this order: loopback interfaces in collectd-configuration.xml,
             * other interfaces in collectd-configuration.xml, loopback interfaces in
             * the database, other interfaces in the database.
             */
            boolean strict = true;
            InetAddress primarySnmpIf = null;
            String psiType = null;
            if (lbAddressList != null) {
                primarySnmpIf = getCapsdConfig().determinePrimarySnmpInterface(lbAddressList, strict);
                psiType = ConfigFileConstants.getFileName(ConfigFileConstants.COLLECTD_CONFIG_FILE_NAME)
                        + " loopback addresses";
            }
            if (primarySnmpIf == null) {
                primarySnmpIf = getCapsdConfig().determinePrimarySnmpInterface(addressList, strict);
                psiType = ConfigFileConstants.getFileName(ConfigFileConstants.COLLECTD_CONFIG_FILE_NAME)
                        + " addresses";
            }
            strict = false;
            if ((primarySnmpIf == null) && (lbAddressList != null)) {
                primarySnmpIf = getCapsdConfig().determinePrimarySnmpInterface(lbAddressList, strict);
                psiType = "DB loopback addresses";
            }
            if (primarySnmpIf == null) {
                primarySnmpIf = getCapsdConfig().determinePrimarySnmpInterface(addressList, strict);
                psiType = "DB addresses";
            }

            if (LOG.isDebugEnabled()) {
                if (primarySnmpIf == null) {
                    LOG.debug("syncSnmpPrimaryState: No primary SNMP interface found for node {}", nId);
                } else {
                    LOG.debug("syncSnmpPrimaryState: primary SNMP interface for node {} is: {}, selected from {}",
                            nId, primarySnmpIf, psiType);
                }
            }

            /*
             * Iterate back over interface list and update primary SNMP
             * iinterface state for this node...if the primary SNMP interface
             * state has changed, update the database to reflect the new state.
             */
            for (LightWeightIfEntry lwIf : ifEntries) {
                if (lwIf.getIfIndex() == LightWeightIfEntry.NULL_IFINDEX) {
                    lwIf.setSnmpPrimaryState(DbIpInterfaceEntry.SNMP_NOT_ELIGIBLE);
                } else if (primarySnmpIf == null
                        || !lwIf.getAddress().equals(InetAddressUtils.str(primarySnmpIf))) {
                    if (getCollectdConfig().isServiceCollectionEnabled(lwIf.getAddress(), "SNMP")) {
                        lwIf.setSnmpPrimaryState(DbIpInterfaceEntry.SNMP_SECONDARY);
                    } else {
                        lwIf.setSnmpPrimaryState(DbIpInterfaceEntry.SNMP_NOT_ELIGIBLE);
                    }
                } else {
                    lwIf.setSnmpPrimaryState(DbIpInterfaceEntry.SNMP_PRIMARY);
                }

                // Has SNMP primary state changed?
                if (lwIf.hasSnmpPrimaryStateChanged()) {
                    LOG.debug("syncSnmpPrimaryState: updating {}/{}, marking with state: {}", lwIf.getNodeId(),
                            lwIf.getAddress(), lwIf.getSnmpPrimaryState());

                    try {
                        // prepare the SQL statement to query the database
                        PreparedStatement updateStmt = conn.prepareStatement(SQL_DB_UPDATE_SNMP_PRIMARY_STATE);
                        d.watch(updateStmt);
                        updateStmt.setString(1, new String(new char[] { lwIf.getSnmpPrimaryState() }));
                        updateStmt.setInt(2, lwIf.getNodeId());
                        updateStmt.setString(3, lwIf.getAddress());

                        updateStmt.executeUpdate();
                    } finally {
                        d.cleanUp();
                    }
                }
            }
        }

        LOG.debug("syncSnmpPrimaryState: sync completed.");
    }

    /**
     * <p>getCapsdConfig</p>
     *
     * @return a {@link org.opennms.netmgt.config.CapsdConfig} object.
     */
    public CapsdConfig getCapsdConfig() {
        return m_capsdConfig;
    }

    /**
     * <p>setCapsdConfig</p>
     *
     * @param capsdConfig a {@link org.opennms.netmgt.config.CapsdConfig} object.
     */
    public void setCapsdConfig(CapsdConfig capsdConfig) {
        m_capsdConfig = capsdConfig;
    }

    /**
     * <p>getOpennmsServerConfig</p>
     *
     * @return a {@link org.opennms.netmgt.config.OpennmsServerConfigFactory} object.
     */
    public OpennmsServerConfig getOpennmsServerConfig() {
        return m_opennmsServerConfig;
    }

    /**
     * <p>setOpennmsServerConfig</p>
     *
     * @param serverConfigFactory a {@link org.opennms.netmgt.config.OpennmsServerConfigFactory} object.
     */
    public void setOpennmsServerConfig(OpennmsServerConfig serverConfigFactory) {
        m_opennmsServerConfig = serverConfigFactory;
    }

    /**
     * <p>getPollerConfig</p>
     *
     * @return a {@link org.opennms.netmgt.config.PollerConfig} object.
     */
    public PollerConfig getPollerConfig() {
        return m_pollerConfig;
    }

    /**
     * <p>setPollerConfig</p>
     *
     * @param pollerConfig a {@link org.opennms.netmgt.config.PollerConfig} object.
     */
    public void setPollerConfig(PollerConfig pollerConfig) {
        m_pollerConfig = pollerConfig;
    }

    /**
     * <p>getCollectdConfig</p>
     *
     * @return a {@link org.opennms.netmgt.config.CollectdConfigFactory} object.
     */
    public CollectdConfig getCollectdConfig() {
        return m_collectdConfig;
    }

    /**
     * <p>setCollectdConfig</p>
     *
     * @param collectdConfigFactory a {@link org.opennms.netmgt.config.CollectdConfigFactory} object.
     */
    public void setCollectdConfig(CollectdConfig collectdConfigFactory) {
        m_collectdConfig = collectdConfigFactory;
    }

    /**
     * <p>afterPropertiesSet</p>
     */

    public void afterPropertiesSet() {
        Assert.state(m_jdbcTemplate != null, "property jdbcTemplate must be set to a non-null value");
        Assert.state(m_opennmsServerConfig != null, "property opennmsServerConfig must be set to a non-null value");
        Assert.state(m_pollerConfig != null, "property pollerConfig must be set to a non-null value");
        Assert.state(m_collectdConfig != null, "property collectdConfig must be set to a non-null value");
    }

    /* (non-Javadoc)
     * @see org.opennms.netmgt.capsd.CapsdDbSyncerI#getInterfaceDbNodeId(java.sql.Connection, java.net.InetAddress, int)
     */
    /**
     * <p>getInterfaceDbNodeId</p>
     *
     * @param dbConn a {@link java.sql.Connection} object.
     * @param ifAddress a {@link java.net.InetAddress} object.
     * @param ifIndex a int.
     * @return a int.
     * @throws java.sql.SQLException if any.
     */
    public int getInterfaceDbNodeId(Connection dbConn, InetAddress ifAddress, int ifIndex) throws SQLException {
        LOG.debug("getInterfaceDbNodeId: attempting to lookup interface {}/ifindex: {} in the database.",
                InetAddressUtils.str(ifAddress), ifIndex);

        // Set connection as read-only
        // dbConn.setReadOnly(true);

        StringBuffer qs = new StringBuffer(RETRIEVE_IPADDR_NODEID_SQL);
        if (ifIndex != -1) {
            qs.append(" AND ifindex=?");
        }

        int nodeid = -1;

        final DBUtils d = new DBUtils(getClass());
        try {
            PreparedStatement s = dbConn.prepareStatement(qs.toString());
            d.watch(s);
            s.setString(1, InetAddressUtils.str(ifAddress));

            if (ifIndex != -1) {
                s.setInt(2, ifIndex);
            }

            ResultSet rs = s.executeQuery();
            d.watch(rs);
            if (rs.next()) {
                nodeid = rs.getInt(1);
            }
        } finally {
            d.cleanUp();
        }

        return nodeid;
    }

    /* (non-Javadoc)
      * @see org.opennms.netmgt.capsd.CapsdDbSyncerI#isInterfaceInDB(java.sql.Connection, java.net.InetAddress)
      */
    /** {@inheritDoc} */
    @Override
    public boolean isInterfaceInDB(final InetAddress ifAddress) {
        return m_jdbcTemplate.execute(new ConnectionCallback<Boolean>() {

            @Override
            public Boolean doInConnection(Connection con) throws SQLException, DataAccessException {
                return isInterfaceInDB(con, ifAddress) ? Boolean.TRUE : Boolean.FALSE;
            }

        }).booleanValue();
    }

    /** {@inheritDoc} */
    @Override
    public boolean isInterfaceInDB(Connection dbConn, InetAddress ifAddress) throws SQLException {
        boolean result = false;

        LOG.debug("isInterfaceInDB: attempting to lookup interface {} in the database.",
                InetAddressUtils.str(ifAddress));

        // Set connection as read-only
        //
        // dbConn.setReadOnly(true);

        ResultSet rs = null;
        final DBUtils d = new DBUtils(getClass());

        try {
            PreparedStatement s = dbConn.prepareStatement(RETRIEVE_IPADDR_SQL);
            d.watch(s);
            s.setString(1, InetAddressUtils.str(ifAddress));

            rs = s.executeQuery();
            d.watch(rs);
            result = rs.next();
        } finally {
            d.cleanUp();
        }

        return result;
    }

    /**
     * <p>setNextSvcIdSql</p>
     *
     * @param nextSvcIdSql a {@link String} object.
     */
    public void setNextSvcIdSql(String nextSvcIdSql) {
        m_nextSvcIdSql = nextSvcIdSql;
    }

    /**
     * <p>getNextSvcIdSql</p>
     *
     * @return a {@link String} object.
     */
    public String getNextSvcIdSql() {
        return m_nextSvcIdSql;
    }

    /**
     * <p>setJdbcTemplate</p>
     *
     * @param jdbcTemplate a {@link org.springframework.jdbc.core.JdbcTemplate} object.
     */
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        m_jdbcTemplate = jdbcTemplate;
    }

}