2 * Copyright (c) 2024 PANTHEON.tech, s.r.o. and others. All rights reserved.
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
8 package org.opendaylight.restconf.api;
10 import static java.util.Objects.requireNonNull;
12 import com.google.common.collect.ImmutableMap;
13 import com.google.common.collect.Maps;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.List;
18 import java.util.Map.Entry;
19 import java.util.function.Function;
20 import org.eclipse.jdt.annotation.NonNullByDefault;
21 import org.eclipse.jdt.annotation.Nullable;
22 import org.opendaylight.restconf.api.query.RestconfQueryParam;
23 import org.opendaylight.yangtools.concepts.Immutable;
26 * Query parameters of a RESTCONF request URI. Individual parameters can be looked up by
27 * {@link RestconfQueryParam#paramName()} via {@link #lookup(String)}. All parameters are accessible via
28 * {@link #asCollection()}, where each {@link RestconfQueryParam#paramName()} is guaranteed to be encountered at most
32 public final class QueryParameters implements Immutable {
33 static final QueryParameters EMPTY = new QueryParameters(ImmutableMap.of());
35 private final ImmutableMap<String, String> params;
37 private QueryParameters(final ImmutableMap<String, String> params) {
38 this.params = requireNonNull(params);
41 private QueryParameters(final Collection<RestconfQueryParam<?>> params) {
42 // TODO: consider caching common request parameter combinations
44 .collect(ImmutableMap.toImmutableMap(RestconfQueryParam::paramName, RestconfQueryParam::paramValue)));
47 public static QueryParameters of() {
51 public static QueryParameters of(final String paramName, final String paramValue) {
52 return new QueryParameters(ImmutableMap.of(paramName, paramValue));
55 public static QueryParameters of(final Entry<String, String> entry) {
56 return of(entry.getKey(), entry.getValue());
59 public static QueryParameters of(final RestconfQueryParam<?> param) {
60 return of(param.paramName(), param.paramValue());
63 public static QueryParameters of(final RestconfQueryParam<?>... params) {
64 return switch (params.length) {
66 case 1 -> of(params[0]);
67 default -> new QueryParameters(Arrays.asList(params));
71 public static QueryParameters of(final Collection<RestconfQueryParam<?>> params) {
72 return params instanceof List ? of((List<RestconfQueryParam<?>>) params) : switch (params.size()) {
74 case 1 -> of(params.iterator().next());
75 default -> new QueryParameters(params);
79 public static QueryParameters of(final List<RestconfQueryParam<?>> params) {
80 return switch (params.size()) {
82 case 1 -> of(params.get(0));
83 default -> new QueryParameters(params);
87 public static QueryParameters of(final Map<String, String> params) {
88 return params.isEmpty() ? of() : new QueryParameters(ImmutableMap.copyOf(params));
92 * Normalize query parameters from an map containing zero or more values for each parameter value, such as coming
93 * from JAX-RS's {@code UriInfo}.
95 * @param multiParams Input map
96 * @return A {@link QueryParameters} instance
97 * @throws NullPointerException if {@code uriInfo} is {@code null}
98 * @throws IllegalArgumentException if there are multiple values for a parameter
100 public static QueryParameters ofMultiValue(final Map<String, List<String>> multiParams) {
101 if (multiParams.isEmpty()) {
105 final var builder = ImmutableMap.<String, String>builder();
106 for (var entry : multiParams.entrySet()) {
107 final var values = entry.getValue();
108 switch (values.size()) {
112 case 1 -> builder.put(entry.getKey(), values.get(0));
113 default -> throw new IllegalArgumentException(
114 "Parameter " + entry.getKey() + " can appear at most once in request URI");
118 final var params = builder.build();
119 return params.isEmpty() ? of() : new QueryParameters(params);
122 public boolean isEmpty() {
123 return params.isEmpty();
126 public Collection<Entry<String, String>> asCollection() {
127 return params.entrySet();
130 public @Nullable String lookup(final String paramName) {
131 return params.get(requireNonNull(paramName));
134 public <T> @Nullable T lookup(final String paramName, final Function<String, T> parseFunction) {
135 final var str = lookup(paramName);
137 return parseFunction.apply(str);
142 public QueryParameters withoutParam(final String paramName) {
143 return params.containsKey(paramName) ? of(Maps.filterKeys(params, key -> !key.equals(paramName))) : this;
147 public String toString() {
148 return QueryParameters.class.getSimpleName() + "(" + params + ")";