From f71ebfb83c5f27bfd7d2679c8c4e3534dec5b72e Mon Sep 17 00:00:00 2001 From: lolodomo Date: Fri, 24 Nov 2023 16:53:10 +0100 Subject: [PATCH] Extend support to ISO8601 format for sitemap chart period parameter (#3863) * Extend support to ISO8601 format for sitemap chart period parameter Signed-off-by: Laurent Garnier --- .../openhab/core/io/rest/RESTConstants.java | 12 +- .../core/ui/internal/chart/ChartServlet.java | 50 +++++--- .../chart/ChartServletPeriodParamTest.java | 107 ++++++++++++++++++ 3 files changed, 155 insertions(+), 14 deletions(-) create mode 100644 bundles/org.openhab.core.ui/src/test/java/org/openhab/core/ui/internal/chart/ChartServletPeriodParamTest.java diff --git a/bundles/org.openhab.core.io.rest/src/main/java/org/openhab/core/io/rest/RESTConstants.java b/bundles/org.openhab.core.io.rest/src/main/java/org/openhab/core/io/rest/RESTConstants.java index 7f3c5b5affb..73a7c68474a 100644 --- a/bundles/org.openhab.core.io.rest/src/main/java/org/openhab/core/io/rest/RESTConstants.java +++ b/bundles/org.openhab.core.io.rest/src/main/java/org/openhab/core/io/rest/RESTConstants.java @@ -27,5 +27,15 @@ public class RESTConstants { public static final String JAX_RS_NAME = "openhab"; - public static final String API_VERSION = "5"; + /** + * Version of the openHAB API + * + * Version 1: initial version + * Version 2: include invisible widgets into sitemap response (#499) + * Version 3: Addition of anyFormat icon parameter (#978) + * Version 4: OH3, refactored extensions to addons (#1560) + * Version 5: transparent charts (#2502) + * Version 6: extended chart period parameter format (#3863) + */ + public static final String API_VERSION = "6"; } diff --git a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/chart/ChartServlet.java b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/chart/ChartServlet.java index 9464e1c4195..82091f3f92f 100644 --- a/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/chart/ChartServlet.java +++ b/bundles/org.openhab.core.ui/src/main/java/org/openhab/core/ui/internal/chart/ChartServlet.java @@ -12,15 +12,15 @@ */ package org.openhab.core.ui.internal.chart; -import static java.util.Map.entry; - import java.awt.image.BufferedImage; import java.io.IOException; import java.time.Duration; import java.time.LocalDateTime; +import java.time.Period; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; +import java.time.temporal.TemporalAmount; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -69,6 +69,7 @@ * * @author Chris Jackson - Initial contribution * @author Holger Reichert - Support for themes, DPI, legend hiding + * @author Laurent Garnier - Extend support to ISO8601 format for chart period parameter */ @Component(immediate = true, service = { ChartServlet.class, Servlet.class }, configurationPid = "org.openhab.chart", // property = Constants.SERVICE_PID + "=org.openhab.chart") @@ -101,16 +102,6 @@ public class ChartServlet extends HttpServlet { private static final Duration DEFAULT_PERIOD = Duration.ofDays(1); - private static final Map PERIODS = Map.ofEntries( // - entry("h", Duration.ofHours(1)), entry("4h", Duration.ofHours(4)), // - entry("8h", Duration.ofHours(8)), entry("12h", Duration.ofHours(12)), // - entry("D", Duration.ofDays(1)), entry("2D", Duration.ofDays(2)), // - entry("3D", Duration.ofDays(3)), entry("W", Duration.ofDays(7)), // - entry("2W", Duration.ofDays(14)), entry("M", Duration.ofDays(30)), // - entry("2M", Duration.ofDays(60)), entry("4M", Duration.ofDays(120)), // - entry("Y", Duration.ofDays(365))// - ); - protected static final Map CHART_PROVIDERS = new ConcurrentHashMap<>(); @Activate @@ -233,7 +224,7 @@ protected void doGet(HttpServletRequest req, HttpServletResponse res) throws Ser } // Read out the parameter period, begin and end and save them. - Duration period = periodParam == null ? DEFAULT_PERIOD : PERIODS.getOrDefault(periodParam, DEFAULT_PERIOD); + TemporalAmount period = convertToTemporalAmount(periodParam, DEFAULT_PERIOD); ZonedDateTime timeBegin = null; ZonedDateTime timeEnd = null; @@ -359,4 +350,37 @@ public void init(@Nullable ServletConfig config) throws ServletException { @Override public void destroy() { } + + public static TemporalAmount convertToTemporalAmount(@Nullable String periodParam, TemporalAmount defaultPeriod) { + TemporalAmount period = defaultPeriod; + String convertedPeriod = convertPeriodToISO8601(periodParam); + if (convertedPeriod != null) { + boolean failed = false; + try { + period = Period.parse(convertedPeriod); + } catch (DateTimeParseException e) { + failed = true; + } + if (failed) { + try { + period = Duration.parse(convertedPeriod); + } catch (DateTimeParseException e) { + // Ignored + } + } + } + return period; + } + + private static @Nullable String convertPeriodToISO8601(@Nullable String period) { + if (period == null || period.startsWith("P") || !(period.endsWith("h") || period.endsWith("D") + || period.endsWith("W") || period.endsWith("M") || period.endsWith("Y"))) { + return period; + } + String newPeriod = period.length() == 1 ? "1" + period : period; + if (newPeriod.endsWith("h")) { + newPeriod = "T" + newPeriod.replace("h", "H"); + } + return "P" + newPeriod; + } } diff --git a/bundles/org.openhab.core.ui/src/test/java/org/openhab/core/ui/internal/chart/ChartServletPeriodParamTest.java b/bundles/org.openhab.core.ui/src/test/java/org/openhab/core/ui/internal/chart/ChartServletPeriodParamTest.java new file mode 100644 index 00000000000..31e0d642d2c --- /dev/null +++ b/bundles/org.openhab.core.ui/src/test/java/org/openhab/core/ui/internal/chart/ChartServletPeriodParamTest.java @@ -0,0 +1,107 @@ +/** + * Copyright (c) 2010-2023 Contributors to the openHAB project + * + * See the NOTICE file(s) distributed with this work for additional + * information. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0 + * + * SPDX-License-Identifier: EPL-2.0 + */ +package org.openhab.core.ui.internal.chart; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; +import java.time.temporal.TemporalAmount; + +import org.eclipse.jdt.annotation.NonNullByDefault; +import org.junit.jupiter.api.Test; + +/** + * @author Laurent Garnier - Initial contribution + */ +@NonNullByDefault +public class ChartServletPeriodParamTest { + + @Test + public void convertToTemporalAmountFromNull() { + TemporalAmount period = ChartServlet.convertToTemporalAmount(null, Duration.ZERO); + assertEquals(0, period.get(ChronoUnit.SECONDS)); + } + + @Test + public void convertToTemporalAmountFromHours() { + TemporalAmount period = ChartServlet.convertToTemporalAmount("h", Duration.ZERO); + assertEquals(1 * 60 * 60, period.get(ChronoUnit.SECONDS)); + + period = ChartServlet.convertToTemporalAmount("12h", Duration.ZERO); + assertEquals(12 * 60 * 60, period.get(ChronoUnit.SECONDS)); + } + + @Test + public void convertToTemporalAmountFromDays() { + TemporalAmount period = ChartServlet.convertToTemporalAmount("D", Duration.ZERO); + assertEquals(1, period.get(ChronoUnit.DAYS)); + assertEquals(0, period.get(ChronoUnit.MONTHS)); + assertEquals(0, period.get(ChronoUnit.YEARS)); + + period = ChartServlet.convertToTemporalAmount("4D", Duration.ZERO); + assertEquals(4, period.get(ChronoUnit.DAYS)); + assertEquals(0, period.get(ChronoUnit.MONTHS)); + assertEquals(0, period.get(ChronoUnit.YEARS)); + } + + @Test + public void convertToTemporalAmountFromWeeks() { + TemporalAmount period = ChartServlet.convertToTemporalAmount("W", Duration.ZERO); + assertEquals(7, period.get(ChronoUnit.DAYS)); + assertEquals(0, period.get(ChronoUnit.MONTHS)); + assertEquals(0, period.get(ChronoUnit.YEARS)); + + period = ChartServlet.convertToTemporalAmount("2W", Duration.ZERO); + assertEquals(14, period.get(ChronoUnit.DAYS)); + assertEquals(0, period.get(ChronoUnit.MONTHS)); + assertEquals(0, period.get(ChronoUnit.YEARS)); + } + + @Test + public void convertToTemporalAmountFromMonths() { + TemporalAmount period = ChartServlet.convertToTemporalAmount("M", Duration.ZERO); + assertEquals(0, period.get(ChronoUnit.DAYS)); + assertEquals(1, period.get(ChronoUnit.MONTHS)); + assertEquals(0, period.get(ChronoUnit.YEARS)); + + period = ChartServlet.convertToTemporalAmount("3M", Duration.ZERO); + assertEquals(0, period.get(ChronoUnit.DAYS)); + assertEquals(3, period.get(ChronoUnit.MONTHS)); + assertEquals(0, period.get(ChronoUnit.YEARS)); + } + + @Test + public void convertToTemporalAmountFromYears() { + TemporalAmount period = ChartServlet.convertToTemporalAmount("Y", Duration.ZERO); + assertEquals(0, period.get(ChronoUnit.DAYS)); + assertEquals(0, period.get(ChronoUnit.MONTHS)); + assertEquals(1, period.get(ChronoUnit.YEARS)); + + period = ChartServlet.convertToTemporalAmount("2Y", Duration.ZERO); + assertEquals(0, period.get(ChronoUnit.DAYS)); + assertEquals(0, period.get(ChronoUnit.MONTHS)); + assertEquals(2, period.get(ChronoUnit.YEARS)); + } + + @Test + public void convertToTemporalAmountFromISO8601() { + TemporalAmount period = ChartServlet.convertToTemporalAmount("P2Y3M4D", Duration.ZERO); + assertEquals(4, period.get(ChronoUnit.DAYS)); + assertEquals(3, period.get(ChronoUnit.MONTHS)); + assertEquals(2, period.get(ChronoUnit.YEARS)); + + period = ChartServlet.convertToTemporalAmount("P1DT12H30M15S", Duration.ZERO); + assertEquals(36 * 60 * 60 + 30 * 60 + 15, period.get(ChronoUnit.SECONDS)); + } +}