2 * Copyright (c) 2014 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
8 package org.opendaylight.controller.frm;
10 import java.util.HashSet;
12 import java.util.Map.Entry;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.atomic.AtomicLong;
17 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
18 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
20 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
22 import org.opendaylight.yangtools.yang.binding.DataObject;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
28 * AbstractChangeListner implemented basic {@link AsyncDataChangeEvent} processing for
29 * flow node subDataObject (flows, groups and meters).
31 * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
34 public abstract class AbstractChangeListener implements DataChangeListener {
36 private final static Logger LOG = LoggerFactory.getLogger(AbstractChangeListener.class);
38 private final AtomicLong txNum = new AtomicLong();
39 private String transactionId;
42 public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
43 this.transactionId = this.newTransactionIdentifier().toString();
44 /* All DataObjects for create */
45 final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
46 changeEvent.getCreatedData().entrySet();
47 /* All DataObjects for updates - init HashSet */
48 final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updatedEntries = new HashSet<>();
49 /* Filtered DataObject for update processing only */
50 Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> updateConfigEntrySet =
51 changeEvent.getUpdatedData().entrySet();
52 updatedEntries.addAll(updateConfigEntrySet);
53 updatedEntries.removeAll(createdEntries);
54 /* All DataObjects for remove */
55 final Set<InstanceIdentifier<? extends DataObject>> removeEntriesInstanceIdentifiers =
56 changeEvent.getRemovedPaths();
57 /* Create DataObject processing (send to device) */
58 for (final Entry<InstanceIdentifier<? extends DataObject>, DataObject> createdEntry : createdEntries) {
59 InstanceIdentifier<? extends DataObject> entryKey = createdEntry.getKey();
60 DataObject entryValue = createdEntry.getValue();
61 if (preconditionForChange(entryKey, entryValue, null)) {
62 this.add(entryKey, entryValue);
66 for (final Entry<InstanceIdentifier<?>, DataObject> updatedEntrie : updatedEntries) {
67 Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
68 changeEvent.getOriginalData();
70 InstanceIdentifier<? extends Object> entryKey = updatedEntrie.getKey();
71 final DataObject original = origConfigData.get(entryKey);
72 final DataObject updated = updatedEntrie.getValue();
73 if (preconditionForChange(entryKey, original, updated)) {
74 this.update(entryKey, original, updated);
78 for (final InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers) {
79 Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
80 changeEvent.getOriginalData();
82 final DataObject removeValue = origConfigData.get(instanceId);
83 if (preconditionForChange(instanceId, removeValue, null)) {
84 this.remove(instanceId, removeValue);
90 * Method returns generated transaction ID, which is unique for
91 * every transaction. ID is composite from prefix ("DOM") and unique number.
93 * @return String transactionID
95 public String getTransactionId() {
96 return this.transactionId;
99 private Object newTransactionIdentifier() {
100 return "DOM-" + txNum.getAndIncrement();
104 * Method check all local preconditions for apply relevant changes.
106 * @param InstanceIdentifier identifier - the whole path to DataObject
107 * @param DataObject original - original DataObject (for update)
108 * or relevant DataObject (add/delete operations)
109 * @param DataObject update - changed DataObject (contain updates)
110 * or should be null for (add/delete operations)
112 * @return boolean - applicable
114 protected abstract boolean preconditionForChange(
115 final InstanceIdentifier<? extends DataObject> identifier,
116 final DataObject original, final DataObject update);
119 * Method checks the node data path in DataStore/OPERATIONAL because
120 * without the Node Identifier in DataStore/OPERATIONAL, device
121 * is not connected and device pre-configuration is allowed only.
123 * @param InstanceIdentifier identifier - could be whole path to DataObject,
124 * but parent Node.class InstanceIdentifier is used for a check only
126 * @return boolean - is the Node available in DataStore/OPERATIONAL (is connected)
128 protected boolean isNodeAvailable(final InstanceIdentifier<? extends DataObject> identifier,
129 final ReadOnlyTransaction readTrans) {
130 final InstanceIdentifier<Node> nodeInstanceId = identifier.firstIdentifierOf(Node.class);
132 return readTrans.read(LogicalDatastoreType.OPERATIONAL, nodeInstanceId).get().isPresent();
134 catch (InterruptedException | ExecutionException e) {
135 LOG.error("Unexpected exception by reading Node ".concat(nodeInstanceId.toString()), e);
144 * Method removes DataObject which is identified by InstanceIdentifier
147 * @param InstanceIdentifier identifier - the whole path to DataObject
148 * @param DataObject remove - DataObject for removing
150 protected abstract void remove(final InstanceIdentifier<? extends DataObject> identifier,
151 final DataObject remove);
154 * Method updates the original DataObject to the update DataObject
155 * in device. Both are identified by same InstanceIdentifier
157 * @param InstanceIdentifier identifier - the whole path to DataObject
158 * @param DataObject original - original DataObject (for update)
159 * @param DataObject update - changed DataObject (contain updates)
161 protected abstract void update(final InstanceIdentifier<? extends DataObject> identifier,
162 final DataObject original, final DataObject update);
165 * Method adds the DataObject which is identified by InstanceIdentifier
168 * @param InstanceIdentifier identifier - the whole path to new DataObject
169 * @param DataObject add - new DataObject
171 protected abstract void add(final InstanceIdentifier<? extends DataObject> identifier,
172 final DataObject add);