Merge "BUG 1839 - HTTP delete of non existing data"
[controller.git] / opendaylight / md-sal / compatibility / sal-compatibility / src / main / java / org / opendaylight / controller / sal / compatibility / AbstractDataChangeListener.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 package org.opendaylight.controller.sal.compatibility;
9
10 import java.util.Collections;
11 import java.util.Map;
12 import java.util.Set;
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.common.api.data.AsyncDataBroker.DataChangeScope;
17 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.yangtools.concepts.ListenerRegistration;
20 import org.opendaylight.yangtools.yang.binding.DataObject;
21 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 import com.google.common.base.Optional;
26 import com.google.common.base.Preconditions;
27
28 public abstract class AbstractDataChangeListener <T extends DataObject> implements AutoCloseable,DataChangeListener{
29
30     private static final Logger LOG = LoggerFactory.getLogger(AbstractDataChangeListener.class);
31     protected InventoryAndReadAdapter adapter;
32     protected final Class<T> clazz;
33     protected ListenerRegistration<DataChangeListener> listenerRegistration;
34
35     public AbstractDataChangeListener(final InventoryAndReadAdapter adapter, DataBroker db, final Class<T> clazz) {
36         this.adapter = Preconditions.checkNotNull(adapter, "InventoryAndReadAdapter can not be null!");
37         this.clazz = Preconditions.checkNotNull(clazz, "Class can not be null!");
38         Preconditions.checkNotNull(db, "DataBroker can not be null!");
39         registrationListener(db, 5);
40     }
41
42     @Override
43     public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
44         Preconditions.checkNotNull(changeEvent,"Async ChangeEvent can not be null!");
45         /* All DataObjects for create */
46         final Map<InstanceIdentifier<?>, DataObject> createdData = changeEvent.getCreatedData() != null
47                 ? changeEvent.getCreatedData() : Collections.<InstanceIdentifier<?>, DataObject> emptyMap();
48         /* All DataObjects for remove */
49         final Set<InstanceIdentifier<?>> removeData = changeEvent.getRemovedPaths() != null
50                 ? changeEvent.getRemovedPaths() : Collections.<InstanceIdentifier<?>> emptySet();
51         /* All DataObjects for updates */
52         final Map<InstanceIdentifier<?>, DataObject> updateData = changeEvent.getUpdatedData() != null
53                 ? changeEvent.getUpdatedData() : Collections.<InstanceIdentifier<?>, DataObject> emptyMap();
54         /* All Original DataObjects */
55         final Map<InstanceIdentifier<?>, DataObject> originalData = changeEvent.getOriginalData() != null
56                 ? changeEvent.getOriginalData() : Collections.<InstanceIdentifier<?>, DataObject> emptyMap();
57         this.createData(createdData);
58         this.updateData(updateData, originalData);
59         this.removeData(removeData, originalData);
60     }
61
62     @SuppressWarnings("unchecked")
63     private void createData(final Map<InstanceIdentifier<?>, DataObject> createdData) {
64         final Set<InstanceIdentifier<?>> keys = createdData.keySet() != null
65                 ? createdData.keySet() : Collections.<InstanceIdentifier<?>> emptySet();
66         for (InstanceIdentifier<?> key : keys) {
67             if (clazz.equals(key.getTargetType())) {
68                 InstanceIdentifier<T> createKeyIdent = key.firstIdentifierOf(clazz);
69                 final Optional<DataObject> value = Optional.of(createdData.get(key));
70                 if (value.isPresent()) {
71                     this.add(createKeyIdent, (T)value.get());
72                 }
73             }
74         }
75     }
76
77     abstract protected void add(InstanceIdentifier<T> createKeyIdent, T node);
78
79     @SuppressWarnings("unchecked")
80     private void updateData(final Map<InstanceIdentifier<?>, DataObject> updateData, final Map<InstanceIdentifier<?>, DataObject> originalData) {
81
82         final Set<InstanceIdentifier<?>> keys = updateData.keySet() != null
83                 ? updateData.keySet() : Collections.<InstanceIdentifier<?>> emptySet();
84         for (InstanceIdentifier<?> key : keys) {
85             if (clazz.equals(key.getTargetType())) {
86                 InstanceIdentifier<T> updateKeyIdent = key.firstIdentifierOf(clazz);
87                 final Optional<DataObject> value = Optional.of(updateData.get(key));
88                 final Optional<DataObject> original = Optional.of(originalData.get(key));
89                 if (value.isPresent() && original.isPresent()) {
90                     this.update(updateKeyIdent, (T)original.get(), (T)value.get());
91                 }
92             }
93         }
94     }
95
96     abstract protected void update(InstanceIdentifier<T> updateKeyIdent, T node,
97             T node2);
98
99     @SuppressWarnings("unchecked")
100     private void removeData(final Set<InstanceIdentifier<?>> removeData, final Map<InstanceIdentifier<?>, DataObject> originalData) {
101
102         for (InstanceIdentifier<?> key : removeData) {
103             if (clazz.equals(key.getTargetType())) {
104                 final InstanceIdentifier<T> ident = key.firstIdentifierOf(clazz);
105                 final DataObject removeValue = originalData.get(key);
106                 this.remove(ident, (T)removeValue);
107             }
108         }
109     }
110
111     abstract protected void remove(InstanceIdentifier<T> ident, T removeValue);
112
113     protected void registrationListener(final DataBroker db, int i) {
114         try {
115             listenerRegistration = db.registerDataChangeListener(LogicalDatastoreType.OPERATIONAL,
116                     getWildCardPath(), this, DataChangeScope.BASE);
117         } catch (final Exception e) {
118             if (i >= 1) {
119                 try {
120                     Thread.sleep(100);
121                 } catch (InterruptedException e1) {
122                     LOG.error("Thread interrupted '{}'", e1);
123                     Thread.currentThread().interrupt();
124                 }
125                 registrationListener(db, --i);
126             } else {
127                 LOG.error("AbstractDataChangeListener registration fail!", e);
128                 throw new IllegalStateException("AbstractDataChangeListener registration Listener fail! System needs restart.", e);
129             }
130         }
131     }
132
133     protected abstract InstanceIdentifier<?> getWildCardPath();
134
135     @Override
136     public void close() {
137         if (listenerRegistration != null) {
138             try {
139                 listenerRegistration.close();
140             } catch (final Exception e) {
141                 LOG.error("Error by stop AbstractDataChangeListener.", e);
142             }
143             listenerRegistration = null;
144         }
145     }
146 }