Bind Insert point PathArgument earlier
[netconf.git] / restconf / restconf-nb / src / main / java / org / opendaylight / restconf / nb / rfc8040 / databind / jaxrs / QueryParams.java
index 94789a91db0f9d84b7b7e5ad25e0674eb12f3085..00d2c6b77821f07844ffe9bcd3f8344280133be3 100644 (file)
@@ -18,30 +18,33 @@ import java.util.function.Function;
 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.api.query.ChangedLeafNodesOnlyParam;
+import org.opendaylight.restconf.api.query.ChildNodesOnlyParam;
+import org.opendaylight.restconf.api.query.ContentParam;
+import org.opendaylight.restconf.api.query.DepthParam;
+import org.opendaylight.restconf.api.query.FieldsParam;
+import org.opendaylight.restconf.api.query.FilterParam;
+import org.opendaylight.restconf.api.query.InsertParam;
+import org.opendaylight.restconf.api.query.LeafNodesOnlyParam;
+import org.opendaylight.restconf.api.query.PointParam;
+import org.opendaylight.restconf.api.query.PrettyPrintParam;
+import org.opendaylight.restconf.api.query.SkipNotificationDataParam;
+import org.opendaylight.restconf.api.query.StartTimeParam;
+import org.opendaylight.restconf.api.query.StopTimeParam;
+import org.opendaylight.restconf.api.query.WithDefaultsParam;
 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
 import org.opendaylight.restconf.common.errors.RestconfError;
-import org.opendaylight.restconf.nb.rfc8040.ChangedLeafNodesOnlyParam;
-import org.opendaylight.restconf.nb.rfc8040.ContentParam;
-import org.opendaylight.restconf.nb.rfc8040.DepthParam;
-import org.opendaylight.restconf.nb.rfc8040.FieldsParam;
-import org.opendaylight.restconf.nb.rfc8040.FilterParam;
-import org.opendaylight.restconf.nb.rfc8040.InsertParam;
-import org.opendaylight.restconf.nb.rfc8040.LeafNodesOnlyParam;
+import org.opendaylight.restconf.nb.rfc8040.Insert;
 import org.opendaylight.restconf.nb.rfc8040.NotificationQueryParams;
-import org.opendaylight.restconf.nb.rfc8040.PointParam;
-import org.opendaylight.restconf.nb.rfc8040.PrettyPrintParam;
 import org.opendaylight.restconf.nb.rfc8040.ReadDataParams;
-import org.opendaylight.restconf.nb.rfc8040.SkipNotificationDataParam;
-import org.opendaylight.restconf.nb.rfc8040.StartTimeParam;
-import org.opendaylight.restconf.nb.rfc8040.StopTimeParam;
-import org.opendaylight.restconf.nb.rfc8040.WithDefaultsParam;
-import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
+import org.opendaylight.restconf.nb.rfc8040.legacy.InstanceIdentifierContext;
 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;
+import org.opendaylight.restconf.nb.rfc8040.utils.parser.YangInstanceIdentifierDeserializer;
 import org.opendaylight.yangtools.yang.common.ErrorTag;
 import org.opendaylight.yangtools.yang.common.ErrorType;
+import org.opendaylight.yangtools.yang.model.api.EffectiveModelContext;
 
 @Beta
 public final class QueryParams {
@@ -53,7 +56,9 @@ public final class QueryParams {
         InsertParam.uriName, PointParam.uriName,
         // Notifications
         FilterParam.uriName, StartTimeParam.uriName, StopTimeParam.uriName,
-        LeafNodesOnlyParam.uriName, SkipNotificationDataParam.uriName, ChangedLeafNodesOnlyParam.uriName);
+        // ODL extensions
+        LeafNodesOnlyParam.uriName, SkipNotificationDataParam.uriName, ChangedLeafNodesOnlyParam.uriName,
+        ChildNodesOnlyParam.uriName);
 
     private QueryParams() {
         // Utility class
@@ -66,6 +71,7 @@ public final class QueryParams {
         LeafNodesOnlyParam leafNodesOnly = null;
         SkipNotificationDataParam skipNotificationData = null;
         ChangedLeafNodesOnlyParam changedLeafNodesOnly = null;
+        ChildNodesOnlyParam childNodesOnly = null;
 
         for (Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
             final String paramName = entry.getKey();
@@ -93,6 +99,9 @@ public final class QueryParams {
                         changedLeafNodesOnly = optionalParam(ChangedLeafNodesOnlyParam::forUriValue, paramName,
                             paramValues);
                         break;
+                    case ChildNodesOnlyParam.uriName:
+                        childNodesOnly = optionalParam(ChildNodesOnlyParam::forUriValue, paramName, paramValues);
+                        break;
                     default:
                         throw unhandledParam("notification", paramName);
                 }
@@ -104,7 +113,7 @@ public final class QueryParams {
 
         try {
             return NotificationQueryParams.of(startTime, stopTime, filter, leafNodesOnly, skipNotificationData,
-                    changedLeafNodesOnly);
+                changedLeafNodesOnly, childNodesOnly);
         } catch (IllegalArgumentException e) {
             throw new RestconfDocumentedException("Invalid query parameters: " + e.getMessage(), e);
         }
@@ -134,7 +143,6 @@ public final class QueryParams {
         FieldsParam fields = null;
         WithDefaultsParam withDefaults = null;
         PrettyPrintParam prettyPrint = null;
-        boolean tagged = false;
 
         for (Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
             final String paramName = entry.getKey();
@@ -159,22 +167,7 @@ public final class QueryParams {
                         fields = optionalParam(FieldsParam::forUriValue, paramName, paramValues);
                         break;
                     case WithDefaultsParam.uriName:
-                        final var defaultsVal = optionalParam(WithDefaultsParam::forUriValue, paramName, paramValues);
-                        if (defaultsVal != null) {
-                            switch (defaultsVal) {
-                                case REPORT_ALL:
-                                    withDefaults = null;
-                                    tagged = false;
-                                    break;
-                                case REPORT_ALL_TAGGED:
-                                    withDefaults = null;
-                                    tagged = true;
-                                    break;
-                                default:
-                                    withDefaults = defaultsVal;
-                                    tagged = false;
-                            }
-                        }
+                        withDefaults = optionalParam(WithDefaultsParam::forUriValue, paramName, paramValues);
                         break;
                     case PrettyPrintParam.uriName:
                         prettyPrint = optionalParam(PrettyPrintParam::forUriValue, paramName, paramValues);
@@ -188,16 +181,16 @@ public final class QueryParams {
             }
         }
 
-        return ReadDataParams.of(content, depth, fields, withDefaults, tagged, prettyPrint);
+        return new ReadDataParams(content, depth, fields, withDefaults, prettyPrint);
     }
 
-    public static @NonNull WriteDataParams newWriteDataParams(final UriInfo uriInfo) {
+    public static @Nullable Insert parseInsert(final EffectiveModelContext modelContext, 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) {
@@ -217,7 +210,12 @@ public final class QueryParams {
         }
 
         try {
-            return WriteDataParams.of(insert, point);
+            return Insert.forParams(insert, point,
+                // TODO: instead of a EffectiveModelContext, we should have received
+                //       YangInstanceIdentifierDeserializer.Result, from which we can use to seed the parser. This
+                //       call-site should not support 'yang-ext:mount' and should just reuse DataSchemaContextTree,
+                //       saving a lookup
+                value -> YangInstanceIdentifierDeserializer.create(modelContext, value).path.getLastPathArgument());
         } catch (IllegalArgumentException e) {
             throw new RestconfDocumentedException("Invalid query parameters: " + e.getMessage(), e);
         }
@@ -233,15 +231,13 @@ public final class QueryParams {
 
     @VisibleForTesting
     static @Nullable String optionalParam(final String name, final List<String> values) {
-        switch (values.size()) {
-            case 0:
-                return null;
-            case 1:
-                return requireNonNull(values.get(0));
-            default:
-                throw new RestconfDocumentedException("Parameter " + name + " can appear at most once in request URI",
-                    ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
-        }
+        return switch (values.size()) {
+            case 0 -> null;
+            case 1 -> requireNonNull(values.get(0));
+            default -> throw new RestconfDocumentedException(
+                "Parameter " + name + " can appear at most once in request URI",
+                ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
+        };
     }
 
     private static <T> @Nullable T optionalParam(final Function<String, @NonNull T> factory, final String name,