Bug 4105: Remove EntityOwnershipCandidate
[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.Multimap;
15 import java.util.Arrays;
16 import java.util.Collection;
17 import java.util.HashSet;
18 import java.util.IdentityHashMap;
19 import java.util.Map;
20 import java.util.Set;
21 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
22 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
23 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * Manages EntityOwnershipListener registrations and notifications for the EntityOwnershipShard.
29  *
30  * @author Thomas Pantelis
31  */
32 class EntityOwnershipListenerSupport {
33     private static final Logger LOG = LoggerFactory.getLogger(EntityOwnershipListenerSupport.class);
34
35     private final String logId;
36     private final ActorContext actorContext;
37     private final Map<EntityOwnershipListener, ListenerActorRefEntry> listenerActorMap = new IdentityHashMap<>();
38     private final Set<Entity> entitiesWithCandidateSet = new HashSet<>();
39     private final Multimap<String, EntityOwnershipListener> entityTypeListenerMap = HashMultimap.create();
40
41     EntityOwnershipListenerSupport(ActorContext actorContext, String logId) {
42         this.actorContext = actorContext;
43         this.logId = logId;
44     }
45
46     String getLogId() {
47         return logId;
48     }
49
50     boolean hasCandidateForEntity(Entity entity) {
51         return entitiesWithCandidateSet.contains(entity);
52     }
53
54     void setHasCandidateForEntity(Entity entity) {
55         entitiesWithCandidateSet.add(entity);
56     }
57
58     void unsetHasCandidateForEntity(Entity entity) {
59         entitiesWithCandidateSet.remove(entity);
60     }
61
62     void addEntityOwnershipListener(String entityType, EntityOwnershipListener listener) {
63         LOG.debug("{}: Adding EntityOwnershipListener {} for entity type {}", logId, listener, entityType);
64
65         addListener(listener, entityType, entityTypeListenerMap);
66     }
67
68     void removeEntityOwnershipListener(String entityType, EntityOwnershipListener listener) {
69         LOG.debug("{}: Removing EntityOwnershipListener {} for entity type {}", logId, listener, entityType);
70
71         removeListener(listener, entityType, entityTypeListenerMap);
72     }
73
74     void notifyEntityOwnershipListeners(Entity entity, boolean wasOwner, boolean isOwner, boolean hasOwner) {
75         notifyListeners(entity, entity.getType(), wasOwner, isOwner, hasOwner, entityTypeListenerMap);
76     }
77
78     void notifyEntityOwnershipListener(Entity entity, boolean wasOwner, boolean isOwner, boolean hasOwner,
79             EntityOwnershipListener listener) {
80         notifyListeners(entity, wasOwner, isOwner, hasOwner, Arrays.asList(listener));
81     }
82
83     private <T> void notifyListeners(Entity entity, T mapKey, boolean wasOwner, boolean isOwner, boolean hasOwner,
84             Multimap<T, EntityOwnershipListener> listenerMap) {
85         Collection<EntityOwnershipListener> listeners = listenerMap.get(mapKey);
86         if(!listeners.isEmpty()) {
87             notifyListeners(entity, wasOwner, isOwner, hasOwner, listeners);
88         }
89     }
90
91     private void notifyListeners(Entity entity, boolean wasOwner, boolean isOwner, boolean hasOwner,
92             Collection<EntityOwnershipListener> listeners) {
93         EntityOwnershipChange changed = new EntityOwnershipChange(entity, wasOwner, isOwner, hasOwner);
94         for(EntityOwnershipListener listener: listeners) {
95             ActorRef listenerActor = listenerActorFor(listener);
96
97             LOG.debug("{}: Notifying EntityOwnershipListenerActor {} with {}", logId, listenerActor, changed);
98
99             listenerActor.tell(changed, ActorRef.noSender());
100         }
101     }
102
103     private <T> void addListener(EntityOwnershipListener listener, T mapKey,
104             Multimap<T, EntityOwnershipListener> toListenerMap) {
105         if(toListenerMap.put(mapKey, listener)) {
106             ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
107             if(listenerEntry == null) {
108                 listenerActorMap.put(listener, new ListenerActorRefEntry());
109             } else {
110                 listenerEntry.referenceCount++;
111             }
112         }
113     }
114
115     private <T> void removeListener(EntityOwnershipListener listener, T mapKey,
116             Multimap<T, EntityOwnershipListener> fromListenerMap) {
117         if(fromListenerMap.remove(mapKey, listener)) {
118             ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
119
120             LOG.debug("{}: Found {}", logId, listenerEntry);
121
122             listenerEntry.referenceCount--;
123             if(listenerEntry.referenceCount <= 0) {
124                 listenerActorMap.remove(listener);
125
126                 if(listenerEntry.actorRef != null) {
127                     LOG.debug("Killing EntityOwnershipListenerActor {}", listenerEntry.actorRef);
128                     listenerEntry.actorRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
129                 }
130             }
131         }
132     }
133
134     private ActorRef listenerActorFor(EntityOwnershipListener listener) {
135         return listenerActorMap.get(listener).actorFor(listener);
136     }
137
138     private class ListenerActorRefEntry {
139         ActorRef actorRef;
140         int referenceCount = 1;
141
142         ActorRef actorFor(EntityOwnershipListener listener) {
143             if(actorRef == null) {
144                 actorRef = actorContext.actorOf(EntityOwnershipListenerActor.props(listener));
145
146                 LOG.debug("{}: Created EntityOwnershipListenerActor {} for listener {}", logId, actorRef, listener);
147             }
148
149             return actorRef;
150         }
151
152         @Override
153         public String toString() {
154             return "ListenerActorRefEntry [actorRef=" + actorRef + ", referenceCount=" + referenceCount + "]";
155         }
156     }
157 }