Bug 6366 - of-switch-config-pusher - DTCL instead of DTL 03/43503/9
authorAndrej Leitner <andrej.leitner@pantheon.tech>
Tue, 9 Aug 2016 12:19:17 +0000 (14:19 +0200)
committerAndrej Leitner <andrej.leitner@pantheon.sk>
Mon, 15 Aug 2016 10:53:16 +0000 (10:53 +0000)
 - of-switch-config-pusher app converted to use DataTreeChangeListener
   instead of deprecated DataChangeListener
 - updated tests

Change-Id: Ic0f125ac87b52f67febbb16924227152a2bf7b25
Signed-off-by: Andrej Leitner <andrej.leitner@pantheon.tech>
applications/of-switch-config-pusher/pom.xml
applications/of-switch-config-pusher/src/main/java/org/opendaylight/openflowplugin/openflow/ofswitch/config/DefaultConfigPusher.java
applications/of-switch-config-pusher/src/main/resources/org/opendaylight/blueprint/of-switch-config-pusher.xml
applications/of-switch-config-pusher/src/test/java/org/opendaylight/openflowplugin/openflow/ofswitch/config/DefaultConfigPusherTest.java

index ccfc4b1a047ec9452192e4c1a4f5623dbdd6501d..ecd3ccdb155e7f854774d7bf6e98eeb7d0abc057 100644 (file)
             <groupId>org.opendaylight.openflowplugin.model</groupId>
             <artifactId>model-flow-service</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.openflowplugin</groupId>
+            <artifactId>openflowplugin-common</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.mockito</groupId>
             <artifactId>mockito-all</artifactId>
index 40952c6ac779bc0b4f6d49fa98cf2be1aa4592c0..72544ae50d24263c23c1a1138a6e182e6ada838d 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/**
  * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others.  All rights reserved.
  *
  * This program and the accompanying materials are made available under the
@@ -8,13 +8,17 @@
 
 package org.opendaylight.openflowplugin.openflow.ofswitch.config;
 
-import java.util.Set;
+import java.util.Collection;
+import java.util.concurrent.Callable;
+import javax.annotation.Nonnull;
 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;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.openflowplugin.api.OFConstants;
+import org.opendaylight.openflowplugin.common.wait.SimpleTaskRetryLooper;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
@@ -23,17 +27,17 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.module.config.rev141015.Nod
 import org.opendaylight.yang.gen.v1.urn.opendaylight.module.config.rev141015.SetConfigInputBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.SwitchConfigFlag;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-/**
- * Created by Martin Bobak mbobak@cisco.com on 10/14/14.
- */
-public class DefaultConfigPusher implements AutoCloseable, DataChangeListener {
-
+public class DefaultConfigPusher implements AutoCloseable, DataTreeChangeListener<FlowCapableNode> {
+    private static final Logger LOG = LoggerFactory.getLogger(DefaultConfigPusher.class);
+    private static final long STARTUP_LOOP_TICK = 500L;
+    private static final int STARTUP_LOOP_MAX_RETRIES = 8;
     private final NodeConfigService nodeConfigService;
     private final DataBroker dataBroker;
-    private ListenerRegistration<DataChangeListener> dataChangeListenerRegistration;
+    private ListenerRegistration<DataTreeChangeListener> listenerRegistration;
 
     public DefaultConfigPusher(NodeConfigService nodeConfigService, DataBroker dataBroker) {
         this.nodeConfigService = nodeConfigService;
@@ -41,33 +45,41 @@ public class DefaultConfigPusher implements AutoCloseable, DataChangeListener {
     }
 
     public void start() {
-        InstanceIdentifier<FlowCapableNode> path = InstanceIdentifier.create(Nodes.class).child(Node.class).
-                augmentation(FlowCapableNode.class);
-        dataChangeListenerRegistration = dataBroker.registerDataChangeListener(
-                LogicalDatastoreType.OPERATIONAL,
-                path, this, AsyncDataBroker.DataChangeScope.BASE);
+        try {
+            final InstanceIdentifier<FlowCapableNode> path = InstanceIdentifier.create(Nodes.class).child(Node.class).augmentation(FlowCapableNode.class);
+            final DataTreeIdentifier<FlowCapableNode> identifier = new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, path);
+            final SimpleTaskRetryLooper looper = new SimpleTaskRetryLooper(STARTUP_LOOP_TICK, STARTUP_LOOP_MAX_RETRIES);
+            listenerRegistration = looper.loopUntilNoException(new Callable<ListenerRegistration<DataTreeChangeListener>>() {
+                @Override
+                public ListenerRegistration<DataTreeChangeListener> call() throws Exception {
+                    return dataBroker.registerDataTreeChangeListener(identifier, DefaultConfigPusher.this);
+                }
+            });
+        } catch (Exception e) {
+            LOG.error("DataTreeChangeListener registration failed: {}", e);
+            throw new IllegalStateException("DefaultConfigPusher startup failed!", e);
+        }
+        LOG.info("DefaultConfigPusher has started.");
     }
 
     @Override
     public void close() {
-        if(dataChangeListenerRegistration != null) {
-            dataChangeListenerRegistration.close();
+        if(listenerRegistration != null) {
+            listenerRegistration.close();
         }
     }
 
     @Override
-    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
-        final Set<InstanceIdentifier<?>> changedDataKeys = change.getCreatedData().keySet();
-
-        if (changedDataKeys != null) {
-            for (InstanceIdentifier<?> key : changedDataKeys) {
+    public void onDataTreeChanged(@Nonnull final Collection<DataTreeModification<FlowCapableNode>> modifications) {
+        for (DataTreeModification modification : modifications) {
+            if (modification.getRootNode().getModificationType() == ModificationType.WRITE) {
                 SetConfigInputBuilder setConfigInputBuilder = new SetConfigInputBuilder();
                 setConfigInputBuilder.setFlag(SwitchConfigFlag.FRAGNORMAL.toString());
                 setConfigInputBuilder.setMissSearchLength(OFConstants.OFPCML_NO_BUFFER);
-                setConfigInputBuilder.setNode(new NodeRef(key.firstIdentifierOf(Node.class)));
+                setConfigInputBuilder.setNode(new NodeRef(modification.getRootPath().getRootIdentifier().firstIdentifierOf(Node.class)));
                 nodeConfigService.setConfig(setConfigInputBuilder.build());
             }
         }
-
     }
+
 }
index 39e82e8f9de73bde2eb160d817b5ba63b9bd7ae3..93a7f599853bea9a3118bd2a6bfd055329c963d8 100644 (file)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0"
            xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
-        odl:use-default-for-reference-types="true">
+           odl:use-default-for-reference-types="true">
 
   <reference id="dataBroker" interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"/>
 
index 777974332980e052efb35d2e4789b1fc6f61c867..9417ae7c16616ffa6af5967eb298708ecd263272 100644 (file)
@@ -8,68 +8,71 @@
 
 package org.opendaylight.openflowplugin.openflow.ofswitch.config;
 
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-import java.util.HashMap;
-import java.util.Map;
+import java.util.Collections;
+import org.junit.After;
+import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.mockito.Matchers;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.runners.MockitoJUnitRunner;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.AddFlowInputBuilder;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.openflowplugin.api.OFConstants;
+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.yang.gen.v1.urn.opendaylight.module.config.rev141015.NodeConfigService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.module.config.rev141015.SetConfigInput;
-import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.openflow.common.types.rev130731.SwitchConfigFlag;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * Test for {@link DefaultConfigPusher}.
  */
 @RunWith(MockitoJUnitRunner.class)
 public class DefaultConfigPusherTest {
-
-    private static final Logger LOG = LoggerFactory.getLogger(DefaultConfigPusherTest.class);
-
-    @Mock
-    private NodeConfigService mockNodeConfigService;
+    private DefaultConfigPusher defaultConfigPusher;
+    private final static InstanceIdentifier<Node> nodeIID = InstanceIdentifier.create(Nodes.class)
+            .child(Node.class, new NodeKey(new NodeId("testnode:1")));
     @Mock
-    private AsyncDataChangeEvent mockAsyncDataChangeEvent;
+    private NodeConfigService nodeConfigService;
     @Mock
-    private DataBroker mockDataBroker;
-
-    private DefaultConfigPusher defaultConfigPusher;
+    private DataTreeModification<FlowCapableNode> dataTreeModification;
+    @Captor
+    private ArgumentCaptor<SetConfigInput> setConfigInputCaptor;
 
     @Before
     public void setUp() throws Exception {
-        defaultConfigPusher = new DefaultConfigPusher(mockNodeConfigService, mockDataBroker);
+        defaultConfigPusher = new DefaultConfigPusher(nodeConfigService, Mockito.mock(DataBroker.class));
+        final DataTreeIdentifier<FlowCapableNode> identifier = new DataTreeIdentifier(LogicalDatastoreType.OPERATIONAL, nodeIID);
+        Mockito.when(dataTreeModification.getRootPath()).thenReturn(identifier);
+        Mockito.when(dataTreeModification.getRootNode()).thenReturn(Mockito.mock(DataObjectModification.class));
+        Mockito.when(dataTreeModification.getRootNode().getModificationType()).thenReturn(ModificationType.WRITE);
     }
 
     @Test
-    public void testOnDataChanged() throws Exception {
-        final InstanceIdentifier<Node> nodeIID = InstanceIdentifier.builder(Nodes.class)
-                .child(Node.class, new NodeKey(new NodeId("1")))
-                .build();
-
-        AddFlowInputBuilder addFlowInputBuilder = new AddFlowInputBuilder()
-                .setFlowName("flow:1");
-
-        Map<InstanceIdentifier<?>,DataObject> created = new HashMap<>();
-        created.put(nodeIID, addFlowInputBuilder.build());
+    public void testOnDataChanged() {
+        defaultConfigPusher.onDataTreeChanged(Collections.singleton(dataTreeModification));
+        Mockito.verify(nodeConfigService).setConfig(setConfigInputCaptor.capture());
+        final SetConfigInput captured = setConfigInputCaptor.getValue();
+        Assert.assertEquals(SwitchConfigFlag.FRAGNORMAL.toString(), captured.getFlag());
+        Assert.assertEquals(OFConstants.OFPCML_NO_BUFFER, captured.getMissSearchLength());
+        Assert.assertEquals(nodeIID, captured.getNode().getValue());
+    }
 
-        when(mockAsyncDataChangeEvent.getCreatedData()).thenReturn(created);
-        defaultConfigPusher.onDataChanged(mockAsyncDataChangeEvent);
-        verify(mockNodeConfigService).setConfig(Matchers.<SetConfigInput>any());
+    @After
+    public void tearDown() {
+        defaultConfigPusher.close();
     }
 
 }
\ No newline at end of file