Use Executors.newSingleThreadExecutor in AsyncDataTreeChangeListenerBase
[genius.git] / mdsalutil / mdsalutil-api / src / main / java / org / opendaylight / genius / datastoreutils / AsyncDataTreeChangeListenerBase.java
1 /*
2  * Copyright (c) 2016 Ericsson India Global Services Pvt Ltd. 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
9 package org.opendaylight.genius.datastoreutils;
10
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.utils.concurrent.Executors;
24 import org.opendaylight.yangtools.concepts.ListenerRegistration;
25 import org.opendaylight.yangtools.yang.binding.DataObject;
26 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 @Deprecated
31 public abstract class AsyncDataTreeChangeListenerBase<T extends DataObject, K extends DataTreeChangeListener<T>>
32         implements DataTreeChangeListener<T>, ChainableDataTreeChangeListener<T>, AutoCloseable {
33
34     private static final Logger LOG = LoggerFactory.getLogger(AsyncDataTreeChangeListenerBase.class);
35
36     private ListenerRegistration<K> listenerRegistration;
37     private final ChainableDataTreeChangeListenerImpl<T> chainingDelegate = new ChainableDataTreeChangeListenerImpl<>();
38
39     private final ExecutorService dataTreeChangeHandlerExecutor =
40             Executors.newSingleThreadExecutor("AsyncDataTreeChangeListenerBase-DataTreeChangeHandler", LOG);
41     protected final Class<T> clazz;
42
43     protected AsyncDataTreeChangeListenerBase() {
44         this.clazz = SuperTypeUtil.getTypeParameter(getClass(), 0);
45     }
46
47     @Deprecated
48     public AsyncDataTreeChangeListenerBase(Class<T> clazz, Class<K> eventClazz) {
49         this.clazz = Preconditions.checkNotNull(clazz, "Class can not be null!");
50     }
51
52     @Override
53     public void addBeforeListener(DataTreeChangeListener<T> listener) {
54         chainingDelegate.addBeforeListener(listener);
55     }
56
57     @Override
58     public void addAfterListener(DataTreeChangeListener<T> listener) {
59         chainingDelegate.addAfterListener(listener);
60     }
61
62     @Override
63     public void onDataTreeChanged(Collection<DataTreeModification<T>> changes) {
64         if (changes == null || changes.isEmpty()) {
65             return;
66         }
67
68         DataTreeChangeHandler dataTreeChangeHandler = new DataTreeChangeHandler(changes);
69         dataTreeChangeHandlerExecutor.execute(dataTreeChangeHandler);
70     }
71
72     public void registerListener(LogicalDatastoreType dsType, final DataBroker db) {
73         final DataTreeIdentifier<T> treeId = new DataTreeIdentifier<>(dsType, getWildCardPath());
74         listenerRegistration = db.registerDataTreeChangeListener(treeId, getDataTreeChangeListener());
75     }
76
77     /**
78      * Subclasses override this and place initialization logic here, notably
79      * calls to registerListener(). Note that the overriding method MUST repeat
80      * the PostConstruct annotation, because JSR 250 specifies that lifecycle
81      * methods "are called unless a subclass of the declaring class overrides
82      * the method without repeating the annotation".  (The blueprint-maven-plugin
83      * would gen. XML which calls PostConstruct annotated methods even if they are
84      * in a subclass without repeating the annotation, but this is wrong and not
85      * JSR 250 compliant, and while working in BP, then causes issues e.g. when
86      * wiring with Guice for tests, so do always repeat it.)
87      */
88     @PostConstruct
89     protected void init() {
90     }
91
92     @Override
93     @PreDestroy
94     public void close() {
95         dataTreeChangeHandlerExecutor.shutdownNow();
96
97         if (listenerRegistration != null) {
98             try {
99                 listenerRegistration.close();
100             } finally {
101                 listenerRegistration = null;
102             }
103         }
104     }
105
106     protected abstract InstanceIdentifier<T> getWildCardPath();
107
108     protected abstract void remove(InstanceIdentifier<T> key, T dataObjectModification);
109
110     protected abstract void update(InstanceIdentifier<T> key,
111             T dataObjectModificationBefore, T dataObjectModificationAfter);
112
113     protected abstract void add(InstanceIdentifier<T> key, T dataObjectModification);
114
115     protected abstract K getDataTreeChangeListener();
116
117     public class DataTreeChangeHandler implements Runnable {
118         private final Collection<DataTreeModification<T>> changes;
119
120         public DataTreeChangeHandler(Collection<DataTreeModification<T>> changes) {
121             chainingDelegate.notifyBeforeOnDataTreeChanged(changes);
122             this.changes = changes;
123         }
124
125         @Override
126         public void run() {
127             for (DataTreeModification<T> change : changes) {
128                 final InstanceIdentifier<T> key = change.getRootPath().getRootIdentifier();
129                 final DataObjectModification<T> mod = change.getRootNode();
130
131                 switch (mod.getModificationType()) {
132                     case DELETE:
133                         remove(key, mod.getDataBefore());
134                         break;
135                     case SUBTREE_MODIFIED:
136                         update(key, mod.getDataBefore(), mod.getDataAfter());
137                         break;
138                     case WRITE:
139                         if (mod.getDataBefore() == null) {
140                             add(key, mod.getDataAfter());
141                         } else {
142                             update(key, mod.getDataBefore(), mod.getDataAfter());
143                         }
144                         break;
145                     default:
146                         // FIXME: May be not a good idea to throw.
147                         throw new IllegalArgumentException("Unhandled modification type " + mod.getModificationType());
148                 }
149             }
150             chainingDelegate.notifyAfterOnDataTreeChanged(changes);
151         }
152     }
153 }