7f11d5f17cef8123aed221e1f88d8c8b589cbe22
[controller.git] / opendaylight / md-sal / sal-dom-compat / src / main / java / org / opendaylight / controller / sal / core / 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.sal.core.compat;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.ClassToInstanceMap;
13 import com.google.common.collect.ForwardingObject;
14 import com.google.common.collect.ImmutableClassToInstanceMap;
15 import com.google.common.collect.ImmutableClassToInstanceMap.Builder;
16 import com.google.common.util.concurrent.CheckedFuture;
17 import com.google.common.util.concurrent.FluentFuture;
18 import com.google.common.util.concurrent.FutureCallback;
19 import com.google.common.util.concurrent.Futures;
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.md.sal.common.api.data.AsyncTransaction;
26 import org.opendaylight.controller.md.sal.common.api.data.DataStoreUnavailableException;
27 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
28 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
29 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
30 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
31 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
32 import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataTreeChangeListener;
33 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
34 import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
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.CommitInfo;
44 import org.opendaylight.mdsal.common.api.MappingCheckedFuture;
45 import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohort;
46 import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistration;
47 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
48 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
49 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
50 import org.opendaylight.yangtools.concepts.ListenerRegistration;
51 import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
52 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
53 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
54
55 /**
56  * Adapter between the legacy controller API-based DOMDataBroker and the mdsal API-based DOMDataBroker.
57  *
58  * @author Thomas Pantelis
59  */
60 public class LegacyDOMDataBrokerAdapter extends ForwardingObject implements DOMDataBroker {
61     private static final ExceptionMapper<TransactionCommitFailedException> COMMIT_EX_MAPPER =
62             new ExceptionMapper<TransactionCommitFailedException>("commit", TransactionCommitFailedException.class) {
63         @Override
64         protected TransactionCommitFailedException newWithCause(String message, Throwable cause) {
65             if (cause instanceof org.opendaylight.mdsal.common.api.OptimisticLockFailedException) {
66                 return new OptimisticLockFailedException(cause.getMessage(), cause.getCause());
67             } else if (cause instanceof org.opendaylight.mdsal.common.api.TransactionCommitFailedException) {
68                 Throwable rootCause = cause.getCause();
69                 if (rootCause instanceof org.opendaylight.mdsal.common.api.DataStoreUnavailableException) {
70                     rootCause = new DataStoreUnavailableException(rootCause.getMessage(), rootCause.getCause());
71                 }
72
73                 return new TransactionCommitFailedException(cause.getMessage(), rootCause);
74             }
75
76             return new TransactionCommitFailedException(message, cause);
77         }
78     };
79
80     private final org.opendaylight.mdsal.dom.api.DOMDataBroker delegate;
81     private final ClassToInstanceMap<DOMDataBrokerExtension> extensions;
82
83     public LegacyDOMDataBrokerAdapter(org.opendaylight.mdsal.dom.api.DOMDataBroker delegate) {
84         this.delegate = delegate;
85
86         ClassToInstanceMap<org.opendaylight.mdsal.dom.api.DOMDataBrokerExtension> delegateExtensions =
87                 delegate.getExtensions();
88
89         Builder<DOMDataBrokerExtension> extBuilder = ImmutableClassToInstanceMap.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 org.opendaylight.mdsal.dom.api.DOMDataBroker 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 ? COMMIT_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     private static org.opendaylight.mdsal.common.api.LogicalDatastoreType convert(LogicalDatastoreType datastoreType) {
215         return org.opendaylight.mdsal.common.api.LogicalDatastoreType.valueOf(datastoreType.name());
216     }
217
218     private static class DOMDataTransactionAdapter implements DOMDataReadWriteTransaction {
219         private final DOMDataTreeReadTransaction readDelegate;
220         private final DOMDataTreeWriteTransaction writeDelegate;
221         private final Object identifier;
222
223         DOMDataTransactionAdapter(@Nonnull DOMDataTreeReadTransaction readDelegate) {
224             this.readDelegate = Preconditions.checkNotNull(readDelegate);
225             this.identifier = readDelegate.getIdentifier();
226             this.writeDelegate = null;
227         }
228
229         DOMDataTransactionAdapter(@Nonnull DOMDataTreeWriteTransaction writeDelegate) {
230             this.writeDelegate = Preconditions.checkNotNull(writeDelegate);
231             this.identifier = writeDelegate.getIdentifier();
232             this.readDelegate = null;
233         }
234
235         DOMDataTransactionAdapter(@Nonnull DOMDataTreeReadWriteTransaction rwDelegate) {
236             this.readDelegate = Preconditions.checkNotNull(rwDelegate);
237             this.writeDelegate = rwDelegate;
238             this.identifier = readDelegate.getIdentifier();
239         }
240
241         DOMDataTreeReadTransaction readDelegate() {
242             return readDelegate;
243         }
244
245         DOMDataTreeWriteTransaction writeDelegate() {
246             return writeDelegate;
247         }
248
249         @Override
250         public Object getIdentifier() {
251             return identifier;
252         }
253
254         @Override
255         public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(LogicalDatastoreType store,
256                 YangInstanceIdentifier path) {
257             return MappingCheckedFuture.create(readDelegate().read(convert(store), path).transformAsync(
258                 optional -> Futures.immediateFuture(Optional.fromJavaUtil(optional)), MoreExecutors.directExecutor()),
259                 ReadFailedExceptionAdapter.INSTANCE);
260         }
261
262         @Override
263         public CheckedFuture<Boolean, ReadFailedException> exists(LogicalDatastoreType store,
264                 YangInstanceIdentifier path) {
265             return MappingCheckedFuture.create(readDelegate().exists(convert(store), path),
266                     ReadFailedExceptionAdapter.INSTANCE);
267         }
268
269         @Override
270         public void delete(LogicalDatastoreType store, YangInstanceIdentifier path) {
271             writeDelegate().delete(convert(store), path);
272         }
273
274         @Override
275         public void put(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
276             writeDelegate().put(convert(store), path, data);
277         }
278
279         @Override
280         public void merge(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
281             writeDelegate().merge(convert(store), path, data);
282         }
283
284         @Override
285         public boolean cancel() {
286             return writeDelegate().cancel();
287         }
288
289         @Override
290         public FluentFuture<? extends CommitInfo> commit() {
291             final SettableFuture<CommitInfo> resultFuture = SettableFuture.create();
292             writeDelegate().commit().addCallback(new FutureCallback<CommitInfo>() {
293                 @Override
294                 public void onSuccess(CommitInfo result) {
295                     resultFuture.set(result);
296                 }
297
298                 @Override
299                 public void onFailure(Throwable ex) {
300                     if (ex instanceof Exception) {
301                         resultFuture.setException(COMMIT_EX_MAPPER.apply((Exception)ex));
302                     } else {
303                         resultFuture.setException(ex);
304                     }
305                 }
306             }, MoreExecutors.directExecutor());
307
308             return resultFuture;
309         }
310     }
311
312     private static class DOMDataReadOnlyTransactionAdapter implements DOMDataReadOnlyTransaction {
313         private final DOMDataTransactionAdapter adapter;
314
315         DOMDataReadOnlyTransactionAdapter(DOMDataTreeReadTransaction delegateTx) {
316             adapter = new DOMDataTransactionAdapter(delegateTx);
317         }
318
319         @Override
320         public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(LogicalDatastoreType store,
321                 YangInstanceIdentifier path) {
322             return adapter.read(store, path);
323         }
324
325         @Override
326         public CheckedFuture<Boolean, ReadFailedException> exists(LogicalDatastoreType store,
327                 YangInstanceIdentifier path) {
328             return adapter.exists(store, path);
329         }
330
331         @Override
332         public Object getIdentifier() {
333             return adapter.getIdentifier();
334         }
335
336         @Override
337         public void close() {
338             adapter.readDelegate().close();
339         }
340     }
341 }