From 159a779b8d254f2ed12cee30a7e5dc0a8b1b79fa Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 16 Nov 2023 23:23:18 +0100 Subject: [PATCH 1/1] Codify operationsGET GET on /operations is well-defined, express it in RestconfServer, migrating callers of OperationsContent.bodyFor(). JIRA: NETCONF-773 Change-Id: I64b713fdddac2dc3b1e4166a26ea554d23e3cfa1 Signed-off-by: Robert Varga --- .../services/impl/MdsalRestconfServer.java | 16 +++++++++++++ .../services/impl/OperationsContent.java | 2 +- .../impl/RestconfOperationsServiceImpl.java | 22 +++++++++--------- .../restconf/server/api/RestconfServer.java | 23 +++++++++++++++++++ .../rests/services/impl/Netconf822Test.java | 13 +++++++---- ...stconfInvokeOperationsServiceImplTest.java | 4 ++-- .../RestconfOperationsServiceImplTest.java | 6 ++--- 7 files changed, 65 insertions(+), 21 deletions(-) diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServer.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServer.java index 55f9bdb433..1514a3eaf7 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServer.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/MdsalRestconfServer.java @@ -50,6 +50,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes; import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext; import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack; +import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference; import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; @@ -127,6 +128,21 @@ public final class MdsalRestconfServer implements RestconfServer { ImmutableNodes.leafNode(YANG_LIBRARY_VERSION, YANG_LIBRARY_REVISION)); } + @Override + public String operationsGET(final OperationsContent contentType) { + return operationsGET(contentType, bindRequestRoot().inference()); + } + + @Override + public String operationsGET(final OperationsContent contentType, final String operation) { + return operationsGET(contentType, bindRequestPath(operation).inference()); + } + + @VisibleForTesting + static @NonNull String operationsGET(final OperationsContent contentType, final @NonNull Inference inference) { + return contentType.bodyFor(inference); + } + @Override public RestconfFuture operationsPOST(final URI restconfURI, final String apiPath, final OperationInputBody body) { diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/OperationsContent.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/OperationsContent.java index 51e9c4ff1e..ab6c075bf8 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/OperationsContent.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/OperationsContent.java @@ -25,7 +25,7 @@ import org.opendaylight.yangtools.yang.model.util.SchemaInferenceStack.Inference * RESTCONF {@code /operations} content for a {@code GET} operation as per * RFC8040. */ -enum OperationsContent { +public enum OperationsContent { JSON("{ \"ietf-restconf:operations\" : { } }") { @Override String createBody(final List>> rpcsByPrefix) { diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImpl.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImpl.java index 9def8bd0d9..bce5f4fc90 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImpl.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImpl.java @@ -57,7 +57,7 @@ public final class RestconfOperationsServiceImpl { @Path("/operations") @Produces({ MediaTypes.APPLICATION_YANG_DATA_JSON, MediaType.APPLICATION_JSON }) public String getOperationsJSON() { - return OperationsContent.JSON.bodyFor(server.bindRequestRoot().inference()); + return server.operationsGET(OperationsContent.JSON); } /** @@ -70,7 +70,7 @@ public final class RestconfOperationsServiceImpl { @Path("/operations/{identifier:.+}") @Produces({ MediaTypes.APPLICATION_YANG_DATA_JSON, MediaType.APPLICATION_JSON }) public String getOperationJSON(@PathParam("identifier") final String identifier) { - return OperationsContent.JSON.bodyFor(server.bindRequestPath(identifier).inference()); + return server.operationsGET(OperationsContent.JSON, identifier); } /** @@ -81,8 +81,8 @@ public final class RestconfOperationsServiceImpl { @GET @Path("/operations") @Produces({ MediaTypes.APPLICATION_YANG_DATA_XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public String getOperationsXML() { - return OperationsContent.XML.bodyFor(server.bindRequestRoot().inference()); + public String operationsGetXML() { + return server.operationsGET(OperationsContent.XML); } /** @@ -94,8 +94,8 @@ public final class RestconfOperationsServiceImpl { @GET @Path("/operations/{identifier:.+}") @Produces({ MediaTypes.APPLICATION_YANG_DATA_XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public String getOperationXML(@PathParam("identifier") final String identifier) { - return OperationsContent.XML.bodyFor(server.bindRequestPath(identifier).inference()); + public String operationsGetXML(@PathParam("identifier") final String identifier) { + return server.operationsGET(OperationsContent.XML, identifier); } /** @@ -121,10 +121,10 @@ public final class RestconfOperationsServiceImpl { MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public void invokeRpcXML(@Encoded @PathParam("identifier") final String identifier, final InputStream body, + public void operationsPostXML(@Encoded @PathParam("identifier") final String identifier, final InputStream body, @Context final UriInfo uriInfo, @Suspended final AsyncResponse ar) { try (var xmlBody = new XmlOperationInputBody(body)) { - invokeRpc(identifier, uriInfo, ar, xmlBody); + operationsPOST(identifier, uriInfo, ar, xmlBody); } } @@ -150,14 +150,14 @@ public final class RestconfOperationsServiceImpl { MediaType.APPLICATION_XML, MediaType.TEXT_XML }) - public void invokeRpcJSON(@Encoded @PathParam("identifier") final String identifier, final InputStream body, + public void operationsPostJSON(@Encoded @PathParam("identifier") final String identifier, final InputStream body, @Context final UriInfo uriInfo, @Suspended final AsyncResponse ar) { try (var jsonBody = new JsonOperationInputBody(body)) { - invokeRpc(identifier, uriInfo, ar, jsonBody); + operationsPOST(identifier, uriInfo, ar, jsonBody); } } - private void invokeRpc(final String identifier, final UriInfo uriInfo, final AsyncResponse ar, + private void operationsPOST(final String identifier, final UriInfo uriInfo, final AsyncResponse ar, final OperationInputBody body) { server.operationsPOST(uriInfo.getBaseUri(), identifier, body) .addCallback(new JaxRsRestconfCallback(ar) { diff --git a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/server/api/RestconfServer.java b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/server/api/RestconfServer.java index 431bc262b0..435959c55c 100644 --- a/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/server/api/RestconfServer.java +++ b/restconf/restconf-nb/src/main/java/org/opendaylight/restconf/server/api/RestconfServer.java @@ -13,6 +13,7 @@ import org.opendaylight.restconf.api.ApiPath; import org.opendaylight.restconf.common.errors.RestconfFuture; import org.opendaylight.restconf.nb.rfc8040.databind.OperationInputBody; import org.opendaylight.restconf.nb.rfc8040.legacy.NormalizedNodePayload; +import org.opendaylight.restconf.nb.rfc8040.rests.services.impl.OperationsContent; import org.opendaylight.restconf.server.spi.OperationOutput; /** @@ -32,6 +33,28 @@ public interface RestconfServer { // FIXME: RestconfFuture if we transition to being used by restconf-client implementation NormalizedNodePayload yangLibraryVersionGET(); + /** + * Return the set of supported RPCs supported by {@link #operationsPOST(URI, String, OperationInputBody)}. + * + * @param contentType Formatting type + * @return A formatted string + */ + String operationsGET(OperationsContent contentType); + + /* + * Return the details about a particular operation supported by + * {@link #operationsPOST(URI, String, OperationInputBody)}, as expressed in the + * RFC8040 Operation Resource. diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf822Test.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf822Test.java index 7c8c9bbf45..a60cb9d448 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf822Test.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/Netconf822Test.java @@ -35,7 +35,8 @@ public class Netconf822Test { "foo:new": [null], "foo:new1": [null] } - }""", OperationsContent.JSON.bodyFor(SchemaInferenceStack.of(SCHEMA).toInference())); + }""", + MdsalRestconfServer.operationsGET(OperationsContent.JSON, SchemaInferenceStack.of(SCHEMA).toInference())); } @Test @@ -45,7 +46,8 @@ public class Netconf822Test { "ietf-restconf:operations" : { "foo:new1": [null] } - }""", OperationsContent.JSON.bodyFor(SchemaInferenceStack.of(SCHEMA, NEW1).toInference())); + }""", + MdsalRestconfServer.operationsGET(OperationsContent.JSON, SchemaInferenceStack.of(SCHEMA, NEW1).toInference())); } @Test @@ -56,7 +58,8 @@ public class Netconf822Test { xmlns:ns0="foo" > - """, OperationsContent.XML.bodyFor(SchemaInferenceStack.of(SCHEMA).toInference())); + """, + MdsalRestconfServer.operationsGET(OperationsContent.XML, SchemaInferenceStack.of(SCHEMA).toInference())); } @Test @@ -66,6 +69,8 @@ public class Netconf822Test { - """, OperationsContent.XML.bodyFor(SchemaInferenceStack.of(SCHEMA, NEW1).toInference())); + """, + MdsalRestconfServer.operationsGET(OperationsContent.XML, + SchemaInferenceStack.of(SCHEMA, NEW1).toInference())); } } diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImplTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImplTest.java index 789b192249..8206b39bfd 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImplTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfInvokeOperationsServiceImplTest.java @@ -102,7 +102,7 @@ public class RestconfInvokeOperationsServiceImplTest { prepNNC(result); final var ar = mock(AsyncResponse.class); final var captor = ArgumentCaptor.forClass(Response.class); - invokeOperationsService.invokeRpcXML("invoke-rpc-module:rpc-test", new ByteArrayInputStream(""" + invokeOperationsService.operationsPostXML("invoke-rpc-module:rpc-test", new ByteArrayInputStream(""" """.getBytes(StandardCharsets.UTF_8)), mock(UriInfo.class), ar); verify(ar).resume(captor.capture()); @@ -121,7 +121,7 @@ public class RestconfInvokeOperationsServiceImplTest { prepNNC(result); final var ar = mock(AsyncResponse.class); final var response = ArgumentCaptor.forClass(Response.class); - invokeOperationsService.invokeRpcJSON("invoke-rpc-module:rpc-test", new ByteArrayInputStream(""" + invokeOperationsService.operationsPostJSON("invoke-rpc-module:rpc-test", new ByteArrayInputStream(""" { "invoke-rpc-module:input" : { } diff --git a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImplTest.java b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImplTest.java index 29b2e36ad9..e50b171744 100644 --- a/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImplTest.java +++ b/restconf/restconf-nb/src/test/java/org/opendaylight/restconf/nb/rfc8040/rests/services/impl/RestconfOperationsServiceImplTest.java @@ -96,7 +96,7 @@ public class RestconfOperationsServiceImplTest { @Test public void testOperationsXml() { - final var operationsXML = opService.getOperationsXML(); + final var operationsXML = opService.operationsGetXML(); assertEquals(EXPECTED_XML, operationsXML); } @@ -108,7 +108,7 @@ public class RestconfOperationsServiceImplTest { @Test public void testMountPointOperationsXml() { - final var operationXML = opService.getOperationXML(DEVICE_ID); + final var operationXML = opService.operationsGetXML(DEVICE_ID); assertEquals(EXPECTED_XML, operationXML); } @@ -125,7 +125,7 @@ public class RestconfOperationsServiceImplTest { @Test public void testMountPointSpecificOperationsXml() { - final var operationXML = opService.getOperationXML(DEVICE_RPC1_MODULE1_ID); + final var operationXML = opService.operationsGetXML(DEVICE_RPC1_MODULE1_ID); assertEquals("""