Promote QueryParams as WriteDataParams
[netconf.git] / restconf / restconf-nb-rfc8040 / src / main / java / org / opendaylight / restconf / nb / rfc8040 / databind / jaxrs / QueryParams.java
1 /*
2  * Copyright (c) 2021 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.restconf.nb.rfc8040.databind.jaxrs;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import java.util.List;
14 import java.util.Map.Entry;
15 import java.util.function.Function;
16 import javax.ws.rs.core.MultivaluedMap;
17 import javax.ws.rs.core.UriInfo;
18 import org.eclipse.jdt.annotation.NonNull;
19 import org.eclipse.jdt.annotation.Nullable;
20 import org.opendaylight.restconf.common.errors.RestconfDocumentedException;
21 import org.opendaylight.restconf.nb.rfc8040.FilterParameter;
22 import org.opendaylight.restconf.nb.rfc8040.InsertParameter;
23 import org.opendaylight.restconf.nb.rfc8040.NotificationQueryParams;
24 import org.opendaylight.restconf.nb.rfc8040.PointParameter;
25 import org.opendaylight.restconf.nb.rfc8040.StartTimeParameter;
26 import org.opendaylight.restconf.nb.rfc8040.StopTimeParameter;
27 import org.opendaylight.restconf.nb.rfc8040.WriteDataParams;
28 import org.opendaylight.yangtools.yang.common.ErrorTag;
29 import org.opendaylight.yangtools.yang.common.ErrorType;
30
31 @Beta
32 public final class QueryParams {
33     private QueryParams() {
34         // Utility class
35     }
36
37     public static @NonNull NotificationQueryParams newNotificationQueryParams(final UriInfo uriInfo) {
38         StartTimeParameter startTime = null;
39         StopTimeParameter stopTime = null;
40         FilterParameter filter = null;
41         boolean skipNotificationData = false;
42
43         for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
44             final String paramName = entry.getKey();
45             final List<String> paramValues = entry.getValue();
46
47             try {
48                 if (paramName.equals(StartTimeParameter.uriName())) {
49                     startTime = optionalParam(StartTimeParameter::forUriValue, paramName, paramValues);
50                     break;
51                 } else if (paramName.equals(StopTimeParameter.uriName())) {
52                     stopTime = optionalParam(StopTimeParameter::forUriValue, paramName, paramValues);
53                     break;
54                 } else if (paramName.equals(FilterParameter.uriName())) {
55                     filter = optionalParam(FilterParameter::forUriValue, paramName, paramValues);
56                 } else if (paramName.equals("odl-skip-notification-data")) {
57                     // FIXME: this should be properly encapsulated in SkipNotificatioDataParameter
58                     skipNotificationData = Boolean.parseBoolean(optionalParam(paramName, paramValues));
59                 } else {
60                     throw new RestconfDocumentedException("Bad parameter used with notifications: " + paramName);
61                 }
62             } catch (IllegalArgumentException e) {
63                 throw new RestconfDocumentedException("Invalid " + paramName + " value: " + e.getMessage(), e);
64             }
65         }
66
67         try {
68             return NotificationQueryParams.of(startTime, stopTime, filter, skipNotificationData);
69         } catch (IllegalArgumentException e) {
70             throw new RestconfDocumentedException("Invalid query parameters: " + e.getMessage(), e);
71         }
72     }
73
74     public static @NonNull WriteDataParams newWriteDataParams(final UriInfo uriInfo) {
75         InsertParameter insert = null;
76         PointParameter point = null;
77
78         for (final Entry<String, List<String>> entry : uriInfo.getQueryParameters().entrySet()) {
79             final String uriName = entry.getKey();
80             final List<String> paramValues = entry.getValue();
81             if (uriName.equals(InsertParameter.uriName())) {
82                 final String str = optionalParam(uriName, paramValues);
83                 if (str != null) {
84                     insert = InsertParameter.forUriValue(str);
85                     if (insert == null) {
86                         throw new RestconfDocumentedException("Unrecognized insert parameter value '" + str + "'",
87                             ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT);
88                     }
89                 }
90             } else if (PointParameter.uriName().equals(uriName)) {
91                 final String str = optionalParam(uriName, paramValues);
92                 if (str != null) {
93                     point = PointParameter.forUriValue(str);
94                 }
95             } else {
96                 throw new RestconfDocumentedException("Bad parameter for post: " + uriName,
97                     ErrorType.PROTOCOL, ErrorTag.BAD_ELEMENT);
98             }
99         }
100
101         try {
102             return WriteDataParams.of(insert, point);
103         } catch (IllegalArgumentException e) {
104             throw new RestconfDocumentedException("Invalid query parameters: " + e.getMessage(), e);
105         }
106     }
107
108     public static @Nullable String getSingleParameter(final MultivaluedMap<String, String> params, final String name) {
109         final var values = params.get(name);
110         return values == null ? null : optionalParam(name, values);
111     }
112
113     private static @Nullable String optionalParam(final String name, final List<String> values) {
114         switch (values.size()) {
115             case 0:
116                 return null;
117             case 1:
118                 return requireNonNull(values.get(0));
119             default:
120                 throw new RestconfDocumentedException("Parameter " + name + " can appear at most once in request URI",
121                     ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
122         }
123     }
124
125     private static <T> @Nullable T optionalParam(final Function<String, @NonNull T> factory, final String name,
126             final List<String> values) {
127         final String str = optionalParam(name, values);
128         return str == null ? null : factory.apply(str);
129     }
130 }