Merge "BUG-2288: deprecate old binding Notification API elements"
[controller.git] / opendaylight / md-sal / sal-binding-broker / src / main / java / org / opendaylight / controller / md / sal / binding / impl / AbstractForwardedDataBroker.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.md.sal.binding.impl;
9
10 import com.google.common.base.Objects;
11 import com.google.common.base.Optional;
12 import java.util.Collections;
13 import java.util.HashMap;
14 import java.util.HashSet;
15 import java.util.Map;
16 import java.util.Map.Entry;
17 import java.util.Set;
18 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
19 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
20 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
21 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
22 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
23 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
24 import org.opendaylight.controller.sal.core.api.model.SchemaService;
25 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
26 import org.opendaylight.yangtools.concepts.Delegator;
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.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBroker>, AutoCloseable {
37
38     private static final Logger LOG = LoggerFactory.getLogger(AbstractForwardedDataBroker.class);
39     // The Broker to whom we do all forwarding
40     private final DOMDataBroker domDataBroker;
41
42     private final BindingToNormalizedNodeCodec codec;
43
44     protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker, final BindingToNormalizedNodeCodec codec,
45             final SchemaService schemaService) {
46         this.domDataBroker = domDataBroker;
47         this.codec = codec;
48     }
49
50     protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker, final BindingToNormalizedNodeCodec codec) {
51         this.domDataBroker = domDataBroker;
52         this.codec = codec;
53     }
54
55     protected BindingToNormalizedNodeCodec getCodec() {
56         return codec;
57     }
58
59     @Override
60     public DOMDataBroker getDelegate() {
61         return domDataBroker;
62     }
63
64     public ListenerRegistration<DataChangeListener> registerDataChangeListener(final LogicalDatastoreType store,
65             final InstanceIdentifier<?> path, final DataChangeListener listener, final DataChangeScope triggeringScope) {
66         final DOMDataChangeListener domDataChangeListener = new TranslatingDataChangeInvoker(store, path, listener,
67                 triggeringScope);
68         final YangInstanceIdentifier domPath = codec.toNormalized(path);
69         final ListenerRegistration<DOMDataChangeListener> domRegistration = domDataBroker.registerDataChangeListener(store,
70                 domPath, domDataChangeListener, triggeringScope);
71         return new ListenerRegistrationImpl(listener, domRegistration);
72     }
73
74     protected Map<InstanceIdentifier<?>, DataObject> toBinding(final InstanceIdentifier<?> path,
75             final Map<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized) {
76         final Map<InstanceIdentifier<?>, DataObject> newMap = new HashMap<>();
77
78         for (final Map.Entry<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> entry : normalized.entrySet()) {
79             try {
80                 final Optional<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> potential = getCodec().toBinding(entry);
81                 if (potential.isPresent()) {
82                     final Entry<InstanceIdentifier<? extends DataObject>, DataObject> binding = potential.get();
83                     newMap.put(binding.getKey(), binding.getValue());
84                 }
85             } catch (final DeserializationException e) {
86                 LOG.warn("Failed to transform {}, omitting it", entry, e);
87             }
88         }
89         return newMap;
90     }
91
92     protected Set<InstanceIdentifier<?>> toBinding(final InstanceIdentifier<?> path,
93             final Set<YangInstanceIdentifier> normalized) {
94         final Set<InstanceIdentifier<?>> hashSet = new HashSet<>();
95         for (final YangInstanceIdentifier normalizedPath : normalized) {
96             try {
97                 final Optional<InstanceIdentifier<? extends DataObject>> potential = getCodec().toBinding(normalizedPath);
98                 if (potential.isPresent()) {
99                     final InstanceIdentifier<? extends DataObject> binding = potential.get();
100                     hashSet.add(binding);
101                 } else if (normalizedPath.getLastPathArgument() instanceof YangInstanceIdentifier.AugmentationIdentifier) {
102                     hashSet.add(path);
103                 }
104             } catch (final DeserializationException e) {
105                 LOG.warn("Failed to transform {}, omitting it", normalizedPath, e);
106             }
107         }
108         return hashSet;
109     }
110
111     protected Optional<DataObject> toBindingData(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> data) {
112         if (path.isWildcarded()) {
113             return Optional.absent();
114         }
115         return (Optional<DataObject>) getCodec().deserializeFunction(path).apply(Optional.<NormalizedNode<?, ?>> of(data));
116     }
117
118     private class TranslatingDataChangeInvoker implements DOMDataChangeListener {
119         private final DataChangeListener bindingDataChangeListener;
120         private final LogicalDatastoreType store;
121         private final InstanceIdentifier<?> path;
122         private final DataChangeScope triggeringScope;
123
124         public TranslatingDataChangeInvoker(final LogicalDatastoreType store, final InstanceIdentifier<?> path,
125                 final DataChangeListener bindingDataChangeListener, final DataChangeScope triggeringScope) {
126             this.store = store;
127             this.path = path;
128             this.bindingDataChangeListener = bindingDataChangeListener;
129             this.triggeringScope = triggeringScope;
130         }
131
132         @Override
133         public void onDataChanged(final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
134             bindingDataChangeListener.onDataChanged(new TranslatedDataChangeEvent(change, path));
135         }
136
137         @Override
138         public String toString() {
139             return bindingDataChangeListener.getClass().getName();
140         }
141     }
142
143     private class TranslatedDataChangeEvent implements AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> {
144         private final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> domEvent;
145         private final InstanceIdentifier<?> path;
146
147         private Map<InstanceIdentifier<?>, DataObject> createdCache;
148         private Map<InstanceIdentifier<?>, DataObject> updatedCache;
149         private Map<InstanceIdentifier<?>, DataObject> originalCache;
150         private Set<InstanceIdentifier<?>> removedCache;
151         private Optional<DataObject> originalDataCache;
152         private Optional<DataObject> updatedDataCache;
153
154         public TranslatedDataChangeEvent(
155                 final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change,
156                 final InstanceIdentifier<?> path) {
157             this.domEvent = change;
158             this.path = path;
159         }
160
161         @Override
162         public Map<InstanceIdentifier<?>, DataObject> getCreatedData() {
163             if (createdCache == null) {
164                 createdCache = Collections.unmodifiableMap(toBinding(path, domEvent.getCreatedData()));
165             }
166             return createdCache;
167         }
168
169         @Override
170         public Map<InstanceIdentifier<?>, DataObject> getUpdatedData() {
171             if (updatedCache == null) {
172                 updatedCache = Collections.unmodifiableMap(toBinding(path, domEvent.getUpdatedData()));
173             }
174             return updatedCache;
175
176         }
177
178         @Override
179         public Set<InstanceIdentifier<?>> getRemovedPaths() {
180             if (removedCache == null) {
181                 removedCache = Collections.unmodifiableSet(toBinding(path, domEvent.getRemovedPaths()));
182             }
183             return removedCache;
184         }
185
186         @Override
187         public Map<InstanceIdentifier<?>, DataObject> getOriginalData() {
188             if (originalCache == null) {
189                 originalCache = Collections.unmodifiableMap(toBinding(path, domEvent.getOriginalData()));
190             }
191             return originalCache;
192
193         }
194
195         @Override
196         public DataObject getOriginalSubtree() {
197             if (originalDataCache == null) {
198                 if (domEvent.getOriginalSubtree() != null) {
199                     originalDataCache = toBindingData(path, domEvent.getOriginalSubtree());
200                 } else {
201                     originalDataCache = Optional.absent();
202                 }
203             }
204             return originalDataCache.orNull();
205         }
206
207         @Override
208         public DataObject getUpdatedSubtree() {
209             if (updatedDataCache == null) {
210                 if (domEvent.getUpdatedSubtree() != null) {
211                     updatedDataCache = toBindingData(path, domEvent.getUpdatedSubtree());
212                 } else {
213                     updatedDataCache = Optional.absent();
214                 }
215             }
216             return updatedDataCache.orNull();
217         }
218
219         @Override
220         public String toString() {
221             return Objects.toStringHelper(TranslatedDataChangeEvent.class) //
222                     .add("created", getCreatedData()) //
223                     .add("updated", getUpdatedData()) //
224                     .add("removed", getRemovedPaths()) //
225                     .add("dom", domEvent) //
226                     .toString();
227         }
228     }
229
230     private static class ListenerRegistrationImpl extends AbstractListenerRegistration<DataChangeListener> {
231         private final ListenerRegistration<DOMDataChangeListener> registration;
232
233         public ListenerRegistrationImpl(final DataChangeListener listener,
234                 final ListenerRegistration<DOMDataChangeListener> registration) {
235             super(listener);
236             this.registration = registration;
237         }
238
239         @Override
240         protected void removeRegistration() {
241             registration.close();
242         }
243     }
244
245     @Override
246     public void close() {
247     }
248
249 }