Bug 1699 - FRM: Change data change listener scope from BASE to SUBTREE
[controller.git] / opendaylight / md-sal / forwardingrules-manager / src / main / java / org / opendaylight / controller / frm / impl / FlowNodeReconciliationImpl.java
1 /**
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8
9 package org.opendaylight.controller.frm.impl;
10
11 import java.util.Collections;
12 import java.util.List;
13 import java.util.Set;
14
15 import org.opendaylight.controller.frm.FlowNodeReconciliation;
16 import org.opendaylight.controller.frm.ForwardingRulesManager;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
19 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
21 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
22 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.Meter;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.meters.MeterKey;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.Table;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.TableKey;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.Flow;
29 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.tables.table.FlowKey;
30 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.Group;
31 import org.opendaylight.yang.gen.v1.urn.opendaylight.group.types.rev131018.groups.GroupKey;
32 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
33 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
34 import org.opendaylight.yangtools.concepts.ListenerRegistration;
35 import org.opendaylight.yangtools.yang.binding.DataObject;
36 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
37 import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40
41 import com.google.common.base.Optional;
42 import com.google.common.base.Preconditions;
43
44 /**
45  * forwardingrules-manager
46  * org.opendaylight.controller.frm
47  *
48  * FlowNode Reconciliation Listener
49  * Reconciliation for a new FlowNode
50  *
51  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
52  *
53  * Created: Jun 13, 2014
54  */
55 public class FlowNodeReconciliationImpl implements FlowNodeReconciliation {
56
57     private static final Logger LOG = LoggerFactory.getLogger(FlowNodeReconciliationImpl.class);
58
59     private final ForwardingRulesManager provider;
60
61     private ListenerRegistration<DataChangeListener> listenerRegistration;
62
63     public FlowNodeReconciliationImpl (final ForwardingRulesManager manager, final DataBroker db) {
64         this.provider = Preconditions.checkNotNull(manager, "ForwardingRulesManager can not be null!");
65         Preconditions.checkNotNull(db, "DataBroker can not be null!");
66         /* Build Path */
67         InstanceIdentifier<FlowCapableNode> flowNodeWildCardIdentifier = InstanceIdentifier.create(Nodes.class)
68                 .child(Node.class).augmentation(FlowCapableNode.class);
69         this.listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
70                 flowNodeWildCardIdentifier, FlowNodeReconciliationImpl.this, DataChangeScope.BASE);
71     }
72
73     @Override
74     public void close() {
75         if (listenerRegistration != null) {
76             try {
77                 listenerRegistration.close();
78             } catch (Exception e) {
79                 LOG.error("Error by stop FRM FlowNodeReconilListener.", e);
80             }
81             listenerRegistration = null;
82         }
83     }
84
85     @Override
86     public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
87         Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
88         /* All DataObjects for create */
89         final Set<InstanceIdentifier<?>>  createdData = changeEvent.getCreatedData() != null
90                 ? changeEvent.getCreatedData().keySet() : Collections.<InstanceIdentifier<?>> emptySet();
91         /* All DataObjects for remove */
92         final Set<InstanceIdentifier<?>> removeData = changeEvent.getRemovedPaths() != null
93                 ? changeEvent.getRemovedPaths() : Collections.<InstanceIdentifier<?>> emptySet();
94
95         for (InstanceIdentifier<?> entryKey : removeData) {
96             final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
97                     .firstIdentifierOf(FlowCapableNode.class);
98             if ( ! nodeIdent.isWildcarded()) {
99                 flowNodeDisconnected(nodeIdent);
100             }
101         }
102         for (InstanceIdentifier<?> entryKey : createdData) {
103             final InstanceIdentifier<FlowCapableNode> nodeIdent = entryKey
104                     .firstIdentifierOf(FlowCapableNode.class);
105             if ( ! nodeIdent.isWildcarded()) {
106                 flowNodeConnected(nodeIdent);
107             }
108         }
109     }
110
111     @Override
112     public void flowNodeDisconnected(InstanceIdentifier<FlowCapableNode> disconnectedNode) {
113         provider.unregistrateNode(disconnectedNode);
114     }
115
116     @Override
117     public void flowNodeConnected(InstanceIdentifier<FlowCapableNode> connectedNode) {
118         if ( ! provider.isNodeActive(connectedNode)) {
119             provider.registrateNewNode(connectedNode);
120             reconciliation(connectedNode);
121         }
122     }
123
124     private void reconciliation(final InstanceIdentifier<FlowCapableNode> nodeIdent) {
125
126         ReadOnlyTransaction trans = provider.getReadTranaction();
127         Optional<FlowCapableNode> flowNode = Optional.absent();
128
129         try {
130             flowNode = trans.read(LogicalDatastoreType.CONFIGURATION, nodeIdent).get();
131         }
132         catch (Exception e) {
133             LOG.error("Fail with read Config/DS for Node {} !", nodeIdent, e);
134         }
135
136         if (flowNode.isPresent()) {
137             /* Groups - have to be first */
138             List<Group> groups = flowNode.get().getGroup() != null
139                     ? flowNode.get().getGroup() : Collections.<Group> emptyList();
140             for (Group group : groups) {
141                 final KeyedInstanceIdentifier<Group, GroupKey> groupIdent =
142                         nodeIdent.child(Group.class, group.getKey());
143                 this.provider.getGroupCommiter().add(groupIdent, group, nodeIdent);
144             }
145             /* Meters */
146             List<Meter> meters = flowNode.get().getMeter() != null
147                     ? flowNode.get().getMeter() : Collections.<Meter> emptyList();
148             for (Meter meter : meters) {
149                 final KeyedInstanceIdentifier<Meter, MeterKey> meterIdent =
150                         nodeIdent.child(Meter.class, meter.getKey());
151                 this.provider.getMeterCommiter().add(meterIdent, meter, nodeIdent);
152             }
153             /* Flows */
154             List<Table> tables = flowNode.get().getTable() != null
155                     ? flowNode.get().getTable() : Collections.<Table> emptyList();
156             for (Table table : tables) {
157                 final KeyedInstanceIdentifier<Table, TableKey> tableIdent =
158                         nodeIdent.child(Table.class, table.getKey());
159                 List<Flow> flows = table.getFlow() != null ? table.getFlow() : Collections.<Flow> emptyList();
160                 for (Flow flow : flows) {
161                     final KeyedInstanceIdentifier<Flow, FlowKey> flowIdent =
162                             tableIdent.child(Flow.class, flow.getKey());
163                     this.provider.getFlowCommiter().add(flowIdent, flow, nodeIdent);
164                 }
165             }
166         }
167         /* clean transaction */
168         trans.close();
169     }
170 }
171