Merge "Custom mailbox that is bounded and instrumented."
[controller.git] / opendaylight / md-sal / forwardingrules-manager / src / main / java / org / opendaylight / controller / frm / AbstractChangeListener.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 package org.opendaylight.controller.frm;
9
10 import java.util.HashSet;
11 import java.util.Map;
12 import java.util.Map.Entry;
13 import java.util.Set;
14 import java.util.concurrent.ExecutionException;
15 import java.util.concurrent.atomic.AtomicLong;
16
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;
26
27 /**
28  * AbstractChangeListner implemented basic {@link AsyncDataChangeEvent} processing for
29  * flow node subDataObject (flows, groups and meters).
30  *
31  * @author <a href="mailto:vdemcak@cisco.com">Vaclav Demcak</a>
32  *
33  */
34 public abstract class AbstractChangeListener implements DataChangeListener {
35
36     private final static Logger LOG = LoggerFactory.getLogger(AbstractChangeListener.class);
37
38     private final AtomicLong txNum = new AtomicLong();
39     private String transactionId;
40
41     @Override
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);
63             }
64         }
65
66         for (final Entry<InstanceIdentifier<?>, DataObject> updatedEntrie : updatedEntries) {
67             Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
68                     changeEvent.getOriginalData();
69
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);
75             }
76         }
77
78         for (final InstanceIdentifier<?> instanceId : removeEntriesInstanceIdentifiers) {
79             Map<InstanceIdentifier<? extends DataObject>, DataObject> origConfigData =
80                     changeEvent.getOriginalData();
81
82             final DataObject removeValue = origConfigData.get(instanceId);
83             if (preconditionForChange(instanceId, removeValue, null)) {
84                 this.remove(instanceId, removeValue);
85             }
86         }
87     }
88
89     /**
90      * Method returns generated transaction ID, which is unique for
91      * every transaction. ID is composite from prefix ("DOM") and unique number.
92      *
93      * @return String transactionID
94      */
95     public String getTransactionId() {
96         return this.transactionId;
97     }
98
99     private Object newTransactionIdentifier() {
100         return "DOM-" + txNum.getAndIncrement();
101     }
102
103     /**
104      * Method check all local preconditions for apply relevant changes.
105      *
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)
111      *
112      * @return boolean - applicable
113      */
114     protected abstract boolean preconditionForChange(
115             final InstanceIdentifier<? extends DataObject> identifier,
116             final DataObject original, final DataObject update);
117
118     /**
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.
122      *
123      * @param InstanceIdentifier identifier - could be whole path to DataObject,
124      *            but parent Node.class InstanceIdentifier is used for a check only
125      *
126      * @return boolean - is the Node available in DataStore/OPERATIONAL (is connected)
127      */
128     protected boolean isNodeAvailable(final InstanceIdentifier<? extends DataObject> identifier,
129             final ReadOnlyTransaction readTrans) {
130         final InstanceIdentifier<Node> nodeInstanceId = identifier.firstIdentifierOf(Node.class);
131         try {
132             return readTrans.read(LogicalDatastoreType.OPERATIONAL, nodeInstanceId).get().isPresent();
133         }
134         catch (InterruptedException | ExecutionException e) {
135             LOG.error("Unexpected exception by reading Node ".concat(nodeInstanceId.toString()), e);
136             return false;
137         }
138         finally {
139             readTrans.close();
140         }
141     }
142
143     /**
144      * Method removes DataObject which is identified by InstanceIdentifier
145      * from device.
146      *
147      * @param InstanceIdentifier identifier - the whole path to DataObject
148      * @param DataObject remove - DataObject for removing
149      */
150     protected abstract void remove(final InstanceIdentifier<? extends DataObject> identifier,
151             final DataObject remove);
152
153     /**
154      * Method updates the original DataObject to the update DataObject
155      * in device. Both are identified by same InstanceIdentifier
156      *
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)
160      */
161     protected abstract void update(final InstanceIdentifier<? extends DataObject> identifier,
162             final DataObject original, final DataObject update);
163
164     /**
165      * Method adds the DataObject which is identified by InstanceIdentifier
166      * to device.
167      *
168      * @param InstanceIdentifier identifier - the whole path to new DataObject
169      * @param DataObject add - new DataObject
170      */
171     protected abstract void add(final InstanceIdentifier<? extends DataObject> identifier,
172             final DataObject add);
173 }