X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=restconf%2Fsal-rest-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Frestconf%2Frestful%2Futils%2FPostDataTransactionUtil.java;fp=restconf%2Fsal-rest-connector%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Frestconf%2Frestful%2Futils%2FPostDataTransactionUtil.java;h=2d9c246ac256af6300f4f44436d792e1fb23f91c;hb=96fa29a30499d4ae0ad21cb9a5c8fe9d401512a4;hp=0000000000000000000000000000000000000000;hpb=b2fd55e123e82a350337c3733e0809a6f8a02fb3;p=netconf.git diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PostDataTransactionUtil.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PostDataTransactionUtil.java new file mode 100644 index 0000000000..2d9c246ac2 --- /dev/null +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PostDataTransactionUtil.java @@ -0,0 +1,191 @@ +/* + * 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.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.ListenableFuture; +import java.net.URI; +import java.util.concurrent.ExecutionException; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.UriInfo; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; +import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext; +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.common.references.SchemaContextRef; +import org.opendaylight.restconf.restful.transaction.TransactionVarsWrapper; +import org.opendaylight.restconf.utils.parser.ParserIdentifier; +import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; +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.LeafSetEntryNode; +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.model.api.SchemaContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Util class to post data to DS + * + */ +public final class PostDataTransactionUtil { + + private static final Logger LOG = LoggerFactory.getLogger(PostDataTransactionUtil.class); + + private PostDataTransactionUtil() { + throw new UnsupportedOperationException("Util class."); + } + + /** + * Check mount point and prepare variables for post data + * + * @param uriInfo + * + * @param payload + * - data + * @param transactionNode + * - wrapper for transaction data + * @param schemaContextRef + * - reference to actual {@link SchemaContext} + * @return {@link CheckedFuture} + */ + public static Response postData(final UriInfo uriInfo, final NormalizedNodeContext payload, + final TransactionVarsWrapper transactionNode, final SchemaContextRef schemaContextRef) { + final CheckedFuture future = submitData( + payload.getInstanceIdentifierContext().getInstanceIdentifier(), payload.getData(), + transactionNode, schemaContextRef.get()); + final URI location = PostDataTransactionUtil.resolveLocation(uriInfo, transactionNode, schemaContextRef); + final ResponseFactory dataFactory = new ResponseFactory( + ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.CONFIG, transactionNode), + location); + FutureCallbackTx.addCallback(future, transactionNode.getTransaction(), + RestconfDataServiceConstant.PostData.POST_TX_TYPE, dataFactory); + return dataFactory.build(); + } + + /** + * Post data by type + * + * @param path + * - path + * @param data + * - data + * @param transactionNode + * - wrapper for data to transaction + * @param schemaContext + * - schema context of data + * @return {@link CheckedFuture} + */ + private static CheckedFuture submitData(final YangInstanceIdentifier path, + final NormalizedNode data, final TransactionVarsWrapper transactionNode, + final SchemaContext schemaContext) { + final DOMDataReadWriteTransaction transaction = transactionNode.getTransaction(); + final NormalizedNode node = ImmutableNodes.fromInstanceId(schemaContext, path); + transaction.put(LogicalDatastoreType.CONFIGURATION, YangInstanceIdentifier.create(node.getIdentifier()), node); + TransactionUtil.ensureParentsByMerge(path, schemaContext, transaction); + + if (data instanceof MapNode) { + for (final MapEntryNode child : ((MapNode) data).getValue()) { + putChild(child, transaction, path); + } + } else if (data instanceof AugmentationNode) { + for (final DataContainerChild child : ((AugmentationNode) data).getValue()) { + putChild(child, transaction, path); + } + } else if (data instanceof ChoiceNode) { + for (final DataContainerChild child : ((ChoiceNode) data).getValue()) { + putChild(child, transaction, path); + } + } else if (data instanceof LeafSetNode) { + for (final LeafSetEntryNode child : ((LeafSetNode) data).getValue()) { + putChild(child, transaction, path); + } + } else if (data instanceof ContainerNode) { + for (final DataContainerChild child : ((ContainerNode) data).getValue()) { + putChild(child, transaction, path); + } + } + return transaction.submit(); + } + + /** + * Prepare data for submit + * + * @param child + * - data + * @param readWriteTx + * - transaction + * @param path + * - path to data + */ + private static void putChild(final NormalizedNode child, final DOMDataReadWriteTransaction readWriteTx, + final YangInstanceIdentifier path) { + final YangInstanceIdentifier childPath = path.node(child.getIdentifier()); + checkItemDesNotExits(childPath, readWriteTx); + readWriteTx.put(LogicalDatastoreType.CONFIGURATION, childPath, child); + } + + /** + * Check if data posted to create doesn't exits. + * + * @param path + * - path to data + * @param readWriteTx + * - read write transaction + */ + private static void checkItemDesNotExits(final YangInstanceIdentifier path, + final DOMDataReadWriteTransaction readWriteTx) { + final ListenableFuture existData = readWriteTx.exists(LogicalDatastoreType.CONFIGURATION, path); + try { + if (existData.get()) { + readWriteTx.cancel(); + throw new RestconfDocumentedException("Data already exists for path: " + path, ErrorType.PROTOCOL, + ErrorTag.DATA_EXISTS); + } + } catch (InterruptedException | ExecutionException e) { + LOG.warn("It wasn't possible to get data loaded from datastore at path {}", path, e); + } + } + + /** + * Get location from {@link YangInstanceIdentifier} and {@link UriInfo} + * + * @param uriInfo + * - uri info + * @param transactionNode + * - wrapper for data of transaction + * @param schemaContextRef + * -reference to {@link SchemaContext} + * @return {@link URI} + */ + private static URI resolveLocation(final UriInfo uriInfo, final TransactionVarsWrapper transactionNode, + final SchemaContextRef schemaContextRef) { + if (uriInfo == null) { + return null; + } + + final UriBuilder uriBuilder = uriInfo.getBaseUriBuilder(); + uriBuilder.path("data"); + uriBuilder.path(ParserIdentifier.stringFromYangInstanceIdentifier(transactionNode.getInstanceIdentifier().getInstanceIdentifier(), + schemaContextRef.get())); + + return uriBuilder.build(); + } +} +