Use DataTreeChangeListener instead of DataChangeListener 78/37478/9
authorStephen Kitt <skitt@redhat.com>
Thu, 31 Mar 2016 14:58:00 +0000 (16:58 +0200)
committerStephen Kitt <skitt@redhat.com>
Mon, 18 Apr 2016 16:49:09 +0000 (18:49 +0200)
For now this patch sticks to the old approach, where we just listen
for all Node events and rebuild the changes and re-extract them.

Change-Id: I0f8e4ed09998a28326d39306cbb1b3486260e7f8
Signed-off-by: Stephen Kitt <skitt@redhat.com>
29 files changed:
southbound/southbound-impl/pom.xml
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/OvsdbConnectionInstance.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/OvsdbDataTreeChangeListener.java [new file with mode: 0644]
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/SouthboundProvider.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/AutoAttachRemovedCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/AutoAttachUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/BridgeOperationalState.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/BridgeRemovedCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/BridgeUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/ControllerRemovedCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/ControllerUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/OpenVSwitchBridgeAddCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/OvsdbNodeUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/ProtocolRemovedCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/ProtocolUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QosRemovedCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QosUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QueueRemovedCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/QueueUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TerminationPointCreateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TerminationPointDeleteCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TerminationPointUpdateCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactCommand.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactCommandAggregator.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactInvoker.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactInvokerImpl.java
southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/ovsdb/transact/TransactUtils.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbDataChangeListenerTest.java
southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbDataTreeChangeListenerTest.java [new file with mode: 0644]

index 062bf28e41655e6f3cb694d6fc7d1abbbc316ddd..3b908b6c625c4c062a3fb830c9684f79af368fe5 100644 (file)
@@ -106,6 +106,12 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.ovsdb</groupId>
+      <artifactId>utils.southbound-utils</artifactId>
+      <version>1.3.0-SNAPSHOT</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
   <build>
     <plugins>
index 516cd2202ad40fb97d37aeb1c939730bc25affbc..69907f2b5b06b8caee9e9eec423cfb27bac05268 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.ovsdb.southbound;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -18,6 +19,7 @@ import java.util.concurrent.ExecutionException;
 
 import javax.annotation.Nonnull;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidateRegistration;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
@@ -88,6 +90,13 @@ public class OvsdbConnectionInstance implements OvsdbClient {
         this.instanceIdentifier = iid;
     }
 
+    /**
+     * Apply the given command to the given events, based on the given bridge state.
+     *
+     * @param command The command to run.
+     * @param state The current bridge state.
+     * @param events The events to process.
+     */
     public void transact(TransactCommand command, BridgeOperationalState state,
                  AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> events) {
         for (TransactInvoker transactInvoker : transactInvokers.values()) {
@@ -95,6 +104,20 @@ public class OvsdbConnectionInstance implements OvsdbClient {
         }
     }
 
+    /**
+     * Apply the given command to the given modifications, based on the given bridge state.
+     *
+     * @param command The command to run.
+     * @param state The current bridge state.
+     * @param modifications The modifications to process.
+     */
+    public void transact(TransactCommand command, BridgeOperationalState state,
+                 Collection<DataTreeModification<Node>> modifications) {
+        for (TransactInvoker transactInvoker : transactInvokers.values()) {
+            transactInvoker.invoke(command, state, modifications);
+        }
+    }
+
     public void registerCallbacks() {
         if ( this.callback == null) {
             if (this.initialCreateData != null ) {
diff --git a/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/OvsdbDataTreeChangeListener.java b/southbound/southbound-impl/src/main/java/org/opendaylight/ovsdb/southbound/OvsdbDataTreeChangeListener.java
new file mode 100644 (file)
index 0000000..2c0d709
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright © 2016 Red Hat, Inc. 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
+ */
+
+package org.opendaylight.ovsdb.southbound;
+
+import java.net.UnknownHostException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.OvsdbClient;
+import org.opendaylight.ovsdb.southbound.ovsdb.transact.BridgeOperationalState;
+import org.opendaylight.ovsdb.southbound.ovsdb.transact.TransactCommandAggregator;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.node.TerminationPoint;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Data-tree change listener for OVSDB.
+ */
+public class OvsdbDataTreeChangeListener implements ClusteredDataTreeChangeListener<Node>, AutoCloseable {
+
+    /** Our registration. */
+    private final ListenerRegistration<DataTreeChangeListener<Node>> registration;
+
+    /** The connection manager. */
+    private final OvsdbConnectionManager cm;
+
+    /** The data broker. */
+    private final DataBroker db;
+
+    /** Logger. */
+    private static final Logger LOG = LoggerFactory.getLogger(OvsdbDataTreeChangeListener.class);
+
+    /**
+     * Create an instance and register the listener.
+     *
+     * @param db The data broker.
+     * @param cm The connection manager.
+     */
+    OvsdbDataTreeChangeListener(DataBroker db, OvsdbConnectionManager cm) {
+        LOG.info("Registering OvsdbNodeDataChangeListener");
+        this.cm = cm;
+        this.db = db;
+        InstanceIdentifier<Node> path = InstanceIdentifier
+                .create(NetworkTopology.class)
+                .child(Topology.class, new TopologyKey(SouthboundConstants.OVSDB_TOPOLOGY_ID))
+                .child(Node.class);
+        DataTreeIdentifier<Node> dataTreeIdentifier =
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, path);
+        registration = db.registerDataTreeChangeListener(dataTreeIdentifier, this);
+    }
+
+    @Override
+    public void close() {
+        registration.close();
+    }
+
+    @Override
+    public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Node>> changes) {
+        LOG.trace("onDataTreeChanged: {}", changes);
+
+        // Connect first if necessary
+        connect(changes);
+
+        // Update connections if necessary
+        updateConnections(changes);
+
+        // Update the actual data
+        updateData(changes);
+
+        // Disconnect if necessary
+        disconnect(changes);
+
+        LOG.trace("onDataTreeChanged: exit");
+    }
+
+    private void connect(@Nonnull Collection<DataTreeModification<Node>> changes) {
+        for (DataTreeModification<Node> change : changes) {
+            if (change.getRootNode().getModificationType() == DataObjectModification.ModificationType.WRITE || change
+                    .getRootNode().getModificationType() == DataObjectModification.ModificationType.SUBTREE_MODIFIED) {
+                DataObjectModification<OvsdbNodeAugmentation> ovsdbNodeModification =
+                        change.getRootNode().getModifiedAugmentation(OvsdbNodeAugmentation.class);
+                if (ovsdbNodeModification != null && ovsdbNodeModification.getDataBefore() == null
+                        && ovsdbNodeModification.getDataAfter() != null) {
+                    OvsdbNodeAugmentation ovsdbNode = ovsdbNodeModification.getDataAfter();
+                    ConnectionInfo key = ovsdbNode.getConnectionInfo();
+                    InstanceIdentifier<Node> iid = cm.getInstanceIdentifier(key);
+                    if ( iid != null) {
+                        LOG.warn("Connection to device {} already exists. Plugin does not allow multiple connections "
+                                + "to same device, hence dropping the request {}", key, ovsdbNode);
+                    } else {
+                        try {
+                            InstanceIdentifier<Node> instanceIdentifier = change.getRootPath().getRootIdentifier();
+                            LOG.info("Connecting on key {} to {}", instanceIdentifier, ovsdbNode);
+                            cm.connect(instanceIdentifier, ovsdbNode);
+                        } catch (UnknownHostException e) {
+                            LOG.warn("Failed to connect to ovsdbNode", e);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void disconnect(@Nonnull Collection<DataTreeModification<Node>> changes) {
+        for (DataTreeModification<Node> change : changes) {
+            if (change.getRootNode().getModificationType() == DataObjectModification.ModificationType.DELETE) {
+                DataObjectModification<OvsdbNodeAugmentation> ovsdbNodeModification =
+                        change.getRootNode().getModifiedAugmentation(OvsdbNodeAugmentation.class);
+                if (ovsdbNodeModification != null && ovsdbNodeModification.getDataBefore() != null) {
+                    OvsdbNodeAugmentation ovsdbNode = ovsdbNodeModification.getDataBefore();
+                    ConnectionInfo key = ovsdbNode.getConnectionInfo();
+                    InstanceIdentifier<Node> iid = cm.getInstanceIdentifier(key);
+                    try {
+                        LOG.info("Disconnecting from {}", ovsdbNode);
+                        cm.disconnect(ovsdbNode);
+                        cm.stopConnectionReconciliationIfActive(iid.firstIdentifierOf(Node.class), ovsdbNode);
+                    } catch (UnknownHostException e) {
+                        LOG.warn("Failed to disconnect ovsdbNode", e);
+                    }
+                }
+            }
+        }
+    }
+
+    private void updateConnections(@Nonnull Collection<DataTreeModification<Node>> changes) {
+        for (DataTreeModification<Node> change : changes) {
+            if (change.getRootNode().getModificationType() == DataObjectModification.ModificationType.WRITE || change
+                    .getRootNode().getModificationType() == DataObjectModification.ModificationType.SUBTREE_MODIFIED) {
+                DataObjectModification<OvsdbNodeAugmentation> ovsdbNodeModification =
+                        change.getRootNode().getModifiedAugmentation(OvsdbNodeAugmentation.class);
+                if (ovsdbNodeModification != null && ovsdbNodeModification.getDataBefore() != null
+                        && ovsdbNodeModification.getDataAfter() != null) {
+                    OvsdbClient client = cm.getClient(ovsdbNodeModification.getDataAfter().getConnectionInfo());
+                    if (client == null) {
+                        if (ovsdbNodeModification.getDataBefore() != null) {
+                            try {
+                                cm.disconnect(ovsdbNodeModification.getDataBefore());
+                                cm.connect(change.getRootPath().getRootIdentifier(), ovsdbNodeModification
+                                        .getDataAfter());
+                            } catch (UnknownHostException e) {
+                                LOG.warn("Error disconnecting from or connecting to ovsdbNode", e);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void updateData(@Nonnull Collection<DataTreeModification<Node>> changes) {
+        for (Entry<InstanceIdentifier<Node>, OvsdbConnectionInstance> connectionInstanceEntry :
+                connectionInstancesFromChanges(changes).entrySet()) {
+            OvsdbConnectionInstance connectionInstance = connectionInstanceEntry.getValue();
+            connectionInstance.transact(new TransactCommandAggregator(),
+                    new BridgeOperationalState(db, changes), changes);
+        }
+    }
+
+    private Map<InstanceIdentifier<Node>, OvsdbConnectionInstance> connectionInstancesFromChanges(
+            @Nonnull Collection<DataTreeModification<Node>> changes) {
+        Map<InstanceIdentifier<Node>,OvsdbConnectionInstance> result =
+                new HashMap<>();
+        for (DataTreeModification<Node> change : changes) {
+            DataObjectModification<OvsdbBridgeAugmentation> bridgeModification =
+                    change.getRootNode().getModifiedAugmentation(OvsdbBridgeAugmentation.class);
+            OvsdbConnectionInstance client = null;
+            Node node = change.getRootNode().getDataAfter();
+            if (bridgeModification != null && bridgeModification.getDataAfter() != null) {
+                client = cm.getConnectionInstance(bridgeModification.getDataAfter());
+            } else {
+                DataObjectModification<OvsdbNodeAugmentation> nodeModification =
+                        change.getRootNode().getModifiedAugmentation(OvsdbNodeAugmentation.class);
+                if (nodeModification != null && nodeModification.getDataAfter() != null && nodeModification
+                        .getDataAfter().getConnectionInfo() != null) {
+                    client = cm.getConnectionInstance(nodeModification.getDataAfter().getConnectionInfo());
+                } else {
+                    if (node != null) {
+                        List<TerminationPoint> terminationPoints = node.getTerminationPoint();
+                        if (terminationPoints != null && !terminationPoints.isEmpty()) {
+                            InstanceIdentifier<Node> nodeIid = SouthboundMapper.createInstanceIdentifier(
+                                    node.getNodeId());
+                            client = cm.getConnectionInstance(nodeIid);
+                        }
+                    }
+                }
+            }
+            if (client != null) {
+                LOG.debug("Found client for {}", node);
+                    /*
+                     * As of now data change sets are processed by single thread, so we can assume that device will
+                     * be connected and ownership will be decided before sending any instructions down to the device.
+                     * Note:Processing order in onDataChange() method should not change. If processing is changed to
+                     * use multiple thread, we might need to take care of corner cases, where ownership is not decided
+                     * but transaction are ready to go to switch. In that scenario, either we need to queue those task
+                     * till ownership is decided for that specific device.
+                     * Given that each DataChangeNotification is notified through separate thread, so we are already
+                     * multi threaded and i don't see any need to further parallelism per DataChange
+                     * notifications processing.
+                     */
+                if ( cm.getHasDeviceOwnership(client.getMDConnectionInfo())) {
+                    LOG.debug("*This* instance of southbound plugin is an owner of the device {}", node);
+                    result.put(change.getRootPath().getRootIdentifier(), client);
+                } else {
+                    LOG.debug("*This* instance of southbound plugin is *not* an owner of the device {}", node);
+                }
+            } else {
+                LOG.debug("Did not find client for {}", node);
+            }
+        }
+        return result;
+    }
+}
index a331a2ab5d6c83661d9df46d35a148ad9e70b757..28e93c4e44d496c64024ed9941d41890be3d10ca 100644 (file)
@@ -48,7 +48,7 @@ public class SouthboundProvider implements BindingAwareProvider, AutoCloseable {
     private static DataBroker db;
     private OvsdbConnectionManager cm;
     private TransactionInvoker txInvoker;
-    private OvsdbDataChangeListener ovsdbDataChangeListener;
+    private OvsdbDataTreeChangeListener ovsdbDataTreeChangeListener;
     private EntityOwnershipService entityOwnershipService;
     private EntityOwnershipCandidateRegistration registration;
     private SouthboundPluginInstanceEntityOwnershipListener providerOwnershipChangeListener;
@@ -70,7 +70,7 @@ public class SouthboundProvider implements BindingAwareProvider, AutoCloseable {
         db = session.getSALService(DataBroker.class);
         this.txInvoker = new TransactionInvokerImpl(db);
         cm = new OvsdbConnectionManager(db,txInvoker,entityOwnershipService, ovsdbConnection);
-        ovsdbDataChangeListener = new OvsdbDataChangeListener(db,cm);
+        ovsdbDataTreeChangeListener = new OvsdbDataTreeChangeListener(db, cm);
 
         //Register listener for entityOnwership changes
         providerOwnershipChangeListener =
@@ -100,7 +100,7 @@ public class SouthboundProvider implements BindingAwareProvider, AutoCloseable {
     public void close() {
         LOG.info("SouthboundProvider Closed");
         cm.close();
-        ovsdbDataChangeListener.close();
+        ovsdbDataTreeChangeListener.close();
         registration.close();
         providerOwnershipChangeListener.close();
     }
index 8fd2a66559b4841c1c3488aaf99f6ac533d3b349..feb537f6183d9042a4928efcf3e49fc2459154c0 100644 (file)
@@ -10,10 +10,12 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -38,12 +40,18 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
 import com.google.common.collect.Sets;
 
 public class AutoAttachRemovedCommand implements TransactCommand {
     private static final Logger LOG = LoggerFactory.getLogger(AutoAttachRemovedCommand.class);
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractOriginal(modifications, OvsdbNodeAugmentation.class),
+                TransactUtils.extractUpdated(modifications, OvsdbNodeAugmentation.class));
+    }
+
     @Override
     public void execute(TransactionBuilder transaction, BridgeOperationalState state,
                         AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> events) {
index 593bbb99986e7907933a46385f3e6b0167b91093..4c320094d49ba36d477c1dc21e355f4d0e44a783 100644 (file)
@@ -10,12 +10,14 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.ExecutionException;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -58,6 +60,12 @@ public class AutoAttachUpdateCommand implements TransactCommand {
         execute(transaction, state, TransactUtils.extractCreatedOrUpdated(events, OvsdbNodeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractCreatedOrUpdated(modifications, OvsdbNodeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                          Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> createdOrUpdated) {
 
index 86e60e9cad4553107af0d4378e57ca3532968879..1a6cb96d0a01b53c75fe1639de1bb3e50e4516d9 100644 (file)
@@ -8,12 +8,14 @@
 
 package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.concurrent.ExecutionException;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -61,6 +63,23 @@ public class BridgeOperationalState {
         transaction.close();
     }
 
+    public BridgeOperationalState(DataBroker db, Collection<DataTreeModification<Node>> changes) {
+        ReadOnlyTransaction transaction = db.newReadOnlyTransaction();
+        Map<InstanceIdentifier<Node>, Node> nodeCreateOrUpdateOrRemove =
+                TransactUtils.extractCreatedOrUpdatedOrRemoved(changes, Node.class);
+        for (Entry<InstanceIdentifier<Node>, Node> entry : nodeCreateOrUpdateOrRemove.entrySet()) {
+            try {
+                Optional<Node> nodeOptional = transaction.read(LogicalDatastoreType.OPERATIONAL, entry.getKey())
+                            .checkedGet();
+                if (nodeOptional.isPresent()) {
+                    operationalNodes.put(entry.getKey(), nodeOptional.get());
+                }
+            } catch (ReadFailedException e) {
+                LOG.warn("Error reading from datastore", e);
+            }
+        }
+    }
+
     public Optional<Node> getBridgeNode(InstanceIdentifier<?> iid) {
         InstanceIdentifier<Node> nodeIid = iid.firstIdentifierOf(Node.class);
         return Optional.fromNullable(operationalNodes.get(nodeIid));
index ebd1c140faf91d8635848a298f9261d6ede67961..ef6c2d6df9f3c1a0b43369e791ed3579e1b7cfaf 100644 (file)
@@ -10,9 +10,11 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
 import org.opendaylight.ovsdb.lib.notation.UUID;
@@ -21,6 +23,7 @@ import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -39,6 +42,13 @@ public class BridgeRemovedCommand implements TransactCommand {
                 TransactUtils.extractOriginal(events, OvsdbBridgeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractRemoved(modifications, OvsdbBridgeAugmentation.class),
+                TransactUtils.extractOriginal(modifications, OvsdbBridgeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state, Set<InstanceIdentifier<OvsdbBridgeAugmentation>> removed,
                          Map<InstanceIdentifier<OvsdbBridgeAugmentation>, OvsdbBridgeAugmentation> originals) {
         for (InstanceIdentifier<OvsdbBridgeAugmentation> ovsdbManagedNodeIid: removed) {
index 5f04ff018d610e16e46fd102d4210f2aeb6feab9..676a2aaa0758c501d6c39f7df20434da6a907830 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
@@ -16,6 +17,7 @@ import java.util.Map.Entry;
 
 import javax.annotation.Nonnull;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.Insert;
@@ -53,6 +55,13 @@ public class BridgeUpdateCommand implements TransactCommand {
         execute(transaction, state, TransactUtils.extractCreatedOrUpdated(events, OvsdbBridgeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state,
+                TransactUtils.extractCreatedOrUpdated(modifications, OvsdbBridgeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                         Map<InstanceIdentifier<OvsdbBridgeAugmentation>, OvsdbBridgeAugmentation> createdOrUpdated) {
         for (Entry<InstanceIdentifier<OvsdbBridgeAugmentation>, OvsdbBridgeAugmentation> ovsdbManagedNodeEntry :
index dd9e630b3235b37c0a77578e285609406af462bb..2e75636fb4d9a790af0ab838b6a129468685b9bc 100644 (file)
@@ -9,9 +9,11 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
 import org.opendaylight.ovsdb.lib.notation.UUID;
@@ -20,6 +22,7 @@ import org.opendaylight.ovsdb.lib.schema.typed.TyperUtils;
 import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -35,6 +38,13 @@ public class ControllerRemovedCommand implements TransactCommand {
                 TransactUtils.extractCreatedOrUpdatedOrRemoved(events, OvsdbBridgeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractRemoved(modifications, ControllerEntry.class),
+                TransactUtils.extractCreatedOrUpdatedOrRemoved(modifications, OvsdbBridgeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                          Set<InstanceIdentifier<ControllerEntry>> removedControllers,
                          Map<InstanceIdentifier<OvsdbBridgeAugmentation>, OvsdbBridgeAugmentation>
index 8e55699df4ba54c2612da43380dc61763dc69912..4737cf13578ebde82099ff980024fd18d54d1dc4 100644 (file)
@@ -9,9 +9,11 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
 import org.opendaylight.ovsdb.lib.notation.UUID;
@@ -22,6 +24,7 @@ import org.opendaylight.ovsdb.schema.openvswitch.Controller;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ControllerEntry;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -40,6 +43,13 @@ public class ControllerUpdateCommand implements TransactCommand {
                 TransactUtils.extractCreatedOrUpdated(events, OvsdbBridgeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractCreatedOrUpdated(modifications, ControllerEntry.class),
+                TransactUtils.extractCreatedOrUpdated(modifications, OvsdbBridgeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                          Map<InstanceIdentifier<ControllerEntry>, ControllerEntry> controllers,
                          Map<InstanceIdentifier<OvsdbBridgeAugmentation>, OvsdbBridgeAugmentation> bridges) {
index b8bcf0bfc0086b0b2ba341ba7c4c0cb30e2daf6b..b90df1225629025514e9ef9d64c9780e4543b02f 100644 (file)
@@ -10,8 +10,10 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.List;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
 import org.opendaylight.ovsdb.lib.operations.Insert;
@@ -21,6 +23,7 @@ import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.schema.openvswitch.OpenVSwitch;
 
 import com.google.common.collect.Sets;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -32,6 +35,12 @@ public class OpenVSwitchBridgeAddCommand implements TransactCommand {
         execute(transaction);
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction);
+    }
+
     private void execute(TransactionBuilder transaction) {
         Bridge bridge = TyperUtils.getTypedRowWrapper(transaction.getDatabaseSchema(), Bridge.class);
         List<Insert> inserts = TransactUtils.extractInsert(transaction, bridge.getSchema());
index ba24c908d699f42dd3c18de2e1ca3ecbf9f2db0e..a79bbcadee381b4d3352d232b1c1cd4096a7a191 100644 (file)
@@ -9,11 +9,13 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
 import org.opendaylight.ovsdb.lib.operations.Mutate;
@@ -40,6 +42,12 @@ public class OvsdbNodeUpdateCommand implements TransactCommand {
         execute(transaction, TransactUtils.extractCreatedOrUpdated(events, OvsdbNodeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, TransactUtils.extractCreatedOrUpdated(modifications, OvsdbNodeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction,
                          Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> updated) {
         for (Entry<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> ovsdbNodeEntry:
index 79184c58f7e1f1ecf94e1b7e6788577c1d0d1e99..cb94560034f618608f174d1878498ea829029c09 100644 (file)
@@ -10,9 +10,11 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
@@ -22,6 +24,7 @@ import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -41,6 +44,13 @@ public class ProtocolRemovedCommand implements TransactCommand {
                 TransactUtils.extractCreatedOrUpdatedOrRemoved(events, OvsdbBridgeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractRemoved(modifications, ProtocolEntry.class),
+                TransactUtils.extractCreatedOrUpdatedOrRemoved(modifications, OvsdbBridgeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state, Set<InstanceIdentifier<ProtocolEntry>> removed,
                          Map<InstanceIdentifier<OvsdbBridgeAugmentation>, OvsdbBridgeAugmentation> updatedBridges) {
         for (InstanceIdentifier<ProtocolEntry> protocolIid : removed) {
index a42c6a4890a25ad69ecfd7b1248b6d50d68cb7b6..3eb9f460da1c7615daaa073ca077cd64785e4b9b 100644 (file)
@@ -10,9 +10,11 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
@@ -22,6 +24,7 @@ import org.opendaylight.ovsdb.schema.openvswitch.Bridge;
 import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbBridgeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.bridge.attributes.ProtocolEntry;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -41,6 +44,13 @@ public class ProtocolUpdateCommand implements TransactCommand {
                 TransactUtils.extractCreatedOrUpdated(events, OvsdbBridgeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractCreatedOrUpdated(modifications, ProtocolEntry.class),
+                TransactUtils.extractCreatedOrUpdated(modifications, OvsdbBridgeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                          Map<InstanceIdentifier<ProtocolEntry>, ProtocolEntry> protocols,
                          Map<InstanceIdentifier<OvsdbBridgeAugmentation>, OvsdbBridgeAugmentation> bridges) {
index 4abcd53e05c18637cace02a40d9c2ebd003716dc..8822cd8f0db8b82516c81edbf23a9e7a07dd417b 100644 (file)
@@ -10,9 +10,11 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
@@ -22,6 +24,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.QosEntries;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -38,6 +41,14 @@ public class QosRemovedCommand implements TransactCommand {
                 TransactUtils.extractUpdated(events, OvsdbNodeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state,
+                TransactUtils.extractOriginal(modifications, OvsdbNodeAugmentation.class),
+                TransactUtils.extractUpdated(modifications, OvsdbNodeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                         Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> originals,
                         Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> updated) {
index e4deca17a3fb7a687d8273b9ba1bd882fd555725..4f1cb86da4040d6135d6aa5e93da0a235dfa30c9 100644 (file)
@@ -9,11 +9,13 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
@@ -29,6 +31,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosExternalIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QosOtherConfig;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.qos.entries.QueueList;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -43,6 +46,12 @@ public class QosUpdateCommand implements TransactCommand {
         execute(transaction, state, TransactUtils.extractCreatedOrUpdated(events, OvsdbNodeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractCreatedOrUpdated(modifications, OvsdbNodeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                          Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> createdOrUpdated) {
         for (Entry<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> ovsdbNodeEntry:
index c9706c8957224be5c6b1bf8f075cb0da1e853fd5..2e590af0e01fc29fd7cfdd9e31dc50f4f33d5005 100644 (file)
@@ -10,9 +10,11 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
@@ -22,6 +24,7 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types.rev130715.Uuid;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.OvsdbNodeAugmentation;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Queues;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -37,6 +40,13 @@ public class QueueRemovedCommand implements TransactCommand {
                 TransactUtils.extractUpdated(events, OvsdbNodeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractOriginal(modifications, OvsdbNodeAugmentation.class),
+                TransactUtils.extractUpdated(modifications, OvsdbNodeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                          Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> originals,
                          Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> updated) {
index 76197311744afed57a5460835326663a1350eddf..6018b8572a898dcb82280756b469584d701dc47f 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -16,6 +17,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.UUID;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
@@ -29,6 +31,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.Queues;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesExternalIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.queues.QueuesOtherConfig;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -43,6 +46,12 @@ public class QueueUpdateCommand implements TransactCommand {
         execute(transaction, state, TransactUtils.extractCreatedOrUpdated(events, OvsdbNodeAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractCreatedOrUpdated(modifications, OvsdbNodeAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                          Map<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> createdOrUpdated) {
         for (Entry<InstanceIdentifier<OvsdbNodeAugmentation>, OvsdbNodeAugmentation> ovsdbNodeEntry:
index 9c102f2ed99696030fd13fdbe714634cd3b6f290..1bef344ac087c91bd1249210e7a5577614f48a03 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -18,6 +19,7 @@ import java.util.Map.Entry;
 import java.util.concurrent.ExecutionException;
 import java.util.Set;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -69,6 +71,13 @@ public class TerminationPointCreateCommand implements TransactCommand {
                 TransactUtils.extractCreatedOrUpdated(events, Node.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state, TransactUtils.extractCreated(modifications, OvsdbTerminationPointAugmentation.class),
+                TransactUtils.extractCreatedOrUpdated(modifications, Node.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                          Map<InstanceIdentifier<OvsdbTerminationPointAugmentation>,
                                  OvsdbTerminationPointAugmentation>
index b59e6db15028fb3959e7c0b5205ec6a9b461d7e4..431f4ba3b0a918de8ef9b8e281687b6491be401b 100644 (file)
@@ -9,9 +9,11 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
 import org.opendaylight.ovsdb.lib.notation.UUID;
@@ -45,6 +47,15 @@ public class TerminationPointDeleteCommand implements TransactCommand {
                 TransactUtils.extractRemoved(events, OvsdbTerminationPointAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction, state,
+                TransactUtils.extractOriginal(modifications, OvsdbTerminationPointAugmentation.class),
+                TransactUtils.extractOriginal(modifications, Node.class),
+                TransactUtils.extractRemoved(modifications, OvsdbTerminationPointAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction, BridgeOperationalState state,
                          Map<InstanceIdentifier<OvsdbTerminationPointAugmentation>, OvsdbTerminationPointAugmentation> originals,
                          Map<InstanceIdentifier<Node>, Node> originalNodes,
index 344eb92bc4deaee7ddf8378cc84e02c9f77449b6..3e91aab5e6f2a5a7e6dfd2399df0dfac1b495df1 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
@@ -16,6 +17,7 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.error.SchemaVersionMismatchException;
 import org.opendaylight.ovsdb.lib.notation.UUID;
@@ -36,6 +38,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.re
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortExternalIds;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.PortOtherConfigs;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.port._interface.attributes.Trunks;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -53,6 +56,13 @@ public class TerminationPointUpdateCommand implements TransactCommand {
         execute(transaction, TransactUtils.extractCreatedOrUpdated(events, OvsdbTerminationPointAugmentation.class));
     }
 
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        execute(transaction,
+                TransactUtils.extractCreatedOrUpdated(modifications, OvsdbTerminationPointAugmentation.class));
+    }
+
     private void execute(TransactionBuilder transaction,
                          Map<InstanceIdentifier<OvsdbTerminationPointAugmentation>,
                                  OvsdbTerminationPointAugmentation> createdOrUpdated) {
index 7d265e7213fdf92d6ceeb05ced578506496d3aa7..971e6a386a6adf3521904fb901ccf3b0662d492a 100644 (file)
@@ -7,8 +7,12 @@
  */
 package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -26,4 +30,15 @@ public interface TransactCommand {
      */
     void execute(TransactionBuilder transaction, BridgeOperationalState state,
                  AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> events);
+
+    /**
+     * Queue the command defined by the class implementing this interface in the given transaction builder, with the
+     * given bridge state, in reaction to the given modifications.
+     *
+     * @param transaction The transaction builder.
+     * @param state The bridge state.
+     * @param modifications The modifications to be represented.
+     */
+    void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                 Collection<DataTreeModification<Node>> modifications);
 }
index e3e43005875cc45757cadb7366e3fa2d6e045b9d..17bd9aa35c097f5dc1fcc52a66c079f7ee0d61b0 100644 (file)
@@ -7,8 +7,12 @@
  */
 package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -52,4 +56,16 @@ public class TransactCommandAggregator implements TransactCommand {
             }
         }
     }
+
+    @Override
+    public void execute(TransactionBuilder transaction, BridgeOperationalState state,
+                        Collection<DataTreeModification<Node>> modifications) {
+        for (Class<? extends TransactCommand> commandClass : COMMAND_CLASSES) {
+            try {
+                commandClass.newInstance().execute(transaction, state, modifications);
+            } catch (InstantiationException | IllegalAccessException e) {
+                LOG.error("Error instantiating {}", commandClass, e);
+            }
+        }
+    }
 }
index 33b7b4e4fc701c6e3d86a54be1d11a4577eecb14..5009ece165618eebb715afc20890c27bd2ac8e56 100644 (file)
@@ -7,7 +7,11 @@
  */
 package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
+import java.util.Collection;
+
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -24,4 +28,14 @@ public interface TransactInvoker {
      */
     void invoke(TransactCommand command, BridgeOperationalState state,
                 AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> events);
+
+    /**
+     * Invoke the given transactional command, with the given bridge state, on the given modifications.
+     *
+     * @param command The transactional command.
+     * @param state The bridge state.
+     * @param modifications The modifications to be processed.
+     */
+    void invoke(TransactCommand command, BridgeOperationalState state,
+                Collection<DataTreeModification<Node>> modifications);
 }
index cc7056d65b18013d7c37e785fbdb3dae1ebb6231..a179df7d326713a98f149e38bb31829c32b5c2be 100644 (file)
@@ -7,13 +7,16 @@
  */
 package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 
+import java.util.Collection;
 import java.util.List;
 
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.operations.OperationResult;
 import org.opendaylight.ovsdb.lib.operations.TransactionBuilder;
 import org.opendaylight.ovsdb.lib.schema.DatabaseSchema;
 import org.opendaylight.ovsdb.southbound.OvsdbConnectionInstance;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -39,6 +42,14 @@ public class TransactInvokerImpl implements TransactInvoker {
         invoke(command, tb);
     }
 
+    @Override
+    public void invoke(TransactCommand command, BridgeOperationalState state,
+                       Collection<DataTreeModification<Node>> modifications) {
+        TransactionBuilder tb = new TransactionBuilder(connectionInstance, dbSchema);
+        command.execute(tb, state, modifications);
+        invoke(command, tb);
+    }
+
     private void invoke(TransactCommand command, TransactionBuilder tb) {
         ListenableFuture<List<OperationResult>> result = tb.execute();
         LOG.debug("invoke: command: {}, tb: {}", command, tb);
index 0d37f5ecefa06c66b8ce03b03d35439b1a561934..26b9581fa0675e1eed73f19a85e2612bd8964f08 100644 (file)
@@ -10,13 +10,21 @@ package org.opendaylight.ovsdb.southbound.ovsdb.transact;
 import static org.opendaylight.ovsdb.lib.operations.Operations.op;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Queue;
 import java.util.Set;
 
+import javax.annotation.Nullable;
+
+import com.google.common.base.Predicate;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.ovsdb.lib.notation.Mutation;
 import org.opendaylight.ovsdb.lib.notation.Mutator;
@@ -33,8 +41,13 @@ import org.opendaylight.ovsdb.southbound.SouthboundConstants;
 import org.opendaylight.ovsdb.southbound.SouthboundMapper;
 import org.opendaylight.ovsdb.southbound.SouthboundUtil;
 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+
+import org.opendaylight.yangtools.yang.binding.ChildOf;
 import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.Identifiable;
+import org.opendaylight.yangtools.yang.binding.Identifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -47,6 +60,73 @@ import com.google.common.collect.Sets;
 public class TransactUtils {
     private static final Logger LOG = LoggerFactory.getLogger(TransactUtils.class);
 
+    private static <T extends DataObject> Predicate<DataObjectModification<T>> hasDataBefore() {
+        return new Predicate<DataObjectModification<T>>() {
+            @Override
+            public boolean apply(@Nullable DataObjectModification<T> input) {
+                return input != null && input.getDataBefore() != null;
+            }
+        };
+    }
+
+    private static <T extends DataObject> Predicate<DataObjectModification<T>> hasDataBeforeAndDataAfter() {
+        return new Predicate<DataObjectModification<T>>() {
+            @Override
+            public boolean apply(@Nullable DataObjectModification<T> input) {
+                return input != null && input.getDataBefore() != null && input.getDataAfter() != null;
+            }
+        };
+    }
+
+    private static <T extends DataObject> Predicate<DataObjectModification<T>> hasNoDataBefore() {
+        return new Predicate<DataObjectModification<T>>() {
+            @Override
+            public boolean apply(@Nullable DataObjectModification<T> input) {
+                return input != null && input.getDataBefore() == null;
+            }
+        };
+    }
+
+    private static <T extends DataObject> Predicate<DataObjectModification<T>> hasDataAfterAndMatchesFilter(
+            final Predicate<DataObjectModification<T>> filter) {
+        return new Predicate<DataObjectModification<T>>() {
+            @Override
+            public boolean apply(@Nullable DataObjectModification<T> input) {
+                return input != null && input.getDataAfter() != null && filter.apply(input);
+            }
+        };
+    }
+
+    private static <T extends DataObject> Predicate<DataObjectModification<T>> matchesEverything() {
+        return new Predicate<DataObjectModification<T>>() {
+            @Override
+            public boolean apply(@Nullable DataObjectModification<T> input) {
+                return true;
+            }
+        };
+    }
+
+    private static <T extends DataObject> Predicate<DataObjectModification<T>> modificationIsDeletion() {
+        return new Predicate<DataObjectModification<T>>() {
+            @Override
+            public boolean apply(@Nullable DataObjectModification<T> input) {
+                return input != null && input.getModificationType() == DataObjectModification
+                        .ModificationType.DELETE;
+            }
+        };
+    }
+
+    private static <T extends DataObject> Predicate<DataObjectModification<T>> modificationIsDeletionAndHasDataBefore
+            () {
+        return new Predicate<DataObjectModification<T>>() {
+            @Override
+            public boolean apply(@Nullable DataObjectModification<T> input) {
+                return input != null && input.getModificationType() == DataObjectModification
+                        .ModificationType.DELETE && input.getDataBefore() != null;
+            }
+        };
+    }
+
     public static Map<InstanceIdentifier<Node>,Node> extractNode(
             Map<InstanceIdentifier<?>, DataObject> changes) {
         Map<InstanceIdentifier<Node>,Node> result
@@ -72,11 +152,61 @@ public class TransactUtils {
         return extract(changes.getCreatedData(),klazz);
     }
 
+    /**
+     * Extract all the instances of {@code clazz} which were created in the given set of modifications.
+     *
+     * @param changes The changes to process.
+     * @param clazz The class we're interested in.
+     * @param <T> The type of changes we're interested in.
+     * @param <U> The type of changes to process.
+     * @return The created instances, mapped by instance identifier.
+     */
+    public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractCreated(
+            Collection<DataTreeModification<U>> changes, Class<T> clazz) {
+        return extractCreatedOrUpdated(changes, clazz, hasNoDataBefore());
+    }
+
+    /**
+     * Extract all the instance of {@code clazz} which were created or updated in the given set of modifications, and
+     * which satisfy the given filter.
+     *
+     * @param changes The changes to process.
+     * @param clazz The class we're interested in.
+     * @param filter The filter the changes must satisfy.
+     * @param <T> The type of changes we're interested in.
+     * @param <U> The type of changes to process.
+     * @return The created or updated instances which satisfy the filter, mapped by instance identifier.
+     */
+    public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractCreatedOrUpdated(
+            Collection<DataTreeModification<U>> changes, Class<T> clazz,
+            Predicate<DataObjectModification<T>> filter) {
+        Map<InstanceIdentifier<T>, T> result = new HashMap<>();
+        for (Map.Entry<InstanceIdentifier<T>, DataObjectModification<T>> entry : extractDataObjectModifications(changes,
+                clazz, hasDataAfterAndMatchesFilter(filter)).entrySet()) {
+            result.put(entry.getKey(), entry.getValue().getDataAfter());
+        }
+        return result;
+    }
+
     public static <T extends DataObject> Map<InstanceIdentifier<T>,T> extractUpdated(
             AsyncDataChangeEvent<InstanceIdentifier<?>,DataObject> changes,Class<T> klazz) {
         return extract(changes.getUpdatedData(),klazz);
     }
 
+    /**
+     * Extract all the instances of {@code clazz} which were updated in the given set of modifications.
+     *
+     * @param changes The changes to process.
+     * @param clazz The class we're interested in.
+     * @param <T> The type of changes we're interested in.
+     * @param <U> The type of changes to process.
+     * @return The updated instances, mapped by instance identifier.
+     */
+    public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractUpdated(
+            Collection<DataTreeModification<U>> changes, Class<T> clazz) {
+        return extractCreatedOrUpdated(changes, clazz, hasDataBeforeAndDataAfter());
+    }
+
     public static <T extends DataObject> Map<InstanceIdentifier<T>,T> extractCreatedOrUpdated(
             AsyncDataChangeEvent<InstanceIdentifier<?>,DataObject> changes,Class<T> klazz) {
         Map<InstanceIdentifier<T>,T> result = extractUpdated(changes,klazz);
@@ -84,6 +214,20 @@ public class TransactUtils {
         return result;
     }
 
+    /**
+     * Extract all the instances of {@code clazz} which were created or updated in the given set of modifications.
+     *
+     * @param changes The changes to process.
+     * @param clazz The class we're interested in.
+     * @param <T> The type of changes we're interested in.
+     * @param <U> The type of changes to process.
+     * @return The created or updated instances, mapped by instance identifier.
+     */
+    public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractCreatedOrUpdated(
+            Collection<DataTreeModification<U>> changes, Class<T> clazz) {
+        return extractCreatedOrUpdated(changes, clazz, matchesEverything());
+    }
+
     public static <T extends DataObject> Map<InstanceIdentifier<T>, T> extractCreatedOrUpdatedOrRemoved(
             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
             Class<T> klazz) {
@@ -92,11 +236,49 @@ public class TransactUtils {
         return result;
     }
 
+    /**
+     * Extract all the instances of {@code clazz} which were created, updated, or removed in the given set of
+     * modifications. For instances which were created or updated, the new instances are returned; for instances
+     * which were removed, the old instances are returned.
+     *
+     * @param changes The changes to process.
+     * @param clazz The class we're interested in.
+     * @param <T> The type of changes we're interested in.
+     * @param <U> The type of changes to process.
+     * @return The created, updated or removed instances, mapped by instance identifier.
+     */
+    public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T>
+    extractCreatedOrUpdatedOrRemoved(
+            Collection<DataTreeModification<U>> changes, Class<T> clazz) {
+        Map<InstanceIdentifier<T>, T> result = extractCreatedOrUpdated(changes, clazz);
+        result.putAll(extractRemovedObjects(changes, clazz));
+        return result;
+    }
+
     public static <T extends DataObject> Map<InstanceIdentifier<T>,T> extractOriginal(
             AsyncDataChangeEvent<InstanceIdentifier<?>,DataObject> changes,Class<T> klazz) {
         return extract(changes.getOriginalData(),klazz);
     }
 
+    /**
+     * Extract the original instances of class {@code clazz} in the given set of modifications.
+     *
+     * @param changes The changes to process.
+     * @param clazz The class we're interested in.
+     * @param <T> The type of changes we're interested in.
+     * @param <U> The type of changes to process.
+     * @return The original instances, mapped by instance identifier.
+     */
+    public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractOriginal(
+            Collection<DataTreeModification<U>> changes, Class<T> clazz) {
+        Map<InstanceIdentifier<T>, T> result = new HashMap<>();
+        for (Map.Entry<InstanceIdentifier<T>, DataObjectModification<T>> entry :
+                extractDataObjectModifications(changes, clazz, hasDataBefore()).entrySet()) {
+            result.put(entry.getKey(), entry.getValue().getDataBefore());
+        }
+        return result;
+    }
+
     public static <T extends DataObject> Set<InstanceIdentifier<T>> extractRemoved(
             AsyncDataChangeEvent<InstanceIdentifier<?>,DataObject> changes,Class<T> klazz) {
         Set<InstanceIdentifier<T>> result = new HashSet<>();
@@ -112,6 +294,108 @@ public class TransactUtils {
         return result;
     }
 
+    /**
+     * Extract the instance identifier of removed instances of {@code clazz} from the given set of modifications.
+     *
+     * @param changes The changes to process.
+     * @param clazz The class we're interested in.
+     * @param <T> The type of changes we're interested in.
+     * @param <U> The type of changes to process.
+     * @return The instance identifiers of removed instances.
+     */
+    public static <T extends DataObject, U extends DataObject> Set<InstanceIdentifier<T>> extractRemoved(
+            Collection<DataTreeModification<U>> changes, Class<T> clazz) {
+        return extractDataObjectModifications(changes, clazz, modificationIsDeletion()).keySet();
+    }
+
+    /**
+     * Extract all the modifications affecting instances of {@code clazz} which are present in the given set of
+     * modifications and satisfy the given filter.
+     *
+     * @param changes The changes to process.
+     * @param clazz The class we're interested in.
+     * @param filter The filter the changes must satisfy.
+     * @param <T> The type of changes we're interested in.
+     * @param <U> The type of changes to process.
+     * @return The modifications, mapped by instance identifier.
+     */
+    private static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, DataObjectModification<T>>
+    extractDataObjectModifications(
+            Collection<DataTreeModification<U>> changes, Class<T> clazz,
+            Predicate<DataObjectModification<T>> filter) {
+        List<DataObjectModification<? extends DataObject>> dataObjectModifications = new ArrayList<>();
+        List<InstanceIdentifier<? extends DataObject>> paths = new ArrayList<>();
+        if (changes != null) {
+            for (DataTreeModification<? extends DataObject> change : changes) {
+                dataObjectModifications.add(change.getRootNode());
+                paths.add(change.getRootPath().getRootIdentifier());
+            }
+        }
+        return extractDataObjectModifications(dataObjectModifications, paths, clazz, filter);
+    }
+
+    /**
+     * Extract all the modifications affecting instances of {@code clazz} which are present in the given set of
+     * modifications and satisfy the given filter.
+     *
+     * @param changes The changes to process.
+     * @param paths The paths of the changes.
+     * @param clazz The class we're interested in.
+     * @param filter The filter the changes must satisfy.
+     * @param <T> The type of changes we're interested in.
+     * @return The modifications, mapped by instance identifier.
+     */
+    private static <T extends DataObject> Map<InstanceIdentifier<T>, DataObjectModification<T>>
+    extractDataObjectModifications(
+            Collection<DataObjectModification<? extends DataObject>> changes,
+            Collection<InstanceIdentifier<? extends DataObject>> paths, Class<T> clazz,
+            Predicate<DataObjectModification<T>> filter) {
+        Map<InstanceIdentifier<T>, DataObjectModification<T>> result = new HashMap<>();
+        Queue<DataObjectModification<? extends DataObject>> remainingChanges = new LinkedList<>(changes);
+        Queue<InstanceIdentifier<? extends DataObject>> remainingPaths = new LinkedList<>(paths);
+        while (!remainingChanges.isEmpty()) {
+            DataObjectModification<? extends DataObject> change = remainingChanges.remove();
+            InstanceIdentifier<? extends DataObject> path = remainingPaths.remove();
+            // Is the change relevant?
+            if (clazz.isAssignableFrom(change.getDataType()) && filter.apply((DataObjectModification<T>) change)) {
+                result.put((InstanceIdentifier<T>) path, (DataObjectModification<T>) change);
+            }
+            // Add any children to the queue
+            for (DataObjectModification<? extends DataObject> child : change.getModifiedChildren()) {
+                remainingChanges.add(child);
+                remainingPaths.add(extendPath(path, child));
+            }
+        }
+        return result;
+    }
+
+    /**
+     * Extends the given instance identifier path to include the given child. Augmentations are treated in the same way
+     * as children; keyed children are handled correctly.
+     *
+     * @param path The current path.
+     * @param child The child modification to include.
+     * @return The extended path.
+     */
+    private static <N extends Identifiable<K> & ChildOf<? super T>, K extends Identifier<N>, T extends DataObject>
+    InstanceIdentifier<? extends DataObject> extendPath(
+            InstanceIdentifier path,
+            DataObjectModification child) {
+        Class<N> item = (Class<N>) child.getDataType();
+        if (child.getIdentifier() instanceof InstanceIdentifier.IdentifiableItem) {
+            K key = (K) ((InstanceIdentifier.IdentifiableItem) child.getIdentifier()).getKey();
+            KeyedInstanceIdentifier<N, K> extendedPath = path.child(item, key);
+            LOG.debug("Building a new child iid for {} with {} and key {}, resulting in {}",
+                    path, item, extendedPath);
+            return extendedPath;
+        } else {
+            InstanceIdentifier<N> extendedPath = path.child(item);
+            LOG.debug("Building a new child iid for {} with {}, resulting in {}",
+                    path, item, extendedPath);
+            return extendedPath;
+        }
+    }
+
     public static <T extends DataObject> Map<InstanceIdentifier<T>, T> extractRemovedObjects(
             AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changes,
             Class<T> klazz) {
@@ -119,6 +403,25 @@ public class TransactUtils {
         return Maps.filterKeys(extractOriginal(changes, klazz),Predicates.in(iids));
     }
 
+    /**
+     * Extract the removed instances of {@code clazz} from the given set of modifications.
+     *
+     * @param changes The changes to process.
+     * @param clazz The class we're interested in.
+     * @param <T> The type of changes we're interested in.
+     * @param <U> The type of changes to process.
+     * @return The removed instances, keyed by instance identifier.
+     */
+    public static <T extends DataObject, U extends DataObject> Map<InstanceIdentifier<T>, T> extractRemovedObjects(
+            Collection<DataTreeModification<U>> changes, Class<T> clazz) {
+        Map<InstanceIdentifier<T>, T> result = new HashMap<>();
+        for (Map.Entry<InstanceIdentifier<T>, DataObjectModification<T>> entry :
+                extractDataObjectModifications(changes, clazz, modificationIsDeletionAndHasDataBefore()).entrySet()) {
+            result.put(entry.getKey(), entry.getValue().getDataBefore());
+        }
+        return result;
+    }
+
     public static <T extends DataObject> Map<InstanceIdentifier<T>,T> extract(
             Map<InstanceIdentifier<?>, DataObject> changes, Class<T> klazz) {
         Map<InstanceIdentifier<T>,T> result = new HashMap<>();
index 3db9470fe0037d079cc4a5128f4c411e68556e31..d5cdba81824e5eae573b9e298d972d3c8bb80af5 100644 (file)
@@ -125,7 +125,9 @@ public class OvsdbDataChangeListenerTest {
                 any(InstanceIdentifier.class),
                 any(AsyncDataChangeEvent.class)).thenReturn(dataChangesManagedByOvsdbNodeEvent);
 
-        PowerMockito.whenNew(BridgeOperationalState.class).withArguments(any(DataBroker.class), any(AsyncDataChangeEvent.class)).thenReturn(bridgeOperationalState);
+        PowerMockito.whenNew(BridgeOperationalState.class.getConstructor(DataBroker.class,
+                AsyncDataChangeEvent.class)).withArguments(any(DataBroker.class),
+                any(AsyncDataChangeEvent.class)).thenReturn(bridgeOperationalState);
 
         when(connectionInstance.getInstanceIdentifier()).thenReturn(iid);
         doNothing().when(connectionInstance).transact(any(TransactCommandAggregator.class), eq(bridgeOperationalState),
diff --git a/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbDataTreeChangeListenerTest.java b/southbound/southbound-impl/src/test/java/org/opendaylight/ovsdb/southbound/OvsdbDataTreeChangeListenerTest.java
new file mode 100644 (file)
index 0000000..6b546e8
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2016 Red Hat, Inc. and others.
+ *
+ * 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
+ */
+package org.opendaylight.ovsdb.southbound;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.concurrent.ExecutionException;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
+import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.ovsdb.lib.OvsdbConnection;
+import org.opendaylight.ovsdb.southbound.transactions.md.TransactionInvokerImpl;
+import org.opendaylight.ovsdb.utils.southbound.utils.SouthboundUtils;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.PortNumber;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes.ConnectionInfo;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.ovsdb.rev150105.ovsdb.node.attributes
+        .ConnectionInfoBuilder;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology
+        .Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Unit tests for the data-tree change listener.
+ */
+public class OvsdbDataTreeChangeListenerTest extends AbstractDataBrokerTest {
+    private final OvsdbConnection ovsdbConnection = Mockito.mock(OvsdbConnection.class);
+    private DataBroker dataBroker;
+    private OvsdbDataTreeChangeListener listener;
+
+    @Before
+    public void setupListener() {
+        dataBroker = getDataBroker();
+        EntityOwnershipService entityOwnershipService = Mockito.mock(EntityOwnershipService.class);
+        listener = new OvsdbDataTreeChangeListener(dataBroker,
+                new OvsdbConnectionManager(dataBroker, new TransactionInvokerImpl(dataBroker), entityOwnershipService,
+                        ovsdbConnection));
+    }
+
+    @Test
+    public void testConnect() throws UnknownHostException, InterruptedException, ExecutionException {
+        // Given ...
+
+        // When we request a connection ...
+        InetAddress inetAddress = InetAddress.getByName("127.0.0.1");
+        int port = 6640;
+        IpAddress ipAddress = SouthboundMapper.createIpAddress(inetAddress);
+        PortNumber portNumber = new PortNumber(port);
+
+        final ConnectionInfo connectionInfo = new ConnectionInfoBuilder()
+                .setRemoteIp(ipAddress)
+                .setRemotePort(portNumber)
+                .build();
+        final InstanceIdentifier<Node> iid = SouthboundUtils.createInstanceIdentifier(connectionInfo);
+        WriteTransaction transaction = dataBroker.newWriteOnlyTransaction();
+        transaction.put(LogicalDatastoreType.CONFIGURATION, iid, SouthboundUtils.createNode(connectionInfo),
+                WriteTransaction.CREATE_MISSING_PARENTS);
+        transaction.submit().get();
+
+        // Then the listener tries to open a connection
+        Mockito.verify(ovsdbConnection).connect(inetAddress, port);
+    }
+}