Bug 5528 - Read data impl 64/39464/32
authorJakub Toth <jatoth@cisco.com>
Thu, 26 May 2016 08:32:29 +0000 (10:32 +0200)
committerJakub Toth <jatoth@cisco.com>
Tue, 28 Jun 2016 12:23:21 +0000 (12:23 +0000)
  *impl RestconfDataService
    *util class for constants
  *wrapper for transaction vars

Change-Id: I61f4662b61ac9cf15535492f31bc896a863ce986
Signed-off-by: Jakub Toth <jatoth@cisco.com>
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfDataServiceImpl.java [new file with mode: 0644]
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/transaction/TransactionVarsWrapper.java [new file with mode: 0644]
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureCallbackTx.java [new file with mode: 0644]
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureDataFactory.java [new file with mode: 0644]
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/ReadDataTransactionUtil.java [new file with mode: 0644]
restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/RestconfDataServiceConstant.java [new file with mode: 0644]

diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfDataServiceImpl.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/services/impl/RestconfDataServiceImpl.java
new file mode 100644 (file)
index 0000000..cc34101
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.restful.services.impl;
+
+import com.google.common.base.Preconditions;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriInfo;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
+import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
+import org.opendaylight.netconf.sal.restconf.impl.PATCHContext;
+import org.opendaylight.netconf.sal.restconf.impl.PATCHStatusContext;
+import org.opendaylight.restconf.common.references.SchemaContextRef;
+import org.opendaylight.restconf.handlers.DOMMountPointServiceHandler;
+import org.opendaylight.restconf.handlers.SchemaContextHandler;
+import org.opendaylight.restconf.handlers.TransactionChainHandler;
+import org.opendaylight.restconf.restful.services.api.RestconfDataService;
+import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
+import org.opendaylight.restconf.restful.utils.ReadDataTransactionUtil;
+import org.opendaylight.restconf.restful.utils.RestconfDataServiceConstant;
+import org.opendaylight.restconf.utils.parser.ParserIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Implementation of {@link RestconfDataService}
+ */
+public class RestconfDataServiceImpl implements RestconfDataService {
+
+    private SchemaContextHandler schemaContextHandler;
+    private DOMMountPointServiceHandler domMountPointServiceHandler;
+    private TransactionChainHandler transactionChainHandler;
+
+    @Override
+    public NormalizedNodeContext readData(final String identifier, final UriInfo uriInfo) {
+        Preconditions.checkNotNull(identifier);
+        final SchemaContextRef schemaContextRef = new SchemaContextRef(this.schemaContextHandler.get());
+
+        final InstanceIdentifierContext<?> instanceIdentifier = ParserIdentifier.toInstanceIdentifier(identifier, schemaContextRef.get());
+        final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
+        final String value = uriInfo.getQueryParameters().getFirst(RestconfDataServiceConstant.CONTENT);
+
+        final TransactionVarsWrapper transactionNode = new TransactionVarsWrapper(instanceIdentifier, mountPoint,
+                this.transactionChainHandler.get(), this.domMountPointServiceHandler.get(), schemaContextRef.get());
+        final NormalizedNode<?, ?> node = ReadDataTransactionUtil.readData(value, transactionNode);
+
+        return new NormalizedNodeContext(instanceIdentifier, node);
+    }
+
+    @Override
+    public Response putData(final String identifier, final NormalizedNodeContext payload) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    @Override
+    public Response postData(final String identifier, final NormalizedNodeContext payload, final UriInfo uriInfo) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    @Override
+    public Response postData(final NormalizedNodeContext payload, final UriInfo uriInfo) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    @Override
+    public Response deleteData(final String identifier) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    @Override
+    public PATCHStatusContext patchData(final String identifier, final PATCHContext context, final UriInfo uriInfo) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    @Override
+    public PATCHStatusContext patchData(final PATCHContext context, final UriInfo uriInfo) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+}
diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/transaction/TransactionVarsWrapper.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/transaction/TransactionVarsWrapper.java
new file mode 100644 (file)
index 0000000..3b65762
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.restful.transaction;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+/**
+ * This class represent delegation wrapper for transaction variables.
+ *
+ */
+public final class TransactionVarsWrapper {
+
+    private final InstanceIdentifierContext<?> instanceIdentifier;
+    private final DOMMountPoint mountPoint;
+    private LogicalDatastoreType configuration = null;
+    private final DOMMountPointService domMountPointService;
+    private final SchemaContext schemaContext;
+    private final DOMTransactionChain domTransactionChain;
+
+    /**
+     * Set base type of variables, which ones we need for transaction.
+     * {@link LogicalDatastoreType} is default set to null (to read all data
+     * from ds - config + state).
+     *
+     * @param instanceIdentifier
+     *            - {@link InstanceIdentifierContext} of data for transaction
+     * @param mountPoint
+     *            - mount point if is presnet
+     * @param domTransactionChain
+     *            - {@link DOMTransactionChain} for transactions
+     * @param domMountPointService
+     *            - mount point service
+     * @param schemaContext
+     *            - {@link SchemaContext}
+     */
+    public TransactionVarsWrapper(final InstanceIdentifierContext<?> instanceIdentifier, final DOMMountPoint mountPoint,
+            final DOMTransactionChain domTransactionChain, final DOMMountPointService domMountPointService,
+            final SchemaContext schemaContext) {
+        this.instanceIdentifier = instanceIdentifier;
+        this.mountPoint = mountPoint;
+        this.domTransactionChain = domTransactionChain;
+        this.domMountPointService = domMountPointService;
+        this.schemaContext = schemaContext;
+    }
+
+    /**
+     * Get instance identifier of data
+     *
+     * @return {@link InstanceIdentifierContext}
+     */
+    public InstanceIdentifierContext<?> getInstanceIdentifier() {
+        return this.instanceIdentifier;
+    }
+
+    /**
+     * Get mount point
+     *
+     * @return {@link DOMMountPoint}
+     */
+    public DOMMountPoint getMountPoint() {
+        return this.mountPoint;
+    }
+
+    /**
+     * Set {@link LogicalDatastoreType} of data for transaction.
+     *
+     * @param configuration
+     *            - {@link LogicalDatastoreType}
+     */
+    public void setLogicalDatastoreType(final LogicalDatastoreType configuration) {
+        this.configuration = configuration;
+
+    }
+
+    /**
+     * Get type of data.
+     *
+     * @return {@link LogicalDatastoreType}
+     */
+    public LogicalDatastoreType getLogicalDatastoreType() {
+        return this.configuration;
+    }
+
+    /**
+     * Get mount point service
+     *
+     * @return {@link DOMMountPointService}
+     */
+    public DOMMountPointService getDomMountPointService() {
+        return this.domMountPointService;
+    }
+
+    /**
+     * Get schema context of data
+     *
+     * @return {@link SchemaContext}
+     */
+    public SchemaContext getSchemaContext() {
+        return this.schemaContext;
+    }
+
+    /**
+     * Get transaction chain
+     *
+     * @return {@link DOMTransactionChain}
+     */
+    public DOMTransactionChain getDomTransactionChain() {
+        return this.domTransactionChain;
+    }
+}
diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureCallbackTx.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureCallbackTx.java
new file mode 100644 (file)
index 0000000..a2b95fb
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.restful.utils;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Add callback for future objects and result set to the data factory.
+ *
+ */
+final class FutureCallbackTx {
+
+    private final static Logger LOG = LoggerFactory.getLogger(FutureCallbackTx.class);
+
+    private FutureCallbackTx() {
+        throw new UnsupportedOperationException("Util class");
+    }
+
+    /**
+     * Add callback to the future object
+     *
+     * @param listenableFuture
+     *            - future object
+     * @param transaction
+     *            - transaction used for read of future object
+     * @param txType
+     *            - type of operation (READ, POST, PUT, DELETE)
+     * @param dataFactory
+     *            - factory setting result
+     */
+    static void addCallback(final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> listenableFuture,
+            final AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>> transaction, final String txType,
+            final FutureDataFactory dataFactory) {
+        Futures.addCallback(listenableFuture, new FutureCallback<Optional<NormalizedNode<?, ?>>>() {
+
+            @Override
+            public void onFailure(final Throwable t) {
+                handlingLoggerAndValues(t, txType, transaction, null, null);
+            }
+
+            @Override
+            public void onSuccess(final Optional<NormalizedNode<?, ?>> result) {
+                handlingLoggerAndValues(null, txType, transaction, result, dataFactory);
+            }
+
+        });
+    }
+
+    /**
+     * Handling logger and result of callback - on success or on failure
+     * <ul>
+     * <li>on success - set result to the factory
+     * <li>on failure - throw exception
+     * </ul>
+     *
+     * @param t
+     *            - exception - if callback is onFailure
+     * @param txType
+     *            - type of operation (READ, POST, PUT, DELETE)
+     * @param transaction
+     *            - transaction used for read of future object
+     * @param optionalNN
+     *            - result - if callback is on Success
+     * @param dataFactory
+     *            - setter for result - in callback is onSuccess
+     */
+    protected static void handlingLoggerAndValues(@Nullable final Throwable t, final String txType,
+            final AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>> transaction,
+            final Optional<NormalizedNode<?, ?>> optionalNN, final FutureDataFactory dataFactory) {
+        if (t != null) {
+            LOG.info("Transaction({}) {} FAILED!", txType, transaction.getIdentifier(), t);
+            throw new IllegalStateException("  Transaction(" + txType + ") not committed correctly", t);
+        } else {
+            LOG.trace("Transaction({}) {} SUCCESSFUL!", txType, transaction.getIdentifier());
+            if (optionalNN.isPresent()) {
+                dataFactory.setData(optionalNN.get());
+            }
+        }
+    }
+}
diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureDataFactory.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/FutureDataFactory.java
new file mode 100644 (file)
index 0000000..42f7565
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.restful.utils;
+
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+class FutureDataFactory {
+
+    private NormalizedNode<?, ?> normalizedNode = null;
+
+    public void setData(final NormalizedNode<?, ?> normalizedNode) {
+        this.normalizedNode = normalizedNode;
+    }
+
+    public NormalizedNode<?, ?> getData() {
+        return this.normalizedNode;
+    }
+
+}
diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/ReadDataTransactionUtil.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/ReadDataTransactionUtil.java
new file mode 100644 (file)
index 0000000..a6c4ef6
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.restful.utils;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorTag;
+import org.opendaylight.netconf.sal.restconf.impl.RestconfError.ErrorType;
+import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
+import org.opendaylight.yangtools.yang.common.QNameModule;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ChoiceNode;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafNode;
+import org.opendaylight.yangtools.yang.data.api.schema.LeafSetNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Util class for read data from data store via transaction.
+ * <ul>
+ * <li>config
+ * <li>state
+ * <li>all (config + state)
+ * </ul>
+ *
+ */
+public final class ReadDataTransactionUtil {
+
+    private final static Logger LOG = LoggerFactory.getLogger(ReadDataTransactionUtil.class);
+
+    private ReadDataTransactionUtil() {
+        throw new UnsupportedOperationException("Util class.");
+    }
+
+    /**
+     * Read specific type of data from data store via transaction.
+     *
+     * @param valueOfContent
+     *            - type of data to read (config, state, all)
+     * @param transactionNode
+     *            - {@link TransactionVarsWrapper} - wrapper for variables
+     * @return {@link NormalizedNode}
+     */
+    public static NormalizedNode<?, ?> readData(final String valueOfContent, final TransactionVarsWrapper transactionNode) {
+        if (valueOfContent != null) {
+            switch (valueOfContent) {
+                case RestconfDataServiceConstant.ReadData.CONFIG:
+                    transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
+                    return readData(transactionNode);
+                case RestconfDataServiceConstant.ReadData.NONCONFIG:
+                    transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
+                    return readData(transactionNode);
+                case RestconfDataServiceConstant.ReadData.ALL:
+                    return readData(transactionNode);
+                default:
+                    throw new RestconfDocumentedException("Bad querry parameter for content.", ErrorType.APPLICATION,
+                            ErrorTag.INVALID_VALUE);
+            }
+        } else {
+            return readData(transactionNode);
+        }
+    }
+
+    /**
+     * Check mount point
+     *
+     * @param transactionNode
+     *            - {@link TransactionVarsWrapper} - wrapper for variables
+     * @return {@link NormalizedNode}
+     */
+    private static NormalizedNode<?, ?> readData(final TransactionVarsWrapper transactionNode) {
+        if (transactionNode.getMountPoint() == null) {
+            return readDataViaTransaction(transactionNode.getDomTransactionChain().newReadOnlyTransaction(),
+                    transactionNode);
+        } else {
+            return readDataOfMountPointViaTransaction(transactionNode);
+        }
+    }
+
+    /**
+     * If is set specific {@link LogicalDatastoreType} in
+     * {@link TransactionVarsWrapper}, then read this type of data from DS. If don't,
+     * we have to read all data from DS (state + config)
+     *
+     * @param readTransaction
+     *            - {@link DOMDataReadTransaction} to read data from DS
+     * @param transactionNode
+     *            - {@link TransactionVarsWrapper} - wrapper for variables
+     * @return {@link NormalizedNode}
+     */
+    private static NormalizedNode<?, ?> readDataViaTransaction(final DOMDataReadTransaction readTransaction,
+            final TransactionVarsWrapper transactionNode) {
+        if (transactionNode.getLogicalDatastoreType() != null) {
+            final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> listenableFuture = readTransaction
+                    .read(transactionNode.getLogicalDatastoreType(),
+                            transactionNode.getInstanceIdentifier().getInstanceIdentifier());
+            final FutureDataFactory dataFactory = new FutureDataFactory();
+            FutureCallbackTx.addCallback(listenableFuture, readTransaction,
+                    RestconfDataServiceConstant.ReadData.READ_TYPE_TX, dataFactory);
+            return dataFactory.getData();
+        } else {
+            return readAllData(transactionNode);
+        }
+    }
+
+    /**
+     * Prepare transaction to read data of mount point, if these data are
+     * present.
+     *
+     * @param transactionNode
+     *            - {@link TransactionVarsWrapper} - wrapper for variables
+     * @return {@link NormalizedNode}
+     */
+    private static NormalizedNode<?, ?> readDataOfMountPointViaTransaction(final TransactionVarsWrapper transactionNode) {
+        final Optional<DOMDataBroker> domDataBrokerService = transactionNode.getMountPoint()
+                .getService(DOMDataBroker.class);
+        if (domDataBrokerService.isPresent()) {
+            return readDataViaTransaction(domDataBrokerService.get().newReadOnlyTransaction(), transactionNode);
+        } else {
+            final String errMsg = "DOM data broker service isn't available for mount point "
+                    + transactionNode.getInstanceIdentifier().getInstanceIdentifier();
+            LOG.warn(errMsg);
+            throw new RestconfDocumentedException(errMsg);
+        }
+    }
+
+    /**
+     * Read config and state data, then map them.
+     *
+     * @param transactionNode
+     *            - {@link TransactionVarsWrapper} - wrapper for variables
+     * @return {@link NormalizedNode}
+     */
+    private static NormalizedNode<?, ?> readAllData(final TransactionVarsWrapper transactionNode) {
+        // PREPARE STATE DATA NODE
+        transactionNode.setLogicalDatastoreType(LogicalDatastoreType.OPERATIONAL);
+        final NormalizedNode<?, ?> stateDataNode = readData(transactionNode);
+
+        // PREPARE CONFIG DATA NODE
+        transactionNode.setLogicalDatastoreType(LogicalDatastoreType.CONFIGURATION);
+        final NormalizedNode<?, ?> configDataNode = readData(transactionNode);
+
+        return mapNode(stateDataNode, configDataNode, transactionNode);
+    }
+
+    /**
+     * Map data by type of read node.
+     *
+     * @param stateDataNode
+     *            - data node of state data
+     * @param configDataNode
+     *            - data node of config data
+     * @param transactionNode
+     *            - {@link TransactionVarsWrapper} - wrapper for variables
+     * @return {@link NormalizedNode}
+     */
+    private static NormalizedNode<?, ?> mapNode(final NormalizedNode<?, ?> stateDataNode,
+            final NormalizedNode<?, ?> configDataNode,
+            final TransactionVarsWrapper transactionNode) {
+        validPossibilityOfMergeNodes(stateDataNode, configDataNode);
+        if (configDataNode instanceof RpcDefinition) {
+            return prepareRpcData(configDataNode, stateDataNode);
+        } else {
+            return prepareData(configDataNode, stateDataNode);
+        }
+    }
+
+    /**
+     * Prepare and map data for rpc
+     *
+     * @param configDataNode
+     *            - data node of config data
+     * @param stateDataNode
+     *            - data node of state data
+     * @return {@link NormalizedNode}
+     */
+    private static NormalizedNode<?, ?> prepareRpcData(final NormalizedNode<?, ?> configDataNode,
+            final NormalizedNode<?, ?> stateDataNode) {
+        final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = ImmutableNodes
+                .mapEntryBuilder();
+        mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier());
+
+        // MAP CONFIG DATA
+        mapRpcDataNode(configDataNode, mapEntryBuilder);
+        // MAP STATE DATA
+        mapRpcDataNode(stateDataNode, mapEntryBuilder);
+
+        return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build();
+    }
+
+    /**
+     * Map node to map entry builder.
+     *
+     * @param dataNode
+     *            - data node
+     * @param mapEntryBuilder
+     *            - builder for mapping data
+     */
+    private static void mapRpcDataNode(final NormalizedNode<?, ?> dataNode,
+            final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
+        for (final DataContainerChild<? extends PathArgument, ?> child : ((ContainerNode) dataNode).getValue()) {
+            mapEntryBuilder.addChild(child);
+        }
+    }
+
+    /**
+     * Prepare and map all data from DS
+     *
+     * @param configDataNode
+     *            - data node of config data
+     * @param stateDataNode
+     *            - data node of state data
+     * @return {@link NormalizedNode}
+     */
+    private static NormalizedNode<?, ?> prepareData(final NormalizedNode<?, ?> configDataNode,
+            final NormalizedNode<?, ?> stateDataNode) {
+        final MapNode immutableStateData = ImmutableNodes.mapNodeBuilder(stateDataNode.getNodeType())
+                .addChild((MapEntryNode) stateDataNode).build();
+        final MapNode immutableConfigData = ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType())
+                .addChild((MapEntryNode) configDataNode).build();
+
+        final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder = ImmutableNodes
+                .mapEntryBuilder();
+        mapEntryBuilder.withNodeIdentifier((NodeIdentifierWithPredicates) configDataNode.getIdentifier());
+
+        // MAP CONFIG DATA
+        mapDataNode(immutableConfigData, mapEntryBuilder);
+        // MAP STATE DATA
+        mapDataNode(immutableStateData, mapEntryBuilder);
+
+        return ImmutableNodes.mapNodeBuilder(configDataNode.getNodeType()).addChild(mapEntryBuilder.build()).build();
+    }
+
+    /**
+     * Map data to builder
+     *
+     * @param immutableData
+     *            - immutable data - {@link MapNode}
+     * @param mapEntryBuilder
+     *            - builder for mapping data
+     */
+    private static void mapDataNode(final MapNode immutableData,
+            final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
+        for (final DataContainerChild<? extends PathArgument, ?> child : immutableData.getValue().iterator()
+                .next().getValue()) {
+            Preconditions.checkNotNull(child);
+            if (child instanceof ContainerNode) {
+                addChildToMap(ContainerNode.class, child, mapEntryBuilder);
+            } else if (child instanceof AugmentationNode) {
+                addChildToMap(AugmentationNode.class, child, mapEntryBuilder);
+            } else if(child instanceof MapNode){
+                final MapNode listNode = (MapNode) child;
+                for (final MapEntryNode listChild : listNode.getValue()) {
+                    for (final DataContainerChild<? extends PathArgument, ?> entryChild : listChild.getValue()) {
+                        addChildToMap(MapEntryNode.class, entryChild, mapEntryBuilder);
+                    }
+                }
+            } else if (child instanceof ChoiceNode) {
+                addChildToMap(ChoiceNode.class, child, mapEntryBuilder);
+            } else if ((child instanceof LeafSetNode<?>) || (child instanceof LeafNode)) {
+                mapEntryBuilder.addChild(child);
+            }
+
+        }
+    }
+
+    /**
+     * Mapping child
+     *
+     * @param type
+     *            - type of data
+     * @param child
+     *            - child to map
+     * @param mapEntryBuilder
+     *            - builder for mapping child
+     */
+    private static <T extends DataContainerNode<? extends PathArgument>> void addChildToMap(final Class<T> type,
+            final DataContainerChild<? extends PathArgument, ?> child,
+            final DataContainerNodeBuilder<NodeIdentifierWithPredicates, MapEntryNode> mapEntryBuilder) {
+        @SuppressWarnings("unchecked")
+        final T node = (T) child;
+        for (final DataContainerChild<? extends PathArgument, ?> childNode : node.getValue()) {
+            mapEntryBuilder.addChild(childNode);
+        }
+    }
+
+    /**
+     * Valid of can be data merged together.
+     *
+     * @param stateDataNode
+     *            - data node of state data
+     * @param configDataNode
+     *            - data node of config data
+     */
+    private static void validPossibilityOfMergeNodes(final NormalizedNode<?, ?> stateDataNode,
+            final NormalizedNode<?, ?> configDataNode) {
+        final QNameModule moduleOfStateData = stateDataNode.getIdentifier().getNodeType().getModule();
+        final QNameModule moduleOfConfigData = configDataNode.getIdentifier().getNodeType().getModule();
+        if (moduleOfStateData != moduleOfConfigData) {
+            throw new RestconfDocumentedException("It is not possible to merge ");
+        }
+    }
+
+    /**
+     * Get data from future object if these data are present.
+     *
+     * @param listenableFuture
+     *            - future of optional {@link NormalizedNode}
+     * @param transactionNode
+     *            - {@link TransactionVarsWrapper} - wrapper for variables
+     * @return {@link NormalizedNode}
+     */
+    private static NormalizedNode<?, ?> getNodeFromFuture(
+            final CheckedFuture<Optional<NormalizedNode<?, ?>>, ReadFailedException> listenableFuture,
+            final TransactionVarsWrapper transactionNode) {
+        Optional<NormalizedNode<?, ?>> optional;
+        try {
+            LOG.debug("Reading result data from transaction.");
+            optional = listenableFuture.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Exception by reading {} via Restconf: {}", transactionNode.getLogicalDatastoreType().name(),
+                    transactionNode.getInstanceIdentifier().getInstanceIdentifier(), e);
+            throw new RestconfDocumentedException("Problem to get data from transaction.", e.getCause());
+
+        }
+        if (optional != null) {
+            if (optional.isPresent()) {
+                return optional.get();
+            }
+        }
+        throw new RestconfDocumentedException("Normalized node is not available : "
+                + transactionNode.getInstanceIdentifier().getInstanceIdentifier());
+    }
+}
diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/RestconfDataServiceConstant.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/RestconfDataServiceConstant.java
new file mode 100644 (file)
index 0000000..01cec9e
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.restconf.restful.utils;
+
+/**
+ * Constants for RestconfDataService
+ *
+ */
+public final class RestconfDataServiceConstant {
+
+    public static final String CONTENT = "content";
+
+    private RestconfDataServiceConstant() {
+        throw new UnsupportedOperationException("Util class.");
+    }
+
+    /**
+     * Constants for read data
+     *
+     */
+    public final class ReadData {
+
+        public static final String CONFIG = "config";
+        public static final String NONCONFIG = "nonconfig";
+        public static final String ALL = "all";
+        public static final String READ_TYPE_TX = "READ";
+
+        private ReadData() {
+            throw new UnsupportedOperationException("Util class.");
+        }
+    }
+
+}