2 * Copyright (c) 2014 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
9 package org.opendaylight.openflowplugin.applications.statistics.manager.impl;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import java.util.Collection;
15 import java.util.concurrent.Callable;
16 import java.util.concurrent.ConcurrentHashMap;
17 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
18 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
19 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
20 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
23 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
24 import org.opendaylight.openflowplugin.applications.statistics.manager.StatListeningCommiter;
25 import org.opendaylight.openflowplugin.applications.statistics.manager.StatNodeRegistration;
26 import org.opendaylight.openflowplugin.applications.statistics.manager.StatisticsManager;
27 import org.opendaylight.openflowplugin.common.wait.SimpleTaskRetryLooper;
28 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
29 import org.opendaylight.yangtools.concepts.ListenerRegistration;
30 import org.opendaylight.yangtools.yang.binding.DataObject;
31 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
32 import org.opendaylight.yangtools.yang.binding.NotificationListener;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
38 * org.opendaylight.openflowplugin.applications.statistics.manager.impl
40 * StatAbstractListeneningCommiter
41 * Class is abstract implementation for all Configuration/DataStore DataTreeModification
42 * listenable DataObjects like flows, groups, meters. It is a holder for common
43 * functionality needed by construction/destruction class and for DataTreeModification
46 public abstract class StatAbstractListenCommit<T extends DataObject, N extends NotificationListener>
47 extends StatAbstractNotifyCommit<N> implements StatListeningCommiter<T,N> {
49 private static final Logger LOG = LoggerFactory.getLogger(StatAbstractListenCommit.class);
51 private ListenerRegistration<StatAbstractListenCommit<T, N>> listenerRegistration;
53 protected final Map<InstanceIdentifier<Node>, Map<InstanceIdentifier<T>, Integer>> mapNodesForDelete = new ConcurrentHashMap<>();
54 protected final Map<InstanceIdentifier<Node>, Integer> mapNodeFeautureRepeater = new ConcurrentHashMap<>();
56 private final Class<T> clazz;
58 private final DataBroker dataBroker;
60 protected final StatNodeRegistration nodeRegistrationManager;
62 private ReadOnlyTransaction currentReadTx;
63 private volatile boolean currentReadTxStale;
65 private static final int STARTUP_LOOP_TICK = 500;
66 private static final int STARTUP_LOOP_MAX_RETRIES = 8;
68 private final DataTreeIdentifier<T> treeId =
69 new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, getWildCardedRegistrationPath());
71 /* Constructor has to make a registration */
72 public StatAbstractListenCommit(final StatisticsManager manager, final DataBroker db,
73 final NotificationProviderService nps, final Class<T> clazz, final StatNodeRegistration nodeRegistrationManager) {
74 super(manager,nps, nodeRegistrationManager);
75 this.clazz = Preconditions.checkNotNull(clazz, "Referenced Class can not be null");
76 Preconditions.checkArgument(db != null, "DataBroker can not be null!");
78 this.nodeRegistrationManager = nodeRegistrationManager;
80 SimpleTaskRetryLooper looper = new SimpleTaskRetryLooper(STARTUP_LOOP_TICK, STARTUP_LOOP_MAX_RETRIES);
82 listenerRegistration = looper.loopUntilNoException(new Callable<ListenerRegistration<StatAbstractListenCommit<T, N>>>() {
84 public ListenerRegistration<StatAbstractListenCommit<T, N>> call() throws Exception {
85 return db.registerDataTreeChangeListener(treeId,StatAbstractListenCommit.this);
88 } catch (final Exception ex) {
89 LOG.debug(" StatAbstractListenCommit DataTreeChangeListener registration failed {}", ex.getMessage());
90 throw new IllegalStateException("Notification supplier startup fail! System needs restart.", ex);
95 * Method returns WildCarded Path which is used for registration as a listening path changes in
96 * {@link org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener}
99 protected abstract InstanceIdentifier<T> getWildCardedRegistrationPath();
102 public void onDataTreeChanged(Collection<DataTreeModification<T>> changes) {
103 Preconditions.checkNotNull(changes, "Changes must not be null!");
105 * If we have opened read transaction for configuration data store, we need to mark it as stale.
107 * Latest read transaction will be allocated on another read using readLatestConfiguration
109 currentReadTxStale = true;
112 @SuppressWarnings("unchecked")
113 protected void removeData(final InstanceIdentifier<?> key, final Integer value) {
114 if (clazz.equals(key.getTargetType())) {
115 final InstanceIdentifier<Node> nodeIdent = key.firstIdentifierOf(Node.class);
116 Map<InstanceIdentifier<T>, Integer> map = null;
117 if (mapNodesForDelete.containsKey(nodeIdent)) {
118 map = mapNodesForDelete.get(nodeIdent);
121 map = new ConcurrentHashMap<>();
122 mapNodesForDelete.put(nodeIdent, map);
124 map.put((InstanceIdentifier<T>) key, value);
129 public void cleanForDisconnect(final InstanceIdentifier<Node> nodeIdent) {
130 mapNodesForDelete.remove(nodeIdent);
134 public void close() {
135 if (listenerRegistration != null) {
137 listenerRegistration.close();
138 } catch (final Exception e) {
139 LOG.error("Error by stop {} DataTreeChangeListener StatListeningCommiter.", clazz.getSimpleName(), e);
141 listenerRegistration = null;
148 * Method return actual DataObject identified by InstanceIdentifier from Config/DS
152 protected final <K extends DataObject> Optional<K> readLatestConfiguration(final InstanceIdentifier<K> path) {
153 for(int i = 0; i < 2; i++) {
154 boolean localReadTxStale = currentReadTxStale;
156 // This non-volatile read piggy backs the volatile currentReadTxStale read above to
157 // ensure visibility in case this method is called across threads (although not concurrently).
158 ReadOnlyTransaction localReadTx = currentReadTx;
159 if(localReadTx == null || localReadTxStale) {
160 if(localReadTx != null) {
164 localReadTx = dataBroker.newReadOnlyTransaction();
166 currentReadTx = localReadTx;
168 // Note - this volatile write also publishes the non-volatile currentReadTx write above.
169 currentReadTxStale = false;
173 return localReadTx.read(LogicalDatastoreType.CONFIGURATION, path).checkedGet();
174 } catch (final ReadFailedException e) {
175 LOG.debug("It wasn't possible to read {} from datastore. Exception: {}", path, e);
177 // Loop back and try again with a new Tx.
178 currentReadTxStale = true;
182 return Optional.absent();