BUG 2049 DataStore failure in StatisticsManager
[controller.git] / opendaylight / md-sal / statistics-manager / src / main / java / org / opendaylight / controller / md / statistics / manager / impl / StatAbstractListenCommit.java
1 /**
2  * Copyright (c) 2014 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
9 package org.opendaylight.controller.md.statistics.manager.impl;
10
11 import java.util.Map;
12 import java.util.concurrent.ConcurrentHashMap;
13
14 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
15 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
16 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
17 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
18 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
21 import org.opendaylight.controller.md.statistics.manager.StatListeningCommiter;
22 import org.opendaylight.controller.md.statistics.manager.StatisticsManager;
23 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
24 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
25 import org.opendaylight.yangtools.concepts.ListenerRegistration;
26 import org.opendaylight.yangtools.yang.binding.DataObject;
27 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
28 import org.opendaylight.yangtools.yang.binding.NotificationListener;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import com.google.common.base.Optional;
33 import com.google.common.base.Preconditions;
34
35 /**
36  * statistics-manager
37  * org.opendaylight.controller.md.statistics.manager.impl
38  *
39  * StatAbstractListeneningCommiter
40  * Class is abstract implementation for all Configuration/DataStore DataChange
41  * listenable DataObjects like flows, groups, meters. It is a holder for common
42  * functionality needed by construction/destruction class and for DataChange
43  * event processing.
44  *
45  */
46 public abstract class StatAbstractListenCommit<T extends DataObject, N extends NotificationListener>
47                                             extends StatAbstractNotifyCommit<N> implements StatListeningCommiter<T,N> {
48
49     private static final Logger LOG = LoggerFactory.getLogger(StatAbstractListenCommit.class);
50
51     private ListenerRegistration<DataChangeListener> listenerRegistration;
52
53     protected final Map<InstanceIdentifier<Node>, Map<InstanceIdentifier<T>, Integer>> mapNodesForDelete = new ConcurrentHashMap<>();
54
55     private final Class<T> clazz;
56
57     private final DataBroker dataBroker;
58
59     private volatile ReadOnlyTransaction currentReadTx;
60
61     /* Constructor has to make a registration */
62     public StatAbstractListenCommit(final StatisticsManager manager, final DataBroker db,
63             final NotificationProviderService nps, final Class<T> clazz) {
64         super(manager,nps);
65         this.clazz = Preconditions.checkNotNull(clazz, "Referenced Class can not be null");
66         Preconditions.checkArgument(db != null, "DataBroker can not be null!");
67         listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.CONFIGURATION,
68                 getWildCardedRegistrationPath(), this, DataChangeScope.BASE);
69         this.dataBroker = db;
70     }
71
72     /**
73      * Method returns WildCarded Path which is used for registration as a listening path changes in
74      * {@link org.opendaylight.controller.md.sal.binding.api.DataChangeListener}
75      * @return
76      */
77     protected abstract InstanceIdentifier<T> getWildCardedRegistrationPath();
78
79     @Override
80     public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
81         Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
82         /*
83          * If we have opened read transaction for configuraiton data store,
84          * we will close and null it.
85          *
86          * Latest read transaction will be allocated on another read using readLatestConfiguration
87          */
88         if(currentReadTx != null) {
89             final ReadOnlyTransaction previous = currentReadTx;
90             currentReadTx = null;
91             previous.close();
92         }
93     }
94
95     @SuppressWarnings("unchecked")
96     protected void removeData(final InstanceIdentifier<?> key, final Integer value) {
97         if (clazz.equals(key.getTargetType())) {
98             final InstanceIdentifier<Node> nodeIdent = key.firstIdentifierOf(Node.class);
99             Map<InstanceIdentifier<T>, Integer> map = null;
100             if (mapNodesForDelete.containsKey(nodeIdent)) {
101                 map = mapNodesForDelete.get(nodeIdent);
102             }
103             if (map == null) {
104                 map = new ConcurrentHashMap<>();
105                 mapNodesForDelete.put(nodeIdent, map);
106             }
107             map.put((InstanceIdentifier<T>) key, value);
108         }
109     }
110
111     @Override
112     public void cleanForDisconnect(final InstanceIdentifier<Node> nodeIdent) {
113         mapNodesForDelete.remove(nodeIdent);
114     }
115
116     @Override
117     public void close() {
118         if (listenerRegistration != null) {
119             try {
120                 listenerRegistration.close();
121             } catch (final Exception e) {
122                 LOG.error("Error by stop {} DataChange StatListeningCommiter.", clazz.getSimpleName(), e);
123             }
124             listenerRegistration = null;
125         }
126     }
127
128     protected final <K extends DataObject> Optional<K> readLatestConfiguration(final InstanceIdentifier<K> path) {
129         if(currentReadTx == null) {
130              currentReadTx = dataBroker.newReadOnlyTransaction();
131         }
132         try {
133             return currentReadTx.read(LogicalDatastoreType.CONFIGURATION, path).checkedGet();
134         } catch (final ReadFailedException e) {
135             return Optional.absent();
136         }
137     }
138 }
139