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.Collection;
16 import java.util.Collections;
17 import java.util.HashSet;
18 import java.util.IdentityHashMap;
21 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
22 import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
23 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
24 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
29 * Manages EntityOwnershipListener registrations and notifications for the EntityOwnershipShard.
31 * @author Thomas Pantelis
33 class EntityOwnershipListenerSupport {
34 private static final Logger LOG = LoggerFactory.getLogger(EntityOwnershipListenerSupport.class);
36 private final String logId;
37 private final ActorContext actorContext;
38 private final Map<DOMEntityOwnershipListener, ListenerActorRefEntry> listenerActorMap = new IdentityHashMap<>();
39 private final Set<DOMEntity> entitiesWithCandidateSet = new HashSet<>();
40 private final Multimap<String, DOMEntityOwnershipListener> entityTypeListenerMap = HashMultimap.create();
41 private volatile boolean inJeopardy = false;
43 EntityOwnershipListenerSupport(ActorContext actorContext, String logId) {
44 this.actorContext = actorContext;
53 * Set the in-jeopardy flag and indicate its previous state.
55 * @param inJeopardy new value of the in-jeopardy flag
56 * @return Previous value of the flag.
58 boolean setInJeopardy(final boolean inJeopardy) {
59 final boolean wasInJeopardy = this.inJeopardy;
60 this.inJeopardy = inJeopardy;
64 boolean hasCandidateForEntity(DOMEntity entity) {
65 return entitiesWithCandidateSet.contains(entity);
68 void setHasCandidateForEntity(DOMEntity entity) {
69 entitiesWithCandidateSet.add(entity);
72 void unsetHasCandidateForEntity(DOMEntity entity) {
73 entitiesWithCandidateSet.remove(entity);
76 void addEntityOwnershipListener(String entityType, DOMEntityOwnershipListener listener) {
77 LOG.debug("{}: Adding EntityOwnershipListener {} for entity type {}", logId, listener, entityType);
79 addListener(listener, entityType);
82 void removeEntityOwnershipListener(String entityType, DOMEntityOwnershipListener listener) {
83 LOG.debug("{}: Removing EntityOwnershipListener {} for entity type {}", logId, listener, entityType);
85 removeListener(listener, entityType);
88 void notifyEntityOwnershipListeners(DOMEntity entity, boolean wasOwner, boolean isOwner, boolean hasOwner) {
89 notifyListeners(entity, entity.getType(), wasOwner, isOwner, hasOwner);
92 void notifyEntityOwnershipListener(DOMEntity entity, boolean wasOwner, boolean isOwner, boolean hasOwner,
93 DOMEntityOwnershipListener listener) {
94 notifyListeners(entity, wasOwner, isOwner, hasOwner, Collections.singleton(listener));
97 private void notifyListeners(DOMEntity entity, String mapKey, boolean wasOwner, boolean isOwner, boolean hasOwner) {
98 Collection<DOMEntityOwnershipListener> listeners = entityTypeListenerMap.get(mapKey);
99 if (!listeners.isEmpty()) {
100 notifyListeners(entity, wasOwner, isOwner, hasOwner, listeners);
104 private void notifyListeners(DOMEntity entity, boolean wasOwner, boolean isOwner, boolean hasOwner,
105 Collection<DOMEntityOwnershipListener> listeners) {
106 DOMEntityOwnershipChange changed = new DOMEntityOwnershipChange(entity,
107 EntityOwnershipChangeState.from(wasOwner, isOwner, hasOwner), inJeopardy);
108 for (DOMEntityOwnershipListener listener: listeners) {
109 ActorRef listenerActor = listenerActorFor(listener);
111 LOG.debug("{}: Notifying EntityOwnershipListenerActor {} with {}", logId, listenerActor, changed);
113 listenerActor.tell(changed, ActorRef.noSender());
117 private void addListener(DOMEntityOwnershipListener listener, String mapKey) {
118 if (entityTypeListenerMap.put(mapKey, listener)) {
119 ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
120 if (listenerEntry == null) {
121 listenerActorMap.put(listener, new ListenerActorRefEntry());
123 listenerEntry.referenceCount++;
128 private void removeListener(DOMEntityOwnershipListener listener, String mapKey) {
129 if (entityTypeListenerMap.remove(mapKey, listener)) {
130 ListenerActorRefEntry listenerEntry = listenerActorMap.get(listener);
132 LOG.debug("{}: Found {}", logId, listenerEntry);
134 listenerEntry.referenceCount--;
135 if (listenerEntry.referenceCount <= 0) {
136 listenerActorMap.remove(listener);
138 if (listenerEntry.actorRef != null) {
139 LOG.debug("Killing EntityOwnershipListenerActor {}", listenerEntry.actorRef);
140 listenerEntry.actorRef.tell(PoisonPill.getInstance(), ActorRef.noSender());
146 private ActorRef listenerActorFor(DOMEntityOwnershipListener listener) {
147 return listenerActorMap.get(listener).actorFor(listener);
150 private class ListenerActorRefEntry {
152 int referenceCount = 1;
154 ActorRef actorFor(DOMEntityOwnershipListener listener) {
155 if (actorRef == null) {
156 actorRef = actorContext.actorOf(EntityOwnershipListenerActor.props(listener));
158 LOG.debug("{}: Created EntityOwnershipListenerActor {} for listener {}", logId, actorRef, listener);
165 public String toString() {
166 return "ListenerActorRefEntry [actorRef=" + actorRef + ", referenceCount=" + referenceCount + "]";