2 * Copyright (c) 2017 Cisco 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.mdsal.eos.dom.simple;
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState.LOCAL_OWNERSHIP_GRANTED;
12 import static org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState.LOCAL_OWNERSHIP_LOST_NO_OWNER;
14 import com.google.common.annotations.VisibleForTesting;
15 import com.google.common.base.MoreObjects;
16 import com.google.common.base.MoreObjects.ToStringHelper;
17 import com.google.common.collect.ArrayListMultimap;
18 import com.google.common.collect.HashBasedTable;
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.Multimap;
21 import com.google.common.collect.Table;
22 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
23 import java.util.Collection;
24 import java.util.Optional;
25 import java.util.UUID;
26 import org.checkerframework.checker.lock.qual.GuardedBy;
27 import org.kohsuke.MetaInfServices;
28 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
29 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
30 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipState;
31 import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
32 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipCandidateRegistration;
33 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
34 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
35 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListenerRegistration;
36 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
37 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
38 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
43 * Simple {@link DOMEntityOwnershipService} operating as an isolated island. It has no awareness of the world outside
46 * @author Robert Varga
49 public final class SimpleDOMEntityOwnershipService implements DOMEntityOwnershipService {
50 private static final Logger LOG = LoggerFactory.getLogger(SimpleDOMEntityOwnershipService.class);
52 @GuardedBy("entities")
53 private final Table<String, YangInstanceIdentifier, DOMEntity> entities = HashBasedTable.create();
55 @GuardedBy("listeners")
56 private final Multimap<String, DOMEntityOwnershipListener> listeners = ArrayListMultimap.create(0, 1);
58 private final UUID uuid;
61 SimpleDOMEntityOwnershipService(final UUID uuid) {
62 this.uuid = requireNonNull(uuid);
65 public SimpleDOMEntityOwnershipService() {
66 this(UUID.randomUUID());
70 public DOMEntityOwnershipCandidateRegistration registerCandidate(final DOMEntity entity)
71 throws CandidateAlreadyRegisteredException {
72 synchronized (entities) {
73 final DOMEntity prev = entities.get(entity.getType(), entity.getIdentifier());
75 throw new CandidateAlreadyRegisteredException(prev);
78 entities.put(entity.getType(), entity.getIdentifier(), entity);
79 LOG.debug("{}: registered candidate {}", uuid, entity);
82 notifyListeners(entity, LOCAL_OWNERSHIP_GRANTED);
83 return new EntityRegistration(entity);
87 public DOMEntityOwnershipListenerRegistration registerListener(final String entityType,
88 final DOMEntityOwnershipListener listener) {
90 final Collection<DOMEntity> owned;
91 synchronized (entities) {
92 owned = ImmutableList.copyOf(entities.row(entityType).values());
93 LOG.trace("{}: acquired candidates {} for new listener {}", uuid, owned, listener);
96 synchronized (listeners) {
97 listeners.put(entityType, listener);
100 for (DOMEntity entity : owned) {
101 notifyListener(listener, new DOMEntityOwnershipChange(entity, LOCAL_OWNERSHIP_GRANTED));
103 LOG.debug("{}: registered listener {}", uuid, listener);
104 return new ListenerRegistration(entityType, listener);
108 public Optional<EntityOwnershipState> getOwnershipState(final DOMEntity forEntity) {
109 return isCandidateRegistered(forEntity) ? Optional.of(EntityOwnershipState.IS_OWNER) : Optional.empty();
113 public boolean isCandidateRegistered(final DOMEntity forEntity) {
114 synchronized (entities) {
115 return entities.contains(forEntity.getType(), forEntity.getIdentifier());
119 @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
120 justification = "https://github.com/spotbugs/spotbugs/issues/811")
121 private void removeEntity(final DOMEntity entity) {
122 synchronized (entities) {
123 entities.remove(entity.getType(), entity.getIdentifier());
124 LOG.debug("{}: unregistered candidate {}", uuid, entity);
127 notifyListeners(entity, LOCAL_OWNERSHIP_LOST_NO_OWNER);
130 @SuppressWarnings("checkstyle:illegalCatch")
131 private void notifyListener(final DOMEntityOwnershipListener listener, final DOMEntityOwnershipChange change) {
133 LOG.trace("{} notifying listener {} change {}", uuid, listener, change);
134 listener.ownershipChanged(change);
135 } catch (RuntimeException e) {
136 LOG.warn("{}: Listener {} change {} failed", uuid, listener, change, e);
140 private void notifyListeners(final DOMEntity entity, final EntityOwnershipChangeState state) {
141 final DOMEntityOwnershipChange change = new DOMEntityOwnershipChange(entity, state);
143 final Collection<DOMEntityOwnershipListener> snap;
145 synchronized (listeners) {
146 snap = ImmutableList.copyOf(listeners.get(entity.getType()));
149 for (DOMEntityOwnershipListener listener : snap) {
150 notifyListener(listener, change);
154 void unregisterListener(final ListenerRegistration reg) {
155 synchronized (listeners) {
156 listeners.remove(reg.getEntityType(), reg.getInstance());
157 LOG.debug("{}: unregistered listener {}", uuid, reg.getInstance());
162 public String toString() {
163 final ToStringHelper h = MoreObjects.toStringHelper(SimpleDOMEntityOwnershipService.class).add("uuid", uuid);
165 synchronized (entities) {
166 h.add("entities", entities);
168 synchronized (listeners) {
169 h.add("listeners", listeners);
175 private final class EntityRegistration extends AbstractObjectRegistration<DOMEntity> implements
176 DOMEntityOwnershipCandidateRegistration {
177 EntityRegistration(final DOMEntity entity) {
182 protected void removeRegistration() {
183 removeEntity(getInstance());
187 private final class ListenerRegistration extends AbstractObjectRegistration<DOMEntityOwnershipListener>
188 implements DOMEntityOwnershipListenerRegistration {
189 private final String entityType;
191 ListenerRegistration(final String entityType, final DOMEntityOwnershipListener listener) {
193 this.entityType = requireNonNull(entityType);
197 public String getEntityType() {
202 protected void removeRegistration() {
203 unregisterListener(this);