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