2 * Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
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
9 package org.opendaylight.openflowplugin.applications.frsync.impl;
11 import com.google.common.base.Optional;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import java.util.Collection;
14 import java.util.List;
15 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
16 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
17 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
20 import org.opendaylight.openflowplugin.applications.frsync.SyncReactor;
21 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeDao;
22 import org.opendaylight.openflowplugin.applications.frsync.dao.FlowCapableNodeSnapshotDao;
23 import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
25 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
26 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
27 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
34 * Listens to operational new nodes and delegates add/remove/update/barrier to {@link SyncReactor}.
36 public class SimplifiedOperationalListener extends AbstractFrmSyncListener<Node> {
37 private static final Logger LOG = LoggerFactory.getLogger(SimplifiedOperationalListener.class);
39 protected final SyncReactor reactor;
40 protected final FlowCapableNodeSnapshotDao operationalSnapshot;
41 protected final FlowCapableNodeDao configDao;
43 public SimplifiedOperationalListener(SyncReactor reactor, FlowCapableNodeSnapshotDao operationalSnapshot,
44 FlowCapableNodeDao configDao) {
45 this.reactor = reactor;
46 this.operationalSnapshot = operationalSnapshot;
47 this.configDao = configDao;
51 public void onDataTreeChanged(Collection<DataTreeModification<Node>> modifications) {
52 LOG.trace("Inventory Operational changes {}", modifications.size());
53 super.onDataTreeChanged(modifications);
57 * This method behaves like this:
59 * <li>If node is added to operational store then reconciliation.</li>
60 * <li>Node is deleted from operational cache is removed.</li>
61 * <li>Skip this event otherwise.</li>
64 * @throws InterruptedException from syncup
66 protected Optional<ListenableFuture<Boolean>> processNodeModification(
67 DataTreeModification<Node> modification) throws ReadFailedException, InterruptedException {
69 updateCache(modification);
70 if (isReconciliationNeeded(modification)) {
71 return reconciliation(modification);
73 return skipModification(modification);
77 * Remove if delete. Update only if FlowCapableNode Augmentation modified.
79 * @param modification Datastore modification
80 * @return true for cache update, false for cache remove
82 protected boolean updateCache(DataTreeModification<Node> modification) {
83 if (isDelete(modification) || isDeleteLogical(modification)) {
84 operationalSnapshot.updateCache(nodeId(modification), Optional.<FlowCapableNode>absent());
87 operationalSnapshot.updateCache(nodeId(modification), Optional.fromNullable(flowCapableNodeAfter(modification)));
91 private Optional<ListenableFuture<Boolean>> skipModification(DataTreeModification<Node> modification) {
92 LOG.trace("Skipping Inventory Operational modification {}, before {}, after {}", nodeIdValue(modification),
93 modification.getRootNode().getDataBefore() == null ? "null" : "nonnull",
94 modification.getRootNode().getDataAfter() == null ? "null" : "nonnull");
95 return Optional.absent();
99 * ModificationType.DELETE
101 private boolean isDelete(DataTreeModification<Node> modification) {
102 if (ModificationType.DELETE == modification.getRootNode().getModificationType()) {
103 LOG.trace("Delete {} (physical)", nodeIdValue(modification));
111 * All connectors disappeared from operational store (logical delete).
113 private boolean isDeleteLogical(DataTreeModification<Node> modification) {
114 final DataObjectModification<Node> rootNode = modification.getRootNode();
115 if (!safeConnectorsEmpty(rootNode.getDataBefore()) && safeConnectorsEmpty(rootNode.getDataAfter())) {
116 LOG.trace("Delete {} (logical)", nodeIdValue(modification));
123 private boolean isAdd(DataTreeModification<Node> modification) {
124 final DataObjectModification<Node> rootNode = modification.getRootNode();
125 final Node dataAfter = rootNode.getDataAfter();
126 final Node dataBefore = rootNode.getDataBefore();
128 final boolean nodeAppearedInOperational = dataBefore == null && dataAfter != null;
129 if (nodeAppearedInOperational) {
130 LOG.trace("Add {} (physical)", nodeIdValue(modification));
132 return nodeAppearedInOperational;
136 * All connectors appeared in operational store (logical add).
138 private boolean isAddLogical(DataTreeModification<Node> modification) {
139 final DataObjectModification<Node> rootNode = modification.getRootNode();
140 if (safeConnectorsEmpty(rootNode.getDataBefore()) && !safeConnectorsEmpty(rootNode.getDataAfter())) {
141 LOG.trace("Add {} (logical)", nodeIdValue(modification));
148 protected boolean isReconciliationNeeded(DataTreeModification<Node> modification) {
149 return isAdd(modification) || isAddLogical(modification);
152 private Optional<ListenableFuture<Boolean>> reconciliation(DataTreeModification<Node> modification) throws InterruptedException {
153 final NodeId nodeId = nodeId(modification);
154 final Optional<FlowCapableNode> nodeConfiguration = configDao.loadByNodeId(nodeId);
156 if (nodeConfiguration.isPresent()) {
157 LOG.debug("Reconciliation: {}", nodeId.getValue());
158 final InstanceIdentifier<FlowCapableNode> nodePath = InstanceIdentifier.create(Nodes.class)
159 .child(Node.class, new NodeKey(nodeId(modification))).augmentation(FlowCapableNode.class);
160 return Optional.of(reactor.syncup(nodePath, nodeConfiguration.get(), flowCapableNodeAfter(modification), dsType()));
162 return skipModification(modification);
166 static FlowCapableNode flowCapableNodeAfter(DataTreeModification<Node> modification) {
167 final Node dataAfter = modification.getRootNode().getDataAfter();
168 if (dataAfter == null) {
171 return dataAfter.getAugmentation(FlowCapableNode.class);
174 static boolean safeConnectorsEmpty(Node node) {
179 final List<NodeConnector> nodeConnectors = node.getNodeConnector();
181 return nodeConnectors == null || nodeConnectors.isEmpty();
184 static String nodeIdValue(DataTreeModification<Node> modification) {
185 final NodeId nodeId = nodeId(modification);
187 if (nodeId == null) {
191 return nodeId.getValue();
194 static NodeId nodeId(DataTreeModification<Node> modification) {
195 final DataObjectModification<Node> rootNode = modification.getRootNode();
196 final Node dataAfter = rootNode.getDataAfter();
198 if (dataAfter != null) {
199 return dataAfter.getId();
202 final Node dataBefore = rootNode.getDataBefore();
203 if (dataBefore != null) {
204 return dataBefore.getId();
211 public LogicalDatastoreType dsType() {
212 return LogicalDatastoreType.OPERATIONAL;