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%2FPutDataTransactionUtil.java;h=19fb343d11e39c40ed9e86bdfde21c61b6ebed7f;hb=d434f750405b4509121900b677a80402c077b422;hp=698a4787cb559ea5ef5ce8ffd9b5e50b2e633b08;hpb=96fa29a30499d4ae0ad21cb9a5c8fe9d401512a4;p=netconf.git diff --git a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PutDataTransactionUtil.java b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PutDataTransactionUtil.java index 698a4787cb..19fb343d11 100644 --- a/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PutDataTransactionUtil.java +++ b/restconf/sal-rest-connector/src/main/java/org/opendaylight/restconf/restful/utils/PutDataTransactionUtil.java @@ -14,8 +14,11 @@ import java.util.Map; import javax.ws.rs.core.Response; 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.controller.md.sal.dom.api.DOMDataWriteTransaction; +import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain; import org.opendaylight.netconf.md.sal.rest.common.RestconfValidationUtils; +import org.opendaylight.netconf.sal.restconf.impl.ControllerContext; import org.opendaylight.netconf.sal.restconf.impl.InstanceIdentifierContext; import org.opendaylight.netconf.sal.restconf.impl.NormalizedNodeContext; import org.opendaylight.netconf.sal.restconf.impl.RestconfDocumentedException; @@ -27,8 +30,18 @@ import org.opendaylight.yangtools.yang.common.QName; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; 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.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.api.schema.OrderedLeafSetNode; +import org.opendaylight.yangtools.yang.data.api.schema.OrderedMapNode; +import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; +import org.opendaylight.yangtools.yang.data.util.DataSchemaContextNode; +import org.opendaylight.yangtools.yang.data.util.DataSchemaContextTree; +import org.opendaylight.yangtools.yang.model.api.DataSchemaNode; +import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode; import org.opendaylight.yangtools.yang.model.api.ListSchemaNode; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.api.SchemaNode; @@ -131,17 +144,21 @@ public final class PutDataTransactionUtil { * @param schemaCtxRef * - reference to {@link SchemaContext} * @param transactionNode + * - wrapper of variables for transaction + * @param point + * - query parameter + * @param insert + * - query parameter * @return {@link CheckedFuture} */ public static Response putData(final NormalizedNodeContext payload, - final SchemaContextRef schemaCtxRef, final TransactionVarsWrapper transactionNode) { + final SchemaContextRef schemaCtxRef, final TransactionVarsWrapper transactionNode, final String insert, final String point) { final YangInstanceIdentifier path = payload.getInstanceIdentifierContext().getInstanceIdentifier(); final ResponseFactory responseFactory = new ResponseFactory( ReadDataTransactionUtil.readData(RestconfDataServiceConstant.ReadData.CONFIG, transactionNode)); final CheckedFuture submitData = submitData(path, schemaCtxRef.get(), - transactionNode.getTransaction(), payload.getData()); - FutureCallbackTx.addCallback(submitData, transactionNode.getTransaction(), - RestconfDataServiceConstant.PutData.PUT_TX_TYPE, responseFactory); + transactionNode.getTransactionChain(), payload.getData(), insert, point); + FutureCallbackTx.addCallback(submitData, RestconfDataServiceConstant.PutData.PUT_TX_TYPE, responseFactory); return responseFactory.build(); } @@ -152,17 +169,241 @@ public final class PutDataTransactionUtil { * - path of data * @param schemaContext * - {@link SchemaContext} - * @param writeTx + * @param domTransactionChain * - write transaction * @param data * - data + * @param point + * - query parameter + * @param insert + * - query parameter * @return {@link CheckedFuture} */ private static CheckedFuture submitData(final YangInstanceIdentifier path, - final SchemaContext schemaContext, - final DOMDataWriteTransaction writeTx, final NormalizedNode data) { + final SchemaContext schemaContext, final DOMTransactionChain domTransactionChain, + final NormalizedNode data, final String insert, final String point) { + final DOMDataReadWriteTransaction newReadWriteTransaction = domTransactionChain.newReadWriteTransaction(); + if (insert == null) { + return makePut(path, schemaContext, newReadWriteTransaction, data); + } else { + final DataSchemaNode schemaNode = checkListAndOrderedType(schemaContext, path); + switch (insert) { + case "first": + if (schemaNode instanceof ListSchemaNode) { + final NormalizedNode readData = + readList(path, schemaContext, domTransactionChain, schemaNode); + final OrderedMapNode readList = (OrderedMapNode) readData; + if ((readList == null) || readList.getValue().isEmpty()) { + return makePut(path, schemaContext, newReadWriteTransaction, data); + } else { + newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, path.getParent()); + simplePut(LogicalDatastoreType.CONFIGURATION, path, newReadWriteTransaction, schemaContext, data); + listPut(LogicalDatastoreType.CONFIGURATION, path.getParent(), newReadWriteTransaction, schemaContext, + readList); + return newReadWriteTransaction.submit(); + } + } else { + final NormalizedNode readData = + readList(path, schemaContext, domTransactionChain, schemaNode); + + final OrderedLeafSetNode readLeafList = (OrderedLeafSetNode) readData; + if ((readLeafList == null) || readLeafList.getValue().isEmpty()) { + return makePut(path, schemaContext, newReadWriteTransaction, data); + } else { + newReadWriteTransaction.delete(LogicalDatastoreType.CONFIGURATION, path.getParent()); + simplePut(LogicalDatastoreType.CONFIGURATION, path, newReadWriteTransaction, schemaContext, data); + listPut(LogicalDatastoreType.CONFIGURATION, path.getParent(), newReadWriteTransaction, schemaContext, + readLeafList); + return newReadWriteTransaction.submit(); + } + } + case "last": + return makePut(path, schemaContext, newReadWriteTransaction, data); + case "before": + if (schemaNode instanceof ListSchemaNode) { + final NormalizedNode readData = + readList(path, schemaContext, domTransactionChain, schemaNode); + final OrderedMapNode readList = (OrderedMapNode) readData; + if ((readList == null) || readList.getValue().isEmpty()) { + return makePut(path, schemaContext, newReadWriteTransaction, data); + } else { + insertWithPointListPut(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data, + schemaContext, point, readList, true); + return newReadWriteTransaction.submit(); + } + } else { + final NormalizedNode readData = + readList(path, schemaContext, domTransactionChain, schemaNode); + + final OrderedLeafSetNode readLeafList = (OrderedLeafSetNode) readData; + if ((readLeafList == null) || readLeafList.getValue().isEmpty()) { + return makePut(path, schemaContext, newReadWriteTransaction, data); + } else { + insertWithPointLeafListPut(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data, + schemaContext, point, readLeafList, true); + return newReadWriteTransaction.submit(); + } + } + case "after": + if (schemaNode instanceof ListSchemaNode) { + final NormalizedNode readData = + readList(path, schemaContext, domTransactionChain, schemaNode); + final OrderedMapNode readList = (OrderedMapNode) readData; + if ((readList == null) || readList.getValue().isEmpty()) { + return makePut(path, schemaContext, newReadWriteTransaction, data); + } else { + insertWithPointListPut(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data, + schemaContext, point, readList, false); + return newReadWriteTransaction.submit(); + } + } else { + final NormalizedNode readData = + readList(path, schemaContext, domTransactionChain, schemaNode); + + final OrderedLeafSetNode readLeafList = (OrderedLeafSetNode) readData; + if ((readLeafList == null) || readLeafList.getValue().isEmpty()) { + return makePut(path, schemaContext, newReadWriteTransaction, data); + } else { + insertWithPointLeafListPut(newReadWriteTransaction, LogicalDatastoreType.CONFIGURATION, path, data, + schemaContext, point, readLeafList, true); + return newReadWriteTransaction.submit(); + } + } + default: + throw new RestconfDocumentedException( + "Used bad value of insert parameter. Possible values are first, last, before or after, " + + "but was: " + insert); + } + } + } + + public static NormalizedNode readList(final YangInstanceIdentifier path, final SchemaContext schemaContext, + final DOMTransactionChain domTransactionChain, final DataSchemaNode schemaNode) { + final InstanceIdentifierContext iid = new InstanceIdentifierContext( + path.getParent(), schemaNode, null, schemaContext); + final TransactionVarsWrapper transactionNode = + new TransactionVarsWrapper(iid, null, domTransactionChain); + final NormalizedNode readData = ReadDataTransactionUtil + .readData(RestconfDataServiceConstant.ReadData.CONFIG, transactionNode); + return readData; + } + + private static void insertWithPointLeafListPut(final DOMDataReadWriteTransaction rWTransaction, + final LogicalDatastoreType datastore, final YangInstanceIdentifier path, + final NormalizedNode data, final SchemaContext schemaContext, final String point, + final OrderedLeafSetNode readLeafList, final boolean before) { + rWTransaction.delete(datastore, path.getParent()); + final InstanceIdentifierContext instanceIdentifier = + ControllerContext.getInstance().toInstanceIdentifier(point); + int p = 0; + for (final LeafSetEntryNode nodeChild : readLeafList.getValue()) { + if (nodeChild.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) { + break; + } + p++; + } + if (!before) { + p++; + } + int h = 0; + final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path.getParent()); + rWTransaction.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree); + for (final LeafSetEntryNode nodeChild : readLeafList.getValue()) { + if (h == p) { + simplePut(datastore, path, rWTransaction, schemaContext, data); + } + final YangInstanceIdentifier childPath = path.getParent().node(nodeChild.getIdentifier()); + rWTransaction.put(datastore, childPath, nodeChild); + h++; + } + } + + private static void insertWithPointListPut(final DOMDataReadWriteTransaction writeTx, + final LogicalDatastoreType datastore, final YangInstanceIdentifier path, + final NormalizedNode data, final SchemaContext schemaContext, final String point, + final OrderedMapNode readList, final boolean before) { + writeTx.delete(datastore, path.getParent()); + final InstanceIdentifierContext instanceIdentifier = + ControllerContext.getInstance().toInstanceIdentifier(point); + int p = 0; + for (final MapEntryNode mapEntryNode : readList.getValue()) { + if (mapEntryNode.getIdentifier().equals(instanceIdentifier.getInstanceIdentifier().getLastPathArgument())) { + break; + } + p++; + } + if (!before) { + p++; + } + int h = 0; + final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path.getParent()); + writeTx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree); + for (final MapEntryNode mapEntryNode : readList.getValue()) { + if (h == p) { + simplePut(datastore, path, writeTx, schemaContext, data); + } + final YangInstanceIdentifier childPath = path.getParent().node(mapEntryNode.getIdentifier()); + writeTx.put(datastore, childPath, mapEntryNode); + h++; + } + } + + private static void listPut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path, + final DOMDataReadWriteTransaction writeTx, final SchemaContext schemaContext, + final OrderedLeafSetNode payload) { + final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path); + writeTx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree); + TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTx); + for (final LeafSetEntryNode child : ((LeafSetNode) payload).getValue()) { + final YangInstanceIdentifier childPath = path.node(child.getIdentifier()); + writeTx.put(datastore, childPath, child); + } + } + + private static void listPut(final LogicalDatastoreType datastore, final YangInstanceIdentifier path, + final DOMDataReadWriteTransaction writeTx, final SchemaContext schemaContext, + final OrderedMapNode payload) { + final NormalizedNode emptySubtree = ImmutableNodes.fromInstanceId(schemaContext, path); + writeTx.merge(datastore, YangInstanceIdentifier.create(emptySubtree.getIdentifier()), emptySubtree); + TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTx); + for (final MapEntryNode child : ((MapNode) payload).getValue()) { + final YangInstanceIdentifier childPath = path.node(child.getIdentifier()); + writeTx.put(datastore, childPath, child); + } + } + + private static void simplePut(final LogicalDatastoreType configuration, final YangInstanceIdentifier path, + final DOMDataReadWriteTransaction writeTx, final SchemaContext schemaContext, + final NormalizedNode data) { + TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTx); + writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); + } + + private static CheckedFuture makePut(final YangInstanceIdentifier path, + final SchemaContext schemaContext, final DOMDataWriteTransaction writeTx, final NormalizedNode data) { TransactionUtil.ensureParentsByMerge(path, schemaContext, writeTx); writeTx.put(LogicalDatastoreType.CONFIGURATION, path, data); return writeTx.submit(); } + + public static DataSchemaNode checkListAndOrderedType(final SchemaContext ctx, final YangInstanceIdentifier path) { + final YangInstanceIdentifier parent = path.getParent(); + final DataSchemaContextNode node = DataSchemaContextTree.from(ctx).getChild(parent); + final DataSchemaNode dataSchemaNode = node.getDataSchemaNode(); + + if (dataSchemaNode instanceof ListSchemaNode) { + if (!((ListSchemaNode) dataSchemaNode).isUserOrdered()) { + throw new RestconfDocumentedException("Insert parameter can be used only with ordered-by user list."); + } + return dataSchemaNode; + } + if (dataSchemaNode instanceof LeafListSchemaNode) { + if (!((LeafListSchemaNode) dataSchemaNode).isUserOrdered()) { + throw new RestconfDocumentedException( + "Insert parameter can be used only with ordered-by user leaf-list."); + } + return dataSchemaNode; + } + throw new RestconfDocumentedException("Insert parameter can be used only with list or leaf-list"); + } }