Update binding-dom adaptation to remove AugmentationNode
[mdsal.git] / binding / mdsal-binding-dom-adapter / src / main / java / org / opendaylight / mdsal / binding / dom / adapter / AbstractForwardedTransaction.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. 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.mdsal.binding.dom.adapter;
9
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;
13
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;
41
42 abstract class AbstractForwardedTransaction<T extends DOMDataTreeTransaction> implements Delegator<T>,
43         Identifiable<Object> {
44     private static final Logger LOG = LoggerFactory.getLogger(AbstractForwardedTransaction.class);
45
46     private final @NonNull AdapterContext adapterContext;
47     private final @NonNull T delegate;
48
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");
52     }
53
54     @Override
55     public final Object getIdentifier() {
56         return delegate.getIdentifier();
57     }
58
59     @Override
60     public final T getDelegate() {
61         return delegate;
62     }
63
64     protected final <S extends DOMDataTreeTransaction> S getDelegateChecked(final Class<S> txType) {
65         checkState(txType.isInstance(delegate));
66         return txType.cast(delegate);
67     }
68
69     protected final AdapterContext adapterContext() {
70         return adapterContext;
71     }
72
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);
77
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());
83     }
84
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));
92         } else {
93             throw new VerifyException("Unhandled codec " + codec);
94         }
95     }
96
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);
100
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
105             //                   this indirection
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()));
112         } else {
113             return readOps.exists(store, domPath);
114         }
115     }
116
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;
122
123         final var domFuture = requireNonNull(readOps) instanceof DOMDataTreeQueryOperations dtqOps
124             ? dtqOps.execute(store, defaultQuery.asDOMQuery())
125                 : fallbackExecute(readOps, store, defaultQuery.asDOMQuery());
126
127         return domFuture.transform(defaultQuery::toQueryResult, MoreExecutors.directExecutor());
128     }
129
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())
134             .transform(
135                 node -> node.map(data -> DOMQueryEvaluator.evaluateOn(domQuery, data)).orElse(DOMQueryResult.of()),
136                 // TODO: execute on a dedicated thread pool
137                 MoreExecutors.directExecutor());
138     }
139 }