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 java.util.Collection;
14 import javax.annotation.Nonnull;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
17 import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
18 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
19 import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
20 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
21 import org.opendaylight.yangtools.yang.common.QNameModule;
22 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
24 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
25 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
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.DataContainerNode;
30 import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
31 import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
32 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
33 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
34 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
35 import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
36 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
37 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeAttrBuilder;
38 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
39 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
42 * Util class for read data from data store via transaction.
46 * <li>all (config + state)
50 public final class ReadDataTransactionUtil {
52 private ReadDataTransactionUtil() {
53 throw new UnsupportedOperationException("Util class.");
57 * Read specific type of data from data store via transaction.
59 * @param valueOfContent
60 * - type of data to read (config, state, all)
61 * @param transactionNode
62 * - {@link TransactionVarsWrapper} - wrapper for variables
63 * @return {@link NormalizedNode}
65 public static NormalizedNode<?, ?> readData(final String valueOfContent, final TransactionVarsWrapper transactionNode) {
66 if (valueOfContent != null) {
67 switch (valueOfContent) {
68 case RestconfDataServiceConstant.ReadData.CONFIG:
69 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
70 return readDataViaTransaction(transactionNode);
71 case RestconfDataServiceConstant.ReadData.NONCONFIG:
72 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
73 return readDataViaTransaction(transactionNode);
74 case RestconfDataServiceConstant.ReadData.ALL:
75 return readDataViaTransaction(transactionNode);
77 throw new RestconfDocumentedException("Bad querry parameter for content.", ErrorType.APPLICATION,
78 ErrorTag.INVALID_VALUE);
81 return readDataViaTransaction(transactionNode);
86 * If is set specific {@link LogicalDatastoreType} in
87 * {@link TransactionVarsWrapper}, then read this type of data from DS. If
88 * don't, we have to read all data from DS (state + config)
90 * @param transactionNode
91 * - {@link TransactionVarsWrapper} - wrapper for variables
92 * @return {@link NormalizedNode}
94 private static NormalizedNode<?, ?> readDataViaTransaction(final TransactionVarsWrapper transactionNode) {
95 if (transactionNode.getLogicalDatastoreType() != null) {
96 final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> listenableFuture = transactionNode
97 .getTransactionChain().newReadOnlyTransaction().read(transactionNode.getLogicalDatastoreType(),
98 transactionNode.getInstanceIdentifier().getInstanceIdentifier());
99 final NormalizedNodeFactory dataFactory = new NormalizedNodeFactory();
100 FutureCallbackTx.addCallback(listenableFuture, RestconfDataServiceConstant.ReadData.READ_TYPE_TX,
102 return dataFactory.build();
104 return readAllData(transactionNode);
109 * Read config and state data, then map them.
111 * @param transactionNode
112 * - {@link TransactionVarsWrapper} - wrapper for variables
113 * @return {@link NormalizedNode}
115 private static NormalizedNode<?, ?> readAllData(final TransactionVarsWrapper transactionNode) {
116 // PREPARE STATE DATA NODE
117 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
118 final NormalizedNode<?, ?> stateDataNode = readDataViaTransaction(transactionNode);
120 // PREPARE CONFIG DATA NODE
121 transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
122 final NormalizedNode<?, ?> configDataNode = readDataViaTransaction(transactionNode);
125 if ((stateDataNode == null) && (configDataNode == null)) {
126 throw new RestconfDocumentedException(
127 "Request could not be completed because the relevant data model content does not exist",
129 ErrorTag.DATA_MISSING);
132 // return config data
133 if (stateDataNode == null) {
134 return configDataNode;
138 if (configDataNode == null) {
139 return stateDataNode;
142 // merge data from config and state
143 return mapNode(stateDataNode, configDataNode);
147 * Map data by type of read node.
149 * @param stateDataNode
150 * - data node of state data
151 * @param configDataNode
152 * - data node of config data
153 * @param transactionNode
154 * - {@link TransactionVarsWrapper} - wrapper for variables
155 * @return {@link NormalizedNode}
157 private static NormalizedNode<?, ?> mapNode(final NormalizedNode<?, ?> stateDataNode,
158 final NormalizedNode<?, ?> configDataNode) {
159 validPossibilityOfMergeNodes(stateDataNode, configDataNode);
160 if (configDataNode instanceof RpcDefinition) {
161 return prepareRpcData(configDataNode, stateDataNode);
163 return prepareData(configDataNode, stateDataNode);
168 * Prepare and map data for rpc
170 * @param configDataNode
171 * - data node of config data
172 * @param stateDataNode
173 * - data node of state data
174 * @return {@link NormalizedNode}
176 private static NormalizedNode<?, ?> prepareRpcData(final NormalizedNode<?, ?> configDataNode,
177 final NormalizedNode<?, ?> stateDataNode) {
178 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = ImmutableNodes
180 mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier());
183 mapRpcDataNode(configDataNode, mapEntryBuilder);
185 mapRpcDataNode(stateDataNode, mapEntryBuilder);
187 return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build();
191 * Map node to map entry builder.
195 * @param mapEntryBuilder
196 * - builder for mapping data
198 private static void mapRpcDataNode(final NormalizedNode<?, ?> dataNode,
199 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
200 for (final DataContainerChild<? extends PathArgument, ?> child : ((ContainerNode) dataNode).getValue()) {
201 mapEntryBuilder.addChild(child);
206 * Prepare and map all data from DS
208 * @param configDataNode
209 * - data node of config data
210 * @param stateDataNode
211 * - data node of state data
212 * @return {@link NormalizedNode}
214 private static NormalizedNode<?, ?> prepareData(final NormalizedNode<?, ?> configDataNode,
215 final NormalizedNode<?, ?> stateDataNode) {
217 if (configDataNode instanceof MapNode) { // part for lists mapping
218 final MapNode immutableStateData = ImmutableNodes.mapNodeBuilder(stateDataNode.getNodeType())
219 .addChild((MapEntryNode) stateDataNode).build();
220 final MapNode immutableConfigData = ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType())
221 .addChild((MapEntryNode) configDataNode).build();
222 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = ImmutableNodes
224 mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier());
227 mapDataNode(immutableConfigData, mapEntryBuilder);
229 mapDataNode(immutableStateData, mapEntryBuilder);
230 return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build();
231 } else if (configDataNode instanceof ContainerNode) { // part for
234 final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder = Builders
235 .containerBuilder((ContainerNode) configDataNode);
237 mapCont(containerBuilder, ((ContainerNode) configDataNode).getValue());
239 mapCont(containerBuilder, ((ContainerNode) stateDataNode).getValue());
241 return containerBuilder.build();
243 throw new RestconfDocumentedException("Bad type of node.");
248 * Map data to builder
250 * @param containerBuilder
251 * - builder for mapping data
253 * - childs of data (container)
255 private static void mapCont(final DataContainerNodeAttrBuilder<NodeIdentifier, ContainerNode> containerBuilder,
256 final Collection<DataContainerChild<? extends PathArgument, ?>> childs) {
257 for (final DataContainerChild<? extends PathArgument, ?> child : childs) {
258 containerBuilder.addChild(child);
263 * Map data to builder
265 * @param immutableData
266 * - immutable data - {@link MapNode}
267 * @param mapEntryBuilder
268 * - builder for mapping data
270 private static void mapDataNode(final MapNode immutableData,
271 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
272 for (final DataContainerChild<? extends PathArgument, ?> child : immutableData.getValue().iterator()
273 .next().getValue()) {
274 Preconditions.checkNotNull(child);
275 if (child instanceof ContainerNode) {
276 addChildToMap(ContainerNode.class, child, mapEntryBuilder);
277 } else if (child instanceof AugmentationNode) {
278 addChildToMap(AugmentationNode.class, child, mapEntryBuilder);
279 } else if(child instanceof MapNode){
280 final MapNode listNode = (MapNode) child;
281 for (final MapEntryNode listChild : listNode.getValue()) {
282 for (final DataContainerChild<? extends PathArgument, ?> entryChild : listChild.getValue()) {
283 addChildToMap(MapEntryNode.class, entryChild, mapEntryBuilder);
286 } else if (child instanceof ChoiceNode) {
287 addChildToMap(ChoiceNode.class, child, mapEntryBuilder);
288 } else if ((child instanceof LeafSetNode<?>) || (child instanceof LeafNode)) {
289 mapEntryBuilder.addChild(child);
302 * @param mapEntryBuilder
303 * - builder for mapping child
305 private static <T extends DataContainerNode<? extends PathArgument>> void addChildToMap(final Class<T> type,
306 final DataContainerChild<? extends PathArgument, ?> child,
307 final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
308 @SuppressWarnings("unchecked")
309 final T node = (T) child;
310 for (final DataContainerChild<? extends PathArgument, ?> childNode : node.getValue()) {
311 mapEntryBuilder.addChild(childNode);
316 * Valid of can be data merged together.
318 * @param stateDataNode
319 * - data node of state data
320 * @param configDataNode
321 * - data node of config data
323 private static void validPossibilityOfMergeNodes(@Nonnull final NormalizedNode<?, ?> stateDataNode,
324 @Nonnull final NormalizedNode<?, ?> configDataNode) {
325 final QNameModule moduleOfStateData = stateDataNode.getIdentifier().getNodeType().getModule();
326 final QNameModule moduleOfConfigData = configDataNode.getIdentifier().getNodeType().getModule();
327 if (moduleOfStateData != moduleOfConfigData) {
328 throw new RestconfDocumentedException("It is not possible to merge ");