Fix behaviour of listeners in the InventoryService 46/9246/2
authorDave Tucker <djt@redhat.com>
Tue, 22 Jul 2014 22:08:48 +0000 (23:08 +0100)
committerDave Tucker <djt@redhat.com>
Wed, 23 Jul 2014 01:58:27 +0000 (02:58 +0100)
Currently a random OVSDB Inventory Listener will be resolved from the
OSGi Service Registry. This commit enables ALL registered inventory
listeners to receive updates using the OSGi Whiteboard Pattern

Additionally there was a hack in the Port and Network Handlers that
created InventoryService events, breaking the Provider/Consumer
contract. This is also fixed in this commit.

Fixes bug 1298

Change-Id: Iec1871a9022291b222a56cbb03e2093d3d45cc7a
Signed-off-by: Dave Tucker <djt@redhat.com>
integrationtest/pom.xml
integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/ConfigurationBundles.java
integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/neutron/NeutronIT.java
integrationtest/src/test/java/org/opendaylight/ovsdb/integrationtest/plugin/OvsdbPluginIT.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/Activator.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/NetworkHandler.java
openstack/net-virt/src/main/java/org/opendaylight/ovsdb/openstack/netvirt/PortHandler.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/Activator.java
plugin/src/main/java/org/opendaylight/ovsdb/plugin/InventoryService.java

index 752a6a10e11c660dce7dde5f7d55e4fd87aeed40..afbb8b1857ce4fb9b9f2ab88994e2040556afef2 100644 (file)
       <groupId>org.ops4j.pax.url</groupId>
       <artifactId>pax-url-aether</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-all</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
   <build>
     <pluginManagement>
index 5e249c9942216be97adf06cad8be04e77f3f3046..f43dea7f331640a2f45f1505fe9efb2b1c2a5a5f 100644 (file)
@@ -188,6 +188,13 @@ public class ConfigurationBundles {
         );
     }
 
+    public static Option ovsdbPluginBundles() {
+        return new DefaultCompositeOption(
+                mavenBundle("org.opendaylight.ovsdb", "plugin").versionAsInProject(),
+                mavenBundle("org.mockito", "mockito-all").versionAsInProject()
+        );
+    }
+
     public static Option ovsdbDefaultSchemaBundles() {
         return new DefaultCompositeOption(
                 mavenBundle("org.opendaylight.ovsdb", "schema.openvswitch").versionAsInProject(),
@@ -211,7 +218,6 @@ public class ConfigurationBundles {
                 mavenBundle("org.opendaylight.controller", "connectionmanager").versionAsInProject(),
                 mavenBundle("org.opendaylight.controller", "connectionmanager.implementation").versionAsInProject(),
                 mavenBundle("org.opendaylight.controller", "forwardingrulesmanager").versionAsInProject(),
-                mavenBundle("org.opendaylight.ovsdb", "plugin").versionAsInProject(),
                 mavenBundle("org.opendaylight.ovsdb", "openstack.net-virt").versionAsInProject()
         );
     }
index 9f45015cefbb175b8d6b072725552ee6fc85197b..43f92324148f31cce67068ffe0e462219cc09d71 100644 (file)
@@ -102,6 +102,7 @@ public class NeutronIT extends OvsdbIntegrationTestBase {
                 ConfigurationBundles.controllerBundles(),
                 ConfigurationBundles.ovsdbLibraryBundles(),
                 ConfigurationBundles.ovsdbDefaultSchemaBundles(),
+                ConfigurationBundles.ovsdbPluginBundles(),
                 ConfigurationBundles.ovsdbNeutronBundles(),
                 junitBundles()
         );
index 29c45c6648fc0f3e09443c91ae2c37e5e486af13..df77a37d0041011cbb346dfdbbc1f1c3a6fd3ddb 100644 (file)
@@ -16,7 +16,6 @@ import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.ops4j.pax.exam.CoreOptions.junitBundles;
-import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
 import static org.ops4j.pax.exam.CoreOptions.options;
 import static org.ops4j.pax.exam.CoreOptions.propagateSystemProperty;
 import static org.ops4j.pax.exam.CoreOptions.systemProperty;
@@ -26,6 +25,8 @@ import java.util.concurrent.ConcurrentMap;
 
 import javax.inject.Inject;
 
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -39,10 +40,14 @@ import org.opendaylight.ovsdb.lib.OvsdbConnectionInfo;
 import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.plugin.Connection;
 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
+import org.opendaylight.ovsdb.plugin.InventoryServiceInternal;
 import org.opendaylight.ovsdb.plugin.OvsdbConfigService;
+import org.opendaylight.ovsdb.plugin.OvsdbInventoryListener;
 import org.opendaylight.ovsdb.plugin.StatusWithUuid;
 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
+
+import org.mockito.Mockito;
 import org.ops4j.pax.exam.Configuration;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.junit.PaxExam;
@@ -61,6 +66,10 @@ public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
     @Inject
     private BundleContext bc;
     private OvsdbConfigService ovsdbConfigService = null;
+
+    @Inject
+    private InventoryServiceInternal inventoryService;
+
     private Node node = null;
     private OvsdbClient client = null;
 
@@ -82,7 +91,7 @@ public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
             ConfigurationBundles.controllerBundles(),
             ConfigurationBundles.ovsdbLibraryBundles(),
             ConfigurationBundles.ovsdbDefaultSchemaBundles(),
-            mavenBundle("org.opendaylight.ovsdb", "plugin").versionAsInProject(),
+            ConfigurationBundles.ovsdbPluginBundles(),
             junitBundles()
         );
     }
@@ -163,6 +172,36 @@ public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
         this.endToEndApiTest(connection, null);
     }
 
+    @Test
+    public void testInventoryListeners(){
+        DependencyManager dm = new DependencyManager(bc);
+
+        OvsdbInventoryListener listenerA = Mockito.mock(FakeListener.class);
+        OvsdbInventoryListener listenerB = Mockito.mock(FakeListener.class);
+
+        Component componentA = dm.createComponent();
+        componentA.setInterface(OvsdbInventoryListener.class.getName(), null);
+        componentA.setImplementation(listenerA);
+        dm.add(componentA);
+
+        Component componentB = dm.createComponent();
+        componentB.setInterface(OvsdbInventoryListener.class.getName(), null);
+        componentB.setImplementation(listenerB);
+        dm.add(componentB);
+
+        Node newNode = Node.fromString("OVS:10.10.10.10:65342");
+
+        // Trigger event
+        inventoryService.notifyNodeAdded(newNode);
+
+        Mockito.verify(listenerA, Mockito.times(1)).nodeAdded(newNode);
+        Mockito.verify(listenerB, Mockito.times(1)).nodeAdded(newNode);
+
+        dm.remove(componentA);
+        dm.remove(componentB);
+
+    }
+
     public void endToEndApiTest(Connection connection, String parentUuid) throws Exception {
         // 1. Print Cache and Assert to make sure the bridge is not created yet.
         printCache();
@@ -217,4 +256,32 @@ public class OvsdbPluginIT extends OvsdbIntegrationTestBase {
         }
     }
 
+    public class FakeListener implements OvsdbInventoryListener{
+
+        @Override
+        public void nodeAdded(Node node) {
+
+        }
+
+        @Override
+        public void nodeRemoved(Node node) {
+
+        }
+
+        @Override
+        public void rowAdded(Node node, String tableName, String uuid, Row row) {
+
+        }
+
+        @Override
+        public void rowUpdated(Node node, String tableName, String uuid, Row old, Row row) {
+
+        }
+
+        @Override
+        public void rowRemoved(Node node, String tableName, String uuid, Row row, Object context) {
+
+        }
+    }
+
 }
index 661113a69b17da1ba45e4433b08cad29ceb23c25..c0ebd86b4edf224b904ca24f86e5b2382fadeda1 100644 (file)
@@ -148,7 +148,6 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.setInterface(INeutronPortAware.class.getName(), null);
             c.add(createServiceDependency().setService(OvsdbConfigService.class).setRequired(true));
             c.add(createServiceDependency().setService(IConnectionServiceInternal.class).setRequired(true));
-            c.add(createServiceDependency().setService(INeutronNetworkCRUD.class).setRequired(true));
             c.add(createServiceDependency().setService(OvsdbInventoryListener.class).setRequired(true));
         }
 
index 81da6503d76daffde580d96fbbe20b576adf6011..1aaa4c678ff5e3ff6fe9a4a4cd35327de0251d2f 100644 (file)
@@ -14,6 +14,7 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
 import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.openstack.netvirt.api.BridgeConfigurationManager;
 import org.opendaylight.ovsdb.openstack.netvirt.api.ConfigurationService;
 import org.opendaylight.ovsdb.openstack.netvirt.api.TenantNetworkManager;
@@ -21,6 +22,7 @@ import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
 import org.opendaylight.ovsdb.plugin.OvsdbConfigService;
 import org.opendaylight.ovsdb.plugin.OvsdbInventoryListener;
 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
+import org.opendaylight.ovsdb.schema.openvswitch.Port;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -153,20 +155,35 @@ public class NetworkHandler extends AbstractHandler
                 for (Node node : nodes) {
                     List<String> phyIfName = bridgeConfigurationManager.getAllPhysicalInterfaceNames(node);
                     try {
-                        ConcurrentMap<String, Row> interfaces = this.ovsdbConfigService.getRows(node, ovsdbConfigService.getTableName(node, Interface.class));
-                        if (interfaces != null) {
-                            for (String intfUUID : interfaces.keySet()) {
-                                Interface intf = ovsdbConfigService.getTypedRow(node, Interface.class, interfaces.get(intfUUID));
-                                String intfType = intf.getTypeColumn().getData();
-                                if (intfType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN) || intfType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_GRE)) {
-                                    /* delete tunnel ports on this node */
-                                    logger.trace("Delete tunnel intf {}", intf);
-                                    inventoryListener.rowRemoved(node, intf.getSchema().getName(), intfUUID,
-                                            intf.getRow(), null);
-                                } else if (!phyIfName.isEmpty() && phyIfName.contains(intf.getName())) {
-                                    logger.trace("Delete physical intf {}", intf);
-                                    inventoryListener.rowRemoved(node, intf.getSchema().getName(), intfUUID,
-                                            intf.getRow(), null);
+                        ConcurrentMap<String, Row> ports =
+                                this.ovsdbConfigService.getRows(node,
+                                                                ovsdbConfigService.getTableName(node, Port.class));
+                        if (ports != null) {
+                            for (Row portRow : ports.values()) {
+                                Port port = ovsdbConfigService.getTypedRow(node, Port.class, portRow);
+                                for (UUID interfaceUuid : port.getInterfacesColumn().getData()) {
+                                    Interface interfaceRow = (Interface) ovsdbConfigService
+                                            .getRow(node,
+                                                    ovsdbConfigService.getTableName(node, Interface.class),
+                                                    interfaceUuid.toString());
+
+                                    String interfaceType = interfaceRow.getTypeColumn().getData();
+                                    if (interfaceType.equalsIgnoreCase(NetworkHandler.NETWORK_TYPE_VXLAN)
+                                        || interfaceType.equalsIgnoreCase(
+                                            NetworkHandler.NETWORK_TYPE_GRE)) {
+                                        /* delete tunnel ports on this node */
+                                        logger.trace("Delete tunnel interface {}", interfaceRow);
+                                        ovsdbConfigService.deleteRow(node,
+                                                                     ovsdbConfigService.getTableName(node, Port.class),
+                                                                     port.getUuid().toString());
+                                        break;
+                                    } else if (!phyIfName.isEmpty() && phyIfName.contains(interfaceRow.getName())) {
+                                        logger.trace("Delete physical interface {}", interfaceRow);
+                                        ovsdbConfigService.deleteRow(node,
+                                                                     ovsdbConfigService.getTableName(node, Port.class),
+                                                                     port.getUuid().toString());
+                                        break;
+                                    }
                                 }
                             }
                         }
index ac4e4b134ff7ff2b7c200c35e07d8b2c29d7c654..c62fe26678bed0362016b6254bd1ed31c06844d3 100644 (file)
@@ -9,17 +9,17 @@
  */
 package org.opendaylight.ovsdb.openstack.netvirt;
 
-import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronPortAware;
-import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
 import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
 import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.ovsdb.lib.notation.Row;
+import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.openstack.netvirt.api.Constants;
 import org.opendaylight.ovsdb.plugin.IConnectionServiceInternal;
 import org.opendaylight.ovsdb.plugin.OvsdbConfigService;
 import org.opendaylight.ovsdb.plugin.OvsdbInventoryListener;
 import org.opendaylight.ovsdb.schema.openvswitch.Interface;
+import org.opendaylight.ovsdb.schema.openvswitch.Port;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -42,7 +42,6 @@ public class PortHandler extends AbstractHandler
 
     private volatile OvsdbConfigService ovsdbConfigService;
     private volatile IConnectionServiceInternal connectionService;
-    private volatile INeutronNetworkCRUD neutronNetworkCache;
     private volatile OvsdbInventoryListener ovsdbInventoryListener;
 
     /**
@@ -125,40 +124,52 @@ public class PortHandler extends AbstractHandler
     /**
      * Invoked to take action after a port has been deleted.
      *
-     * @param port  An instance of deleted Neutron Port object.
+     * @param neutronPort  An instance of deleted Neutron Port object.
      */
     @Override
-    public void neutronPortDeleted(NeutronPort port) {
+    public void neutronPortDeleted(NeutronPort neutronPort) {
 
-        int result = canDeletePort(port);
+        int result = canDeletePort(neutronPort);
         if  (result != HttpURLConnection.HTTP_OK) {
             logger.error(" deletePort validation failed - result {} ", result);
             return;
         }
 
-        NeutronNetwork neutronNetwork = neutronNetworkCache.getNetwork(port.getNetworkUUID());
         List<Node> nodes = connectionService.getNodes();
         for (Node node : nodes) {
             try {
-                ConcurrentMap<String, Row> interfaces = this.ovsdbConfigService.getRows(node, ovsdbConfigService.getTableName(node, Interface.class));
-                if (interfaces != null) {
-                    for (String intfUUID : interfaces.keySet()) {
-                        Interface intf = ovsdbConfigService.getTypedRow(node, Interface.class, interfaces.get(intfUUID));
-                        Map<String, String> externalIds = intf.getExternalIdsColumn().getData();
-                        if (externalIds == null) {
-                            logger.trace("No external_ids seen in {}", intf);
-                            continue;
-                        }
-                        /* Compare Neutron port uuid */
-                        String neutronPortId = externalIds.get(Constants.EXTERNAL_ID_INTERFACE_ID);
-                        if (neutronPortId == null) {
-                            continue;
-                        }
-                        if (neutronPortId.equalsIgnoreCase(port.getPortUUID())) {
-                            logger.trace("neutronPortDeleted: Delete interface {}", intf.getName());
-                            ovsdbInventoryListener.rowRemoved(node, intf.getSchema().getName(), intfUUID,
-                                                              intf.getRow(), neutronNetwork);
-                            break;
+                ConcurrentMap<String, Row> portRows =
+                        this.ovsdbConfigService.getRows(node,
+                                                        ovsdbConfigService.getTableName(node, Port.class));
+                if (portRows != null) {
+                    for (Row portRow : portRows.values()) {
+                        Port port = ovsdbConfigService.getTypedRow(node, Port.class, portRow);
+                        for (UUID interfaceUuid : port.getInterfacesColumn().getData()) {
+                            Interface interfaceRow = (Interface) ovsdbConfigService
+                                    .getRow(node,
+                                            ovsdbConfigService.getTableName(node, Interface.class),
+                                            interfaceUuid.toString());
+
+                            Map<String, String> externalIds = interfaceRow.getExternalIdsColumn().getData();
+
+                            if (externalIds == null) {
+                                logger.trace("No external_ids seen in {}", interfaceRow);
+                                continue;
+                            }
+
+                            /* Compare Neutron port uuid */
+                            String neutronPortId = externalIds.get(Constants.EXTERNAL_ID_INTERFACE_ID);
+                            if (neutronPortId == null) {
+                                continue;
+                            }
+
+                            if (neutronPortId.equalsIgnoreCase(neutronPort.getPortUUID())) {
+                                logger.trace("neutronPortDeleted: Delete interface {}", interfaceRow.getName());
+                                ovsdbConfigService.deleteRow(node,
+                                                             ovsdbConfigService.getTableName(node, Port.class),
+                                                             port.getUuid().toString());
+                                break;
+                            }
                         }
                     }
                 }
@@ -168,8 +179,8 @@ public class PortHandler extends AbstractHandler
         }
         logger.debug(" PORT delete successful for tenant-id - {}, " +
                      " network-id - {}, port-id - {}",
-                     port.getTenantID(), port.getNetworkUUID(),
-                     port.getID());
+                     neutronPort.getTenantID(), neutronPort.getNetworkUUID(),
+                     neutronPort.getID());
 
     }
 }
index 36f414db0746e546fa99c5c19a2e89d3324bf487..07d4b37c5c820f14d2b18bed994d22eaa1318dde 100644 (file)
@@ -122,6 +122,9 @@ public class Activator extends ComponentActivatorAbstractBase {
                     .setCallbacks("setPluginOutInventoryServices",
                             "unsetPluginOutInventoryServices")
                     .setRequired(true));
+            c.add(createServiceDependency()
+                    .setService(OvsdbInventoryListener.class)
+                    .setCallbacks("listenerAdded", "listenerRemoved"));
             c.add(createServiceDependency()
                     .setService(OvsdbConfigService.class)
                     .setCallbacks("setConfigurationService", "unsetConfigurationService")
index 66a59b7eeef9eeeca75e02750a029d4b14d08617..58b27fd9b02e58e8ba9dfc9d946dbee8495f1868 100644 (file)
@@ -37,6 +37,8 @@ import org.opendaylight.ovsdb.lib.message.TableUpdates;
 import org.opendaylight.ovsdb.lib.notation.Row;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
+
+import com.google.common.collect.Sets;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -58,6 +60,8 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
     private ScheduledExecutorService executor;
     private OvsdbConfigService configurationService;
 
+    private Set<OvsdbInventoryListener> ovsdbInventoryListeners = Sets.newCopyOnWriteArraySet();
+
     /**
      * Function called by the dependency manager when all the required
      * dependencies are satisfied
@@ -171,7 +175,6 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
             dbCache.put(n, db);
         }
 
-        OvsdbInventoryListener inventoryListener = (OvsdbInventoryListener)ServiceHelper.getGlobalInstance(OvsdbInventoryListener.class, this);
         for (String tableName : tableUpdates.getUpdates().keySet()) {
             Map<String, Row> tCache = db.getTableCache(databaseName, tableName);
             TableUpdate update = tableUpdates.getUpdates().get(tableName);
@@ -182,13 +185,25 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
                 db.updateRow(databaseName, tableName, uuid.toString(), update.getNew(uuid));
                 if (isNewRow) {
                     this.handleOpenVSwitchSpecialCase(n, databaseName, tableName, uuid);
-                    if (inventoryListener != null) inventoryListener.rowAdded(n, tableName, uuid.toString(), update.getNew(uuid));
+                    if (!ovsdbInventoryListeners.isEmpty()) {
+                        for (OvsdbInventoryListener listener : ovsdbInventoryListeners) {
+                            listener.rowAdded(n, tableName, uuid.toString(), update.getNew(uuid));
+                        }
+                    }
                 } else {
-                    if (inventoryListener != null) inventoryListener.rowUpdated(n, tableName, uuid.toString(), update.getOld(uuid), update.getNew(uuid));
+                    if (!ovsdbInventoryListeners.isEmpty()) {
+                        for (OvsdbInventoryListener listener : ovsdbInventoryListeners) {
+                            listener.rowUpdated(n, tableName, uuid.toString(), update.getOld(uuid), update.getNew(uuid));
+                        }
+                    }
                 }
             } else if (update.getOld(uuid) != null){
                 if (tCache != null) {
-                    if (inventoryListener != null) inventoryListener.rowRemoved(n, tableName, uuid.toString(), update.getOld(uuid), update.getNew(uuid));
+                    if (!ovsdbInventoryListeners.isEmpty()) {
+                        for (OvsdbInventoryListener listener : ovsdbInventoryListeners) {
+                            listener.rowRemoved(n, tableName, uuid.toString(), update.getOld(uuid), update.getNew(uuid));
+                        }
+                    }
                 }
                 db.removeRow(databaseName, tableName, uuid.toString());
             }
@@ -261,9 +276,10 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
 
     @Override
     public void notifyNodeAdded(Node node) {
-        OvsdbInventoryListener inventoryListener = (OvsdbInventoryListener)ServiceHelper.getGlobalInstance(OvsdbInventoryListener.class, this);
-        if (inventoryListener != null) {
-            inventoryListener.nodeAdded(node);
+        if (!ovsdbInventoryListeners.isEmpty()) {
+            for (OvsdbInventoryListener listener : ovsdbInventoryListeners) {
+                listener.nodeAdded(node);
+            }
         }
     }
 
@@ -282,9 +298,10 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
 
     @Override
     public void removeNode(Node node) {
-        OvsdbInventoryListener inventoryListener = (OvsdbInventoryListener)ServiceHelper.getGlobalInstance(OvsdbInventoryListener.class, this);
-        if (inventoryListener != null) {
-            inventoryListener.nodeRemoved(node);
+        if (!ovsdbInventoryListeners.isEmpty()) {
+            for (OvsdbInventoryListener listener : ovsdbInventoryListeners) {
+                listener.nodeRemoved(node);
+            }
         }
 
         for (IPluginOutInventoryService service : pluginOutInventoryServices) {
@@ -298,4 +315,12 @@ public class InventoryService implements IPluginInInventoryService, InventorySer
     public Set<Node> getConfiguredNotConnectedNodes() {
         return Collections.emptySet();
     }
+
+    private void listenerAdded(OvsdbInventoryListener listener) {
+        this.ovsdbInventoryListeners.add(listener);
+    }
+
+    private void listenerRemoved(OvsdbInventoryListener listener) {
+        this.ovsdbInventoryListeners.remove(listener);
+    }
 }