Fix checkstyle reported by odlparent-3.0.0
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / datastore / entityownership / EntityOwnershipListenerSupport.java
1 /*
2  * Copyright (c) 2015 Brocade Communications 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.cluster.datastore.entityownership;
9
10 import akka.actor.ActorContext;
11 import akka.actor.ActorRef;
12 import akka.actor.PoisonPill;
13 import com.google.common.collect.HashMultimap;
14 import com.google.common.collect.ImmutableList;
15 import com.google.common.collect.Multimap;
16 import java.util.Collection;
17 import java.util.IdentityHashMap;
18 import java.util.Map;
19 import java.util.concurrent.locks.ReadWriteLock;
20 import java.util.concurrent.locks.ReentrantReadWriteLock;
21 import java.util.stream.Collectors;
22 import javax.annotation.concurrent.GuardedBy;
23 import javax.annotation.concurrent.ThreadSafe;
24 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
25 import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
26 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
27 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30
31 /**
32  * Manages EntityOwnershipListener registrations and notifications for the EntityOwnershipShard.
33  *
34  * @author Thomas Pantelis
35  */
36 @ThreadSafe
37 class EntityOwnershipListenerSupport extends EntityOwnershipChangePublisher {
38     private static final Logger LOG = LoggerFactory.getLogger(EntityOwnershipListenerSupport.class);
39
40     private final String logId;
41     private final ActorContext actorContext;
42     private final ReadWriteLock listenerLock = new ReentrantReadWriteLock();
43
44     @GuardedBy("listenerLock")
45     private final Map<DOMEntityOwnershipListener, ListenerActorRefEntry> listenerActorMap = new IdentityHashMap<>();
46
47     @GuardedBy("listenerLock")
48     private final Multimap<String, DOMEntityOwnershipListener> entityTypeListenerMap = HashMultimap.create();
49
50     private volatile boolean inJeopardy = false;
51
52     EntityOwnershipListenerSupport(final ActorContext actorContext, final String logId) {
53         this.actorContext = actorContext;
54         this.logId = logId;
55     }
56
57     @Override
58     String getLogId() {
59         return logId;
60     }
61
62     /**
63      * Set the in-jeopardy flag and indicate its previous state.
64      *
65      * @param inJeopardy new value of the in-jeopardy flag
66      * @return Previous value of the flag.
67      */
68     @SuppressWarnings("checkstyle:hiddenField")
69     boolean setInJeopardy(final boolean inJeopardy) {
70         final boolean wasInJeopardy = this.inJeopardy;
71         this.inJeopardy = inJeopardy;
72         return wasInJeopardy;
73     }
74
75     void addEntityOwnershipListener(final String entityType, final DOMEntityOwnershipListener listener) {
76         LOG.debug("{}: Adding EntityOwnershipListener {} for entity type {}", logId, listener, entityType);
77
78         listenerLock.writeLock().lock();
79         try {
80             if (entityTypeListenerMap.put(entityType, listener)) {
81                 ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
82                 if (listenerEntry == null) {
83                     listenerActorMap.put(listener, new ListenerActorRefEntry(listener));
84                 } else {
85                     listenerEntry.referenceCount++;
86                 }
87             }
88         } finally {
89             listenerLock.writeLock().unlock();
90         }
91     }
92
93     void removeEntityOwnershipListener(final String entityType, final DOMEntityOwnershipListener listener) {
94         LOG.debug("{}: Removing EntityOwnershipListener {} for entity type {}", logId, listener, entityType);
95
96         listenerLock.writeLock().lock();
97         try {
98             if (entityTypeListenerMap.remove(entityType, listener)) {
99                 ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
100
101                 LOG.debug("{}: Found {}", logId, listenerEntry);
102
103                 listenerEntry.referenceCount--;
104                 if (listenerEntry.referenceCount <= 0) {
105                     listenerActorMap.remove(listener);
106
107                     if (listenerEntry.actorRef != null) {
108                         LOG.debug("Killing EntityOwnershipListenerActor {}", listenerEntry.actorRef);
109                         listenerEntry.actorRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
110                     }
111                 }
112             }
113         } finally {
114             listenerLock.writeLock().unlock();
115         }
116     }
117
118     @Override
119     void notifyEntityOwnershipListeners(final DOMEntity entity, final boolean wasOwner, final boolean isOwner,
120             final boolean hasOwner) {
121         listenerLock.readLock().lock();
122         try {
123             Collection<DOMEntityOwnershipListener> listeners = entityTypeListenerMap.get(entity.getType());
124             if (!listeners.isEmpty()) {
125                 notifyListeners(entity, wasOwner, isOwner, hasOwner,
126                         listeners.stream().map(listenerActorMap::get).collect(Collectors.toList()));
127             }
128         } finally {
129             listenerLock.readLock().unlock();
130         }
131     }
132
133     void notifyEntityOwnershipListener(final DOMEntity entity, final boolean wasOwner, final boolean isOwner,
134             final boolean hasOwner, final DOMEntityOwnershipListener listener) {
135         listenerLock.readLock().lock();
136         try {
137             notifyListeners(entity, wasOwner, isOwner, hasOwner, ImmutableList.of(listenerActorMap.get(listener)));
138         } finally {
139             listenerLock.readLock().unlock();
140         }
141     }
142
143     @GuardedBy("listenerLock")
144     private void notifyListeners(final DOMEntity entity, final boolean wasOwner, final boolean isOwner,
145             final boolean hasOwner, final Collection<ListenerActorRefEntry> listenerEntries) {
146         DOMEntityOwnershipChange changed = new DOMEntityOwnershipChange(entity,
147                 EntityOwnershipChangeState.from(wasOwner, isOwner, hasOwner), inJeopardy);
148         for (ListenerActorRefEntry entry: listenerEntries) {
149             ActorRef listenerActor = entry.actorFor();
150
151             LOG.debug("{}: Notifying EntityOwnershipListenerActor {} with {}", logId, listenerActor, changed);
152
153             listenerActor.tell(changed, ActorRef.noSender());
154         }
155     }
156
157     private class ListenerActorRefEntry {
158         final DOMEntityOwnershipListener listener;
159
160         @GuardedBy("listenerLock")
161         ActorRef actorRef;
162
163         @GuardedBy("listenerLock")
164         int referenceCount = 1;
165
166         ListenerActorRefEntry(final DOMEntityOwnershipListener listener) {
167             this.listener = listener;
168         }
169
170         ActorRef actorFor() {
171             if (actorRef == null) {
172                 actorRef = actorContext.actorOf(EntityOwnershipListenerActor.props(listener));
173
174                 LOG.debug("{}: Created EntityOwnershipListenerActor {} for listener {}", logId, actorRef, listener);
175             }
176
177             return actorRef;
178         }
179
180         @Override
181         public String toString() {
182             return "ListenerActorRefEntry [actorRef=" + actorRef + ", referenceCount=" + referenceCount + "]";
183         }
184     }
185 }