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