Convert CDS implementation to use msdal APIs
[controller.git] / opendaylight / md-sal / sal-distributed-datastore / src / main / java / org / opendaylight / controller / cluster / databroker / compat / LegacyDOMDataBrokerAdapter.java
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/databroker/compat/LegacyDOMDataBrokerAdapter.java b/opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/databroker/compat/LegacyDOMDataBrokerAdapter.java
new file mode 100644 (file)
index 0000000..f495037
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ * Copyright (c) 2017 Inocybe Technologies and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.cluster.databroker.compat;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ForwardingObject;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.cluster.databroker.AbstractDOMBroker;
+import org.opendaylight.controller.cluster.datastore.DistributedDataStoreInterface;
+import org.opendaylight.controller.cluster.datastore.compat.LegacyDOMStoreAdapter;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.DataStoreUnavailableException;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
+import org.opendaylight.controller.md.sal.dom.api.ClusteredDOMDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeCommitCohortRegistry;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.mdsal.common.api.MappingCheckedFuture;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohort;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistration;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.util.concurrent.ExceptionMapper;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Adapter between the legacy controller API-based DOMDataBroker and the mdsal API-based DOMDataBroker.
+ *
+ * @author Thomas Pantelis
+ */
+public class LegacyDOMDataBrokerAdapter extends ForwardingObject implements DOMDataBroker {
+    private static final ExceptionMapper<TransactionCommitFailedException> SUBMIT_EX_MAPPER =
+            new ExceptionMapper<TransactionCommitFailedException>("submit", TransactionCommitFailedException.class) {
+        @Override
+        protected TransactionCommitFailedException newWithCause(String message, Throwable cause) {
+            if (cause instanceof org.opendaylight.mdsal.common.api.OptimisticLockFailedException) {
+                return new OptimisticLockFailedException(cause.getMessage(), cause.getCause());
+            } else if (cause instanceof org.opendaylight.mdsal.common.api.TransactionCommitFailedException) {
+                Throwable rootCause = cause.getCause();
+                if (rootCause instanceof org.opendaylight.mdsal.common.api.DataStoreUnavailableException) {
+                    rootCause = new DataStoreUnavailableException(rootCause.getMessage(), rootCause.getCause());
+                }
+
+                return new TransactionCommitFailedException(cause.getMessage(), rootCause);
+            }
+
+            return new TransactionCommitFailedException(message, cause);
+        }
+    };
+
+    private final AbstractDOMBroker delegate;
+    private final Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> extensions;
+
+    public LegacyDOMDataBrokerAdapter(AbstractDOMBroker delegate) {
+        this.delegate = delegate;
+
+        Map<Class<? extends org.opendaylight.mdsal.dom.api.DOMDataBrokerExtension>,
+            org.opendaylight.mdsal.dom.api.DOMDataBrokerExtension> delegateExtensions =
+                delegate.getSupportedExtensions();
+
+        Builder<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> extBuilder = ImmutableMap.builder();
+        final org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService delegateTreeChangeService =
+                (org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService) delegateExtensions.get(
+                        org.opendaylight.mdsal.dom.api.DOMDataTreeChangeService.class);
+        if (delegateTreeChangeService != null) {
+            extBuilder.put(DOMDataTreeChangeService.class, new DOMDataTreeChangeService() {
+                @Override
+                public <L extends DOMDataTreeChangeListener> ListenerRegistration<L> registerDataTreeChangeListener(
+                        DOMDataTreeIdentifier treeId, final L listener) {
+                    final org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener delegateListener;
+                    if (listener instanceof ClusteredDOMDataTreeChangeListener) {
+                        delegateListener = (org.opendaylight.mdsal.dom.api.ClusteredDOMDataTreeChangeListener)
+                            changes -> listener.onDataTreeChanged(changes);
+                    } else {
+                        delegateListener = changes -> listener.onDataTreeChanged(changes);
+                    }
+
+                    final ListenerRegistration<org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener> reg =
+                        delegateTreeChangeService.registerDataTreeChangeListener(
+                            new org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier(convert(treeId.getDatastoreType()),
+                                    treeId.getRootIdentifier()), delegateListener);
+
+                    return new ListenerRegistration<L>() {
+                        @Override
+                        public L getInstance() {
+                            return listener;
+                        }
+
+                        @Override
+                        public void close() {
+                            reg.close();
+                        }
+                    };
+                }
+            });
+        }
+
+        final org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistry delegateCohortRegistry =
+                (org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistry) delegateExtensions.get(
+                        org.opendaylight.mdsal.dom.api.DOMDataTreeCommitCohortRegistry.class);
+        if (delegateCohortRegistry != null) {
+            extBuilder.put(DOMDataTreeCommitCohortRegistry.class, new DOMDataTreeCommitCohortRegistry() {
+                @Override
+                public <T extends DOMDataTreeCommitCohort> DOMDataTreeCommitCohortRegistration<T> registerCommitCohort(
+                        org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier path, T cohort) {
+                    return delegateCohortRegistry.registerCommitCohort(path, cohort);
+                }
+            });
+        }
+
+        extensions = extBuilder.build();
+    }
+
+    @Override
+    protected AbstractDOMBroker delegate() {
+        return delegate;
+    }
+
+    @Override
+    public Map<Class<? extends DOMDataBrokerExtension>, DOMDataBrokerExtension> getSupportedExtensions() {
+        return extensions;
+    }
+
+    @Override
+    public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+        return new DOMDataReadOnlyTransactionAdapter(delegate().newReadOnlyTransaction());
+    }
+
+    @Override
+    public DOMDataReadWriteTransaction newReadWriteTransaction() {
+        return new DOMDataTransactionAdapter(delegate().newReadWriteTransaction());
+    }
+
+    @Override
+    public DOMDataWriteTransaction newWriteOnlyTransaction() {
+        return new DOMDataTransactionAdapter(delegate().newWriteOnlyTransaction());
+    }
+
+    @Override
+    public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+        AtomicReference<DOMTransactionChain> legacyChain = new AtomicReference<>();
+        org.opendaylight.mdsal.common.api.TransactionChainListener delegateListener =
+                new org.opendaylight.mdsal.common.api.TransactionChainListener() {
+            @SuppressWarnings("rawtypes")
+            @Override
+            public void onTransactionChainFailed(final org.opendaylight.mdsal.common.api.TransactionChain<?, ?> chain,
+                    final org.opendaylight.mdsal.common.api.AsyncTransaction<?, ?> transaction, final Throwable cause) {
+                listener.onTransactionChainFailed(legacyChain.get(),
+                        (AsyncTransaction) () -> transaction.getIdentifier(),
+                            cause instanceof Exception ? SUBMIT_EX_MAPPER.apply((Exception)cause) : cause);
+            }
+
+            @Override
+            public void onTransactionChainSuccessful(org.opendaylight.mdsal.common.api.TransactionChain<?, ?> chain) {
+                listener.onTransactionChainSuccessful(legacyChain.get());
+            }
+        };
+
+        final org.opendaylight.mdsal.dom.api.DOMTransactionChain delegateChain =
+                delegate().createTransactionChain(delegateListener);
+        legacyChain.set(new DOMTransactionChain() {
+            @Override
+            public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+                return new DOMDataReadOnlyTransactionAdapter(delegateChain.newReadOnlyTransaction());
+            }
+
+            @Override
+            public DOMDataReadWriteTransaction newReadWriteTransaction() {
+                return new DOMDataTransactionAdapter(delegateChain.newReadWriteTransaction());
+            }
+
+            @Override
+            public DOMDataWriteTransaction newWriteOnlyTransaction() {
+                return new DOMDataTransactionAdapter(delegateChain.newWriteOnlyTransaction());
+            }
+
+            @Override
+            public void close() {
+                delegateChain.close();
+            }
+        });
+
+        return legacyChain.get();
+    }
+
+    @Override
+    public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store,
+            final YangInstanceIdentifier path, final DOMDataChangeListener listener,
+            final DataChangeScope triggeringScope) {
+        org.opendaylight.mdsal.dom.spi.store.DOMStore potentialStore = delegate().getTxFactories().get(convert(store));
+        checkState(potentialStore != null, "Requested logical data store is not available.");
+        checkState(potentialStore instanceof DistributedDataStoreInterface,
+                "Requested logical data store does not support DataChangeListener.");
+        return ((DistributedDataStoreInterface)potentialStore).registerChangeListener(path, listener, triggeringScope);
+    }
+
+    private static org.opendaylight.mdsal.common.api.LogicalDatastoreType convert(LogicalDatastoreType datastoreType) {
+        return org.opendaylight.mdsal.common.api.LogicalDatastoreType.valueOf(datastoreType.name());
+    }
+
+    private static class DOMDataTransactionAdapter implements DOMDataReadWriteTransaction {
+        private final DOMDataTreeReadTransaction readDelegate;
+        private final DOMDataTreeWriteTransaction writeDelegate;
+        private final Object identifier;
+
+        DOMDataTransactionAdapter(@Nonnull DOMDataTreeReadTransaction readDelegate) {
+            this.readDelegate = Preconditions.checkNotNull(readDelegate);
+            this.identifier = readDelegate.getIdentifier();
+            this.writeDelegate = null;
+        }
+
+        DOMDataTransactionAdapter(@Nonnull DOMDataTreeWriteTransaction writeDelegate) {
+            this.writeDelegate = Preconditions.checkNotNull(writeDelegate);
+            this.identifier = writeDelegate.getIdentifier();
+            this.readDelegate = null;
+        }
+
+        DOMDataTransactionAdapter(@Nonnull DOMDataTreeReadWriteTransaction rwDelegate) {
+            this.readDelegate = Preconditions.checkNotNull(rwDelegate);
+            this.writeDelegate = rwDelegate;
+            this.identifier = readDelegate.getIdentifier();
+        }
+
+        DOMDataTreeReadTransaction readDelegate() {
+            return readDelegate;
+        }
+
+        DOMDataTreeWriteTransaction writeDelegate() {
+            return writeDelegate;
+        }
+
+        @Override
+        public Object getIdentifier() {
+            return identifier;
+        }
+
+        @Override
+        public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(LogicalDatastoreType store,
+                YangInstanceIdentifier path) {
+            return MappingCheckedFuture.create(readDelegate().read(convert(store), path),
+                    LegacyDOMStoreAdapter.READ_EX_MAPPER);
+        }
+
+        @Override
+        public CheckedFuture<Boolean, ReadFailedException> exists(LogicalDatastoreType store,
+                YangInstanceIdentifier path) {
+            return MappingCheckedFuture.create(readDelegate().exists(convert(store), path),
+                    LegacyDOMStoreAdapter.READ_EX_MAPPER);
+        }
+
+        @Override
+        public void delete(LogicalDatastoreType store, YangInstanceIdentifier path) {
+            writeDelegate().delete(convert(store), path);
+        }
+
+        @Override
+        public void put(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
+            writeDelegate().put(convert(store), path, data);
+        }
+
+        @Override
+        public void merge(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data) {
+            writeDelegate().merge(convert(store), path, data);
+        }
+
+        @Override
+        public boolean cancel() {
+            return writeDelegate().cancel();
+        }
+
+        @Override
+        public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+            return MappingCheckedFuture.create(writeDelegate().submit(), SUBMIT_EX_MAPPER);
+        }
+
+        @Override
+        public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+            return AbstractDataTransaction.convertToLegacyCommitFuture(submit());
+        }
+    }
+
+    private static class DOMDataReadOnlyTransactionAdapter implements DOMDataReadOnlyTransaction {
+        private final DOMDataTransactionAdapter adapter;
+
+        DOMDataReadOnlyTransactionAdapter(DOMDataTreeReadTransaction delegateTx) {
+            adapter = new DOMDataTransactionAdapter(delegateTx);
+        }
+
+        @Override
+        public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(LogicalDatastoreType store,
+                YangInstanceIdentifier path) {
+            return adapter.read(store, path);
+        }
+
+        @Override
+        public CheckedFuture<Boolean, ReadFailedException> exists(LogicalDatastoreType store,
+                YangInstanceIdentifier path) {
+            return adapter.exists(store, path);
+        }
+
+        @Override
+        public Object getIdentifier() {
+            return adapter.getIdentifier();
+        }
+
+        @Override
+        public void close() {
+            adapter.readDelegate().close();
+        }
+    }
+}