Bug 6936 - Fix post request
[netconf.git] / restconf / sal-rest-connector / src / main / java / org / opendaylight / restconf / restful / utils / PostDataTransactionUtil.java
1 /*
2  * Copyright (c) 2016 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.restconf.restful.utils;
9
10 import com.google.common.util.concurrent.CheckedFuture;
11 import java.net.URI;
12 import javax.ws.rs.core.Response;
13 import javax.ws.rs.core.UriBuilder;
14 import javax.ws.rs.core.UriInfo;
15 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
16 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
17 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
18 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
19 import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext;
20 import org.opendaylight.restconf.common.references.SchemaContextRef;
21 import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper;
22 import org.opendaylight.restconf.utils.parser.ParserIdentifier;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
25 import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
26 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
27 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
28 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33  * Util class to post data to DS
34  *
35  */
36 public final class PostDataTransactionUtil {
37
38     private static final Logger LOG = LoggerFactory.getLogger(PostDataTransactionUtil.class);
39
40     private PostDataTransactionUtil() {
41         throw new UnsupportedOperationException("Util class.");
42     }
43
44     /**
45      * Check mount point and prepare variables for post data
46      *
47      * @param uriInfo
48      *
49      * @param payload
50      *            - data
51      * @param transactionNode
52      *            - wrapper for transaction data
53      * @param schemaContextRef
54      *            - reference to actual {@link SchemaContext}
55      * @return {@link CheckedFuture}
56      */
57     public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload,
58             final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef) {
59         final CheckedFuture<Void, TransactionCommitFailedException> future = submitData(
60                 payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(),
61                 transactionNode, schemaContextRef.get());
62         final URI location = PostDataTransactionUtil.resolveLocation(uriInfo, transactionNode, schemaContextRef);
63         final ResponseFactory dataFactory = new ResponseFactory(null, location);
64         FutureCallbackTx.addCallback(future, RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory);
65         return dataFactory.build();
66     }
67
68     /**
69      * Post data by type
70      *
71      * @param path
72      *            - path
73      * @param data
74      *            - data
75      * @param transactionNode
76      *            - wrapper for data to transaction
77      * @param schemaContext
78      *            - schema context of data
79      * @return {@link CheckedFuture}
80      */
81     private static CheckedFuture<Void, TransactionCommitFailedException> submitData(final YangInstanceIdentifier path,
82             final NormalizedNode<?, ?> data, final TransactionVarsWrapper transactionNode,
83             final SchemaContext schemaContext) {
84         final DOMTransactionChain transactionChain = transactionNode.getTransactionChain();
85         final DOMDataReadWriteTransaction transaction = transactionChain.newReadWriteTransaction();
86
87         if (data instanceof MapNode) {
88             boolean merge = false;
89             for (final MapEntryNode child : ((MapNode) data).getValue()) {
90                 final YangInstanceIdentifier childPath = path.node(child.getIdentifier());
91                 TransactionUtil.checkItemDoesNotExists(
92                         transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, childPath,
93                         RestconfDataServiceConstant.PostData.POST_TX_TYPE);
94                 if (!merge) {
95                     merge = true;
96                     TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
97                     final NormalizedNode<?, ?> emptySubTree = ImmutableNodes.fromInstanceId(schemaContext, path);
98                     transaction.merge(LogicalDatastoreType.CONFIGURATION,
99                             YangInstanceIdentifier.create(emptySubTree.getIdentifier()), emptySubTree);
100                 }
101                 transaction.put(LogicalDatastoreType.CONFIGURATION, childPath, child);
102             }
103         } else {
104             TransactionUtil.checkItemDoesNotExists(
105                     transactionChain, transaction, LogicalDatastoreType.CONFIGURATION, path,
106                     RestconfDataServiceConstant.PostData.POST_TX_TYPE);
107
108             TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction);
109             transaction.put(LogicalDatastoreType.CONFIGURATION, path, data);
110         }
111
112         return transaction.submit();
113     }
114
115     /**
116      * Get location from {@link YangInstanceIdentifier} and {@link UriInfo}
117      *
118      * @param uriInfo
119      *            - uri info
120      * @param transactionNode
121      *            - wrapper for data of transaction
122      * @param schemaContextRef
123      *            -reference to {@link SchemaContext}
124      * @return {@link URI}
125      */
126     private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode,
127             final SchemaContextRef schemaContextRef) {
128         if (uriInfo == null) {
129             return null;
130         }
131
132         final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder();
133         uriBuilder.path("data");
134         uriBuilder.path(ParserIdentifier.stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(),
135                 schemaContextRef.get()));
136
137         return uriBuilder.build();
138     }
139 }