--- /dev/null
+/*
+ * Copyright (c) 2021 PANTHEON.tech, s.r.o. 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.nb.rfc8040;
+
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.base.MoreObjects;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.restconf.api.query.InsertParam;
+import org.opendaylight.restconf.api.query.PointParam;
+import org.opendaylight.yangtools.concepts.Immutable;
+
+/**
+ * Parser and holder of query parameters from uriInfo for data and datastore modification operations.
+ */
+// FIXME: Java 21: model this as a sealed interface and two records BeforeOrAfter and FirstOrLast, which further expose
+// a boolean to differentiate which of the cases we are dealing with. This will allow users to use
+// switch expression with record decomposition to safely dispatch execution. Only BeforeOrAfter will
+// have a @NonNull PointParam then and there will not be an insert field. We can also ditch toString(),
+// as the records will do the right thing.
+public final class Insert implements Immutable {
+ private final @NonNull InsertParam insert;
+ private final @Nullable PointParam point;
+
+ private Insert(final InsertParam insert, final PointParam point) {
+ this.insert = requireNonNull(insert);
+ this.point = point;
+ }
+
+ public static @Nullable Insert forParams(final @Nullable InsertParam insert, final @Nullable PointParam point) {
+ if (insert == null) {
+ if (point != null) {
+ throw invalidPointIAE();
+ }
+ return null;
+ }
+
+ return switch (insert) {
+ case BEFORE, AFTER -> {
+ // https://www.rfc-editor.org/rfc/rfc8040#section-4.8.5:
+ // If the values "before" or "after" are used, then a "point" query
+ // parameter for the "insert" query parameter MUST also be present, or a
+ // "400 Bad Request" status-line is returned.
+ if (point == null) {
+ throw new IllegalArgumentException(
+ "Insert parameter " + insert.paramValue() + " cannot be used without a Point parameter.");
+ }
+ yield new Insert(insert, point);
+ }
+ case FIRST, LAST -> {
+ // https://www.rfc-editor.org/rfc/rfc8040#section-4.8.6:
+ // [when "point" parameter is present and]
+ // If the "insert" query parameter is not present or has a value other
+ // than "before" or "after", then a "400 Bad Request" status-line is
+ // returned.
+ if (point != null) {
+ throw invalidPointIAE();
+ }
+ yield new Insert(insert, null);
+ }
+ };
+ }
+
+ private static IllegalArgumentException invalidPointIAE() {
+ return new IllegalArgumentException(
+ "Point parameter can be used only with 'after' or 'before' values of Insert parameter.");
+ }
+
+ public @NonNull InsertParam insert() {
+ return insert;
+ }
+
+ public @Nullable PointParam point() {
+ return point;
+ }
+
+ @Override
+ public String toString() {
+ final var helper = MoreObjects.toStringHelper(this).add("insert", insert.paramValue());
+ final var local = point;
+ if (local != null) {
+ helper.add("point", local.value());
+ }
+ return helper.toString();
+ }
+}
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2021 PANTHEON.tech, s.r.o. 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.nb.rfc8040;
-
-import com.google.common.base.MoreObjects;
-import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
-import org.opendaylight.restconf.api.query.InsertParam;
-import org.opendaylight.restconf.api.query.PointParam;
-import org.opendaylight.yangtools.concepts.Immutable;
-
-/**
- * Parser and holder of query parameters from uriInfo for data and datastore modification operations.
- */
-// FIXME: this should be a record with JDK17+
-public final class WriteDataParams implements Immutable {
- private static final @NonNull WriteDataParams EMPTY = new WriteDataParams(null, null);
-
- private final PointParam point;
- private final InsertParam insert;
-
- private WriteDataParams(final InsertParam insert, final PointParam point) {
- this.insert = insert;
- this.point = point;
- }
-
- public static @NonNull WriteDataParams empty() {
- return EMPTY;
- }
-
- public static @NonNull WriteDataParams of(final InsertParam insert, final PointParam point) {
- if (point == null) {
- if (insert == null) {
- return empty();
- }
-
- // https://www.rfc-editor.org/rfc/rfc8040#section-4.8.5:
- // If the values "before" or "after" are used, then a "point" query
- // parameter for the "insert" query parameter MUST also be present, or a
- // "400 Bad Request" status-line is returned.
- if (insert == InsertParam.BEFORE || insert == InsertParam.AFTER) {
- throw new IllegalArgumentException(
- "Insert parameter " + insert.paramValue() + " cannot be used without a Point parameter.");
- }
- } else if (insert != InsertParam.BEFORE && insert != InsertParam.AFTER) {
- // https://www.rfc-editor.org/rfc/rfc8040#section-4.8.6:
- // [when "point" parameter is present and]
- // If the "insert" query parameter is not present or has a value other
- // than "before" or "after", then a "400 Bad Request" status-line is
- // returned.
- throw new IllegalArgumentException(
- "Point parameter can be used only with 'after' or 'before' values of Insert parameter.");
- }
-
- return new WriteDataParams(insert, point);
- }
-
- public @Nullable InsertParam insert() {
- return insert;
- }
-
- public @Nullable PointParam point() {
- return point;
- }
-
- @Override
- public String toString() {
- final var helper = MoreObjects.toStringHelper(this).omitNullValues();
- if (insert != null) {
- helper.add("insert", insert.paramValue());
- }
- if (point != null) {
- helper.add("point", point.value());
- }
- return helper.toString();
- }
-}
\ No newline at end of file
import org.opendaylight.restconf.common.context.InstanceIdentifierContext;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
+import org.opendaylight.restconf.nb.rfc8040.Insert;
import org.opendaylight.restconf.nb.rfc8040.NotificationQueryParams;
import org.opendaylight.restconf.nb.rfc8040.ReadDataParams;
-import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.NetconfFieldsTranslator;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.WriterFieldsTranslator;
return new ReadDataParams(content, depth, fields, withDefaults, prettyPrint);
}
- public static @NonNull WriteDataParams newWriteDataParams(final UriInfo uriInfo) {
+ public static @Nullable Insert parseInsert(final UriInfo uriInfo) {
InsertParam insert = null;
PointParam point = null;
- for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
- final String paramName = entry.getKey();
- final List<String> paramValues = entry.getValue();
+ for (var entry : uriInfo.getQueryParameters().entrySet()) {
+ final var paramName = entry.getKey();
+ final var paramValues = entry.getValue();
try {
switch (paramName) {
}
try {
- return WriteDataParams.of(insert, point);
+ return Insert.forParams(insert, point);
} catch (IllegalArgumentException e) {
throw new RestconfDocumentedException("Invalid query parameters: " + e.getMessage(), e);
}
}
private Response putData(final @Nullable String identifier, final UriInfo uriInfo, final ResourceBody body) {
- final var params = QueryParams.newWriteDataParams(uriInfo);
+ final var insert = QueryParams.parseInsert(uriInfo);
final var req = bindResourceRequest(identifier, body);
return switch (
- req.strategy().putData(req.path(), req.data(), req.modelContext(), params)) {
+ req.strategy().putData(req.path(), req.data(), req.modelContext(), insert)) {
// Note: no Location header, as it matches the request path
case CREATED -> Response.status(Status.CREATED).build();
case REPLACED -> Response.noContent().build();
}
private Response postData(final InstanceIdentifierContext iid, final ChildBody body, final UriInfo uriInfo) {
- final var params = QueryParams.newWriteDataParams(uriInfo);
+ final var insert = QueryParams.parseInsert(uriInfo);
final var strategy = getRestconfStrategy(iid.getMountPoint());
final var context = iid.getSchemaContext();
var path = iid.getInstanceIdentifier();
path = path.node(arg);
}
- strategy.postData(path, data, context, params);
+ strategy.postData(path, data, context, insert);
return Response.created(resolveLocation(uriInfo, path, context, data)).build();
}
import org.opendaylight.mdsal.dom.api.DOMDataBroker;
import org.opendaylight.mdsal.dom.api.DOMMountPoint;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
-import org.opendaylight.restconf.api.query.InsertParam;
import org.opendaylight.restconf.api.query.PointParam;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfFuture;
import org.opendaylight.restconf.common.errors.SettableRestconfFuture;
-import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
+import org.opendaylight.restconf.nb.rfc8040.Insert;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.TransactionUtil;
import org.opendaylight.restconf.nb.rfc8040.utils.parser.YangInstanceIdentifierDeserializer;
import org.opendaylight.yangtools.yang.common.Empty;
* @param path path of data
* @param data data
* @param context reference to {@link EffectiveModelContext}
- * @param params {@link WriteDataParams}
+ * @param insert {@link Insert}
* @return A {@link CreateOrReplaceResult}
*/
public @NonNull CreateOrReplaceResult putData(final YangInstanceIdentifier path, final NormalizedNode data,
- final EffectiveModelContext context, final WriteDataParams params) {
+ final EffectiveModelContext context, final @Nullable Insert insert) {
final var exists = TransactionUtil.syncAccess(exists(path), path);
- final var insert = params.insert();
final ListenableFuture<? extends CommitInfo> commitFuture;
if (insert != null) {
final var parentPath = path.coerceParent();
checkListAndOrderedType(context, parentPath);
- commitFuture = insertAndCommitPut(path, data, insert, params.point(), parentPath, context);
+ commitFuture = insertAndCommitPut(path, data, insert, parentPath, context);
} else {
commitFuture = replaceAndCommit(prepareWriteExecution(), path, data, context);
}
}
private ListenableFuture<? extends CommitInfo> insertAndCommitPut(final YangInstanceIdentifier path,
- final NormalizedNode data, final @NonNull InsertParam insert, final @Nullable PointParam point,
- final YangInstanceIdentifier parentPath, final EffectiveModelContext context) {
+ final NormalizedNode data, final @NonNull Insert insert, final YangInstanceIdentifier parentPath,
+ final EffectiveModelContext context) {
final var tx = prepareWriteExecution();
- return switch (insert) {
+ return switch (insert.insert()) {
case FIRST -> {
final var readData = tx.readList(parentPath);
if (readData == null || readData.isEmpty()) {
if (readData == null || readData.isEmpty()) {
yield replaceAndCommit(tx, path, data, context);
}
- insertWithPointPut(tx, path, data, verifyNotNull(point), readData, true, context);
+ insertWithPointPut(tx, path, data, verifyNotNull(insert.point()), readData, true, context);
yield tx.commit();
}
case AFTER -> {
if (readData == null || readData.isEmpty()) {
yield replaceAndCommit(tx, path, data, context);
}
- insertWithPointPut(tx, path, data, verifyNotNull(point), readData, false, context);
+ insertWithPointPut(tx, path, data, verifyNotNull(insert.point()), readData, false, context);
yield tx.commit();
}
};
* @param path path
* @param data data
* @param context reference to actual {@link EffectiveModelContext}
- * @param params {@link WriteDataParams}
+ * @param insert {@link Insert}
*/
public final void postData(final YangInstanceIdentifier path, final NormalizedNode data,
- final EffectiveModelContext context, final WriteDataParams params) {
- final var insert = params.insert();
+ final EffectiveModelContext context, final @Nullable Insert insert) {
final ListenableFuture<? extends CommitInfo> future;
if (insert != null) {
final var parentPath = path.coerceParent();
checkListAndOrderedType(context, parentPath);
- future = insertAndCommitPost(path, data, insert, params.point(), parentPath, context);
+ future = insertAndCommitPost(path, data, insert, parentPath, context);
} else {
future = createAndCommit(prepareWriteExecution(), path, data, context);
}
}
private ListenableFuture<? extends CommitInfo> insertAndCommitPost(final YangInstanceIdentifier path,
- final NormalizedNode data, final @NonNull InsertParam insert, final @Nullable PointParam point,
- final YangInstanceIdentifier parent, final EffectiveModelContext context) {
+ final NormalizedNode data, final @NonNull Insert insert, final YangInstanceIdentifier parent,
+ final EffectiveModelContext context) {
final var grandParent = parent.coerceParent();
final var tx = prepareWriteExecution();
- return switch (insert) {
+ return switch (insert.insert()) {
case FIRST -> {
final var readData = tx.readList(grandParent);
if (readData == null || readData.isEmpty()) {
tx.replace(path, data, context);
} else {
checkItemDoesNotExists(exists(path), path);
- insertWithPointPost(tx, path, data, verifyNotNull(point), readData, grandParent, true, context);
+ insertWithPointPost(tx, path, data, verifyNotNull(insert.point()), readData, grandParent, true,
+ context);
}
yield tx.commit();
}
tx.replace(path, data, context);
} else {
checkItemDoesNotExists(exists(path), path);
- insertWithPointPost(tx, path, data, verifyNotNull(point), readData, grandParent, false, context);
+ insertWithPointPost(tx, path, data, verifyNotNull(insert.point()), readData, grandParent, false,
+ context);
}
yield tx.commit();
}
public void checkParametersTypesNegativeTest() {
assertUnknownParam(QueryParams::newNotificationQueryParams);
assertUnknownParam(QueryParams::newReadDataParams);
- assertUnknownParam(QueryParams::newWriteDataParams);
+ assertUnknownParam(QueryParams::parseInsert);
assertInvalidParam(QueryParams::newNotificationQueryParams, ContentParam.ALL);
assertInvalidParam(QueryParams::newReadDataParams, InsertParam.LAST);
- assertInvalidParam(QueryParams::newWriteDataParams, ContentParam.ALL);
+ assertInvalidParam(QueryParams::parseInsert, ContentParam.ALL);
}
/**
import org.opendaylight.restconf.common.patch.PatchEntity;
import org.opendaylight.restconf.common.patch.PatchStatusContext;
import org.opendaylight.restconf.nb.rfc8040.AbstractJukeboxTest;
-import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.PatchDataTransactionUtil;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.ReadDataTransactionUtil;
import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.patch.rev170222.yang.patch.yang.patch.Edit.Operation;
@Test
public final void testPostContainerData() {
- testPostContainerDataStrategy().postData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA,
- WriteDataParams.empty());
+ testPostContainerDataStrategy().postData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA, null);
}
abstract @NonNull RestconfStrategy testPostContainerDataStrategy();
@Test
public final void testPostListData() {
testPostListDataStrategy(BAND_ENTRY, PLAYLIST_IID.node(BAND_ENTRY.name())).postData(PLAYLIST_IID, PLAYLIST,
- JUKEBOX_SCHEMA, WriteDataParams.empty());
+ JUKEBOX_SCHEMA, null);
}
abstract @NonNull RestconfStrategy testPostListDataStrategy(MapEntryNode entryNode, YangInstanceIdentifier node);
final var domException = new DOMException((short) 414, "Post request failed");
RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
- () -> testPostDataFailStrategy(domException).postData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA,
- WriteDataParams.empty()));
+ () -> testPostDataFailStrategy(domException).postData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA, null));
assertEquals(1, ex.getErrors().size());
assertThat(ex.getErrors().get(0).getErrorInfo(), containsString(domException.getMessage()));
}
import org.opendaylight.restconf.api.query.ContentParam;
import org.opendaylight.restconf.api.query.WithDefaultsParam;
import org.opendaylight.restconf.common.patch.PatchStatusContext;
-import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
import org.opendaylight.restconf.nb.rfc8040.rests.utils.ReadDataTransactionUtil;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
- new MdsalRestconfStrategy(mockDataBroker).putData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA,
- WriteDataParams.empty());
+ new MdsalRestconfStrategy(mockDataBroker).putData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA, null);
verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX);
}
doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
- new MdsalRestconfStrategy(mockDataBroker).putData(GAP_IID, GAP_LEAF, JUKEBOX_SCHEMA, WriteDataParams.empty());
+ new MdsalRestconfStrategy(mockDataBroker).putData(GAP_IID, GAP_LEAF, JUKEBOX_SCHEMA, null);
verify(read).exists(LogicalDatastoreType.CONFIGURATION, GAP_IID);
verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF);
}
doNothing().when(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
doReturn(CommitInfo.emptyFluentFuture()).when(readWrite).commit();
- new MdsalRestconfStrategy(mockDataBroker).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, JUKEBOX_SCHEMA,
- WriteDataParams.empty());
+ new MdsalRestconfStrategy(mockDataBroker).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, JUKEBOX_SCHEMA, null);
verify(read).exists(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID);
verify(readWrite).put(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS);
}
import org.opendaylight.netconf.api.NetconfDocumentedException;
import org.opendaylight.netconf.dom.api.NetconfDataTreeService;
import org.opendaylight.restconf.common.patch.PatchStatusContext;
-import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
import org.opendaylight.yangtools.yang.common.ErrorSeverity;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
.replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, Optional.empty());
- new NetconfRestconfStrategy(netconfService).putData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA,
- WriteDataParams.empty());
+ new NetconfRestconfStrategy(netconfService).putData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA, null);
verify(netconfService).lock();
verify(netconfService).getConfig(JUKEBOX_IID);
verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX,
doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
.replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX, Optional.empty());
- new NetconfRestconfStrategy(netconfService).putData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA,
- WriteDataParams.empty());
+ new NetconfRestconfStrategy(netconfService).putData(JUKEBOX_IID, EMPTY_JUKEBOX, JUKEBOX_SCHEMA, null);
verify(netconfService).getConfig(JUKEBOX_IID);
verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, EMPTY_JUKEBOX,
Optional.empty());
doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
.replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty());
- new NetconfRestconfStrategy(netconfService).putData(GAP_IID, GAP_LEAF, JUKEBOX_SCHEMA, WriteDataParams.empty());
+ new NetconfRestconfStrategy(netconfService).putData(GAP_IID, GAP_LEAF, JUKEBOX_SCHEMA, null);
verify(netconfService).getConfig(GAP_IID);
verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty());
}
doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
.replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty());
- new NetconfRestconfStrategy(netconfService).putData(GAP_IID, GAP_LEAF, JUKEBOX_SCHEMA, WriteDataParams.empty());
+ new NetconfRestconfStrategy(netconfService).putData(GAP_IID, GAP_LEAF, JUKEBOX_SCHEMA, null);
verify(netconfService).getConfig(GAP_IID);
verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, GAP_IID, GAP_LEAF, Optional.empty());
}
doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
.replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS, Optional.empty());
- new NetconfRestconfStrategy(netconfService).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, JUKEBOX_SCHEMA,
- WriteDataParams.empty());
+ new NetconfRestconfStrategy(netconfService).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, JUKEBOX_SCHEMA, null);
verify(netconfService).getConfig(JUKEBOX_IID);
verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS,
Optional.empty());
doReturn(Futures.immediateFuture(new DefaultDOMRpcResult())).when(netconfService)
.replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS, Optional.empty());
- new NetconfRestconfStrategy(netconfService).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, JUKEBOX_SCHEMA,
- WriteDataParams.empty());
+ new NetconfRestconfStrategy(netconfService).putData(JUKEBOX_IID, JUKEBOX_WITH_BANDS, JUKEBOX_SCHEMA, null);
verify(netconfService).getConfig(JUKEBOX_IID);
verify(netconfService).replace(LogicalDatastoreType.CONFIGURATION, JUKEBOX_IID, JUKEBOX_WITH_BANDS,
Optional.empty());