Use OSGi DS instead of Activator/blueprint
[mdsal.git] / entityownership / mdsal-eos-dom-simple / src / main / java / org / opendaylight / mdsal / eos / dom / simple / SimpleDOMEntityOwnershipService.java
1 /*
2  * Copyright (c) 2017 Cisco 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.mdsal.eos.dom.simple;
9
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;
13
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 javax.inject.Singleton;
27 import org.checkerframework.checker.lock.qual.GuardedBy;
28 import org.kohsuke.MetaInfServices;
29 import org.opendaylight.mdsal.eos.common.api.CandidateAlreadyRegisteredException;
30 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipChangeState;
31 import org.opendaylight.mdsal.eos.common.api.EntityOwnershipState;
32 import org.opendaylight.mdsal.eos.dom.api.DOMEntity;
33 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipCandidateRegistration;
34 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipChange;
35 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListener;
36 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipListenerRegistration;
37 import org.opendaylight.mdsal.eos.dom.api.DOMEntityOwnershipService;
38 import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
39 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
40 import org.osgi.service.component.annotations.Component;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
43
44 /**
45  * Simple {@link DOMEntityOwnershipService} operating as an isolated island. It has no awareness of the world outside
46  * of itself.
47  *
48  * @author Robert Varga
49  */
50 @MetaInfServices
51 @Singleton
52 @Component(immediate = true)
53 public final class SimpleDOMEntityOwnershipService implements DOMEntityOwnershipService {
54     private static final Logger LOG = LoggerFactory.getLogger(SimpleDOMEntityOwnershipService.class);
55
56     @GuardedBy("entities")
57     private final Table<String, YangInstanceIdentifier, DOMEntity> entities = HashBasedTable.create();
58
59     @GuardedBy("listeners")
60     private final Multimap<String, DOMEntityOwnershipListener> listeners = ArrayListMultimap.create(0, 1);
61
62     private final UUID uuid;
63
64     @VisibleForTesting
65     SimpleDOMEntityOwnershipService(final UUID uuid) {
66         this.uuid = requireNonNull(uuid);
67     }
68
69     public SimpleDOMEntityOwnershipService() {
70         this(UUID.randomUUID());
71     }
72
73     @Override
74     public DOMEntityOwnershipCandidateRegistration registerCandidate(final DOMEntity entity)
75             throws CandidateAlreadyRegisteredException {
76         synchronized (entities) {
77             final DOMEntity prev = entities.get(entity.getType(), entity.getIdentifier());
78             if (prev != null) {
79                 throw new CandidateAlreadyRegisteredException(prev);
80             }
81
82             entities.put(entity.getType(), entity.getIdentifier(), entity);
83             LOG.debug("{}: registered candidate {}", uuid, entity);
84         }
85
86         notifyListeners(entity, LOCAL_OWNERSHIP_GRANTED);
87         return new EntityRegistration(entity);
88     }
89
90     @Override
91     public DOMEntityOwnershipListenerRegistration registerListener(final String entityType,
92             final DOMEntityOwnershipListener listener) {
93
94         final Collection<DOMEntity> owned;
95         synchronized (entities) {
96             owned = ImmutableList.copyOf(entities.row(entityType).values());
97             LOG.trace("{}: acquired candidates {} for new listener {}", uuid, owned, listener);
98         }
99
100         synchronized (listeners) {
101             listeners.put(entityType, listener);
102         }
103
104         for (DOMEntity entity : owned) {
105             notifyListener(listener, new DOMEntityOwnershipChange(entity, LOCAL_OWNERSHIP_GRANTED));
106         }
107         LOG.debug("{}: registered listener {}", uuid, listener);
108         return new ListenerRegistration(entityType, listener);
109     }
110
111     @Override
112     public Optional<EntityOwnershipState> getOwnershipState(final DOMEntity forEntity) {
113         return isCandidateRegistered(forEntity) ? Optional.of(EntityOwnershipState.IS_OWNER) : Optional.empty();
114     }
115
116     @Override
117     public boolean isCandidateRegistered(final DOMEntity forEntity) {
118         synchronized (entities) {
119             return entities.contains(forEntity.getType(), forEntity.getIdentifier());
120         }
121     }
122
123     @SuppressFBWarnings(value = "UPM_UNCALLED_PRIVATE_METHOD",
124             justification = "https://github.com/spotbugs/spotbugs/issues/811")
125     private void removeEntity(final DOMEntity entity) {
126         synchronized (entities) {
127             entities.remove(entity.getType(), entity.getIdentifier());
128             LOG.debug("{}: unregistered candidate {}", uuid, entity);
129         }
130
131         notifyListeners(entity, LOCAL_OWNERSHIP_LOST_NO_OWNER);
132     }
133
134     @SuppressWarnings("checkstyle:illegalCatch")
135     private void notifyListener(final DOMEntityOwnershipListener listener, final DOMEntityOwnershipChange change) {
136         try {
137             LOG.trace("{} notifying listener {} change {}", uuid, listener, change);
138             listener.ownershipChanged(change);
139         } catch (RuntimeException e) {
140             LOG.warn("{}: Listener {} change {} failed", uuid, listener, change, e);
141         }
142     }
143
144     private void notifyListeners(final DOMEntity entity, final EntityOwnershipChangeState state) {
145         final DOMEntityOwnershipChange change = new DOMEntityOwnershipChange(entity, state);
146
147         final Collection<DOMEntityOwnershipListener> snap;
148
149         synchronized (listeners) {
150             snap = ImmutableList.copyOf(listeners.get(entity.getType()));
151         }
152
153         for (DOMEntityOwnershipListener listener : snap) {
154             notifyListener(listener, change);
155         }
156     }
157
158     void unregisterListener(final ListenerRegistration reg) {
159         synchronized (listeners) {
160             listeners.remove(reg.getEntityType(), reg.getInstance());
161             LOG.debug("{}: unregistered listener {}", uuid, reg.getInstance());
162         }
163     }
164
165     @Override
166     public String toString() {
167         final ToStringHelper h = MoreObjects.toStringHelper(SimpleDOMEntityOwnershipService.class).add("uuid", uuid);
168
169         synchronized (entities) {
170             h.add("entities", entities);
171         }
172         synchronized (listeners) {
173             h.add("listeners", listeners);
174         }
175
176         return h.toString();
177     }
178
179     private final class EntityRegistration extends AbstractObjectRegistration<DOMEntity> implements
180             DOMEntityOwnershipCandidateRegistration {
181         EntityRegistration(final DOMEntity entity) {
182             super(entity);
183         }
184
185         @Override
186         protected void removeRegistration() {
187             removeEntity(getInstance());
188         }
189     }
190
191     private final class ListenerRegistration extends AbstractObjectRegistration<DOMEntityOwnershipListener>
192             implements DOMEntityOwnershipListenerRegistration {
193         private final String entityType;
194
195         ListenerRegistration(final String entityType, final DOMEntityOwnershipListener listener) {
196             super(listener);
197             this.entityType = requireNonNull(entityType);
198         }
199
200         @Override
201         public String getEntityType() {
202             return entityType;
203         }
204
205         @Override
206         protected void removeRegistration() {
207             unregisterListener(this);
208         }
209     }
210 }