package org.opendaylight.restconf.nb.rfc8040.databind.jaxrs;
import static java.util.Objects.requireNonNull;
+import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter.parseFieldsParameter;
+import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter.parseFieldsPaths;
import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
+import java.util.Set;
import java.util.function.Function;
+import java.util.stream.Collectors;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
+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.ContentParameter;
+import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
+import org.opendaylight.restconf.nb.rfc8040.FieldsParameter;
import org.opendaylight.restconf.nb.rfc8040.FilterParameter;
import org.opendaylight.restconf.nb.rfc8040.InsertParameter;
import org.opendaylight.restconf.nb.rfc8040.NotificationQueryParams;
import org.opendaylight.restconf.nb.rfc8040.PointParameter;
import org.opendaylight.restconf.nb.rfc8040.StartTimeParameter;
import org.opendaylight.restconf.nb.rfc8040.StopTimeParameter;
+import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParameter;
import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
+import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
+import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters.Builder;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
@Beta
public final class QueryParams {
+ private static final Set<String> ALLOWED_PARAMETERS = Set.of(ContentParameter.uriName(), DepthParameter.uriName(),
+ FieldsParameter.uriName(), WithDefaultsParameter.uriName());
+ private static final List<String> POSSIBLE_CONTENT = Arrays.stream(ContentParameter.values())
+ .map(ContentParameter::uriValue)
+ .collect(Collectors.toUnmodifiableList());
+ private static final List<String> POSSIBLE_WITH_DEFAULTS = Arrays.stream(WithDefaultsParameter.values())
+ .map(WithDefaultsParameter::uriValue)
+ .collect(Collectors.toUnmodifiableList());
+
private QueryParams() {
// Utility class
}
}
}
+ /**
+ * Parse parameters from URI request and check their types and values.
+ *
+ * @param identifier {@link InstanceIdentifierContext}
+ * @param uriInfo URI info
+ * @return {@link QueryParameters}
+ */
+ public static QueryParameters newReadDataParams(final InstanceIdentifierContext<?> identifier,
+ final UriInfo uriInfo) {
+ if (uriInfo == null) {
+ return QueryParameters.empty();
+ }
+
+ // check only allowed parameters
+ final MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
+ checkParametersTypes(queryParams.keySet(), ALLOWED_PARAMETERS);
+
+ final Builder builder = QueryParameters.builder();
+ // check and set content
+ final String contentStr = getSingleParameter(queryParams, ContentParameter.uriName());
+ if (contentStr != null) {
+ builder.setContent(RestconfDocumentedException.throwIfNull(
+ ContentParameter.forUriValue(contentStr), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ "Invalid content parameter: %s, allowed values are %s", contentStr, POSSIBLE_CONTENT));
+ }
+
+ // check and set depth
+ final String depthStr = getSingleParameter(queryParams, DepthParameter.uriName());
+ if (depthStr != null) {
+ try {
+ builder.setDepth(DepthParameter.forUriValue(depthStr));
+ } catch (IllegalArgumentException e) {
+ throw new RestconfDocumentedException(e, new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
+ "Invalid depth parameter: " + depthStr, null,
+ "The depth parameter must be an integer between 1 and 65535 or \"unbounded\""));
+ }
+ }
+
+ // check and set fields
+ final String fieldsStr = getSingleParameter(queryParams, FieldsParameter.uriName());
+ if (fieldsStr != null) {
+ // FIXME: parse a FieldsParameter instead
+ if (identifier.getMountPoint() != null) {
+ builder.setFieldPaths(parseFieldsPaths(identifier, fieldsStr));
+ } else {
+ builder.setFields(parseFieldsParameter(identifier, fieldsStr));
+ }
+ }
+
+ // check and set withDefaults parameter
+ final String withDefaultsStr = getSingleParameter(queryParams, WithDefaultsParameter.uriName());
+ if (withDefaultsStr != null) {
+ final WithDefaultsParameter val = WithDefaultsParameter.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:
+ break;
+ case REPORT_ALL_TAGGED:
+ builder.setTagged(true);
+ break;
+ default:
+ builder.setWithDefault(val);
+ }
+ }
+
+ return builder.build();
+ }
+
public static @NonNull WriteDataParams newWriteDataParams(final UriInfo uriInfo) {
InsertParameter insert = null;
PointParameter point = null;
}
}
- public static @Nullable String getSingleParameter(final MultivaluedMap<String, String> params, final String name) {
+ /**
+ * Check if URI does not contain not allowed parameters for specified operation.
+ *
+ * @param usedParameters parameters used in URI request
+ * @param allowedParameters allowed parameters for operation
+ */
+ @VisibleForTesting
+ static void checkParametersTypes(final Set<String> usedParameters, final Set<String> allowedParameters) {
+ if (!allowedParameters.containsAll(usedParameters)) {
+ final Set<String> notAllowedParameters = usedParameters.stream()
+ .filter(param -> !allowedParameters.contains(param))
+ .collect(Collectors.toSet());
+ throw new RestconfDocumentedException("Not allowed parameters for read operation: " + notAllowedParameters,
+ ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+ }
+ }
+
+ @VisibleForTesting
+ static @Nullable String getSingleParameter(final MultivaluedMap<String, String> params, final String name) {
final var values = params.get(name);
return values == null ? null : optionalParam(name, values);
}
final EffectiveModelContext schemaContextRef = schemaContextHandler.get();
final InstanceIdentifierContext<?> instanceIdentifier = ParserIdentifier.toInstanceIdentifier(
identifier, schemaContextRef, Optional.of(mountPointService));
- final QueryParameters parameters = ReadDataTransactionUtil.parseUriParameters(instanceIdentifier, uriInfo);
+ final QueryParameters parameters = QueryParams.newReadDataParams(instanceIdentifier, uriInfo);
final DOMMountPoint mountPoint = instanceIdentifier.getMountPoint();
*/
package org.opendaylight.restconf.nb.rfc8040.rests.utils;
-import static org.opendaylight.restconf.nb.rfc8040.databind.jaxrs.QueryParams.getSingleParameter;
-import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter.parseFieldsParameter;
-import static org.opendaylight.restconf.nb.rfc8040.utils.parser.ParserFieldsParameter.parseFieldsPaths;
-
-import com.google.common.annotations.VisibleForTesting;
import com.google.common.util.concurrent.ListenableFuture;
-import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
-import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
-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.ContentParameter;
-import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
-import org.opendaylight.restconf.nb.rfc8040.FieldsParameter;
import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParameter;
-import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
* </ul>
*/
public final class ReadDataTransactionUtil {
- private static final Set<String> ALLOWED_PARAMETERS = Set.of(ContentParameter.uriName(), DepthParameter.uriName(),
- FieldsParameter.uriName(), WithDefaultsParameter.uriName());
- private static final List<String> POSSIBLE_CONTENT = Arrays.stream(ContentParameter.values())
- .map(ContentParameter::uriValue)
- .collect(Collectors.toUnmodifiableList());
- private static final List<String> POSSIBLE_WITH_DEFAULTS = Arrays.stream(WithDefaultsParameter.values())
- .map(WithDefaultsParameter::uriValue)
- .collect(Collectors.toUnmodifiableList());
-
- private static final String READ_TYPE_TX = "READ";
-
private ReadDataTransactionUtil() {
// Hidden on purpose
}
- /**
- * Parse parameters from URI request and check their types and values.
- *
- * @param identifier {@link InstanceIdentifierContext}
- * @param uriInfo URI info
- * @return {@link QueryParameters}
- */
- public static QueryParameters parseUriParameters(final InstanceIdentifierContext<?> identifier,
- final UriInfo uriInfo) {
- final QueryParameters.Builder builder = QueryParameters.builder();
- if (uriInfo == null) {
- return builder.build();
- }
-
- // check only allowed parameters
- final MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
- checkParametersTypes(queryParams.keySet(), ALLOWED_PARAMETERS);
-
- // check and set content
- final String contentStr = getSingleParameter(queryParams, ContentParameter.uriName());
- if (contentStr != null) {
- builder.setContent(RestconfDocumentedException.throwIfNull(
- ContentParameter.forUriValue(contentStr), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
- "Invalid content parameter: %s, allowed values are %s", contentStr, POSSIBLE_CONTENT));
- }
-
- // check and set depth
- final String depthStr = getSingleParameter(queryParams, DepthParameter.uriName());
- if (depthStr != null) {
- try {
- builder.setDepth(DepthParameter.forUriValue(depthStr));
- } catch (IllegalArgumentException e) {
- throw new RestconfDocumentedException(e, new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
- "Invalid depth parameter: " + depthStr, null,
- "The depth parameter must be an integer between 1 and 65535 or \"unbounded\""));
- }
- }
-
- // check and set fields
- final String fieldsStr = getSingleParameter(queryParams, FieldsParameter.uriName());
- if (fieldsStr != null) {
- // FIXME: parse a FieldsParameter instead
- if (identifier.getMountPoint() != null) {
- builder.setFieldPaths(parseFieldsPaths(identifier, fieldsStr));
- } else {
- builder.setFields(parseFieldsParameter(identifier, fieldsStr));
- }
- }
-
- // check and set withDefaults parameter
- final String withDefaultsStr = getSingleParameter(queryParams, WithDefaultsParameter.uriName());
- if (withDefaultsStr != null) {
- final WithDefaultsParameter val = WithDefaultsParameter.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:
- break;
- case REPORT_ALL_TAGGED:
- builder.setTagged(true);
- break;
- default:
- builder.setWithDefault(val);
- }
- }
-
- return builder.build();
- }
-
/**
* Read specific type of data from data store via transaction. Close {@link DOMTransactionChain} if any
* inside of object {@link RestconfStrategy} provided as a parameter.
}
}
- /**
- * Check if URI does not contain not allowed parameters for specified operation.
- *
- * @param usedParameters parameters used in URI request
- * @param allowedParameters allowed parameters for operation
- */
- @VisibleForTesting
- static void checkParametersTypes(final Set<String> usedParameters, final Set<String> allowedParameters) {
- if (!allowedParameters.containsAll(usedParameters)) {
- final Set<String> notAllowedParameters = usedParameters.stream()
- .filter(param -> !allowedParameters.contains(param))
- .collect(Collectors.toSet());
- throw new RestconfDocumentedException(
- "Not allowed parameters for " + READ_TYPE_TX + " operation: " + notAllowedParameters,
- ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
- }
- }
-
private static NormalizedNode prepareDataByParamWithDef(final NormalizedNode result,
final YangInstanceIdentifier path, final WithDefaultsParameter withDefa, final EffectiveModelContext ctx) {
boolean trim;
private static NormalizedNode extractReadData(final RestconfStrategy strategy,
final YangInstanceIdentifier path, final ListenableFuture<Optional<NormalizedNode>> dataFuture) {
final NormalizedNodeFactory dataFactory = new NormalizedNodeFactory();
- FutureCallbackTx.addCallback(dataFuture, READ_TYPE_TX, dataFactory, path);
+ FutureCallbackTx.addCallback(dataFuture, "READ", dataFactory, path);
return dataFactory.build();
}
import static org.junit.Assert.assertThrows;
import java.util.List;
+import java.util.Set;
import javax.ws.rs.core.MultivaluedHashMap;
import org.junit.Test;
import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
import org.opendaylight.restconf.common.errors.RestconfError;
import org.opendaylight.restconf.nb.rfc8040.ContentParameter;
+import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
import org.opendaylight.yangtools.yang.common.ErrorTag;
import org.opendaylight.yangtools.yang.common.ErrorType;
assertEquals("Error type is not correct", ErrorType.PROTOCOL, error.getErrorType());
assertEquals("Error tag is not correct", ErrorTag.INVALID_VALUE, error.getErrorTag());
}
+
+ /**
+ * Test when all parameters are allowed.
+ */
+ @Test
+ public void checkParametersTypesTest() {
+ QueryParams.checkParametersTypes(Set.of("content"),
+ Set.of(ContentParameter.uriName(), DepthParameter.uriName()));
+ }
+
+ /**
+ * Test when not allowed parameter type is used.
+ */
+ @Test
+ public void checkParametersTypesNegativeTest() {
+ final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
+ () -> QueryParams.checkParametersTypes(Set.of("not-allowed-parameter"),
+ Set.of(ContentParameter.uriName(), DepthParameter.uriName())));
+ final List<RestconfError> errors = ex.getErrors();
+ assertEquals(1, errors.size());
+
+ 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());
+ }
}
import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.Optional;
-import java.util.Set;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.UriInfo;
import org.eclipse.jdt.annotation.NonNull;
import org.opendaylight.restconf.nb.rfc8040.ContentParameter;
import org.opendaylight.restconf.nb.rfc8040.DepthParameter;
import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParameter;
+import org.opendaylight.restconf.nb.rfc8040.databind.jaxrs.QueryParams;
import org.opendaylight.restconf.nb.rfc8040.legacy.QueryParameters;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.MdsalRestconfStrategy;
import org.opendaylight.restconf.nb.rfc8040.rests.transactions.NetconfRestconfStrategy;
// no parameters, default values should be used
when(uriInfo.getQueryParameters()).thenReturn(parameters);
- final QueryParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
+ final QueryParameters parsedParameters = QueryParams.newReadDataParams(context, uriInfo);
assertEquals(ContentParameter.ALL, parsedParameters.getContent());
assertNull(parsedParameters.getDepth());
when(uriInfo.getQueryParameters()).thenReturn(parameters);
- final QueryParameters parsedParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
+ final QueryParameters parsedParameters = QueryParams.newReadDataParams(context, uriInfo);
// content
assertEquals(ContentParameter.CONFIG, parsedParameters.getContent());
when(uriInfo.getQueryParameters()).thenReturn(parameters);
final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
- () -> ReadDataTransactionUtil.parseUriParameters(context, uriInfo));
+ () -> QueryParams.newReadDataParams(context, 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());
when(uriInfo.getQueryParameters()).thenReturn(parameters);
RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
- () -> ReadDataTransactionUtil.parseUriParameters(context, uriInfo));
+ () -> QueryParams.newReadDataParams(context, 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());
when(uriInfo.getQueryParameters()).thenReturn(parameters);
RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
- () -> ReadDataTransactionUtil.parseUriParameters(context, uriInfo));
+ () -> QueryParams.newReadDataParams(context, 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());
when(uriInfo.getQueryParameters()).thenReturn(parameters);
RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
- () -> ReadDataTransactionUtil.parseUriParameters(context, uriInfo));
+ () -> QueryParams.newReadDataParams(context, 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());
parameters.putSingle("with-defaults", "explicit");
when(uriInfo.getQueryParameters()).thenReturn(parameters);
- final QueryParameters writerParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
+ final QueryParameters writerParameters = QueryParams.newReadDataParams(context, uriInfo);
assertSame(WithDefaultsParameter.EXPLICIT, writerParameters.getWithDefault());
assertFalse(writerParameters.isTagged());
}
when(uriInfo.getQueryParameters()).thenReturn(parameters);
final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
- () -> ReadDataTransactionUtil.parseUriParameters(context, uriInfo));
+ () -> QueryParams.newReadDataParams(context, uriInfo));
final List<RestconfError> errors = ex.getErrors();
assertEquals(1, errors.size());
assertEquals(ErrorTag.INVALID_VALUE, errors.get(0).getErrorTag());
parameters.putSingle("with-defaults", "report-all-tagged");
when(uriInfo.getQueryParameters()).thenReturn(parameters);
- final QueryParameters writerParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
+ final QueryParameters writerParameters = QueryParams.newReadDataParams(context, uriInfo);
assertNull(writerParameters.getWithDefault());
assertTrue(writerParameters.isTagged());
}
parameters.putSingle("with-defaults", "report-all");
when(uriInfo.getQueryParameters()).thenReturn(parameters);
- final QueryParameters writerParameters = ReadDataTransactionUtil.parseUriParameters(context, uriInfo);
+ final QueryParameters writerParameters = QueryParams.newReadDataParams(context, uriInfo);
assertNull(writerParameters.getWithDefault());
assertFalse(writerParameters.isTagged());
}
- /**
- * Test when all parameters are allowed.
- */
- @Test
- public void checkParametersTypesTest() {
- ReadDataTransactionUtil.checkParametersTypes(Set.of("content"),
- Set.of(ContentParameter.uriName(), DepthParameter.uriName()));
- }
-
- /**
- * Test when not allowed parameter type is used.
- */
- @Test
- public void checkParametersTypesNegativeTest() {
- final RestconfDocumentedException ex = assertThrows(RestconfDocumentedException.class,
- () -> ReadDataTransactionUtil.checkParametersTypes(Set.of("not-allowed-parameter"),
- Set.of(ContentParameter.uriName(), DepthParameter.uriName())));
- final List<RestconfError> errors = ex.getErrors();
- assertEquals(1, errors.size());
-
- 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());
- }
-
/**
* Read specific type of data from data store via transaction.
*