2 * Copyright (c) 2015 Brocade Communications Systems, Inc. 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.controller.cluster.datastore.entityownership;
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.IdentityHashMap;
19 import org.opendaylight.controller.md.sal.common.api.clustering.Entity;
20 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipCandidate;
21 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipChange;
22 import org.opendaylight.controller.md.sal.common.api.clustering.EntityOwnershipListener;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
27 * Manages EntityOwnershipListener registrations and notifications for the EntityOwnershipShard.
29 * @author Thomas Pantelis
31 class EntityOwnershipListenerSupport {
32 private static final Logger LOG = LoggerFactory.getLogger(EntityOwnershipListenerSupport.class);
34 private final String logId;
35 private final ActorContext actorContext;
36 private final Map<EntityOwnershipListener, ListenerActorRefEntry> listenerActorMap = new IdentityHashMap<>();
37 private final Multimap<Entity, EntityOwnershipListener> entityListenerMap = HashMultimap.create();
38 private final Multimap<String, EntityOwnershipListener> entityTypeListenerMap = HashMultimap.create();
40 EntityOwnershipListenerSupport(ActorContext actorContext, String logId) {
41 this.actorContext = actorContext;
49 boolean hasCandidateForEntity(Entity entity) {
50 for(EntityOwnershipListener listener: entityListenerMap.get(entity)) {
51 if(listener instanceof EntityOwnershipCandidate) {
59 void addEntityOwnershipListener(Entity entity, EntityOwnershipListener listener) {
60 LOG.debug("{}: Adding EntityOwnershipListener {} for {}", logId, listener, entity);
62 addListener(listener, entity, entityListenerMap);
65 void addEntityOwnershipListener(String entityType, EntityOwnershipListener listener) {
66 LOG.debug("{}: Adding EntityOwnershipListener {} for entity type {}", logId, listener, entityType);
68 addListener(listener, entityType, entityTypeListenerMap);
71 void removeEntityOwnershipListener(Entity entity, EntityOwnershipListener listener) {
72 LOG.debug("{}: Removing EntityOwnershipListener {} for {}", logId, listener, entity);
74 removeListener(listener, entity, entityListenerMap);
77 void removeEntityOwnershipListener(String entityType, EntityOwnershipListener listener) {
78 LOG.debug("{}: Removing EntityOwnershipListener {} for entity type {}", logId, listener, entityType);
80 removeListener(listener, entityType, entityTypeListenerMap);
83 void notifyEntityOwnershipListeners(Entity entity, boolean wasOwner, boolean isOwner, boolean hasOwner) {
84 notifyListeners(entity, entity, wasOwner, isOwner, hasOwner, entityListenerMap);
85 notifyListeners(entity, entity.getType(), wasOwner, isOwner, hasOwner, entityTypeListenerMap);
88 void notifyEntityOwnershipListener(Entity entity, boolean wasOwner, boolean isOwner, boolean hasOwner,
89 EntityOwnershipListener listener) {
90 notifyListeners(entity, wasOwner, isOwner, hasOwner, Arrays.asList(listener));
93 private <T> void notifyListeners(Entity entity, T mapKey, boolean wasOwner, boolean isOwner, boolean hasOwner,
94 Multimap<T, EntityOwnershipListener> listenerMap) {
95 Collection<EntityOwnershipListener> listeners = listenerMap.get(mapKey);
96 if(!listeners.isEmpty()) {
97 notifyListeners(entity, wasOwner, isOwner, hasOwner, listeners);
101 private void notifyListeners(Entity entity, boolean wasOwner, boolean isOwner, boolean hasOwner,
102 Collection<EntityOwnershipListener> listeners) {
103 EntityOwnershipChange changed = new EntityOwnershipChange(entity, wasOwner, isOwner, hasOwner);
104 for(EntityOwnershipListener listener: listeners) {
105 ActorRef listenerActor = listenerActorFor(listener);
107 LOG.debug("{}: Notifying EntityOwnershipListenerActor {} with {}", logId, listenerActor, changed);
109 listenerActor.tell(changed, ActorRef.noSender());
113 private <T> void addListener(EntityOwnershipListener listener, T mapKey,
114 Multimap<T, EntityOwnershipListener> toListenerMap) {
115 if(toListenerMap.put(mapKey, listener)) {
116 ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
117 if(listenerEntry == null) {
118 listenerActorMap.put(listener, new ListenerActorRefEntry());
120 listenerEntry.referenceCount++;
125 private <T> void removeListener(EntityOwnershipListener listener, T mapKey,
126 Multimap<T, EntityOwnershipListener> fromListenerMap) {
127 if(fromListenerMap.remove(mapKey, listener)) {
128 ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
130 LOG.debug("{}: Found {}", logId, listenerEntry);
132 listenerEntry.referenceCount--;
133 if(listenerEntry.referenceCount <= 0) {
134 listenerActorMap.remove(listener);
136 if(listenerEntry.actorRef != null) {
137 LOG.debug("Killing EntityOwnershipListenerActor {}", listenerEntry.actorRef);
138 listenerEntry.actorRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
144 private ActorRef listenerActorFor(EntityOwnershipListener listener) {
145 return listenerActorMap.get(listener).actorFor(listener);
148 private class ListenerActorRefEntry {
150 int referenceCount = 1;
152 ActorRef actorFor(EntityOwnershipListener listener) {
153 if(actorRef == null) {
154 actorRef = actorContext.actorOf(EntityOwnershipListenerActor.props(listener));
156 LOG.debug("{}: Created EntityOwnershipListenerActor {} for listener {}", logId, actorRef, listener);
163 public String toString() {
164 return "ListenerActorRefEntry [actorRef=" + actorRef + ", referenceCount=" + referenceCount + "]";