From: Robert Varga Date: Mon, 25 Oct 2021 00:59:29 +0000 (+0200) Subject: Expose parameter names as String constants X-Git-Tag: v2.0.6~13 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=43c19cd73d0d60bc76afa3ddec2601842bf32333;p=netconf.git Expose parameter names as String constants Remove static methods in favor of proper constants. This allows us to use switch statements instead of if/else. Since we are at it, differentiate between unknown and known-but-invalid parameters. JIRA: NETCONF-773 Change-Id: Id2a9b09f8cbb5688d1722fc7ee932be4c46ceac6 Signed-off-by: Robert Varga --- diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/ContentParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/ContentParam.java index f4f6fa5438..6ed8e20f1f 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/ContentParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/ContentParam.java @@ -30,6 +30,10 @@ public enum ContentParam implements RestconfQueryParam { */ NONCONFIG("nonconfig"); + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final @NonNull String uriName = "content"; + private final @NonNull String uriValue; ContentParam(final String uriValue) { @@ -43,7 +47,7 @@ public enum ContentParam implements RestconfQueryParam { @Override public final String paramName() { - return uriName(); + return uriName; } @Override @@ -51,10 +55,6 @@ public enum ContentParam implements RestconfQueryParam { return uriValue; } - public static @NonNull String uriName() { - return "content"; - } - // Note: returns null of unknowns public static @Nullable ContentParam forUriValue(final String uriValue) { switch (uriValue) { diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/DepthParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/DepthParam.java index d489c7f0bd..8ece8d1e3d 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/DepthParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/DepthParam.java @@ -19,6 +19,10 @@ import org.eclipse.jdt.annotation.Nullable; * RFC8040 section 4.8.2. */ public final class DepthParam implements RestconfQueryParam { + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final @NonNull String uriName = "depth"; + private static final @NonNull URI CAPABILITY = URI.create("urn:ietf:params:restconf:capability:depth:1.0"); private static final @NonNull DepthParam MIN = of(1); private static final @NonNull DepthParam MAX = of(65535); @@ -41,7 +45,7 @@ public final class DepthParam implements RestconfQueryParam { @Override public String paramName() { - return uriName(); + return uriName; } @Override @@ -49,10 +53,6 @@ public final class DepthParam implements RestconfQueryParam { return String.valueOf(value); } - public static @NonNull String uriName() { - return "depth"; - } - @Beta public static @NonNull DepthParam min() { return MIN; diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/FieldsParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/FieldsParam.java index e51b45a090..247fb43084 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/FieldsParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/FieldsParam.java @@ -74,6 +74,9 @@ public final class FieldsParam implements RestconfQueryParam { } } + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final String uriName = "fields"; private static final URI CAPABILITY = URI.create("urn:ietf:params:restconf:capability:fields:1.0"); private final ImmutableList nodeSelectors; @@ -82,7 +85,7 @@ public final class FieldsParam implements RestconfQueryParam { private FieldsParam(final ImmutableList nodeSelectors, final String uriValue) { this.nodeSelectors = requireNonNull(nodeSelectors); checkArgument(!nodeSelectors.isEmpty(), "At least one selector is required"); - this.paramValue = requireNonNull(uriValue); + paramValue = requireNonNull(uriValue); } /** @@ -103,11 +106,7 @@ public final class FieldsParam implements RestconfQueryParam { @Override public String paramName() { - return uriName(); - } - - public static String uriName() { - return "fields"; + return uriName; } public static URI capabilityUri() { diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/FilterParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/FilterParam.java index f66bd2dfd2..67f56eed35 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/FilterParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/FilterParam.java @@ -18,6 +18,10 @@ import org.eclipse.jdt.annotation.NonNull; */ public final class FilterParam implements RestconfQueryParam { + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final @NonNull String uriName = "filter"; + private static final @NonNull URI CAPABILITY = URI.create("urn:ietf:params:restconf:capability:filter:1.0"); // FIXME: can we have a parsed, but not bound version of an XPath, please? @@ -34,7 +38,7 @@ public final class FilterParam implements RestconfQueryParam { @Override public String paramName() { - return uriName(); + return uriName; } @Override @@ -46,10 +50,6 @@ public final class FilterParam implements RestconfQueryParam { return new FilterParam(uriValue); } - public static @NonNull String uriName() { - return "filter"; - } - public static @NonNull URI capabilityUri() { return CAPABILITY; } diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/InsertParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/InsertParam.java index 206e66a627..4c60198c86 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/InsertParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/InsertParam.java @@ -34,6 +34,10 @@ public enum InsertParam implements RestconfQueryParam { */ LAST("last"); + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final @NonNull String uriName = "insert"; + private @NonNull String uriValue; InsertParam(final String uriValue) { @@ -47,7 +51,7 @@ public enum InsertParam implements RestconfQueryParam { @Override public String paramName() { - return uriName(); + return uriName; } @Override @@ -55,10 +59,6 @@ public enum InsertParam implements RestconfQueryParam { return uriValue; } - public static @NonNull String uriName() { - return "insert"; - } - // Note: returns null of unknowns public static @Nullable InsertParam forUriValue(final String uriValue) { switch (uriValue) { diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/PointParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/PointParam.java index 1cfc3c01c8..9e9c3b9b4b 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/PointParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/PointParam.java @@ -18,6 +18,10 @@ import org.eclipse.jdt.annotation.NonNullByDefault; */ @NonNullByDefault public final class PointParam implements RestconfQueryParam { + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final String uriName = "point"; + // FIXME: This should be ApiPath private final String value; @@ -32,7 +36,7 @@ public final class PointParam implements RestconfQueryParam { @Override public String paramName() { - return uriName(); + return uriName; } @Override @@ -44,10 +48,6 @@ public final class PointParam implements RestconfQueryParam { return new PointParam(uriValue); } - public static String uriName() { - return "point"; - } - public String value() { return value; } diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/RestconfQueryParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/RestconfQueryParam.java index f3f43996dd..f14a72095d 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/RestconfQueryParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/RestconfQueryParam.java @@ -13,6 +13,14 @@ import org.opendaylight.yangtools.concepts.Immutable; /** * Interface implemented by all Java classes which represent a * RESTCONF query parameter. + * + *

+ * Implementations of this interface are required to expose a {@code public static @NonNull uriName} constant, which + * holds the well-known URI Request Query Parameter name of the associated definition. + * + *

+ * This naming violates the usual Java coding style, we need it to keep API consistency as an enum can be used as an + * implementation, in which case users could be confused by upper-case constants which are not enum members. */ // FIXME: sealed when we have JDK17+? public interface RestconfQueryParam> extends Immutable { diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/StartTimeParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/StartTimeParam.java index 3d4c0acae8..4fbecb87a1 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/StartTimeParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/StartTimeParam.java @@ -15,6 +15,10 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types. * RFC8040 section 4.8.7. */ public final class StartTimeParam extends AbstractReplayParam { + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final @NonNull String uriName = "start-time"; + private StartTimeParam(final DateAndTime value) { super(value); } @@ -30,11 +34,7 @@ public final class StartTimeParam extends AbstractReplayParam { @Override public String paramName() { - return uriName(); - } - - public static @NonNull String uriName() { - return "start-time"; + return uriName; } public static @NonNull StartTimeParam forUriValue(final String uriValue) { diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/StopTimeParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/StopTimeParam.java index 0c3fa6cbc4..51067d4cde 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/StopTimeParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/StopTimeParam.java @@ -15,6 +15,10 @@ import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.yang.types. * RFC8040 section 4.8.8. */ public final class StopTimeParam extends AbstractReplayParam { + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final @NonNull String uriName = "stop-time"; + private StopTimeParam(final DateAndTime value) { super(value); } @@ -30,11 +34,7 @@ public final class StopTimeParam extends AbstractReplayParam { @Override public String paramName() { - return uriName(); - } - - public static @NonNull String uriName() { - return "stop-time"; + return uriName; } public static @NonNull StopTimeParam forUriValue(final String uriValue) { diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/WithDefaultsParam.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/WithDefaultsParam.java index daf4e77ca5..aa9f7ac045 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/WithDefaultsParam.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/WithDefaultsParam.java @@ -35,6 +35,10 @@ public enum WithDefaultsParam implements RestconfQueryParam { */ TRIM("trim"); + // API consistency: must not be confused with enum constants + @SuppressWarnings("checkstyle:ConstantName") + public static final @NonNull String uriName = "with-defaults"; + private static final @NonNull URI CAPABILITY = URI.create("urn:ietf:params:restconf:capability:with-defaults:1.0"); private final @NonNull String uriValue; @@ -50,7 +54,7 @@ public enum WithDefaultsParam implements RestconfQueryParam { @Override public String paramName() { - return uriName(); + return uriName; } @Override @@ -58,10 +62,6 @@ public enum WithDefaultsParam implements RestconfQueryParam { return uriValue; } - public static @NonNull String uriName() { - return "with-defaults"; - } - public static @Nullable WithDefaultsParam forUriValue(final String uriValue) { switch (uriValue) { case "explicit": diff --git a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java index f3c766bb20..db7bb59c3f 100644 --- a/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java +++ b/restconf/restconf-nb-rfc8040/src/main/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParams.java @@ -44,14 +44,20 @@ import org.opendaylight.yangtools.yang.common.ErrorType; @Beta public final class QueryParams { - private static final Set ALLOWED_PARAMETERS = Set.of(ContentParam.uriName(), DepthParam.uriName(), - FieldsParam.uriName(), WithDefaultsParam.uriName()); private static final List POSSIBLE_CONTENT = Arrays.stream(ContentParam.values()) .map(ContentParam::paramValue) .collect(Collectors.toUnmodifiableList()); private static final List POSSIBLE_WITH_DEFAULTS = Arrays.stream(WithDefaultsParam.values()) .map(WithDefaultsParam::paramValue) .collect(Collectors.toUnmodifiableList()); + private static final Set KNOWN_PARAMS = Set.of( + // Read data + ContentParam.uriName, DepthParam.uriName, FieldsParam.uriName, WithDefaultsParam.uriName, + // Modify data + InsertParam.uriName, PointParam.uriName, + // Notifications + FilterParam.uriName, StartTimeParam.uriName, StopTimeParam.uriName ,"odl-skip-notification-data"); + private QueryParams() { // Utility class @@ -68,23 +74,26 @@ public final class QueryParams { final List paramValues = entry.getValue(); try { - if (paramName.equals(StartTimeParam.uriName())) { - startTime = optionalParam(StartTimeParam::forUriValue, paramName, paramValues); - break; - } else if (paramName.equals(StopTimeParam.uriName())) { - stopTime = optionalParam(StopTimeParam::forUriValue, paramName, paramValues); - break; - } else if (paramName.equals(FilterParam.uriName())) { - filter = optionalParam(FilterParam::forUriValue, paramName, paramValues); - } else if (paramName.equals("odl-skip-notification-data")) { - // FIXME: this should be properly encapsulated in SkipNotificatioDataParameter - skipNotificationData = Boolean.parseBoolean(optionalParam(paramName, paramValues)); - } else { - throw new RestconfDocumentedException("Bad parameter used with notifications: " + paramName, - ErrorType.PROTOCOL, ErrorTag. UNKNOWN_ATTRIBUTE); + switch (paramName) { + case FilterParam.uriName: + filter = optionalParam(FilterParam::forUriValue, paramName, paramValues); + break; + case StartTimeParam.uriName: + startTime = optionalParam(StartTimeParam::forUriValue, paramName, paramValues); + break; + case StopTimeParam.uriName: + stopTime = optionalParam(StopTimeParam::forUriValue, paramName, paramValues); + break; + case "odl-skip-notification-data": + // FIXME: this should be properly encapsulated in SkipNotificatioDataParameter + skipNotificationData = Boolean.parseBoolean(optionalParam(paramName, paramValues)); + break; + default: + throw unhandledParam("notification", paramName); } } catch (IllegalArgumentException e) { - throw new RestconfDocumentedException("Invalid " + paramName + " value: " + e.getMessage(), e); + throw new RestconfDocumentedException("Invalid " + paramName + " value: " + e.getMessage(), + ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, e); } } @@ -124,60 +133,64 @@ public final class QueryParams { final String paramName = entry.getKey(); final List paramValues = entry.getValue(); - if (paramName.equals(ContentParam.uriName())) { - final String str = optionalParam(paramName, paramValues); - if (str != null) { - content = RestconfDocumentedException.throwIfNull(ContentParam.forUriValue(str), - ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, - "Invalid content parameter: %s, allowed values are %s", str, POSSIBLE_CONTENT); - } - } else if (paramName.equals(DepthParam.uriName())) { - final String str = optionalParam(paramName, paramValues); - try { - depth = DepthParam.forUriValue(str); - } catch (IllegalArgumentException e) { - throw new RestconfDocumentedException(e, new RestconfError(ErrorType.PROTOCOL, - ErrorTag.INVALID_VALUE, "Invalid depth parameter: " + str, null, - "The depth parameter must be an integer between 1 and 65535 or \"unbounded\"")); - } - } else if (paramName.equals(FieldsParam.uriName())) { - final String str = optionalParam(paramName, paramValues); - if (str != null) { + switch (paramName) { + case ContentParam.uriName: + final String contentStr = optionalParam(paramName, paramValues); + if (contentStr != null) { + content = RestconfDocumentedException.throwIfNull(ContentParam.forUriValue(contentStr), + ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE, + "Invalid content parameter: %s, allowed values are %s", contentStr, POSSIBLE_CONTENT); + } + break; + case DepthParam.uriName: + final String depthStr = optionalParam(paramName, paramValues); try { - fields = FieldsParam.parse(str); - } catch (ParseException e) { + depth = DepthParam.forUriValue(depthStr); + } catch (IllegalArgumentException e) { throw new RestconfDocumentedException(e, new RestconfError(ErrorType.PROTOCOL, - ErrorTag.INVALID_VALUE, "Invalid filds parameter: " + str)); + ErrorTag.INVALID_VALUE, "Invalid depth parameter: " + depthStr, null, + "The depth parameter must be an integer between 1 and 65535 or \"unbounded\"")); } - } - } else if (paramName.equals(WithDefaultsParam.uriName())) { - final String str = optionalParam(paramName, paramValues); - if (str != null) { - final WithDefaultsParam val = WithDefaultsParam.forUriValue(str); - if (val == null) { - throw new RestconfDocumentedException(new RestconfError(ErrorType.PROTOCOL, - ErrorTag.INVALID_VALUE, "Invalid with-defaults parameter: " + str, null, - "The with-defaults parameter must be a string in " + POSSIBLE_WITH_DEFAULTS)); + break; + case FieldsParam.uriName: + final String fieldsStr = optionalParam(paramName, paramValues); + if (fieldsStr != null) { + try { + fields = FieldsParam.parse(fieldsStr); + } catch (ParseException e) { + throw new RestconfDocumentedException(e, new RestconfError(ErrorType.PROTOCOL, + ErrorTag.INVALID_VALUE, "Invalid filds parameter: " + fieldsStr)); + } } + break; + case WithDefaultsParam.uriName: + final String withDefaultsStr = optionalParam(paramName, paramValues); + if (withDefaultsStr != null) { + final WithDefaultsParam val = WithDefaultsParam.forUriValue(withDefaultsStr); + if (val == null) { + throw new RestconfDocumentedException(new RestconfError(ErrorType.PROTOCOL, + ErrorTag.INVALID_VALUE, "Invalid with-defaults parameter: " + withDefaultsStr, null, + "The with-defaults parameter must be a string in " + POSSIBLE_WITH_DEFAULTS)); + } - switch (val) { - case REPORT_ALL: - withDefaults = null; - tagged = false; - break; - case REPORT_ALL_TAGGED: - withDefaults = null; - tagged = true; - break; - default: - withDefaults = val; - tagged = false; + switch (val) { + case REPORT_ALL: + withDefaults = null; + tagged = false; + break; + case REPORT_ALL_TAGGED: + withDefaults = null; + tagged = true; + break; + default: + withDefaults = val; + tagged = false; + } } - } - } else { - // FIXME: recognize pretty-print here - throw new RestconfDocumentedException("Not allowed parameter for read operation: " + paramName, - ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE); + break; + default: + // FIXME: recognize pretty-print here + throw unhandledParam("read", paramName); } } @@ -191,23 +204,26 @@ public final class QueryParams { for (final Entry> entry : uriInfo.getQueryParameters().entrySet()) { final String uriName = entry.getKey(); final List paramValues = entry.getValue(); - if (uriName.equals(InsertParam.uriName())) { - final String str = optionalParam(uriName, paramValues); - if (str != null) { - insert = InsertParam.forUriValue(str); - if (insert == null) { - throw new RestconfDocumentedException("Unrecognized insert parameter value '" + str + "'", - ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT); + switch (uriName) { + case InsertParam.uriName: + final String instartStr = optionalParam(uriName, paramValues); + if (instartStr != null) { + insert = InsertParam.forUriValue(instartStr); + if (insert == null) { + throw new RestconfDocumentedException( + "Unrecognized insert parameter value '" + instartStr + "'", ErrorType.PROTOCOL, + ErrorTag.BAD_ELEMENT); + } } - } - } else if (PointParam.uriName().equals(uriName)) { - final String str = optionalParam(uriName, paramValues); - if (str != null) { - point = PointParam.forUriValue(str); - } - } else { - throw new RestconfDocumentedException("Bad parameter for post: " + uriName, - ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE); + break; + case PointParam.uriName: + final String pointStr = optionalParam(uriName, paramValues); + if (pointStr != null) { + point = PointParam.forUriValue(pointStr); + } + break; + default: + throw unhandledParam("write", uriName); } } @@ -218,6 +234,14 @@ public final class QueryParams { } } + private static RestconfDocumentedException unhandledParam(final String operation, final String name) { + return KNOWN_PARAMS.contains(name) + ? new RestconfDocumentedException("Invalid parameter in " + operation + ": " + name, + ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE) + : new RestconfDocumentedException("Unknown parameter in " + operation + ": " + name, + ErrorType.PROTOCOL, ErrorTag.UNKNOWN_ATTRIBUTE); + } + @VisibleForTesting static @Nullable String optionalParam(final String name, final List values) { switch (values.size()) { diff --git a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParamsTest.java b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParamsTest.java index 4f2b51d38c..995828d72f 100644 --- a/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParamsTest.java +++ b/restconf/restconf-nb-rfc8040/src/test/java/org/opendaylight/restconf/nb/rfc8040/databind/jaxrs/QueryParamsTest.java @@ -11,26 +11,27 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import java.util.List; import java.util.Set; +import java.util.function.Function; import javax.ws.rs.core.MultivaluedHashMap; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.UriInfo; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; 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.ContentParam; import org.opendaylight.restconf.nb.rfc8040.DepthParam; -import org.opendaylight.restconf.nb.rfc8040.ReadDataParams; +import org.opendaylight.restconf.nb.rfc8040.InsertParam; +import org.opendaylight.restconf.nb.rfc8040.RestconfQueryParam; import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParam; import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters; import org.opendaylight.yangtools.yang.common.ErrorTag; @@ -42,23 +43,12 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode; @RunWith(MockitoJUnitRunner.StrictStubs.class) public class QueryParamsTest { - @Mock - public InstanceIdentifierContext context; - @Mock - public UriInfo uriInfo; - @Mock - public EffectiveModelContext modelContext; - @Mock - public ContainerSchemaNode containerSchema; - @Mock - public LeafSchemaNode containerChildSchema; - /** * Test when parameter is present at most once. */ @Test public void optionalParamTest() { - assertEquals("all", QueryParams.optionalParam(ContentParam.uriName(), List.of("all"))); + assertEquals("all", QueryParams.optionalParam(ContentParam.uriName, List.of("all"))); } /** @@ -67,7 +57,7 @@ public class QueryParamsTest { @Test public void optionalParamMultipleTest() { final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class, - () -> QueryParams.optionalParam(ContentParam.uriName(), List.of("config", "nonconfig", "all"))); + () -> QueryParams.optionalParam(ContentParam.uriName, List.of("config", "nonconfig", "all"))); final List errors = ex.getErrors(); assertEquals(1, errors.size()); @@ -81,16 +71,13 @@ public class QueryParamsTest { */ @Test public void checkParametersTypesNegativeTest() { - mockQueryParameter("not-allowed-parameter", "does-not-matter"); - - final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class, - () -> QueryParams.newWriteDataParams(uriInfo)); - final List errors = ex.getErrors(); - assertEquals(1, errors.size()); + assertUnknownParam(QueryParams::newNotificationQueryParams); + assertUnknownParam(QueryParams::newReadDataParams); + assertUnknownParam(QueryParams::newWriteDataParams); - final RestconfError error = errors.get(0); - assertEquals("Error type is not correct", ErrorType.PROTOCOL, error.getErrorType()); - assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, error.getErrorTag()); + assertInvalidParam(QueryParams::newNotificationQueryParams, ContentParam.ALL); + assertInvalidParam(QueryParams::newReadDataParams, InsertParam.LAST); + assertInvalidParam(QueryParams::newWriteDataParams, ContentParam.ALL); } /** @@ -99,86 +86,22 @@ public class QueryParamsTest { @Test public void parseUriParametersDefaultTest() { // no parameters, default values should be used - mockQueryParameters(new MultivaluedHashMap()); - - final var parsedParameters = QueryParams.newReadDataParams(uriInfo); - assertEquals(ContentParam.ALL, parsedParameters.content()); - assertNull(parsedParameters.depth()); - assertNull(parsedParameters.fields()); + final var params = assertParams(QueryParams::newReadDataParams, new MultivaluedHashMap()); + assertEquals(ContentParam.ALL, params.content()); + assertNull(params.depth()); + assertNull(params.fields()); } - /** - * Testing parsing of with-defaults parameter which value which is not supported. - */ @Test - public void parseUriParametersWithDefaultInvalidTest() { - // preparation of input data - mockQueryParameter("with-defaults", "invalid"); - - final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class, - () -> QueryParams.newReadDataParams(uriInfo)); - final List errors = ex.getErrors(); - assertEquals(1, errors.size()); - assertEquals(ErrorTag.INVALID_VALUE, errors.get(0).getErrorTag()); - } - - /** - * Negative test of parsing request URI parameters when depth parameter has not allowed value. - */ - @Test - public void parseUriParametersDepthParameterNegativeTest() { - // inserted value is not allowed - mockQueryParameter("depth", "bounded"); - - RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class, - () -> QueryParams.newReadDataParams(uriInfo)); - // Bad request - assertEquals("Error type is not correct", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType()); - assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, ex.getErrors().get(0).getErrorTag()); - } - - /** - * Negative test of parsing request URI parameters when content parameter has not allowed value. - */ - @Test - public void parseUriParametersContentParameterNegativeTest() { - mockQueryParameter("content", "not-allowed-parameter-value"); - - final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class, - () -> QueryParams.newReadDataParams(uriInfo)); - // Bad request - assertEquals("Error type is not correct", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType()); - assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, ex.getErrors().get(0).getErrorTag()); - } + public void testInvalidValueReadDataParams() { + assertInvalidValue(QueryParams::newReadDataParams, ContentParam.uriName); + assertInvalidValue(QueryParams::newReadDataParams, DepthParam.uriName); + assertInvalidValue(QueryParams::newReadDataParams, WithDefaultsParam.uriName); - /** - * Negative test of parsing request URI parameters when depth parameter has not allowed value (more than maximum). - */ - @Test - public void parseUriParametersDepthMaximalParameterNegativeTest() { // inserted value is too high - mockQueryParameter("depth", "65536"); - - RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class, - () -> QueryParams.newReadDataParams(uriInfo)); - // Bad request - assertEquals("Error type is not correct", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType()); - assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, ex.getErrors().get(0).getErrorTag()); - } - - /** - * Negative test of parsing request URI parameters when depth parameter has not allowed value (less than minimum). - */ - @Test - public void parseUriParametersDepthMinimalParameterNegativeTest() { + assertInvalidValue(QueryParams::newReadDataParams, DepthParam.uriName, "65536"); // inserted value is too low - mockQueryParameter("depth", "0"); - - RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class, - () -> QueryParams.newReadDataParams(uriInfo)); - // Bad request - assertEquals("Error type is not correct", ErrorType.PROTOCOL, ex.getErrors().get(0).getErrorType()); - assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, ex.getErrors().get(0).getErrorTag()); + assertInvalidValue(QueryParams::newReadDataParams, DepthParam.uriName, "0"); } /** @@ -187,12 +110,9 @@ public class QueryParamsTest { */ @Test public void parseUriParametersWithDefaultAndTaggedTest() { - // preparation of input data - mockQueryParameter("with-defaults", "report-all-tagged"); - - final var parsedParameters = QueryParams.newReadDataParams(uriInfo); - assertNull(parsedParameters.withDefaults()); - assertTrue(parsedParameters.tagged()); + final var params = assertParams(QueryParams::newReadDataParams, WithDefaultsParam.uriName, "report-all-tagged"); + assertNull(params.withDefaults()); + assertTrue(params.tagged()); } /** @@ -201,12 +121,9 @@ public class QueryParamsTest { */ @Test public void parseUriParametersWithDefaultAndReportAllTest() { - // preparation of input data - mockQueryParameter("with-defaults", "report-all"); - - final var parsedParameters = QueryParams.newReadDataParams(uriInfo); - assertNull(parsedParameters.withDefaults()); - assertFalse(parsedParameters.tagged()); + final var params = assertParams(QueryParams::newReadDataParams, WithDefaultsParam.uriName, "report-all"); + assertNull(params.withDefaults()); + assertFalse(params.tagged()); } /** @@ -215,12 +132,9 @@ public class QueryParamsTest { */ @Test public void parseUriParametersWithDefaultAndNonTaggedTest() { - // preparation of input data - mockQueryParameter("with-defaults", "explicit"); - - final var parsedParameters = QueryParams.newReadDataParams(uriInfo); - assertSame(WithDefaultsParam.EXPLICIT, parsedParameters.withDefaults()); - assertFalse(parsedParameters.tagged()); + final var params = assertParams(QueryParams::newReadDataParams, WithDefaultsParam.uriName, "explicit"); + assertEquals(WithDefaultsParam.EXPLICIT, params.withDefaults()); + assertFalse(params.tagged()); } /** @@ -230,45 +144,89 @@ public class QueryParamsTest { public void parseUriParametersUserDefinedTest() { final QName containerChild = QName.create("ns", "container-child"); - final MultivaluedMap parameters = new MultivaluedHashMap<>(); + final var parameters = new MultivaluedHashMap(); parameters.putSingle("content", "config"); parameters.putSingle("depth", "10"); parameters.putSingle("fields", "container-child"); - mockQueryParameters(parameters); - final ReadDataParams parsedParameters = QueryParams.newReadDataParams(uriInfo); + final var params = assertParams(QueryParams::newReadDataParams, parameters); // content - assertEquals(ContentParam.CONFIG, parsedParameters.content()); + assertEquals(ContentParam.CONFIG, params.content()); // depth - final DepthParam depth = parsedParameters.depth(); + final DepthParam depth = params.depth(); assertNotNull(depth); assertEquals(10, depth.value()); // fields - assertNotNull(parsedParameters.fields()); + assertNotNull(params.fields()); // fields for write filtering + final var containerSchema = mock(ContainerSchemaNode.class); doReturn(QName.create(containerChild, "container")).when(containerSchema).getQName(); - doReturn(containerChildSchema).when(containerSchema).dataChildByName(containerChild); + final var containerChildSchema = mock(LeafSchemaNode.class); doReturn(containerChild).when(containerChildSchema).getQName(); + doReturn(containerChildSchema).when(containerSchema).dataChildByName(containerChild); + final var context = mock(InstanceIdentifierContext.class); + final var modelContext = mock(EffectiveModelContext.class); doReturn(modelContext).when(context).getSchemaContext(); doReturn(containerSchema).when(context).getSchemaNode(); - final QueryParameters queryParameters = QueryParams.newQueryParameters(parsedParameters, context); + final QueryParameters queryParameters = QueryParams.newQueryParameters(params, context); final List> fields = queryParameters.fields(); assertNotNull(fields); assertEquals(1, fields.size()); assertEquals(Set.of(containerChild), fields.get(0)); } - private void mockQueryParameter(final String name, final String value) { - final MultivaluedMap parameters = new MultivaluedHashMap<>(); - parameters.putSingle(name, value); - mockQueryParameters(parameters); + private static void assertInvalidParam(final Function paramsMethod, final RestconfQueryParam param) { + final var params = new MultivaluedHashMap(); + params.putSingle(param.paramName(), "odl-test-value"); + assertParamsThrows(ErrorTag.MALFORMED_MESSAGE, paramsMethod, params); + } + + private static void assertUnknownParam(final Function paramsMethod) { + final var params = new MultivaluedHashMap(); + params.putSingle("odl-unknown-param", "odl-test-value"); + assertParamsThrows(ErrorTag.UNKNOWN_ATTRIBUTE, paramsMethod, params); + } + + private static void assertInvalidValue(final Function paramsMethod, final String name) { + assertInvalidValue(paramsMethod, name, "odl-invalid-value"); + } + + private static void assertInvalidValue(final Function paramsMethod, final String name, + final String value) { + final var params = new MultivaluedHashMap(); + params.putSingle(name, value); + assertParamsThrows(ErrorTag.INVALID_VALUE, paramsMethod, params); + } + + private static void assertParamsThrows(final ErrorTag expectedTag, final Function paramsMethod, + final MultivaluedMap params) { + final var uriInfo = mock(UriInfo.class); + doReturn(params).when(uriInfo).getQueryParameters(); + + final var ex = assertThrows(RestconfDocumentedException.class, () -> paramsMethod.apply(uriInfo)); + final var errors = ex.getErrors(); + assertEquals(1, errors.size()); + + final var error = errors.get(0); + assertEquals(ErrorType.PROTOCOL, error.getErrorType()); + assertEquals(expectedTag, error.getErrorTag()); + } + + private static T assertParams(final Function paramsMethod, final String name, + final String value) { + final var params = new MultivaluedHashMap(); + params.putSingle(name, value); + return assertParams(paramsMethod, params); } - private void mockQueryParameters(final MultivaluedMap parameters) { - doReturn(parameters).when(uriInfo).getQueryParameters(); + private static T assertParams(final Function paramsMethod, + final MultivaluedMap params) { + final var uriInfo = mock(UriInfo.class); + doReturn(params).when(uriInfo).getQueryParameters(); + return paramsMethod.apply(uriInfo); } }