import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.openflowplugin.applications.old.notification.supplier.impl.NodeConnectorNotificationSupplierImpl;
import org.opendaylight.openflowplugin.applications.old.notification.supplier.impl.NodeNotificationSupplierImpl;
+import org.opendaylight.openflowplugin.applications.old.notification.supplier.impl.item.FlowNotificationSupplierImpl;
import org.opendaylight.openflowplugin.applications.old.notification.supplier.tools.OldNotifProviderConfig;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
+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.FlowAdded;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRemoved;
private List<OldNotifSupplierDefinition<?>> supplierList;
private OldNotifSupplierForItemRoot<FlowCapableNode, NodeUpdated, NodeRemoved> nodeSupp;
private OldNotifSupplierForItemRoot<FlowCapableNodeConnector, NodeConnectorUpdated, NodeConnectorRemoved> connectorSupp;
+ private OldNotifSupplierForItem<Flow, FlowAdded, FlowUpdated, FlowRemoved> flowSupp;
/**
* Provider constructor set all needed final parameters
public void start() {
nodeSupp = new NodeNotificationSupplierImpl(nps, db);
connectorSupp = new NodeConnectorNotificationSupplierImpl(nps, db);
+ flowSupp = config.isFlowSupport() ? new FlowNotificationSupplierImpl(nps, db) : null;
- supplierList = new ArrayList<>(Arrays.<OldNotifSupplierDefinition<?>> asList(nodeSupp, connectorSupp));
+ supplierList = new ArrayList<>(Arrays.asList(nodeSupp, connectorSupp, flowSupp));
}
@Override
--- /dev/null
+/*
+ * Copyright (c) 2015 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.openflowplugin.applications.old.notification.supplier;
+
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+/**
+ * Supplier Item contracts definition for every Old Notifications. All items are described
+ * by three notifications. Notification for Create, Update and Delete. So interface
+ * has to contain three methods for every Notification.
+ *
+ * @param <O> - data tree item Object
+ * @param <C> - Create notification
+ * @param <U> - Update notification
+ * @param <D> - Delete notification
+ */
+public interface OldNotifSupplierForItem<O extends DataObject, C extends Notification, U extends Notification, D extends Notification>
+ extends OldNotifSupplierDefinition<O> {
+
+ /**
+ * Method produces relevant addItem kind of {@link Notification} from
+ * data tree item identified by {@link InstanceIdentifier} path.
+ *
+ * @param o - Data Tree Item object
+ * @param path - Identifier of Data Tree Item
+ * @return {@link Notification} - relevant API contract Notification
+ */
+ C createNotification(O o, InstanceIdentifier<O> path);
+
+ /**
+ * Method produces relevant updateItem kind of {@link Notification} from
+ * data tree item identified by {@link InstanceIdentifier} path.
+ *
+ * @param o - Data Tree Item object
+ * @param path - Identifier of Data Tree Item
+ * @return {@link Notification} - relevant API contract Notification
+ */
+ U updateNotification(O o, InstanceIdentifier<O> path);
+
+ /**
+ * Method produces relevant deleteItem kind of {@link Notification} from
+ * path {@link InstanceIdentifier} to deleted item.
+ *
+ * @param path - Identifier of Data Tree Item
+ * @return {@link Notification} - relevant API contract Notification
+ */
+ D deleteNotification(InstanceIdentifier<O> path);
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2015 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.openflowplugin.applications.old.notification.supplier.impl.item;
+
+import com.google.common.base.Preconditions;
+import java.util.Map.Entry;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.openflowplugin.applications.old.notification.supplier.OldNotifSupplierForItem;
+import org.opendaylight.openflowplugin.applications.old.notification.supplier.impl.AbstractNotifSupplierBase;
+import org.opendaylight.yangtools.yang.binding.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.Notification;
+
+/**
+ * Class is package protected abstract implementation for all Old Root Items
+ * Notification Suppliers
+ *
+ * @param <O> - data tree item Object
+ * @param <C> - Create notification
+ * @param <U> - Update notification
+ * @param <D> - Delete notification
+ */
+abstract class AbstractNotifSupplierForItem<O extends DataObject,
+ C extends Notification,
+ U extends Notification,
+ D extends Notification>
+ extends AbstractNotifSupplierBase<O>
+ implements OldNotifSupplierForItem<O, C, U, D> {
+
+ private final NotificationProviderService notifProviderService;
+
+ /**
+ * Default constructor for all item Notification Supplier implementation
+ *
+ * @param notifProviderService - notification publisher
+ * @param db - DataBroker for DataChangeEvent registration
+ * @param clazz - Statistics Notification Class
+ */
+ public AbstractNotifSupplierForItem(final NotificationProviderService notifProviderService, final DataBroker db,
+ final Class<O> clazz) {
+ super(db, clazz);
+ this.notifProviderService = Preconditions.checkNotNull(notifProviderService);
+ }
+
+ @Override
+ public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+ Preconditions.checkArgument(change != null, "ChangeEvent can not be null!");
+ if (change.getCreatedData() != null && !(change.getCreatedData().isEmpty())) {
+ for (final Entry<InstanceIdentifier<?>, DataObject> createDataObj : change.getCreatedData().entrySet()) {
+ if (clazz.isAssignableFrom(createDataObj.getKey().getTargetType())) {
+ final InstanceIdentifier<O> ii = createDataObj.getKey().firstIdentifierOf(clazz);
+ final C notif = createNotification((O) createDataObj.getValue(), ii);
+ if (notif != null) {
+ notifProviderService.publish(notif);
+ }
+ }
+ }
+ }
+
+ if (change.getUpdatedData() != null && !(change.getUpdatedData().isEmpty())) {
+ for (final Entry<InstanceIdentifier<?>, DataObject> updateDataObj : change.getUpdatedData().entrySet()) {
+ if (clazz.isAssignableFrom(updateDataObj.getKey().getTargetType())) {
+ final InstanceIdentifier<O> ii = updateDataObj.getKey().firstIdentifierOf(clazz);
+ final U notif = updateNotification((O) updateDataObj.getValue(), ii);
+ if (notif != null) {
+ notifProviderService.publish(notif);
+ }
+ }
+ }
+ }
+
+ if (change.getRemovedPaths() != null && !(change.getRemovedPaths().isEmpty())) {
+ for (final InstanceIdentifier<?> deleteDataPath : change.getRemovedPaths()) {
+ if (clazz.isAssignableFrom(deleteDataPath.getTargetType())) {
+ final D notif = deleteNotification(deleteDataPath.firstIdentifierOf(clazz));
+ if (notif != null) {
+ notifProviderService.publish(notif);
+ }
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015 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.openflowplugin.applications.old.notification.supplier.impl.item;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+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.FlowAdded;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowAddedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemovedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdatedBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.rev131026.FlowRef;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ * Implementation define a contract between {@link Flow} data object
+ * and {@link FlowAdded}, {@link FlowUpdated} and {@link FlowRemoved} notifications.
+ */
+public class FlowNotificationSupplierImpl extends
+ AbstractNotifSupplierForItem<Flow, FlowAdded, FlowUpdated, FlowRemoved> {
+
+ private static final InstanceIdentifier<Flow> wildCardedInstanceIdent = getNodeWildII().augmentation(FlowCapableNode.class).child(Table.class).child(Flow.class);
+
+ /**
+ * Constructor register supplier as DataChangeLister and create wildCarded InstanceIdentifier.
+ *
+ * @param notifProviderService - {@link NotificationProviderService}
+ * @param db - {@link DataBroker}
+ */
+ public FlowNotificationSupplierImpl(final NotificationProviderService notifProviderService, final DataBroker db) {
+ super(notifProviderService, db, Flow.class);
+ }
+
+ @Override
+ public InstanceIdentifier<Flow> getWildCardPath() {
+ return wildCardedInstanceIdent;
+ }
+
+ @Override
+ public FlowAdded createNotification(final Flow o, final InstanceIdentifier<Flow> path) {
+ Preconditions.checkArgument(o != null);
+ Preconditions.checkArgument(path != null);
+ final FlowAddedBuilder builder = new FlowAddedBuilder(o);
+ builder.setFlowRef(new FlowRef(path));
+ builder.setNode(createNodeRef(path));
+ return builder.build();
+ }
+
+ @Override
+ public FlowUpdated updateNotification(final Flow o, final InstanceIdentifier<Flow> path) {
+ Preconditions.checkArgument(o != null);
+ Preconditions.checkArgument(path != null);
+ final FlowUpdatedBuilder builder = new FlowUpdatedBuilder(o);
+ builder.setFlowRef(new FlowRef(path));
+ builder.setNode(createNodeRef(path));
+ return builder.build();
+ }
+
+ @Override
+ public FlowRemoved deleteNotification(final InstanceIdentifier<Flow> path) {
+ Preconditions.checkArgument(path != null);
+ final FlowRemovedBuilder builder = new FlowRemovedBuilder();
+ builder.setFlowRef(new FlowRef(path));
+ builder.setNode(createNodeRef(path));
+ return builder.build();
+ }
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2015 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 contains OF Items (Flow, Group, Meter ...) notification listener/supplier implementations
+ */
+package org.opendaylight.openflowplugin.applications.old.notification.supplier.impl.item;
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2015 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.openflowplugin.applications.old.notification.supplier.impl.item;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Matchers;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
+import org.opendaylight.openflowplugin.applications.old.notification.supplier.impl.helper.TestChangeEventBuildHelper;
+import org.opendaylight.openflowplugin.applications.old.notification.supplier.impl.helper.TestSupplierVerifyHelper;
+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.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.FlowAdded;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowRemoved;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.service.rev130819.FlowUpdated;
+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.DataObject;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+/**
+ *
+ */
+public class FlowNotificationSupplierImplTest {
+
+ private static final String FLOW_NODE_ID = "test-111";
+ private static final Short FLOW_TABLE_ID = 111;
+ private static final String FLOW_ID = "test-flow-111";
+ private FlowNotificationSupplierImpl notifSupplierImpl;
+ private NotificationProviderService notifProviderService;
+ private DataBroker dataBroker;
+
+ @Before
+ public void initalization() {
+ notifProviderService = mock(NotificationProviderService.class);
+ dataBroker = mock(DataBroker.class);
+ notifSupplierImpl = new FlowNotificationSupplierImpl(notifProviderService, dataBroker);
+ TestSupplierVerifyHelper.verifyDataChangeRegistration(dataBroker);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNullChangeEvent() {
+ notifSupplierImpl.onDataChanged(null);
+ }
+
+ @Test
+ public void testNullableChangeEvent() {
+ notifSupplierImpl.onDataChanged(TestChangeEventBuildHelper.createEmptyTestDataEvent());
+ }
+
+ @Test
+ public void testEmptyChangeEvent() {
+ notifSupplierImpl.onDataChanged(TestChangeEventBuildHelper.createEmptyTestDataEvent());
+ }
+
+ @Test
+ public void testCreate() {
+ final FlowAdded notification = notifSupplierImpl.createNotification(createTestFlow(), createTestFlowPath());
+ assertNotNull(notification);
+ assertEquals(FLOW_ID, notification.getFlowRef().getValue().firstKeyOf(Flow.class, FlowKey.class).getId().getValue());
+ assertEquals(FLOW_TABLE_ID, notification.getFlowRef().getValue().firstKeyOf(Table.class, TableKey.class).getId());
+ assertEquals(FLOW_NODE_ID, notification.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId().getValue());
+ }
+
+ @Test
+ public void testCreateChangeEvent() {
+ final Map<InstanceIdentifier<?>, DataObject> createdData = new HashMap<>();
+ createdData.put(createTestFlowPath(), createTestFlow());
+ notifSupplierImpl.onDataChanged(TestChangeEventBuildHelper.createTestDataEvent(createdData, null, null));
+ verify(notifProviderService, times(1)).publish(Matchers.any(FlowAdded.class));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testCreateFromNullNodeConnector() {
+ notifSupplierImpl.createNotification(null, createTestFlowPath());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testCreateFromNullPath() {
+ notifSupplierImpl.createNotification(createTestFlow(), null);
+ }
+
+ @Test
+ public void testUpdate() {
+ final FlowUpdated notification = notifSupplierImpl.updateNotification(createTestFlow(), createTestFlowPath());
+ assertNotNull(notification);
+ assertEquals(FLOW_ID, notification.getFlowRef().getValue().firstKeyOf(Flow.class, FlowKey.class).getId().getValue());
+ assertEquals(FLOW_TABLE_ID, notification.getFlowRef().getValue().firstKeyOf(Table.class, TableKey.class).getId());
+ assertEquals(FLOW_NODE_ID, notification.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId().getValue());
+ }
+
+ @Test
+ public void testUpdateChangeEvent() {
+ final Map<InstanceIdentifier<?>, DataObject> createdData = new HashMap<>();
+ createdData.put(createTestFlowPath(), createTestFlow());
+ notifSupplierImpl.onDataChanged(TestChangeEventBuildHelper.createTestDataEvent(createdData, null, null));
+ verify(notifProviderService, times(1)).publish(Matchers.any(FlowUpdated.class));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testUpdateFromNullNodeConnector() {
+ notifSupplierImpl.createNotification(null, createTestFlowPath());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testUpdateFromNullPath() {
+ notifSupplierImpl.createNotification(createTestFlow(), null);
+ }
+
+ @Test
+ public void testDelete() {
+ final FlowRemoved notification = notifSupplierImpl.deleteNotification(createTestFlowPath());
+ assertNotNull(notification);
+ assertEquals(FLOW_ID, notification.getFlowRef().getValue().firstKeyOf(Flow.class, FlowKey.class).getId().getValue());
+ assertEquals(FLOW_TABLE_ID, notification.getFlowRef().getValue().firstKeyOf(Table.class, TableKey.class).getId());
+ assertEquals(FLOW_NODE_ID, notification.getNode().getValue().firstKeyOf(Node.class, NodeKey.class).getId().getValue());
+ }
+
+ @Test
+ public void testDeleteChangeEvent() {
+ final Set<InstanceIdentifier<?>> removeData = new HashSet<>();
+ removeData.add(createTestFlowPath());
+ notifSupplierImpl.onDataChanged(TestChangeEventBuildHelper.createTestDataEvent(null, null, removeData));
+ verify(notifProviderService, times(1)).publish(Matchers.any(FlowRemoved.class));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testDeleteFromNullPath() {
+ notifSupplierImpl.deleteNotification(null);
+ }
+
+ private static InstanceIdentifier<Flow> createTestFlowPath() {
+ return InstanceIdentifier.create(Nodes.class).child(Node.class, new NodeKey(new NodeId(FLOW_NODE_ID)))
+ .augmentation(FlowCapableNode.class).child(Table.class, new TableKey(FLOW_TABLE_ID))
+ .child(Flow.class, new FlowKey(new FlowId(FLOW_ID)));
+ }
+
+ private static Flow createTestFlow() {
+ final FlowBuilder builder = new FlowBuilder();
+ builder.setId(new FlowId(FLOW_ID));
+ builder.setTableId(FLOW_TABLE_ID);
+ return builder.build();
+ }
+}
+