Value for transactions moved to yang module
[controller.git] / opendaylight / md-sal / sal-netconf-connector / src / main / java / org / opendaylight / controller / sal / connect / netconf / sal / tx / ReadOnlyTx.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.controller.sal.connect.netconf.sal.tx;
9
10 import com.google.common.base.Function;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.Futures;
16 import com.google.common.util.concurrent.ListenableFuture;
17 import java.util.concurrent.ExecutionException;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
20 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
21 import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
22 import org.opendaylight.controller.sal.connect.netconf.util.NetconfBaseOps;
23 import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
24 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
25 import org.opendaylight.yangtools.util.concurrent.MappingCheckedFuture;
26 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
27 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
29 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33
34
35 public final class ReadOnlyTx implements DOMDataReadOnlyTransaction {
36
37     private static final Logger LOG  = LoggerFactory.getLogger(ReadOnlyTx.class);
38
39     private final NetconfBaseOps netconfOps;
40     private final RemoteDeviceId id;
41     private final FutureCallback<DOMRpcResult> loggingCallback;
42
43     public ReadOnlyTx(final NetconfBaseOps netconfOps, final RemoteDeviceId id) {
44         this.netconfOps = netconfOps;
45         this.id = id;
46
47         // Simple logging callback to log result of read operation
48         loggingCallback = new FutureCallback<DOMRpcResult>() {
49             @Override
50             public void onSuccess(final DOMRpcResult result) {
51                 if(AbstractWriteTx.isSuccess(result)) {
52                     LOG.trace("{}: Reading data successful", id);
53                 } else {
54                     LOG.warn("{}: Reading data unsuccessful: {}", id, result.getErrors());
55                 }
56
57             }
58
59             @Override
60             public void onFailure(final Throwable t) {
61                 LOG.warn("{}: Reading data failed", id, t);
62             }
63         };
64     }
65
66     private CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readConfigurationData(
67             final YangInstanceIdentifier path) {
68         final ListenableFuture<DOMRpcResult> configRunning = netconfOps.getConfigRunning(loggingCallback, Optional.fromNullable(path));
69
70         final ListenableFuture<Optional<NormalizedNode<?, ?>>> transformedFuture = Futures.transform(configRunning, new Function<DOMRpcResult, Optional<NormalizedNode<?, ?>>>() {
71             @Override
72             public Optional<NormalizedNode<?, ?>> apply(final DOMRpcResult result) {
73                 checkReadSuccess(result, path);
74
75                 final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> dataNode = findDataNode(result);
76                 return NormalizedNodes.findNode(dataNode, path.getPathArguments());
77             }
78         });
79
80         return MappingCheckedFuture.create(transformedFuture, ReadFailedException.MAPPER);
81     }
82
83     private DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> findDataNode(final DOMRpcResult result) {
84         return ((ContainerNode) result.getResult()).getChild(NetconfMessageTransformUtil.toId(NetconfMessageTransformUtil.NETCONF_DATA_QNAME)).get();
85     }
86
87     private void checkReadSuccess(final DOMRpcResult result, final YangInstanceIdentifier path) {
88         try {
89             Preconditions.checkArgument(AbstractWriteTx.isSuccess(result), "%s: Unable to read data: %s, errors: %s", id, path, result.getErrors());
90         } catch (final IllegalArgumentException e) {
91             LOG.warn("{}: Unable to read data: {}, errors: {}", id, path, result.getErrors());
92             throw e;
93         }
94     }
95
96     private CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> readOperationalData(
97             final YangInstanceIdentifier path) {
98         final ListenableFuture<DOMRpcResult> configCandidate = netconfOps.get(loggingCallback, Optional.fromNullable(path));
99
100         // Find data node and normalize its content
101         final ListenableFuture<Optional<NormalizedNode<?, ?>>> transformedFuture = Futures.transform(configCandidate, new Function<DOMRpcResult, Optional<NormalizedNode<?, ?>>>() {
102             @Override
103             public Optional<NormalizedNode<?, ?>> apply(final DOMRpcResult result) {
104                 checkReadSuccess(result, path);
105
106                 final DataContainerChild<? extends YangInstanceIdentifier.PathArgument, ?> dataNode = findDataNode(result);
107                 return NormalizedNodes.findNode(dataNode, path.getPathArguments());
108             }
109         });
110
111         return MappingCheckedFuture.create(transformedFuture, ReadFailedException.MAPPER);
112     }
113
114     @Override
115     public void close() {
116         // NOOP
117     }
118
119     @Override
120     public CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> read(
121             final LogicalDatastoreType store, final YangInstanceIdentifier path) {
122         switch (store) {
123             case CONFIGURATION : {
124                 return readConfigurationData(path);
125             }
126             case OPERATIONAL : {
127                 return readOperationalData(path);
128             }
129         }
130
131         throw new IllegalArgumentException(String.format("%s, Cannot read data %s for %s datastore, unknown datastore type", id, path, store));
132     }
133
134     @Override
135     public CheckedFuture<Boolean, ReadFailedException> exists(final LogicalDatastoreType store, final YangInstanceIdentifier path) {
136         final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> data = read(store, path);
137
138         try {
139             return Futures.immediateCheckedFuture(data.get().isPresent());
140         } catch (InterruptedException | ExecutionException e) {
141             return Futures.immediateFailedCheckedFuture(new ReadFailedException("Exists failed",e));
142         }
143     }
144
145     @Override
146     public Object getIdentifier() {
147         return this;
148     }
149 }