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