2 * Copyright (c) 2014 André Martins 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.l2switch.hosttracker.plugin.internal;
10 import java.util.Collection;
11 import java.util.Iterator;
12 import java.util.List;
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;
28 * This will (try to) submit all writes and deletes in to the MD-SAL database.
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
40 * org.opendaylight.l2switch.hosttracker.plugin.inventory.Host;
42 public class ConcurrentClusterAwareHostHashMap<K, V> implements ConcurrentMap<K, V> {
43 private final OperationProcessor opProcessor;
44 private final String topologyId;
46 private static final Logger LOG = LoggerFactory.getLogger(ConcurrentClusterAwareHostHashMap.class);
49 * The instance identifiers for each host submitted to MD-SAL.
51 private final ConcurrentHashMap<InstanceIdentifier<Node>, K> instanceIDs;
54 * The local Hosts' HashMap.
56 private final ConcurrentHashMap<K, V> hostHashMap;
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<>();
66 * Removes, if exists, the Host with the given
67 * InstanceIdentifier<Node> from this local HashMap. Ideally used for
68 * host data listener events.
71 * the InstanceIdentifier<Node> of the Host to remove.
72 * @return the removed Host if exits, null if it doesn't exist.
74 public synchronized V removeLocally(InstanceIdentifier<Node> iiN) {
75 K hostId = this.instanceIDs.get(iiN);
77 this.instanceIDs.remove(iiN);
78 return this.hostHashMap.remove(hostId);
84 * Removes, if exists, the Host with the given Key (HostId) from this local
85 * HashMap. Ideally used for host data listener events.
88 * the key (HostId) of the Host to remove.
89 * @return the removed Host if exits, null if it doesn't exist.
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)) {
99 return hostHashMap.remove(key);
103 * Puts the given value (Host) only in this local HashMap. Ideally used for
104 * host data listener events.
107 * the value's (Host's) InstanceIdentifier<Node>
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>
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);
121 * Removes the given hosts both locally and on MD-SAL database.
124 * the hosts to remove.
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() {
132 public void applyOperation(ReadWriteTransaction tx) {
133 tx.delete(LogicalDatastoreType.OPERATIONAL, e.getKey());
136 this.hostHashMap.remove(e.getValue());
144 * Forces the local Host with the given HostId to be merged into MD-SAL
148 * the Host's hostId that will be merged into MD-SAL database.
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() {
156 public void applyOperation(ReadWriteTransaction tx) {
157 tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true);
160 putLocally(buildNodeIID, (V) h);
161 this.instanceIDs.put(buildNodeIID, (K) h.getId());
162 LOG.trace("Enqueued for MD-SAL transaction {}", hostNode.getNodeId());
166 * Puts all the given hosts into this local HashMap and into MD-SAL
170 * the hosts to be sent into MD-SAL database.
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() {
178 public void applyOperation(ReadWriteTransaction tx) {
179 tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true);
182 putLocally(buildNodeIID, (V) h);
183 this.instanceIDs.put(buildNodeIID, (K) h.getId());
184 LOG.trace("Putting MD-SAL {}", hostNode.getNodeId());
189 * Puts the given host in the this local HashMap and into MD-SAL database.
192 * the key for the map
194 * the value for the map
195 * @return the old value from the local cache if present, null otherwise.
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() {
203 public void applyOperation(ReadWriteTransaction tx) {
204 tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true);
207 LOG.trace("Putting MD-SAL {}", hostNode.getNodeId());
208 return putLocally(buildNodeIID, host);
212 * Removes the value (Host) with the given hostId from this local HashMap
213 * and MD-SAL database.
216 * the Host's hostId to remove
217 * @return the old value from the local cache if present, null otherwise.
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() {
227 public void applyOperation(ReadWriteTransaction tx) {
228 tx.delete(LogicalDatastoreType.OPERATIONAL, hnIID);
231 this.instanceIDs.remove(hnIID);
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.
241 * the key for the map
243 * the value for the map
244 * @return the old value from the local cache if present, null otherwise.
247 public synchronized V putIfAbsent(K key, V value) {
248 if (!this.hostHashMap.contains(value)) {
249 return this.hostHashMap.put(key, value);
251 return this.hostHashMap.get(key);
256 * Removes the entry for a key only if currently mapped to a given value.
259 * key with which the specified value is associated
261 * value expected to be associated with the specified key
262 * @return <tt>true</tt> if the value was removed
265 public synchronized boolean remove(Object key, Object value) {
266 if (this.hostHashMap.containsKey((K) key) && this.hostHashMap.get((K) key).equals(value)) {
276 * Replaces the entry for a key only if currently mapped to a given value.
279 * key with which the specified value is associated
281 * value expected to be associated with the specified key
283 * value to be associated with the specified key
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)) {
297 * Replaces the entry for a key only if currently mapped to some value.
300 * key with which the specified value is associated
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.)
310 public synchronized V replace(K key, V value) {
311 if (this.hostHashMap.containsKey(key)) {
312 return put(key, value);
319 public synchronized int size() {
320 return this.hostHashMap.size();
324 public synchronized boolean isEmpty() {
325 return this.hostHashMap.isEmpty();
329 public synchronized boolean containsKey(Object key) {
330 return this.hostHashMap.containsKey(key);
334 public synchronized boolean containsValue(Object value) {
335 return this.hostHashMap.contains(value);
339 public synchronized V get(Object key) {
340 return this.hostHashMap.get(key);
344 * Copies all of the mappings from the specified map to this local HashMap
348 * mappings to be stored in this local HashMap and into MD-SAL
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() {
357 public void applyOperation(ReadWriteTransaction tx) {
358 tx.merge(LogicalDatastoreType.OPERATIONAL, buildNodeIID, hostNode, true);
361 putLocally(buildNodeIID, e.getValue());
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.
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() {
376 public void applyOperation(ReadWriteTransaction tx) {
377 tx.delete(LogicalDatastoreType.OPERATIONAL, e.getKey());
381 this.hostHashMap.clear();
385 * Returns the KeySet from this local HashMap.
387 * @return the KeySet from this local HashMap.
390 public synchronized Set<K> keySet() {
391 return this.hostHashMap.keySet();
395 * Returns the Values from this local HashMap.
397 * @return the Values from this local HashMap.
400 public synchronized Collection<V> values() {
401 return this.hostHashMap.values();
405 * Returns the EntrySet from this local HashMap.
407 * @return the EntrySet from this local HashMap.
410 public synchronized Set<Entry<K, V>> entrySet() {
411 return this.hostHashMap.entrySet();