2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding.dom.adapter;
10 import static com.google.common.base.Preconditions.checkArgument;
11 import static com.google.common.base.Preconditions.checkState;
12 import static java.util.Objects.requireNonNull;
14 import com.google.common.base.VerifyException;
15 import com.google.common.collect.ImmutableList;
16 import com.google.common.util.concurrent.FluentFuture;
17 import com.google.common.util.concurrent.Futures;
18 import com.google.common.util.concurrent.MoreExecutors;
19 import java.util.Optional;
20 import org.eclipse.jdt.annotation.NonNull;
21 import org.opendaylight.mdsal.binding.api.query.QueryExpression;
22 import org.opendaylight.mdsal.binding.api.query.QueryResult;
23 import org.opendaylight.mdsal.binding.dom.adapter.query.DefaultQuery;
24 import org.opendaylight.mdsal.binding.dom.codec.api.BindingAugmentationCodecTreeNode;
25 import org.opendaylight.mdsal.binding.dom.codec.api.BindingDataObjectCodecTreeNode;
26 import org.opendaylight.mdsal.binding.dom.codec.api.CommonDataObjectCodecTreeNode;
27 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
28 import org.opendaylight.mdsal.dom.api.DOMDataTreeQueryOperations;
29 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadOperations;
30 import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
31 import org.opendaylight.mdsal.dom.api.query.DOMQuery;
32 import org.opendaylight.mdsal.dom.api.query.DOMQueryResult;
33 import org.opendaylight.mdsal.dom.spi.query.DOMQueryEvaluator;
34 import org.opendaylight.yangtools.concepts.Delegator;
35 import org.opendaylight.yangtools.concepts.Identifiable;
36 import org.opendaylight.yangtools.yang.binding.DataObject;
37 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
38 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
39 import org.slf4j.Logger;
40 import org.slf4j.LoggerFactory;
42 abstract class AbstractForwardedTransaction<T extends DOMDataTreeTransaction> implements Delegator<T>,
43 Identifiable<Object> {
44 private static final Logger LOG = LoggerFactory.getLogger(AbstractForwardedTransaction.class);
46 private final @NonNull AdapterContext adapterContext;
47 private final @NonNull T delegate;
49 AbstractForwardedTransaction(final AdapterContext adapterContext, final T delegateTx) {
50 this.adapterContext = requireNonNull(adapterContext, "Codec must not be null");
51 delegate = requireNonNull(delegateTx, "Delegate must not be null");
55 public final Object getIdentifier() {
56 return delegate.getIdentifier();
60 public final T getDelegate() {
64 protected final <S extends DOMDataTreeTransaction> S getDelegateChecked(final Class<S> txType) {
65 checkState(txType.isInstance(delegate));
66 return txType.cast(delegate);
69 protected final AdapterContext adapterContext() {
70 return adapterContext;
73 protected final <D extends DataObject> @NonNull FluentFuture<Optional<D>> doRead(
74 final DOMDataTreeReadOperations readOps, final LogicalDatastoreType store,
75 final InstanceIdentifier<D> path) {
76 checkArgument(!path.isWildcarded(), "Invalid read of wildcarded path %s", path);
78 final var codecWithPath = adapterContext.currentSerializer().getSubtreeCodecWithPath(path);
79 final var domPath = codecWithPath.path();
80 final var codec = codecWithPath.codec();
81 return readOps.read(store, domPath)
82 .transform(optData -> optData.flatMap(data -> decodeRead(codec, data)), MoreExecutors.directExecutor());
85 @SuppressWarnings("unchecked")
86 private static <D extends DataObject> Optional<D> decodeRead(final CommonDataObjectCodecTreeNode<D> codec,
87 final @NonNull NormalizedNode data) {
88 if (codec instanceof BindingDataObjectCodecTreeNode<?> dataObject) {
89 return Optional.of((D) dataObject.deserialize(data));
90 } else if (codec instanceof BindingAugmentationCodecTreeNode<?> augment) {
91 return Optional.ofNullable((D) augment.filterFrom(data));
93 throw new VerifyException("Unhandled codec " + codec);
97 protected final @NonNull FluentFuture<Boolean> doExists(final DOMDataTreeReadOperations readOps,
98 final LogicalDatastoreType store, final InstanceIdentifier<?> path) {
99 checkArgument(!path.isWildcarded(), "Invalid exists of wildcarded path %s", path);
101 final var codecWithPath = adapterContext.currentSerializer().getSubtreeCodecWithPath(path);
102 final var domPath = codecWithPath.path();
103 if (codecWithPath.codec() instanceof BindingAugmentationCodecTreeNode<?> augment) {
104 // Complicated case: we need to check if any of the children exist, as DOM layer just does not know about
106 return FluentFuture.from(Futures.transform(
107 Futures.allAsList(augment.childPathArguments().stream()
108 .map(child -> readOps.exists(store, domPath.node(child)))
109 .collect(ImmutableList.toImmutableList())),
110 children -> children.contains(Boolean.TRUE),
111 MoreExecutors.directExecutor()));
113 return readOps.exists(store, domPath);
117 protected static final <T extends @NonNull DataObject> @NonNull FluentFuture<QueryResult<T>> doExecute(
118 final DOMDataTreeReadOperations readOps, final @NonNull LogicalDatastoreType store,
119 final @NonNull QueryExpression<T> query) {
120 checkArgument(query instanceof DefaultQuery, "Unsupported query type %s", query);
121 final var defaultQuery = (DefaultQuery<T>) query;
123 final var domFuture = requireNonNull(readOps) instanceof DOMDataTreeQueryOperations dtqOps
124 ? dtqOps.execute(store, defaultQuery.asDOMQuery())
125 : fallbackExecute(readOps, store, defaultQuery.asDOMQuery());
127 return domFuture.transform(defaultQuery::toQueryResult, MoreExecutors.directExecutor());
130 private static FluentFuture<DOMQueryResult> fallbackExecute(final @NonNull DOMDataTreeReadOperations readOps,
131 final @NonNull LogicalDatastoreType store, final @NonNull DOMQuery domQuery) {
132 LOG.trace("Fallback evaluation of {} on {}", domQuery, readOps);
133 return readOps.read(store, domQuery.getRoot())
135 node -> node.map(data -> DOMQueryEvaluator.evaluateOn(domQuery, data)).orElse(DOMQueryResult.of()),
136 // TODO: execute on a dedicated thread pool
137 MoreExecutors.directExecutor());