org.opendaylight.defense4all.core.impl.DFMgmtPointImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.opendaylight.defense4all.core.impl.DFMgmtPointImpl.java

Source

/**
 * Copyright (c) <2013> <Radware Ltd.> and others.  All rights reserved.
 *
 * This program and the accompanying materials are made available under the terms of the Eclipse Public License
 * v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html
 * @author Gera Goft 
 * @author Konstantin Pozdeev
 * @version 0.1
 */

package org.opendaylight.defense4all.core.impl;

import java.io.IOException;
import java.io.InputStream;
import java.lang.IllegalArgumentException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import javax.transaction.NotSupportedException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.opendaylight.defense4all.core.AMS;
import org.opendaylight.defense4all.core.Attack;
import org.opendaylight.defense4all.core.DFAppRoot;
import org.opendaylight.defense4all.core.DFDetector;
import org.opendaylight.defense4all.core.DFMgmtPoint;
import org.opendaylight.defense4all.core.Detector;
import org.opendaylight.defense4all.core.DetectorInfo;
import org.opendaylight.defense4all.core.NetNode;
import org.opendaylight.defense4all.core.OFC;
import org.opendaylight.defense4all.core.PN;
import org.opendaylight.defense4all.core.PN.OperationalStatus;
import org.opendaylight.defense4all.core.PN.StatsCollectionStatus;
import org.opendaylight.defense4all.core.interactionstructures.PNStatReport;
import org.opendaylight.defense4all.framework.core.ExceptionControlApp;
import org.opendaylight.defense4all.framework.core.HealthTracker;
import org.opendaylight.defense4all.framework.core.FrameworkMain.ResetLevel;

/** 
 *   TODO: description - app focal point. orchestrates start, stop. 
 */

public class DFMgmtPointImpl extends DFAppCoreModule implements DFMgmtPoint {

    /**
     * DFMgmtPoint Repo types
     */
    public static final int TYPE_INVALID = -1;
    public static final int TYPE_RESERVED = 0;

    private static Log log = LogFactory.getLog(DFMgmtPointImpl.class);

    public DFMgmtPointImpl() {
        super();
    }

    /**
     * Initialize after construction. Look for an OFC to add - first check in repo if one has already been set in 
     * previous life cycle. If not, check if one has been set through Spring.
     * @throws Exception 
     * @throws exception_type circumstances description 
     */
    public void init() throws ExceptionControlApp {

        super.init();

        log.info("DefenseFlow management failed in initialize.");

        /* OFC related initializations. */
        List<String> ofcKeys = null;
        try {
            ofcKeys = dfAppRoot.oFCsRepo.getKeys();
        } catch (Throwable e) {
            log.error("Failed to get keys from oFCsRepo ", e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow management failed in initialize.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get keys from oFCsRepo ", e);
        }
        if (ofcKeys == null) {
            log.error("Invalid null oFCsRepo");
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow management failed in initialize.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE);
            throw new ExceptionControlApp("Invalid null oFCsRepo");
        }

        if (ofcKeys.size() > 0) {
            try {
                addOFC(ofcKeys.get(0));
            } catch (Throwable e) {
                // TODO Currently Ignore, but need to account for regular init vs. reset init
                log.error("Failed to re-add OFC " + ofcKeys.get(0), e);
            }
        }

        /* AMS related initializations. */
        List<String> amsKeys;
        try {
            amsKeys = dfAppRoot.amsRepo.getKeys();
        } catch (Exception e1) {
            log.error("Failed to get keys from amsRepo ", e1);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow management failed in initialize.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get keys from amsRepo ", e1);
        }
        if (amsKeys == null) {
            log.debug("Invalid null amsRepo");
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow management failed in initialize.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE);
            throw new ExceptionControlApp("Invalid null oFCsRepo");
        }

        for (int i = 0; i < amsKeys.size(); i++) // Re-register all AMSs if not there yet
            addAMS(amsKeys.get(i));

        /* NetNode related initializations. */
        List<String> netNodeKeys;
        try {
            netNodeKeys = dfAppRoot.netNodesRepo.getKeys();
        } catch (Throwable e3) {
            log.error("Failed to get keys from amsRepo ", e3);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow management failed in initialize.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get keys from netNodesRepo ", e3);
        }
        if (netNodeKeys == null) {
            log.debug("Invalid null netNodesRepo");
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow management failed in initialize.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE);
            throw new ExceptionControlApp("Invalid null netNodesRepo");
        }

        /* Re-register all NetNodes if not there yet, except those marked as removed. */
        for (String netNodeLabel : netNodeKeys) {
            try {
                if (NetNode.isRemoved(netNodeLabel))
                    dfAppRoot.netNodesRepo.deleteRow(netNodeLabel);
                else
                    addNetNode(netNodeLabel);
            } catch (Throwable e) {
                continue;
                /* Ignore */}
        }

        /* PN related initializations. */
        List<String> pnKeys;
        try {
            pnKeys = dfAppRoot.pNsRepo.getKeys();
        } catch (Throwable e5) {
            log.error("Failed to get keys from pNsRepo ", e5);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow management failed in initialize.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get keys from pNsRepo ", e5);
        }
        if (pnKeys == null) {
            log.debug("Invalid null pNsRepo");
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow management failed in initialize.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE);
            throw new ExceptionControlApp("Invalid null oFCsRepo");
        }

        for (int i = 0; i < pnKeys.size(); i++) { // Re-register all protected networks in controller if not there yet
            try {
                addPN(pnKeys.get(i));
            } catch (Throwable e) {
                log.error("Failed to re-add PN " + pnKeys.get(i), e);
            }
        }

        try {
            if (pnKeys.size() == 0) { // Add PN if one set through properties file. Next time PN will be in repo.
                loadAndSetPNsFromPropsFile();
            }
        } catch (Throwable e6) {
            log.error("Failed to create PN from default parameters ", e6);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow management failed in initialize.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to create PN from default parameters ", e6);
        }
    }

    /**
     * Cleanup before shutdown
     * @throws exception_type circumstances description 
     */
    public void finit() {
        log.info("DFMgmtPoint is stopping.");
        super.finit();
    }

    /** Reset 
     * @throws ExceptionControlApp */
    public void reset(ResetLevel resetLevel) throws ExceptionControlApp {

        log.info("DFMgmtPoint is resetting to level " + resetLevel);
        super.reset(resetLevel);
        resetPns(resetLevel);
    }

    protected void loadAndSetPNsFromPropsFile() throws Exception {

        // Read properties file with default PNs attributes
        Properties propsFromFile = new Properties();
        Properties pnFields = new Properties();
        InputStream is = DFMgmtPointImpl.class.getClassLoader().getResourceAsStream("pns.properties");
        try {
            propsFromFile.load(is);
        } catch (IOException ioExc) {
            log.warn("DF failed to instantiate PN from properties file.", ioExc);
            try {
                is.close();
            } catch (IOException e) {
                /* Ignore */}
            return;
        }
        try {
            is.close();
        } catch (IOException e) {
            /* Ignore */}

        String pnLabels = propsFromFile.getProperty("PN.pns");
        if (pnLabels == null || pnLabels.isEmpty())
            return;

        PN defaultPN = new PN();
        Set<String> pnKeySet = defaultPN.toRow().keySet();
        Properties pnProps;
        Properties pnAmsProps;
        Set<Object> propsFromFileKeySet;
        String propFromFileKey;
        String pnAttributeKey;
        String[] split;
        String propFromFile;
        int amsPropertyPrefixLen = PN.AMS_PROPERTY_PREFIX.length();
        List<String> netNodes = new ArrayList<String>();

        /* Set each property for relevant pn in the props file - either into its attribute or
         * into the props attribute (can be in case properties of PN sub-classes are set) */
        String[] pnLabelsSplit;
        try {
            pnLabelsSplit = pnLabels.split(",");
        } catch (Exception e) {
            log.error("Invalid lead line(PN.pns) in pns.properties file", e);
            //fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DF failed to instantiate PN from properties file.");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Invalid lead line(PN.pns) in pns.properties file", e);
        }

        for (String pnLabel : pnLabelsSplit) {

            try {
                pnProps = new Properties();
                pnAmsProps = new Properties();
                propsFromFileKeySet = propsFromFile.keySet();
                for (Object keyObject : propsFromFileKeySet) {
                    propFromFileKey = (String) keyObject;
                    split = propFromFileKey.split("\\.");
                    if (split.length < 3)
                        continue;
                    if (!split[1].equals(pnLabel))
                        continue;
                    pnAttributeKey = split[2];
                    propFromFile = propsFromFile.getProperty(propFromFileKey);
                    if (pnKeySet.contains(pnAttributeKey))
                        pnFields.setProperty(pnAttributeKey, propFromFile);
                    else if (pnAttributeKey.startsWith(PN.AMS_PROPERTY_PREFIX))
                        pnAmsProps.setProperty(pnAttributeKey.substring(amsPropertyPrefixLen), propFromFile);
                    else if (pnAttributeKey.startsWith(PN.NETNODE_PREFIX))
                        netNodes.add(propFromFile);
                    else
                        pnProps.setProperty(pnAttributeKey, propFromFile);
                }

                // construct new PN from hash of attributes
                PN pn = new PN(pnFields, pnProps, pnAmsProps, netNodes);
                // Set type of detection from registered detector
                Detector pnDetector = dfAppRootFullImpl.detectorMgrImpl.getDetector(pn.getDetectorLabel());
                if (pnDetector != null) {
                    pn.setOfBasedDetection(pnDetector.getDetectorInfo().getOfBasedDetector());
                }
                addPN(pn);
            } catch (Exception e) {
                log.error("Failed to create PN from pns.properties file", e);
                //fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DF failed to instantiate PN from properties file.");
                fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
                continue;
            }
        }
    }

    protected void resetPns(ResetLevel resetLevel) throws ExceptionControlApp {

        Hashtable<String, Hashtable<String, Object>> pnTable;
        try {
            pnTable = dfAppRootFullImpl.pNsRepo.getTable();
        } catch (Throwable e) {
            log.error("Failed to get pNsRepo table", e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get pNsRepo table", e);
        }
        Set<Entry<String, Hashtable<String, Object>>> pnTableEntrySet = pnTable.entrySet();
        if (pnTableEntrySet == null)
            return;

        Iterator<Map.Entry<String, Hashtable<String, Object>>> iter = pnTableEntrySet.iterator();
        Map.Entry<String, Hashtable<String, Object>> entry;
        String pnKey;
        PN pn;

        while (iter.hasNext()) {

            try {
                entry = iter.next();
                pnKey = entry.getKey();
            } catch (Exception e1) {
                log.error("Invalid entry in pNsRepo table", e1);
                fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
                continue;
            }
            try {
                pn = new PN(entry.getValue());
            } catch (ExceptionControlApp e) {
                continue;
                /* Ignore */}

            pn.averageStr = "";
            pn.latestRateStr = "";
            pn.latestRateTime = 0;
            pn.attackSuspicions = "";
            pn.statsCollectionStatus = StatsCollectionStatus.INVALID;
            if (resetLevel == ResetLevel.dynamic) {
                pn.baselineStr = "";
                pn.baselinesTime = 0;
            }

            try {
                dfAppRootFullImpl.pNsRepo.setRow(pnKey, pn.toRow());
            } catch (Throwable e) {
                log.error("Failed to set pnRow in pNsRepo table " + pnKey, e);
                fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
                continue;
            }
        }
    }

    protected void removeCanceledPns() throws ExceptionControlApp {

        List<String> pnkeys;
        try {
            pnkeys = dfAppRootFullImpl.pNsRepo.getKeys();
            if (pnkeys == null)
                return;
        } catch (Throwable e) {
            log.error("Failed to get pNsRepo keys", e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MODERATE_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get pNsRepo keys", e);
        }

        for (String pnkey : pnkeys) {
            try {
                removePnIfCanceled(pnkey);
            } catch (Throwable e1) {
                continue;
            }
        }
    }

    protected void removePnIfCanceled(String pnkey) throws ExceptionControlApp {

        try {
            Object obj = dfAppRootFullImpl.pNsRepo.getCellValue(pnkey, PN.OPERATIONAL_STATUS);
            OperationalStatus operationalStatus = OperationalStatus.INVALID;
            if (obj != null)
                operationalStatus = OperationalStatus.valueOf((String) obj);
            if (operationalStatus == OperationalStatus.CANCELED)
                dfAppRootFullImpl.pNsRepo.deleteRow(pnkey);
        } catch (Throwable e) {
            log.error("Failed to delete pnRow in pNsRepo table " + pnkey, e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to remove canceled PN " + pnkey, e);
        }
    }

    /**
     * Add OFC according to its purpose - collection or dvsn (the same OFC can be set for both). Ignore if
     * already set (currently we accept only one).
     * @param param_name param description
     * @return return description
     * @throws ExceptionControlApp 
     * @throws exception_type circumstances description 
     */
    @Override
    public void addOFC(OFC ofc) throws ExceptionControlApp, IllegalArgumentException {

        try {
            ofc.validate();
        } catch (Exception e1) {
            throw new IllegalArgumentException(e1);
        }

        List<String> keys;

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DefenseFlow adding a controller. ");
        try {
            keys = dfAppRootFullImpl.oFCsRepo.getKeys();
        } catch (Throwable e) {
            log.error("Failed to get keys from oFCsRepo.", e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add controller " + ofc.hostname);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get keys from oFCsRepo.", e);
        }
        if (keys.size() != 0) {
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow currently supports only one controller. Controller "
                    + ofc.hostname + " was not added.");
            return; // Already have a set OFC. Currently there can be only one OFC in the system.
        }
        try {
            dfAppRootFullImpl.oFCsRepo.setRow(ofc.hostname, ofc.toRow()); // Record ofc in ofcs repo.      
        } catch (Throwable e) {
            log.error("Failed to set row to oFCsRepo. " + ofc.hostname, e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add controller " + ofc.hostname);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to set row to oFCsRepo. " + ofc.hostname, e);
        }
        try {
            addOFC(ofc.hostname); // Notify relevant DF modules. 
        } catch (Throwable e) {
            log.error("Failed to add OFC " + ofc.hostname, e);
            try {
                dfAppRootFullImpl.oFCsRepo.deleteRow(ofc.hostname); // Rollback
            } finally {
                throw new ExceptionControlApp("Failed to add OFC " + ofc.hostname, e);
            }
        }
    }

    /**
    * Add OFC that has already been recorded in ofcs repo. Add according to its purpose - collection or dvsn 
    * (the same OFC can be set for both). Ignore if already set (currently we accept only one).
    * @param param_name param description
    * @return return description
    * @throws exception_type circumstances description 
    */
    protected void addOFC(String ofcKey) throws ExceptionControlApp {

        Boolean forStatsCollection = false;
        Boolean forDvsn = false;
        boolean isError = false;
        ExceptionControlApp concatException = new ExceptionControlApp("");

        try {
            forStatsCollection = (Boolean) dfAppRootFullImpl.oFCsRepo.getCellValue(ofcKey,
                    OFC.FOR_STATS_COLLECTION);
            forDvsn = (Boolean) dfAppRootFullImpl.oFCsRepo.getCellValue(ofcKey, OFC.FOR_DIVERSION);
        } catch (Throwable e) {
            log.error("Failed to get cells from oFCsRepo. ofcKey : " + ofcKey, e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get cells from oFCsRepo. ofcKey : " + ofcKey, e);
        }

        if (forStatsCollection) {
            try {
                dfAppRootFullImpl.getStatsCollectionRep().addOFC(ofcKey);
                int interval = dfAppRootFullImpl.getStatsCollectionRep().getStatsCollectionInterval();
                dfAppRootFullImpl.statsCollectorImpl.startCollection(interval);
            } catch (Throwable e1) {
                log.error("Failed to add OFC to StatsCollectionRep. ofcKey : " + ofcKey, e1);
                try {
                    dfAppRootFullImpl.getStatsCollectionRep().removeOFC(ofcKey);//Rollback
                } finally {
                    concatException = new ExceptionControlApp(
                            "Failed to add OFC to StatsCollectionRep. ofcKey : " + ofcKey, concatException);
                    isError = true;
                }
            }
        }
        if (forDvsn) {
            try {
                dfAppRootFullImpl.getDvsnRep().addOFC(ofcKey);
            } catch (Throwable e2) {
                log.error("Failed to add OFC to DvsnRep. ofcKey : " + ofcKey, e2);
                try {
                    dfAppRootFullImpl.getDvsnRep().removeOFC(ofcKey);//rollback
                } finally {
                    concatException = new ExceptionControlApp("Failed to add OFC to DvsnRep. ofcKey : " + ofcKey,
                            concatException);
                }
            }
        }
        if (isError)
            throw concatException;
    }

    /**
     * Remove OFC. The application will attempt to contact the previously set OFC in order to remove all monitors set through it.
     * @param param_name param description
     * @return return description
     * @throws ExceptionControlApp 
     * @throws exception_type circumstances description 
     */
    @Override
    public void removeOFC(String ofcLabel) throws ExceptionControlApp {

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DefenseFlow removing controller " + ofcLabel);

        String ofcKey = ofcLabel; // get from repo
        boolean forStatsCollection = false; // retrieve from repo
        boolean forDvsn = false; // retrieve from repo
        ExceptionControlApp concatException = new ExceptionControlApp("");
        boolean isError = false;

        try {
            forStatsCollection = (Boolean) dfAppRootFullImpl.oFCsRepo.getCellValue(ofcKey,
                    OFC.FOR_STATS_COLLECTION);
            forDvsn = (Boolean) dfAppRootFullImpl.oFCsRepo.getCellValue(ofcKey, OFC.FOR_DIVERSION);
        } catch (Throwable e) {
            log.error("Failed to get cells from oFCsRepo. ofcKey : " + ofcKey, e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove controller " + ofcLabel);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get cells from oFCsRepo. ofcKey : " + ofcKey, e);
        }

        if (forStatsCollection) {
            try {
                dfAppRootFullImpl.getStatsCollectionRep().removeOFC(ofcKey);
            } catch (Throwable e1) {
                log.error("Failed to remove OFC from StatsCollectionRep. ofcKey : " + ofcKey, e1);
                fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove controller " + ofcLabel);
                concatException = new ExceptionControlApp(
                        "Failed to remove OFC from StatsCollectionRep. ofcKey : " + ofcKey, concatException);
            }
        }
        if (forDvsn) {
            try {
                dfAppRootFullImpl.getDvsnRep().removeOFC(ofcKey);
            } catch (Throwable e2) {
                log.error("Failed to remove OFC from DvsnRep. ofcKey : " + ofcKey, e2);
                fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove controller " + ofcLabel);
                concatException = new ExceptionControlApp("Failed to remove OFC from DvsnRep. ofcKey : " + ofcKey,
                        concatException);
            }
        }
        if (!isError) {
            dfAppRootFullImpl.oFCsRepo.deleteRow(ofcKey);
        } else {
            throw concatException;
        }

    }

    /**
     * Add netNode. Notify statsCollectionRep and DvsnRep.
     * @param param_name param description
     * @return return description
     * @throws NotSupportedException 
     * @throws exception_type circumstances description 
     */
    @Override
    public void addNetNode(NetNode netNode)
            throws ExceptionControlApp, IllegalArgumentException, IllegalStateException, NotSupportedException {

        try {
            netNode.validate();
        } catch (Exception e1) {
            throw new IllegalArgumentException(e1);
        }

        Hashtable<String, Object> netNodeRow;
        try {
            netNodeRow = dfAppRootFullImpl.pNsRepo.getRow(netNode.label);
        } catch (Throwable e) {
            log.error("Failed to get netNodeRow from netNodesRepo ", e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add NetNode " + netNode.label);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("DF Failed to process addition of netNode " + netNode.label, e);
        }

        if (netNodeRow != null) {
            NetNode.Status netNodeStatus = NetNode.Status.valueOf((String) netNodeRow.get(NetNode.STATUS));
            if (netNodeStatus == NetNode.Status.REMOVED) {
                try {
                    dfAppRootFullImpl.netNodesRepo.deleteRow(netNode.label);
                } catch (Throwable e1) {
                    log.error("Failed to delete netNodeRow from netNodesRepo ", e1);
                    fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add NetNode " + netNode.label);
                    fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
                    throw new ExceptionControlApp("Failed to delete netNodeRow from netNodesRepo ", e1);
                }
            } else {
                String msg = "NetNode " + netNode.label + " is already defined. Need to delete it first";
                fr.logRecord(DFAppRoot.FR_DF_CONFIG,
                        "DefenseFlow failed to add NetNode " + netNode.label + ". Illegal argument(s).");
                throw new IllegalStateException(msg);
            }
        }

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DefenseFlow adding NetNode " + netNode.label);

        try {
            dfAppRootFullImpl.netNodesRepo.setRow(netNode.label, netNode.toRow()); // Record netNode in netNodes repo.      
        } catch (Exception e) {
            log.error("Failed to setRow in netNodesRepo " + netNode.label, e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add NetNode " + netNode.label);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to setRow in netNodesRepo " + netNode.label, e);
        }
        addNetNode(netNode.label); // Notify relevant DF modules. 
    }

    /**
     * Add netNode that has already been recorded in netNodes repo. Notify statsCollectionRep and DvsnRep.
     * @param param_name param description
     * @return return description
     * @throws NotSupportedException 
     * @throws exception_type circumstances description 
     */
    protected void addNetNode(String netNodeKey) throws ExceptionControlApp, NotSupportedException {
        boolean isError = false;
        ExceptionControlApp concatException = new ExceptionControlApp("");

        try {
            dfAppRootFullImpl.getStatsCollectionRep().addNetNode(netNodeKey);
        } catch (NotSupportedException e) {
            throw e; // Not supported so abort addNetNode processing and throw this exception
        } catch (Throwable e) {
            log.error("Failed to update StatsCollectionRep", e);
            concatException = new ExceptionControlApp("Failed to update StatsCollectionRep", concatException);
            isError = true;
        }
        try {
            dfAppRootFullImpl.getDvsnRep().addNetNode(netNodeKey);
        } catch (NotSupportedException e) {
            try {
                dfAppRootFullImpl.getStatsCollectionRep().removeNetNode(netNodeKey);
            } catch (Throwable e1) {
                /* Ignore */}
            throw e; // Not supported so abort addNetNode processing and throw this exception
        } catch (Throwable e) {
            log.error("Failed to update DvsnRep", e);
            concatException = new ExceptionControlApp("Failed to update DvsnRep", concatException);
            isError = true;
        }
        try {
            dfAppRoot.netNodesRepo.setCell(netNodeKey, NetNode.STATUS, NetNode.Status.ACTIVE.name());
        } catch (Throwable e) {
            log.error("Failed to update netNodesRepo", e);
            concatException = new ExceptionControlApp("Failed to update netNodesRepo", concatException);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            isError = true;
        }
        try {
            dfAppRootFullImpl.mitigationMgrImpl.addNetNode(netNodeKey);
        } catch (Throwable e) {
            log.error("Failed to update mitigationMgr", e);
            concatException = new ExceptionControlApp("Failed to update mitigationMgrImpl", concatException);
            isError = true;
        }

        if (isError)
            throw concatException; // TODO: Need to undo completed actions
    }

    /**
     * Remove netNode. The application will attempt to remove all traffic counting/diversion elements set in it.
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description 
     */
    @Override
    public void removeNetNode(String netNodeLabel) throws ExceptionControlApp, NotSupportedException {

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DefenseFlow removing NetNode " + netNodeLabel);

        boolean isError = false;

        if (NetNode.isRemoved(netNodeLabel))
            return; // Check if is already marked as removed.

        ExceptionControlApp concatException = new ExceptionControlApp("");
        try {
            dfAppRootFullImpl.getDvsnRep().removeNetNode(netNodeLabel);
        } catch (NotSupportedException e) {
            throw e; // Not supported so abort removeNetNode processing and throw this exception
        } catch (IllegalStateException e1) {
            throw e1; // NetNode cannot be removed at this time/state - abort removeNetNode processing and throw this exception
        } catch (Throwable e2) {
            log.error("Failed to update DvsnRep", e2);
            concatException = new ExceptionControlApp("Failed to update DvsnRep", concatException);
            isError = true;
        }
        try {
            dfAppRootFullImpl.getStatsCollectionRep().removeNetNode(netNodeLabel);
        } catch (NotSupportedException e) {
            throw e; // Not supported so abort removeNetNode processing and throw this exception
        } catch (Throwable e) {
            log.error("Failed to update StatsCollectionRep", e);
            concatException = new ExceptionControlApp("Failed to update StatsCollectionRep", concatException);
            isError = true;
        }
        if (isError) {
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove NetNode " + netNodeLabel);
            throw concatException;
        }

        try {
            dfAppRoot.netNodesRepo.setCell(netNodeLabel, NetNode.STATUS, NetNode.Status.REMOVED.name());
        } catch (Throwable e) {
            log.error("Failed to update netNodesRepo", e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove NetNode " + netNodeLabel);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to update netNodesRepo", e);
        }
    }

    /**
     * Add DP. If it is for stats collection need to notify the DP-based detector. If it is for dvsn,
     * notify both the dvsn rep and the DP rep.
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description 
     */
    @Override
    public void addAMS(AMS ams) throws ExceptionControlApp, IllegalArgumentException {

        try {
            ams.validate();
        } catch (Exception e1) {
            throw new IllegalArgumentException(e1);
        }

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DefenseFlow adding AMS " + ams.label);

        Hashtable<String, Object> amsRow = dfAppRootFullImpl.amsRepo.getRow(ams.label);
        if (amsRow != null) {
            AMS.Status status = AMS.Status.valueOf((String) amsRow.get(AMS.STATUS));
            if (status == AMS.Status.REMOVED) {
                try {
                    dfAppRootFullImpl.amsRepo.deleteRow(ams.label);
                } catch (Throwable e) {
                    log.error("Failed to delete amsRow from amsRepo ", e);
                    fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add AMS " + ams.label);
                    fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
                    throw new ExceptionControlApp("Failed to delete pnRow from pNsRepo ", e);
                }
            } else {
                String msg = "AMS " + ams.label + " is already defined. Need to delete it first";
                fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DefenseFlow failed to add AMS " + ams.label
                        + ". An AMS with the same label already exists.");
                throw new IllegalArgumentException(msg);
            }
        }
        try {
            dfAppRootFullImpl.amsRepo.setRow(ams.label, ams.toRow());
        } catch (ExceptionControlApp e) {
            log.error("Failed to row to amsRepo " + ams.label, e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add AMS " + ams.label);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to add AMS " + ams.label, e);
        }
        if ("Other".equalsIgnoreCase(ams.getBrand())) {//Value from GUI
            dfAppRootFullImpl.setAmsRepByType("DefaultAms");//default from Spring xml
        } else {
            dfAppRootFullImpl.setAmsRepByType("DP");//DP configuration from Spring xml
        }
        addAMS(ams.label);
    }

    /**
     * #### description ####
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description 
     */
    protected void addAMS(String amsKey) throws ExceptionControlApp {

        try {
            dfAppRootFullImpl.amsRep.addAMS(amsKey);
        } catch (ExceptionControlApp e) {
            log.error("Failed to add AMS " + amsKey, e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to add AMS " + amsKey, e);
        }
    }

    /**
     * #### description ####
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description 
     */
    @Override
    public boolean removeAMS(String amsLabel) throws ExceptionControlApp {

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DF is removing AMS " + amsLabel);

        if (AMS.isRemoved(amsLabel))
            return true; // Check if is already marked as removed.

        boolean success = dfAppRootFullImpl.mitigationMgrImpl.removeAMS(amsLabel);
        if (!success)
            return false;

        try {
            dfAppRootFullImpl.amsRep.removeAMS(amsLabel);
        } catch (ExceptionControlApp e) {
            log.error("Failed to remove AMS " + amsLabel, e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DF failed to properly remove AMS " + amsLabel);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("DefenseFlow failed to remove AMS " + amsLabel, e);
        }

        try {
            dfAppRoot.amsRepo.setCell(amsLabel, AMS.STATUS, AMS.Status.REMOVED.name());
        } catch (Throwable e) {
            log.error("Failed to update netNodesRepo", e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove AMS " + amsLabel);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to update netNodesRepo", e);
        }
        return true;
    }

    /**through
     * Add an external detector.
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description 
     */
    public void addDetector(DetectorInfo detectorInfo) throws ExceptionControlApp {

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, " DefenseFlow adding " + detectorInfo.label + " detector ");

        try {
            if (detectorInfo.getExternalDetector() == true) {
                ExternalDetector externalDetector = new ExternalDetector(detectorInfo);
                dfAppRootFullImpl.detectorMgrImpl.addDetector(externalDetector);
            }
        } catch (Throwable e) {
            log.error("Failed to add detector " + detectorInfo.label, e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add " + detectorInfo.label + " detector ");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to add detector " + detectorInfo.label, e);
        }
    }

    /**
     * Remove an external detector.
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description 
     */
    public void removeDetector(String detectorLabel) throws ExceptionControlApp {

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DF is removing detector " + detectorLabel);
        try {
            dfAppRootFullImpl.detectorMgrImpl.removeDetector(detectorLabel);
        } catch (Throwable e) {
            log.error("Failed to remove detector " + detectorLabel, e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove " + detectorLabel + " detector ");
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to remove detector " + detectorLabel, e);
        }
    }

    /**
     * Add protected object. The protection profile referred in the protected object is assumed to be set in the system earlier.
     * If OFC monitoring has been specified then DF will add the object to the OFC monitored objects.
     * If DP based monitoring (then DP should be specified) DF will accept attack detections against the protected object 
     * from registered DPs. In any case DF will mitigate attacks against this protected object. 
     * For NEC vlan and array of vExtNames can be passed in the otherProperties of the ProtectedNetwork object rather than consumed from topology.
     * @param param_name param description
     * @return return description
     * @throws Exception 
     * @throws ExceptionProtectionProfileNotFound If the protection profile specified in the protected object is not found in the system
     */
    public void addPN(PN pn) throws Exception, IllegalArgumentException, IllegalStateException {

        try {
            pn.validate();
        } catch (Exception e1) {
            throw new IllegalArgumentException(e1);
        }

        Hashtable<String, Object> pnRow;
        try {
            pnRow = dfAppRootFullImpl.pNsRepo.getRow(pn.label);
        } catch (Throwable e) {
            log.error("Failed to get pnRow from pNsRepo ", e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add PO " + PN.getPrintableKey(pn.label));
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get pnRow from pNsRepo ", e);
        }

        if (pnRow != null) {
            PN existingPn = new PN(pnRow);
            if (existingPn.operationalStatus == OperationalStatus.CANCELED) {
                try {
                    removePnIfCanceled(existingPn.label);
                } catch (ExceptionControlApp e1) {
                    throw e1;
                }
            } else {
                String msg = "Protected network " + pn.label + " is already defined. Need to delete it first";
                fr.logRecord(DFAppRoot.FR_DF_CONFIG,
                        "DefenseFlow failed to add PO " + PN.getPrintableKey(pn.label));
                throw new IllegalStateException(msg);
            }
        }

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DefenseFlow adding PO " + PN.getPrintableKey(pn.label));

        try {
            dfAppRootFullImpl.pNsRepo.setRow(pn.label, pn.toRow());
        } catch (Throwable e) {
            log.error("Failed to create pnRow from pNsRepo. pn label " + pn.label, e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to add PO " + PN.getPrintableKey(pn.label));
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to create pnRow from pNsRepo. pn label " + pn.label, e);
        }
        addPN(pn.label);
    }

    /**
     * Add protected object. The protection profile referred in the protected object is assumed to be set in the system earlier.
     * If OFC monitoring has been specified then DF will add the object to the OFC monitored objects.
     * If DP based monitoring (then DP should be specified) DF will accept attack detections against the protected object 
     * from registered DPs. In any case DF will mitigate attacks against this protected object. 
     * For NEC vlan and array of vExtNames can be passed in the otherProperties of the ProtectedNetwork object rather than consumed from topology.
     * @param param_name param description
     * @return return description
     * @throws Exception 
     * @throws ExceptionProtectionProfileNotFound If the protection profile specified in the protected object is not found in the system
     */
    protected void addPN(String pnKey) throws ExceptionControlApp {

        /* Don't try to add cancelled PN */
        try {
            Object obj = dfAppRootFullImpl.pNsRepo.getCellValue(pnKey, PN.OPERATIONAL_STATUS);
            OperationalStatus operationalStatus = OperationalStatus.INVALID;
            if (obj != null)
                operationalStatus = OperationalStatus.valueOf((String) obj);
            if (operationalStatus == OperationalStatus.CANCELED)
                return;
        } catch (Throwable e) {
            log.error("Failed to retrieve operational status value for " + pnKey, e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            return;
        }

        /* Reset the PN status to INVALID - to re-attempt its installation after restarts. */
        try {
            dfAppRootFullImpl.pNsRepo.setCell(pnKey, PN.OPERATIONAL_STATUS, PN.OperationalStatus.INVALID.name());
        } catch (Throwable e) {
            log.error("Failed to set PN operational status for " + pnKey, e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to set PN operational status for " + pnKey, e);
        }

        String detectorLabel;
        try {
            detectorLabel = (String) dfAppRoot.pNsRepo.getCellValue(pnKey, PN.DETECTOR_LABEL);
        } catch (Throwable e) {
            log.error("Failed to get detectorLabel from pNsRepo for pnKey " + pnKey, e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get detectorLabel from pNsRepo for pnKey " + pnKey, e);
        }

        try {
            dfAppRootFullImpl.mitigationMgrImpl.addPN(pnKey);
            Detector detector = dfAppRootFullImpl.detectorMgrImpl.getDetector(detectorLabel);
            if (detector != null) {
                boolean ofBasedDetector = detector.getDetectorInfo().ofBasedDetector;
                dfAppRoot.pNsRepo.setCell(pnKey, PN.OF_BASED_DETECTION, ofBasedDetector); // Base on detector, not client param
                detector.addPN(pnKey);
            }
        } catch (Throwable e) {
            log.error("Failed to add PN to detector and/or mitigation manager", e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to add PN to detector and/or mitigation manager", e);
        }
    }

    /** 
     * #### method description ####
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description
     */
    @Override
    public Collection<PNStatReport> getLatestPNStatReports() throws ExceptionControlApp {

        DFDetector dfDetector;
        Collection<PNStatReport> pnStatReports = new ArrayList<PNStatReport>();
        Collection<PNStatReport> detectorPnStatReports = new ArrayList<PNStatReport>();

        /* Add pnStatReports from all OF detectors. */
        try {
            List<Detector> detectors = dfAppRootFullImpl.detectorMgrImpl.getDetectors();
            for (Detector detector : detectors) {
                if (!detector.getDetectorInfo().ofBasedDetector)
                    continue;
                dfDetector = (DFDetector) detector;
                detectorPnStatReports = dfDetector.getLatestPNStatReports();
                pnStatReports.addAll(detectorPnStatReports);
            }
        } catch (Throwable e) {
            log.error("Failed to getLatestPNStatReports ", e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to getLatestPNStatReports ", e);
        }

        return pnStatReports;
    }

    /** 
     * #### method description ####
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description
     */
    @Override
    public PNStatReport getLatestPNStatReport(String pnKey) throws ExceptionControlApp, IllegalArgumentException {

        if (pnKey == null || pnKey.isEmpty())
            throw new IllegalArgumentException("Invalid pnkey " + pnKey);

        String detectorLabel;
        Detector detector;
        DFDetector dfDetector;
        PNStatReport pnStatReport = new PNStatReport();
        pnStatReport.pnKey = pnKey;

        /* Get the label of the detector processing stats for this PN. */
        try {
            detectorLabel = (String) dfAppRoot.pNsRepo.getCellValue(pnKey, PN.DETECTOR_LABEL);
            if (detectorLabel == null)
                return pnStatReport;
        } catch (Throwable e) {
            log.error("Failed to get detectorLabel from pNsRepo for pnKey " + pnKey, e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get detectorLabel from pNsRepo for pnKey " + pnKey, e);
        }

        /* Out of the detector label get the detector processing stats for this PN. */
        try {
            detector = dfAppRootFullImpl.detectorMgrImpl.getDetector(detectorLabel);
            if (detector == null)
                return pnStatReport;
            boolean ofBasedDetector = detector.getDetectorInfo().ofBasedDetector;
            if (!ofBasedDetector)
                return pnStatReport;
            dfDetector = (DFDetector) detector;
        } catch (Throwable e) {
            log.error("Failed to get detector " + detectorLabel, e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get detector " + detectorLabel, e);
        }

        /* Retrieve and return the PN stats from that detector. */
        pnStatReport = dfDetector.getLatestPNStatReport(pnKey);
        return pnStatReport;
    }

    /**
     * #### method description ####
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description 
     */
    public void changePN(PN pn) {
        // No Op at this time.
    }

    /**
     * #### method description ####
     * @param param_name param description
     * @return return description
     * @throws exception_type circumstances description 
     */
    public boolean removePN(String pnLabel) throws ExceptionControlApp {

        fr.logRecord(DFAppRoot.FR_DF_CONFIG, "DefenseFlow removing PO " + PN.getPrintableKey(pnLabel));

        String pnKey = pnLabel;
        boolean isError = false;
        ExceptionControlApp concatException = new ExceptionControlApp("");

        Hashtable<String, Object> pnRow;
        try {
            pnRow = dfAppRootFullImpl.pNsRepo.getRow(pnKey);
        } catch (ExceptionControlApp e1) {
            log.error("Failed to get pnRow from pNsRepo for pnKey " + pnKey, e1);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove PO " + PN.getPrintableKey(pnLabel));
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to get pnRow from pNsRepo for pnKey " + pnKey, e1);
        }

        if (pnRow == null) {
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove PO " + PN.getPrintableKey(pnLabel));
            throw new ExceptionControlApp("Protected network " + pnLabel + " is unknown.");
        }

        Object obj = pnRow.get(PN.OPERATIONAL_STATUS);
        OperationalStatus operationalStatus = OperationalStatus.INVALID;
        if (obj != null)
            operationalStatus = OperationalStatus.valueOf((String) obj);
        if (operationalStatus == OperationalStatus.CANCELED)
            return true;

        try {
            String detectorLabel = (String) dfAppRoot.pNsRepo.getCellValue(pnKey, PN.DETECTOR_LABEL);
            Detector detector = dfAppRootFullImpl.detectorMgrImpl.getDetector(detectorLabel);
            if (detector != null)
                detector.removePN(pnKey);
        } catch (Throwable e1) {
            log.error("Failed to remove PN from detector. PN key " + pnKey, e1);
            concatException = new ExceptionControlApp("Failed to remove PN from detector. PN key " + pnKey,
                    concatException);
            isError = true;
        }

        try {
            dfAppRootFullImpl.attackDecisionPointImpl.removePN(pnKey);
        } catch (Throwable e1) {
            String msg = "Failed to remove PN from attackDecisionPointImpl. PN key " + pnKey;
            log.error(msg, e1);
            concatException = new ExceptionControlApp(msg, concatException);
            isError = true;
        }

        try {
            dfAppRootFullImpl.mitigationMgrImpl.removePN(pnKey);
        } catch (Throwable e1) {
            log.error("Failed to remove PN from mitigationMgr. PN key " + pnKey, e1);
            concatException = new ExceptionControlApp("Failed to remove PN from mitigationMgr. PN key " + pnKey,
                    concatException);
            isError = true;
        }

        try {
            dfAppRoot.pNsRepo.setCell(pnKey, PN.OPERATIONAL_STATUS, PN.OperationalStatus.CANCELED.name());
        } catch (Throwable e) {
            log.error("Failed to update pNsRepo for pnKey " + pnKey, e);
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove PO " + PN.getPrintableKey(pnLabel));
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            throw new ExceptionControlApp("Failed to update pNsRepo for pnKey " + pnKey, e);
        }

        if (isError) {
            fr.logRecord(DFAppRoot.FR_DF_FAILURE, "DefenseFlow failed to remove PO " + PN.getPrintableKey(pnLabel));
            throw concatException;
        }
        // Cannot remove the PN yet because the above methods are asynchronous
        return true;
    }

    protected boolean hasActiveAttacks(String pnKey) {

        List<String> attackKeys = null;
        try {
            attackKeys = dfAppRootFullImpl.attacksRepo.getKeys();
        } catch (ExceptionControlApp e) {
            log.error("Failed to get keys from attacksRepo", e);
            fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
        }
        if (attackKeys == null)
            return false;

        String attackPnKey;
        for (String attackKey : attackKeys) {
            try {
                attackPnKey = (String) dfAppRootFullImpl.attacksRepo.getCellValue(attackKey, Attack.PNKEY);
                if (attackPnKey.equals(pnKey))
                    return true; // Found attack on this PN
            } catch (ExceptionControlApp e) {
                log.error("Failed in hasActiveAttacks. Attack key: " + attackKey);
                fMain.getHealthTracker().reportHealthIssue(HealthTracker.MINOR_HEALTH_ISSUE);
            }
        }
        return false;
    }

    @Override
    protected void actionSwitcher(int actionCode, Object param) {
    }

    public void test() {
    }
}