f4950379ce5366e3640d4fb765beb1c4bce69dcf
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / databroker / compat / LegacyDOMDataBrokerAdapter.java
1 /*
2  * Copyright (c) 2017 Inocybe Technologies 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.cluster.databroker.compat;
9
10 import static com.google.common.base.Preconditions.checkState;
11
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.collect.ForwardingObject;
15 import com.google.common.collect.ImmutableMap;
16 import com.google.common.collect.ImmutableMap.Builder;
17 import com.google.common.util.concurrent.CheckedFuture;
18 import com.google.common.util.concurrent.ListenableFuture;
19 import java.util.Map;
20 import java.util.concurrent.atomic.AtomicReference;
21 import javax.annotation.Nonnull;
22 import org.opendaylight.controller.cluster.databroker.AbstractDOMBroker;
23 import org.opendaylight.controller.cluster.datastore.DistributedDataStoreInterface;
24 import org.opendaylight.controller.cluster.datastore.compat.LegacyDOMStoreAdapter;
25 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
26 import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
27 import org.opendaylight.controller.md.sal.common.api.data.DataStoreUnavailableException;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
30 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
32 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
33 import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
34 import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataTreeChangeListener;
35 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
36 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
37 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
38 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
39 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
40 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
41 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
42 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeCommitCohortRegistry;
43 import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
44 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
45 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
46 import org.opendaylight.mdsal.common.api.MappingCheckedFuture;
47 import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohort;
48 import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistration;
49 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
50 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
51 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
52 import org.opendaylight.yangtools.concepts.ListenerRegistration;
53 import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
54 import org.opendaylight.yangtools.yang.common.RpcResult;
55 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
56 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
57
58 /**
59  * Adapter between the legacy controller API-based DOMDataBroker and the mdsal API-based DOMDataBroker.
60  *
61  * @author Thomas Pantelis
62  */
63 public class LegacyDOMDataBrokerAdapter extends ForwardingObject implements DOMDataBroker {
64     private static final ExceptionMapper<TransactionCommitFailedException> SUBMIT_EX_MAPPER =
65             new ExceptionMapper<TransactionCommitFailedException>("submit", TransactionCommitFailedException.class) {
66         @Override
67         protected TransactionCommitFailedException newWithCause(String message, Throwable cause) {
68             if (cause instanceof org.opendaylight.mdsal.common.api.OptimisticLockFailedException) {
69                 return new OptimisticLockFailedException(cause.getMessage(), cause.getCause());
70             } else if (cause instanceof org.opendaylight.mdsal.common.api.TransactionCommitFailedException) {
71                 Throwable rootCause = cause.getCause();
72                 if (rootCause instanceof org.opendaylight.mdsal.common.api.DataStoreUnavailableException) {
73                     rootCause = new DataStoreUnavailableException(rootCause.getMessage(), rootCause.getCause());
74                 }
75
76                 return new TransactionCommitFailedException(cause.getMessage(), rootCause);
77             }
78
79             return new TransactionCommitFailedException(message, cause);
80         }
81     };
82
83     private final AbstractDOMBroker delegate;
84     private final Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> extensions;
85
86     public LegacyDOMDataBrokerAdapter(AbstractDOMBroker delegate) {
87         this.delegate = delegate;
88
89         Map<Class<? extends org.opendaylight.mdsal.dom.api.DOMDataBrokerExtension>,
90             org.opendaylight.mdsal.dom.api.DOMDataBrokerExtension> delegateExtensions =
91                 delegate.getSupportedExtensions();
92
93         Builder<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> extBuilder = ImmutableMap.builder();
94         final org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService delegateTreeChangeService =
95                 (org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService) delegateExtensions.get(
96                         org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService.class);
97         if (delegateTreeChangeService != null) {
98             extBuilder.put(DOMDataTreeChangeService.class, new DOMDataTreeChangeService() {
99                 @Override
100                 public <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerDataTreeChangeListener(
101                         DOMDataTreeIdentifier treeId, final L listener) {
102                     final org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener delegateListener;
103                     if (listener instanceof ClusteredDOMDataTreeChangeListener) {
104                         delegateListener = (org.opendaylight.mdsal.dom.api.ClusteredDOMDataTreeChangeListener)
105                             changes -> listener.onDataTreeChanged(changes);
106                     } else {
107                         delegateListener = changes -> listener.onDataTreeChanged(changes);
108                     }
109
110                     final ListenerRegistration<org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener> reg =
111                         delegateTreeChangeService.registerDataTreeChangeListener(
112                             new org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier(convert(treeId.getDatastoreType()),
113                                     treeId.getRootIdentifier()), delegateListener);
114
115                     return new ListenerRegistration<L>() {
116                         @Override
117                         public L getInstance() {
118                             return listener;
119                         }
120
121                         @Override
122                         public void close() {
123                             reg.close();
124                         }
125                     };
126                 }
127             });
128         }
129
130         final org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistry delegateCohortRegistry =
131                 (org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistry) delegateExtensions.get(
132                         org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistry.class);
133         if (delegateCohortRegistry != null) {
134             extBuilder.put(DOMDataTreeCommitCohortRegistry.class, new DOMDataTreeCommitCohortRegistry() {
135                 @Override
136                 public <T extends DOMDataTreeCommitCohort> DOMDataTreeCommitCohortRegistration<T> registerCommitCohort(
137                         org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier path, T cohort) {
138                     return delegateCohortRegistry.registerCommitCohort(path, cohort);
139                 }
140             });
141         }
142
143         extensions = extBuilder.build();
144     }
145
146     @Override
147     protected AbstractDOMBroker delegate() {
148         return delegate;
149     }
150
151     @Override
152     public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() {
153         return extensions;
154     }
155
156     @Override
157     public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
158         return new DOMDataReadOnlyTransactionAdapter(delegate().newReadOnlyTransaction());
159     }
160
161     @Override
162     public DOMDataReadWriteTransaction newReadWriteTransaction() {
163         return new DOMDataTransactionAdapter(delegate().newReadWriteTransaction());
164     }
165
166     @Override
167     public DOMDataWriteTransaction newWriteOnlyTransaction() {
168         return new DOMDataTransactionAdapter(delegate().newWriteOnlyTransaction());
169     }
170
171     @Override
172     public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
173         AtomicReference<DOMTransactionChain> legacyChain = new AtomicReference<>();
174         org.opendaylight.mdsal.common.api.TransactionChainListener delegateListener =
175                 new org.opendaylight.mdsal.common.api.TransactionChainListener() {
176             @SuppressWarnings("rawtypes")
177             @Override
178             public void onTransactionChainFailed(final org.opendaylight.mdsal.common.api.TransactionChain<?, ?> chain,
179                     final org.opendaylight.mdsal.common.api.AsyncTransaction<?, ?> transaction, final Throwable cause) {
180                 listener.onTransactionChainFailed(legacyChain.get(),
181                         (AsyncTransaction) () -> transaction.getIdentifier(),
182                             cause instanceof Exception ? SUBMIT_EX_MAPPER.apply((Exception)cause) : cause);
183             }
184
185             @Override
186             public void onTransactionChainSuccessful(org.opendaylight.mdsal.common.api.TransactionChain<?, ?> chain) {
187                 listener.onTransactionChainSuccessful(legacyChain.get());
188             }
189         };
190
191         final org.opendaylight.mdsal.dom.api.DOMTransactionChain delegateChain =
192                 delegate().createTransactionChain(delegateListener);
193         legacyChain.set(new DOMTransactionChain() {
194             @Override
195             public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
196                 return new DOMDataReadOnlyTransactionAdapter(delegateChain.newReadOnlyTransaction());
197             }
198
199             @Override
200             public DOMDataReadWriteTransaction newReadWriteTransaction() {
201                 return new DOMDataTransactionAdapter(delegateChain.newReadWriteTransaction());
202             }
203
204             @Override
205             public DOMDataWriteTransaction newWriteOnlyTransaction() {
206                 return new DOMDataTransactionAdapter(delegateChain.newWriteOnlyTransaction());
207             }
208
209             @Override
210             public void close() {
211                 delegateChain.close();
212             }
213         });
214
215         return legacyChain.get();
216     }
217
218     @Override
219     public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store,
220             final YangInstanceIdentifier path, final DOMDataChangeListener listener,
221             final DataChangeScope triggeringScope) {
222         org.opendaylight.mdsal.dom.spi.store.DOMStore potentialStore = delegate().getTxFactories().get(convert(store));
223         checkState(potentialStore != null, "Requested logical data store is not available.");
224         checkState(potentialStore instanceof DistributedDataStoreInterface,
225                 "Requested logical data store does not support DataChangeListener.");
226         return ((DistributedDataStoreInterface)potentialStore).registerChangeListener(path, listener, triggeringScope);
227     }
228
229     private static org.opendaylight.mdsal.common.api.LogicalDatastoreType convert(LogicalDatastoreType datastoreType) {
230         return org.opendaylight.mdsal.common.api.LogicalDatastoreType.valueOf(datastoreType.name());
231     }
232
233     private static class DOMDataTransactionAdapter implements DOMDataReadWriteTransaction {
234         private final DOMDataTreeReadTransaction readDelegate;
235         private final DOMDataTreeWriteTransaction writeDelegate;
236         private final Object identifier;
237
238         DOMDataTransactionAdapter(@Nonnull DOMDataTreeReadTransaction readDelegate) {
239             this.readDelegate = Preconditions.checkNotNull(readDelegate);
240             this.identifier = readDelegate.getIdentifier();
241             this.writeDelegate = null;
242         }
243
244         DOMDataTransactionAdapter(@Nonnull DOMDataTreeWriteTransaction writeDelegate) {
245             this.writeDelegate = Preconditions.checkNotNull(writeDelegate);
246             this.identifier = writeDelegate.getIdentifier();
247             this.readDelegate = null;
248         }
249
250         DOMDataTransactionAdapter(@Nonnull DOMDataTreeReadWriteTransaction rwDelegate) {
251             this.readDelegate = Preconditions.checkNotNull(rwDelegate);
252             this.writeDelegate = rwDelegate;
253             this.identifier = readDelegate.getIdentifier();
254         }
255
256         DOMDataTreeReadTransaction readDelegate() {
257             return readDelegate;
258         }
259
260         DOMDataTreeWriteTransaction writeDelegate() {
261             return writeDelegate;
262         }
263
264         @Override
265         public Object getIdentifier() {
266             return identifier;
267         }
268
269         @Override
270         public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(LogicalDatastoreType store,
271                 YangInstanceIdentifier path) {
272             return MappingCheckedFuture.create(readDelegate().read(convert(store), path),
273                     LegacyDOMStoreAdapter.READ_EX_MAPPER);
274         }
275
276         @Override
277         public CheckedFuture<Boolean, ReadFailedException> exists(LogicalDatastoreType store,
278                 YangInstanceIdentifier path) {
279             return MappingCheckedFuture.create(readDelegate().exists(convert(store), path),
280                     LegacyDOMStoreAdapter.READ_EX_MAPPER);
281         }
282
283         @Override
284         public void delete(LogicalDatastoreType store, YangInstanceIdentifier path) {
285             writeDelegate().delete(convert(store), path);
286         }
287
288         @Override
289         public void put(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
290             writeDelegate().put(convert(store), path, data);
291         }
292
293         @Override
294         public void merge(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
295             writeDelegate().merge(convert(store), path, data);
296         }
297
298         @Override
299         public boolean cancel() {
300             return writeDelegate().cancel();
301         }
302
303         @Override
304         public CheckedFuture<Void, TransactionCommitFailedException> submit() {
305             return MappingCheckedFuture.create(writeDelegate().submit(), SUBMIT_EX_MAPPER);
306         }
307
308         @Override
309         public ListenableFuture<RpcResult<TransactionStatus>> commit() {
310             return AbstractDataTransaction.convertToLegacyCommitFuture(submit());
311         }
312     }
313
314     private static class DOMDataReadOnlyTransactionAdapter implements DOMDataReadOnlyTransaction {
315         private final DOMDataTransactionAdapter adapter;
316
317         DOMDataReadOnlyTransactionAdapter(DOMDataTreeReadTransaction delegateTx) {
318             adapter = new DOMDataTransactionAdapter(delegateTx);
319         }
320
321         @Override
322         public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(LogicalDatastoreType store,
323                 YangInstanceIdentifier path) {
324             return adapter.read(store, path);
325         }
326
327         @Override
328         public CheckedFuture<Boolean, ReadFailedException> exists(LogicalDatastoreType store,
329                 YangInstanceIdentifier path) {
330             return adapter.exists(store, path);
331         }
332
333         @Override
334         public Object getIdentifier() {
335             return adapter.getIdentifier();
336         }
337
338         @Override
339         public void close() {
340             adapter.readDelegate().close();
341         }
342     }
343 }