diff --git a/bundles/org.openhab.persistence.rrd4j/pom.xml b/bundles/org.openhab.persistence.rrd4j/pom.xml
index 3a8824c9a..74d0b50f6 100644
--- a/bundles/org.openhab.persistence.rrd4j/pom.xml
+++ b/bundles/org.openhab.persistence.rrd4j/pom.xml
@@ -23,7 +23,7 @@
org.rrd4j
rrd4j
- 3.3.1
+ 3.8
diff --git a/bundles/org.openhab.persistence.rrd4j/src/main/java/org/openhab/persistence/rrd4j/internal/RRD4jPersistenceService.java b/bundles/org.openhab.persistence.rrd4j/src/main/java/org/openhab/persistence/rrd4j/internal/RRD4jPersistenceService.java
index 4f9365837..9c1920fce 100644
--- a/bundles/org.openhab.persistence.rrd4j/src/main/java/org/openhab/persistence/rrd4j/internal/RRD4jPersistenceService.java
+++ b/bundles/org.openhab.persistence.rrd4j/src/main/java/org/openhab/persistence/rrd4j/internal/RRD4jPersistenceService.java
@@ -296,7 +296,7 @@ public class RRD4jPersistenceService implements QueryablePersistenceService {
for (double value : result.getValues(DATASOURCE_STATE)) {
if (!Double.isNaN(value) && (((ts >= start) && (ts <= end)) || (start == end))) {
RRD4jItem rrd4jItem = new RRD4jItem(itemName, mapToState(value, item, unit),
- ZonedDateTime.ofInstant(Instant.ofEpochMilli(ts * 1000), ZoneId.systemDefault()));
+ ZonedDateTime.ofInstant(Instant.ofEpochSecond(ts), ZoneId.systemDefault()));
items.add(rrd4jItem);
}
ts += step;
@@ -319,7 +319,7 @@ public class RRD4jPersistenceService implements QueryablePersistenceService {
try {
if (file.exists()) {
// recreate the RrdDb instance from the file
- db = new RrdDb(file.getAbsolutePath());
+ db = RrdDb.of(file.getAbsolutePath());
} else {
File folder = new File(DB_FOLDER);
if (!folder.exists()) {
@@ -328,7 +328,7 @@ public class RRD4jPersistenceService implements QueryablePersistenceService {
RrdDef rrdDef = getRrdDef(alias, file);
if (rrdDef != null) {
// create a new database file
- db = new RrdDb(rrdDef);
+ db = RrdDb.of(rrdDef);
} else {
logger.debug(
"Did not create rrd4j database for item '{}' since no rrd definition could be determined. This is likely due to an unsupported item type.",
@@ -349,7 +349,7 @@ public class RRD4jPersistenceService implements QueryablePersistenceService {
for (Map.Entry e : rrdDefs.entrySet()) {
// try to find special config
RrdDefConfig rdc = e.getValue();
- if (rdc != null && rdc.appliesTo(itemName)) {
+ if (rdc.appliesTo(itemName)) {
useRdc = rdc;
break;
}
@@ -543,13 +543,11 @@ public class RRD4jPersistenceService implements QueryablePersistenceService {
}
for (RrdDefConfig rrdDef : rrdDefs.values()) {
- if (rrdDef != null) {
- if (rrdDef.isValid()) {
- logger.debug("Created {}", rrdDef);
- } else {
- logger.info("Removing invalid definition {}", rrdDef);
- rrdDefs.remove(rrdDef.name);
- }
+ if (rrdDef.isValid()) {
+ logger.debug("Created {}", rrdDef);
+ } else {
+ logger.info("Removing invalid definition {}", rrdDef);
+ rrdDefs.remove(rrdDef.name);
}
}
}
diff --git a/bundles/org.openhab.persistence.rrd4j/src/main/java/org/openhab/persistence/rrd4j/internal/charts/RRD4jChartServlet.java b/bundles/org.openhab.persistence.rrd4j/src/main/java/org/openhab/persistence/rrd4j/internal/charts/RRD4jChartServlet.java
index 522a24563..c07e16f1e 100644
--- a/bundles/org.openhab.persistence.rrd4j/src/main/java/org/openhab/persistence/rrd4j/internal/charts/RRD4jChartServlet.java
+++ b/bundles/org.openhab.persistence.rrd4j/src/main/java/org/openhab/persistence/rrd4j/internal/charts/RRD4jChartServlet.java
@@ -12,16 +12,18 @@
*/
package org.openhab.persistence.rrd4j.internal.charts;
+import static java.util.Map.entry;
+
import java.awt.Color;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
-import java.util.Date;
-import java.util.HashMap;
+import java.io.UncheckedIOException;
+import java.time.Duration;
+import java.time.ZonedDateTime;
import java.util.Hashtable;
import java.util.Map;
-import java.util.Objects;
import javax.imageio.ImageIO;
import javax.servlet.Servlet;
@@ -30,6 +32,9 @@ import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
+import org.eclipse.jdt.annotation.NonNullByDefault;
+import org.eclipse.jdt.annotation.Nullable;
+import org.openhab.core.i18n.TimeZoneProvider;
import org.openhab.core.items.GroupItem;
import org.openhab.core.items.Item;
import org.openhab.core.items.ItemNotFoundException;
@@ -46,6 +51,7 @@ import org.osgi.service.http.NamespaceException;
import org.rrd4j.ConsolFun;
import org.rrd4j.core.RrdDb;
import org.rrd4j.graph.RrdGraph;
+import org.rrd4j.graph.RrdGraphConstants.FontTag;
import org.rrd4j.graph.RrdGraphDef;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,11 +72,15 @@ import org.slf4j.LoggerFactory;
* @author Jan N. Klug - a few improvements
*
*/
+@NonNullByDefault
@Component(service = ChartProvider.class)
public class RRD4jChartServlet implements Servlet, ChartProvider {
private final Logger logger = LoggerFactory.getLogger(RRD4jChartServlet.class);
+ private static final int DEFAULT_HEIGHT = 240;
+ private static final int DEFAULT_WIDTH = 480;
+
/** the URI of this servlet */
public static final String SERVLET_NAME = "/rrdchart.png";
@@ -81,29 +91,30 @@ public class RRD4jChartServlet implements Servlet, ChartProvider {
new Color(0, 255, 255, 30), new Color(255, 0, 128, 30), new Color(255, 128, 128, 30),
new Color(255, 255, 0, 30) };
- protected static final Map PERIODS = new HashMap<>();
+ private static final Duration DEFAULT_PERIOD = Duration.ofDays(1);
- static {
- PERIODS.put("h", -3600000L);
- PERIODS.put("4h", -14400000L);
- PERIODS.put("8h", -28800000L);
- PERIODS.put("12h", -43200000L);
- PERIODS.put("D", -86400000L);
- PERIODS.put("3D", -259200000L);
- PERIODS.put("W", -604800000L);
- PERIODS.put("2W", -1209600000L);
- PERIODS.put("M", -2592000000L);
- PERIODS.put("2M", -5184000000L);
- PERIODS.put("4M", -10368000000L);
- PERIODS.put("Y", -31536000000L);
+ 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))//
+ );
+
+ private final HttpService httpService;
+ private final ItemUIRegistry itemUIRegistry;
+ private final TimeZoneProvider timeZoneProvider;
+
+ @Activate
+ public RRD4jChartServlet(final @Reference HttpService httpService, final @Reference ItemUIRegistry itemUIRegistry,
+ final @Reference TimeZoneProvider timeZoneProvider) {
+ this.httpService = httpService;
+ this.itemUIRegistry = itemUIRegistry;
+ this.timeZoneProvider = timeZoneProvider;
}
- @Reference
- protected HttpService httpService;
-
- @Reference
- protected ItemUIRegistry itemUIRegistry;
-
@Activate
protected void activate() {
try {
@@ -125,35 +136,39 @@ public class RRD4jChartServlet implements Servlet, ChartProvider {
public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
logger.debug("RRD4J received incoming chart request: {}", req);
- int width = 480;
- try {
- width = Integer.parseInt(Objects.requireNonNull(req.getParameter("w")));
- } catch (Exception e) {
- }
- int height = 240;
- try {
- height = Integer.parseInt(Objects.requireNonNull(req.getParameter("h")));
- } catch (Exception e) {
- }
- Long period = PERIODS.get(req.getParameter("period"));
- if (period == null) {
- // use a day as the default period
- period = PERIODS.get("D");
- }
- // Create the start and stop time
- Date timeEnd = new Date();
- Date timeBegin = new Date(timeEnd.getTime() + period);
+ int width = parseInt(req.getParameter("w"), DEFAULT_WIDTH);
+ int height = parseInt(req.getParameter("h"), DEFAULT_HEIGHT);
+ String periodParam = req.getParameter("period");
+ Duration period = periodParam == null ? DEFAULT_PERIOD : PERIODS.getOrDefault(periodParam, DEFAULT_PERIOD);
+
+ // Create the start and stop time
+ ZonedDateTime timeEnd = ZonedDateTime.now(timeZoneProvider.getTimeZone());
+ ZonedDateTime timeBegin = timeEnd.minus(period);
- // Set the content type to that provided by the chart provider
- res.setContentType("image/" + getChartType());
try {
BufferedImage chart = createChart(null, null, timeBegin, timeEnd, height, width, req.getParameter("items"),
req.getParameter("groups"), null, null);
+ // Set the content type to that provided by the chart provider
+ res.setContentType("image/" + getChartType());
ImageIO.write(chart, getChartType().toString(), res.getOutputStream());
} catch (ItemNotFoundException e) {
- logger.debug("Item not found error while generating chart.");
+ logger.debug("Item not found error while generating chart", e);
+ throw new ServletException("Item not found error while generating chart: " + e.getMessage());
} catch (IllegalArgumentException e) {
logger.debug("Illegal argument in chart", e);
+ throw new ServletException("Illegal argument in chart: " + e.getMessage());
+ }
+ }
+
+ private int parseInt(@Nullable String s, int defaultValue) {
+ if (s == null) {
+ return defaultValue;
+ }
+ try {
+ return Integer.parseInt(s);
+ } catch (NumberFormatException e) {
+ logger.debug("'{}' is not an integer, using default: {}", s, defaultValue);
+ return defaultValue;
}
}
@@ -175,7 +190,7 @@ public class RRD4jChartServlet implements Servlet, ChartProvider {
label = label.substring(0, label.indexOf('['));
}
try {
- RrdDb db = new RrdDb(rrdName);
+ RrdDb db = RrdDb.of(rrdName);
consolFun = db.getRrdDef().getArcDefs()[0].getConsolFun();
db.close();
} catch (IOException e) {
@@ -196,16 +211,16 @@ public class RRD4jChartServlet implements Servlet, ChartProvider {
}
@Override
- public void init(ServletConfig config) throws ServletException {
+ public void init(@Nullable ServletConfig config) throws ServletException {
}
@Override
- public ServletConfig getServletConfig() {
+ public @Nullable ServletConfig getServletConfig() {
return null;
}
@Override
- public String getServletInfo() {
+ public @Nullable String getServletInfo() {
return null;
}
@@ -222,20 +237,17 @@ public class RRD4jChartServlet implements Servlet, ChartProvider {
}
@Override
- public BufferedImage createChart(String service, String theme, Date startTime, Date endTime, int height, int width,
- String items, String groups, Integer dpi, Boolean legend) throws ItemNotFoundException {
- RrdGraphDef graphDef = new RrdGraphDef();
-
- long period = (startTime.getTime() - endTime.getTime()) / 1000;
-
+ public BufferedImage createChart(@Nullable String service, @Nullable String theme, ZonedDateTime startTime,
+ ZonedDateTime endTime, int height, int width, @Nullable String items, @Nullable String groups,
+ @Nullable Integer dpi, @Nullable Boolean legend) throws ItemNotFoundException {
+ RrdGraphDef graphDef = new RrdGraphDef(startTime.toEpochSecond(), endTime.toEpochSecond());
graphDef.setWidth(width);
graphDef.setHeight(height);
graphDef.setAntiAliasing(true);
graphDef.setImageFormat("PNG");
- graphDef.setStartTime(period);
graphDef.setTextAntiAliasing(true);
- graphDef.setLargeFont(new Font("SansSerif", Font.PLAIN, 15));
- graphDef.setSmallFont(new Font("SansSerif", Font.PLAIN, 11));
+ graphDef.setFont(FontTag.TITLE, new Font("SansSerif", Font.PLAIN, 15));
+ graphDef.setFont(FontTag.DEFAULT, new Font("SansSerif", Font.PLAIN, 11));
int seriesCounter = 0;
@@ -265,19 +277,15 @@ public class RRD4jChartServlet implements Servlet, ChartProvider {
}
// Write the chart as a PNG image
- RrdGraph graph;
try {
- graph = new RrdGraph(graphDef);
+ RrdGraph graph = new RrdGraph(graphDef);
BufferedImage bi = new BufferedImage(graph.getRrdGraphInfo().getWidth(),
graph.getRrdGraphInfo().getHeight(), BufferedImage.TYPE_INT_RGB);
graph.render(bi.getGraphics());
-
return bi;
} catch (IOException e) {
- logger.error("Error generating graph.", e);
+ throw new UncheckedIOException("Error generating RrdGraph", e);
}
-
- return null;
}
@Override