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;
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;
* @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<Void, TransactionCommitFailedException> 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();
}
* - 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<Void, TransactionCommitFailedException> 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<SchemaNode>(
+ 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<Void, TransactionCommitFailedException> 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");
+ }
}