Bug-5644: Fix checkstyle invocation for l2switch builds
[l2switch.git] / hosttracker / implementation / src / main / java / org / opendaylight / l2switch / hosttracker / plugin / internal / ConcurrentClusterAwareHostHashMap.java
1 /**
2  * Copyright (c) 2014 AndrĂ© Martins 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.l2switch.hosttracker.plugin.internal;
9
10 import java.util.Collection;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Set;
15 import java.util.concurrent.ConcurrentHashMap;
16 import java.util.concurrent.ConcurrentMap;
17 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.l2switch.hosttracker.plugin.inventory.Host;
20 import org.opendaylight.l2switch.hosttracker.plugin.util.Utilities;
21 import org.opendaylight.yang.gen.v1.urn.opendaylight.host.tracker.rev140624.HostId;
22 import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
23 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * This will (try to) submit all writes and deletes in to the MD-SAL database.
29  * The
30  * {@link #removeLocally(org.opendaylight.yangtools.yang.binding.InstanceIdentifier)}
31  * , {@link #removeLocally(java.lang.Object) }
32  * {@link #putLocally(org.opendaylight.yangtools.yang.binding.InstanceIdentifier, java.lang.Object)}
33  * methods should be used when dataChanges are dealt locally and not update to
34  * MD-SAL.
35  *
36  * @param <K>
37  *            Must be a HostId
38  * @param <V>
39  *            Must be
40  *            org.opendaylight.l2switch.hosttracker.plugin.inventory.Host;
41  */
42 public class ConcurrentClusterAwareHostHashMap<K, V> implements ConcurrentMap<K, V> {
43     private final OperationProcessor opProcessor;
44     private final String topologyId;
45
46     private static final Logger LOG = LoggerFactory.getLogger(ConcurrentClusterAwareHostHashMap.class);
47
48     /**
49      * The instance identifiers for each host submitted to MD-SAL.
50      */
51     private final ConcurrentHashMap<InstanceIdentifier<Node>, K> instanceIDs;
52
53     /**
54      * The local Hosts' HashMap.
55      */
56     private final ConcurrentHashMap<K, V> hostHashMap;
57
58     public ConcurrentClusterAwareHostHashMap(OperationProcessor opProcessor, String topologyId) {
59         this.opProcessor = opProcessor;
60         this.topologyId = topologyId;
61         this.hostHashMap = new ConcurrentHashMap<>();
62         this.instanceIDs = new ConcurrentHashMap<>();
63     }
64
65     /**
66      * Removes, if exists, the Host with the given
67      * InstanceIdentifier&lt;Node&gt; from this local HashMap. Ideally used for
68      * host data listener events.
69      *
70      * @param iiN
71      *            the InstanceIdentifier&lt;Node&gt; of the Host to remove.
72      * @return the removed Host if exits, null if it doesn't exist.
73      */
74     public synchronized V removeLocally(InstanceIdentifier<Node> iiN) {
75         K hostId = this.instanceIDs.get(iiN);
76         if (hostId != null) {
77             this.instanceIDs.remove(iiN);
78             return this.hostHashMap.remove(hostId);
79         }
80         return null;
81     }
82
83     /**
84      * Removes, if exists, the Host with the given Key (HostId) from this local
85      * HashMap. Ideally used for host data listener events.
86      *
87      * @param key
88      *            the key (HostId) of the Host to remove.
89      * @return the removed Host if exits, null if it doesn't exist.
90      */
91     public synchronized V removeLocally(K key) {
92         Iterator<Entry<InstanceIdentifier<Node>, K>> iterator = this.instanceIDs.entrySet().iterator();
93         while (iterator.hasNext()) {
94             if (iterator.next().getValue().equals(key)) {
95                 iterator.remove();
96                 break;
97             }
98         }
99         return hostHashMap.remove(key);
100     }
101
102     /**
103      * Puts the given value (Host) only in this local HashMap. Ideally used for
104      * host data listener events.
105      *
106      * @param ii
107      *            the value's (Host's) InstanceIdentifier&lt;Node&gt;
108      * @param value
109      *            the Host to store locally.
110      * @return the previous value associated with <tt>key</tt>, or <tt>null</tt>
111      *         if there was no mapping for <tt>key</tt>
112      */
113     public synchronized V putLocally(InstanceIdentifier<Node> ii, V value) {
114         Host h = ((Host) value);
115         LOG.trace("Putting locally {}", h.getId());
116         this.instanceIDs.put(ii, (K) h.getId());
117         return this.hostHashMap.put((K) h.getId(), value);
118     }
119
120     /**
121      * Removes the given hosts both locally and on MD-SAL database.
122      *
123      * @param hosts
124      *            the hosts to remove.
125      */
126     public synchronized void removeAll(List<Host> hosts) {
127         for (final Map.Entry<InstanceIdentifier<Node>, K> e : this.instanceIDs.entrySet()) {
128             for (Host h : hosts) {
129                 if (e.getValue().equals(h.getId())) {
130                     this.opProcessor.enqueueOperation(new HostTrackerOperation() {
131                         @Override
132                         public void applyOperation(ReadWriteTransaction tx) {
133                             tx.delete(LogicalDatastoreType.OPERATIONAL, e.getKey());
134                         }
135                     });
136                     this.hostHashMap.remove(e.getValue());
137                     break;
138                 }
139             }
140         }
141     }
142
143     /**
144      * Forces the local Host with the given HostId to be merged into MD-SAL
145      * database.
146      *
147      * @param hostid
148      *            the Host's hostId that will be merged into MD-SAL database.
149      */
150     public synchronized void submit(HostId hostid) {
151         Host h = (Host) this.hostHashMap.get(hostid);
152         final Node hostNode = h.getHostNode();
153         final InstanceIdentifier<Node> buildNodeIID = Utilities.buildNodeIID(hostNode.getKey(), topologyId);
154         this.opProcessor.enqueueOperation(new HostTrackerOperation() {
155             @Override
156             public void applyOperation(ReadWriteTransaction tx) {
157                 tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true);
158             }
159         });
160         putLocally(buildNodeIID, (V) h);
161         this.instanceIDs.put(buildNodeIID, (K) h.getId());
162         LOG.trace("Enqueued for MD-SAL transaction {}", hostNode.getNodeId());
163     }
164
165     /**
166      * Puts all the given hosts into this local HashMap and into MD-SAL
167      * database.
168      *
169      * @param hosts
170      *            the hosts to be sent into MD-SAL database.
171      */
172     public synchronized void putAll(List<Host> hosts) {
173         for (Host h : hosts) {
174             final Node hostNode = h.getHostNode();
175             final InstanceIdentifier<Node> buildNodeIID = Utilities.buildNodeIID(hostNode.getKey(), topologyId);
176             this.opProcessor.enqueueOperation(new HostTrackerOperation() {
177                 @Override
178                 public void applyOperation(ReadWriteTransaction tx) {
179                     tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true);
180                 }
181             });
182             putLocally(buildNodeIID, (V) h);
183             this.instanceIDs.put(buildNodeIID, (K) h.getId());
184             LOG.trace("Putting MD-SAL {}", hostNode.getNodeId());
185         }
186     }
187
188     /**
189      * Puts the given host in the this local HashMap and into MD-SAL database.
190      *
191      * @param hostId
192      *            the key for the map
193      * @param host
194      *            the value for the map
195      * @return the old value from the local cache if present, null otherwise.
196      */
197     @Override
198     public synchronized V put(K hostId, V host) {
199         final Node hostNode = ((Host) host).getHostNode();
200         final InstanceIdentifier<Node> buildNodeIID = Utilities.buildNodeIID(hostNode.getKey(), topologyId);
201         this.opProcessor.enqueueOperation(new HostTrackerOperation() {
202             @Override
203             public void applyOperation(ReadWriteTransaction tx) {
204                 tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true);
205             }
206         });
207         LOG.trace("Putting MD-SAL {}", hostNode.getNodeId());
208         return putLocally(buildNodeIID, host);
209     }
210
211     /**
212      * Removes the value (Host) with the given hostId from this local HashMap
213      * and MD-SAL database.
214      *
215      * @param hostId
216      *            the Host's hostId to remove
217      * @return the old value from the local cache if present, null otherwise.
218      */
219     @Override
220     public synchronized V remove(Object hostId) {
221         V removedValue = this.hostHashMap.remove(hostId);
222         if (removedValue != null) {
223             Node hostNode = ((Host) removedValue).getHostNode();
224             final InstanceIdentifier<Node> hnIID = Utilities.buildNodeIID(hostNode.getKey(), topologyId);
225             this.opProcessor.enqueueOperation(new HostTrackerOperation() {
226                 @Override
227                 public void applyOperation(ReadWriteTransaction tx) {
228                     tx.delete(LogicalDatastoreType.OPERATIONAL, hnIID);
229                 }
230             });
231             this.instanceIDs.remove(hnIID);
232         }
233         return removedValue;
234     }
235
236     /**
237      * If it's absent from the this local HashMap, puts the given host in the
238      * this local HashMap and into MD-SAL database.
239      *
240      * @param key
241      *            the key for the map
242      * @param value
243      *            the value for the map
244      * @return the old value from the local cache if present, null otherwise.
245      */
246     @Override
247     public synchronized V putIfAbsent(K key, V value) {
248         if (!this.hostHashMap.contains(value)) {
249             return this.hostHashMap.put(key, value);
250         } else {
251             return this.hostHashMap.get(key);
252         }
253     }
254
255     /**
256      * Removes the entry for a key only if currently mapped to a given value.
257      *
258      * @param key
259      *            key with which the specified value is associated
260      * @param value
261      *            value expected to be associated with the specified key
262      * @return <tt>true</tt> if the value was removed
263      */
264     @Override
265     public synchronized boolean remove(Object key, Object value) {
266         if (this.hostHashMap.containsKey((K) key) && this.hostHashMap.get((K) key).equals(value)) {
267             remove((K) key);
268             return true;
269         } else {
270             return false;
271         }
272     }
273
274     /**
275      *
276      * Replaces the entry for a key only if currently mapped to a given value.
277      *
278      * @param key
279      *            key with which the specified value is associated
280      * @param oldValue
281      *            value expected to be associated with the specified key
282      * @param newValue
283      *            value to be associated with the specified key
284      */
285     @Override
286     public synchronized boolean replace(K key, V oldValue, V newValue) {
287         if (this.hostHashMap.containsKey((K) key) && this.hostHashMap.get((K) key).equals(oldValue)) {
288             put(key, newValue);
289             return true;
290         } else {
291             return false;
292         }
293     }
294
295     /**
296      *
297      * Replaces the entry for a key only if currently mapped to some value.
298      *
299      * @param key
300      *            key with which the specified value is associated
301      * @param value
302      *            value to be associated with the specified key
303      * @return the previous value associated with the specified key, or
304      *         <tt>null</tt> if there was no mapping for the key. (A
305      *         <tt>null</tt> return can also indicate that the map previously
306      *         associated <tt>null</tt> with the key, if the implementation
307      *         supports null values.)
308      */
309     @Override
310     public synchronized V replace(K key, V value) {
311         if (this.hostHashMap.containsKey(key)) {
312             return put(key, value);
313         } else {
314             return null;
315         }
316     }
317
318     @Override
319     public synchronized int size() {
320         return this.hostHashMap.size();
321     }
322
323     @Override
324     public synchronized boolean isEmpty() {
325         return this.hostHashMap.isEmpty();
326     }
327
328     @Override
329     public synchronized boolean containsKey(Object key) {
330         return this.hostHashMap.containsKey(key);
331     }
332
333     @Override
334     public synchronized boolean containsValue(Object value) {
335         return this.hostHashMap.contains(value);
336     }
337
338     @Override
339     public synchronized V get(Object key) {
340         return this.hostHashMap.get(key);
341     }
342
343     /**
344      * Copies all of the mappings from the specified map to this local HashMap
345      * and into MD-SAL.
346      *
347      * @param m
348      *            mappings to be stored in this local HashMap and into MD-SAL
349      */
350     @Override
351     public synchronized void putAll(Map<? extends K, ? extends V> m) {
352         for (Map.Entry<? extends K, ? extends V> e : m.entrySet()) {
353             final Node hostNode = ((Host) e.getValue()).getHostNode();
354             final InstanceIdentifier<Node> buildNodeIID = Utilities.buildNodeIID(hostNode.getKey(), topologyId);
355             this.opProcessor.enqueueOperation(new HostTrackerOperation() {
356                 @Override
357                 public void applyOperation(ReadWriteTransaction tx) {
358                     tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true);
359                 }
360             });
361             putLocally(buildNodeIID, e.getValue());
362         }
363     }
364
365     /**
366      *
367      * Removes all of the mappings from this local HashMap and from MD-SAL. The
368      * local HashMap will be empty after this call returns.
369      *
370      */
371     @Override
372     public synchronized void clear() {
373         for (final Map.Entry<? extends InstanceIdentifier<Node>, ? extends K> e : this.instanceIDs.entrySet()) {
374             this.opProcessor.enqueueOperation(new HostTrackerOperation() {
375                 @Override
376                 public void applyOperation(ReadWriteTransaction tx) {
377                     tx.delete(LogicalDatastoreType.OPERATIONAL, e.getKey());
378                 }
379             });
380         }
381         this.hostHashMap.clear();
382     }
383
384     /**
385      * Returns the KeySet from this local HashMap.
386      *
387      * @return the KeySet from this local HashMap.
388      */
389     @Override
390     public synchronized Set<K> keySet() {
391         return this.hostHashMap.keySet();
392     }
393
394     /**
395      * Returns the Values from this local HashMap.
396      *
397      * @return the Values from this local HashMap.
398      */
399     @Override
400     public synchronized Collection<V> values() {
401         return this.hostHashMap.values();
402     }
403
404     /**
405      * Returns the EntrySet from this local HashMap.
406      *
407      * @return the EntrySet from this local HashMap.
408      */
409     @Override
410     public synchronized Set<Entry<K, V>> entrySet() {
411         return this.hostHashMap.entrySet();
412     }
413
414 }