false
+ * (i.e. the pool will not be used to fetch data from RRD files)
+ */
+ public static final boolean DEFAULT_POOL_USAGE_POLICY = false;
+
+ /**
+ * Returns boolean value representing {@link org.rrd4j.core.RrdDbPool RrdDbPool} usage policy.
+ *
+ * @return true, if the pool will be used internally to fetch data from RRD files, false otherwise.
+ */
+ boolean isPoolUsed();
+
+ /**
+ * Sets the {@link org.rrd4j.core.RrdDbPool RrdDbPool} usage policy.
+ *
+ * @param poolUsed true, if the pool will be used to fetch data from RRD files, false otherwise.
+ */
+ void setPoolUsed(boolean poolUsed);
+
+ RrdDbPool getPool();
+
+ /**
+ * Defines the {@link org.rrd4j.core.RrdDbPool RrdDbPool} to use. If not defined, but {{@link #setPoolUsed(boolean)}
+ * set to true, the default {@link RrdDbPool#getInstance()} will be used.
+ * @param pool an optional pool to use.
+ */
+ void setPool(RrdDbPool pool);
+
+ /**
+ * Set the time zone used for the legend.
+ *
+ * @param tz the time zone to set
+ */
+ void setTimeZone(TimeZone tz);
+
+ TimeZone getTimeZone();
+
+ /**
+ * Sets the time when the graph should end. Time in seconds since epoch
+ * (1970-01-01) is required. Negative numbers are relative to the current time.
+ *
+ * @param time Ending time for the graph in seconds since epoch
+ */
+ void setEndTime(long time);
+
+ /**
+ * Returns ending timestamp.
+ *
+ * @return Ending timestamp in seconds
+ */
+ long getEndTime();
+
+ /**
+ * Sets the time when the graph should start. Time in seconds since epoch
+ * (1970-01-01) is required. Negative numbers are relative to the current time.
+ *
+ * @param time Starting time for the graph in seconds since epoch
+ */
+ void setStartTime(long time);
+
+ /**
+ * Returns starting timestamp.
+ *
+ * @return Starting timestamp in seconds
+ */
+ long getStartTime();
+
+ /**
+ * Sets starting and ending time for the for the graph. Timestamps in seconds since epoch are
+ * required. Negative numbers are relative to the current time.
+ *
+ * @param startTime Starting time in seconds since epoch
+ * @param endTime Ending time in seconds since epoch
+ */
+ void setTimeSpan(long startTime, long endTime);
+
+ /**
+ * Set the step for timestamp interval.
+ */
+ void setStep(long step);
+
+ /**
+ * Returns the time step used for timestamp interval.
+ *
+ * @return Step used for data processing.
+ */
+ long getStep();
+
+ /**
+ * Defines virtual datasource. This datasource can then be used
+ * in other methods like {@link #datasource(String, String)}.
+ *
+ * @param name Source name
+ * @param rrdPath Path to RRD file
+ * @param dsName Datasource name in the specified RRD file
+ * @param consolFun Consolidation function (AVERAGE, MIN, MAX, LAST)
+ */
+ void datasource(String name, String rrdPath, String dsName,
+ ConsolFun consolFun);
+
+ /**
+ * Defines virtual datasource. This datasource can then be used
+ * in other methods like {@link #datasource(String, String)}.
+ *
+ * @param name Source name
+ * @param rrdUri rrdUri to RRD file
+ * @param dsName Datasource name in the specified RRD file
+ * @param consolFun Consolidation function (AVERAGE, MIN, MAX, LAST)
+ */
+ void datasource(String name, URI rrdUri, String dsName,
+ ConsolFun consolFun);
+
+ /**
+ * Defines virtual datasource. This datasource can then be used
+ * in other methods like {@link #datasource(String, String)}.
+ *
+ * @param name Source name
+ * @param rrdPath Path to RRD file
+ * @param dsName Datasource name in the specified RRD file
+ * @param consolFun Consolidation function (AVERAGE, MIN, MAX, LAST)
+ * @param backend Backend to be used while fetching data from a RRD file.
+ */
+ void datasource(String name, String rrdPath, String dsName,
+ ConsolFun consolFun, RrdBackendFactory backend);
+
+ /**
+ * Defines virtual datasource. This datasource can then be used
+ * in other methods like {@link #datasource(String, String)}.
+ *
+ * @param name Source name
+ * @param rrdUri URI to RRD file
+ * @param dsName Datasource name in the specified RRD file
+ * @param consolFun Consolidation function (AVERAGE, MIN, MAX, LAST)
+ * @param backend Backend to be used while fetching data from a RRD file.
+ */
+ void datasource(String name, URI rrdUri, String dsName,
+ ConsolFun consolFun, RrdBackendFactory backend);
+
+ /**
+ * Create a new virtual datasource by evaluating a mathematical
+ * expression, specified in Reverse Polish Notation (RPN).
+ *
+ * @param name Source name
+ * @param rpnExpression RPN expression.
+ */
+ void datasource(String name, String rpnExpression);
+
+ /**
+ * Creates a datasource that performs a variable calculation on an
+ * another named datasource to yield a single combined timestamp/value.
+ *
+ * Requires that the other datasource has already been defined; otherwise, it'll
+ * end up with no data
+ *
+ * @param name - the new virtual datasource name
+ * @param defName - the datasource from which to extract the percentile. Must be a previously
+ * defined virtual datasource
+ * @param var - a new instance of a Variable used to do the calculation
+ */
+ void datasource(String name, String defName, Variable var);
+
+ /**
+ * Creates a new (plottable) datasource. Datasource values are obtained from the given plottable
+ * object.
+ *
+ * @param name Source name.
+ * @param plottable IPlottable object.
+ */
+ void datasource(String name, IPlottable plottable);
+
+ /**
+ * Creates a new 'fetched' datasource. Datasource values are obtained from the
+ * given {@link org.rrd4j.core.FetchData} object.
+ *
+ * @param name Source name.
+ * @param fetchData FetchData object.
+ */
+ void datasource(String name, FetchData fetchData);
+
+ /**
+ * Creates a new 'fetched' datasource. Datasource values are obtained from the
+ * given {@link org.rrd4j.core.FetchData} object.
+ * Values will be extracted from the datasource dsName in the fetchData
+ *
+ * @param name Source name.
+ * @param dsName Source name in fetchData.
+ * @param fetchData FetchData object.
+ */
+ void datasource(String name, String dsName, FetchData fetchData);
+
+}
diff --git a/apps/jrobin/java/src/org/rrd4j/core/RrdBackendFactory.java b/apps/jrobin/java/src/org/rrd4j/core/RrdBackendFactory.java
index ab88da23e..124114e0d 100644
--- a/apps/jrobin/java/src/org/rrd4j/core/RrdBackendFactory.java
+++ b/apps/jrobin/java/src/org/rrd4j/core/RrdBackendFactory.java
@@ -17,6 +17,7 @@ import java.util.Locale;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import java.util.stream.Stream;
/**
* Base (abstract) backend factory class which holds references to all concrete
@@ -210,6 +211,15 @@ public abstract class RrdBackendFactory implements Closeable {
activeFactories.clear();
activeFactories.addAll(Arrays.asList(newFactories));
}
+
+ /**
+ * Return the current active factories as a stream.
+ * @return
+ * @since 3.7
+ */
+ public static synchronized StreamThis class should be used to synchronize access to RRD files * in a multithreaded environment. This class should be also used to prevent opening of * too many RRD files at the same time (thus avoiding operating system limits). *
- *It should not be called directly. Use {@link RrdDb.Builder#usePool()} instead.
+ *It can also be used a factory for RrdDb, using a default backend factory.
+ *In case of interruptions, it throws IllegalStateException.
*/
public class RrdDbPool {
private static class RrdDbPoolSingletonHolder {
@@ -38,8 +38,8 @@ public class RrdDbPool {
}
/**
- * Initial capacity of the pool i.e. maximum number of simultaneously open RRD files. The pool will
- * never open too many RRD files at the same time.
+ * Initial capacity of the pool i.e. maximum number of simultaneously open RRD. The pool will
+ * never open too many RRD at the same time.
*/
public static final int INITIAL_CAPACITY = 200;
@@ -80,7 +80,7 @@ public class RrdDbPool {
if (placeholder) {
return String.format("RrdEntry [placeholder, uri=%s]", uri);
} else {
- return String.format("RrdEntry [count=%d, rrdDb=%s, uri%s]", count, rrdDb, uri);
+ return String.format("RrdEntry [count=%d, rrdDb=%s, uri %s]", count, rrdDb, uri);
}
}
}
@@ -90,7 +90,6 @@ public class RrdDbPool {
* or returns already existing one. Uses Initialization On Demand Holder idiom.
*
* @return Single instance of this class
- * @throws java.lang.RuntimeException Thrown if the default RRD backend is not derived from the {@link org.rrd4j.core.RrdFileBackendFactory}
*/
public static RrdDbPool getInstance() {
return RrdDbPoolSingletonHolder.instance;
@@ -109,7 +108,7 @@ public class RrdDbPool {
private RrdBackendFactory defaultFactory;
/**
- * Constructor for RrdDbPool.
+ * Constructor for RrdDbPool. It will use the default backend factory.
* @since 3.5
*/
public RrdDbPool() {
@@ -118,7 +117,7 @@ public class RrdDbPool {
/**
* Constructor for RrdDbPool.
- * @param defaultFactory the default factory used when given simple path of a rrdDb.
+ * @param defaultFactory the default factory used when given a simple path of a RRD.
* @since 3.6
*/
public RrdDbPool(RrdBackendFactory defaultFactory) {
@@ -130,36 +129,40 @@ public class RrdDbPool {
}
/**
- * Returns the number of open RRD files.
+ * Returns the number of open RRD.
*
- * @return Number of currently open RRD files held in the pool.
+ * @return Number of currently open RRD held in the pool.
*/
public int getOpenFileCount() {
return pool.size();
}
/**
- * Returns an array of open file URI.
+ * Returns an array of open RRD URI.
*
- * @return Array with {@link URI} to open RRD files held in the pool.
+ * @return Array with {@link URI} to open RRD held in the pool.
*/
public URI[] getOpenUri() {
- //Direct toarray from keySet can fail
- Set Requests a RrdDb reference for the given RRD file path. Requests a RrdDb reference for the given RRD path. The path is transformed internally to URI using the default factory, that is the reference that will
- * be used elsewhere. The path is transformed to an URI using the default factory defined at the creation of the pool. Requests a RrdDb reference for the given RRD file path. Requests a RrdDb reference for the given RRD URI.
+ * If the default backend factory for the pool can handle this URI, it will be used,
+ * or else {@link RrdBackendFactory#findFactory(URI)} will be used to find the backend factory used.
*
* @param uri {@link URI} to existing RRD file
* @return reference for the give RRD file
* @throws java.io.IOException Thrown in case of I/O error
*/
public RrdDb requestRrdDb(URI uri) throws IOException {
- RrdBackendFactory factory = RrdBackendFactory.findFactory(uri);
- return requestRrdDb(uri, factory);
+ return requestRrdDb(uri, checkFactory(uri));
}
/**
@@ -412,7 +417,7 @@ public class RrdDbPool {
// Someone might have already open it, rechecks
if (ref.count == 0) {
try {
- ref.rrdDb = RrdDb.getBuilder().setPath(factory.getPath(uri)).setBackendFactory(factory).setPool(this).build();
+ ref.rrdDb = RrdDb.getBuilder().setPath(factory.getPath(uri)).setBackendFactory(factory).setPoolInternal(this).build();
} catch (IOException | RuntimeException e) {
passNext(ACTION.DROP, ref);
throw e;
@@ -427,17 +432,17 @@ public class RrdDbPool {
}
}
- RrdDb requestRrdDb(RrdDef rrdDef, RrdBackendFactory backend) throws IOException {
+ RrdDb requestRrdDb(RrdDef rrdDef, RrdBackendFactory factory) throws IOException {
RrdEntry ref = null;
try {
- URI uri = backend.getCanonicalUri(rrdDef.getUri());
+ URI uri = factory.getCanonicalUri(rrdDef.getUri());
ref = requestEmpty(uri);
- ref.rrdDb = RrdDb.getBuilder().setRrdDef(rrdDef).setBackendFactory(backend).setPool(this).build();
+ ref.rrdDb = RrdDb.getBuilder().setRrdDef(rrdDef).setBackendFactory(factory).setPoolInternal(this).build();
ref.count = 1;
return ref.rrdDb;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
- throw new RuntimeException("request interrupted for new rrdDef " + rrdDef.getPath(), e);
+ throw new IllegalStateException("request interrupted for new rrdDef " + rrdDef.getPath(), e);
} catch (RuntimeException e) {
passNext(ACTION.DROP, ref);
ref = null;
@@ -447,18 +452,18 @@ public class RrdDbPool {
}
}
- private RrdDb requestRrdDb(RrdDb.Builder builder, URI uri, RrdBackendFactory backend)
+ private RrdDb requestRrdDb(RrdDb.Builder builder, URI uri, RrdBackendFactory factory)
throws IOException {
RrdEntry ref = null;
- uri = backend.getCanonicalUri(uri);
+ uri = factory.getCanonicalUri(uri);
try {
ref = requestEmpty(uri);
- ref.rrdDb = builder.setPath(uri).setBackendFactory(backend).setPool(this).build();
+ ref.rrdDb = builder.setPath(uri).setBackendFactory(factory).setPoolInternal(this).build();
ref.count = 1;
return ref.rrdDb;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
- throw new RuntimeException("request interrupted for new rrd " + uri, e);
+ throw new IllegalStateException("request interrupted for new rrd " + uri, e);
} catch (RuntimeException e) {
passNext(ACTION.DROP, ref);
ref = null;
@@ -468,46 +473,51 @@ public class RrdDbPool {
}
}
- RrdDb requestRrdDb(URI uri, RrdBackendFactory backend, DataImporter importer) throws IOException {
- return requestRrdDb(RrdDb.getBuilder().setImporter(importer), uri, backend);
+ RrdDb requestRrdDb(URI uri, RrdBackendFactory factory, DataImporter importer) throws IOException {
+ return requestRrdDb(RrdDb.getBuilder().setImporter(importer), uri, factory);
}
/**
- * Requests a RrdDb reference for the given RRD file definition object. Requests a RrdDb reference for the given RRD definition object.
+ * If the factory defined when creating the pool can handle the URI, it will be used,
+ * or else {@link RrdBackendFactory#findFactory(URI)} will be used.
*
- * @param rrdDef Definition of the RRD file to be created
- * @return Reference to the newly created RRD file
+ * @param rrdDef Definition of the RRD file to be created.
+ * @return Reference to the newly created RRD file.
* @throws java.io.IOException Thrown in case of I/O error
+ * @throws java.lang.IllegalStateException if the thread was interrupted
*/
public RrdDb requestRrdDb(RrdDef rrdDef) throws IOException {
- return requestRrdDb(rrdDef, RrdBackendFactory.findFactory(rrdDef.getUri()));
+ return requestRrdDb(rrdDef, checkFactory(rrdDef.getUri()));
}
/**
- * Requests a RrdDb reference for the given path. The file will be created from
+ * Requests a RrdDb reference for the given path. The RRD will be created from
* external data (from XML dump or RRDTool's binary RRD file). The path is transformed internally to an URI using the default factory of the pool. The path is transformed to an URI using the default factory of the pool. Requests a RrdDb reference for the given path. The file will be created from
+ * Requests a RrdDb reference for the given URI. The RRD will be created from
* external data (from XML dump or RRDTool's binary RRD file). The path is transformed internally to URI using the default factory, that is the reference that will
- * be used elsewhere. The path is transformed to an URI using the default factory. Constructor for RrdMemoryBackend.
+ * Because of locking, each RrdDb can be open only once even from within the JVM. So usage
+ * of the {@link org.rrd4j.core.RrdDbPool} is mandatory with this backend.
*
*/
@RrdBackendAnnotation(name="SAFE", shouldValidateHeader=true, cachingAllowed=false)
diff --git a/apps/jrobin/java/src/org/rrd4j/core/RrdToolkit.java b/apps/jrobin/java/src/org/rrd4j/core/RrdToolkit.java
index 0d2758f93..9bc705284 100644
--- a/apps/jrobin/java/src/org/rrd4j/core/RrdToolkit.java
+++ b/apps/jrobin/java/src/org/rrd4j/core/RrdToolkit.java
@@ -31,7 +31,6 @@ import org.rrd4j.ConsolFun;
* (files which are currently in use).
*
*/
-@SuppressWarnings("deprecation")
public class RrdToolkit {
private static final String SOURCE_AND_DESTINATION_PATHS_ARE_THE_SAME = "Source and destination paths are the same";
@@ -472,11 +471,8 @@ public class RrdToolkit {
if (arcDef.getRows() != newRows) {
arcDef.setRows(newRows);
rrdDef.setPath(destPath);
- RrdDb rrdDest = new RrdDb(rrdDef);
- try {
+ try (RrdDb rrdDest = RrdDb.of(rrdDef)){
rrdSource.copyStateTo(rrdDest);
- } finally {
- rrdDest.close();
}
}
}
@@ -571,4 +567,3 @@ public class RrdToolkit {
}
}
-
diff --git a/apps/jrobin/java/src/org/rrd4j/core/XmlWriter.java b/apps/jrobin/java/src/org/rrd4j/core/XmlWriter.java
index 9b0ba28e5..82a56e234 100644
--- a/apps/jrobin/java/src/org/rrd4j/core/XmlWriter.java
+++ b/apps/jrobin/java/src/org/rrd4j/core/XmlWriter.java
@@ -202,7 +202,7 @@ public class XmlWriter implements AutoCloseable {
}
private static String escape(String s) {
- return s.replaceAll("<", "<").replaceAll(">", ">");
+ return s.replace("<", "<").replace(">", ">");
}
@Override
diff --git a/apps/jrobin/java/src/org/rrd4j/core/jrrd/DataChunk.java b/apps/jrobin/java/src/org/rrd4j/core/jrrd/DataChunk.java
index a5c1fa12d..8cfbf247a 100644
--- a/apps/jrobin/java/src/org/rrd4j/core/jrrd/DataChunk.java
+++ b/apps/jrobin/java/src/org/rrd4j/core/jrrd/DataChunk.java
@@ -2,8 +2,8 @@ package org.rrd4j.core.jrrd;
import java.util.Map;
-import org.rrd4j.data.LinearInterpolator;
import org.rrd4j.data.Plottable;
+import org.rrd4j.data.LinearInterpolator;
/**
* Models a chunk of result data from an RRDatabase.
@@ -11,6 +11,7 @@ import org.rrd4j.data.Plottable;
* @author Ciaran Treanor
* @version $Revision: 1.1 $
*/
+@SuppressWarnings("deprecation")
public class DataChunk {
private static final String NEWLINE = System.getProperty("line.separator");
diff --git a/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeParser.java b/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeParser.java
index 52a06706d..d2501caf5 100644
--- a/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeParser.java
+++ b/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeParser.java
@@ -1,11 +1,13 @@
package org.rrd4j.core.timespec;
-import org.rrd4j.core.Util;
+import java.time.Instant;
/**
* Class which parses at-style time specification (described in detail on the rrdfetch man page),
* used in all RRDTool commands. This code is in most parts just a java port of Tobi's parsetime.c
* code.
+ *
+ * For years written with two digits, any year before 38 will be post 2000.
*
*/
public class TimeParser {
@@ -102,7 +104,8 @@ public class TimeParser {
* the scanner state to what it was at entry, and returns without setting anything.
*/
private void timeOfDay() {
- int hour, minute = 0;
+ int hour = 0;
+ int minute = 0;
/* save token status in case we must abort */
scanner.saveState();
/* first pick out the time of day - we assume a HH (COLON|DOT) MM time */
@@ -165,20 +168,13 @@ public class TimeParser {
}
private void assignDate(long mday, long mon, long year) {
- if (year > 138) {
- if (year > 1970) {
- year -= 1900;
- }
- else {
- throw new IllegalArgumentException("Invalid year " + year + " (should be either 00-99 or >1900)");
- }
+ if (year >= 0 && year < 38) {
+ // 00-37 means post 2000
+ year += 2000;
}
- else if (year >= 0 && year < 38) {
- year += 100; /* Allow year 2000-2037 to be specified as */
- } /* 00-37 until the problem of 2038 year will */
- /* arise for unices with 32-bit time_t */
- if (year < 70) {
- throw new IllegalArgumentException("Won't handle dates before epoch (01/01/1970), sorry");
+ else if (year >= 38 && year <= 99) {
+ // 38-99 means 1938-1999
+ year += 1900;
}
spec.year = (int) year;
spec.month = (int) mon;
@@ -186,7 +182,10 @@ public class TimeParser {
}
private void day() {
- long mday = 0, wday, mon, year = spec.year;
+ long mday = 0;
+ long wday = 0;
+ long mon = 0;
+ long year = spec.year;
switch (token.token_id) {
case TimeToken.YESTERDAY:
spec.day--;
@@ -244,7 +243,7 @@ public class TimeParser {
token = scanner.nextToken();
break;
}
- if (mon > 19700101 && mon < 24000101) { /*works between 1900 and 2400 */
+ if (mon > 19000101 && mon < 24000101) { /*works between 1900 and 2400 */
year = mon / 10000;
mday = mon % 100;
mon = (mon / 100) % 100;
@@ -292,7 +291,7 @@ public class TimeParser {
* @return Object representing parsed date/time.
*/
public TimeSpec parse() {
- long now = Util.getTime();
+ long now = Instant.now().getEpochSecond();
int hr = 0;
/* this MUST be initialized to zero for midnight/noon/teatime */
/* establish the default time reference */
diff --git a/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeScanner.java b/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeScanner.java
index f0297b7c5..f3ae8c7d7 100644
--- a/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeScanner.java
+++ b/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeScanner.java
@@ -7,11 +7,11 @@ class TimeScanner {
private TimeToken token, token_save;
static final TimeToken[] WORDS = {
- new TimeToken("midnight", TimeToken.MIDNIGHT), /* 00:00:00 of today or tomorrow */
- new TimeToken("noon", TimeToken.NOON), /* 12:00:00 of today or tomorrow */
- new TimeToken("teatime", TimeToken.TEATIME), /* 16:00:00 of today or tomorrow */
- new TimeToken("am", TimeToken.AM), /* morning times for 0-12 clock */
- new TimeToken("pm", TimeToken.PM), /* evening times for 0-12 clock */
+ new TimeToken("midnight", TimeToken.MIDNIGHT), /* 00:00:00 of today or tomorrow */
+ new TimeToken("noon", TimeToken.NOON), /* 12:00:00 of today or tomorrow */
+ new TimeToken("teatime", TimeToken.TEATIME), /* 16:00:00 of today or tomorrow */
+ new TimeToken("am", TimeToken.AM), /* morning times for 0-12 clock */
+ new TimeToken("pm", TimeToken.PM), /* evening times for 0-12 clock */
new TimeToken("tomorrow", TimeToken.TOMORROW),
new TimeToken("yesterday", TimeToken.YESTERDAY),
new TimeToken("today", TimeToken.TODAY),
@@ -62,33 +62,33 @@ class TimeScanner {
new TimeToken(null, 0) /*** SENTINEL ***/
};
- static TimeToken[] MULTIPLIERS = {
- new TimeToken("second", TimeToken.SECONDS), /* seconds multiplier */
- new TimeToken("seconds", TimeToken.SECONDS), /* (pluralized) */
- new TimeToken("sec", TimeToken.SECONDS), /* (generic) */
+ static final TimeToken[] MULTIPLIERS = {
+ new TimeToken("second", TimeToken.SECONDS), /* seconds multiplier */
+ new TimeToken("seconds", TimeToken.SECONDS), /* (pluralized) */
+ new TimeToken("sec", TimeToken.SECONDS), /* (generic) */
new TimeToken("s", TimeToken.SECONDS), /* (short generic) */
- new TimeToken("minute", TimeToken.MINUTES), /* minutes multiplier */
- new TimeToken("minutes", TimeToken.MINUTES), /* (pluralized) */
- new TimeToken("min", TimeToken.MINUTES), /* (generic) */
- new TimeToken("m", TimeToken.MONTHS_MINUTES), /* (short generic) */
- new TimeToken("hour", TimeToken.HOURS), /* hours ... */
- new TimeToken("hours", TimeToken.HOURS), /* (pluralized) */
- new TimeToken("hr", TimeToken.HOURS), /* (generic) */
- new TimeToken("h", TimeToken.HOURS), /* (short generic) */
- new TimeToken("day", TimeToken.DAYS), /* days ... */
+ new TimeToken("minute", TimeToken.MINUTES), /* minutes multiplier */
+ new TimeToken("minutes", TimeToken.MINUTES), /* (pluralized) */
+ new TimeToken("min", TimeToken.MINUTES), /* (generic) */
+ new TimeToken("m", TimeToken.MONTHS_MINUTES), /* (short generic) */
+ new TimeToken("hour", TimeToken.HOURS), /* hours ... */
+ new TimeToken("hours", TimeToken.HOURS), /* (pluralized) */
+ new TimeToken("hr", TimeToken.HOURS), /* (generic) */
+ new TimeToken("h", TimeToken.HOURS), /* (short generic) */
+ new TimeToken("day", TimeToken.DAYS), /* days ... */
new TimeToken("days", TimeToken.DAYS), /* (pluralized) */
- new TimeToken("d", TimeToken.DAYS), /* (short generic) */
- new TimeToken("week", TimeToken.WEEKS), /* week ... */
- new TimeToken("weeks", TimeToken.WEEKS), /* (pluralized) */
- new TimeToken("wk", TimeToken.WEEKS), /* (generic) */
- new TimeToken("w", TimeToken.WEEKS), /* (short generic) */
- new TimeToken("month", TimeToken.MONTHS), /* week ... */
+ new TimeToken("d", TimeToken.DAYS), /* (short generic) */
+ new TimeToken("week", TimeToken.WEEKS), /* week ... */
+ new TimeToken("weeks", TimeToken.WEEKS), /* (pluralized) */
+ new TimeToken("wk", TimeToken.WEEKS), /* (generic) */
+ new TimeToken("w", TimeToken.WEEKS), /* (short generic) */
+ new TimeToken("month", TimeToken.MONTHS), /* week ... */
new TimeToken("months", TimeToken.MONTHS), /* (pluralized) */
- new TimeToken("mon", TimeToken.MONTHS), /* (generic) */
- new TimeToken("year", TimeToken.YEARS), /* year ... */
- new TimeToken("years", TimeToken.YEARS), /* (pluralized) */
- new TimeToken("yr", TimeToken.YEARS), /* (generic) */
- new TimeToken("y", TimeToken.YEARS), /* (short generic) */
+ new TimeToken("mon", TimeToken.MONTHS), /* (generic) */
+ new TimeToken("year", TimeToken.YEARS), /* year ... */
+ new TimeToken("years", TimeToken.YEARS), /* (pluralized) */
+ new TimeToken("yr", TimeToken.YEARS), /* (generic) */
+ new TimeToken("y", TimeToken.YEARS), /* (short generic) */
new TimeToken(null, 0) /*** SENTINEL ***/
};
diff --git a/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeSpec.java b/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeSpec.java
index dcc6e960a..af705a0ee 100644
--- a/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeSpec.java
+++ b/apps/jrobin/java/src/org/rrd4j/core/timespec/TimeSpec.java
@@ -1,7 +1,5 @@
package org.rrd4j.core.timespec;
-import org.rrd4j.core.Util;
-
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
@@ -33,7 +31,7 @@ public class TimeSpec {
void localtime(long timestamp) {
GregorianCalendar date = new GregorianCalendar();
date.setTime(new Date(timestamp * 1000L));
- year = date.get(Calendar.YEAR) - 1900;
+ year = date.get(Calendar.YEAR);
month = date.get(Calendar.MONTH);
day = date.get(Calendar.DAY_OF_MONTH);
hour = date.get(Calendar.HOUR_OF_DAY);
@@ -46,7 +44,7 @@ public class TimeSpec {
GregorianCalendar gc;
// absolute time, this is easy
if (type == TYPE_ABSOLUTE) {
- gc = new GregorianCalendar(year + 1900, month, day, hour, min, sec);
+ gc = new GregorianCalendar(year, month, day, hour, min, sec);
}
// relative time, we need a context to evaluate it
else if (context != null && context.type == TYPE_ABSOLUTE) {
@@ -77,7 +75,7 @@ public class TimeSpec {
* @return Timestamp (in seconds, no milliseconds)
*/
public long getTimestamp() {
- return Util.getTimestamp(getTime());
+ return getTime().toInstant().getEpochSecond();
}
String dump() {
@@ -133,7 +131,7 @@ public class TimeSpec {
public static long[] getTimestamps(TimeSpec spec1, TimeSpec spec2) {
Calendar[] gcs = getTimes(spec1, spec2);
return new long[] {
- Util.getTimestamp(gcs[0]), Util.getTimestamp(gcs[1])
+ gcs[0].toInstant().getEpochSecond(), gcs[1].toInstant().getEpochSecond()
};
}
}
diff --git a/apps/jrobin/java/src/org/rrd4j/data/CubicSplineInterpolator.java b/apps/jrobin/java/src/org/rrd4j/data/CubicSplineInterpolator.java
index 94d851615..3327dde1b 100644
--- a/apps/jrobin/java/src/org/rrd4j/data/CubicSplineInterpolator.java
+++ b/apps/jrobin/java/src/org/rrd4j/data/CubicSplineInterpolator.java
@@ -13,6 +13,7 @@ import java.util.Date;
* WARNING: So far, this class cannot handle NaN datasource values
* (an exception will be thrown by the constructor). Future releases might change this.
*/
+@SuppressWarnings("deprecation")
public class CubicSplineInterpolator extends Plottable {
private double[] x;
private double[] y;
diff --git a/apps/jrobin/java/src/org/rrd4j/data/DataProcessor.java b/apps/jrobin/java/src/org/rrd4j/data/DataProcessor.java
index 2871926d5..dec613e5b 100644
--- a/apps/jrobin/java/src/org/rrd4j/data/DataProcessor.java
+++ b/apps/jrobin/java/src/org/rrd4j/data/DataProcessor.java
@@ -1,6 +1,22 @@
package org.rrd4j.data;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.time.Instant;
+import java.time.temporal.TemporalAmount;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TimeZone;
+
import org.rrd4j.ConsolFun;
+import org.rrd4j.core.DataHolder;
import org.rrd4j.core.FetchData;
import org.rrd4j.core.FetchRequest;
import org.rrd4j.core.RrdBackendFactory;
@@ -8,18 +24,6 @@ import org.rrd4j.core.RrdDb;
import org.rrd4j.core.RrdDbPool;
import org.rrd4j.core.Util;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TimeZone;
-
/**
* Class which should be used for all calculations based on the data fetched from RRD files. This class
* supports ordinary DEF datasources (defined in RRD files), CDEF datasources (RPN expressions evaluation),
@@ -43,28 +47,24 @@ import java.util.TimeZone;
* System.out.println(dp.dump());
*
*/
-public class DataProcessor {
+public class DataProcessor implements DataHolder {
/**
- * Constant representing the default number of pixels on a Rrd4j graph (will be used if
- * no other value is specified with {@link #setStep(long) setStep()} method.
+ * Not used any more.
*/
+ @Deprecated
public static final int DEFAULT_PIXEL_COUNT = 600;
/** Constant Roughly corresponds to the --step option in RRDTool's graph/xport commands. Here is an explanation borrowed
- * from RRDTool: "By default rrdgraph calculates the width of one pixel in the time
- * domain and tries to get data at that resolution from the RRD. With
- * this switch you can override this behavior. If you want rrdgraph to
- * get data at 1 hour resolution from the RRD, then you can set the
- * step to 3600 seconds. Note, that a step smaller than 1 pixel will
- * be silently ignored." I think this option is not that useful, but it's here just for compatibility. Adds complex source (CDEF).
+ * Complex sources are evaluated using the supplied
+ * Rrd4j does not force you to specify at least one simple source name as RRDTool.
+ *
+ * For more details on RPN see RRDTool's
+ *
+ * rrdgraph man page.
+ *
+ * @param name source name.
+ * @param rpnExpression RPN expression containing comma delimited simple and complex
+ * source names, RPN constants, functions and operators.
+ * @since 3.7
+ */
+ @Override
+ public void datasource(String name, String rpnExpression) {
CDef cDef = new CDef(name, rpnExpression);
sources.put(name, cDef);
}
@@ -533,7 +587,7 @@ public class DataProcessor {
/**
* Creates a datasource that performs a variable calculation on an
- * another named datasource to yield a single combined timestampe/value.
+ * another named datasource to yield a single combined timestamp/value.
*
* Requires that the other datasource has already been defined; otherwise, it'll
* end up with no data
@@ -542,8 +596,28 @@ public class DataProcessor {
* @param defName - the datasource from which to extract the percentile. Must be a previously
* defined virtual datasource
* @param var - a new instance of a Variable used to do the calculation
+ * @deprecated Uses {@link #datasource(String, String, Variable)} instead.
*/
+ @Deprecated
public void addDatasource(String name, String defName, Variable var) {
+ datasource(name, defName, var);
+ }
+
+ /**
+ * Creates a datasource that performs a variable calculation on an
+ * another named datasource to yield a single combined timestamp/value.
+ *
+ * Requires that the other datasource has already been defined; otherwise, it'll
+ * end up with no data
+ *
+ * @param name - the new virtual datasource name
+ * @param defName - the datasource from which to extract the percentile. Must be a previously
+ * defined virtual datasource
+ * @param var - a new instance of a Variable used to do the calculation
+ * @since 3.7
+ */
+ @Override
+ public void datasource(String name, String defName, Variable var) {
VDef sDef = new VDef(name, defName, var);
sources.put(name, sDef);
}
@@ -560,9 +634,52 @@ public class DataProcessor {
* @param file Path to RRD file.
* @param dsName Datasource name defined in the RRD file.
* @param consolFunc Consolidation function that will be used to extract data from the RRD
+ * @deprecated Uses {@link #datasource(String, String, String, ConsolFun)} instead.
*/
+ @Deprecated
public void addDatasource(String name, String file, String dsName, ConsolFun consolFunc) {
- Def def = new Def(name, file, dsName, consolFunc);
+ datasource(name, file, dsName, consolFunc);
+ }
+
+ /**
+ * Adds simple datasource (DEF). Simple source Adds simple datasource (DEF). Simple source Adds simple source (DEF). Source Adds simple source (DEF). Source If you wish to use a custom datasource in a graph, you should create a class implementing this interface
+ * that represents that datasource, and then pass this class on to the RrdGraphDef.
- *
- *
- *
+ *
- *
+ *
- *
- *
- *
- * DEFAULT_PERCENTILE=95.0 */
public static final double DEFAULT_PERCENTILE = 95.0; // %
- private int pixelCount = DEFAULT_PIXEL_COUNT;
+ private int pixelCount = 0;
- /**
- * Constant that defines the default {@link RrdDbPool} usage policy. Defaults to false
- * (i.e. the pool will not be used to fetch data from RRD files)
- */
- public static final boolean DEFAULT_POOL_USAGE_POLICY = false;
private boolean poolUsed = DEFAULT_POOL_USAGE_POLICY;
private RrdDbPool pool = null;
- private final long tStart;
- private long tEnd, timestamps[];
+ private long tStart;
+ private long tEnd;
+ private long timestamps[];
private long lastRrdArchiveUpdateTime = 0;
// this will be adjusted later
private long step = 0;
@@ -123,11 +123,24 @@ public class DataProcessor {
this.tz = gc1.getTimeZone();
}
+ /**
+ * Creates new DataProcessor object for the given time duration. The given duration will be
+ * substracted from current time.
+ *
+ * @param d duration to substract.
+ */
+ public DataProcessor(TemporalAmount d) {
+ Instant now = Instant.now();
+ this.tEnd = now.getEpochSecond();
+ this.tStart = now.minus(d).getEpochSecond();
+ }
+
/**
* Returns boolean value representing {@link org.rrd4j.core.RrdDbPool RrdDbPool} usage policy.
*
* @return true, if the pool will be used internally to fetch data from RRD files, false otherwise.
*/
+ @Override
public boolean isPoolUsed() {
return poolUsed;
}
@@ -137,10 +150,12 @@ public class DataProcessor {
*
* @param poolUsed true, if the pool should be used to fetch data from RRD files, false otherwise.
*/
+ @Override
public void setPoolUsed(boolean poolUsed) {
this.poolUsed = poolUsed;
}
+ @Override
public RrdDbPool getPool() {
return pool;
}
@@ -150,6 +165,7 @@ public class DataProcessor {
* set to true, the default {@link RrdDbPool#getInstance()} will be used.
* @param pool an optional pool to use.
*/
+ @Override
public void setPool(RrdDbPool pool) {
this.pool = pool;
}
@@ -163,9 +179,6 @@ public class DataProcessor {
* and similar methods. In other words, aggregated values will not change once you decide to change
* the dimension of your graph.RPN expression.name can be used:
+ *
+ *
+ *
+ * The supported RPN functions, operators and constants are detailed at
+ * RRD4J's wiki.
+ * name
+ * can be used:
+ *
+ *
+ * @param name source name.
+ * @param file Path to RRD file.
+ * @param dsName Datasource name defined in the RRD file.
+ * @param consolFunc Consolidation function that will be used to extract data from the RRD
+ * @since 3.7
+ */
+ @Override
+ public void datasource(String name, String file, String dsName, ConsolFun consolFunc) {
+ RrdBackendFactory factory = RrdBackendFactory.getDefaultFactory();
+ Def def = new Def(name, factory.getUri(file), dsName, consolFunc, factory);
+ sources.put(name, def);
+ }
+
+ /**
+ * name
+ * can be used:
+ *
+ *
+ * @param name source name.
+ * @param rrdUri URI to RRD file.
+ * @param dsName Datasource name defined in the RRD file.
+ * @param consolFunc Consolidation function that will be used to extract data from the RRD
+ * @since 3.7
+ */
+ @Override
+ public void datasource(String name, URI rrdUri, String dsName,
+ ConsolFun consolFunc) {
+ Def def = new Def(name, rrdUri, dsName, consolFunc, RrdBackendFactory.findFactory(rrdUri));
sources.put(name, def);
}
@@ -580,11 +697,12 @@ public class DataProcessor {
* file ("AVERAGE", "MIN", "MAX" or "LAST" - these string constants are conveniently defined
* in the {@link org.rrd4j.ConsolFun ConsolFun} class).
* @param backend Name of the RrdBackendFactory that should be used for this RrdDb.
- * @deprecated uses {@link #addDatasource(String, String, String, ConsolFun, RrdBackendFactory)} instead
+ * @deprecated uses {@link #datasource(String, String, String, ConsolFun, RrdBackendFactory)} instead
*/
@Deprecated
public void addDatasource(String name, String file, String dsName, ConsolFun consolFunc, String backend) {
- Def def = new Def(name, file, dsName, consolFunc, RrdBackendFactory.getFactory(backend));
+ RrdBackendFactory factory = RrdBackendFactory.getFactory(backend);
+ Def def = new Def(name, factory.getUri(file), dsName, consolFunc, factory);
sources.put(name, def);
}
@@ -602,9 +720,55 @@ public class DataProcessor {
* file ("AVERAGE", "MIN", "MAX" or "LAST" - these string constants are conveniently defined
* in the {@link org.rrd4j.ConsolFun ConsolFun} class).
* @param backend Name of the RrdBackendFactory that should be used for this RrdDb.
+ * @deprecated uses {@link #datasource(String, String, String, ConsolFun, RrdBackendFactory)} instead
*/
+ @Deprecated
public void addDatasource(String name, String file, String dsName, ConsolFun consolFunc, RrdBackendFactory backend) {
- Def def = new Def(name, file, dsName, consolFunc, backend);
+ datasource(name, file, dsName, consolFunc, backend);
+ }
+
+ /**
+ * name can be used:
+ *
+ *
+ * @param name Source name.
+ * @param file Path to RRD file.
+ * @param dsName Data source name defined in the RRD file.
+ * @param consolFunc Consolidation function that will be used to extract data from the RRD
+ * file ("AVERAGE", "MIN", "MAX" or "LAST" - these string constants are conveniently defined
+ * in the {@link org.rrd4j.ConsolFun ConsolFun} class).
+ * @param backend Name of the RrdBackendFactory that should be used for this RrdDb.
+ * @since 3.7
+ */
+ @Override
+ public void datasource(String name, String file, String dsName, ConsolFun consolFunc, RrdBackendFactory backend) {
+ Def def = new Def(name, backend.getUri(file), dsName, consolFunc, backend);
+ sources.put(name, def);
+ }
+
+
+ /**
+ * name can be used:
+ *
+ *
+ * @param name Source name.
+ * @param uri URI to RRD file.
+ * @param dsName Data source name defined in the RRD file.
+ * @param consolFunc Consolidation function that will be used to extract data from the RRD
+ * file ("AVERAGE", "MIN", "MAX" or "LAST" - these string constants are conveniently defined
+ * in the {@link org.rrd4j.ConsolFun ConsolFun} class).
+ * @param backend Name of the RrdBackendFactory that should be used for this RrdDb.
+ * @since 3.7
+ */
+ @Override
+ public void datasource(String name, URI uri, String dsName, ConsolFun consolFunc, RrdBackendFactory backend) {
+ Def def = new Def(name, uri, dsName, consolFunc, backend);
sources.put(name, def);
}
@@ -614,8 +778,23 @@ public class DataProcessor {
*
* @param name Source name.
* @param fetchData Fetched data containing values for the given source name.
+ * @deprecated Uses {@link #datasource(String, FetchData)} instead.
*/
+ @Deprecated
public void addDatasource(String name, FetchData fetchData) {
+ datasource(name, fetchData);
+ }
+
+ /**
+ * Adds DEF datasource with datasource values already available in the FetchData object. This method is
+ * used internally by Rrd4j and probably has no purpose outside of it.
+ *
+ * @param name Source name.
+ * @param fetchData Fetched data containing values for the given source name.
+ * @since 3.7
+ */
+ @Override
+ public void datasource(String name, FetchData fetchData) {
Def def = new Def(name, fetchData);
sources.put(name, def);
}
@@ -628,12 +807,30 @@ public class DataProcessor {
* @param name Source name.
* @param dsName Source name in the fetch data.
* @param fetchData Fetched data containing values for the given source name.
+ * @deprecated Uses {@link #datasource(String, String, FetchData)} instead.
*/
+ @Deprecated
public void addDatasource(String name, String dsName, FetchData fetchData) {
Def def = new Def(name, dsName, fetchData);
sources.put(name, def);
}
+ /**
+ * Adds DEF datasource with datasource values already available in the FetchData object. This method is
+ * used internally by Rrd4j and probably has no purpose outside of it.
+ * The values will be extracted from dsName in fetchData.
+ *
+ * @param name Source name.
+ * @param dsName Source name in the fetch data.
+ * @param fetchData Fetched data containing values for the given source name.
+ * @since 3.7
+ */
+ @Override
+ public void datasource(String name, String dsName, FetchData fetchData) {
+ Def def = new Def(name, dsName, fetchData);
+ sources.put(name, def);
+ }
+
/////////////////////////////////////////////////////////////////
// CALCULATIONS
/////////////////////////////////////////////////////////////////
@@ -711,7 +908,8 @@ public class DataProcessor {
}
/**
- * Calculates timestamps which correspond to individual pixels on the graph.
+ * Calculates timestamps which correspond to individual pixels on the graph. It also
+ * set the timestampsPerPixel value.
*
* @param pixelCount Graph width
* @return Array of timestamps
@@ -772,35 +970,60 @@ public class DataProcessor {
// PRIVATE METHODS
private void extractDefs() {
- List
If you wish to use a custom datasource in a graph, you should create a class implementing this interface * that represents that datasource, and then pass this class on to the RrdGraphDef.
+ * @deprecated use implementations of {@link IPlottable} instead */ -public abstract class Plottable { +@Deprecated +public abstract class Plottable implements IPlottable { /** * Retrieves datapoint value based on a given timestamp. * Use this method if you only have one series of data in this class. @@ -14,7 +16,5 @@ public abstract class Plottable { * @param timestamp Timestamp in seconds for the datapoint. * @return Double value of the datapoint. */ - public double getValue(long timestamp) { - return Double.NaN; - } + public abstract double getValue(long timestamp); } diff --git a/apps/jrobin/java/src/org/rrd4j/data/Variable.java b/apps/jrobin/java/src/org/rrd4j/data/Variable.java index 2668032cf..d6d6aea40 100644 --- a/apps/jrobin/java/src/org/rrd4j/data/Variable.java +++ b/apps/jrobin/java/src/org/rrd4j/data/Variable.java @@ -26,6 +26,10 @@ public abstract class Variable { this.value = value; this.timestamp = timestamp; } + @Override + public String toString() { + return "Value [value=" + value + ", timestamp=" + timestamp + "]"; + } }; public static final Value INVALIDVALUE = new Value(0, Double.NaN); @@ -33,7 +37,7 @@ public abstract class Variable { private Value val = null; /** - * Used to calculate the needed value from a source, this method call fill. + * Used to calculate the needed value from a source, this method call the abstract method {@link #fill(long[], double[], long, long)}. * @param s * @param start * @param end @@ -44,8 +48,8 @@ public abstract class Variable { int last = -1; // Iterate over array, stop then end cursor reach start or when both start and end has been found // It also stop if cursor cross other side boundary - for(int i = 0, j = s.timestamps.length - 1 ; ( last == -1 && j > first ) || ( first == -1 && ( last == -1 || i < last ) ) ; i++, j--) { - if(first == -1) { + for (int i = 0, j = s.timestamps.length - 1 ; i < s.timestamps.length && j >= 0 ; i++, j--) { + if (first == -1) { long leftdown = Math.max(s.timestamps[i] - step, start); long rightdown = Math.min(s.timestamps[i], end); if(rightdown > leftdown) { @@ -53,34 +57,35 @@ public abstract class Variable { } } - if(last == -1) { + if (last == -1) { long leftup = Math.max(s.timestamps[j] - step, start); long rightup = Math.min(s.timestamps[j], end); - if(rightup > leftup ) { + if (rightup > leftup ) { last = j; } } + if ((( last != -1 || j <= first ) && ( first != -1 || ( last != -1 && i >= last )))) { + break; + } } - if( first == -1 || last == -1) { - throw new RuntimeException("Invalid range"); - } - if(s instanceof VDef) { + if (first == -1 || last == -1) { + val = INVALIDVALUE; + } else if (s instanceof VDef) { // Already a variable, just check if it fits Value v = ((VDef) s).getValue(); // No time stamp, or not time stamped value, keep it - if(v.timestamp == 0) { + if (v.timestamp == 0) { val = v; } else { - if(v.timestamp < end && v.timestamp > start) { + if (v.timestamp < end && v.timestamp > start) { val = v; } else { val = new Value(0, Double.NaN); } } - } - else { + } else { long[] timestamps = new long[ last - first + 1]; System.arraycopy(s.timestamps, first, timestamps, 0, timestamps.length); double[] values = new double[ last - first + 1]; @@ -115,8 +120,8 @@ public abstract class Variable { public static class FIRST extends Variable { @Override protected Value fill(long[] timestamps, double[] values, long start, long end) { - for(int i = 0; i < values.length; i++) { - if( timestamps[i] > start && timestamps[i] < end && ! Double.isNaN(values[i])) { + for (int i = 0; i < values.length; i++) { + if (timestamps[i] > start && timestamps[i] < end && ! Double.isNaN(values[i])) { return new Value(timestamps[i], values[i]); } } @@ -131,8 +136,8 @@ public abstract class Variable { public static class LAST extends Variable { @Override protected Value fill(long[] timestamps, double[] values, long start, long end) { - for(int i = values.length - 1 ; i >=0 ; i--) { - if( ! Double.isNaN(values[i]) ) { + for (int i = values.length - 1 ; i >=0 ; i--) { + if (! Double.isNaN(values[i]) ) { return new Value(timestamps[i], values[i]); } } @@ -149,11 +154,11 @@ public abstract class Variable { protected Value fill(long[] timestamps, double[] values, long start, long end) { long timestamp = 0; double value = Double.NaN; - for(int i = values.length -1 ; i >=0 ; i--) { - if(! Double.isNaN(values[i]) && Double.isNaN(value)) { + for (int i = values.length -1 ; i >=0 ; i--) { + if (! Double.isNaN(values[i]) && Double.isNaN(value)) { timestamp = timestamps[i]; value = values[i]; - } else if( ! Double.isNaN(values[i]) && value > values[i]) { + } else if ( ! Double.isNaN(values[i]) && value > values[i]) { timestamp = timestamps[i]; value = values[i]; } @@ -171,11 +176,11 @@ public abstract class Variable { protected Value fill(long[] timestamps, double[] values, long start, long end) { long timestamp = 0; double value = Double.NaN; - for(int i = values.length -1 ; i >=0 ; i--) { - if(! Double.isNaN(values[i]) && Double.isNaN(value)) { + for (int i = values.length -1 ; i >=0 ; i--) { + if (! Double.isNaN(values[i]) && Double.isNaN(value)) { timestamp = timestamps[i]; value = values[i]; - } else if(!Double.isNaN(values[i]) && value < values[i]) { + } else if (!Double.isNaN(values[i]) && value < values[i]) { timestamp = timestamps[i]; value = values[i]; } @@ -193,7 +198,7 @@ public abstract class Variable { protected Value fill(long[] timestamps, double[] values, long start, long end) { double value = Double.NaN; - for(double tempVal: values) { + for (double tempVal: values) { value = Util.sum(value, tempVal); } return new Value(0, value * (timestamps[1] - timestamps[0]) ); @@ -217,8 +222,7 @@ public abstract class Variable { } if (! Double.isNaN(value) && count > 0) { value = value / count; - } - else { + } else { value = Double.NaN; } return new Value(0, value); @@ -237,21 +241,20 @@ public abstract class Variable { double M = 0.0; double S = 0.0; // See Knuth TAOCP vol 2, 3rd edition, page 232 and http://www.johndcook.com/standard_deviation.html - for(double cursVal: values) { - if(Double.isNaN(cursVal)) + for (double cursVal: values) { + if (Double.isNaN(cursVal)) continue; count++; - if(count == 1) { + if (count == 1) { M = cursVal; S = 0; - } - else { + } else { double dM = cursVal - M; M += dM/count; S += dM * (cursVal - M); } } - if(count > 1) { + if (count > 1) { value = Math.sqrt( S/(count - 1) ); } return new Value(0, value); @@ -303,9 +306,9 @@ public abstract class Variable { static final class ComparPercentElemen implements Comparator+ * The fonts settings can be changed use some on the following properties, sorted by increased priority. + *
org.rrd4j.fonts.propertiesorg.rrd4j.fonts.properties.urlorg.rrd4j.font.plainorg.rrd4j.font.boldorg.rrd4j.font.plain.urlorg.rrd4j.font.bold.urlorg.rrd4j.fonts.properties or org.rrd4j.fonts.properties.url is used, the file provided contains any other property of lower priority .
+ * The last four properties defines directly the plain or bold font. All properties URL related (org.rrd4j.fonts.url, org.rrd4j.font.plain.url and
+ * org.rrd4j.font.bold.url) download data from an URL. They are useful when those data are provided by the file system, defined by the OS.
+ * The others search for the data in the classpath. So it's easy to provided font-pack as a jar that's put before RRD44J's jar.
+ *
+ * The default settings uses org.rrd4j.fonts.properties looking for the file /rrd4jfonts.properties in the classpath.
*/
public interface RrdGraphConstants {
/**
@@ -265,10 +291,70 @@ public interface RrdGraphConstants {
double DEFAULT_BASE = 1000;
/**
- * Font constructor, to use embedded fonts
+ * The file that contains font configuration searched in the class path. The default value is /rrd4jfonts.properties
+ */
+ public static final String PROPERTYFONTSPROPERTIES = "org.rrd4j.fonts.properties";
+ /**
+ * A possible URL to a configuration file.
+ */
+ public static final String PROPERTYFONTSURL = "org.rrd4j.fonts.properties.url";
+ /**
+ * The name of the plain font, used to define the {@link #DEFAULT_SMALL_FONT} and the {@link GATOR_FONT}. To be found in the classpath.
+ */
+ public static final String PROPERTYFONTPLAIN = "org.rrd4j.font.plain";
+ /**
+ * The name of the bold font, used to define the {@link #DEFAULT_LARGE_FONT}. To be found in the classpath.
+ */
+ public static final String PROPERTYFONTBOLD = "org.rrd4j.font.bold";
+ /**
+ * An URL to the plain font, used to define the {@link #DEFAULT_SMALL_FONT} and the {@link GATOR_FONT}.
+ */
+ public static final String PROPERTYFONTPLAINURL = "org.rrd4j.font.plain.url";
+ /**
+ * An URL to the bold font, used to define the {@link #DEFAULT_LARGE_FONT}.
+ */
+ public static final String PROPERTYFONTBOLDURL = "org.rrd4j.font.bold.url";
+
+ /**
+ * Font constructor, to use embedded fonts. Not really useful outside internal use for RRD4J.
*/
static class FontConstructor {
+ private static final Properties fileProps = new Properties();
+ static {
+ refreshConf();
+ }
private FontConstructor() {}
+
+ /**
+ * Used for tests
+ */
+ static void refreshConf() {
+ fileProps.clear();
+ Optional.ofNullable(System.getProperty(PROPERTYFONTSPROPERTIES, "/rrd4jfonts.properties"))
+ .filter(s -> ! s.isEmpty())
+ .map(RrdGraphConstants.class::getResourceAsStream)
+ .ifPresent(t -> {
+ try {
+ fileProps.load(t);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ Optional.ofNullable(System.getProperty(PROPERTYFONTSURL))
+ .filter(s -> ! s.isEmpty())
+ .ifPresent(t -> {
+ try {
+ fileProps.load(new URL(t).openStream());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+ for (String prop: new String[] {PROPERTYFONTPLAIN, PROPERTYFONTBOLD, PROPERTYFONTPLAINURL, PROPERTYFONTBOLDURL}) {
+ Optional.ofNullable(System.getProperty(prop))
+ .filter(s -> ! s.isEmpty())
+ .ifPresent(s -> fileProps.put(prop, s));
+ }
+ }
/**
* Return the default RRD4J's default font for the given strength
@@ -278,14 +364,22 @@ public interface RrdGraphConstants {
*/
public static Font getFont(int type, int size) {
/*
- String fontPath;
- if (type == Font.BOLD)
- fontPath = "/DejaVuSansMono-Bold.ttf";
- else
- fontPath = "/DejaVuSansMono.ttf";
-
- try (InputStream fontstream = RrdGraphConstants.class.getResourceAsStream(fontPath)) {
- return Font.createFont(Font.TRUETYPE_FONT, fontstream).deriveFont(type == Font.BOLD ? Font.BOLD : Font.PLAIN, size);
+ Function
Implementations of this class can be used to generate image than can be @@ -96,7 +101,8 @@ public class RrdGraphDef implements RrdGraphConstants { } } - boolean poolUsed = false; // ok + boolean poolUsed = DEFAULT_POOL_USAGE_POLICY; + private RrdDbPool pool = null; boolean antiAliasing = false; // ok boolean textAntiAliasing = false; // ok String filename = RrdGraphConstants.IN_MEMORY_IMAGE; // ok @@ -173,17 +179,47 @@ public class RrdGraphDef implements RrdGraphConstants { /** * Creates RrdGraphDef object and sets default time span (default ending time is 'now', * default starting time is 'end-1day'. + * @deprecated Uses default value that will be probably overriden. */ + @Deprecated public RrdGraphDef() { setTimeSpan(Util.getTimestamps(DEFAULT_START, DEFAULT_END)); } + /** + * Creates RrdGraphDef object. + * @since 3.7 + */ + public RrdGraphDef(long t1, long t2) { + if ((t1 < t2 && t1 > 0 && t2 > 0) || (t1 > 0 && t2 == 0)) { + this.startTime = t1; + this.endTime = t2; + } + else { + throw new IllegalArgumentException("Invalid timestamps specified: " + t1 + ", " + t2); + } + } + + /** + * Creates new DataProcessor object for the given time duration. The given duration will be + * substracted from current time. + * + * @param d duration to substract. + * @since 3.7 + */ + public RrdGraphDef(TemporalAmount d) { + Instant now = Instant.now(); + this.endTime = now.getEpochSecond(); + this.startTime = now.minus(d).getEpochSecond(); + } + /** * Sets the time when the graph should begin. Time in seconds since epoch * (1970-01-01) is required. Negative numbers are relative to the current time. * * @param time Starting time for the graph in seconds since epoch */ + @Override public void setStartTime(long time) { this.startTime = time; if (time <= 0) { @@ -197,6 +233,7 @@ public class RrdGraphDef implements RrdGraphConstants { * * @param time Ending time for the graph in seconds since epoch */ + @Override public void setEndTime(long time) { this.endTime = time; if (time <= 0) { @@ -211,6 +248,7 @@ public class RrdGraphDef implements RrdGraphConstants { * @param startTime Starting time in seconds since epoch * @param endTime Ending time in seconds since epoch */ + @Override public void setTimeSpan(long startTime, long endTime) { setStartTime(startTime); setEndTime(endTime); @@ -234,10 +272,36 @@ public class RrdGraphDef implements RrdGraphConstants { * * @param poolUsed true, if RrdDbPool class should be used. False otherwise. */ + @Override public void setPoolUsed(boolean poolUsed) { this.poolUsed = poolUsed; } + /** + * @since 3.7 + */ + @Override + public boolean isPoolUsed() { + return poolUsed; + } + + /** + * @since 3.7 + */ + @Override + public RrdDbPool getPool() { + return pool; + } + + /** + * @since 3.7 + */ + @Override + public void setPool(RrdDbPool pool) { + this.poolUsed = true; + this.pool = pool; + } + /** * Sets the name of the graph to generate. Since Rrd4j outputs GIFs, PNGs, * and JPEGs it's recommended that the filename end in either .gif, @@ -781,6 +845,7 @@ public class RrdGraphDef implements RrdGraphConstants { * * @param step Desired time step (don't use this method if you don't know what you're doing). */ + @Override public void setStep(long step) { this.step = step; } @@ -821,7 +886,7 @@ public class RrdGraphDef implements RrdGraphConstants { * font is selected. * * @param smallFont Default font for graphing. Use only monospaced fonts. - * @deprecated Use {@link Variable} based method instead. + * @deprecated Use {@link FontTag} based method instead. */ @Deprecated public void setSmallFont(final Font smallFont) { @@ -832,7 +897,7 @@ public class RrdGraphDef implements RrdGraphConstants { * Sets title font. * * @param largeFont Font to be used for graph title. - * @deprecated Use {@link Variable} based method instead. + * @deprecated Use {@link FontTag} based method instead. */ @Deprecated public void setLargeFont(final Font largeFont) { @@ -948,8 +1013,27 @@ public class RrdGraphDef implements RrdGraphConstants { * @param dsName Datasource name in the specified RRD file * @param consolFun Consolidation function (AVERAGE, MIN, MAX, LAST) */ + @Override public void datasource(String name, String rrdPath, String dsName, ConsolFun consolFun) { - sources.add(new Def(name, rrdPath, dsName, consolFun)); + RrdBackendFactory factory = RrdBackendFactory.getDefaultFactory(); + sources.add(new Def(name, factory.getUri(rrdPath), dsName, consolFun, factory)); + } + + /** + * Defines virtual datasource. This datasource can then be used + * in other methods like {@link #datasource(String, String)} or + * {@link #gprint(String, ConsolFun, String)}. + * + * @param name Source name + * @param rrdUri URI to RRD file + * @param dsName Datasource name in the specified RRD file + * @param consolFun Consolidation function (AVERAGE, MIN, MAX, LAST) + * @since 3.7 + */ + @Override + public void datasource(String name, URI rrdUri, String dsName, + ConsolFun consolFun) { + sources.add(new Def(name, rrdUri, dsName, consolFun, RrdBackendFactory.findFactory(rrdUri))); } /** @@ -967,7 +1051,8 @@ public class RrdGraphDef implements RrdGraphConstants { */ @Deprecated public void datasource(String name, String rrdPath, String dsName, ConsolFun consolFun, String backend) { - sources.add(new Def(name, rrdPath, dsName, consolFun, RrdBackendFactory.getFactory(backend))); + RrdBackendFactory factory = RrdBackendFactory.getFactory(backend); + sources.add(new Def(name, factory.getUri(rrdPath), dsName, consolFun, factory)); } /** @@ -981,8 +1066,27 @@ public class RrdGraphDef implements RrdGraphConstants { * @param consolFun Consolidation function (AVERAGE, MIN, MAX, LAST) * @param backend Backend to be used while fetching data from a RRD file. */ + @Override public void datasource(String name, String rrdPath, String dsName, ConsolFun consolFun, RrdBackendFactory backend) { - sources.add(new Def(name, rrdPath, dsName, consolFun, backend)); + sources.add(new Def(name, backend.getUri(rrdPath), dsName, consolFun, backend)); + } + + /** + * Defines virtual datasource. This datasource can then be used + * in other methods like {@link #datasource(String, String)} or + * {@link #gprint(String, ConsolFun, String)}. + * + * @param name Source name + * @param rrdUri Path to RRD file + * @param dsName Datasource name in the specified RRD file + * @param consolFun Consolidation function (AVERAGE, MIN, MAX, LAST) + * @param backend Backend to be used while fetching data from a RRD file. + * @since 3.7 + */ + @Override + public void datasource(String name, URI rrdUri, String dsName, + ConsolFun consolFun, RrdBackendFactory backend) { + sources.add(new Def(name, rrdUri, dsName, consolFun, backend)); } /** @@ -992,6 +1096,7 @@ public class RrdGraphDef implements RrdGraphConstants { * @param name Source name * @param rpnExpression RPN expression. */ + @Override public void datasource(String name, String rpnExpression) { sources.add(new CDef(name, rpnExpression)); } @@ -1010,6 +1115,19 @@ public class RrdGraphDef implements RrdGraphConstants { datasource(name, defName, consolFun.getVariable()); } + /** + * Creates a datasource that performs a variable calculation on an + * another named datasource to yield a single combined timestamp/value. + * + * Requires that the other datasource has already been defined; otherwise, it'll + * end up with no data + * + * @param name - the new virtual datasource name + * @param defName - the datasource from which to extract the percentile. Must be a previously + * defined virtual datasource + * @param var - a new instance of a Variable used to do the calculation + */ + @Override public void datasource(String name, String defName, Variable var) { sources.add(new VDef(name, defName, var)); } @@ -1020,8 +1138,10 @@ public class RrdGraphDef implements RrdGraphConstants { * * @param name Source name. * @param plottable Plottable object. + * @since 3.7 */ - public void datasource(String name, Plottable plottable) { + @Override + public void datasource(String name, IPlottable plottable) { sources.add(new PDef(name, plottable)); } @@ -1032,6 +1152,7 @@ public class RrdGraphDef implements RrdGraphConstants { * @param name Source name. * @param fetchData FetchData object. */ + @Override public void datasource(String name, FetchData fetchData) { sources.add(new TDef(name, name, fetchData)); } @@ -1045,6 +1166,7 @@ public class RrdGraphDef implements RrdGraphConstants { * @param dsName Source name in fetchData. * @param fetchData FetchData object. */ + @Override public void datasource(String name, String dsName, FetchData fetchData) { sources.add(new TDef(name, dsName, fetchData)); } @@ -1723,10 +1845,19 @@ public class RrdGraphDef implements RrdGraphConstants { * * @param tz the time zone to set */ + @Override public void setTimeZone(TimeZone tz) { this.tz = tz; } + /** + * @since 3.7 + */ + @Override + public TimeZone getTimeZone() { + return this.tz; + } + /** * Set the Stroke used to draw grid * @@ -1784,4 +1915,28 @@ public class RrdGraphDef implements RrdGraphConstants { return colors[element.ordinal()]; } + /** + * @since 3.7 + */ + @Override + public long getEndTime() { + return this.endTime; + } + + /** + * @since 3.7 + */ + @Override + public long getStartTime() { + return this.startTime; + } + + /** + * @since 3.7 + */ + @Override + public long getStep() { + return this.step; + } + } diff --git a/apps/jrobin/java/src/org/rrd4j/graph/TDef.java b/apps/jrobin/java/src/org/rrd4j/graph/TDef.java index dcddb8694..0f197c40a 100644 --- a/apps/jrobin/java/src/org/rrd4j/graph/TDef.java +++ b/apps/jrobin/java/src/org/rrd4j/graph/TDef.java @@ -16,7 +16,7 @@ class TDef extends Source { @Override void requestData(DataProcessor dproc) { - dproc.addDatasource(name, dsName, fetchData); + dproc.datasource(name, dsName, fetchData); } } diff --git a/apps/jrobin/java/src/org/rrd4j/graph/VDef.java b/apps/jrobin/java/src/org/rrd4j/graph/VDef.java index 6161020a9..332380f6f 100644 --- a/apps/jrobin/java/src/org/rrd4j/graph/VDef.java +++ b/apps/jrobin/java/src/org/rrd4j/graph/VDef.java @@ -14,7 +14,7 @@ class VDef extends Source { } void requestData(DataProcessor dproc) { - dproc.addDatasource(name, defName, var); + dproc.datasource(name, defName, var); } }