Simplify trimming
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / rests / utils / ReadDataTransactionUtil.java
index dae342590d54af6b5b7b48373df5c7bb86ecf9bd..76f0d6f1a27f72bdc0767b512a68045977cd0667 100644 (file)
@@ -7,34 +7,21 @@
  */
 package org.opendaylight.restconf.nb.rfc8040.rests.utils;
 
-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.primitives.Ints;
 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.ContentParam;
+import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParam;
 import org.opendaylight.restconf.nb.rfc8040.rests.transactions.RestconfStrategy;
 import org.opendaylight.yangtools.yang.common.ErrorTag;
 import org.opendaylight.yangtools.yang.common.ErrorType;
@@ -86,115 +73,10 @@ import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
  * </ul>
  */
 public final class ReadDataTransactionUtil {
-    // depth values
-    // FIXME: these are known to DepthParameter
-    private static final String UNBOUNDED = "unbounded";
-    private static final int MIN_DEPTH = 1;
-    private static final int MAX_DEPTH = 65535;
-
-    private static final Set<String> ALLOWED_PARAMETERS = Set.of(
-        ContentParameter.uriName(),
-        DepthParameter.uriName(),
-        FieldsParameter.uriName(),
-        WithDefaultsParameter.uriName());
-    private static final List<String> DEFAULT_CONTENT = List.of(ContentParameter.ALL.uriValue());
-    private static final List<String> DEFAULT_DEPTH = List.of(UNBOUNDED);
-    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);
-
-        // read parameters from URI or set default values
-        final List<String> content = queryParams.getOrDefault(ContentParameter.uriName(), DEFAULT_CONTENT);
-        final List<String> depth = queryParams.getOrDefault(DepthParameter.uriName(), DEFAULT_DEPTH);
-        final List<String> withDefaults = queryParams.getOrDefault(WithDefaultsParameter.uriName(), List.of());
-        // fields
-        final List<String> fields = queryParams.getOrDefault(FieldsParameter.uriName(), List.of());
-
-        // parameter can be in URI at most once
-        checkParameterCount(content, ContentParameter.uriName());
-        checkParameterCount(depth, DepthParameter.uriName());
-        checkParameterCount(fields, FieldsParameter.uriName());
-        checkParameterCount(withDefaults, WithDefaultsParameter.uriName());
-
-        // check and set content
-        final String contentValueStr = content.get(0);
-        builder.setContent(RestconfDocumentedException.throwIfNull(
-            ContentParameter.forUriValue(contentValueStr), ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
-            "Invalid content parameter: %s, allowed values are %s", contentValueStr, POSSIBLE_CONTENT));
-
-        // check and set depth
-        if (!depth.get(0).equals(UNBOUNDED)) {
-            final Integer value = Ints.tryParse(depth.get(0));
-
-            if (value == null || value < MIN_DEPTH || value > MAX_DEPTH) {
-                throw new RestconfDocumentedException(
-                        new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
-                                "Invalid depth parameter: " + depth, null,
-                                "The depth parameter must be an integer between 1 and 65535 or \"unbounded\""));
-            } else {
-                builder.setDepth(value);
-            }
-        }
-
-        // check and set fields
-        if (!fields.isEmpty()) {
-            if (identifier.getMountPoint() != null) {
-                builder.setFieldPaths(parseFieldsPaths(identifier, fields.get(0)));
-            } else {
-                builder.setFields(parseFieldsParameter(identifier, fields.get(0)));
-            }
-        }
-
-        // check and set withDefaults parameter
-        if (!withDefaults.isEmpty()) {
-            final String str = withDefaults.get(0);
-            final WithDefaultsParameter val = WithDefaultsParameter.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));
-            }
-
-            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.
@@ -206,10 +88,10 @@ public final class ReadDataTransactionUtil {
      * @param ctx            schema context
      * @return {@link NormalizedNode}
      */
-    public static @Nullable NormalizedNode readData(final @NonNull ContentParameter content,
+    public static @Nullable NormalizedNode readData(final @NonNull ContentParam content,
                                                     final @NonNull YangInstanceIdentifier path,
                                                     final @NonNull RestconfStrategy strategy,
-                                                    final WithDefaultsParameter withDefa,
+                                                    final WithDefaultsParam withDefa,
                                                     final EffectiveModelContext ctx) {
         // FIXME: use a switch expression when they are available, removing source of RestconfDocumentedException
         switch (content) {
@@ -223,7 +105,7 @@ public final class ReadDataTransactionUtil {
             default:
                 throw new RestconfDocumentedException(
                         new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
-                                "Invalid content parameter: " + content.uriValue(), null,
+                                "Invalid content parameter: " + content.paramValue(), null,
                                 "The content parameter value must be either config, nonconfig or all (default)"));
         }
     }
@@ -240,9 +122,9 @@ public final class ReadDataTransactionUtil {
      * @param fields         paths to selected subtrees which should be read, relative to to the parent path
      * @return {@link NormalizedNode}
      */
-    public static @Nullable NormalizedNode readData(final @NonNull ContentParameter content,
+    public static @Nullable NormalizedNode readData(final @NonNull ContentParam content,
             final @NonNull YangInstanceIdentifier path, final @NonNull RestconfStrategy strategy,
-            final @Nullable WithDefaultsParameter withDefa, @NonNull final EffectiveModelContext ctx,
+            final @Nullable WithDefaultsParam withDefa, @NonNull final EffectiveModelContext ctx,
             final @NonNull List<YangInstanceIdentifier> fields) {
         // FIXME: use a switch expression when they are available, removing source of RestconfDocumentedException
         switch (content) {
@@ -256,47 +138,13 @@ public final class ReadDataTransactionUtil {
                 return readDataViaTransaction(strategy, LogicalDatastoreType.OPERATIONAL, path, fields);
             default:
                 throw new RestconfDocumentedException(new RestconfError(ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
-                        "Invalid content parameter: " + content.uriValue(), null,
+                        "Invalid content parameter: " + content.paramValue(), null,
                         "The content parameter value must be either config, nonconfig or all (default)"));
         }
     }
 
-    /**
-     * Check if URI does not contain value for the same parameter more than once.
-     *
-     * @param parameterValues URI parameter values
-     * @param parameterName URI parameter name
-     */
-    @VisibleForTesting
-    static void checkParameterCount(final @NonNull List<String> parameterValues, final @NonNull String parameterName) {
-        if (parameterValues.size() > 1) {
-            throw new RestconfDocumentedException(
-                    "Parameter " + parameterName + " can appear at most once in request URI",
-                    ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
-        }
-    }
-
-    /**
-     * 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 @NonNull Set<String> usedParameters,
-                                     final @NonNull 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) {
+            final YangInstanceIdentifier path, final WithDefaultsParam withDefa, final EffectiveModelContext ctx) {
         boolean trim;
         switch (withDefa) {
             case TRIM:
@@ -306,7 +154,7 @@ public final class ReadDataTransactionUtil {
                 trim = false;
                 break;
             default:
-                throw new RestconfDocumentedException("Unsupported with-defaults value " + withDefa.uriValue());
+                throw new RestconfDocumentedException("Unsupported with-defaults value " + withDefa.paramValue());
         }
 
         final DataSchemaContextTree baseSchemaCtxTree = DataSchemaContextTree.from(ctx);
@@ -351,18 +199,14 @@ public final class ReadDataTransactionUtil {
                 if (keys.contains(child.getIdentifier().getNodeType())) {
                     leafBuilder.withValue(((LeafNode<?>) child).body());
                     builder.withChild(leafBuilder.build());
-                } else {
-                    if (trim) {
-                        if (defaultVal == null || !defaultVal.equals(nodeVal)) {
-                            leafBuilder.withValue(((LeafNode<?>) child).body());
-                            builder.withChild(leafBuilder.build());
-                        }
-                    } else {
-                        if (defaultVal != null && defaultVal.equals(nodeVal)) {
-                            leafBuilder.withValue(((LeafNode<?>) child).body());
-                            builder.withChild(leafBuilder.build());
-                        }
+                } else if (trim) {
+                    if (defaultVal == null || !defaultVal.equals(nodeVal)) {
+                        leafBuilder.withValue(((LeafNode<?>) child).body());
+                        builder.withChild(leafBuilder.build());
                     }
+                } else if (defaultVal != null && defaultVal.equals(nodeVal)) {
+                    leafBuilder.withValue(((LeafNode<?>) child).body());
+                    builder.withChild(leafBuilder.build());
                 }
             }
         }
@@ -409,11 +253,9 @@ public final class ReadDataTransactionUtil {
                         leafBuilder.withValue(((LeafNode<?>) child).body());
                         builder.withChild(leafBuilder.build());
                     }
-                } else {
-                    if (defaultVal != null && defaultVal.equals(nodeVal)) {
-                        leafBuilder.withValue(((LeafNode<?>) child).body());
-                        builder.withChild(leafBuilder.build());
-                    }
+                } else if (defaultVal != null && defaultVal.equals(nodeVal)) {
+                    leafBuilder.withValue(((LeafNode<?>) child).body());
+                    builder.withChild(leafBuilder.build());
                 }
             }
         }
@@ -454,7 +296,7 @@ public final class ReadDataTransactionUtil {
     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();
     }
 
@@ -468,7 +310,7 @@ public final class ReadDataTransactionUtil {
      * @return {@link NormalizedNode}
      */
     private static @Nullable NormalizedNode readAllData(final @NonNull RestconfStrategy strategy,
-            final YangInstanceIdentifier path, final WithDefaultsParameter withDefa, final EffectiveModelContext ctx) {
+            final YangInstanceIdentifier path, final WithDefaultsParam withDefa, final EffectiveModelContext ctx) {
         // PREPARE STATE DATA NODE
         final NormalizedNode stateDataNode = readDataViaTransaction(strategy, LogicalDatastoreType.OPERATIONAL, path);
         // PREPARE CONFIG DATA NODE
@@ -491,7 +333,7 @@ public final class ReadDataTransactionUtil {
      * @return {@link NormalizedNode}
      */
     private static @Nullable NormalizedNode readAllData(final @NonNull RestconfStrategy strategy,
-            final @NonNull YangInstanceIdentifier path, final @Nullable WithDefaultsParameter withDefa,
+            final @NonNull YangInstanceIdentifier path, final @Nullable WithDefaultsParam withDefa,
             final @NonNull EffectiveModelContext ctx, final @NonNull List<YangInstanceIdentifier> fields) {
         // PREPARE STATE DATA NODE
         final NormalizedNode stateDataNode = readDataViaTransaction(strategy, LogicalDatastoreType.OPERATIONAL, path,