2 * Copyright (c) 2016 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.restconf.restful.utils;
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.util.concurrent.CheckedFuture;
13 import javax.annotation.Nonnull;
14 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
15 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
16 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
17 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
18 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
19 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
20 import org.opendaylight.yangtools.yang.common.QNameModule;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
23 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
27 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
33 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
34 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
35 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
38 * Util class for read data from data store via transaction.
42 * <li>all (config + state)
46 public final class ReadDataTransactionUtil {
48 private ReadDataTransactionUtil() {
49 throw new UnsupportedOperationException("Util class.");
53 * Read specific type of data from data store via transaction.
55 * @param valueOfContent
56 * - type of data to read (config, state, all)
57 * @param transactionNode
58 * - {@link TransactionVarsWrapper} - wrapper for variables
59 * @return {@link NormalizedNode}
61 public static NormalizedNode<?, ?> readData(final String valueOfContent, final TransactionVarsWrapper transactionNode) {
62 if (valueOfContent != null) {
63 switch (valueOfContent) {
64 case RestconfDataServiceConstant.ReadData.CONFIG:
65 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
66 return readDataViaTransaction(transactionNode);
67 case RestconfDataServiceConstant.ReadData.NONCONFIG:
68 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
69 return readDataViaTransaction(transactionNode);
70 case RestconfDataServiceConstant.ReadData.ALL:
71 return readDataViaTransaction(transactionNode);
73 throw new RestconfDocumentedException("Bad querry parameter for content.", ErrorType.APPLICATION,
74 ErrorTag.INVALID_VALUE);
77 return readDataViaTransaction(transactionNode);
82 * If is set specific {@link LogicalDatastoreType} in
83 * {@link TransactionVarsWrapper}, then read this type of data from DS. If
84 * don't, we have to read all data from DS (state + config)
86 * @param transactionNode
87 * - {@link TransactionVarsWrapper} - wrapper for variables
88 * @return {@link NormalizedNode}
90 private static NormalizedNode<?, ?> readDataViaTransaction(final TransactionVarsWrapper transactionNode) {
91 if (transactionNode.getLogicalDatastoreType() != null) {
92 final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> listenableFuture = transactionNode
93 .getTransaction().read(transactionNode.getLogicalDatastoreType(),
94 transactionNode.getInstanceIdentifier().getInstanceIdentifier());
95 final NormalizedNodeFactory dataFactory = new NormalizedNodeFactory();
96 FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
98 return dataFactory.build();
100 return readAllData(transactionNode);
105 * Read config and state data, then map them.
107 * @param transactionNode
108 * - {@link TransactionVarsWrapper} - wrapper for variables
109 * @return {@link NormalizedNode}
111 private static NormalizedNode<?, ?> readAllData(final TransactionVarsWrapper transactionNode) {
112 // PREPARE STATE DATA NODE
113 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
114 final NormalizedNode<?, ?> stateDataNode = readDataViaTransaction(transactionNode);
116 // PREPARE CONFIG DATA NODE
117 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
118 final NormalizedNode<?, ?> configDataNode = readDataViaTransaction(transactionNode);
121 if (stateDataNode == null && configDataNode == null) {
122 throw new RestconfDocumentedException(
123 "Request could not be completed because the relevant data model content does not exist",
125 ErrorTag.DATA_MISSING);
128 // return config data
129 if (stateDataNode == null) {
130 return configDataNode;
134 if (configDataNode == null) {
135 return stateDataNode;
138 // merge data from config and state
139 return mapNode(stateDataNode, configDataNode);
143 * Map data by type of read node.
145 * @param stateDataNode
146 * - data node of state data
147 * @param configDataNode
148 * - data node of config data
149 * @param transactionNode
150 * - {@link TransactionVarsWrapper} - wrapper for variables
151 * @return {@link NormalizedNode}
153 private static NormalizedNode<?, ?> mapNode(final NormalizedNode<?, ?> stateDataNode,
154 final NormalizedNode<?, ?> configDataNode) {
155 validPossibilityOfMergeNodes(stateDataNode, configDataNode);
156 if (configDataNode instanceof RpcDefinition) {
157 return prepareRpcData(configDataNode, stateDataNode);
159 return prepareData(configDataNode, stateDataNode);
164 * Prepare and map data for rpc
166 * @param configDataNode
167 * - data node of config data
168 * @param stateDataNode
169 * - data node of state data
170 * @return {@link NormalizedNode}
172 private static NormalizedNode<?, ?> prepareRpcData(final NormalizedNode<?, ?> configDataNode,
173 final NormalizedNode<?, ?> stateDataNode) {
174 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = ImmutableNodes
176 mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier());
179 mapRpcDataNode(configDataNode, mapEntryBuilder);
181 mapRpcDataNode(stateDataNode, mapEntryBuilder);
183 return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build();
187 * Map node to map entry builder.
191 * @param mapEntryBuilder
192 * - builder for mapping data
194 private static void mapRpcDataNode(final NormalizedNode<?, ?> dataNode,
195 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
196 for (final DataContainerChild<? extends PathArgument, ?> child : ((ContainerNode) dataNode).getValue()) {
197 mapEntryBuilder.addChild(child);
202 * Prepare and map all data from DS
204 * @param configDataNode
205 * - data node of config data
206 * @param stateDataNode
207 * - data node of state data
208 * @return {@link NormalizedNode}
210 private static NormalizedNode<?, ?> prepareData(final NormalizedNode<?, ?> configDataNode,
211 final NormalizedNode<?, ?> stateDataNode) {
212 final MapNode immutableStateData = ImmutableNodes.mapNodeBuilder(stateDataNode.getNodeType())
213 .addChild((MapEntryNode) stateDataNode).build();
214 final MapNode immutableConfigData = ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType())
215 .addChild((MapEntryNode) configDataNode).build();
217 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = ImmutableNodes
219 mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier());
222 mapDataNode(immutableConfigData, mapEntryBuilder);
224 mapDataNode(immutableStateData, mapEntryBuilder);
226 return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build();
230 * Map data to builder
232 * @param immutableData
233 * - immutable data - {@link MapNode}
234 * @param mapEntryBuilder
235 * - builder for mapping data
237 private static void mapDataNode(final MapNode immutableData,
238 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
239 for (final DataContainerChild<? extends PathArgument, ?> child : immutableData.getValue().iterator()
240 .next().getValue()) {
241 Preconditions.checkNotNull(child);
242 if (child instanceof ContainerNode) {
243 addChildToMap(ContainerNode.class, child, mapEntryBuilder);
244 } else if (child instanceof AugmentationNode) {
245 addChildToMap(AugmentationNode.class, child, mapEntryBuilder);
246 } else if(child instanceof MapNode){
247 final MapNode listNode = (MapNode) child;
248 for (final MapEntryNode listChild : listNode.getValue()) {
249 for (final DataContainerChild<? extends PathArgument, ?> entryChild : listChild.getValue()) {
250 addChildToMap(MapEntryNode.class, entryChild, mapEntryBuilder);
253 } else if (child instanceof ChoiceNode) {
254 addChildToMap(ChoiceNode.class, child, mapEntryBuilder);
255 } else if ((child instanceof LeafSetNode<?>) || (child instanceof LeafNode)) {
256 mapEntryBuilder.addChild(child);
269 * @param mapEntryBuilder
270 * - builder for mapping child
272 private static <T extends DataContainerNode<? extends PathArgument>> void addChildToMap(final Class<T> type,
273 final DataContainerChild<? extends PathArgument, ?> child,
274 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
275 @SuppressWarnings("unchecked")
276 final T node = (T) child;
277 for (final DataContainerChild<? extends PathArgument, ?> childNode : node.getValue()) {
278 mapEntryBuilder.addChild(childNode);
283 * Valid of can be data merged together.
285 * @param stateDataNode
286 * - data node of state data
287 * @param configDataNode
288 * - data node of config data
290 private static void validPossibilityOfMergeNodes(@Nonnull final NormalizedNode<?, ?> stateDataNode,
291 @Nonnull final NormalizedNode<?, ?> configDataNode) {
292 final QNameModule moduleOfStateData = stateDataNode.getIdentifier().getNodeType().getModule();
293 final QNameModule moduleOfConfigData = configDataNode.getIdentifier().getNodeType().getModule();
294 if (moduleOfStateData != moduleOfConfigData) {
295 throw new RestconfDocumentedException("It is not possible to merge ");