FRM performance refactoring: 94/10294/9
authorVaclav Demcak <vdemcak@cisco.com>
Thu, 28 Aug 2014 15:22:42 +0000 (17:22 +0200)
committerVaclav Demcak <vdemcak@cisco.com>
Thu, 28 Aug 2014 15:22:42 +0000 (17:22 +0200)
* Interface definitions for FRM functionality
* ForwardingRulesManager (old provider)
* ForwardingRulesCommiter (DS changeListener/sender for SalServices)
* FlowNodeReconciliation (reconcil contract definition)
* Centralization Provider/Manager bundle functionality
* fix possibility not unique transaction ID
* implement active NodeHolder (remove unnecessary Operation/DS check)
* Listeners
* identify correct data by wildCarded InstanceIdentifier
* move registration functionality to listener class
* remove all unnecessary functionality
* functionality fragmented
* Cleaning
* move FlowCookie to StatistManager (performance killer, fixing update Flow functionality,
 possibly speed up delete functionality)
* cleaning unnecessary object creation
* Added MockTests

tests PASS: https://jenkins.opendaylight.org/integration/job/integration-master-csit-base-of13/
(Base-OF13/AD_SAL_NSF/TopologyManager/getTopology sometimes fail)

Change-Id: If5ec9920e4574bd170192b14ca978fb628fd051b
Signed-off-by: Vaclav Demcak <vdemcak@cisco.com>
Signed-off-by: Jan Hajnar <jhajnar@cisco.com>
Signed-off-by: Vaclav Demcak <vdemcak@cisco.com>
33 files changed:
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java [deleted file]
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 [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowNodeReconciliation.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/ForwardingRulesCommiter.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/ForwardingRulesManager.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/AbstractListeningCommiter.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowForwarder.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowNodeReconciliationImpl.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/ForwardingRulesManagerImpl.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/GroupForwarder.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/MeterForwarder.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilProvider.java [deleted file]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/FlowListenerTest.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/GroupListenerTest.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/MeterListenerTest.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/NodeListenerTest.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/AbstractDataBrokerTest.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/AbstractSchemaAwareTest.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/DataBrokerTestCustomizer.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/FRMTest.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/MockSchemaService.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/RpcProviderRegistryMock.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/SalFlowServiceMock.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/SalGroupServiceMock.java [new file with mode: 0644]
opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/SalMeterServiceMock.java [new file with mode: 0644]

diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/AbstractChangeListener.java
deleted file mode 100644 (file)
index 130c096..0000000
+++ /dev/null
@@ -1,173 +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;
-
-import java.util.HashSet;
-import java.util.Map;
-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.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(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
-        this.transactionId = this.newTransactionIdentifier().toString();
-        /* All DataObjects for create */
-        final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
-                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.getUpdatedData().entrySet();
-        updatedEntries.addAll(updateConfigEntrySet);
-        updatedEntries.removeAll(createdEntries);
-        /* All DataObjects for remove */
-        final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
-                changeEvent.getRemovedPaths();
-        /* Create DataObject processing (send to device) */
-        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 Entry<InstanceIdentifier<?>, DataObject> updatedEntrie : updatedEntries) {
-            Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
-                    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.getOriginalData();
-
-            final DataObject removeValue = origConfigData.get(instanceId);
-            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;
-    }
-
-    private Object newTransactionIdentifier() {
-        return "DOM-" + txNum.getAndIncrement();
-    }
-
-    /**
-     * 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);
-
-    /**
-     * 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);
-
-    /**
-     * 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 c75c644..9878d16 100644 (file)
@@ -7,10 +7,7 @@
  */
 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.frm.impl.ForwardingRulesManagerImpl;
 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;
@@ -21,8 +18,7 @@ import org.slf4j.LoggerFactory;
 /**
  * Forwarding Rules Manager Activator
  *
- * Activator manages all Providers ({@link FlowProvider}, {@link GroupProvider},
- * {@link MeterProvider} and the {@link FlowNodeReconcilProvider}).
+ * Activator {@link ForwardingRulesManager}.
  * It registers all listeners (DataChangeEvent, ReconcilNotification)
  * in the Session Initialization phase.
  *
@@ -33,56 +29,33 @@ public class FRMActivator extends AbstractBindingAwareProvider {
 
     private final static Logger LOG = LoggerFactory.getLogger(FRMActivator.class);
 
-    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();
-    }
+    private ForwardingRulesManager  manager;
 
     @Override
-    public void onSessionInitiated(final ProviderContext session) {
+    public void onSessionInitiated(ProviderContext session) {
         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);
+            final DataBroker dataBroker = session.getSALService(DataBroker.class);
+            this.manager = new ForwardingRulesManagerImpl(dataBroker, session);
+            this.manager.start();
+            LOG.info("FRMActivator initialization successfull.");
+        }
+        catch (Exception e) {
+            LOG.error("Unexpected error by FRM initialization!", e);
+            this.stopImpl(null);
         }
     }
 
     @Override
     protected void stopImpl(final BundleContext context) {
-        try {
-            this.flowProvider.close();
-            this.groupProvider.close();
-            this.meterProvider.close();
-            this.flowNodeReconcilProvider.close();
-        } catch (Exception e) {
-            LOG.error("Unexpected error by stopping FRMActivator", e);
+        if (manager != null) {
+            try {
+                manager.close();
+            } catch (Exception e) {
+                LOG.error("Unexpected error by stopping FRMActivator", e);
+            }
+            manager = null;
+            LOG.info("FRMActivator stopped.");
         }
     }
   }
\ 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
deleted file mode 100644 (file)
index d7b54e8..0000000
+++ /dev/null
@@ -1,79 +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;
-
-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 !");
-    }
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowNodeReconciliation.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/FlowNodeReconciliation.java
new file mode 100644 (file)
index 0000000..fb3178d
--- /dev/null
@@ -0,0 +1,59 @@
+/**
+ * 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 org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * forwardingrules-manager
+ * org.opendaylight.controller.frm
+ *
+ * FlowNodeReconciliation
+ * It represent Reconciliation functionality for every new device.
+ * So we have to read all possible pre-configured Flows, Meters and Groups from
+ * Config/DS and add all to new device.
+ * New device is represented by new {@link org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode}
+ * in Operational/DS. So we have to add listener for Wildcarded path in base data change scope.
+ *
+ * WildCarded InstanceIdentifier:
+ * {@code
+ *
+ * InstanceIdentifier.create(Nodes.class).child(Node.class).augmentation(FlowCapableNode.class)
+ *
+ * }
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Aug 26, 2014
+ */
+public interface FlowNodeReconciliation extends DataChangeListener, AutoCloseable {
+
+    /**
+     * Method contains Node registration to {@link ForwardingRulesManager} functionality
+     * as a prevention to use a validation check to the Operational/DS for identify
+     * pre-configure transaction and serious device commit in every transaction.
+     *
+     * Second part of functionality is own reconciliation pre-configure
+     * Flows, Meters and Groups.
+     *
+     * @param connectedNode - {@link org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier} to new Node
+     */
+    void flowNodeConnected(InstanceIdentifier<FlowCapableNode> connectedNode);
+
+    /**
+     * Method contains functionality for registered Node {@FlowCapableNode} removing
+     * from {@Link ForwardingRulesManager}
+     *
+     * @param disconnectedNode - {@link org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier} to removed Node
+     */
+    void flowNodeDisconnected(InstanceIdentifier<FlowCapableNode> disconnectedNode);
+}
+
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/ForwardingRulesCommiter.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/ForwardingRulesCommiter.java
new file mode 100644 (file)
index 0000000..2228785
--- /dev/null
@@ -0,0 +1,64 @@
+/**
+ * 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 org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * forwardingrules-manager
+ * org.opendaylight.controller.frm
+ *
+ * ForwardingRulesCommiter
+ * It represent a contract between DataStore DataChangeEvent and relevant
+ * SalRpcService for device. Every implementation has to be registered for
+ * Configurational/DS tree path.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Aug 25, 2014
+ */
+public interface ForwardingRulesCommiter <D extends DataObject> extends AutoCloseable, DataChangeListener {
+
+    /**
+     * Method removes DataObject which is identified by InstanceIdentifier
+     * from device.
+     *
+     * @param InstanceIdentifier identifier - the whole path to DataObject
+     * @param DataObject remove - DataObject for removing
+     * @param InstanceIdentifier<FlowCapableNode> parent Node InstanceIdentifier
+     */
+    void remove(InstanceIdentifier<D> identifier, D del,
+            InstanceIdentifier<FlowCapableNode> nodeIdent);
+
+    /**
+     * 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)
+     */
+    void update(InstanceIdentifier<D> identifier, D original, D update,
+            InstanceIdentifier<FlowCapableNode> nodeIdent);
+
+    /**
+     * 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
+     */
+    void add(InstanceIdentifier<D> identifier, D add,
+            InstanceIdentifier<FlowCapableNode> nodeIdent);
+
+}
+
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/ForwardingRulesManager.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/ForwardingRulesManager.java
new file mode 100644 (file)
index 0000000..504c108
--- /dev/null
@@ -0,0 +1,125 @@
+/**
+ * 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 org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+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.Flow;
+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.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * forwardingrules-manager
+ * org.opendaylight.controller.frm
+ *
+ * ForwardingRulesManager
+ * It represent a central point for whole modul. Implementation
+ * 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>
+ *
+ * Created: Aug 25, 2014
+ */
+public interface ForwardingRulesManager extends AutoCloseable {
+
+    public void start();
+
+    /**
+     * Method returns information :
+     * "is Node with send InstanceIdentifier connected"?
+     *
+     * @param InstanceIdentifier<FlowCapableNode> ident - the key of the node
+     * @return boolean - is device connected
+     */
+    public boolean isNodeActive(InstanceIdentifier<FlowCapableNode> ident);
+
+    /**
+     * Method add new {@link FlowCapableNode} to active Node Holder.
+     * ActiveNodeHolder prevent unnecessary Operational/DS read for identify
+     * pre-configure and serious Configure/DS transactions.
+     *
+     * @param InstanceIdentifier<FlowCapableNode> ident - the key of the node
+     */
+    public void registrateNewNode(InstanceIdentifier<FlowCapableNode> ident);
+
+    /**
+     * Method remove disconnected {@link FlowCapableNode} from active Node
+     * Holder. And all next flows or groups or meters will stay in Config/DS
+     * only.
+     *
+     * @param InstanceIdentifier<FlowCapableNode> ident - the key of the node
+     */
+    public void unregistrateNode(InstanceIdentifier<FlowCapableNode> ident);
+
+    /**
+     * Method returns generated transaction ID, which is unique for
+     * every transaction. ID is composite from prefix ("DOM") and unique number.
+     *
+     * @return String transactionID for RPC transaction identification
+     */
+    public String getNewTransactionId();
+
+    /**
+     * Method returns Read Transacion. It is need for Node reconciliation only.
+     *
+     * @return ReadOnlyTransaction
+     */
+    public ReadOnlyTransaction getReadTranaction();
+
+    /**
+     * Flow RPC service
+     *
+     * @return
+     */
+    public SalFlowService getSalFlowService();
+
+    /**
+     * Group RPC service
+     *
+     * @return
+     */
+    public SalGroupService getSalGroupService();
+
+    /**
+     * Meter RPC service
+     *
+     * @return
+     */
+    public SalMeterService getSalMeterService();
+
+    /**
+     * Content definition method and prevent code duplicity in Reconcil
+     * @return ForwardingRulesCommiter<Flow>
+     */
+    public ForwardingRulesCommiter<Flow> getFlowCommiter();
+
+    /**
+     * Content definition method and prevent code duplicity in Reconcil
+     * @return ForwardingRulesCommiter<Group>
+     */
+    public ForwardingRulesCommiter<Group> getGroupCommiter();
+
+    /**
+     * Content definition method and prevent code duplicity
+     * @return ForwardingRulesCommiter<Meter>
+     */
+    public ForwardingRulesCommiter<Meter> getMeterCommiter();
+
+    /**
+     * Content definition method
+     * @return FlowNodeReconciliation
+     */
+    public FlowNodeReconciliation getFlowNodeReconciliation();
+}
+
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowChangeListener.java
deleted file mode 100644 (file)
index c10b0da..0000000
+++ /dev/null
@@ -1,126 +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;
-
-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.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.RemoveFlowInputBuilder;
-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.OriginalFlowBuilder;
-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.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;
-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.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 static final Logger LOG = LoggerFactory.getLogger(FlowChangeListener.class);
-
-    private final FlowProvider provider;
-
-    public FlowChangeListener (final FlowProvider provider) {
-        this.provider = Preconditions.checkNotNull(provider, "FlowProvider can not be null !");
-    }
-
-    @Override
-    protected void remove(final InstanceIdentifier<? extends DataObject> identifier,
-                          final DataObject 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(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();
-
-        builder.setNode(new NodeRef(nodeIdent));
-        builder.setFlowRef(new FlowRef(identifier));
-
-        Uri uri = new Uri(this.getTransactionId());
-        builder.setTransactionUri(uri);
-
-        builder.setUpdatedFlow((new UpdatedFlowBuilder(updatedFlow)).build());
-        builder.setOriginalFlow((new OriginalFlowBuilder(originalFlow)).build());
-
-        this.provider.getSalFlowService().updateFlow(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 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));
-    }
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/flow/FlowProvider.java
deleted file mode 100644 (file)
index 8c248fa..0000000
+++ /dev/null
@@ -1,107 +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;
-
-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;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.SalFlowService;
-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.InstanceIdentifier;
-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 static final Logger LOG = LoggerFactory.getLogger(FlowProvider.class);
-
-    private SalFlowService salFlowService;
-    private DataBroker dataService;
-
-    /* DataChangeListener */
-    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.");
-
-        /* Build Path */
-        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(FlowProvider.this);
-        this.flowDataChangeListenerRegistration =
-                this.dataService.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
-                        flowIdentifier, flowDataChangeListener, DataChangeScope.SUBTREE);
-
-        LOG.info("FRM Flow Config Provider started.");
-    }
-
-    @Override
-    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 DataChangeListener getFlowDataChangeListener() {
-        return flowDataChangeListener;
-    }
-
-    public SalFlowService getSalFlowService() {
-        return salFlowService;
-    }
-
-    public DataBroker getDataService() {
-        return dataService;
-    }
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupChangeListener.java
deleted file mode 100644 (file)
index 9b03eaa..0000000
+++ /dev/null
@@ -1,111 +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;
-
-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.AddGroupInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder;
-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.OriginalGroupBuilder;
-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;
-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.yangtools.yang.binding.DataObject;
-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 static final Logger LOG = LoggerFactory.getLogger(GroupChangeListener.class);
-
-    private final GroupProvider provider;
-
-    public GroupChangeListener(final GroupProvider provider) {
-        this.provider = Preconditions.checkNotNull(provider, "GroupProvider can not be null !");
-    }
-
-    @Override
-    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 update(final InstanceIdentifier<? extends DataObject> identifier,
-                          final DataObject original, final DataObject update) {
-
-        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));
-
-        Uri uri = new Uri(this.getTransactionId());
-        builder.setTransactionUri(uri);
-
-        builder.setUpdatedGroup((new UpdatedGroupBuilder(updatedGroup)).build());
-        builder.setOriginalGroup((new OriginalGroupBuilder(originalGroup)).build());
-
-        this.provider.getSalGroupService().updateGroup(builder.build());
-        LOG.debug("Transaction {} - Update Group has updated group {} with group {}", new Object[]{uri, original, update});
-    }
-
-    @Override
-    protected void add(final InstanceIdentifier<? extends DataObject> identifier,
-                       final DataObject addDataObj) {
-
-        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.provider.getSalGroupService().addGroup(builder.build());
-        LOG.debug("Transaction {} - Add Group has added group: {}", new Object[]{uri, addDataObj});
-    }
-
-    @Override
-    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));
-    }
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/group/GroupProvider.java
deleted file mode 100644 (file)
index a999242..0000000
+++ /dev/null
@@ -1,105 +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;
-
-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.InstanceIdentifier;
-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 static final Logger LOG = LoggerFactory.getLogger(GroupProvider.class);
-
-    private SalGroupService salGroupService;
-    private DataBroker dataService;
-
-    /* DataChangeListener */
-    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.");
-
-        /* Build Path */
-        InstanceIdentifier<Group> groupIdentifier = InstanceIdentifier.create(Nodes.class)
-                .child(Node.class).augmentation(FlowCapableNode.class).child(Group.class);
-
-        /* DataChangeListener registration */
-        this.groupDataChangeListener = new GroupChangeListener(GroupProvider.this);
-        this.groupDataChangeListenerRegistration = this.dataService.registerDataChangeListener(
-                LogicalDatastoreType.CONFIGURATION, groupIdentifier, groupDataChangeListener, DataChangeScope.SUBTREE);
-
-        LOG.info("FRM Group Config Provider started.");
-    }
-
-    @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 DataChangeListener getGroupDataChangeListener() {
-        return groupDataChangeListener;
-    }
-
-    public SalGroupService getSalGroupService() {
-        return salGroupService;
-    }
-
-    public DataBroker getDataService() {
-        return dataService;
-    }
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/AbstractListeningCommiter.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/AbstractListeningCommiter.java
new file mode 100644 (file)
index 0000000..ec49e61
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+ * 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.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.frm.ForwardingRulesCommiter;
+import org.opendaylight.controller.frm.ForwardingRulesManager;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * 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 AbstractListeningCommiter <T extends DataObject> implements ForwardingRulesCommiter<T> {
+
+    protected ForwardingRulesManager provider;
+
+    protected final Class<T> clazz;
+
+    public AbstractListeningCommiter (ForwardingRulesManager provider, Class<T> clazz) {
+        this.provider = Preconditions.checkNotNull(provider, "ForwardingRulesManager can not be null!");
+        this.clazz = Preconditions.checkNotNull(clazz, "Class can not be null!");
+    }
+
+    @Override
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
+        Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
+
+        /* All DataObjects for create */
+        final Map<InstanceIdentifier<?>, DataObject> createdData = changeEvent.getCreatedData() != null
+                ? changeEvent.getCreatedData() : Collections.<InstanceIdentifier<?>, DataObject> emptyMap();
+        /* All DataObjects for remove */
+        final Set<InstanceIdentifier<?>> removeData = changeEvent.getRemovedPaths() != null
+                ? changeEvent.getRemovedPaths() : Collections.<InstanceIdentifier<?>> emptySet();
+        /* All DataObjects for updates */
+        final Map<InstanceIdentifier<?>, DataObject> updateData = changeEvent.getUpdatedData() != null
+                ? changeEvent.getUpdatedData() : Collections.<InstanceIdentifier<?>, DataObject> emptyMap();
+        /* All Original DataObjects */
+        final Map<InstanceIdentifier<?>, DataObject> originalData = changeEvent.getOriginalData() != null
+                ? changeEvent.getOriginalData() : Collections.<InstanceIdentifier<?>, DataObject> emptyMap();
+
+        this.createData(createdData);
+        this.updateData(updateData, originalData);
+        this.removeData(removeData, originalData);
+    }
+
+    /**
+     * Method return wildCardPath for Listener registration
+     * and for identify the correct KeyInstanceIdentifier from data;
+     */
+    protected abstract InstanceIdentifier<T> getWildCardPath();
+
+
+
+    @SuppressWarnings("unchecked")
+    private void createData(final Map<InstanceIdentifier<?>, DataObject> createdData) {
+        final Set<InstanceIdentifier<?>> keys = createdData.keySet() != null
+                ? createdData.keySet() : Collections.<InstanceIdentifier<?>> emptySet();
+        for (InstanceIdentifier<?> key : keys) {
+            if (clazz.equals(key.getTargetType())) {
+                final InstanceIdentifier<FlowCapableNode> nodeIdent =
+                        key.firstIdentifierOf(FlowCapableNode.class);
+                if (preConfigurationCheck(nodeIdent)) {
+                    InstanceIdentifier<T> createKeyIdent = key.firstIdentifierOf(clazz);
+                    final Optional<DataObject> value = Optional.of(createdData.get(key));
+                    if (value.isPresent()) {
+                        this.add(createKeyIdent, (T)value.get(), nodeIdent);
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void updateData(final Map<InstanceIdentifier<?>, DataObject> updateData,
+            final Map<InstanceIdentifier<?>, DataObject> originalData) {
+
+        final Set<InstanceIdentifier<?>> keys = updateData.keySet() != null
+                ? updateData.keySet() : Collections.<InstanceIdentifier<?>> emptySet();
+        for (InstanceIdentifier<?> key : keys) {
+            if (clazz.equals(key.getTargetType())) {
+                final InstanceIdentifier<FlowCapableNode> nodeIdent =
+                        key.firstIdentifierOf(FlowCapableNode.class);
+                if (preConfigurationCheck(nodeIdent)) {
+                    InstanceIdentifier<T> updateKeyIdent = key.firstIdentifierOf(clazz);
+                    final Optional<DataObject> value = Optional.of(updateData.get(key));
+                    final Optional<DataObject> original = Optional.of(originalData.get(key));
+                    if (value.isPresent() && original.isPresent()) {
+                        this.update(updateKeyIdent, (T)original.get(), (T)value.get(), nodeIdent);
+                    }
+                }
+            }
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private void removeData(final Set<InstanceIdentifier<?>> removeData,
+            final Map<InstanceIdentifier<?>, DataObject> originalData) {
+
+        for (InstanceIdentifier<?> key : removeData) {
+            if (clazz.equals(key.getTargetType())) {
+                final InstanceIdentifier<FlowCapableNode> nodeIdent =
+                        key.firstIdentifierOf(FlowCapableNode.class);
+                if (preConfigurationCheck(nodeIdent)) {
+                    final InstanceIdentifier<T> ident = key.firstIdentifierOf(clazz);
+                    final DataObject removeValue = originalData.get(key);
+                    this.remove(ident, (T)removeValue, nodeIdent);
+                }
+            }
+        }
+    }
+
+    private boolean preConfigurationCheck(final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+        Preconditions.checkNotNull(nodeIdent, "FlowCapableNode ident can not be null!");
+        return provider.isNodeActive(nodeIdent);
+    }
+}
+
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowForwarder.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowForwarder.java
new file mode 100644 (file)
index 0000000..fd0ddec
--- /dev/null
@@ -0,0 +1,140 @@
+/**ab
+ * 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.impl;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.frm.ForwardingRulesManager;
+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.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.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.TableKey;
+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.RemoveFlowInputBuilder;
+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.OriginalFlowBuilder;
+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.FlowRef;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+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.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * GroupForwarder
+ * It implements {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener}}
+ * for WildCardedPath to {@link Flow} and ForwardingRulesCommiter interface for methods:
+ *  add, update and remove {@link Flow} processing for
+ *  {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class FlowForwarder extends AbstractListeningCommiter<Flow> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FlowForwarder.class);
+
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+    public FlowForwarder (final ForwardingRulesManager manager, final DataBroker db) {
+        super(manager, Flow.class);
+        Preconditions.checkNotNull(db, "DataBroker can not be null!");
+        this.listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                getWildCardPath(), FlowForwarder.this, DataChangeScope.BASE);
+    }
+
+    @Override
+    public void close() {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (Exception e) {
+                LOG.error("Error by stop FRM FlowChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+    }
+
+    @Override
+    public void remove(final InstanceIdentifier<Flow> identifier,
+                       final Flow removeDataObj,
+                       final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        final TableKey tableKey = identifier.firstKeyOf(Table.class, TableKey.class);
+        if (tableIdValidationPrecondition(tableKey, removeDataObj)) {
+            final RemoveFlowInputBuilder builder = new RemoveFlowInputBuilder(removeDataObj);
+            builder.setFlowRef(new FlowRef(identifier));
+            builder.setNode(new NodeRef(nodeIdent));
+            builder.setFlowTable(new FlowTableRef(nodeIdent.child(Table.class, tableKey)));
+            builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
+            this.provider.getSalFlowService().removeFlow(builder.build());
+        }
+    }
+
+    @Override
+    public void update(final InstanceIdentifier<Flow> identifier,
+                       final Flow original, final Flow update,
+                       final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        final TableKey tableKey = identifier.firstKeyOf(Table.class, TableKey.class);
+        if (tableIdValidationPrecondition(tableKey, update)) {
+            final UpdateFlowInputBuilder builder = new UpdateFlowInputBuilder();
+
+            builder.setNode(new NodeRef(nodeIdent));
+            builder.setFlowRef(new FlowRef(identifier));
+            builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
+            builder.setUpdatedFlow((new UpdatedFlowBuilder(update)).build());
+            builder.setOriginalFlow((new OriginalFlowBuilder(original)).build());
+
+            this.provider.getSalFlowService().updateFlow(builder.build());
+        }
+    }
+
+    @Override
+    public void add(final InstanceIdentifier<Flow> identifier,
+                    final Flow addDataObj,
+                    final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        final TableKey tableKey = identifier.firstKeyOf(Table.class, TableKey.class);
+        if (tableIdValidationPrecondition(tableKey, addDataObj)) {
+            final AddFlowInputBuilder builder = new AddFlowInputBuilder(addDataObj);
+
+            builder.setNode(new NodeRef(nodeIdent));
+            builder.setFlowRef(new FlowRef(identifier));
+            builder.setFlowTable(new FlowTableRef(nodeIdent.child(Table.class, tableKey)));
+            builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
+            this.provider.getSalFlowService().addFlow(builder.build());
+        }
+    }
+
+    @Override
+    protected InstanceIdentifier<Flow> getWildCardPath() {
+        return InstanceIdentifier.create(Nodes.class).child(Node.class)
+                .augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class);
+    }
+
+    private boolean tableIdValidationPrecondition (final TableKey tableKey, final Flow flow) {
+        Preconditions.checkNotNull(tableKey, "TableKey can not be null or empty!");
+        Preconditions.checkNotNull(flow, "Flow can not be null or empty!");
+        if (flow.getTableId() != tableKey.getId()) {
+            LOG.error("TableID in URI tableId={} and in palyload tableId={} is not same.",
+                    flow.getTableId(), tableKey.getId());
+            return false;
+        }
+        return true;
+    }
+}
+
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowNodeReconciliationImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/FlowNodeReconciliationImpl.java
new file mode 100644 (file)
index 0000000..f1e8dfe
--- /dev/null
@@ -0,0 +1,171 @@
+/**
+ * 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.impl;
+
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.controller.frm.FlowNodeReconciliation;
+import org.opendaylight.controller.frm.ForwardingRulesManager;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+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.AsyncDataBroker.DataChangeScope;
+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.meters.MeterKey;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+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.KeyedInstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * forwardingrules-manager
+ * org.opendaylight.controller.frm
+ *
+ * FlowNode Reconciliation Listener
+ * Reconciliation for a new FlowNode
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Jun 13, 2014
+ */
+public class FlowNodeReconciliationImpl implements FlowNodeReconciliation {
+
+    private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconciliationImpl.class);
+
+    private final ForwardingRulesManager provider;
+
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+    public FlowNodeReconciliationImpl (final ForwardingRulesManager manager, final DataBroker db) {
+        this.provider = Preconditions.checkNotNull(manager, "ForwardingRulesManager can not be null!");
+        Preconditions.checkNotNull(db, "DataBroker can not be null!");
+        /* Build Path */
+        InstanceIdentifier<FlowCapableNode> flowNodeWildCardIdentifier = InstanceIdentifier.create(Nodes.class)
+                .child(Node.class).augmentation(FlowCapableNode.class);
+        this.listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
+                flowNodeWildCardIdentifier, FlowNodeReconciliationImpl.this, DataChangeScope.BASE);
+    }
+
+    @Override
+    public void close() {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (Exception e) {
+                LOG.error("Error by stop FRM FlowNodeReconilListener.", e);
+            }
+            listenerRegistration = null;
+        }
+    }
+
+    @Override
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
+        Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
+        /* All DataObjects for create */
+        final Set<InstanceIdentifier<?>>  createdData = changeEvent.getCreatedData() != null
+                ? changeEvent.getCreatedData().keySet() : Collections.<InstanceIdentifier<?>> emptySet();
+        /* All DataObjects for remove */
+        final Set<InstanceIdentifier<?>> removeData = changeEvent.getRemovedPaths() != null
+                ? changeEvent.getRemovedPaths() : Collections.<InstanceIdentifier<?>> emptySet();
+
+        for (InstanceIdentifier<?> entryKey : removeData) {
+            final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
+                    .firstIdentifierOf(FlowCapableNode.class);
+            if ( ! nodeIdent.isWildcarded()) {
+                flowNodeDisconnected(nodeIdent);
+            }
+        }
+        for (InstanceIdentifier<?> entryKey : createdData) {
+            final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
+                    .firstIdentifierOf(FlowCapableNode.class);
+            if ( ! nodeIdent.isWildcarded()) {
+                flowNodeConnected(nodeIdent);
+            }
+        }
+    }
+
+    @Override
+    public void flowNodeDisconnected(InstanceIdentifier<FlowCapableNode> disconnectedNode) {
+        provider.unregistrateNode(disconnectedNode);
+    }
+
+    @Override
+    public void flowNodeConnected(InstanceIdentifier<FlowCapableNode> connectedNode) {
+        if ( ! provider.isNodeActive(connectedNode)) {
+            provider.registrateNewNode(connectedNode);
+            reconciliation(connectedNode);
+        }
+    }
+
+    private void reconciliation(final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        ReadOnlyTransaction trans = provider.getReadTranaction();
+        Optional<FlowCapableNode> flowNode = Optional.absent();
+
+        try {
+            flowNode = trans.read(LogicalDatastoreType.CONFIGURATION, nodeIdent).get();
+        }
+        catch (Exception e) {
+            LOG.error("Fail with read Config/DS for Node {} !", nodeIdent, e);
+        }
+
+        if (flowNode.isPresent()) {
+            /* Groups - have to be first */
+            List<Group> groups = flowNode.get().getGroup() != null
+                    ? flowNode.get().getGroup() : Collections.<Group> emptyList();
+            for (Group group : groups) {
+                final KeyedInstanceIdentifier<Group, GroupKey> groupIdent =
+                        nodeIdent.child(Group.class, group.getKey());
+                this.provider.getGroupCommiter().add(groupIdent, group, nodeIdent);
+            }
+            /* Meters */
+            List<Meter> meters = flowNode.get().getMeter() != null
+                    ? flowNode.get().getMeter() : Collections.<Meter> emptyList();
+            for (Meter meter : meters) {
+                final KeyedInstanceIdentifier<Meter, MeterKey> meterIdent =
+                        nodeIdent.child(Meter.class, meter.getKey());
+                this.provider.getMeterCommiter().add(meterIdent, meter, nodeIdent);
+            }
+            /* Flows */
+            List<Table> tables = flowNode.get().getTable() != null
+                    ? flowNode.get().getTable() : Collections.<Table> emptyList();
+            for (Table table : tables) {
+                final KeyedInstanceIdentifier<Table, TableKey> tableIdent =
+                        nodeIdent.child(Table.class, table.getKey());
+                List<Flow> flows = table.getFlow() != null ? table.getFlow() : Collections.<Flow> emptyList();
+                for (Flow flow : flows) {
+                    final KeyedInstanceIdentifier<Flow, FlowKey> flowIdent =
+                            tableIdent.child(Flow.class, flow.getKey());
+                    this.provider.getFlowCommiter().add(flowIdent, flow, nodeIdent);
+                }
+            }
+        }
+        /* clean transaction */
+        trans.close();
+    }
+}
+
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/ForwardingRulesManagerImpl.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/ForwardingRulesManagerImpl.java
new file mode 100644 (file)
index 0000000..7cb7acf
--- /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.impl;
+
+import java.util.Collections;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.opendaylight.controller.frm.FlowNodeReconciliation;
+import org.opendaylight.controller.frm.ForwardingRulesCommiter;
+import org.opendaylight.controller.frm.ForwardingRulesManager;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+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.flow.inventory.rev130819.tables.table.Flow;
+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.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.SalMeterService;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+
+/**
+ * forwardingrules-manager
+ * org.opendaylight.controller.frm.impl
+ *
+ * Manager and middle point for whole module.
+ * It contains ActiveNodeHolder and provide all RPC services.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ * Created: Aug 25, 2014
+ */
+public class ForwardingRulesManagerImpl implements ForwardingRulesManager {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ForwardingRulesManagerImpl.class);
+
+    private final AtomicLong txNum = new AtomicLong();
+    private final Object lockObj = new Object();
+    private Set<InstanceIdentifier<FlowCapableNode>> activeNodes = Collections.emptySet();
+
+    private final DataBroker dataService;
+    private final SalFlowService salFlowService;
+    private final SalGroupService salGroupService;
+    private final SalMeterService salMeterService;
+
+    private ForwardingRulesCommiter<Flow> flowListener;
+    private ForwardingRulesCommiter<Group> groupListener;
+    private ForwardingRulesCommiter<Meter> meterListener;
+    private FlowNodeReconciliation nodeListener;
+
+    public ForwardingRulesManagerImpl(final DataBroker dataBroker,
+            final RpcConsumerRegistry rpcRegistry) {
+        this.dataService = Preconditions.checkNotNull(dataBroker, "DataBroker can not be null!");
+
+        Preconditions.checkArgument(rpcRegistry != null, "RpcConsumerRegistry can not be null !");
+
+        this.salFlowService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalFlowService.class),
+                "RPC SalFlowService not found.");
+        this.salGroupService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalGroupService.class),
+                "RPC SalGroupService not found.");
+        this.salMeterService = Preconditions.checkNotNull(rpcRegistry.getRpcService(SalMeterService.class),
+                "RPC SalMeterService not found.");
+    }
+
+    @Override
+    public void start() {
+        this.flowListener = new FlowForwarder(this, dataService);
+        this.groupListener = new GroupForwarder(this, dataService);
+        this.meterListener = new MeterForwarder(this, dataService);
+        this.nodeListener = new FlowNodeReconciliationImpl(this, dataService);
+        LOG.info("ForwardingRulesManager has started successfull.");
+    }
+
+    @Override
+    public void close() throws Exception {
+        if(this.flowListener != null) {
+            this.flowListener.close();
+            this.flowListener = null;
+        }
+        if (this.groupListener != null) {
+            this.groupListener.close();
+            this.groupListener = null;
+        }
+        if (this.meterListener != null) {
+            this.meterListener.close();
+            this.meterListener = null;
+        }
+        if (this.nodeListener != null) {
+            this.nodeListener.close();
+            this.nodeListener = null;
+        }
+    }
+
+    @Override
+    public ReadOnlyTransaction getReadTranaction() {
+        return dataService.newReadOnlyTransaction();
+    }
+
+    @Override
+    public String getNewTransactionId() {
+        return "DOM-" + txNum.getAndIncrement();
+    }
+
+    @Override
+    public boolean isNodeActive(InstanceIdentifier<FlowCapableNode> ident) {
+        return activeNodes.contains(ident);
+    }
+
+    @Override
+    public void registrateNewNode(InstanceIdentifier<FlowCapableNode> ident) {
+        if ( ! activeNodes.contains(ident)) {
+            synchronized (lockObj) {
+                if ( ! activeNodes.contains(ident)) {
+                    Set<InstanceIdentifier<FlowCapableNode>> set =
+                            Sets.newHashSet(activeNodes);
+                    set.add(ident);
+                    activeNodes = Collections.unmodifiableSet(set);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void unregistrateNode(InstanceIdentifier<FlowCapableNode> ident) {
+        if (activeNodes.contains(ident)) {
+            synchronized (lockObj) {
+                if (activeNodes.contains(ident)) {
+                    Set<InstanceIdentifier<FlowCapableNode>> set =
+                            Sets.newHashSet(activeNodes);
+                    set.remove(ident);
+                    activeNodes = Collections.unmodifiableSet(set);
+                }
+            }
+        }
+    }
+
+    @Override
+    public SalFlowService getSalFlowService() {
+        return salFlowService;
+    }
+
+    @Override
+    public SalGroupService getSalGroupService() {
+        return salGroupService;
+    }
+
+    @Override
+    public SalMeterService getSalMeterService() {
+        return salMeterService;
+    }
+
+    @Override
+    public ForwardingRulesCommiter<Flow> getFlowCommiter() {
+        return flowListener;
+    }
+
+    @Override
+    public ForwardingRulesCommiter<Group> getGroupCommiter() {
+        return groupListener;
+    }
+
+    @Override
+    public ForwardingRulesCommiter<Meter> getMeterCommiter() {
+        return meterListener;
+    }
+
+    @Override
+    public FlowNodeReconciliation getFlowNodeReconciliation() {
+        return nodeListener;
+    }
+}
+
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/GroupForwarder.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/GroupForwarder.java
new file mode 100644 (file)
index 0000000..77ef162
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ * 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.impl;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.frm.ForwardingRulesManager;
+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.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.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInputBuilder;
+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.OriginalGroupBuilder;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+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.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * GroupForwarder
+ * It implements {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener}}
+ * for WildCardedPath to {@link Group} and ForwardingRulesCommiter interface for methods:
+ *  add, update and remove {@link Group} processing for
+ *  {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class GroupForwarder extends AbstractListeningCommiter<Group> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GroupForwarder.class);
+
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+    public GroupForwarder (final ForwardingRulesManager manager, final DataBroker db) {
+        super(manager, Group.class);
+        Preconditions.checkNotNull(db, "DataBroker can not be null!");
+        this.listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                getWildCardPath(), GroupForwarder.this, DataChangeScope.BASE);
+    }
+
+    @Override
+    public void close() {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (Exception e) {
+                LOG.error("Error by stop FRM GroupChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+    }
+
+    @Override
+    protected InstanceIdentifier<Group> getWildCardPath() {
+        return InstanceIdentifier.create(Nodes.class).child(Node.class)
+                .augmentation(FlowCapableNode.class).child(Group.class);
+    }
+
+    @Override
+    public void remove(final InstanceIdentifier<Group> identifier, final Group removeDataObj,
+                       final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        final Group group = (removeDataObj);
+        final RemoveGroupInputBuilder builder = new RemoveGroupInputBuilder(group);
+
+        builder.setNode(new NodeRef(nodeIdent));
+        builder.setGroupRef(new GroupRef(identifier));
+        builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
+        this.provider.getSalGroupService().removeGroup(builder.build());
+    }
+
+    @Override
+    public void update(final InstanceIdentifier<Group> identifier,
+                       final Group original, final Group update,
+                       final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        final Group originalGroup = (original);
+        final Group updatedGroup = (update);
+        final UpdateGroupInputBuilder builder = new UpdateGroupInputBuilder();
+
+        builder.setNode(new NodeRef(nodeIdent));
+        builder.setGroupRef(new GroupRef(identifier));
+        builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
+        builder.setUpdatedGroup((new UpdatedGroupBuilder(updatedGroup)).build());
+        builder.setOriginalGroup((new OriginalGroupBuilder(originalGroup)).build());
+
+        this.provider.getSalGroupService().updateGroup(builder.build());
+    }
+
+    @Override
+    public void add(final InstanceIdentifier<Group> identifier, final Group addDataObj,
+                    final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        final Group group = (addDataObj);
+        final AddGroupInputBuilder builder = new AddGroupInputBuilder(group);
+
+        builder.setNode(new NodeRef(nodeIdent));
+        builder.setGroupRef(new GroupRef(identifier));
+        builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
+        this.provider.getSalGroupService().addGroup(builder.build());
+    }
+}
+
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/MeterForwarder.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/impl/MeterForwarder.java
new file mode 100644 (file)
index 0000000..9511fb8
--- /dev/null
@@ -0,0 +1,114 @@
+/**
+ * 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.impl;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.frm.ForwardingRulesManager;
+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.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.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
+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.AddMeterInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder;
+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.OriginalMeterBuilder;
+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.MeterRef;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * MeterForwarder
+ * It implements {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener}}
+ * for WildCardedPath to {@link Meter} and ForwardingRulesCommiter interface for methods:
+ *  add, update and remove {@link Meter} processing for
+ *  {@link org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent}.
+ *
+ * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
+ *
+ */
+public class MeterForwarder extends AbstractListeningCommiter<Meter> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MeterForwarder.class);
+
+    private ListenerRegistration<DataChangeListener> listenerRegistration;
+
+    public MeterForwarder (final ForwardingRulesManager manager, final DataBroker db) {
+        super(manager, Meter.class);
+        Preconditions.checkNotNull(db, "DataBroker can not be null!");
+        this.listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
+                getWildCardPath(), MeterForwarder.this, DataChangeScope.BASE);
+    }
+
+    @Override
+    public void close() {
+        if (listenerRegistration != null) {
+            try {
+                listenerRegistration.close();
+            } catch (Exception e) {
+                LOG.error("Error by stop FRM MeterChangeListener.", e);
+            }
+            listenerRegistration = null;
+        }
+    }
+
+    @Override
+    protected InstanceIdentifier<Meter> getWildCardPath() {
+        return InstanceIdentifier.create(Nodes.class).child(Node.class)
+                .augmentation(FlowCapableNode.class).child(Meter.class);
+    }
+
+    @Override
+    public void remove(final InstanceIdentifier<Meter> identifier, final Meter removeDataObj,
+                       final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(removeDataObj);
+
+        builder.setNode(new NodeRef(nodeIdent));
+        builder.setMeterRef(new MeterRef(identifier));
+        builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
+        this.provider.getSalMeterService().removeMeter(builder.build());
+    }
+
+    @Override
+    public void update(final InstanceIdentifier<Meter> identifier,
+                       final Meter original, final Meter update,
+                       final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder();
+
+        builder.setNode(new NodeRef(nodeIdent));
+        builder.setMeterRef(new MeterRef(identifier));
+        builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
+        builder.setUpdatedMeter((new UpdatedMeterBuilder(update)).build());
+        builder.setOriginalMeter((new OriginalMeterBuilder(original)).build());
+
+        this.provider.getSalMeterService().updateMeter(builder.build());
+    }
+
+    @Override
+    public void add(final InstanceIdentifier<Meter> identifier, final Meter addDataObj,
+                    final InstanceIdentifier<FlowCapableNode> nodeIdent) {
+
+        final AddMeterInputBuilder builder = new AddMeterInputBuilder(addDataObj);
+
+        builder.setNode(new NodeRef(nodeIdent));
+        builder.setMeterRef(new MeterRef(identifier));
+        builder.setTransactionUri(new Uri(provider.getNewTransactionId()));
+        this.provider.getSalMeterService().addMeter(builder.build());
+    }
+}
+
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterChangeListener.java
deleted file mode 100644 (file)
index a2def84..0000000
+++ /dev/null
@@ -1,112 +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;
-
-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.AddMeterInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInputBuilder;
-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.OriginalMeterBuilder;
-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;
-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.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 static final Logger LOG = LoggerFactory.getLogger(MeterChangeListener.class);
-
-    private final MeterProvider provider;
-
-    public MeterChangeListener (final MeterProvider provider) {
-        this.provider = Preconditions.checkNotNull(provider, "MeterProvider can not be null !");
-    }
-
-    @Override
-    protected void remove(final InstanceIdentifier<? extends DataObject> identifier,
-                          final DataObject removeDataObj) {
-
-        final Meter meter = ((Meter) removeDataObj);
-        final InstanceIdentifier<Node> nodeIdent = identifier.firstIdentifierOf(Node.class);
-        final RemoveMeterInputBuilder builder = new RemoveMeterInputBuilder(meter);
-
-        builder.setNode(new NodeRef(nodeIdent));
-        builder.setMeterRef(new MeterRef(identifier));
-
-        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(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.firstIdentifierOf(Node.class);
-        final UpdateMeterInputBuilder builder = new UpdateMeterInputBuilder();
-
-        builder.setNode(new NodeRef(nodeInstanceId));
-        builder.setMeterRef(new MeterRef(identifier));
-
-        Uri uri = new Uri(this.getTransactionId());
-        builder.setTransactionUri(uri);
-
-        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});
-
-    }
-
-    @Override
-    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);
-
-        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) {
-
-        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));
-    }
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java b/opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/meter/MeterProvider.java
deleted file mode 100644 (file)
index 44de7af..0000000
+++ /dev/null
@@ -1,105 +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;
-
-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.InstanceIdentifier;
-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 static final Logger LOG = LoggerFactory.getLogger(MeterProvider.class);
-
-    private SalMeterService salMeterService;
-    private DataBroker dataService;
-
-    /* DataChangeListener */
-    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.");
-
-        /* Build Path */
-        InstanceIdentifier<Meter> meterIdentifier = InstanceIdentifier.create(Nodes.class)
-                .child(Node.class).augmentation(FlowCapableNode.class).child(Meter.class);
-
-        /* DataChangeListener registration */
-        this.meterDataChangeListener = new MeterChangeListener(MeterProvider.this);
-        this.meterDataChangeListenerRegistration =
-                this.dataService.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
-                        meterIdentifier, meterDataChangeListener, DataChangeScope.SUBTREE);
-
-        LOG.info("FRM Meter Config Provider started.");
-    }
-
-    @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 DataChangeListener getMeterDataChangeListener() {
-        return meterDataChangeListener;
-    }
-
-    public DataBroker getDataService() {
-        return dataService;
-    }
-
-    public SalMeterService getSalMeterService() {
-        return salMeterService;
-    }
-}
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
deleted file mode 100644 (file)
index 6308f2a..0000000
+++ /dev/null
@@ -1,196 +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.reconil;
-
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.ListenableFuture;
-import java.util.List;
-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;
-
-/**
- * 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(final 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 */
-            List<Group> groups = flowCapNode.get().getGroup();
-            if(groups != null) {
-                for (Group group : groups) {
-                    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 */
-            List<Meter> meters = flowCapNode.get().getMeter();
-            if(meters != null) {
-                for (Meter meter : meters) {
-                    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 */
-            List<Table> tables = flowCapNode.get().getTable();
-            if(tables != null) {
-                for (Table flowTable : tables) {
-                    final InstanceIdentifier<Table> tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey());
-                    List<Flow> flows = flowTable.getFlow();
-                    if(flows != null) {
-                        for (Flow flow : flows) {
-                            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, final 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
deleted file mode 100644 (file)
index ad970d6..0000000
+++ /dev/null
@@ -1,115 +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.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;
-    }
-}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/FlowListenerTest.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/FlowListenerTest.java
new file mode 100644 (file)
index 0000000..85f4b14
--- /dev/null
@@ -0,0 +1,210 @@
+/**
+ * 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 test.mock;
+
+import org.junit.Test;
+import org.opendaylight.controller.frm.impl.ForwardingRulesManagerImpl;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev100924.Dscp;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowId;
+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.TableBuilder;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.UpdateFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.Match;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.flow.MatchBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+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.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatch;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.model.match.types.rev131026.match.IpMatchBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import test.mock.util.FRMTest;
+import test.mock.util.RpcProviderRegistryMock;
+import test.mock.util.SalFlowServiceMock;
+
+import java.util.Collections;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class FlowListenerTest extends FRMTest {
+    RpcProviderRegistry rpcProviderRegistryMock = new RpcProviderRegistryMock();
+    NodeKey s1Key = new NodeKey(new NodeId("S1"));
+    TableKey tableKey = new TableKey((short) 2);
+
+    @Test
+    public void addTwoFlowsTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        FlowKey flowKey = new FlowKey(new FlowId("test_Flow"));
+        InstanceIdentifier<Table> tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey);
+        InstanceIdentifier<Flow> flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey).child(Flow.class, flowKey);
+        Table table = new TableBuilder().setKey(tableKey).setFlow(Collections.<Flow>emptyList()).build();
+        Flow flow = new FlowBuilder().setKey(flowKey).setTableId((short) 2).build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, tableII, table);
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow);
+        assertCommit(writeTx.submit());
+        SalFlowServiceMock salFlowService = (SalFlowServiceMock) forwardingRulesManager.getSalFlowService();
+        List<AddFlowInput> addFlowCalls = salFlowService.getAddFlowCalls();
+        assertEquals(1, addFlowCalls.size());
+        assertEquals("DOM-0", addFlowCalls.get(0).getTransactionUri().getValue());
+
+        flowKey = new FlowKey(new FlowId("test_Flow2"));
+        flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey).child(Flow.class, flowKey);
+        flow = new FlowBuilder().setKey(flowKey).setTableId((short) 2).build();
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow);
+        assertCommit(writeTx.submit());
+        salFlowService = (SalFlowServiceMock) forwardingRulesManager.getSalFlowService();
+        addFlowCalls = salFlowService.getAddFlowCalls();
+        assertEquals(2, addFlowCalls.size());
+        assertEquals("DOM-1", addFlowCalls.get(1).getTransactionUri().getValue());
+        assertEquals(2, addFlowCalls.get(1).getTableId().intValue());
+        assertEquals(flowII, addFlowCalls.get(1).getFlowRef().getValue());
+
+        forwardingRulesManager.close();
+    }
+
+    @Test
+    public void updateFlowTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        FlowKey flowKey = new FlowKey(new FlowId("test_Flow"));
+        InstanceIdentifier<Table> tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey);
+        InstanceIdentifier<Flow> flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey).child(Flow.class, flowKey);
+        Table table = new TableBuilder().setKey(tableKey).setFlow(Collections.<Flow>emptyList()).build();
+        Flow flow = new FlowBuilder().setKey(flowKey).setTableId((short) 2).build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, tableII, table);
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow);
+        assertCommit(writeTx.submit());
+        SalFlowServiceMock salFlowService = (SalFlowServiceMock) forwardingRulesManager.getSalFlowService();
+        List<AddFlowInput> addFlowCalls = salFlowService.getAddFlowCalls();
+        assertEquals(1, addFlowCalls.size());
+        assertEquals("DOM-0", addFlowCalls.get(0).getTransactionUri().getValue());
+
+        flowKey = new FlowKey(new FlowId("test_Flow"));
+        flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey).child(Flow.class, flowKey);
+        flow = new FlowBuilder().setKey(flowKey).setTableId((short) 2).setOutGroup((long) 5).build();
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow);
+        assertCommit(writeTx.submit());
+        salFlowService = (SalFlowServiceMock) forwardingRulesManager.getSalFlowService();
+        List<UpdateFlowInput> updateFlowCalls = salFlowService.getUpdateFlowCalls();
+        assertEquals(1, updateFlowCalls.size());
+        assertEquals("DOM-1", updateFlowCalls.get(0).getTransactionUri().getValue());
+        assertEquals(flowII, updateFlowCalls.get(0).getFlowRef().getValue());
+
+        forwardingRulesManager.close();
+    }
+
+    @Test
+    public void updateFlowScopeTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        FlowKey flowKey = new FlowKey(new FlowId("test_Flow"));
+        InstanceIdentifier<Table> tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey);
+        InstanceIdentifier<Flow> flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey).child(Flow.class, flowKey);
+        Table table = new TableBuilder().setKey(tableKey).setFlow(Collections.<Flow>emptyList()).build();
+        IpMatch ipMatch = new IpMatchBuilder().setIpDscp(new Dscp((short)4)).build();
+        Match match = new MatchBuilder().setIpMatch(ipMatch).build();
+        Flow flow = new FlowBuilder().setMatch(match).setKey(flowKey).setTableId((short) 2).build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, tableII, table);
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow);
+        assertCommit(writeTx.submit());
+        SalFlowServiceMock salFlowService = (SalFlowServiceMock) forwardingRulesManager.getSalFlowService();
+        List<AddFlowInput> addFlowCalls = salFlowService.getAddFlowCalls();
+        assertEquals(1, addFlowCalls.size());
+        assertEquals("DOM-0", addFlowCalls.get(0).getTransactionUri().getValue());
+
+        flowKey = new FlowKey(new FlowId("test_Flow"));
+        flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey).child(Flow.class, flowKey);
+        ipMatch = new IpMatchBuilder().setIpDscp(new Dscp((short)5)).build();
+        match = new MatchBuilder().setIpMatch(ipMatch).build();
+        flow = new FlowBuilder().setMatch(match).setKey(flowKey).setTableId((short) 2).build();
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow);
+        assertCommit(writeTx.submit());
+        salFlowService = (SalFlowServiceMock) forwardingRulesManager.getSalFlowService();
+        List<UpdateFlowInput> updateFlowCalls = salFlowService.getUpdateFlowCalls();
+        assertEquals(1, updateFlowCalls.size());
+        assertEquals("DOM-1", updateFlowCalls.get(0).getTransactionUri().getValue());
+        assertEquals(flowII, updateFlowCalls.get(0).getFlowRef().getValue());
+        assertEquals(ipMatch, updateFlowCalls.get(0).getUpdatedFlow().getMatch().getIpMatch());
+        forwardingRulesManager.close();
+    }
+
+    @Test
+    public void deleteFlowTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        FlowKey flowKey = new FlowKey(new FlowId("test_Flow"));
+        InstanceIdentifier<Table> tableII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey);
+        InstanceIdentifier<Flow> flowII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Table.class, tableKey).child(Flow.class, flowKey);
+        Table table = new TableBuilder().setKey(tableKey).setFlow(Collections.<Flow>emptyList()).build();
+        Flow flow = new FlowBuilder().setKey(flowKey).setTableId((short) 2).build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, tableII, table);
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowII, flow);
+        assertCommit(writeTx.submit());
+        SalFlowServiceMock salFlowService = (SalFlowServiceMock) forwardingRulesManager.getSalFlowService();
+        List<AddFlowInput> addFlowCalls = salFlowService.getAddFlowCalls();
+        assertEquals(1, addFlowCalls.size());
+        assertEquals("DOM-0", addFlowCalls.get(0).getTransactionUri().getValue());
+
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.delete(LogicalDatastoreType.CONFIGURATION, flowII);
+        assertCommit(writeTx.submit());
+        salFlowService = (SalFlowServiceMock) forwardingRulesManager.getSalFlowService();
+        List<RemoveFlowInput> removeFlowCalls = salFlowService.getRemoveFlowCalls();
+        assertEquals(1, removeFlowCalls.size());
+        assertEquals("DOM-1", removeFlowCalls.get(0).getTransactionUri().getValue());
+        assertEquals(flowII, removeFlowCalls.get(0).getFlowRef().getValue());
+
+        forwardingRulesManager.close();
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/GroupListenerTest.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/GroupListenerTest.java
new file mode 100644 (file)
index 0000000..97eb899
--- /dev/null
@@ -0,0 +1,137 @@
+/**
+ * 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 test.mock;
+
+import org.junit.Test;
+import org.opendaylight.controller.frm.impl.ForwardingRulesManagerImpl;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.UpdateGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.GroupId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+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.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import test.mock.util.FRMTest;
+import test.mock.util.RpcProviderRegistryMock;
+import test.mock.util.SalGroupServiceMock;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class GroupListenerTest extends FRMTest {
+    RpcProviderRegistry rpcProviderRegistryMock = new RpcProviderRegistryMock();
+    NodeKey s1Key = new NodeKey(new NodeId("S1"));
+
+    @Test
+    public void addTwoGroupsTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        GroupKey groupKey = new GroupKey(new GroupId((long) 255));
+        InstanceIdentifier<Group> groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Group.class, groupKey);
+        Group group = new GroupBuilder().setKey(groupKey).setGroupName("Group1").build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, groupII, group);
+        assertCommit(writeTx.submit());
+        SalGroupServiceMock salGroupService = (SalGroupServiceMock) forwardingRulesManager.getSalGroupService();
+        List<AddGroupInput> addGroupCalls = salGroupService.getAddGroupCalls();
+        assertEquals(1, addGroupCalls.size());
+        assertEquals("DOM-0", addGroupCalls.get(0).getTransactionUri().getValue());
+
+        groupKey = new GroupKey(new GroupId((long) 256));
+        groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Group.class, groupKey);
+        group = new GroupBuilder().setKey(groupKey).setGroupName("Group1").build();
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, groupII, group);
+        assertCommit(writeTx.submit());
+        salGroupService = (SalGroupServiceMock) forwardingRulesManager.getSalGroupService();
+        addGroupCalls = salGroupService.getAddGroupCalls();
+        assertEquals(2, addGroupCalls.size());
+        assertEquals("DOM-1", addGroupCalls.get(1).getTransactionUri().getValue());
+
+        forwardingRulesManager.close();
+    }
+
+    @Test
+    public void updateGroupTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        GroupKey groupKey = new GroupKey(new GroupId((long) 255));
+        InstanceIdentifier<Group> groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Group.class, groupKey);
+        Group group = new GroupBuilder().setKey(groupKey).setGroupName("Group1").build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, groupII, group);
+        assertCommit(writeTx.submit());
+        SalGroupServiceMock salGroupService = (SalGroupServiceMock) forwardingRulesManager.getSalGroupService();
+        List<AddGroupInput> addGroupCalls = salGroupService.getAddGroupCalls();
+        assertEquals(1, addGroupCalls.size());
+        assertEquals("DOM-0", addGroupCalls.get(0).getTransactionUri().getValue());
+
+        group = new GroupBuilder().setKey(groupKey).setGroupName("Group2").build();
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, groupII, group);
+        assertCommit(writeTx.submit());
+        salGroupService = (SalGroupServiceMock) forwardingRulesManager.getSalGroupService();
+        List<UpdateGroupInput> updateGroupCalls = salGroupService.getUpdateGroupCalls();
+        assertEquals(1, updateGroupCalls.size());
+        assertEquals("DOM-1", updateGroupCalls.get(0).getTransactionUri().getValue());
+
+        forwardingRulesManager.close();
+    }
+
+    @Test
+    public void removeGroupTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        GroupKey groupKey = new GroupKey(new GroupId((long) 255));
+        InstanceIdentifier<Group> groupII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Group.class, groupKey);
+        Group group = new GroupBuilder().setKey(groupKey).setGroupName("Group1").build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, groupII, group);
+        assertCommit(writeTx.submit());
+        SalGroupServiceMock salGroupService = (SalGroupServiceMock) forwardingRulesManager.getSalGroupService();
+        List<AddGroupInput> addGroupCalls = salGroupService.getAddGroupCalls();
+        assertEquals(1, addGroupCalls.size());
+        assertEquals("DOM-0", addGroupCalls.get(0).getTransactionUri().getValue());
+
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.delete(LogicalDatastoreType.CONFIGURATION, groupII);
+        assertCommit(writeTx.submit());
+        salGroupService = (SalGroupServiceMock) forwardingRulesManager.getSalGroupService();
+        List<RemoveGroupInput> removeGroupCalls = salGroupService.getRemoveGroupCalls();
+        assertEquals(1, removeGroupCalls.size());
+        assertEquals("DOM-1", removeGroupCalls.get(0).getTransactionUri().getValue());
+
+        forwardingRulesManager.close();
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/MeterListenerTest.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/MeterListenerTest.java
new file mode 100644 (file)
index 0000000..0d32f9f
--- /dev/null
@@ -0,0 +1,141 @@
+/**
+ * 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 test.mock;
+
+import org.junit.Test;
+import org.opendaylight.controller.frm.impl.ForwardingRulesManagerImpl;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+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.meters.MeterBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+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.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.UpdateMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.types.rev130918.MeterId;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import test.mock.util.FRMTest;
+import test.mock.util.RpcProviderRegistryMock;
+import test.mock.util.SalMeterServiceMock;
+
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class MeterListenerTest extends FRMTest {
+    RpcProviderRegistry rpcProviderRegistryMock = new RpcProviderRegistryMock();
+    NodeKey s1Key = new NodeKey(new NodeId("S1"));
+
+    @Test
+    public void addTwoMetersTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        MeterKey meterKey = new MeterKey(new MeterId((long) 2000));
+        InstanceIdentifier<Meter> meterII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Meter.class, meterKey);
+        Meter meter = new MeterBuilder().setKey(meterKey).setMeterName("meter_one").build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, meterII, meter);
+        assertCommit(writeTx.submit());
+        SalMeterServiceMock salMeterService = (SalMeterServiceMock) forwardingRulesManager.getSalMeterService();
+        List<AddMeterInput> addMeterCalls = salMeterService.getAddMeterCalls();
+        assertEquals(1, addMeterCalls.size());
+        assertEquals("DOM-0", addMeterCalls.get(0).getTransactionUri().getValue());
+
+        meterKey = new MeterKey(new MeterId((long) 2001));
+        meterII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Meter.class, meterKey);
+        meter = new MeterBuilder().setKey(meterKey).setMeterName("meter_two").setBarrier(true).build();
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, meterII, meter);
+        assertCommit(writeTx.submit());
+        salMeterService = (SalMeterServiceMock) forwardingRulesManager.getSalMeterService();
+        addMeterCalls = salMeterService.getAddMeterCalls();
+        assertEquals(2, addMeterCalls.size());
+        assertEquals("DOM-1", addMeterCalls.get(1).getTransactionUri().getValue());
+        assertEquals(meterII, addMeterCalls.get(1).getMeterRef().getValue());
+
+        forwardingRulesManager.close();
+    }
+
+    @Test
+    public void updateMeterTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        MeterKey meterKey = new MeterKey(new MeterId((long) 2000));
+        InstanceIdentifier<Meter> meterII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Meter.class, meterKey);
+        Meter meter = new MeterBuilder().setKey(meterKey).setMeterName("meter_one").setBarrier(false).build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, meterII, meter);
+        assertCommit(writeTx.submit());
+        SalMeterServiceMock salMeterService = (SalMeterServiceMock) forwardingRulesManager.getSalMeterService();
+        List<AddMeterInput> addMeterCalls = salMeterService.getAddMeterCalls();
+        assertEquals(1, addMeterCalls.size());
+        assertEquals("DOM-0", addMeterCalls.get(0).getTransactionUri().getValue());
+
+        meter = new MeterBuilder().setKey(meterKey).setMeterName("meter_two").setBarrier(true).build();
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, meterII, meter);
+        assertCommit(writeTx.submit());
+        salMeterService = (SalMeterServiceMock) forwardingRulesManager.getSalMeterService();
+        List<UpdateMeterInput> updateMeterCalls = salMeterService.getUpdateMeterCalls();
+        assertEquals(1, updateMeterCalls.size());
+        assertEquals("DOM-1", updateMeterCalls.get(0).getTransactionUri().getValue());
+        assertEquals(meterII, updateMeterCalls.get(0).getMeterRef().getValue());
+
+        forwardingRulesManager.close();
+    }
+
+    @Test
+    public void removeMeterTest() throws Exception {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        MeterKey meterKey = new MeterKey(new MeterId((long) 2000));
+        InstanceIdentifier<Meter> meterII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class).child(Meter.class, meterKey);
+        Meter meter = new MeterBuilder().setKey(meterKey).setMeterName("meter_one").build();
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, meterII, meter);
+        assertCommit(writeTx.submit());
+        SalMeterServiceMock salMeterService = (SalMeterServiceMock) forwardingRulesManager.getSalMeterService();
+        List<AddMeterInput> addMeterCalls = salMeterService.getAddMeterCalls();
+        assertEquals(1, addMeterCalls.size());
+        assertEquals("DOM-0", addMeterCalls.get(0).getTransactionUri().getValue());
+
+        writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.delete(LogicalDatastoreType.CONFIGURATION, meterII);
+        assertCommit(writeTx.submit());
+        salMeterService = (SalMeterServiceMock) forwardingRulesManager.getSalMeterService();
+        List<RemoveMeterInput> removeMeterCalls = salMeterService.getRemoveMeterCalls();
+        assertEquals(1, removeMeterCalls.size());
+        assertEquals("DOM-1", removeMeterCalls.get(0).getTransactionUri().getValue());
+        assertEquals(meterII, removeMeterCalls.get(0).getMeterRef().getValue());
+
+        forwardingRulesManager.close();
+    }
+
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/NodeListenerTest.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/NodeListenerTest.java
new file mode 100644 (file)
index 0000000..3cf2e93
--- /dev/null
@@ -0,0 +1,52 @@
+/**
+ * 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 test.mock;
+
+import org.junit.Test;
+import org.opendaylight.controller.frm.impl.ForwardingRulesManagerImpl;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
+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.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import test.mock.util.FRMTest;
+import test.mock.util.RpcProviderRegistryMock;
+
+import java.util.concurrent.ExecutionException;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class NodeListenerTest extends FRMTest {
+
+    RpcProviderRegistry rpcProviderRegistryMock = new RpcProviderRegistryMock();
+    NodeKey s1Key = new NodeKey(new NodeId("S1"));
+
+    @Test
+    public void addRemoveNodeTest() throws ExecutionException, InterruptedException {
+        ForwardingRulesManagerImpl forwardingRulesManager = new ForwardingRulesManagerImpl(getDataBroker(), rpcProviderRegistryMock);
+        forwardingRulesManager.start();
+
+        addFlowCapableNode(s1Key);
+
+        InstanceIdentifier<FlowCapableNode> nodeII = InstanceIdentifier.create(Nodes.class).child(Node.class, s1Key)
+                .augmentation(FlowCapableNode.class);
+
+        boolean nodeActive = forwardingRulesManager.isNodeActive(nodeII);
+        assertTrue(nodeActive);
+
+        removeNode(s1Key);
+
+        nodeActive = forwardingRulesManager.isNodeActive(nodeII);
+        assertFalse(nodeActive);
+    }
+
+
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/AbstractDataBrokerTest.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/AbstractDataBrokerTest.java
new file mode 100644 (file)
index 0000000..f9efa51
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * 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 test.mock.util;
+
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+public class AbstractDataBrokerTest extends AbstractSchemaAwareTest {
+
+    private DataBrokerTestCustomizer testCustomizer;
+    private DataBroker dataBroker;
+    private DOMDataBroker domBroker;
+
+
+    @Override
+    protected void setupWithSchema(final SchemaContext context) {
+        testCustomizer = createDataBrokerTestCustomizer();
+        dataBroker = testCustomizer.createDataBroker();
+        domBroker = testCustomizer.createDOMDataBroker();
+        testCustomizer.updateSchema(context);
+        setupWithDataBroker(dataBroker);
+    }
+
+    protected void setupWithDataBroker(final DataBroker dataBroker) {
+        // Intentionally left No-op, subclasses may customize it
+    }
+
+   protected DataBrokerTestCustomizer createDataBrokerTestCustomizer() {
+        return new DataBrokerTestCustomizer();
+    }
+
+    public DataBroker getDataBroker() {
+        return dataBroker;
+    }
+
+    public DOMDataBroker getDomBroker() {
+        return domBroker;
+    }
+
+    protected static final void assertCommit(final ListenableFuture<Void> commit) {
+        try {
+            commit.get(500, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/AbstractSchemaAwareTest.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/AbstractSchemaAwareTest.java
new file mode 100644 (file)
index 0000000..d520d59
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 test.mock.util;
+
+import org.junit.Before;
+import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
+import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
+import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public abstract class AbstractSchemaAwareTest {
+
+    private Iterable<YangModuleInfo> moduleInfos;
+    private SchemaContext schemaContext;
+
+
+    protected Iterable<YangModuleInfo> getModuleInfos() {
+        return BindingReflections.loadModuleInfos();
+    }
+
+
+    @Before
+    public final void setup() {
+        moduleInfos = getModuleInfos();
+        ModuleInfoBackedContext moduleContext = ModuleInfoBackedContext.create();
+        moduleContext.addModuleInfos(moduleInfos);
+        schemaContext = moduleContext.tryToCreateSchemaContext().get();
+        setupWithSchema(schemaContext);
+    }
+
+    /**
+     * Setups test with Schema context.
+     * This method is called before {@link #setupWithSchemaService(SchemaService)}
+     *
+     * @param context
+     */
+    protected abstract void setupWithSchema(SchemaContext context);
+
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/DataBrokerTestCustomizer.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/DataBrokerTestCustomizer.java
new file mode 100644 (file)
index 0000000..36ab41f
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * 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 test.mock.util;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import javassist.ClassPool;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
+import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker;
+import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMDataBrokerImpl;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class DataBrokerTestCustomizer {
+
+    private DOMDataBroker domDataBroker;
+    private final RuntimeGeneratedMappingServiceImpl mappingService;
+    private final MockSchemaService schemaService;
+    private ImmutableMap<LogicalDatastoreType, DOMStore> datastores;
+    private final BindingToNormalizedNodeCodec bindingToNormalized ;
+
+    public ImmutableMap<LogicalDatastoreType, DOMStore> createDatastores() {
+        return ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
+                .put(LogicalDatastoreType.OPERATIONAL, createOperationalDatastore())
+                .put(LogicalDatastoreType.CONFIGURATION,createConfigurationDatastore())
+                .build();
+    }
+
+    public DataBrokerTestCustomizer() {
+        schemaService = new MockSchemaService();
+        ClassPool pool = ClassPool.getDefault();
+        mappingService = new RuntimeGeneratedMappingServiceImpl(pool);
+        DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(pool));
+        BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator);
+        GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+        bindingToNormalized = new BindingToNormalizedNodeCodec(loading, mappingService, codecRegistry);
+        schemaService.registerSchemaContextListener(bindingToNormalized);
+    }
+
+    public DOMStore createConfigurationDatastore() {
+        InMemoryDOMDataStore store = new InMemoryDOMDataStore("CFG",
+                MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor());
+        schemaService.registerSchemaContextListener(store);
+        return store;
+    }
+
+    public DOMStore createOperationalDatastore() {
+        InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER",
+                MoreExecutors.sameThreadExecutor(), MoreExecutors.sameThreadExecutor());
+        schemaService.registerSchemaContextListener(store);
+        return store;
+    }
+
+    public DOMDataBroker createDOMDataBroker() {
+        return new DOMDataBrokerImpl(getDatastores(), getCommitCoordinatorExecutor());
+    }
+
+    public ListeningExecutorService getCommitCoordinatorExecutor() {
+        return MoreExecutors.sameThreadExecutor();
+    }
+
+    public DataBroker createDataBroker() {
+        return new ForwardedBindingDataBroker(getDOMDataBroker(), bindingToNormalized, schemaService );
+    }
+
+    public ForwardedBackwardsCompatibleDataBroker createBackwardsCompatibleDataBroker() {
+        return new ForwardedBackwardsCompatibleDataBroker(getDOMDataBroker(), bindingToNormalized, getSchemaService(), MoreExecutors.sameThreadExecutor());
+    }
+
+    private SchemaService getSchemaService() {
+        return schemaService;
+    }
+
+    private DOMDataBroker getDOMDataBroker() {
+        if(domDataBroker == null) {
+            domDataBroker = createDOMDataBroker();
+        }
+        return domDataBroker;
+    }
+
+    private synchronized ImmutableMap<LogicalDatastoreType, DOMStore> getDatastores() {
+        if (datastores == null) {
+            datastores = createDatastores();
+        }
+        return datastores;
+    }
+
+    public void updateSchema(final SchemaContext ctx) {
+        schemaService.changeSchema(ctx);
+        mappingService.onGlobalContextUpdated(ctx);
+    }
+
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/FRMTest.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/FRMTest.java
new file mode 100644 (file)
index 0000000..811d6ca
--- /dev/null
@@ -0,0 +1,42 @@
+package test.mock.util;
+
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+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.FlowCapableNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+import java.util.Collections;
+import java.util.concurrent.ExecutionException;
+
+public abstract class FRMTest extends AbstractDataBrokerTest{
+
+    public void addFlowCapableNode(NodeKey nodeKey) throws ExecutionException, InterruptedException {
+        Nodes nodes = new NodesBuilder().setNode(Collections.<Node>emptyList()).build();
+        InstanceIdentifier<Node> flowNodeIdentifier = InstanceIdentifier.create(Nodes.class)
+                .child(Node.class, nodeKey);
+
+        FlowCapableNodeBuilder fcnBuilder = new FlowCapableNodeBuilder();
+        NodeBuilder nodeBuilder = new NodeBuilder();
+        nodeBuilder.setKey(nodeKey);
+        nodeBuilder.addAugmentation(FlowCapableNode.class, fcnBuilder.build());
+
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class), nodes);
+        writeTx.put(LogicalDatastoreType.OPERATIONAL, flowNodeIdentifier, nodeBuilder.build());
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(Nodes.class), nodes);
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, flowNodeIdentifier, nodeBuilder.build());
+        assertCommit(writeTx.submit());
+    }
+
+    public void removeNode(NodeKey nodeKey) throws ExecutionException, InterruptedException {
+        WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
+        writeTx.delete(LogicalDatastoreType.OPERATIONAL, InstanceIdentifier.create(Nodes.class).child(Node.class, nodeKey));
+        writeTx.submit().get();
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/MockSchemaService.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/MockSchemaService.java
new file mode 100644 (file)
index 0000000..b4876a3
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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 test.mock.util;
+
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+
+@SuppressWarnings("deprecation")
+public final class MockSchemaService implements SchemaService, SchemaContextProvider {
+
+    private SchemaContext schemaContext;
+
+    ListenerRegistry<SchemaContextListener> listeners = ListenerRegistry.create();
+
+    @Override
+    public void addModule(final Module module) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public synchronized SchemaContext getGlobalContext() {
+        return schemaContext;
+    }
+
+    @Override
+    public synchronized SchemaContext getSessionContext() {
+        return schemaContext;
+    }
+
+    @Override
+    public ListenerRegistration<SchemaContextListener> registerSchemaContextListener(
+            final SchemaContextListener listener) {
+        return listeners.register(listener);
+    }
+
+    @Override
+    public void removeModule(final Module module) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public synchronized SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
+    public synchronized void changeSchema(final SchemaContext newContext) {
+        schemaContext = newContext;
+        for (ListenerRegistration<SchemaContextListener> listener : listeners) {
+            listener.getInstance().onGlobalContextUpdated(schemaContext);
+        }
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/RpcProviderRegistryMock.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/RpcProviderRegistryMock.java
new file mode 100644 (file)
index 0000000..ff17a0c
--- /dev/null
@@ -0,0 +1,42 @@
+package test.mock.util;
+
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.controller.sal.binding.api.rpc.RpcContextIdentifier;
+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.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.RpcService;
+
+public class RpcProviderRegistryMock implements RpcProviderRegistry {
+    @Override
+    public <T extends RpcService> BindingAwareBroker.RpcRegistration<T> addRpcImplementation(Class<T> serviceInterface, T implementation) throws IllegalStateException {
+        return null;
+    }
+
+    @Override
+    public <T extends RpcService> BindingAwareBroker.RoutedRpcRegistration<T> addRoutedRpcImplementation(Class<T> serviceInterface, T implementation) throws IllegalStateException {
+        return null;
+    }
+
+    @Override
+    public <L extends RouteChangeListener<RpcContextIdentifier, InstanceIdentifier<?>>> ListenerRegistration<L> registerRouteChangeListener(L listener) {
+        return null;
+    }
+
+    @Override
+    public <T extends RpcService> T getRpcService(Class<T> serviceInterface) {
+        if (serviceInterface.equals(SalFlowService.class)) {
+            return (T) new SalFlowServiceMock();
+        } else if (serviceInterface.equals(SalGroupService.class)) {
+            return (T) new SalGroupServiceMock();
+        } else if (serviceInterface.equals(SalMeterService.class)) {
+            return (T) new SalMeterServiceMock();
+        } else {
+            return null;
+        }
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/SalFlowServiceMock.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/SalFlowServiceMock.java
new file mode 100644 (file)
index 0000000..4bddc69
--- /dev/null
@@ -0,0 +1,51 @@
+package test.mock.util;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.RemoveFlowOutput;
+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.UpdateFlowOutput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+
+public class SalFlowServiceMock implements SalFlowService{
+    private List<AddFlowInput> addFlowCalls = new ArrayList<>();
+    private List<RemoveFlowInput> removeFlowCalls = new ArrayList<>();
+    private List<UpdateFlowInput> updateFlowCalls = new ArrayList<>();
+
+    @Override
+    public Future<RpcResult<AddFlowOutput>> addFlow(AddFlowInput input) {
+        addFlowCalls.add(input);
+        return null;
+    }
+
+
+    @Override
+    public Future<RpcResult<RemoveFlowOutput>> removeFlow(RemoveFlowInput input) {
+        removeFlowCalls.add(input);
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<UpdateFlowOutput>> updateFlow(UpdateFlowInput input) {
+        updateFlowCalls.add(input);
+        return null;
+    }
+
+    public List<AddFlowInput> getAddFlowCalls() {
+        return addFlowCalls;
+    }
+
+    public List<RemoveFlowInput> getRemoveFlowCalls() {
+        return removeFlowCalls;
+    }
+
+    public List<UpdateFlowInput> getUpdateFlowCalls() {
+        return updateFlowCalls;
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/SalGroupServiceMock.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/SalGroupServiceMock.java
new file mode 100644 (file)
index 0000000..9fa7b76
--- /dev/null
@@ -0,0 +1,50 @@
+package test.mock.util;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.AddGroupOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.group.service.rev130918.RemoveGroupOutput;
+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.UpdateGroupOutput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+
+public class SalGroupServiceMock implements SalGroupService {
+    private List<AddGroupInput> addGroupCalls = new ArrayList<>();
+    private List<RemoveGroupInput> removeGroupCalls = new ArrayList<>();
+    private List<UpdateGroupInput> updateGroupCalls = new ArrayList<>();
+
+    @Override
+    public Future<RpcResult<AddGroupOutput>> addGroup(AddGroupInput input) {
+        addGroupCalls.add(input);
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<RemoveGroupOutput>> removeGroup(RemoveGroupInput input) {
+        removeGroupCalls.add(input);
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<UpdateGroupOutput>> updateGroup(UpdateGroupInput input) {
+        updateGroupCalls.add(input);
+        return null;
+    }
+
+    public List<AddGroupInput> getAddGroupCalls() {
+        return addGroupCalls;
+    }
+
+    public List<RemoveGroupInput> getRemoveGroupCalls() {
+        return removeGroupCalls;
+    }
+
+    public List<UpdateGroupInput> getUpdateGroupCalls() {
+        return updateGroupCalls;
+    }
+}
diff --git a/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/SalMeterServiceMock.java b/opendaylight/md-sal/forwardingrules-manager/src/test/java/test/mock/util/SalMeterServiceMock.java
new file mode 100644 (file)
index 0000000..fb053cb
--- /dev/null
@@ -0,0 +1,50 @@
+package test.mock.util;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.AddMeterOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.meter.service.rev130918.RemoveMeterOutput;
+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.UpdateMeterOutput;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Future;
+
+public class SalMeterServiceMock implements SalMeterService {
+    private List<AddMeterInput> addMeterCalls = new ArrayList<>();
+    private List<RemoveMeterInput> removeMeterCalls = new ArrayList<>();
+    private List<UpdateMeterInput> updateMeterCalls = new ArrayList<>();
+
+    @Override
+    public Future<RpcResult<AddMeterOutput>> addMeter(AddMeterInput input) {
+        addMeterCalls.add(input);
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<RemoveMeterOutput>> removeMeter(RemoveMeterInput input) {
+        removeMeterCalls.add(input);
+        return null;
+    }
+
+    @Override
+    public Future<RpcResult<UpdateMeterOutput>> updateMeter(UpdateMeterInput input) {
+        updateMeterCalls.add(input);
+        return null;
+    }
+
+    public List<AddMeterInput> getAddMeterCalls() {
+        return addMeterCalls;
+    }
+
+    public List<RemoveMeterInput> getRemoveMeterCalls() {
+        return removeMeterCalls;
+    }
+
+    public List<UpdateMeterInput> getUpdateMeterCalls() {
+        return updateMeterCalls;
+    }
+}