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 org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
14 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
15 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
16 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
17 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
18 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
19 import org.opendaylight.yangtools.yang.common.QNameModule;
20 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
21 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
22 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
23 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
24 import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
26 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
27 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
28 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
29 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
32 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
33 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
34 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
37 * Util class for read data from data store via transaction.
41 * <li>all (config + state)
45 public final class ReadDataTransactionUtil {
47 private ReadDataTransactionUtil() {
48 throw new UnsupportedOperationException("Util class.");
52 * Read specific type of data from data store via transaction.
54 * @param valueOfContent
55 * - type of data to read (config, state, all)
56 * @param transactionNode
57 * - {@link TransactionVarsWrapper} - wrapper for variables
58 * @return {@link NormalizedNode}
60 public static NormalizedNode<?, ?> readData(final String valueOfContent, final TransactionVarsWrapper transactionNode) {
61 if (valueOfContent != null) {
62 switch (valueOfContent) {
63 case RestconfDataServiceConstant.ReadData.CONFIG:
64 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
65 return readDataViaTransaction(transactionNode);
66 case RestconfDataServiceConstant.ReadData.NONCONFIG:
67 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
68 return readDataViaTransaction(transactionNode);
69 case RestconfDataServiceConstant.ReadData.ALL:
70 return readDataViaTransaction(transactionNode);
72 throw new RestconfDocumentedException("Bad querry parameter for content.", ErrorType.APPLICATION,
73 ErrorTag.INVALID_VALUE);
76 return readDataViaTransaction(transactionNode);
81 * If is set specific {@link LogicalDatastoreType} in
82 * {@link TransactionVarsWrapper}, then read this type of data from DS. If
83 * don't, we have to read all data from DS (state + config)
85 * @param transactionNode
86 * - {@link TransactionVarsWrapper} - wrapper for variables
87 * @return {@link NormalizedNode}
89 private static NormalizedNode<?, ?> readDataViaTransaction(final TransactionVarsWrapper transactionNode) {
90 if (transactionNode.getLogicalDatastoreType() != null) {
91 final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> listenableFuture = transactionNode
92 .getTransaction().read(transactionNode.getLogicalDatastoreType(),
93 transactionNode.getInstanceIdentifier().getInstanceIdentifier());
94 final NormalizedNodeFactory dataFactory = new NormalizedNodeFactory();
95 FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
97 return dataFactory.build();
99 return readAllData(transactionNode);
104 * Read config and state data, then map them.
106 * @param transactionNode
107 * - {@link TransactionVarsWrapper} - wrapper for variables
108 * @return {@link NormalizedNode}
110 private static NormalizedNode<?, ?> readAllData(final TransactionVarsWrapper transactionNode) {
111 // PREPARE STATE DATA NODE
112 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
113 final NormalizedNode<?, ?> stateDataNode = readDataViaTransaction(transactionNode);
115 // PREPARE CONFIG DATA NODE
116 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
117 final NormalizedNode<?, ?> configDataNode = readDataViaTransaction(transactionNode);
119 return mapNode(stateDataNode, configDataNode);
123 * Map data by type of read node.
125 * @param stateDataNode
126 * - data node of state data
127 * @param configDataNode
128 * - data node of config data
129 * @param transactionNode
130 * - {@link TransactionVarsWrapper} - wrapper for variables
131 * @return {@link NormalizedNode}
133 private static NormalizedNode<?, ?> mapNode(final NormalizedNode<?, ?> stateDataNode,
134 final NormalizedNode<?, ?> configDataNode) {
135 validPossibilityOfMergeNodes(stateDataNode, configDataNode);
136 if (configDataNode instanceof RpcDefinition) {
137 return prepareRpcData(configDataNode, stateDataNode);
139 return prepareData(configDataNode, stateDataNode);
144 * Prepare and map data for rpc
146 * @param configDataNode
147 * - data node of config data
148 * @param stateDataNode
149 * - data node of state data
150 * @return {@link NormalizedNode}
152 private static NormalizedNode<?, ?> prepareRpcData(final NormalizedNode<?, ?> configDataNode,
153 final NormalizedNode<?, ?> stateDataNode) {
154 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = ImmutableNodes
156 mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier());
159 mapRpcDataNode(configDataNode, mapEntryBuilder);
161 mapRpcDataNode(stateDataNode, mapEntryBuilder);
163 return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build();
167 * Map node to map entry builder.
171 * @param mapEntryBuilder
172 * - builder for mapping data
174 private static void mapRpcDataNode(final NormalizedNode<?, ?> dataNode,
175 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
176 for (final DataContainerChild<? extends PathArgument, ?> child : ((ContainerNode) dataNode).getValue()) {
177 mapEntryBuilder.addChild(child);
182 * Prepare and map all data from DS
184 * @param configDataNode
185 * - data node of config data
186 * @param stateDataNode
187 * - data node of state data
188 * @return {@link NormalizedNode}
190 private static NormalizedNode<?, ?> prepareData(final NormalizedNode<?, ?> configDataNode,
191 final NormalizedNode<?, ?> stateDataNode) {
192 final MapNode immutableStateData = ImmutableNodes.mapNodeBuilder(stateDataNode.getNodeType())
193 .addChild((MapEntryNode) stateDataNode).build();
194 final MapNode immutableConfigData = ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType())
195 .addChild((MapEntryNode) configDataNode).build();
197 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = ImmutableNodes
199 mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier());
202 mapDataNode(immutableConfigData, mapEntryBuilder);
204 mapDataNode(immutableStateData, mapEntryBuilder);
206 return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build();
210 * Map data to builder
212 * @param immutableData
213 * - immutable data - {@link MapNode}
214 * @param mapEntryBuilder
215 * - builder for mapping data
217 private static void mapDataNode(final MapNode immutableData,
218 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
219 for (final DataContainerChild<? extends PathArgument, ?> child : immutableData.getValue().iterator()
220 .next().getValue()) {
221 Preconditions.checkNotNull(child);
222 if (child instanceof ContainerNode) {
223 addChildToMap(ContainerNode.class, child, mapEntryBuilder);
224 } else if (child instanceof AugmentationNode) {
225 addChildToMap(AugmentationNode.class, child, mapEntryBuilder);
226 } else if(child instanceof MapNode){
227 final MapNode listNode = (MapNode) child;
228 for (final MapEntryNode listChild : listNode.getValue()) {
229 for (final DataContainerChild<? extends PathArgument, ?> entryChild : listChild.getValue()) {
230 addChildToMap(MapEntryNode.class, entryChild, mapEntryBuilder);
233 } else if (child instanceof ChoiceNode) {
234 addChildToMap(ChoiceNode.class, child, mapEntryBuilder);
235 } else if ((child instanceof LeafSetNode<?>) || (child instanceof LeafNode)) {
236 mapEntryBuilder.addChild(child);
249 * @param mapEntryBuilder
250 * - builder for mapping child
252 private static <T extends DataContainerNode<? extends PathArgument>> void addChildToMap(final Class<T> type,
253 final DataContainerChild<? extends PathArgument, ?> child,
254 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
255 @SuppressWarnings("unchecked")
256 final T node = (T) child;
257 for (final DataContainerChild<? extends PathArgument, ?> childNode : node.getValue()) {
258 mapEntryBuilder.addChild(childNode);
263 * Valid of can be data merged together.
265 * @param stateDataNode
266 * - data node of state data
267 * @param configDataNode
268 * - data node of config data
270 private static void validPossibilityOfMergeNodes(final NormalizedNode<?, ?> stateDataNode,
271 final NormalizedNode<?, ?> configDataNode) {
272 final QNameModule moduleOfStateData = stateDataNode.getIdentifier().getNodeType().getModule();
273 final QNameModule moduleOfConfigData = configDataNode.getIdentifier().getNodeType().getModule();
274 if (moduleOfStateData != moduleOfConfigData) {
275 throw new RestconfDocumentedException("It is not possible to merge ");