2 * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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.genius.datastoreutils;
11 import com.google.common.base.Preconditions;
12 import java.util.Collection;
13 import java.util.concurrent.ExecutorService;
14 import javax.annotation.PostConstruct;
15 import javax.annotation.PreDestroy;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
18 import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
19 import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
20 import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.genius.utils.SuperTypeUtil;
23 import org.opendaylight.infrautils.metrics.MetricProvider;
24 import org.opendaylight.infrautils.utils.concurrent.Executors;
25 import org.opendaylight.serviceutils.tools.mdsal.listener.ChainableDataTreeChangeListener;
26 import org.opendaylight.serviceutils.tools.mdsal.listener.ChainableDataTreeChangeListenerImpl;
27 import org.opendaylight.yangtools.concepts.ListenerRegistration;
28 import org.opendaylight.yangtools.yang.binding.DataObject;
29 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
35 * Deprecated DS listener.
36 * @deprecated Please use
37 * {@link org.opendaylight.serviceutils.tools.mdsal.listener.AbstractAsyncDataTreeChangeListener} instead of this!
41 public abstract class AsyncDataTreeChangeListenerBase<T extends DataObject, K extends DataTreeChangeListener<T>>
42 implements DataTreeChangeListener<T>, ChainableDataTreeChangeListener<T>, AutoCloseable {
44 private static final Logger LOG = LoggerFactory.getLogger(AsyncDataTreeChangeListenerBase.class);
46 private ListenerRegistration<K> listenerRegistration;
47 private final ChainableDataTreeChangeListenerImpl<T> chainingDelegate = new ChainableDataTreeChangeListenerImpl<>();
48 private final ExecutorService dataTreeChangeHandlerExecutor;
49 protected final Class<T> clazz;
50 private DataStoreMetrics dataStoreMetrics;
52 protected AsyncDataTreeChangeListenerBase() {
53 this.clazz = SuperTypeUtil.getTypeParameter(getClass(), 0);
54 this.dataTreeChangeHandlerExecutor = newThreadPoolExecutor(clazz);
57 protected AsyncDataTreeChangeListenerBase(MetricProvider metricProvider) {
59 this.dataStoreMetrics = new DataStoreMetrics(metricProvider, getClass());
63 public AsyncDataTreeChangeListenerBase(Class<T> clazz, Class<K> eventClazz) {
64 this.clazz = Preconditions.checkNotNull(clazz, "Class can not be null!");
65 this.dataTreeChangeHandlerExecutor = newThreadPoolExecutor(clazz);
68 private static ExecutorService newThreadPoolExecutor(Class<?> clazz) {
69 return Executors.newSingleThreadExecutor(
70 // class name first so it shows up in logs' prefix, but fixed length
71 clazz.getName() + "_AsyncDataTreeChangeListenerBase-DataTreeChangeHandler", LOG);
75 public void addBeforeListener(DataTreeChangeListener<T> listener) {
76 chainingDelegate.addBeforeListener(listener);
80 public void addAfterListener(DataTreeChangeListener<T> listener) {
81 chainingDelegate.addAfterListener(listener);
85 public void onDataTreeChanged(Collection<DataTreeModification<T>> changes) {
86 if (changes == null || changes.isEmpty()) {
90 DataTreeChangeHandler dataTreeChangeHandler = new DataTreeChangeHandler(changes);
91 dataTreeChangeHandlerExecutor.execute(dataTreeChangeHandler);
94 public void registerListener(LogicalDatastoreType dsType, final DataBroker db) {
95 final DataTreeIdentifier<T> treeId = new DataTreeIdentifier<>(dsType, getWildCardPath());
96 listenerRegistration = db.registerDataTreeChangeListener(treeId, getDataTreeChangeListener());
101 * Subclasses override this and place initialization logic here, notably
102 * calls to registerListener(). Note that the overriding method MUST repeat
103 * the PostConstruct annotation, because JSR 250 specifies that lifecycle
104 * methods "are called unless a subclass of the declaring class overrides
105 * the method without repeating the annotation". (The blueprint-maven-plugin
106 * would gen. XML which calls PostConstruct annotated methods even if they are
107 * in a subclass without repeating the annotation, but this is wrong and not
108 * JSR 250 compliant, and while working in BP, then causes issues e.g. when
109 * wiring with Guice for tests, so do always repeat it.)
113 protected void init() {
116 public void deregisterListener() {
117 if (listenerRegistration != null) {
119 listenerRegistration.close();
121 listenerRegistration = null;
128 public void close() {
129 dataTreeChangeHandlerExecutor.shutdownNow();
130 deregisterListener();
133 protected abstract InstanceIdentifier<T> getWildCardPath();
135 protected abstract void remove(InstanceIdentifier<T> key, T dataObjectModification);
137 protected abstract void update(InstanceIdentifier<T> key,
138 T dataObjectModificationBefore, T dataObjectModificationAfter);
140 protected abstract void add(InstanceIdentifier<T> key, T dataObjectModification);
142 protected abstract K getDataTreeChangeListener();
144 public class DataTreeChangeHandler implements Runnable {
145 private final Collection<DataTreeModification<T>> changes;
147 public DataTreeChangeHandler(Collection<DataTreeModification<T>> changes) {
148 chainingDelegate.notifyBeforeOnDataTreeChanged(changes);
149 this.changes = changes;
154 for (DataTreeModification<T> change : changes) {
155 final InstanceIdentifier<T> key = change.getRootPath().getRootIdentifier();
156 final DataObjectModification<T> mod = change.getRootNode();
158 switch (mod.getModificationType()) {
160 if (dataStoreMetrics != null) {
161 dataStoreMetrics.incrementDeleted();
163 remove(key, mod.getDataBefore());
165 case SUBTREE_MODIFIED:
166 if (dataStoreMetrics != null) {
167 dataStoreMetrics.incrementUpdated();
169 update(key, mod.getDataBefore(), mod.getDataAfter());
172 if (mod.getDataBefore() == null) {
173 if (dataStoreMetrics != null) {
174 dataStoreMetrics.incrementAdded();
176 add(key, mod.getDataAfter());
178 if (dataStoreMetrics != null) {
179 dataStoreMetrics.incrementUpdated();
181 update(key, mod.getDataBefore(), mod.getDataAfter());
185 // FIXME: May be not a good idea to throw.
186 throw new IllegalArgumentException("Unhandled modification type " + mod.getModificationType());
189 chainingDelegate.notifyAfterOnDataTreeChanged(changes);