/* * 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.sal.core.compat; import static java.util.Objects.requireNonNull; import com.google.common.base.Optional; import com.google.common.collect.ClassToInstanceMap; import com.google.common.collect.ForwardingObject; import com.google.common.collect.ImmutableClassToInstanceMap; import com.google.common.collect.ImmutableClassToInstanceMap.Builder; import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.SettableFuture; import java.util.Collection; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; import org.eclipse.jdt.annotation.NonNull; import org.opendaylight.controller.md.sal.common.api.MappingCheckedFuture; 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.TransactionChainClosedException; 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.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.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.CommitInfo; import org.opendaylight.mdsal.dom.api.DOMDataTreeReadOperations; import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction; import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction; import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction; import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction; import org.opendaylight.mdsal.dom.api.DOMTransactionChainClosedException; import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.util.concurrent.ExceptionMapper; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate; /** * Adapter between the legacy controller API-based DOMDataBroker and the mdsal API-based DOMDataBroker. * * @author Thomas Pantelis */ @Deprecated public abstract class AbstractLegacyDOMDataBrokerAdapter extends ForwardingObject implements DOMDataBroker { private static final ExceptionMapper COMMIT_EX_MAPPER = new ExceptionMapper("commit", TransactionCommitFailedException.class) { @Override protected TransactionCommitFailedException newWithCause(final String message, final 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 org.opendaylight.mdsal.dom.api.DOMDataBroker delegate; private final ClassToInstanceMap extensions; public AbstractLegacyDOMDataBrokerAdapter(final org.opendaylight.mdsal.dom.api.DOMDataBroker delegate) { this.delegate = delegate; ClassToInstanceMap delegateExtensions = delegate.getExtensions(); Builder extBuilder = ImmutableClassToInstanceMap.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 ListenerRegistration registerDataTreeChangeListener( final DOMDataTreeIdentifier treeId, final L listener) { final org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener delegateListener; if (listener instanceof ClusteredDOMDataTreeChangeListener) { delegateListener = new ClusteredProxyListener(listener); } else { delegateListener = new ProxyListener(listener); } final ListenerRegistration reg = delegateTreeChangeService.registerDataTreeChangeListener(treeId.toMdsal(), delegateListener); return new ListenerRegistration() { @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, delegateCohortRegistry::registerCommitCohort); } extensions = extBuilder.build(); } @Override protected org.opendaylight.mdsal.dom.api.DOMDataBroker delegate() { return delegate; } @Override public Map, 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 legacyChain = new AtomicReference<>(); DOMTransactionChainListener delegateListener = new DOMTransactionChainListener() { @Override @SuppressWarnings("rawtypes") public void onTransactionChainFailed(final org.opendaylight.mdsal.dom.api.DOMTransactionChain chain, final DOMDataTreeTransaction transaction, final Throwable cause) { listener.onTransactionChainFailed(legacyChain.get(), (AsyncTransaction) () -> transaction.getIdentifier(), cause instanceof Exception ? COMMIT_EX_MAPPER.apply((Exception)cause) : cause); } @Override public void onTransactionChainSuccessful(final org.opendaylight.mdsal.dom.api.DOMTransactionChain 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(wrapException(delegateChain::newReadOnlyTransaction)); } @Override public DOMDataReadWriteTransaction newReadWriteTransaction() { return new DOMDataTransactionAdapter(wrapException(delegateChain::newReadWriteTransaction)); } @Override public DOMDataWriteTransaction newWriteOnlyTransaction() { return new DOMDataTransactionAdapter(wrapException(delegateChain::newWriteOnlyTransaction)); } @Override public void close() { delegateChain.close(); } }); return legacyChain.get(); } abstract org.opendaylight.mdsal.dom.api.DOMTransactionChain createDelegateChain( DOMTransactionChainListener listener); static T wrapException(final Supplier supplier) { try { return supplier.get(); } catch (DOMTransactionChainClosedException e) { throw new TransactionChainClosedException("Transaction chain already closed", e); } } private static class DOMDataTransactionAdapter implements DOMDataReadWriteTransaction { private final DOMDataTreeReadOperations readDelegate; private final DOMDataTreeWriteTransaction writeDelegate; private final Object identifier; DOMDataTransactionAdapter(final @NonNull DOMDataTreeReadOperations readDelegate, final Object identifier) { this.readDelegate = requireNonNull(readDelegate); this.identifier = requireNonNull(identifier); this.writeDelegate = null; } DOMDataTransactionAdapter(final @NonNull DOMDataTreeWriteTransaction writeDelegate) { this.writeDelegate = requireNonNull(writeDelegate); this.identifier = writeDelegate.getIdentifier(); this.readDelegate = null; } DOMDataTransactionAdapter(final @NonNull DOMDataTreeReadWriteTransaction rwDelegate) { this.readDelegate = requireNonNull(rwDelegate); this.writeDelegate = rwDelegate; this.identifier = rwDelegate.getIdentifier(); } DOMDataTreeReadOperations readDelegate() { return readDelegate; } DOMDataTreeWriteTransaction writeDelegate() { return writeDelegate; } @Override public Object getIdentifier() { return identifier; } @Override public CheckedFuture>, ReadFailedException> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) { return MappingCheckedFuture.create(readDelegate().read(store.toMdsal(), path).transform( Optional::fromJavaUtil, MoreExecutors.directExecutor()), ReadFailedExceptionAdapter.INSTANCE); } @Override public CheckedFuture exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) { return MappingCheckedFuture.create(readDelegate().exists(store.toMdsal(), path), ReadFailedExceptionAdapter.INSTANCE); } @Override public void delete(final LogicalDatastoreType store, final YangInstanceIdentifier path) { writeDelegate().delete(store.toMdsal(), path); } @Override public void put(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode data) { writeDelegate().put(store.toMdsal(), path, data); } @Override public void merge(final LogicalDatastoreType store, final YangInstanceIdentifier path, final NormalizedNode data) { writeDelegate().merge(store.toMdsal(), path, data); } @Override public boolean cancel() { return writeDelegate().cancel(); } @Override public FluentFuture commit() { final SettableFuture resultFuture = SettableFuture.create(); writeDelegate().commit().addCallback(new FutureCallback() { @Override public void onSuccess(final CommitInfo result) { resultFuture.set(result); } @Override public void onFailure(final Throwable ex) { if (ex instanceof Exception) { resultFuture.setException(COMMIT_EX_MAPPER.apply((Exception)ex)); } else { resultFuture.setException(ex); } } }, MoreExecutors.directExecutor()); return FluentFuture.from(resultFuture); } } private static class DOMDataReadOnlyTransactionAdapter implements DOMDataReadOnlyTransaction { private final DOMDataTreeReadTransaction transaction; private final DOMDataTransactionAdapter adapter; DOMDataReadOnlyTransactionAdapter(final DOMDataTreeReadTransaction delegateTx) { this.transaction = requireNonNull(delegateTx); adapter = new DOMDataTransactionAdapter(delegateTx, transaction.getIdentifier()); } @Override public CheckedFuture>, ReadFailedException> read(final LogicalDatastoreType store, final YangInstanceIdentifier path) { return adapter.read(store, path); } @Override public CheckedFuture exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) { return adapter.exists(store, path); } @Override public Object getIdentifier() { return adapter.getIdentifier(); } @Override public void close() { transaction.close(); } } private static class ProxyListener extends ForwardingObject implements org.opendaylight.mdsal.dom.api.DOMDataTreeChangeListener { private final DOMDataTreeChangeListener delegate; ProxyListener(final DOMDataTreeChangeListener delegate) { this.delegate = requireNonNull(delegate); } @Override public void onDataTreeChanged(Collection changes) { delegate.onDataTreeChanged(changes); } @Override protected DOMDataTreeChangeListener delegate() { return delegate; } } private static final class ClusteredProxyListener extends ProxyListener implements org.opendaylight.mdsal.dom.api.ClusteredDOMDataTreeChangeListener { ClusteredProxyListener(DOMDataTreeChangeListener delegate) { super(delegate); } } }