All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opengis.cite.ogcapiprocesses10.util.JsonUtils Maven / Gradle / Ivy

There is a newer version: 1.2
Show newest version
package org.opengis.cite.ogcapiprocesses10.util;

import static io.restassured.RestAssured.given;
import static io.restassured.http.Method.GET;
import static org.opengis.cite.ogcapiprocesses10.OgcApiProcesses10.GEOJSON_MIME_TYPE;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDate;
import java.time.Period;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.IOUtils;

import com.fasterxml.jackson.databind.ObjectMapper;

import io.restassured.path.json.JsonPath;
import io.restassured.response.Response;
import io.restassured.specification.RequestSpecification;

/**
 * 

* JsonUtils class. *

* * @author Lyn Goltz */ public class JsonUtils { private static ObjectMapper objectMapper; private JsonUtils() { } /** * Parses the id of the first feature from the passed json. * @param collectionItemJson the json document containing the features, never * null * @return the parsed id, may be null if no feature could be found */ public static String parseFeatureId(JsonPath collectionItemJson) { List> features = collectionItemJson.get("features"); if (features == null) return null; for (Map feature : features) { if (feature.containsKey("id")) return feature.get("id").toString(); } return null; } /** * Parses the temporal extent from the passed collection. * @param collection the collection containing the extent to parse, never * null * @return the parsed temporal extent, null if no extent exists * @throws java.lang.IllegalArgumentException if the number of items in the extent * invalid */ public static TemporalExtent parseTemporalExtent(Map collection) { Object extent = collection.get("extent"); if (extent == null || !(extent instanceof Map)) return null; Object spatial = ((Map) extent).get("temporal"); if (spatial == null || !(spatial instanceof List)) return null; List coords = (List) spatial; if (coords.size() == 2) { ZonedDateTime begin = parseAsDate((String) coords.get(0)); ZonedDateTime end = parseAsDate((String) coords.get(1)); return new TemporalExtent(begin, end); } throw new IllegalArgumentException("Temporal extent with " + coords.size() + " items is invalid"); } /** * Parses the passed string as ISO 8601 date. * @param dateTime the dateTime to parse, never null * @return the parsed date, never null */ public static ZonedDateTime parseAsDate(String dateTime) { return ZonedDateTime.parse(dateTime); } /** * Formats the passed string as ISO 8601 date. Example: "2018-02-12T23:20:50Z" * @param dateTime the dateTime to format, never null * @return the formatted date, never null */ public static String formatDate(ZonedDateTime dateTime) { return DateTimeFormatter.ISO_INSTANT.format(dateTime); } /** * Formats the passed string as ISO 8601 date. Example: "2018-02-12" * @param date the dateTime to format, never null * @return the formatted date, never null */ public static String formatDate(LocalDate date) { return DateTimeFormatter.ISO_DATE.format(date); } /** * Formats the passed string as a period using a start and end time. Example: * "2018-02-12T00:00:00Z/2018-03-18T12:31:12Z" * @param beginDateTime the begin dateTime to format, never null * @param endDateTime the end dateTime to format, never null * @return the formatted date, never null */ public static String formatDateRange(ZonedDateTime beginDateTime, ZonedDateTime endDateTime) { return formatDate(beginDateTime) + "/" + formatDate(endDateTime); } /** * Formats the passed string as a period using start time and a duration. Example: * "2018-02-12T00:00:00Z/P1M6DT12H31M12S" * @param beginDate the begin date to format, never null * @param endDate the end date to format, never null * @return the formatted date, never null */ public static String formatDateRangeWithDuration(LocalDate beginDate, LocalDate endDate) { Period betweenDate = Period.between(beginDate, endDate); return formatDate(beginDate) + "/" + betweenDate; } /** * Parses the spatial extent from the passed collection. * @param collection the collection containing the extent to parse, never * null * @return the parsed bbox, null if no extent exists * @throws java.lang.IllegalArgumentException if the number of items in the extent * invalid */ public static BBox parseSpatialExtent(Map collection) { Object extent = collection.get("extent"); if (extent == null || !(extent instanceof Map)) return null; Object spatial = ((Map) extent).get("spatial"); if (spatial == null || !(spatial instanceof List)) return null; List coords = (List) spatial; if (coords.size() == 4) { double minX = parseValueAsDouble(coords.get(0)); double minY = parseValueAsDouble(coords.get(1)); double maxX = parseValueAsDouble(coords.get(2)); double maxY = parseValueAsDouble(coords.get(3)); return new BBox(minX, minY, maxX, maxY); } else if (coords.size() == 6) { throw new IllegalArgumentException( "BBox with " + coords.size() + " coordinates is currently not supported"); } throw new IllegalArgumentException("BBox with " + coords.size() + " coordinates is invalid"); } /** * Parses all links with 'type' of one of the passed mediaTypes and the 'rel' property * with the passed value. * @param links list of all links, never null * @param mediaTypesToSupport a list of media types the links searched for should * support, may be empty but never null * @param expectedRel the expected value of the property 'rel', never * null * @return a list of links supporting one of the media types and with the expected * 'rel' property, may be empty but never null */ public static List> findLinksWithSupportedMediaTypeByRel(List> links, List mediaTypesToSupport, String expectedRel) { List> alternateLinks = new ArrayList<>(); for (Map link : links) { Object type = link.get("type"); Object rel = link.get("rel"); if (expectedRel.equals(rel) && isSupportedMediaType(type, mediaTypesToSupport)) alternateLinks.add(link); } return alternateLinks; } /** * Parsing the media types which does not have a link woth property 'type' for. * @param links list of links to search in, never null * @param mediaTypesToSuppport a list of media types which should be supported, never * null * @return the media types which does not have a link for. */ public static List findUnsupportedTypes(List> links, List mediaTypesToSuppport) { List unsupportedType = new ArrayList<>(); for (String contentMediaType : mediaTypesToSuppport) { boolean hasLinkForContentType = hasLinkForContentType(links, contentMediaType); if (!hasLinkForContentType) unsupportedType.add(contentMediaType); } return unsupportedType; } /** * Parses the links without 'rel' or 'type' property. * @param links list of links to search in, never null * @param rels rels null * @return the links without 'rel' or 'type' property */ public static List findLinksWithoutRelOrType(List> links, Set rels) { List linksWithoutRelOrType = new ArrayList<>(); for (Map link : links) { if (rels.contains(link.get("rel")) && !linkIncludesRelAndType(link)) linksWithoutRelOrType.add((String) link.get("href")); } return linksWithoutRelOrType; } /** * Parses the link with 'rel=self'. * @param links list of links to search in, never null * @param expectedRel the expected value of the property 'rel', never * null * @return the link to itself or null if no such link exists */ public static Map findLinkByRel(List> links, String expectedRel) { if (links == null) return null; for (Map link : links) { Object rel = link.get("rel"); if (expectedRel.equals(rel)) return link; } return null; } /** * Checks if the passed link contains 'rel' and 'type' properties. * @param link to check, never null * @return true if the link contains 'rel' and 'type' properties, * false otherwise */ public static boolean linkIncludesRelAndType(Map link) { Object rel = link.get("rel"); Object type = link.get("type"); if (rel != null && type != null) return true; return false; } /** * Checks if a property with the passed name exists in the jsonPath. * @param propertyName name of the property to check, never null * @param jsonPath to check, never null * @return true if the property exists, false otherwise */ public static boolean hasProperty(String propertyName, JsonPath jsonPath) { return jsonPath.get(propertyName) != null; } /** * Collects the number of all returned features by iterating over all 'next' links and * summarizing the size of features in 'features' array property. * @param jsonPath the initial collection, never null * @param maximumLimit the limit parameter value to use, if <= 0 the parameter is * omitted * @return the number of all returned features * @throws java.net.URISyntaxException if the creation of a uri fails */ public static int collectNumberOfAllReturnedFeatures(JsonPath jsonPath, int maximumLimit) throws URISyntaxException { int numberOfAllReturnedFeatures = jsonPath.getList("features").size(); Map nextLink = findLinkByRel(jsonPath.getList("links"), "next"); while (nextLink != null) { String nextUrl = (String) nextLink.get("href"); URI uri = new URI(nextUrl); RequestSpecification accept = given().log().all().baseUri(nextUrl).accept(GEOJSON_MIME_TYPE); String[] pairs = uri.getQuery().split("&"); String limitParamFromUri = null; for (String pair : pairs) { int idx = pair.indexOf("="); String key = pair.substring(0, idx); String value = pair.substring(idx + 1); if ("limit".equals(key)) { limitParamFromUri = value; } else { accept.param(key, value); } } if (maximumLimit > 0) { accept.param("limit", maximumLimit); } else if (limitParamFromUri != null) { accept.param("limit", limitParamFromUri); } Response response = accept.when().request(GET); response.then().statusCode(200); JsonPath nextJsonPath = response.jsonPath(); int features = nextJsonPath.getList("features").size(); if (features > 0) { numberOfAllReturnedFeatures += features; nextLink = findLinkByRel(nextJsonPath.getList("links"), "next"); } else { nextLink = null; } } return numberOfAllReturnedFeatures; } /** * Converts an inputstream to String using UTF-8 encoding. * @param inputStream the inputstream * @return the content of the inputstream as String * @throws java.io.IOException if an I/O error occurs */ public static String inputStreamToString(InputStream inputStream) throws IOException { StringWriter writer = new StringWriter(); String encoding = StandardCharsets.UTF_8.name(); IOUtils.copy(inputStream, writer, encoding); return prettifyString(writer.toString()); } /** *

* prettifyString. *

* @param string a {@link java.lang.String} object * @return a {@link java.lang.String} object */ public static String prettifyString(String string) { ObjectMapper objectMapper = getObjectMapper(); try { Object jsonObject = objectMapper.readValue(string, Object.class); String prettyJson = objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject); return prettyJson; } catch (Exception e) { // String was not JSON return string; } } private static ObjectMapper getObjectMapper() { if (objectMapper == null) { objectMapper = new ObjectMapper(); } return objectMapper; } private static boolean isSameMediaType(String mediaType1, String mediaType2) { if (mediaType1.contains(";") || mediaType2.contains(";")) { // media types are not case sensitive String[] components1 = mediaType1.toLowerCase().split(";"); String[] components2 = mediaType2.toLowerCase().split(";"); // type and subtype must match if (!components1[0].trim().equals(components2[0].trim())) return false; Set parameters1 = new HashSet<>(); Set parameters2 = new HashSet<>(); // normalize parameter values and compare them for (int i = 1; i < components1.length; i++) { String parameter = components1[i].trim().replace("\"", ""); if (!parameter.isEmpty()) parameters1.add(parameter); } for (int i = 1; i < components2.length; i++) { String parameter = components2[i].trim().replace("\"", ""); if (!parameter.isEmpty()) parameters2.add(parameter); } if (parameters1.size() != parameters2.size()) return false; if (!parameters1.containsAll(parameters2)) return false; } else if (!mediaType1.trim().equalsIgnoreCase(mediaType2.trim())) return false; return true; } private static boolean hasLinkForContentType(List> alternateLinks, String mediaType) { for (Map alternateLink : alternateLinks) { Object type = alternateLink.get("type"); if (type instanceof String && isSameMediaType(mediaType, (String) type)) return true; } return false; } private static boolean isSupportedMediaType(Object type, List mediaTypes) { for (String mediaType : mediaTypes) { if (type instanceof String && isSameMediaType(mediaType, (String) type)) return true; } return false; } private static double parseValueAsDouble(Object cords) { if (cords instanceof Integer) { return ((Integer) cords).doubleValue(); } else if (cords instanceof Float) { return ((Float) cords).doubleValue(); } else if (cords instanceof Double) { return (Double) cords; } else { return Double.parseDouble(cords.toString()); } } }