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 4bee2537656e3ac1ddfda162cd20735939a50a58..c0d1b50a4657a314fbcdd7010fdb89d28e72ffa8 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 fdba533b5bfa827bf2ccd79bf2f061785d06d597..e2d8f6b03b270f7f602de6b4470bc0a971487f61 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 76c38664d4d44adde2e799d1f5ff595702aa0c67..79edd93c67466a6da6820fe654dd0aeea95ac656 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 22a4343f332ed2e79e7f7ecc979d8535acc4ea26..b94ffec1ddba5d1f6cc699813d22fea6b02c7c0e 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();
     }
 
     /**