bug 537 - Node Reconciliation 74/8174/15
authorMichal Rehak <mirehak@cisco.com>
Fri, 15 Aug 2014 18:25:19 +0000 (20:25 +0200)
committerMichal Rehak <mirehak@cisco.com>
Fri, 15 Aug 2014 18:25:19 +0000 (20:25 +0200)
https://wiki.opendaylight.org/view/OpenDaylight_OpenFlow_Plugin:Backlog:Node_Status_Reconciliation

* FRM Reconciliation Notify Listener (DataChangeScope.BASE for FlowCapableNode in DataStore/OPERATIONAL)
* FlowCookieProducer - MapHolder for an unique relation flow_cookie to flow_id via FRM
* FlowStatTracker changes
        * search flow_id by flow_cookie for exist flow
* add flow_id - flow_cookie for new Flow
* FRM migration for new DataBroker API
* merge with new DataStore/OPERATIONAL hierarchy (Flow vs. FlowStatistics)
* fixed flow delete - generated cookie is bypassed with mask=0

In additional commit has fixed Bug 282 - Pre-configuration of flows causes exception
+ remove the transaction validators - not needed for now

Change-Id: Iadc2b111780524b9a8fd86cfc248e5fa194e6638
Signed-off-by: Vaclav Demcak <vdemcak@cisco.com>
Signed-off-by: Michal Rehak <mirehak@cisco.com>
17 files changed:
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FRMActivator.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java [new file with mode: 0644]
opendaylight/md-sal/model/model-flow-service/src/main/yang/flow-node-inventory.yang
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowComparator.java
opendaylight/md-sal/statistics-manager/src/main/java/org/opendaylight/controller/md/statistics/manager/FlowStatsTracker.java

index c8a7f01..130c096 100644 (file)
@@ -9,67 +9,89 @@ package org.opendaylight.controller.frm;
 
 import java.util.HashSet;
 import java.util.Map;
-import java.util.Set;
 import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.atomic.AtomicLong;
 
-import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
+ * AbstractChangeListner implemented basic {@link AsyncDataChangeEvent} processing for
+ * flow node subDataObject (flows, groups and meters).
  *
  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
  *
  */
 public abstract class AbstractChangeListener implements DataChangeListener {
 
+    private final static Logger LOG = LoggerFactory.getLogger(AbstractChangeListener.class);
+
     private final AtomicLong txNum = new AtomicLong();
     private String transactionId;
 
     @Override
-    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
         this.transactionId = this.newTransactionIdentifier().toString();
-
+        /* All DataObjects for create */
         final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
-                changeEvent.getCreatedConfigurationData().entrySet();
-        final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries =
-                new HashSet<Entry<InstanceIdentifier<? extends DataObject>, DataObject>>();
-
+                changeEvent.getCreatedData().entrySet();
+        /* All DataObjects for updates - init HashSet */
+        final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = new HashSet<>();
+        /* Filtered DataObject for update processing only */
         Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updateConfigEntrySet =
-                changeEvent.getUpdatedConfigurationData().entrySet();
+                changeEvent.getUpdatedData().entrySet();
         updatedEntries.addAll(updateConfigEntrySet);
         updatedEntries.removeAll(createdEntries);
-
+        /* All DataObjects for remove */
         final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
-                changeEvent.getRemovedConfigurationData();
-
+                changeEvent.getRemovedPaths();
+        /* Create DataObject processing (send to device) */
         for (final Entry<InstanceIdentifier<? extends DataObject>, DataObject> createdEntry : createdEntries) {
-            InstanceIdentifier<? extends DataObject> c_key = createdEntry.getKey();
-            DataObject c_value = createdEntry.getValue();
-            this.add(c_key, c_value);
+            InstanceIdentifier<? extends DataObject> entryKey = createdEntry.getKey();
+            DataObject entryValue = createdEntry.getValue();
+            if (preconditionForChange(entryKey, entryValue, null)) {
+                this.add(entryKey, entryValue);
+            }
         }
 
         for (final Entry<InstanceIdentifier<?>, DataObject> updatedEntrie : updatedEntries) {
             Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
-                    changeEvent.getOriginalConfigurationData();
-
-            InstanceIdentifier<? extends Object> u_key = updatedEntrie.getKey();
-            final DataObject originalFlow = origConfigData.get(u_key);
-            final DataObject updatedFlow = updatedEntrie.getValue();
-            this.update(u_key, originalFlow, updatedFlow);
+                    changeEvent.getOriginalData();
+
+            InstanceIdentifier<? extends Object> entryKey = updatedEntrie.getKey();
+            final DataObject original = origConfigData.get(entryKey);
+            final DataObject updated = updatedEntrie.getValue();
+            if (preconditionForChange(entryKey, original, updated)) {
+                this.update(entryKey, original, updated);
+            }
         }
 
         for (final InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers) {
             Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
-                    changeEvent.getOriginalConfigurationData();
+                    changeEvent.getOriginalData();
 
             final DataObject removeValue = origConfigData.get(instanceId);
-            this.remove(instanceId, removeValue);
+            if (preconditionForChange(instanceId, removeValue, null)) {
+                this.remove(instanceId, removeValue);
+            }
         }
     }
 
+    /**
+     * Method returns generated transaction ID, which is unique for
+     * every transaction. ID is composite from prefix ("DOM") and unique number.
+     *
+     * @return String transactionID
+     */
     public String getTransactionId() {
         return this.transactionId;
     }
@@ -78,17 +100,74 @@ public abstract class AbstractChangeListener implements DataChangeListener {
         return "DOM-" + txNum.getAndIncrement();
     }
 
-    protected abstract void validate() throws IllegalStateException;
-
-    protected abstract void remove(
+    /**
+     * Method check all local preconditions for apply relevant changes.
+     *
+     * @param InstanceIdentifier identifier - the whole path to DataObject
+     * @param DataObject original - original DataObject (for update)
+     *                              or relevant DataObject (add/delete operations)
+     * @param DataObject update - changed DataObject (contain updates)
+     *                              or should be null for (add/delete operations)
+     *
+     * @return boolean - applicable
+     */
+    protected abstract boolean preconditionForChange(
             final InstanceIdentifier<? extends DataObject> identifier,
+            final DataObject original, final DataObject update);
+
+    /**
+     * Method checks the node data path in DataStore/OPERATIONAL because
+     * without the Node Identifier in DataStore/OPERATIONAL, device
+     * is not connected and device pre-configuration is allowed only.
+     *
+     * @param InstanceIdentifier identifier - could be whole path to DataObject,
+     *            but parent Node.class InstanceIdentifier is used for a check only
+     *
+     * @return boolean - is the Node available in DataStore/OPERATIONAL (is connected)
+     */
+    protected boolean isNodeAvailable(final InstanceIdentifier<? extends DataObject> identifier,
+            final ReadOnlyTransaction readTrans) {
+        final InstanceIdentifier<Node> nodeInstanceId = identifier.firstIdentifierOf(Node.class);
+        try {
+            return readTrans.read(LogicalDatastoreType.OPERATIONAL, nodeInstanceId).get().isPresent();
+        }
+        catch (InterruptedException | ExecutionException e) {
+            LOG.error("Unexpected exception by reading Node ".concat(nodeInstanceId.toString()), e);
+            return false;
+        }
+        finally {
+            readTrans.close();
+        }
+    }
+
+    /**
+     * Method removes DataObject which is identified by InstanceIdentifier
+     * from device.
+     *
+     * @param InstanceIdentifier identifier - the whole path to DataObject
+     * @param DataObject remove - DataObject for removing
+     */
+    protected abstract void remove(final InstanceIdentifier<? extends DataObject> identifier,
             final DataObject remove);
 
-    protected abstract void update(
-            final InstanceIdentifier<? extends DataObject> identifier,
+    /**
+     * Method updates the original DataObject to the update DataObject
+     * in device. Both are identified by same InstanceIdentifier
+     *
+     * @param InstanceIdentifier identifier - the whole path to DataObject
+     * @param DataObject original - original DataObject (for update)
+     * @param DataObject update - changed DataObject (contain updates)
+     */
+    protected abstract void update(final InstanceIdentifier<? extends DataObject> identifier,
             final DataObject original, final DataObject update);
 
-    protected abstract void add(
-            final InstanceIdentifier<? extends DataObject> identifier,
+    /**
+     * Method adds the DataObject which is identified by InstanceIdentifier
+     * to device.
+     *
+     * @param InstanceIdentifier identifier - the whole path to new DataObject
+     * @param DataObject add - new DataObject
+     */
+    protected abstract void add(final InstanceIdentifier<? extends DataObject> identifier,
             final DataObject add);
 }
index 2f986ea..c75c644 100644 (file)
@@ -10,52 +10,79 @@ package org.opendaylight.controller.frm;
 import org.opendaylight.controller.frm.flow.FlowProvider;
 import org.opendaylight.controller.frm.group.GroupProvider;
 import org.opendaylight.controller.frm.meter.MeterProvider;
+import org.opendaylight.controller.frm.reconil.FlowNodeReconcilProvider;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.sal.binding.api.AbstractBindingAwareProvider;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ProviderContext;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+/**
+ * Forwarding Rules Manager Activator
+ *
+ * Activator manages all Providers ({@link FlowProvider}, {@link GroupProvider},
+ * {@link MeterProvider} and the {@link FlowNodeReconcilProvider}).
+ * It registers all listeners (DataChangeEvent, ReconcilNotification)
+ * in the Session Initialization phase.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ * *
+ */
 public class FRMActivator extends AbstractBindingAwareProvider {
 
     private final static Logger LOG = LoggerFactory.getLogger(FRMActivator.class);
 
-    private static FlowProvider flowProvider = new FlowProvider();
-    private static GroupProvider groupProvider = new GroupProvider();
-    private static MeterProvider meterProvider = new MeterProvider();
+    private final FlowProvider flowProvider;
+    private final GroupProvider groupProvider;
+    private final MeterProvider meterProvider;
+    private final FlowNodeReconcilProvider flowNodeReconcilProvider;
+
+    public FRMActivator() {
+        this.flowProvider = new FlowProvider();
+        this.groupProvider = new GroupProvider();
+        this.meterProvider = new MeterProvider();
+        this.flowNodeReconcilProvider = new FlowNodeReconcilProvider();
+    }
 
     @Override
     public void onSessionInitiated(final ProviderContext session) {
-        DataProviderService flowSalService = session.<DataProviderService>getSALService(DataProviderService.class);
-        FRMActivator.flowProvider.setDataService(flowSalService);
-        SalFlowService rpcFlowSalService = session.<SalFlowService>getRpcService(SalFlowService.class);
-        FRMActivator.flowProvider.setSalFlowService(rpcFlowSalService);
-        FRMActivator.flowProvider.start();
-        DataProviderService groupSalService = session.<DataProviderService>getSALService(DataProviderService.class);
-        FRMActivator.groupProvider.setDataService(groupSalService);
-        SalGroupService rpcGroupSalService = session.<SalGroupService>getRpcService(SalGroupService.class);
-        FRMActivator.groupProvider.setSalGroupService(rpcGroupSalService);
-        FRMActivator.groupProvider.start();
-        DataProviderService meterSalService = session.<DataProviderService>getSALService(DataProviderService.class);
-        FRMActivator.meterProvider.setDataService(meterSalService);
-        SalMeterService rpcMeterSalService = session.<SalMeterService>getRpcService(SalMeterService.class);
-        FRMActivator.meterProvider.setSalMeterService(rpcMeterSalService);
-        FRMActivator.meterProvider.start();
+        LOG.info("FRMActivator initialization.");
+        /* Flow */
+        try {
+            final DataBroker flowSalService = session.getSALService(DataBroker.class);
+            this.flowProvider.init(flowSalService);
+            this.flowProvider.start(session);
+            /* Group */
+            final DataBroker groupSalService = session.getSALService(DataBroker.class);
+            this.groupProvider.init(groupSalService);
+            this.groupProvider.start(session);
+            /* Meter */
+            final DataBroker meterSalService = session.getSALService(DataBroker.class);
+            this.meterProvider.init(meterSalService);
+            this.meterProvider.start(session);
+            /* FlowNode Reconciliation */
+            final DataBroker dbs = session.getSALService(DataBroker.class);
+            this.flowNodeReconcilProvider.init(dbs);
+            this.flowNodeReconcilProvider.start(session);
+
+            LOG.info("FRMActivator started successfully");
+        } catch (Exception e) {
+            String errMsg = "Unexpected error by starting FRMActivator";
+            LOG.error(errMsg, e);
+            throw new IllegalStateException(errMsg, e);
+        }
     }
 
     @Override
     protected void stopImpl(final BundleContext context) {
         try {
-            FRMActivator.flowProvider.close();
-            FRMActivator.groupProvider.close();
-            FRMActivator.meterProvider.close();
-        } catch (Throwable e) {
+            this.flowProvider.close();
+            this.groupProvider.close();
+            this.meterProvider.close();
+            this.flowNodeReconcilProvider.close();
+        } catch (Exception e) {
             LOG.error("Unexpected error by stopping FRMActivator", e);
-            throw new RuntimeException(e);
         }
     }
   }
\ No newline at end of file
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowCookieProducer.java
new file mode 100644 (file)
index 0000000..d7b54e8
--- /dev/null
@@ -0,0 +1,79 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, 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.controller.frm;
+
+import java.math.BigInteger;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.AtomicLongMap;
+
+/**
+ * forwardingrules-manager
+ * org.opendaylight.controller.frm
+ *
+ * Singleton FlowCookieProducer contains a FlowCookie generator which is generated unique
+ * flowCookie identifier for every flow in same Table. That could help with quick
+ * identification of flow statistic because DataStore/CONFIGURATION could contains
+ * a lot of flows with same flowCookie. So we are replacing original flowCookie
+ * with unique and we are building final FlowCookieMap in DataStore/OPERATIONAL
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Jun 13, 2014
+ */
+public enum FlowCookieProducer {
+
+    INSTANCE;
+
+    /* Flow_Cookie_Key and Flow_Ids MapHolder */
+    private static final AtomicLongMap<InstanceIdentifier<Table>> cookieKeys = AtomicLongMap.create();
+
+    /**
+     * Method returns the unique cookie for a node table.
+     * Flow Cookie Key signs List<FlowId> for a right flow statistic identification
+     * in the DataStore/operational.
+     * We need a List<FlowId> because system doesn't guarantee unique mapping
+     * from flow_cookie to flow_id. REST Operations doesn't used FRM yet, so
+     * cookie from user input could have a user input flow ID and an alien system ID
+     * which is generated by system.
+     *
+     * @param InstanceIdentifier<Table> tableIdentifier
+     * @return unique BigInteger flowCookie for a node table
+     */
+    public BigInteger getNewCookie(final InstanceIdentifier<Table> tableIdentifier) {
+        FlowCookieProducer.validationTableIdentifier(tableIdentifier);
+        if ( cookieKeys.containsKey(tableIdentifier)) {
+            /* new identifier always starts from ONE because
+             * ZERO is reserved for the NO_COOKIES flows */
+            return BigInteger.valueOf(cookieKeys.addAndGet(tableIdentifier, 1L));
+        } else {
+            return BigInteger.valueOf(cookieKeys.incrementAndGet(tableIdentifier));
+        }
+    }
+
+    /**
+     * Method cleans the node table flow_cookie_key for the disconnected Node.
+     *
+     * @param InstanceIdentifier<Table> tableIdentifier
+     */
+    public void clean(final InstanceIdentifier<Table> tableIdentifier) {
+        FlowCookieProducer.validationTableIdentifier(tableIdentifier);
+        cookieKeys.remove(tableIdentifier);
+    }
+
+    /*
+     * Help the TableIdentifer input validation method
+     */
+    private static void validationTableIdentifier(final InstanceIdentifier<Table> tableIdent) {
+        Preconditions.checkArgument(tableIdent != null, "Input validation exception: TableIdentifier can not be null !");
+    }
+}
index b604245..c10b0da 100644 (file)
@@ -7,22 +7,21 @@
  */
 package org.opendaylight.controller.frm.flow;
 
+import java.math.BigInteger;
+
 import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.controller.frm.FlowCookieProducer;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.OriginalFlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlow;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.flow.update.UpdatedFlowBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
@@ -31,90 +30,97 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+
 /**
+ * Flow Change Listener
+ *  add, update and remove {@link Flow} processing from {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}.
  *
  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
  *
  */
 public class FlowChangeListener extends AbstractChangeListener {
 
-    private final static Logger LOG = LoggerFactory.getLogger(FlowChangeListener.class);
+    private static final Logger LOG = LoggerFactory.getLogger(FlowChangeListener.class);
 
-    private final SalFlowService salFlowService;
-
-    public SalFlowService getSalFlowService() {
-        return this.salFlowService;
-    }
+    private final FlowProvider provider;
 
-    public FlowChangeListener(final SalFlowService manager) {
-        this.salFlowService = manager;
+    public FlowChangeListener (final FlowProvider provider) {
+        this.provider = Preconditions.checkNotNull(provider, "FlowProvider can not be null !");
     }
 
     @Override
-    protected void validate() throws IllegalStateException {
-        FlowTransactionValidator.validate(this);
-    }
+    protected void remove(final InstanceIdentifier<? extends DataObject> identifier,
+                          final DataObject removeDataObj) {
 
-    @Override
-    protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
-        if ((removeDataObj instanceof Flow)) {
-
-            final Flow flow = ((Flow) removeDataObj);
-            final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
-            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
-            final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow);
-
-            builder.setFlowRef(new FlowRef(identifier));
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setFlowTable(new FlowTableRef(tableInstanceId));
-
-            Uri uri = new Uri(this.getTransactionId());
-            builder.setTransactionUri(uri);
-            this.salFlowService.removeFlow((RemoveFlowInput) builder.build());
-            LOG.debug("Transaction {} - Removed Flow has removed flow: {}", new Object[]{uri, removeDataObj});
-        }
+        final Flow flow = ((Flow) removeDataObj);
+        final InstanceIdentifier<Table> tableIdent = identifier.firstIdentifierOf(Table.class);
+        final InstanceIdentifier<Node> nodeIdent = identifier.firstIdentifierOf(Node.class);
+        final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(flow);
+
+        // use empty cookie mask in order to delete flow even with generated cookie
+        builder.setCookieMask(new FlowCookie(BigInteger.ZERO));
+
+        builder.setFlowRef(new FlowRef(identifier));
+        builder.setNode(new NodeRef(nodeIdent));
+        builder.setFlowTable(new FlowTableRef(tableIdent));
+
+        Uri uri = new Uri(this.getTransactionId());
+        builder.setTransactionUri(uri);
+        this.provider.getSalFlowService().removeFlow(builder.build());
+        LOG.debug("Transaction {} - Removed Flow has removed flow: {}", new Object[]{uri, removeDataObj});
     }
 
     @Override
-    protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
-        if (original instanceof Flow && update instanceof Flow) {
+    protected void update(final InstanceIdentifier<? extends DataObject> identifier,
+                          final DataObject original, final DataObject update) {
+
+        final Flow originalFlow = ((Flow) original);
+        final Flow updatedFlow = ((Flow) update);
+        final InstanceIdentifier<Node> nodeIdent = identifier.firstIdentifierOf(Node.class);
+        final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder();
 
-            final Flow originalFlow = ((Flow) original);
-            final Flow updatedFlow = ((Flow) update);
-            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node>firstIdentifierOf(Node.class);
-            final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder();
+        builder.setNode(new NodeRef(nodeIdent));
+        builder.setFlowRef(new FlowRef(identifier));
 
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setFlowRef(new FlowRef(identifier));
+        Uri uri = new Uri(this.getTransactionId());
+        builder.setTransactionUri(uri);
 
-            Uri uri = new Uri(this.getTransactionId());
-            builder.setTransactionUri(uri);
+        builder.setUpdatedFlow((new UpdatedFlowBuilder(updatedFlow)).build());
+        builder.setOriginalFlow((new OriginalFlowBuilder(originalFlow)).build());
 
-            builder.setUpdatedFlow((UpdatedFlow) (new UpdatedFlowBuilder(updatedFlow)).build());
-            builder.setOriginalFlow((OriginalFlow) (new OriginalFlowBuilder(originalFlow)).build());
+        this.provider.getSalFlowService().updateFlow(builder.build());
+        LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update});
+    }
 
-            this.salFlowService.updateFlow((UpdateFlowInput) builder.build());
-            LOG.debug("Transaction {} - Update Flow has updated flow {} with {}", new Object[]{uri, original, update});
-      }
+    @Override
+    protected void add(final InstanceIdentifier<? extends DataObject> identifier,
+                       final DataObject addDataObj) {
+
+        final Flow flow = ((Flow) addDataObj);
+        final InstanceIdentifier<Table> tableIdent = identifier.firstIdentifierOf(Table.class);
+        final NodeRef nodeRef = new NodeRef(identifier.firstIdentifierOf(Node.class));
+        final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent));
+        final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow);
+
+        builder.setNode(nodeRef);
+        builder.setFlowRef(new FlowRef(identifier));
+        builder.setFlowTable(new FlowTableRef(tableIdent));
+        builder.setCookie( flowCookie );
+
+        Uri uri = new Uri(this.getTransactionId());
+        builder.setTransactionUri(uri);
+        this.provider.getSalFlowService().addFlow(builder.build());
+        LOG.debug("Transaction {} - Add Flow has added flow: {}", new Object[]{uri, addDataObj});
     }
 
     @Override
-    protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
-        if ((addDataObj instanceof Flow)) {
-
-            final Flow flow = ((Flow) addDataObj);
-            final InstanceIdentifier<Table> tableInstanceId = identifier.<Table> firstIdentifierOf(Table.class);
-            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
-            final AddFlowInputBuilder builder = new AddFlowInputBuilder(flow);
-
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setFlowRef(new FlowRef(identifier));
-            builder.setFlowTable(new FlowTableRef(tableInstanceId));
-
-            Uri uri = new Uri(this.getTransactionId());
-            builder.setTransactionUri(uri);
-            this.salFlowService.addFlow((AddFlowInput) builder.build());
-            LOG.debug("Transaction {} - Add Flow has added flow: {}", new Object[]{uri, addDataObj});
-        }
+    protected boolean preconditionForChange(final InstanceIdentifier<? extends DataObject> identifier,
+            final DataObject dataObj, final DataObject update) {
+
+        final ReadOnlyTransaction trans = this.provider.getDataService().newReadOnlyTransaction();
+        return update != null
+                ? (dataObj instanceof Flow && update instanceof Flow && isNodeAvailable(identifier, trans))
+                : (dataObj instanceof Flow && isNodeAvailable(identifier, trans));
     }
 }
index 33db529..8c248fa 100644 (file)
@@ -7,9 +7,11 @@
  */
 package org.opendaylight.controller.frm.flow;
 
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
@@ -17,54 +19,89 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalF
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+
+/**
+ * Flow Provider registers the {@link FlowChangeListener} and it holds all needed
+ * services for {@link FlowChangeListener}.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
 public class FlowProvider implements AutoCloseable {
 
-    private final static Logger LOG = LoggerFactory.getLogger(FlowProvider.class);
+    private static final Logger LOG = LoggerFactory.getLogger(FlowProvider.class);
 
     private SalFlowService salFlowService;
-    private DataProviderService dataService;
+    private DataBroker dataService;
 
     /* DataChangeListener */
-    private FlowChangeListener flowDataChangeListener;
-    ListenerRegistration<DataChangeListener> flowDataChangeListenerRegistration;
+    private DataChangeListener flowDataChangeListener;
+    private ListenerRegistration<DataChangeListener> flowDataChangeListenerRegistration;
+
+    /**
+     * Provider Initialization Phase.
+     *
+     * @param DataProviderService dataService
+     */
+    public void init (final DataBroker dataService) {
+        LOG.info("FRM Flow Config Provider initialization.");
+        this.dataService = Preconditions.checkNotNull(dataService, "DataProviderService can not be null !");
+    }
+
+    /**
+     * Listener Registration Phase
+     *
+     * @param RpcConsumerRegistry rpcRegistry
+     */
+    public void start(final RpcConsumerRegistry rpcRegistry) {
+        Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !");
+
+        this.salFlowService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalFlowService.class),
+                "RPC SalFlowService not found.");
 
-    public void start() {
         /* Build Path */
-        InstanceIdentifierBuilder<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
-        InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
-        InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
-        InstanceIdentifierBuilder<Table> tableChild = augmentFlowCapNode.<Table> child(Table.class);
-        InstanceIdentifierBuilder<Flow> flowChild = tableChild.<Flow> child(Flow.class);
-        final InstanceIdentifier<? extends DataObject> flowDataObjectPath = flowChild.toInstance();
+        InstanceIdentifier<Flow> flowIdentifier = InstanceIdentifier.create(Nodes.class)
+                .child(Node.class).augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class);
 
         /* DataChangeListener registration */
-        this.flowDataChangeListener = new FlowChangeListener(this.salFlowService);
-        this.flowDataChangeListenerRegistration = this.dataService.registerDataChangeListener(flowDataObjectPath, flowDataChangeListener);
-        LOG.info("Flow Config Provider started.");
-    }
+        this.flowDataChangeListener = new FlowChangeListener(FlowProvider.this);
+        this.flowDataChangeListenerRegistration =
+                this.dataService.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                        flowIdentifier, flowDataChangeListener, DataChangeScope.SUBTREE);
 
-    protected DataModificationTransaction startChange() {
-        return this.dataService.beginTransaction();
+        LOG.info("FRM Flow Config Provider started.");
     }
 
     @Override
-    public void close() throws Exception {
-        if(flowDataChangeListenerRegistration != null){
-            flowDataChangeListenerRegistration.close();
+    public void close() {
+        LOG.info("FRM Flow Config Provider stopped.");
+        if (flowDataChangeListenerRegistration != null) {
+            try {
+                flowDataChangeListenerRegistration.close();
+            } catch (Exception e) {
+                String errMsg = "Error by stop FRM Flow Config Provider.";
+                LOG.error(errMsg, e);
+                throw new IllegalStateException(errMsg, e);
+            } finally {
+                flowDataChangeListenerRegistration = null;
+            }
         }
     }
 
-    public void setDataService(final DataProviderService dataService) {
-        this.dataService = dataService;
+    public DataChangeListener getFlowDataChangeListener() {
+        return flowDataChangeListener;
+    }
+
+    public SalFlowService getSalFlowService() {
+        return salFlowService;
     }
 
-    public void setSalFlowService(final SalFlowService salFlowService) {
-        this.salFlowService = salFlowService;
+    public DataBroker getDataService() {
+        return dataService;
     }
 }
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowTransactionValidator.java
deleted file mode 100644 (file)
index 9cd4246..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Copyright (c) 2014 Cisco Systems, 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.controller.frm.flow;
-
-public class FlowTransactionValidator {
-
-    public static void validate(FlowChangeListener transaction) throws IllegalStateException {
-        // NOOP
-    }
-}
index 54f12bf..9b03eaa 100644 (file)
@@ -8,17 +8,12 @@
 package org.opendaylight.controller.frm.group;
 
 import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroup;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.OriginalGroupBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroup;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.group.update.UpdatedGroupBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
@@ -29,85 +24,88 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+
 /**
+ * Group Change Listener
+ *  add, update and remove {@link Group} processing from {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}.
  *
  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
  *
  */
 public class GroupChangeListener extends AbstractChangeListener {
 
-    private final static Logger LOG = LoggerFactory.getLogger(GroupChangeListener.class);
-
-    private final SalGroupService salGroupService;
+    private static final Logger LOG = LoggerFactory.getLogger(GroupChangeListener.class);
 
-    public SalGroupService getSalGroupService() {
-        return this.salGroupService;
-    }
+    private final GroupProvider provider;
 
-    public GroupChangeListener(final SalGroupService manager) {
-        this.salGroupService = manager;
+    public GroupChangeListener(final GroupProvider provider) {
+        this.provider = Preconditions.checkNotNull(provider, "GroupProvider can not be null !");
     }
 
     @Override
-    protected void validate() throws IllegalStateException {
-        GroupTransactionValidator.validate(this);
+    protected void remove(final InstanceIdentifier<? extends DataObject> identifier,
+                          final DataObject removeDataObj) {
+
+        final Group group = ((Group) removeDataObj);
+        final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+        final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group);
+
+        builder.setNode(new NodeRef(nodeInstanceId));
+        builder.setGroupRef(new GroupRef(identifier));
+
+        Uri uri = new Uri(this.getTransactionId());
+        builder.setTransactionUri(uri);
+        this.provider.getSalGroupService().removeGroup(builder.build());
+        LOG.debug("Transaction {} - Remove Group has removed group: {}", new Object[]{uri, removeDataObj});
     }
 
     @Override
-    protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
-        if ((removeDataObj instanceof Group)) {
+    protected void update(final InstanceIdentifier<? extends DataObject> identifier,
+                          final DataObject original, final DataObject update) {
 
-            final Group group = ((Group) removeDataObj);
-            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
-            final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group);
+        final Group originalGroup = ((Group) original);
+        final Group updatedGroup = ((Group) update);
+        final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+        final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder();
 
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setGroupRef(new GroupRef(identifier));
+        builder.setNode(new NodeRef(nodeInstanceId));
+        builder.setGroupRef(new GroupRef(identifier));
 
-            Uri uri = new Uri(this.getTransactionId());
-            builder.setTransactionUri(uri);
-            this.salGroupService.removeGroup((RemoveGroupInput) builder.build());
-            LOG.debug("Transaction {} - Remove Group has removed group: {}", new Object[]{uri, removeDataObj});
-        }
-    }
+        Uri uri = new Uri(this.getTransactionId());
+        builder.setTransactionUri(uri);
 
-    @Override
-    protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
-        if (original instanceof Group && update instanceof Group) {
+        builder.setUpdatedGroup((new UpdatedGroupBuilder(updatedGroup)).build());
+        builder.setOriginalGroup((new OriginalGroupBuilder(originalGroup)).build());
 
-            final Group originalGroup = ((Group) original);
-            final Group updatedGroup = ((Group) update);
-            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
-            final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder();
+        this.provider.getSalGroupService().updateGroup(builder.build());
+        LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update});
+    }
 
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setGroupRef(new GroupRef(identifier));
+    @Override
+    protected void add(final InstanceIdentifier<? extends DataObject> identifier,
+                       final DataObject addDataObj) {
 
-            Uri uri = new Uri(this.getTransactionId());
-            builder.setTransactionUri(uri);
+        final Group group = ((Group) addDataObj);
+        final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
+        final AddGroupInputBuilder builder = new AddGroupInputBuilder(group);
 
-            builder.setUpdatedGroup((UpdatedGroup) (new UpdatedGroupBuilder(updatedGroup)).build());
-            builder.setOriginalGroup((OriginalGroup) (new OriginalGroupBuilder(originalGroup)).build());
+        builder.setNode(new NodeRef(nodeInstanceId));
+        builder.setGroupRef(new GroupRef(identifier));
 
-            this.salGroupService.updateGroup((UpdateGroupInput) builder.build());
-            LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update});
-        }
+        Uri uri = new Uri(this.getTransactionId());
+        builder.setTransactionUri(uri);
+        this.provider.getSalGroupService().addGroup(builder.build());
+        LOG.debug("Transaction {} - Add Group has added group: {}", new Object[]{uri, addDataObj});
     }
 
     @Override
-    protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
-        if ((addDataObj instanceof Group)) {
-            final Group group = ((Group) addDataObj);
-            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
-            final AddGroupInputBuilder builder = new AddGroupInputBuilder(group);
-
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setGroupRef(new GroupRef(identifier));
-
-            Uri uri = new Uri(this.getTransactionId());
-            builder.setTransactionUri(uri);
-            this.salGroupService.addGroup((AddGroupInput) builder.build());
-            LOG.debug("Transaction {} - Add Group has added group: {}", new Object[]{uri, addDataObj});
-        }
+    protected boolean preconditionForChange(final InstanceIdentifier<? extends DataObject> identifier,
+            final DataObject dataObj, final DataObject update) {
+
+        final ReadOnlyTransaction trans = this.provider.getDataService().newReadOnlyTransaction();
+        return update != null
+                ? (dataObj instanceof Group && update instanceof Group && isNodeAvailable(identifier, trans))
+                : (dataObj instanceof Group && isNodeAvailable(identifier, trans));
     }
 }
index 9f2806e..a999242 100644 (file)
@@ -7,61 +7,99 @@
  */
 package org.opendaylight.controller.frm.group;
 
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+
+/**
+ * Group Provider registers the {@link GroupChangeListener} and it holds all needed
+ * services for {@link GroupChangeListener}.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
 public class GroupProvider implements AutoCloseable {
 
-    private final static Logger LOG = LoggerFactory.getLogger(GroupProvider.class);
+    private static final Logger LOG = LoggerFactory.getLogger(GroupProvider.class);
 
     private SalGroupService salGroupService;
-    private DataProviderService dataService;
+    private DataBroker dataService;
 
     /* DataChangeListener */
-    private GroupChangeListener groupDataChangeListener;
-    ListenerRegistration<DataChangeListener> groupDataChangeListenerRegistration;
+    private DataChangeListener groupDataChangeListener;
+    private ListenerRegistration<DataChangeListener> groupDataChangeListenerRegistration;
+
+    /**
+     * Provider Initialization Phase.
+     *
+     * @param DataProviderService dataService
+     */
+    public void init (final DataBroker dataService) {
+        LOG.info("FRM Group Config Provider initialization.");
+        this.dataService = Preconditions.checkNotNull(dataService, "DataService can not be null !");
+    }
+
+    /**
+     * Listener Registration Phase
+     *
+     * @param RpcConsumerRegistry rpcRegistry
+     */
+    public void start(final RpcConsumerRegistry rpcRegistry) {
+        Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !");
+
+        this.salGroupService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalGroupService.class),
+                "RPC SalGroupService not found.");
 
-    public void start() {
         /* Build Path */
-        InstanceIdentifierBuilder<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
-        InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
-        InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
-        InstanceIdentifierBuilder<Group> groupChild = augmentFlowCapNode.<Group> child(Group.class);
-        final InstanceIdentifier<? extends DataObject> groupDataObjectPath = groupChild.toInstance();
+        InstanceIdentifier<Group> groupIdentifier = InstanceIdentifier.create(Nodes.class)
+                .child(Node.class).augmentation(FlowCapableNode.class).child(Group.class);
 
         /* DataChangeListener registration */
-        this.groupDataChangeListener = new GroupChangeListener(this.salGroupService);
-        this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener(groupDataObjectPath, groupDataChangeListener);
-        LOG.info("Group Config Provider started.");
-    }
+        this.groupDataChangeListener = new GroupChangeListener(GroupProvider.this);
+        this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener(
+                LogicalDatastoreType.CONFIGURATION, groupIdentifier, groupDataChangeListener, DataChangeScope.SUBTREE);
 
-    protected DataModificationTransaction startChange() {
-        return this.dataService.beginTransaction();
+        LOG.info("FRM Group Config Provider started.");
     }
 
-    public void close() throws Exception {
-        if(groupDataChangeListenerRegistration != null){
-            groupDataChangeListenerRegistration.close();
+    @Override
+    public void close() {
+        LOG.info("FRM Group Config Provider stopped.");
+        if (groupDataChangeListenerRegistration != null) {
+            try {
+                groupDataChangeListenerRegistration.close();
+            } catch (Exception e) {
+                String errMsg = "Error by stop FRM Group Config Provider.";
+                LOG.error(errMsg, e);
+                throw new IllegalStateException(errMsg, e);
+            } finally {
+                groupDataChangeListenerRegistration = null;
+            }
         }
     }
 
-    public void setDataService(final DataProviderService dataService) {
-        this.dataService = dataService;
+    public DataChangeListener getGroupDataChangeListener() {
+        return groupDataChangeListener;
+    }
+
+    public SalGroupService getSalGroupService() {
+        return salGroupService;
     }
 
-    public void setSalGroupService(final SalGroupService salGroupService) {
-        this.salGroupService = salGroupService;
+    public DataBroker getDataService() {
+        return dataService;
     }
 }
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupTransactionValidator.java
deleted file mode 100644 (file)
index 88eea0d..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Copyright (c) 2014 Cisco Systems, 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.controller.frm.group;
-
-public class GroupTransactionValidator {
-
-    public static void validate(GroupChangeListener transaction) throws IllegalStateException {
-        // NOOP
-    }
-}
index 48d5257..a2def84 100644 (file)
@@ -8,19 +8,14 @@
 package org.opendaylight.controller.frm.meter;
 
 import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Uri;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInput;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.OriginalMeterBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.meter.update.UpdatedMeterBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.Meter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef;
@@ -29,86 +24,89 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+
 /**
+ * Meter Change Listener
+ *  add, update and remove {@link Meter} processing from {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}.
  *
  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
  *
  */
 public class MeterChangeListener extends AbstractChangeListener {
 
-    private final static Logger LOG = LoggerFactory.getLogger(MeterChangeListener.class);
-
-    private final SalMeterService salMeterService;
-
-    public SalMeterService getSalMeterService() {
-        return this.salMeterService;
-    }
+    private static final Logger LOG = LoggerFactory.getLogger(MeterChangeListener.class);
 
-    public MeterChangeListener(final SalMeterService manager) {
-        this.salMeterService = manager;
-    }
+    private final MeterProvider provider;
 
-    @Override
-    protected void validate() throws IllegalStateException {
-        MeterTransactionValidator.validate(this);
+    public MeterChangeListener (final MeterProvider provider) {
+        this.provider = Preconditions.checkNotNull(provider, "MeterProvider can not be null !");
     }
 
     @Override
-    protected void remove(InstanceIdentifier<? extends DataObject> identifier, DataObject removeDataObj) {
-        if ((removeDataObj instanceof Meter)) {
+    protected void remove(final InstanceIdentifier<? extends DataObject> identifier,
+                          final DataObject removeDataObj) {
 
-            final Meter meter = ((Meter) removeDataObj);
-            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
-            final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter);
+        final Meter meter = ((Meter) removeDataObj);
+        final InstanceIdentifier<Node> nodeIdent = identifier.firstIdentifierOf(Node.class);
+        final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter);
 
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setMeterRef(new MeterRef(identifier));
+        builder.setNode(new NodeRef(nodeIdent));
+        builder.setMeterRef(new MeterRef(identifier));
 
-            Uri uri = new Uri(this.getTransactionId());
-            builder.setTransactionUri(uri);
-            this.salMeterService.removeMeter((RemoveMeterInput) builder.build());
-            LOG.debug("Transaction {} - Remove Meter has removed meter: {}", new Object[]{uri, removeDataObj});
-        }
+        Uri uri = new Uri(this.getTransactionId());
+        builder.setTransactionUri(uri);
+        this.provider.getSalMeterService().removeMeter(builder.build());
+        LOG.debug("Transaction {} - Remove Meter has removed meter: {}", new Object[]{uri, removeDataObj});
     }
 
     @Override
-    protected void update(InstanceIdentifier<? extends DataObject> identifier, DataObject original, DataObject update) {
-        if (original instanceof Meter && update instanceof Meter) {
+    protected void update(final InstanceIdentifier<? extends DataObject> identifier,
+                          final DataObject original, final DataObject update) {
 
-            final Meter originalMeter = ((Meter) original);
-            final Meter updatedMeter = ((Meter) update);
-            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
-            final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder();
+        final Meter originalMeter = ((Meter) original);
+        final Meter updatedMeter = ((Meter) update);
+        final InstanceIdentifier<Node> nodeInstanceId = identifier.firstIdentifierOf(Node.class);
+        final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder();
 
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setMeterRef(new MeterRef(identifier));
+        builder.setNode(new NodeRef(nodeInstanceId));
+        builder.setMeterRef(new MeterRef(identifier));
 
-            Uri uri = new Uri(this.getTransactionId());
-            builder.setTransactionUri(uri);
+        Uri uri = new Uri(this.getTransactionId());
+        builder.setTransactionUri(uri);
 
-            builder.setUpdatedMeter((UpdatedMeter) (new UpdatedMeterBuilder(updatedMeter)).build());
-            builder.setOriginalMeter((OriginalMeter) (new OriginalMeterBuilder(originalMeter)).build());
+        builder.setUpdatedMeter((new UpdatedMeterBuilder(updatedMeter)).build());
+        builder.setOriginalMeter((new OriginalMeterBuilder(originalMeter)).build());
+
+        this.provider.getSalMeterService().updateMeter(builder.build());
+        LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update});
 
-            this.salMeterService.updateMeter((UpdateMeterInput) builder.build());
-            LOG.debug("Transaction {} - Update Meter has updated meter {} with {}", new Object[]{uri, original, update});
-        }
     }
 
     @Override
-    protected void add(InstanceIdentifier<? extends DataObject> identifier, DataObject addDataObj) {
-        if ((addDataObj instanceof Meter)) {
+    protected void add(final InstanceIdentifier<? extends DataObject> identifier,
+                       final DataObject addDataObj) {
+
+        final Meter meter = ((Meter) addDataObj);
+        final InstanceIdentifier<Node> nodeInstanceId = identifier.firstIdentifierOf(Node.class);
+        final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter);
 
-            final Meter meter = ((Meter) addDataObj);
-            final InstanceIdentifier<Node> nodeInstanceId = identifier.<Node> firstIdentifierOf(Node.class);
-            final AddMeterInputBuilder builder = new AddMeterInputBuilder(meter);
+        builder.setNode(new NodeRef(nodeInstanceId));
+        builder.setMeterRef(new MeterRef(identifier));
 
-            builder.setNode(new NodeRef(nodeInstanceId));
-            builder.setMeterRef(new MeterRef(identifier));
+        Uri uri = new Uri(this.getTransactionId());
+        builder.setTransactionUri(uri);
+        this.provider.getSalMeterService().addMeter(builder.build());
+        LOG.debug("Transaction {} - Add Meter has added meter: {}", new Object[]{uri, addDataObj});
+    }
+
+    @Override
+    protected boolean preconditionForChange(final InstanceIdentifier<? extends DataObject> identifier,
+            final DataObject dataObj, final DataObject update) {
 
-            Uri uri = new Uri(this.getTransactionId());
-            builder.setTransactionUri(uri);
-            this.salMeterService.addMeter((AddMeterInput) builder.build());
-            LOG.debug("Transaction {} - Add Meter has added meter: {}", new Object[]{uri, addDataObj});
-        }
+        final ReadOnlyTransaction trans = this.provider.getDataService().newReadOnlyTransaction();
+        return update != null
+                ? (dataObj instanceof Meter && update instanceof Meter && isNodeAvailable(identifier, trans))
+                : (dataObj instanceof Meter && isNodeAvailable(identifier, trans));
     }
-}
\ No newline at end of file
+}
index 8596c3f..44de7af 100644 (file)
@@ -7,61 +7,99 @@
  */
 package org.opendaylight.controller.frm.meter;
 
-import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Preconditions;
+
+/**
+ * Meter Provider registers the {@link MeterChangeListener} and it holds all needed
+ * services for {@link MeterChangeListener}.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
 public class MeterProvider implements AutoCloseable {
 
-    private final static Logger LOG = LoggerFactory.getLogger(MeterProvider.class);
+    private static final Logger LOG = LoggerFactory.getLogger(MeterProvider.class);
 
-    private DataProviderService dataService;
     private SalMeterService salMeterService;
+    private DataBroker dataService;
 
     /* DataChangeListener */
-    private MeterChangeListener meterDataChangeListener;
-    ListenerRegistration<DataChangeListener> meterDataChangeListenerRegistration;
+    private DataChangeListener meterDataChangeListener;
+    private ListenerRegistration<DataChangeListener> meterDataChangeListenerRegistration;
+
+    /**
+     * Provider Initialization Phase.
+     *
+     * @param DataProviderService dataService
+     */
+    public void init(final DataBroker dataService) {
+        LOG.info("FRM Meter Config Provider initialization.");
+        this.dataService = Preconditions.checkNotNull(dataService, "DataProviderService can not be null !");
+    }
+
+    /**
+     * Listener Registration Phase
+     *
+     * @param RpcConsumerRegistry rpcRegistry
+     */
+    public void start(final RpcConsumerRegistry rpcRegistry) {
+        Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !");
+        this.salMeterService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalMeterService.class),
+                "RPC SalMeterService not found.");
 
-    public void start() {
         /* Build Path */
-        InstanceIdentifierBuilder<Nodes> nodesBuilder = InstanceIdentifier.<Nodes> builder(Nodes.class);
-        InstanceIdentifierBuilder<Node> nodeChild = nodesBuilder.<Node> child(Node.class);
-        InstanceIdentifierBuilder<FlowCapableNode> augmentFlowCapNode = nodeChild.<FlowCapableNode> augmentation(FlowCapableNode.class);
-        InstanceIdentifierBuilder<Meter> meterChild = augmentFlowCapNode.<Meter> child(Meter.class);
-        final InstanceIdentifier<? extends DataObject> meterDataObjectPath = meterChild.toInstance();
+        InstanceIdentifier<Meter> meterIdentifier = InstanceIdentifier.create(Nodes.class)
+                .child(Node.class).augmentation(FlowCapableNode.class).child(Meter.class);
 
         /* DataChangeListener registration */
-        this.meterDataChangeListener = new MeterChangeListener(this.salMeterService);
-        this.meterDataChangeListenerRegistration = this.dataService.registerDataChangeListener(meterDataObjectPath, meterDataChangeListener);
-        LOG.info("Meter Config Provider started.");
-    }
+        this.meterDataChangeListener = new MeterChangeListener(MeterProvider.this);
+        this.meterDataChangeListenerRegistration =
+                this.dataService.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                        meterIdentifier, meterDataChangeListener, DataChangeScope.SUBTREE);
 
-    protected DataModificationTransaction startChange() {
-        return this.dataService.beginTransaction();
+        LOG.info("FRM Meter Config Provider started.");
     }
 
-    public void close() throws Exception {
-        if(meterDataChangeListenerRegistration != null){
-            meterDataChangeListenerRegistration.close();
+    @Override
+    public void close() {
+        LOG.info("FRM Meter Config Provider stopped.");
+        if (meterDataChangeListenerRegistration != null) {
+            try {
+                meterDataChangeListenerRegistration.close();
+            } catch (Exception e) {
+                String errMsg = "Error by stop FRM Meter Config Provider.";
+                LOG.error(errMsg, e);
+                throw new IllegalStateException(errMsg, e);
+            } finally {
+                meterDataChangeListenerRegistration = null;
+            }
         }
     }
 
-    public void setDataService(final DataProviderService dataService) {
-        this.dataService = dataService;
+    public DataChangeListener getMeterDataChangeListener() {
+        return meterDataChangeListener;
+    }
+
+    public DataBroker getDataService() {
+        return dataService;
     }
 
-    public void setSalMeterService(final SalMeterService salMeterService) {
-        this.salMeterService = salMeterService;
+    public SalMeterService getSalMeterService() {
+        return salMeterService;
     }
-}
\ No newline at end of file
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterTransactionValidator.java
deleted file mode 100644 (file)
index c8fba23..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Copyright (c) 2014 Cisco Systems, 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.controller.frm.meter;
-
-public class MeterTransactionValidator {
-
-    public static void validate(MeterChangeListener transaction) throws IllegalStateException {
-        // NOOP
-    }
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java
new file mode 100644 (file)
index 0000000..eb5ae4a
--- /dev/null
@@ -0,0 +1,185 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, 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.controller.frm.reconil;
+
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.frm.AbstractChangeListener;
+import org.opendaylight.controller.frm.FlowCookieProducer;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowTableRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterRef;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ListenableFuture;
+
+/**
+ * forwardingrules-manager
+ * org.opendaylight.controller.frm
+ *
+ * FlowNode Reconciliation Listener
+ * Reconciliation for a new FlowNode
+ * Remove CookieMapKey for removed FlowNode
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Jun 13, 2014
+ */
+public class FlowNodeReconcilListener extends AbstractChangeListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconcilListener.class);
+
+    private final FlowNodeReconcilProvider provider;
+
+    public FlowNodeReconcilListener(final FlowNodeReconcilProvider provider) {
+        this.provider = Preconditions.checkNotNull(provider, "Flow Node Reconcil Provider can not be null!");
+    }
+
+    @Override
+    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
+        /* FlowCapableNode DataObjects for reconciliation */
+        final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
+                changeEvent.getCreatedData().entrySet();
+        /* FlowCapableNode DataObjects for clean FlowCookieHolder */
+        final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
+                changeEvent.getRemovedPaths();
+        for (final Entry<InstanceIdentifier<? extends DataObject>, DataObject> createdEntry : createdEntries) {
+            InstanceIdentifier<? extends DataObject> entryKey = createdEntry.getKey();
+            DataObject entryValue = createdEntry.getValue();
+            if (preconditionForChange(entryKey, entryValue, null)) {
+                this.add(entryKey, entryValue);
+            }
+        }
+        for (final InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers) {
+            Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
+                    changeEvent.getOriginalData();
+            final DataObject removeValue = origConfigData.get(instanceId);
+            if (preconditionForChange(instanceId, removeValue, null)) {
+                this.remove(instanceId, removeValue);
+            }
+        }
+    }
+
+    @Override
+    /* Cleaning FlowCookieManager holder for all node tables */
+    protected void remove(final InstanceIdentifier<? extends DataObject> identifier,
+                          final DataObject removeDataObj) {
+
+        final InstanceIdentifier<FlowCapableNode> flowNodeIdent =
+                identifier.firstIdentifierOf(FlowCapableNode.class);
+        final FlowCapableNode flowNode = ((FlowCapableNode) removeDataObj);
+
+        for (Table flowTable : flowNode.getTable()) {
+            final InstanceIdentifier<Table> tableIdent =
+                    flowNodeIdent.child(Table.class, flowTable.getKey());
+            FlowCookieProducer.INSTANCE.clean(tableIdent);
+        }
+    }
+
+    @Override
+    /* Reconciliation by connect new FlowCapableNode */
+    protected void add(final InstanceIdentifier<? extends DataObject> identifier,
+                       final DataObject addDataObj) {
+
+        final InstanceIdentifier<FlowCapableNode> flowNodeIdent =
+                identifier.firstIdentifierOf(FlowCapableNode.class);
+        final Optional<FlowCapableNode> flowCapNode = this.readFlowCapableNode(flowNodeIdent);
+
+        if (flowCapNode.isPresent()) {
+            final InstanceIdentifier<Node> nodeIdent = identifier.firstIdentifierOf(Node.class);
+            final NodeRef nodeRef = new NodeRef(nodeIdent);
+            /* Groups - have to be first */
+            for (Group group : flowCapNode.get().getGroup()) {
+                final GroupRef groupRef = new GroupRef(flowNodeIdent.child(Group.class, group.getKey()));
+                final AddGroupInputBuilder groupBuilder = new AddGroupInputBuilder(group);
+                groupBuilder.setGroupRef(groupRef);
+                groupBuilder.setNode(nodeRef);
+                this.provider.getSalGroupService().addGroup(groupBuilder.build());
+            }
+            /* Meters */
+            for (Meter meter : flowCapNode.get().getMeter()) {
+                final MeterRef meterRef = new MeterRef(flowNodeIdent.child(Meter.class, meter.getKey()));
+                final AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder(meter);
+                meterBuilder.setMeterRef(meterRef);
+                meterBuilder.setNode(nodeRef);
+                this.provider.getSalMeterService().addMeter(meterBuilder.build());
+            }
+            /* Flows */
+            for (Table flowTable : flowCapNode.get().getTable()) {
+                final InstanceIdentifier<Table> tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey());
+                for (Flow flow : flowTable.getFlow()) {
+                    final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent));
+                    final FlowRef flowRef = new FlowRef(tableIdent.child(Flow.class, flow.getKey()));
+                    final FlowTableRef flowTableRef = new FlowTableRef(tableIdent);
+                    final AddFlowInputBuilder flowBuilder = new AddFlowInputBuilder(flow);
+                    flowBuilder.setCookie(flowCookie);
+                    flowBuilder.setNode(nodeRef);
+                    flowBuilder.setFlowTable(flowTableRef);
+                    flowBuilder.setFlowRef(flowRef);
+                    this.provider.getSalFlowService().addFlow(flowBuilder.build());
+                }
+            }
+        }
+    }
+
+    @Override
+    protected void update(final InstanceIdentifier<? extends DataObject> identifier,
+                          final DataObject original, DataObject update) {
+        // NOOP - Listener is registered for DataChangeScope.BASE only
+    }
+
+    @Override
+    protected boolean preconditionForChange(final InstanceIdentifier<? extends DataObject> identifier,
+                                            final DataObject dataObj, final DataObject update) {
+        return (dataObj instanceof FlowCapableNode);
+    }
+
+    private Optional<FlowCapableNode> readFlowCapableNode(final InstanceIdentifier<FlowCapableNode> flowNodeIdent) {
+        ReadOnlyTransaction readTrans = this.provider.getDataService().newReadOnlyTransaction();
+        try {
+            ListenableFuture<Optional<FlowCapableNode>> confFlowNode =
+                    readTrans.read(LogicalDatastoreType.CONFIGURATION, flowNodeIdent);
+            if (confFlowNode.get().isPresent()) {
+                return Optional.<FlowCapableNode> of(confFlowNode.get().get());
+            } else {
+                return Optional.absent();
+            }
+        }
+        catch (InterruptedException | ExecutionException e) {
+            LOG.error("Unexpected exception by reading flow ".concat(flowNodeIdent.toString()), e);
+            return Optional.absent();
+        }
+        finally {
+            readTrans.close();
+        }
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java
new file mode 100644 (file)
index 0000000..ad970d6
--- /dev/null
@@ -0,0 +1,115 @@
+/**
+ * Copyright (c) 2014 Cisco Systems, 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.controller.frm.reconil;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.SalGroupService;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+/**
+ * forwardingrules-manager
+ * org.opendaylight.controller.frm
+ *
+ * FlowNode Reconciliation Provider registers the FlowNodeReconilListener
+ * and it holds all needed services for FlowNodeReconcilListener.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Jun 13, 2014
+ */
+public class FlowNodeReconcilProvider implements AutoCloseable {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconcilProvider.class);
+
+    private SalFlowService salFlowService;
+    private SalMeterService salMeterService;
+    private SalGroupService salGroupService;
+    private DataBroker dataService;
+
+    /* DataChangeListener */
+    private DataChangeListener flowNodeReconcilListener;
+    private ListenerRegistration<DataChangeListener> flowNodeReconcilListenerRegistration;
+
+    public void init (final DataBroker dataService) {
+        LOG.info("FRM Flow Node Config Reconcil Provider initialization.");
+
+        this.dataService = Preconditions.checkNotNull(dataService, "DataProviderService can not be null !");
+    }
+
+    public void start( final RpcConsumerRegistry rpcRegistry ) {
+        Preconditions.checkArgument(rpcRegistry != null, "RpcConcumerRegistry can not be null !");
+
+        this.salFlowService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalFlowService.class),
+                "RPC SalFlowService not found.");
+        this.salMeterService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalMeterService.class),
+                "RPC SalMeterService not found.");
+        this.salGroupService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalGroupService.class),
+                "RPC SalGroupService not found.");
+
+        /* Build Path */
+        InstanceIdentifier<FlowCapableNode> flowCapableNodeIdent =
+                InstanceIdentifier.create(Nodes.class).child(Node.class).augmentation(FlowCapableNode.class);
+
+        /* ReconcilNotificationListener registration */
+        this.flowNodeReconcilListener = new FlowNodeReconcilListener(FlowNodeReconcilProvider.this);
+        this.flowNodeReconcilListenerRegistration = this.dataService.registerDataChangeListener(
+                LogicalDatastoreType.OPERATIONAL, flowCapableNodeIdent, flowNodeReconcilListener, DataChangeScope.BASE);
+        LOG.info("FRM Flow Node Config Reconcil Provider started.");
+    }
+
+    @Override
+    public void close() {
+        LOG.info("FRM Flow Node Config Reconcil Provider stopped.");
+        if (flowNodeReconcilListenerRegistration != null) {
+            try {
+                flowNodeReconcilListenerRegistration.close();
+            } catch (Exception e) {
+                String errMsg = "Error by stop FRM Flow Node Config Reconcil Provider.";
+                LOG.error(errMsg, e);
+                throw new IllegalStateException(errMsg, e);
+            } finally {
+                flowNodeReconcilListenerRegistration = null;
+            }
+        }
+    }
+
+    public DataChangeListener getFlowNodeReconcilListener() {
+        return flowNodeReconcilListener;
+    }
+
+    public DataBroker getDataService() {
+        return dataService;
+    }
+
+    public SalFlowService getSalFlowService() {
+        return salFlowService;
+    }
+
+    public SalMeterService getSalMeterService() {
+        return salMeterService;
+    }
+
+    public SalGroupService getSalGroupService() {
+        return salGroupService;
+    }
+}
index 65362a1..605cb90 100644 (file)
@@ -229,4 +229,16 @@ module flow-node-inventory {
         uses flow-node-connector;
     }
 
+    augment "/inv:nodes/inv:node/table" {
+        ext:augment-identifier "flow-cookie-mapping";
+        list flow-cookie-map {
+            key "cookie";
+            leaf cookie {
+                type flow:flow-cookie;
+            }
+            leaf-list flow-ids {
+                type flow-id;
+            }
+        }
+    }
 }
index b1db280..cd9738c 100644 (file)
@@ -32,6 +32,9 @@ final class FlowComparator {
     }
 
     public static boolean flowEquals(Flow statsFlow, Flow storedFlow) {
+        if (statsFlow == null || storedFlow == null) {
+            return false;
+        }
         if (statsFlow.getClass() != storedFlow.getClass()) {
             return false;
         }
@@ -42,19 +45,18 @@ final class FlowComparator {
         } else if(!statsFlow.getContainerName().equals(storedFlow.getContainerName())) {
             return false;
         }
-        if (statsFlow.getMatch()== null) {
-            if (storedFlow.getMatch() != null) {
+        if (storedFlow.getPriority() == null) {
+            if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) {
                 return false;
             }
-        } //else if(!statsFlow.getMatch().equals(storedFlow.getMatch())) {
-        else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
+        } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
             return false;
         }
-        if (storedFlow.getPriority() == null) {
-            if (statsFlow.getPriority() != null && statsFlow.getPriority()!= 0x8000) {
+        if (statsFlow.getMatch()== null) {
+            if (storedFlow.getMatch() != null) {
                 return false;
             }
-        } else if(!statsFlow.getPriority().equals(storedFlow.getPriority())) {
+        } else if(!matchEquals(statsFlow.getMatch(), storedFlow.getMatch())) {
             return false;
         }
         if (statsFlow.getTableId() == null) {
index 1a14de6..e92d0bd 100644 (file)
@@ -7,14 +7,20 @@
  */
 package org.opendaylight.controller.md.statistics.manager;
 
+import java.math.BigInteger;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Map.Entry;
 
 import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
 import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCookieMapping;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMap;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.nodes.node.table.FlowCookieMapKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
@@ -29,6 +35,7 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.O
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.and.statistics.map.list.FlowAndStatisticsMapListBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.statistics.rev130819.flow.statistics.FlowStatisticsBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowCookie;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.model.statistics.types.rev130925.GenericStatistics;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
@@ -36,12 +43,16 @@ import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.base.Optional;
+
 final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatisticsMapList, FlowStatsEntry> {
-    private static final Logger logger = LoggerFactory.getLogger(FlowStatsTracker.class);
+    private static final Logger LOG = LoggerFactory.getLogger(FlowStatsTracker.class);
+    private static final String ALIEN_SYSTEM_FLOW_ID = "#UF$TABLE*";
     private final OpendaylightFlowStatisticsService flowStatsService;
     private FlowTableStatsTracker flowTableStats;
     private int unaccountedFlowsCounter = 1;
 
+
     FlowStatsTracker(final OpendaylightFlowStatisticsService flowStatsService, final FlowCapableContext context) {
         super(context);
         this.flowStatsService = flowStatsService;
@@ -66,15 +77,15 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatis
 
         FlowStatisticsDataBuilder flowStatisticsData = new FlowStatisticsDataBuilder();
 
-        FlowBuilder flow = new FlowBuilder(map);
-        if(map.getFlowId() != null) {
-            flow.setId(new FlowId(map.getFlowId().getValue()));
+        FlowBuilder flowBuilder = new FlowBuilder(map);
+        if (map.getFlowId() != null) {
+            flowBuilder.setId(new FlowId(map.getFlowId().getValue()));
         }
-        if(map.getFlowId()!= null) {
-            flow.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
+        if (map.getFlowId() != null) {
+            flowBuilder.setKey(new FlowKey(new FlowId(map.getKey().getFlowId().getValue())));
         }
 
-        Flow flowRule = flow.build();
+        Flow flowRule = flowBuilder.build();
 
         FlowAndStatisticsMapListBuilder stats = new FlowAndStatisticsMapListBuilder();
         stats.setByteCount(map.getByteCount());
@@ -92,76 +103,45 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatis
 
         flowStatisticsData.setFlowStatistics(flowStatistics.build());
 
-        logger.debug("Flow : {}",flowRule.toString());
-        logger.debug("Statistics to augment : {}",flowStatistics.build().toString());
+        LOG.debug("Flow : {}",flowRule.toString());
+        LOG.debug("Statistics to augment : {}",flowStatistics.build().toString());
 
         InstanceIdentifier<Table> tableRef = getNodeIdentifierBuilder()
-                .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(tableId)).toInstance();
-
-        //TODO: Not a good way to do it, need to figure out better way.
-        //TODO: major issue in any alternate approach is that flow key is incrementally assigned
-        //to the flows stored in data store.
-        // Augment same statistics to all the matching masked flow
-        Table table= (Table)trans.readConfigurationData(tableRef);
-        if(table != null){
-            for(Flow existingFlow : table.getFlow()){
-                logger.debug("Existing flow in data store : {}",existingFlow.toString());
-                if(FlowComparator.flowEquals(flowRule,existingFlow)){
-                    InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
-                            .augmentation(FlowCapableNode.class)
-                            .child(Table.class, new TableKey(tableId))
-                            .child(Flow.class,existingFlow.getKey()).toInstance();
-                    flow.setKey(existingFlow.getKey());
-                    flow.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-                    logger.debug("Found matching flow in the datastore, augmenting statistics");
-                    // Update entry with timestamp of latest response
-                    FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
-                    trans.putOperationalData(flowRef, flow.build());
-                    return flowStatsEntry;
-                }
-            }
-        }
-
-        table = (Table)trans.readOperationalData(tableRef);
-        if(table != null){
-            for(Flow existingFlow : table.getFlow()){
-                FlowStatisticsData augmentedflowStatisticsData = existingFlow.getAugmentation(FlowStatisticsData.class);
-                if(augmentedflowStatisticsData != null){
-                    FlowBuilder existingOperationalFlow = new FlowBuilder();
-                    existingOperationalFlow.fieldsFrom(augmentedflowStatisticsData.getFlowStatistics());
-                    logger.debug("Existing unaccounted flow in operational data store : {}",existingFlow.toString());
-                    if(FlowComparator.flowEquals(flowRule,existingOperationalFlow.build())){
-                        InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
-                                .augmentation(FlowCapableNode.class)
-                                .child(Table.class, new TableKey(tableId))
-                                .child(Flow.class,existingFlow.getKey()).toInstance();
-                        flow.setKey(existingFlow.getKey());
-                        flow.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-                        logger.debug("Found matching unaccounted flow in the operational datastore, augmenting statistics");
-                        // Update entry with timestamp of latest response
-                        FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
-                        trans.putOperationalData(flowRef, flow.build());
-                        return flowStatsEntry;
-                    }
-                }
+                .augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(tableId)).toInstance();
+
+        final FlowCookie flowCookie = flowRule.getCookie() != null
+                ? flowRule.getCookie() : new FlowCookie(BigInteger.ZERO);
+        final InstanceIdentifier<FlowCookieMap> flowCookieRef = tableRef
+                .augmentation(FlowCookieMapping.class)
+                .child(FlowCookieMap.class, new FlowCookieMapKey(flowCookie));
+
+        FlowCookieMap cookieMap = (FlowCookieMap) trans.readOperationalData(flowCookieRef);
+
+        /* find flowKey in FlowCookieMap from DataStore/OPERATIONAL */
+        Optional<FlowKey> flowKey = this.getExistFlowKey(flowRule, tableRef, trans, cookieMap);
+        if ( ! flowKey.isPresent()) {
+            /* DataStore/CONFIG For every first statistic needs to be created */
+            flowKey = this.getFlowKeyFromExistFlow(flowRule, tableRef, trans);
+            if ( ! flowKey.isPresent()) {
+                /* Alien flow */
+                flowKey = this.makeAlienFlowKey(flowRule);
             }
+            cookieMap = applyNewFlowKey(cookieMap, flowKey, flowCookie);
+            trans.putOperationalData(flowCookieRef, cookieMap);
         }
 
-        String flowKey = "#UF$TABLE*"+Short.toString(tableId)+"*"+Integer.toString(this.unaccountedFlowsCounter);
-        this.unaccountedFlowsCounter++;
-        FlowKey newFlowKey = new FlowKey(new FlowId(flowKey));
-        InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder().augmentation(FlowCapableNode.class)
-                    .child(Table.class, new TableKey(tableId))
-                    .child(Flow.class,newFlowKey).toInstance();
-        flow.setKey(newFlowKey);
-        flow.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
-        logger.debug("Flow {} is not present in config data store, augmenting statistics as an unaccounted flow",
-                    flow.build());
+        InstanceIdentifier<Flow> flowRef = getNodeIdentifierBuilder()
+                .augmentation(FlowCapableNode.class)
+                .child(Table.class, new TableKey(tableId))
+                .child(Flow.class, flowKey.get()).toInstance();
+        flowBuilder.setKey(flowKey.get());
+        flowBuilder.addAugmentation(FlowStatisticsData.class, flowStatisticsData.build());
 
         // Update entry with timestamp of latest response
-        flow.setKey(newFlowKey);
-        FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId,flow.build());
-        trans.putOperationalData(flowRef, flow.build());
+        flowBuilder.setKey(flowKey.get());
+        FlowStatsEntry flowStatsEntry = new FlowStatsEntry(tableId, flowBuilder.build());
+        trans.putOperationalData(flowRef, flowBuilder.build());
         return flowStatsEntry;
     }
 
@@ -180,9 +160,9 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatis
         // FIXME: it does not make sense to trigger this before sendAllFlowTablesStatisticsRequest()
         //        comes back -- we do not have any tables anyway.
         final Collection<TableKey> tables = flowTableStats.getTables();
-        logger.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size());
+        LOG.debug("Node {} supports {} table(s)", this.getNodeRef(), tables.size());
         for (final TableKey key : tables) {
-            logger.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef());
+            LOG.debug("Send aggregate stats request for flow table {} to node {}", key.getId(), this.getNodeRef());
             this.requestAggregateFlows(key);
         }
 
@@ -224,10 +204,10 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatis
         for (Entry<InstanceIdentifier<?>, DataObject> e : change.getCreatedConfigurationData().entrySet()) {
             if (Flow.class.equals(e.getKey().getTargetType())) {
                 final Flow flow = (Flow) e.getValue();
-                logger.debug("Key {} triggered request for flow {}", e.getKey(), flow);
+                LOG.debug("Key {} triggered request for flow {}", e.getKey(), flow);
                 requestFlow(flow);
             } else {
-                logger.debug("Ignoring key {}", e.getKey());
+                LOG.debug("Ignoring key {}", e.getKey());
             }
         }
 
@@ -236,7 +216,7 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatis
             if (Flow.class.equals(key.getTargetType())) {
                 @SuppressWarnings("unchecked")
                 final InstanceIdentifier<Flow> flow = (InstanceIdentifier<Flow>)key;
-                logger.debug("Key {} triggered remove of Flow from operational space.", key);
+                LOG.debug("Key {} triggered remove of Flow from operational space.", key);
                 trans.removeOperationalData(flow);
             }
         }
@@ -246,10 +226,79 @@ final class FlowStatsTracker extends AbstractListeningStatsTracker<FlowAndStatis
     @Override
     public void start(final DataBrokerService dbs) {
         if (flowStatsService == null) {
-            logger.debug("No Flow Statistics service, not subscribing to flows on node {}", getNodeIdentifier());
+            LOG.debug("No Flow Statistics service, not subscribing to flows on node {}", getNodeIdentifier());
             return;
         }
 
         super.start(dbs);
     }
+
+    /* Returns Exist FlowKey from exist FlowCookieMap identified by cookie
+     * and by switch flow identification (priority and match)*/
+    private Optional<FlowKey> getExistFlowKey(final Flow flowRule, final InstanceIdentifier<Table> tableRef,
+            final DataModificationTransaction trans, final FlowCookieMap cookieMap) {
+
+        if (cookieMap != null) {
+            for (FlowId flowId : cookieMap.getFlowIds()) {
+                InstanceIdentifier<Flow> flowIdent = tableRef.child(Flow.class, new FlowKey(flowId));
+                if (flowId.getValue().startsWith(ALIEN_SYSTEM_FLOW_ID)) {
+                    LOG.debug("Search for flow in the operational datastore by flowID: {} ", flowIdent);
+                    Flow readedFlow = (Flow) trans.readOperationalData(flowIdent);
+                    if (FlowComparator.flowEquals(flowRule, readedFlow)) {
+                        return Optional.<FlowKey> of(new FlowKey(flowId));
+                    }
+                } else {
+                    LOG.debug("Search for flow in the configuration datastore by flowID: {} ", flowIdent);
+                    Flow readedFlow = (Flow) trans.readConfigurationData(flowIdent);
+                    if (FlowComparator.flowEquals(flowRule, readedFlow)) {
+                        return Optional.<FlowKey> of(new FlowKey(flowId));
+                    }
+                }
+            }
+            LOG.debug("Flow was not found in the datastore. Flow {} ", flowRule);
+        }
+        return Optional.absent();
+    }
+
+    /* Returns FlowKey from existing Flow in DataStore/CONFIGURATIONAL which is identified by cookie
+     * and by switch flow identification (priority and match) */
+    private Optional<FlowKey> getFlowKeyFromExistFlow(final Flow flowRule, final InstanceIdentifier<Table> tableRef,
+            final DataModificationTransaction trans) {
+
+        /* Try to find it in DataSotre/CONFIG */
+        Table table= (Table)trans.readConfigurationData(tableRef);
+        if(table != null) {
+            for(Flow existingFlow : table.getFlow()) {
+                LOG.debug("Existing flow in data store : {}",existingFlow.toString());
+                if(FlowComparator.flowEquals(flowRule,existingFlow)){
+                    return Optional.<FlowKey> of(new FlowKey(existingFlow.getId()));
+                }
+            }
+        }
+        return Optional.absent();
+    }
+
+    /* Returns FlowKey which doesn't exist in any DataStore for now */
+    private Optional<FlowKey> makeAlienFlowKey(final Flow flowRule) {
+
+        StringBuilder sBuilder = new StringBuilder(ALIEN_SYSTEM_FLOW_ID)
+            .append(flowRule.getTableId()).append("-").append(this.unaccountedFlowsCounter);
+        this.unaccountedFlowsCounter++;
+        final FlowId flowId = new FlowId(sBuilder.toString());
+        return Optional.<FlowKey> of(new FlowKey(flowId));
+    }
+
+    /* Build new whole FlowCookieMap or add new flowKey */
+    private FlowCookieMap applyNewFlowKey(FlowCookieMap flowCookieMap, final Optional<FlowKey> flowKey,
+            final FlowCookie flowCookie) {
+        if (flowCookieMap != null) {
+            flowCookieMap.getFlowIds().add(flowKey.get().getId());
+        } else {
+            final FlowCookieMapBuilder flowCookieMapBuilder = new FlowCookieMapBuilder();
+            flowCookieMapBuilder.setCookie(flowCookie);
+            flowCookieMapBuilder.setFlowIds(Collections.singletonList(flowKey.get().getId()));
+            flowCookieMap = flowCookieMapBuilder.build();
+        }
+        return flowCookieMap;
+    }
 }

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.