Fix Connection manager to retrieve inventory when is up 76/976/1
authorGiovanni Meo <gmeo@cisco.com>
Thu, 22 Aug 2013 20:53:26 +0000 (22:53 +0200)
committerGiovanni Meo <gmeo@cisco.com>
Thu, 22 Aug 2013 20:53:26 +0000 (22:53 +0200)
When ConnectionManager comes up, it's very much possible that may have
missed some inventory updates, so it needs to retrieve them to make
sure holes are covered, this is seen during integration test with the
stub protocol plugin, hence also make sure stub protocol plugin
provides the necessary hooks.

Change-Id: I41d5c71dd70aad909f7a75e0f596ec69a212400c
Signed-off-by: Giovanni Meo <gmeo@cisco.com>
opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/internal/Activator.java
opendaylight/connectionmanager/implementation/src/main/java/org/opendaylight/controller/connectionmanager/internal/ConnectionManager.java
opendaylight/protocol_plugins/stub/src/main/java/org/opendaylight/controller/protocol_plugins/stub/internal/Activator.java
opendaylight/protocol_plugins/stub/src/main/java/org/opendaylight/controller/protocol_plugins/stub/internal/InventoryService.java

index 4bee253..c0d1b50 100644 (file)
@@ -25,6 +25,7 @@ import org.apache.felix.dm.Component;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
+import org.opendaylight.controller.sal.inventory.IInventoryService;
 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
 
 public class Activator extends ComponentActivatorAbstractBase {
@@ -37,6 +38,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * ComponentActivatorAbstractBase.
      *
      */
+    @Override
     public void init() {
     }
 
@@ -45,6 +47,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * cleanup done by ComponentActivatorAbstractBase
      *
      */
+    @Override
     public void destroy() {
     }
 
@@ -61,6 +64,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * @return The list of implementations the bundle will support,
      * in Global version
      */
+    @Override
     protected Object[] getGlobalImplementations() {
         Object[] res = { ConnectionManager.class };
         return res;
@@ -74,6 +78,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * @param imp implementation to be configured
      * @param containerName container on which the configuration happens
      */
+    @Override
     protected void configureGlobalInstance(Component c, Object imp) {
         if (imp.equals(ConnectionManager.class)) {
             Dictionary<String, Object> props = new Hashtable<String, Object>();
@@ -100,6 +105,9 @@ public class Activator extends ComponentActivatorAbstractBase {
             c.add(createServiceDependency().setService(IConnectionService.class)
                     .setCallbacks("setConnectionService", "unsetConnectionService")
                     .setRequired(true));
+            c.add(createServiceDependency().setService(IInventoryService.class, "(scope=Global)")
+                    .setCallbacks("setInventoryService", "unsetInventoryService")
+                    .setRequired(true));
         }
     }
 }
index fdba533..e2d8f6b 100644 (file)
@@ -32,7 +32,6 @@ import java.util.concurrent.LinkedBlockingQueue;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import org.eclipse.osgi.framework.console.CommandInterpreter;
 import org.eclipse.osgi.framework.console.CommandProvider;
 import org.opendaylight.controller.clustering.services.ICacheUpdateAware;
@@ -49,6 +48,7 @@ import org.opendaylight.controller.sal.core.Node;
 import org.opendaylight.controller.sal.core.NodeConnector;
 import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.core.UpdateType;
+import org.opendaylight.controller.sal.inventory.IInventoryService;
 import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates;
 import org.opendaylight.controller.sal.utils.Status;
 import org.opendaylight.controller.sal.utils.StatusCode;
@@ -66,6 +66,7 @@ public class ConnectionManager implements IConnectionManager, IConnectionListene
     private IConnectionService connectionService;
     private Thread connectionEventThread;
     private BlockingQueue<ConnectionMgmtEvent> connectionEvents;
+    private IInventoryService inventoryService;
 
     public void setClusterServices(IClusterGlobalServices i) {
         this.clusterServices = i;
@@ -87,12 +88,48 @@ public class ConnectionManager implements IConnectionManager, IConnectionListene
         }
     }
 
+    public void setInventoryService(IInventoryService service) {
+        logger.trace("Got inventory service set request {}", service);
+        this.inventoryService = service;
+    }
+
+    public void unsetInventoryService(IInventoryService service) {
+        logger.trace("Got a service UNset request");
+        this.inventoryService = null;
+    }
+
+    private void getInventories() {
+        Map<Node, Map<String, Property>> nodeProp = this.inventoryService.getNodeProps();
+        for (Map.Entry<Node, Map<String, Property>> entry : nodeProp.entrySet()) {
+            Node node = entry.getKey();
+            logger.debug("getInventories for node:{}", new Object[] { node });
+            Map<String, Property> propMap = entry.getValue();
+            Set<Property> props = new HashSet<Property>();
+            for (Property property : propMap.values()) {
+                props.add(property);
+            }
+            updateNode(node, UpdateType.ADDED, props);
+        }
+
+        Map<NodeConnector, Map<String, Property>> nodeConnectorProp = this.inventoryService.getNodeConnectorProps();
+        for (Map.Entry<NodeConnector, Map<String, Property>> entry : nodeConnectorProp.entrySet()) {
+            Map<String, Property> propMap = entry.getValue();
+            Set<Property> props = new HashSet<Property>();
+            for (Property property : propMap.values()) {
+                props.add(property);
+            }
+            updateNodeConnector(entry.getKey(), UpdateType.ADDED, props);
+        }
+    }
+
     public void started() {
         connectionEventThread = new Thread(new EventHandler(), "ConnectionEvent Thread");
         connectionEventThread.start();
 
         registerWithOSGIConsole();
         notifyClusterViewChanged();
+        // Should pull the Inventory updates in case we missed it
+        getInventories();
     }
 
     public void init() {
index 76c3866..79edd93 100644 (file)
@@ -40,6 +40,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * are done by the ComponentActivatorAbstractBase.
      *
      */
+    @Override
     public void init() {
         Node.NodeIDType.registerIDType("STUB", Integer.class);
         NodeConnector.NodeConnectorIDType.registerIDType("STUB", Integer.class, "STUB");
@@ -50,6 +51,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      * ComponentActivatorAbstractBase
      *
      */
+    @Override
     public void destroy() {
         Node.NodeIDType.unRegisterIDType("STUB");
         NodeConnector.NodeConnectorIDType.unRegisterIDType("STUB");
@@ -64,6 +66,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      *         instantiated in order to get an fully working implementation
      *         Object
      */
+    @Override
     public Object[] getImplementations() {
         Object[] res = { ReadService.class, InventoryService.class };
         return res;
@@ -84,6 +87,7 @@ public class Activator extends ComponentActivatorAbstractBase {
      *            per-container different behavior if needed, usually should not
      *            be the case though.
      */
+    @Override
     public void configureInstance(Component c, Object imp, String containerName) {
         if (imp.equals(ReadService.class)) {
             // export the service to be used by SAL
@@ -104,11 +108,18 @@ public class Activator extends ComponentActivatorAbstractBase {
         }
     }
 
+    @Override
     public Object[] getGlobalImplementations() {
-        Object[] res = { FlowProgrammerService.class, StubNodeFactory.class, StubNodeConnectorFactory.class };
+        Object[] res =
+                {
+                        FlowProgrammerService.class,
+                        StubNodeFactory.class,
+                        StubNodeConnectorFactory.class,
+                        InventoryService.class };
         return res;
     }
 
+    @Override
     public void configureGlobalInstance(Component c, Object imp){
         if (imp.equals(FlowProgrammerService.class)) {
             // export the service to be used by SAL
@@ -136,6 +147,17 @@ public class Activator extends ComponentActivatorAbstractBase {
             props.put("protocolName", "STUB");
             c.setInterface(INodeConnectorFactory.class.getName(), props);
         }
-
+        if (imp.equals(InventoryService.class)) {
+            // export the service to be used by SAL
+            Dictionary<String, Object> props = new Hashtable<String, Object>();
+            // Set the protocolPluginType property which will be used
+            // by SAL
+            props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), "STUB");
+            props.put("scope", "Global");
+            c.setInterface(IPluginInInventoryService.class.getName(), props);
+            c.add(createServiceDependency().setService(IPluginOutInventoryService.class, "(scope=Global)")
+                    .setCallbacks("setPluginOutInventoryServices", "unsetPluginOutInventoryServices")
+                    .setRequired(true));
+        }
     }
 }
index 22a4343..b94ffec 100644 (file)
@@ -12,11 +12,11 @@ import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.CopyOnWriteArraySet;
 
 import org.apache.felix.dm.Component;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-
 import org.opendaylight.controller.sal.core.Actions;
 import org.opendaylight.controller.sal.core.Bandwidth;
 import org.opendaylight.controller.sal.core.Buffers;
@@ -29,7 +29,9 @@ import org.opendaylight.controller.sal.core.Property;
 import org.opendaylight.controller.sal.core.State;
 import org.opendaylight.controller.sal.core.Tables;
 import org.opendaylight.controller.sal.core.TimeStamp;
+import org.opendaylight.controller.sal.core.UpdateType;
 import org.opendaylight.controller.sal.inventory.IPluginInInventoryService;
+import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService;
 import org.opendaylight.controller.sal.utils.NodeCreator;
 import org.opendaylight.controller.sal.utils.NodeConnectorCreator;
 
@@ -55,6 +57,22 @@ public class InventoryService implements IPluginInInventoryService {
                                                                                     // global
                                                                                     // container
                                                                                     // only
+    private final Set<IPluginOutInventoryService> pluginOutInventoryServices =
+            new CopyOnWriteArraySet<IPluginOutInventoryService>();
+
+    public void setPluginOutInventoryServices(IPluginOutInventoryService service) {
+        logger.trace("Got a service set request {}", service);
+        if (this.pluginOutInventoryServices != null) {
+            this.pluginOutInventoryServices.add(service);
+        }
+    }
+
+    public void unsetPluginOutInventoryServices(IPluginOutInventoryService service) {
+        logger.trace("Got a service UNset request");
+        if (this.pluginOutInventoryServices != null) {
+            this.pluginOutInventoryServices.remove(service);
+        }
+    }
 
     /**
      * Function called by the dependency manager when all the required
@@ -173,6 +191,29 @@ public class InventoryService implements IPluginInInventoryService {
     void start() {
     }
 
+    /**
+     * Method called when the plugin has exposed it's services, this will be
+     * used to publish the updates so connection manager can think the
+     * connection is local
+     */
+    void started() {
+        // update sal and discovery
+        for (IPluginOutInventoryService service : pluginOutInventoryServices) {
+            for (Node node : nodeProps.keySet()) {
+                Set<Property> props = new HashSet<Property>(nodeProps.get(node)
+                        .values());
+                service.updateNode(node, UpdateType.ADDED, props);
+                logger.trace("Adding Node {} with props {}", node, props);
+            }
+            for (NodeConnector nc : nodeConnectorProps.keySet()) {
+                Set<Property> props = new HashSet<Property>(nodeConnectorProps.get(nc)
+                        .values());
+                service.updateNodeConnector(nc, UpdateType.ADDED, props);
+                logger.trace("Adding NodeConnectors {} with props {}", nc, props);
+            }
+        }
+    }
+
     /**
      * Function called by the dependency manager before the services exported by
      * the component are unregistered, this will be followed by a "destroy ()"
@@ -180,6 +221,7 @@ public class InventoryService implements IPluginInInventoryService {
      *
      */
     void stop() {
+        pluginOutInventoryServices.clear();
     }
 
     /**