Bug 4105: Add EntityOwnershipListenerActor and support
[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.Collection;
16 import java.util.IdentityHashMap;
17 import java.util.Map;
18 import org.opendaylight.controller.cluster.datastore.entityownership.messages.EntityOwnershipChanged;
19 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
20 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
21 import org.slf4j.Logger;
22 import org.slf4j.LoggerFactory;
23
24 /**
25  * Manages EntityOwnershipListener registrations and notifications for the EntityOwnershipShard.
26  *
27  * @author Thomas Pantelis
28  */
29 class EntityOwnershipListenerSupport {
30     private static final Logger LOG = LoggerFactory.getLogger(EntityOwnershipListenerSupport.class);
31
32     private final ActorContext actorContext;
33     private final Map<EntityOwnershipListener, ListenerActorRefEntry> listenerActorMap = new IdentityHashMap<>();
34     private final Multimap<Entity, EntityOwnershipListener> entityListenerMap = HashMultimap.create();
35
36     EntityOwnershipListenerSupport(ActorContext actorContext) {
37         this.actorContext = actorContext;
38     }
39
40     void addEntityOwnershipListener(Entity entity, EntityOwnershipListener listener) {
41         LOG.debug("Adding EntityOwnershipListener {} for {}", listener, entity);
42
43         if(entityListenerMap.put(entity, listener)) {
44             ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
45             if(listenerEntry == null) {
46                 listenerActorMap.put(listener, new ListenerActorRefEntry());
47             } else {
48                 listenerEntry.referenceCount++;
49             }
50         }
51     }
52
53     void removeEntityOwnershipListener(Entity entity, EntityOwnershipListener listener) {
54         LOG.debug("Removing EntityOwnershipListener {} for {}", listener, entity);
55
56         if(entityListenerMap.remove(entity, listener)) {
57             ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
58
59             LOG.debug("Found {}", listenerEntry);
60
61             listenerEntry.referenceCount--;
62             if(listenerEntry.referenceCount <= 0) {
63                 listenerActorMap.remove(listener);
64
65                 if(listenerEntry.actorRef != null) {
66                     LOG.debug("Killing EntityOwnershipListenerActor {}", listenerEntry.actorRef);
67                     listenerEntry.actorRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
68                 }
69             }
70         }
71     }
72
73     void notifyEntityOwnershipListeners(Entity entity, boolean wasOwner, boolean isOwner) {
74         Collection<EntityOwnershipListener> listeners = entityListenerMap.get(entity);
75         if(listeners.isEmpty()) {
76             return;
77         }
78
79         EntityOwnershipChanged changed = new EntityOwnershipChanged(entity, wasOwner, isOwner);
80         for(EntityOwnershipListener listener: listeners) {
81             ActorRef listenerActor = listenerActorFor(listener);
82
83             LOG.debug("Notifying EntityOwnershipListenerActor {} with {}", listenerActor,changed);
84
85             listenerActor.tell(changed, ActorRef.noSender());
86         }
87     }
88
89     private ActorRef listenerActorFor(EntityOwnershipListener listener) {
90         return listenerActorMap.get(listener).actorFor(listener);
91     }
92
93     private class ListenerActorRefEntry {
94         ActorRef actorRef;
95         int referenceCount = 1;
96
97         ActorRef actorFor(EntityOwnershipListener listener) {
98             if(actorRef == null) {
99                 actorRef = actorContext.actorOf(EntityOwnershipListenerActor.props(listener));
100
101                 LOG.debug("Created EntityOwnershipListenerActor {} for listener {}", actorRef, listener);
102             }
103
104             return actorRef;
105         }
106
107         @Override
108         public String toString() {
109             return "ListenerActorRefEntry [actorRef=" + actorRef + ", referenceCount=" + referenceCount + "]";
110         }
111     }
112 }