
net.pincette.jes.api.Request Maven / Gradle / Ivy
package net.pincette.jes.api;
import static java.lang.String.join;
import static java.net.URLDecoder.decode;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.joining;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static net.pincette.jes.api.Util.headersToString;
import static net.pincette.util.Json.string;
import static net.pincette.util.Pair.pair;
import static net.pincette.util.Util.isFloat;
import static net.pincette.util.Util.tryToGetSilent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.IntSupplier;
import javax.json.JsonStructure;
import net.pincette.util.Array;
import net.pincette.util.Pair;
/**
* Represents the part of an HTTP request that is relevant to the API.
*
* @author Werner Donn\u00e9
* @since 1.0
*/
public class Request {
/**
* The request body.
*
* @since 1.0
*/
public final JsonStructure body;
/**
* The cookies. If there are no cookies the map will be empty.
*
* @since 1.0
*/
public final Map cookies;
/**
* The request headers. If there are no headers the map will be empty.
*
* @since 1.0
*/
public final Map headers;
/**
* The request headers with the header names converted to lower case. If there are no headers the
* map will be empty.
*
* @since 1.0
*/
public final Map headersLowerCaseKeys;
/**
* The user's preferred language tags, ordered by descending priority.
*
* @since 1.0
*/
public final List languages;
/**
* The HTTP method in upper case.
*
* @since 1.0
*/
public final String method;
/**
* The full path of the request.
*
* @since 1.0
*/
public final String path;
/**
* The query string of the URL.
*
* @since 1.0
*/
public final Map queryString;
public Request() {
this(null, null, null, null, null);
}
private Request(
final Map headers,
final String path,
final String method,
final JsonStructure body,
final Map queryString) {
this.headers = headers != null ? headers : new HashMap<>();
this.path = path;
this.method = method != null ? method.toUpperCase() : null;
this.body = body;
this.queryString = queryString;
headersLowerCaseKeys = toLowerCase(this.headers);
languages = getLanguages(headersLowerCaseKeys);
cookies = getCookies(headersLowerCaseKeys);
}
private static int compareWeighted(final Pair w1, final Pair w2) {
final IntSupplier equalOr = () -> w1.second.floatValue() == w2.second.floatValue() ? 0 : 1;
return w1.second >= w2.second ? -1 : equalOr.getAsInt();
}
private static Map getCookies(final Map headers) {
return Optional.ofNullable(headers.get("cookie"))
.map(
values ->
stream(values)
.flatMap(value -> stream(value.split(";")))
.map(cookie -> cookie.trim().split("="))
.filter(split -> split.length == 2)
.collect(toMap(s -> s[0], s -> s[1])))
.orElseGet(HashMap::new);
}
private static List getLanguages(final Map headers) {
return Optional.ofNullable(headers.get("accept-language"))
.map(Request::sortByQualityValue)
.orElseGet(ArrayList::new);
}
private static Map getQueryString(final String queryString) {
return stream(queryString.split("&"))
.map(parameter -> parameter.split("="))
.filter(split -> split.length == 1 || split.length == 2)
.map(split -> split.length == 1 ? new String[] {split[0], "true"} : split)
.collect(
toMap(
s -> s[0],
s -> new String[] {tryToGetSilent(() -> decode(s[1], "UTF-8")).orElse(s[1])},
Array::append));
}
private static float getWeight(final String s) {
return Optional.of(s.split("="))
.filter(split -> split.length == 2 && split[0].equalsIgnoreCase("q") && isFloat(split[1]))
.map(split -> split[1])
.map(Float::parseFloat)
.filter(f -> f >= 0 || f <= 1)
.orElse(0F);
}
private static List sortByQualityValue(final String[] values) {
return stream(values)
.flatMap(v -> stream(v.split(" ,")))
.map(v -> v.split(" ;"))
.filter(split -> split.length == 1 || split.length == 2)
.map(split -> pair(split[0], split.length == 1 ? 1 : getWeight(split[1])))
.sorted(Request::compareWeighted)
.map(pair -> pair.first)
.collect(toList());
}
private static Map toLowerCase(final Map map) {
return map.entrySet().stream()
.collect(toMap(e -> e.getKey().toLowerCase(), Map.Entry::getValue));
}
private String queryStringToString() {
return queryString.entrySet().stream()
.flatMap(entry -> stream(entry.getValue()).map(v -> entry.getKey() + "=" + v))
.collect(joining("&"));
}
public String toString() {
return method
+ " "
+ path
+ (queryString != null ? ("?" + queryStringToString()) : "")
+ "\n"
+ headersToString(headers)
+ "\n"
+ (body != null ? string(body) : "");
}
public Request withBody(final JsonStructure body) {
return new Request(headers, path, method, body, queryString);
}
public Request withHeaders(final Map headers) {
return new Request(headers, path, method, body, queryString);
}
public Request withMethod(final String method) {
return new Request(headers, path, method, body, queryString);
}
public Request withPath(final String path) {
return new Request(headers, path, method, body, queryString);
}
public Request withQueryString(final String queryString) {
return new Request(
headers, path, method, body, queryString != null ? getQueryString(queryString) : null);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy