RRD4J 3.8

Merged in our previous javadoc fixes
Their updated font-selector code remains commented
out in RrdGraphConstants.getFont()
Now requires Java 8
This commit is contained in:
zzz
2021-05-21 07:36:57 -04:00
parent 6926f5769e
commit b9efc002c0
33 changed files with 1212 additions and 392 deletions

View File

@@ -271,7 +271,7 @@ Applications:
See licenses/LICENSE-Apache2.0.txt
See licenses/LICENSE-ECLIPSE-1.0.html
RRD4J 3.6 (jrobin.jar):
RRD4J 3.8 (jrobin.jar):
Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor.
Copyright (c) 2011 The OpenNMS Group, Inc.
Copyright 2011 The RRD4J Authors.

View File

@@ -0,0 +1,207 @@
package org.rrd4j.core;
import java.net.URI;
import java.util.TimeZone;
import org.rrd4j.ConsolFun;
import org.rrd4j.data.IPlottable;
import org.rrd4j.data.Variable;
/**
* @author Fabrice Bacchella
* @since 3;7
*/
public interface DataHolder {
/**
* Constant that defines the default {@link RrdDbPool} usage policy. Defaults to <code>false</code>
* (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);
}

View File

@@ -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 Stream<RrdBackendFactory> getActiveFactories() {
return activeFactories.stream();
}
/**
* Add factories to the list of active factories, i.e. the factory used to resolve URI.

View File

@@ -70,6 +70,7 @@ public class RrdDb implements RrdUpdater<RrdDb>, Closeable {
* @return a new build RrdDb
* @throws IOException in case of I/O error.
* @throws IllegalArgumentException if the builder settings were incomplete
* @throws java.lang.IllegalStateException if the thread was interrupted in pool usage
*/
public RrdDb build() throws IOException {
if (rrdDef != null) {
@@ -113,6 +114,7 @@ public class RrdDb implements RrdUpdater<RrdDb>, Closeable {
*
* @throws IOException in case of I/O error.
* @throws IllegalArgumentException if the builder settings were incomplete
* @throws java.lang.IllegalStateException if the thread was interrupted in pool usage
*/
public void doimport() throws IOException {
if (rrdDef != null || (importer == null && externalPath == null)) {
@@ -185,7 +187,8 @@ public class RrdDb implements RrdUpdater<RrdDb>, Closeable {
}
/**
* Activate the pool usage
* Activate the pool usage. If the pool is not declared using
* {@link #setPool(RrdDbPool)}, the singleton instance will be used.
*
* @return the same builder.
*/
@@ -195,18 +198,29 @@ public class RrdDb implements RrdUpdater<RrdDb>, Closeable {
}
/**
* Set the pool that will be used if {@link #usePool} is true. If not defined,
* the singleton instance will be used.
* Set the pool that will be used and set usePool to true.
*
* @param pool true if a pool is going to be used
* @return the same builder.
*/
public Builder setPool(RrdDbPool pool) {
this.pool = pool;
this.usePool = pool != null;
return this;
}
/**
* Internal method used to memorized the pool, without generating a loop
* @param pool
* @return
*/
Builder setPoolInternal(RrdDbPool pool) {
this.pool = pool;
this.usePool = false;
return this;
}
/**
* Set when the builder will be used to import external data with a predefined source: XML or RRDTool.
* @param externalPath an URI-like indication of RRD data to import
* @return the same builder.
@@ -396,6 +410,7 @@ public class RrdDb implements RrdUpdater<RrdDb>, Closeable {
* </pre>
*
* @param rrdDef Object describing the structure of the new RRD file.
* @return a new Rrdb created from the definition.
* @throws java.io.IOException Thrown in case of I/O error.
*/
public static RrdDb of(RrdDef rrdDef) throws IOException {
@@ -807,6 +822,7 @@ public class RrdDb implements RrdUpdater<RrdDb>, Closeable {
* Closes RRD. No further operations are allowed on this RrdDb object.
*
* @throws java.io.IOException Thrown in case of I/O related error.
* @throws java.lang.IllegalStateException if the thread was interrupted in pool usage.
*/
@SuppressWarnings("deprecation")
public synchronized void close() throws IOException {
@@ -1381,6 +1397,10 @@ public class RrdDb implements RrdUpdater<RrdDb>, Closeable {
return backend.getUri();
}
public URI getCanonicalUri() {
return backend.getFactory().getCanonicalUri(getUri());
}
/**
* Returns backend object for this RRD which performs actual I/O operations.
*

View File

@@ -1,28 +1,28 @@
package org.rrd4j.core;
import java.io.IOException;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.URI;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.stream.Stream;
/**
* <p>This 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).
* </p>
* <p>It should not be called directly. Use {@link RrdDb.Builder#usePool()} instead.</p>
* <p>It can also be used a factory for RrdDb, using a default backend factory.</p>
* <p>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<URI> uris = new HashSet<>(pool.size());
pool.forEach((k,v) -> uris.add(k));
return uris.toArray(new URI[uris.size()]);
return pool.keySet().stream().toArray(URI[]::new);
}
/**
* Returns an array of open file path.
* Returns an stream open RRD.
*
* @return Array with canonical path to open RRD files held in the pool.
* @return Stream with canonical URI to open RRD path held in the pool.
* @since 3.7
*/
public Stream<URI> getOpenUriStream() {
return pool.keySet().stream();
}
/**
* Returns an array of open RRD.
*
* @return Array with canonical path to open RRD path held in the pool.
*/
public String[] getOpenFiles() {
//Direct toarray from keySet can fail
Set<String> uris = new HashSet<>(pool.size());
pool.forEach((k,v) -> uris.add(k.getPath()));
return uris.toArray(new String[uris.size()]);
return pool.keySet().stream().map(URI::getPath).toArray(String[]::new);
}
private RrdEntry getEntry(URI uri, boolean cancreate) throws InterruptedException {
@@ -260,8 +263,9 @@ public class RrdDbPool {
try {
usageWLock.lockInterruptibly();
fullCondition.signalAll();
} catch (InterruptedException ex) {
throw new UndeclaredThrowableException(ex);
} catch (InterruptedException e1) {
// Lost slot available notification
Thread.currentThread().interrupt();
} finally {
if (usageWLock.isHeldByCurrentThread()) {
usageWLock.unlock();
@@ -278,11 +282,12 @@ public class RrdDbPool {
/**
* Releases RrdDb reference previously obtained from the pool. When a reference is released, its usage
* count is decremented by one. If usage count drops to zero, the underlying RRD file will be closed.
* count is decremented by one. If usage count drops to zero, the underlying RRD will be closed.
*
* @param rrdDb RrdDb reference to be returned to the pool
* @throws java.io.IOException Thrown in case of I/O error
* @deprecated a db remember if it was open directly or from the pool, no need to manage it manually any more
* @throws java.lang.IllegalStateException if the thread was interrupted
* @deprecated A RrdDb remember if it was open directly or from a pool, no need to manage it manually any more
*/
@Deprecated
public void release(RrdDb rrdDb) throws IOException {
@@ -291,8 +296,7 @@ public class RrdDbPool {
if (rrdDb == null) {
return;
}
URI dburi = rrdDb.getUri();
URI dburi = rrdDb.getCanonicalUri();
RrdEntry ref = null;
try {
ref = getEntry(dburi, false);
@@ -326,20 +330,19 @@ public class RrdDbPool {
}
/**
* <p>Requests a RrdDb reference for the given RRD file path.</p>
* <p>Requests a RrdDb reference for the given RRD path.</p>
* <ul>
* <li>If the file is already open, previously returned RrdDb reference will be returned. Its usage count
* <li>If the RRD is already open, previously returned RrdDb reference will be returned. Its usage count
* will be incremented by one.
* <li>If the file is not already open and the number of already open RRD files is less than
* {@link #INITIAL_CAPACITY}, the file will be open and a new RrdDb reference will be returned.
* If the file is not already open and the number of already open RRD files is equal to
* {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
* <li>If the RRD is not already open and the number of already open RRD is less than
* {@link #getCapacity()}, it will be opened and a new RrdDb reference will be returned.
* If the RRD is not already open and the number of already open RRD is equal to
* {@link #getCapacity()}, the method blocks until some RRD are closed.
* </ul>
* <p>The path is transformed internally to URI using the default factory, that is the reference that will
* be used elsewhere.</p>
* <p>The path is transformed to an URI using the default factory defined at the creation of the pool.</p>
*
* @param path Path to existing RRD file
* @return reference for the give RRD file
* @param path Path to existing RRD.
* @return reference for the given RRD.
* @throws java.io.IOException Thrown in case of I/O error
*/
public RrdDb requestRrdDb(String path) throws IOException {
@@ -347,23 +350,25 @@ public class RrdDbPool {
}
/**
* <p>Requests a RrdDb reference for the given RRD file path.</p>
* <p>Requests a RrdDb reference for the given RRD URI.</p>
* <ul>
* <li>If the file is already open, previously returned RrdDb reference will be returned. Its usage count
* <li>If the RRD is already open, previously returned RrdDb reference will be returned. Its usage count
* will be incremented by one.
* <li>If the file is not already open and the number of already open RRD files is less than
* {@link #INITIAL_CAPACITY}, the file will be open and a new RrdDb reference will be returned.
* If the file is not already open and the number of already open RRD files is equal to
* {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
* <li>If the RRD is not already open and the number of already open RRD is less than
* {@link #getCapacity()}, it will be opened and a new RrdDb reference will be returned.
* If the RRD is not already open and the number of already open RRD is equal to
* {@link #getCapacity()}, the method blocks until some RRD are closed.
* </ul>
* <p>
* 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);
}
/**
* <p>Requests a RrdDb reference for the given RRD file definition object.</p>
* <p>Requests a RrdDb reference for the given RRD definition object.</p>
* <ul>
* <li>If the file with the path specified in the RrdDef object is already open,
* <li>If the RRD with the path specified in the RrdDef object is already open,
* the method blocks until the file is closed.
* <li>If the file is not already open and the number of already open RRD files is less than
* {@link #INITIAL_CAPACITY}, a new RRD file will be created and a its RrdDb reference will be returned.
* If the file is not already open and the number of already open RRD files is equal to
* {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
* <li>If the RRD is not already open and the number of already open RRD is less than
* {@link #getCapacity()}, a new RRD will be created and it's RrdDb reference will be returned.
* If the RRD is not already open and the number of already open RRD is equal to
* {@link #getCapacity()}, the method blocks until some RrdDb references are closed.
* </ul>
* <p>
* 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()));
}
/**
* <p>Requests a RrdDb reference for the given path. The file will be created from
* <p>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).</p>
* <ul>
* <li>If the file with the path specified is already open,
* <li>If the RRD with the path specified is already open,
* the method blocks until the file is closed.
* <li>If the file is not already open and the number of already open RRD files is less than
* {@link #INITIAL_CAPACITY}, a new RRD file will be created and a its RrdDb reference will be returned.
* If the file is not already open and the number of already open RRD files is equal to
* {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
* <li>If the RRD is not already open and the number of already open RRD is less than
* {@link #getCapacity()}, a new RRD will be created and it's RrdDb reference will be returned.
* If the RRD is not already open and the number of already open RRD is equal to
* {@link #getCapacity()}, the method blocks until some RrdDb references are closed.
* </ul>
* <p>The path is transformed internally to an URI using the default factory of the pool.</p>
* <p>The path is transformed to an URI using the default factory of the pool.</p>
*
* @param path Path to RRD file which should be created
* @param sourcePath Path to external data which is to be converted to Rrd4j's native RRD file format
* @return Reference to the newly created RRD file
* @param path Path to the RRD that should be created.
* @param sourcePath Path to external data which is to be converted to Rrd4j's native RRD file format.
* @return Reference to the newly created RRD.
* @throws java.io.IOException Thrown in case of I/O error
* @throws java.lang.IllegalStateException if the thread was interrupted
*/
public RrdDb requestRrdDb(String path, String sourcePath)
throws IOException {
@@ -516,35 +526,39 @@ public class RrdDbPool {
}
/**
* <p>Requests a RrdDb reference for the given path. The file will be created from
* <p>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).</p>
* <ul>
* <li>If the file with the path specified is already open,
* <li>If the RRD with the URI specified is already open,
* the method blocks until the file is closed.
* <li>If the file is not already open and the number of already open RRD files is less than
* {@link #INITIAL_CAPACITY}, a new RRD file will be created and a its RrdDb reference will be returned.
* If the file is not already open and the number of already open RRD files is equal to
* {@link #INITIAL_CAPACITY}, the method blocks until some RRD file is closed.
* <li>If the RRD is not already open and the number of already open RRD is less than
* {@link #getCapacity()}, a new RRD will be created and it's RrdDb reference will be returned.
* If the RRD is not already open and the number of already open RRD is equal to
* {@link #getCapacity()}, the method blocks until some RrdDb references are closed.
* </ul>
* <p>The path is transformed internally to URI using the default factory, that is the reference that will
* be used elsewhere.</p>
* 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 to choose the factory.
*
* @param uri Path to RRD file which should be created
* @param uri URI to the RRD that should be created
* @param sourcePath Path to external data which is to be converted to Rrd4j's native RRD file format
* @return Reference to the newly created RRD file
* @return Reference to the newly created RRD
* @throws java.io.IOException Thrown in case of I/O error
* @throws java.lang.IllegalStateException if the thread was interrupted
*/
public RrdDb requestRrdDb(URI uri, String sourcePath)
throws IOException {
return requestRrdDb(RrdDb.getBuilder().setExternalPath(sourcePath), uri, RrdBackendFactory.findFactory(uri));
return requestRrdDb(RrdDb.getBuilder().setExternalPath(sourcePath), uri, checkFactory(uri));
}
/**
* Sets the default factory to use when obtaining rrdDb from simple path and not URI.
* Sets the default factory to use when obtaining RrdDb reference from simple path and not URI.
*
* @param defaultFactory The factory to used.
* @throws IllegalStateException if done will the pool is not empty or the thread was interrupted.
* @param defaultFactory The factory to use.
* @throws IllegalStateException if called while the pool is not empty or the thread was interrupted
* @throws java.lang.IllegalStateException if the thread was interrupted
* @deprecated the pool is no longer a singleton, create a new pool instead of changing it.
*/
@Deprecated
public void setDefaultFactory(RrdBackendFactory defaultFactory) {
try {
usageWLock.lockInterruptibly();
@@ -563,10 +577,10 @@ public class RrdDbPool {
}
/**
* Sets the maximum number of simultaneously open RRD files.
* Sets the maximum number of simultaneously open RRD.
*
* @param newCapacity Maximum number of simultaneously open RRD files.
* @throws IllegalStateException if done will the pool is not empty or the thread was interrupted.
* @param newCapacity Maximum number of simultaneously open RRD.
* @throws IllegalStateException if called while the pool is not empty or the thread was interrupted.
*/
public void setCapacity(int newCapacity) {
try {
@@ -587,9 +601,10 @@ public class RrdDbPool {
}
/**
* Returns the maximum number of simultaneously open RRD files.
* Returns the maximum number of simultaneously open RRD.
*
* @return maximum number of simultaneously open RRD files
* @return maximum number of simultaneously open RRD
* @throws java.lang.IllegalStateException if the thread was interrupted
*/
public int getCapacity() {
try {
@@ -609,42 +624,76 @@ public class RrdDbPool {
* Returns the number of usage for a RRD.
*
* @param rrdDb RrdDb reference for which informations is needed.
* @return the number of request for this rrd
* @throws java.io.IOException if any.
* @return the number of request for this RRD.
* @throws java.io.IOException if any
* @throws java.lang.IllegalStateException if the thread was interrupted
*/
public int getOpenCount(RrdDb rrdDb) throws IOException {
return getOpenCount(rrdDb.getUri());
return getCanonicalUriUsage(rrdDb.getCanonicalUri());
}
/**
* Returns the number of usage for a RRD.
* <p>The path is transformed to an URI using the default factory.</p>
*
* @param path RRD's path for which informations is needed.
* @return the number of request for this file
* @throws java.io.IOException if any.
* @return the number of request for this RRD.
* @throws java.io.IOException if any
* @throws java.lang.IllegalStateException if the thread was interrupted
*/
public int getOpenCount(String path) throws IOException {
return getOpenCount(defaultFactory.getUri(path));
return getCanonicalUriUsage(defaultFactory.getCanonicalUri(defaultFactory.getUri(path)));
}
/**
* Returns the number of usage for a RRD.
*
* @param uri RRD's uri for which informations is needed.
* @return the number of request for this file
* @throws java.io.IOException if any.
* @param uri RRD's URI for which informations is needed.
* @return the number of request for this RRD.
* @throws java.io.IOException if any
* @throws java.lang.IllegalStateException if the thread was interrupted
*/
public int getOpenCount(URI uri) throws IOException {
return getCanonicalUriUsage(checkFactory(uri).getCanonicalUri(uri));
}
private int getCanonicalUriUsage(URI uri) {
RrdEntry ref = null;
try {
ref = getEntry(uri, false);
return Optional.ofNullable(ref).map(e -> e.count).orElse(0);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException("getOpenCount interrupted", e);
throw new IllegalStateException("getOpenCount interrupted", e);
} finally {
passNext(ACTION.SWAP, ref);
}
}
/**
* Wait until the pool is empty and return a lock that prevent any additions of new RrdDb references until it's released.
*
* @since 3.7
*
* @param timeout the time to wait for the write lock
* @param unit the time unit of the timeout argument
* @return a lock to release when operations on this pool are finished.
* @throws InterruptedException if interrupted whole waiting for the lock
*/
public Lock lockEmpty(long timeout, TimeUnit unit) throws InterruptedException {
usageWLock.tryLock(timeout, unit);
try {
usage.acquire(maxCapacity);
} catch (InterruptedException e) {
usageWLock.unlock();
Thread.currentThread().interrupt();
throw e;
}
return usageWLock;
}
private RrdBackendFactory checkFactory(URI uri) {
return defaultFactory.canStore(uri) ? defaultFactory : RrdBackendFactory.findFactory(uri);
}
}

View File

@@ -2,6 +2,8 @@ package org.rrd4j.core;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
/**
* Backend to be used to store all RRD bytes in memory.
@@ -9,14 +11,17 @@ import java.nio.ByteBuffer;
*/
public class RrdMemoryBackend extends ByteBufferBackend {
private ByteBuffer dbb = null;
private final AtomicReference<ByteBuffer> refbb;
/**
* <p>Constructor for RrdMemoryBackend.</p>
*
* @param path a {@link java.lang.String} object.
* @param refbb
*/
protected RrdMemoryBackend(String path) {
protected RrdMemoryBackend(String path, AtomicReference<ByteBuffer> refbb) {
super(path);
this.refbb = refbb;
Optional.ofNullable(refbb).map(r -> r.get()).ifPresent(this::setByteBuffer);
}
@Override
@@ -24,13 +29,13 @@ public class RrdMemoryBackend extends ByteBufferBackend {
if (length < 0 || length > Integer.MAX_VALUE) {
throw new IllegalArgumentException("Illegal length: " + length);
}
dbb = ByteBuffer.allocate((int) length);
setByteBuffer(dbb);
refbb.set(ByteBuffer.allocate((int) length));
setByteBuffer(refbb.get());
}
@Override
public long getLength() throws IOException {
return dbb.capacity();
return Optional.ofNullable(refbb.get()).map(ByteBuffer::capacity).orElse(0);
}
/**

View File

@@ -2,8 +2,10 @@ package org.rrd4j.core;
import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
/**
* Factory class which creates actual {@link org.rrd4j.core.RrdMemoryBackend} objects. Rrd4j's support
@@ -19,7 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
@RrdBackendAnnotation(name="MEMORY", shouldValidateHeader=false)
public class RrdMemoryBackendFactory extends RrdBackendFactory {
protected final Map<String, RrdMemoryBackend> backends = new ConcurrentHashMap<>();
protected final Map<String, AtomicReference<ByteBuffer>> backends = new ConcurrentHashMap<>();
/**
* {@inheritDoc}
@@ -27,15 +29,8 @@ public class RrdMemoryBackendFactory extends RrdBackendFactory {
* Creates RrdMemoryBackend object.
*/
protected RrdBackend open(String id, boolean readOnly) throws IOException {
RrdMemoryBackend backend;
if (backends.containsKey(id)) {
backend = backends.get(id);
}
else {
backend = new RrdMemoryBackend(id);
backends.put(id, backend);
}
return backend;
AtomicReference<ByteBuffer> refbb = backends.computeIfAbsent(id, i -> new AtomicReference<ByteBuffer>());
return new RrdMemoryBackend(id, refbb);
}
@Override
@@ -47,6 +42,7 @@ public class RrdMemoryBackendFactory extends RrdBackendFactory {
* {@inheritDoc}
*
* Method to determine if a memory storage with the given ID already exists.
*
*/
protected boolean exists(String id) {
return backends.containsKey(id);

View File

@@ -86,7 +86,7 @@ public class RrdNioBackendFactory extends RrdFileBackendFactory {
* Creates a new RrdNioBackendFactory with default settings.
*/
public RrdNioBackendFactory() {
this(RrdNioBackendFactory.defaultSyncPeriod, DefaultSyncThreadPool.INSTANCE);
this(RrdNioBackendFactory.defaultSyncPeriod, RrdNioBackendFactory.defaultSyncPeriod > 0 ? DefaultSyncThreadPool.INSTANCE : null);
}
/**

View File

@@ -4,6 +4,9 @@ import java.io.IOException;
/**
* Factory class which creates actual {@link org.rrd4j.core.RrdSafeFileBackend} objects.
* <p>
* 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)

View File

@@ -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 {
}
}

View File

@@ -202,7 +202,7 @@ public class XmlWriter implements AutoCloseable {
}
private static String escape(String s) {
return s.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
return s.replace("<", "&lt;").replace(">", "&gt;");
}
@Override

View File

@@ -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 <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a>
* @version $Revision: 1.1 $
*/
@SuppressWarnings("deprecation")
public class DataChunk {
private static final String NEWLINE = System.getProperty("line.separator");

View File

@@ -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 */

View File

@@ -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 ***/
};

View File

@@ -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()
};
}
}

View File

@@ -13,6 +13,7 @@ import java.util.Date;
* <b>WARNING</b>: 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;

View File

@@ -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;
/**
* <p>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());
* </pre>
*/
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 <code>DEFAULT_PERCENTILE=95.0</code> */
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 <code>false</code>
* (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.</p>
*
* The default number of pixels is defined by constant {@link #DEFAULT_PIXEL_COUNT}
* and can be changed with a {@link #setPixelCount(int)} method.
*
* @param pixelCount The number of pixels. If you process RRD data in order to display it on the graph,
* this should be the width of your graph.
*/
@@ -183,30 +196,22 @@ public class DataProcessor {
}
/**
* <p>Roughly corresponds to the --step option in RRDTool's graph/xport commands. Here is an explanation borrowed
* from RRDTool:</p>
* <p><i>"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></p>
* <p>I think this option is not that useful, but it's here just for compatibility.</p>
* @param step Time step at which data should be fetched from RRD files. If this method is not used,
* the step will be equal to the smallest RRD step of all processed RRD files. If no RRD file is processed,
* the step will be roughly equal to the with of one graph pixel (in seconds).
* Once data are fetched, the step value will be used to generate values. If not defined, or set to 0, a optimal
* step will be calculated.
* @param step Default to 0.
*/
@Override
public void setStep(long step) {
this.step = step;
}
/**
* Returns the time step used for data processing. Initially, this method returns zero.
* Once {@link #processData()} is finished, the method will return the real value used for
* all internal computations. Roughly corresponds to the --step option in RRDTool's graph/xport commands.
* Once {@link #processData()} is finished, the method will return the time stamp interval.
*
* @return Step used for data processing.
*/
@Override
public long getStep() {
return step;
}
@@ -236,10 +241,12 @@ public class DataProcessor {
this.fetchRequestResolution = fetchRequestResolution;
}
@Override
public TimeZone getTimeZone() {
return tz;
}
@Override
public void setTimeZone(TimeZone tz) {
this.tz = tz;
}
@@ -251,6 +258,7 @@ public class DataProcessor {
* value will be calculated from the last update times of processed RRD files.
*
* @return Ending timestamp in seconds
* @deprecated Uses {@link #getEndTime()} instead.
*/
public long getEndingTimestamp() {
return tEnd;
@@ -263,7 +271,7 @@ public class DataProcessor {
*/
public long[] getTimestamps() {
if (timestamps == null) {
throw new IllegalArgumentException("Timestamps not calculated yet");
throw new IllegalStateException("Timestamps not calculated yet");
}
else {
return timestamps;
@@ -465,8 +473,24 @@ public class DataProcessor {
*
* @param name source name.
* @param plottable class that extends Plottable class and is suited for graphing.
* @deprecated Uses {@link #datasource(String, IPlottable)} instead
*/
@Deprecated
public void addDatasource(String name, Plottable plottable) {
datasource(name, plottable);
}
/**
* Adds a custom, {@link org.rrd4j.data.Plottable plottable} datasource (<b>PDEF</b>).
* The datapoints should be made available by a class extending
* {@link org.rrd4j.data.Plottable Plottable} class.
*
* @param name source name.
* @param plottable class that extends Plottable class and is suited for graphing.
* @since 3.7
*/
@Override
public void datasource(String name, IPlottable plottable) {
PDef pDef = new PDef(name, plottable);
sources.put(name, pDef);
}
@@ -492,8 +516,38 @@ public class DataProcessor {
* @param name source name.
* @param rpnExpression RPN expression containing comma delimited simple and complex
* source names, RPN constants, functions and operators.
* @deprecated Uses {@link #datasource(String, String)} instead
*/
@Deprecated
public void addDatasource(String name, String rpnExpression) {
datasource(name, rpnExpression);
}
/**
* <p>Adds complex source (<b>CDEF</b>).
* Complex sources are evaluated using the supplied <code>RPN</code> expression.</p>
* Complex source <code>name</code> can be used:
* <ul>
* <li>To specify sources for line, area and stack plots.</li>
* <li>To define other complex sources.</li>
* </ul>
*
* The supported RPN functions, operators and constants are detailed at
* <a href="https://github.com/rrd4j/rrd4j/wiki/RPNFuncs" target="man">RRD4J's wiki</a>.
* <p>
* Rrd4j does not force you to specify at least one simple source name as RRDTool.
* <p>
* For more details on RPN see RRDTool's
* <a href="http://oss.oetiker.ch/rrdtool/doc/rrdgraph_rpn.en.html" target="man">
* rrdgraph man page</a>.
*
* @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);
}
/**
* <p>Adds simple datasource (<b>DEF</b>). Simple source <code>name</code>
* can be used:</p>
* <ul>
* <li>To specify sources for line, area and stack plots.</li>
* <li>To define complex sources
* </ul>
*
* @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);
}
/**
* <p>Adds simple datasource (<b>DEF</b>). Simple source <code>name</code>
* can be used:</p>
* <ul>
* <li>To specify sources for line, area and stack plots.</li>
* <li>To define complex sources
* </ul>
*
* @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);
}
/**
* <p>Adds simple source (<b>DEF</b>). Source <code>name</code> can be used:</p>
* <ul>
* <li>To specify sources for line, area and stack plots.</li>
* <li>To define complex sources
* </ul>
*
* @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);
}
/**
* <p>Adds simple source (<b>DEF</b>). Source <code>name</code> can be used:</p>
* <ul>
* <li>To specify sources for line, area and stack plots.</li>
* <li>To define complex sources
* </ul>
*
* @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<Def> defList = new ArrayList<Def>();
for (Source source : sources.values()) {
if (source instanceof Def) {
defList.add((Def) source);
}
}
defSources = defList.toArray(new Def[defList.size()]);
defSources = sources.values().stream().filter(s -> s instanceof Def).toArray(Def[]::new);
}
private void fetchRrdData() throws IOException {
long tEndFixed = (tEnd == 0) ? Util.getTime() : tEnd;
for (int i = 0; i < defSources.length; i++) {
if (!defSources[i].isLoaded()) {
// not fetched yet
Set<String> dsNames = new HashSet<String>();
dsNames.add(defSources[i].getDsName());
// look for all other datasources with the same path and the same consolidation function
for (int j = i + 1; j < defSources.length; j++) {
if (defSources[i].isCompatibleWith(defSources[j])) {
dsNames.add(defSources[j].getDsName());
RrdDb[] batchRrd = new RrdDb[defSources.length];
Map<URI, RrdDb> openRrd = new HashMap<>(defSources.length);
Set<RrdDb> newDb = new HashSet<>(defSources.length);
try {
// Storing of the RrdDb in a array to batch open/close, useful if a pool
// is used.
int d = 0;
for (Def def: defSources) {
URI curi = def.getCanonicalUri();
batchRrd[d++] = openRrd.computeIfAbsent(curi, uri -> {
if (! def.isLoaded()) {
RrdBackendFactory backend = def.getBackend();
try {
RrdDb rrdDb = RrdDb.getBuilder().setPath(curi).setBackendFactory(backend).readOnly().setPool(pool).setUsePool(poolUsed).build();
newDb.add(rrdDb);
return rrdDb;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
} else {
return def.getRrdDb();
}
});
}
for (int i = 0; i < defSources.length; i++) {
if (batchRrd[i] == null) {
// The rrdDb failed to open, skip it
continue;
}
// now we have everything
try (RrdDb rrd = getRrd(defSources[i])){
lastRrdArchiveUpdateTime = Math.max(lastRrdArchiveUpdateTime, rrd.getLastArchiveUpdateTime());
FetchRequest req = rrd.createFetchRequest(defSources[i].getConsolFun(),
tStart, tEndFixed, fetchRequestResolution);
if (!defSources[i].isLoaded()) {
// not fetched yet
Set<String> dsNames = new HashSet<String>();
dsNames.add(defSources[i].getDsName());
// look for all other datasources with the same path and the same consolidation function
for (int j = i + 1; j < defSources.length; j++) {
if (defSources[i].isCompatibleWith(defSources[j])) {
dsNames.add(defSources[j].getDsName());
}
}
// now we have everything
lastRrdArchiveUpdateTime = Math.max(
lastRrdArchiveUpdateTime,
batchRrd[i].getLastArchiveUpdateTime());
FetchRequest req = batchRrd[i].createFetchRequest(
defSources[i].getConsolFun(), tStart, tEndFixed,
fetchRequestResolution);
req.setFilter(dsNames);
FetchData data = req.fetchData();
assert data != null;
defSources[i].setFetchData(data);
for (int j = i + 1; j < defSources.length; j++) {
if (defSources[i].isCompatibleWith(defSources[j])) {
@@ -809,6 +1032,15 @@ public class DataProcessor {
}
}
}
} catch (UncheckedIOException ex){
throw ex.getCause();
} finally {
newDb.forEach(t -> {
try {
t.close();
} catch (IOException e) {
}
});
}
}
@@ -831,7 +1063,8 @@ public class DataProcessor {
private void chooseOptimalStep() {
long newStep = Long.MAX_VALUE;
for (Def defSource : defSources) {
long fetchStep = defSource.getFetchStep(), tryStep = fetchStep;
long fetchStep = defSource.getFetchStep();
long tryStep = fetchStep;
if (step > 0) {
tryStep = Math.min(newStep, (((step - 1) / fetchStep) + 1) * fetchStep);
}
@@ -841,9 +1074,13 @@ public class DataProcessor {
// step resolved from a RRD file
step = newStep;
}
else {
// choose step based on the number of pixels (useful for plottable datasources)
else if (pixelCount != 0) {
// Only calculated sources. But requested in a graph. So use the graph
// width as an hint
step = Math.max((tEnd - tStart) / pixelCount, 1);
} else if (step <= 0) {
// If step was not given, just 1
step = 1;
}
}
@@ -884,12 +1121,6 @@ public class DataProcessor {
}
}
private RrdDb getRrd(Def def) throws IOException {
String path = def.getPath();
RrdBackendFactory backend = def.getBackend();
return RrdDb.getBuilder().setPath(path).setBackendFactory(backend).readOnly().setUsePool(poolUsed).setPool(pool).build();
}
private static String format(String s, int length) {
StringBuilder b = new StringBuilder(s);
for (int i = 0; i < length - s.length(); i++) {
@@ -898,4 +1129,46 @@ public class DataProcessor {
return b.toString();
}
/**
*
* @since 3.7
*/
@Override
public void setEndTime(long time) {
this.tEnd = time;
}
/**
*
* @since 3.7
*/
@Override
public long getEndTime() {
return tEnd;
}
@Override
public void setStartTime(long time) {
this.tStart = time;
}
/**
*
* @since 3.7
*/
@Override
public long getStartTime() {
return tStart;
}
/**
*
* @since 3.7
*/
@Override
public void setTimeSpan(long startTime, long endTime) {
this.tStart = startTime;
this.tEnd = endTime;
}
}

View File

@@ -1,14 +1,15 @@
package org.rrd4j.data;
import java.io.IOException;
import java.net.URI;
import org.rrd4j.ConsolFun;
import org.rrd4j.core.FetchData;
import org.rrd4j.core.RrdBackendFactory;
import org.rrd4j.core.Util;
import java.io.IOException;
import org.rrd4j.core.RrdDb;
class Def extends Source {
private final String path;
private final URI rrdUri;
private final String dsName;
private final RrdBackendFactory backend;
private final ConsolFun consolFun;
@@ -20,34 +21,26 @@ class Def extends Source {
Def(String name, String dsName, FetchData fetchData) {
this(name,
fetchData.getRequest().getParentDb().getPath(),
fetchData.getRequest().getParentDb().getCanonicalUri(),
dsName, fetchData.getRequest().getConsolFun(),
fetchData.getRequest().getParentDb().getRrdBackend().getFactory()
);
this.fetchData = fetchData;
}
Def(String name, String path, String dsName, ConsolFun consolFunc) {
this(name, path, dsName, consolFunc, null);
}
Def(String name, String path, String dsName, ConsolFun consolFunc, RrdBackendFactory backend) {
Def(String name, URI rrdUri, String dsName, ConsolFun consolFunc, RrdBackendFactory backend) {
super(name);
this.path = path;
this.rrdUri = backend.getCanonicalUri(rrdUri);
this.dsName = dsName;
this.consolFun = consolFunc;
this.backend = backend;
}
String getPath() {
return path;
URI getCanonicalUri() throws IOException {
return rrdUri;
}
String getCanonicalPath() throws IOException {
return Util.getCanonicalPath(path);
}
String getDsName() {
String getDsName() {
return dsName;
}
@@ -60,12 +53,16 @@ class Def extends Source {
}
boolean isCompatibleWith(Def def) throws IOException {
return getCanonicalPath().equals(def.getCanonicalPath()) &&
return getCanonicalUri().equals(def.getCanonicalUri()) &&
getConsolFun() == def.consolFun &&
((backend == null && def.backend == null) ||
(backend != null && def.backend != null && backend.equals(def.backend)));
}
RrdDb getRrdDb() {
return fetchData.getRequest().getParentDb();
}
void setFetchData(FetchData fetchData) {
this.fetchData = fetchData;
}

View File

@@ -0,0 +1,20 @@
package org.rrd4j.data;
/**
* Interface to be used for custom datasources.
*
* <p>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.</p>
* @since 3.7
*/
@FunctionalInterface
public interface IPlottable {
/**
* Retrieves datapoint value based on a given timestamp.
* Use this method if you only have one series of data in this class.
*
* @param timestamp Timestamp in seconds for the datapoint.
* @return Double value of the datapoint.
*/
public double getValue(long timestamp);
}

View File

@@ -15,6 +15,7 @@ import java.util.Date;
* Interpolation method handles NaN datasource
* values gracefully.</p>
*/
@SuppressWarnings("deprecation")
public class LinearInterpolator extends Plottable {
/**

View File

@@ -64,4 +64,3 @@ class Normalizer {
return values;
}
}

View File

@@ -1,11 +1,11 @@
package org.rrd4j.data;
class PDef extends Source implements NonRrdSource {
private final Plottable plottable;
private final IPlottable plottable;
PDef(String name, Plottable plottable) {
PDef(String name, IPlottable plottable2) {
super(name);
this.plottable = plottable;
this.plottable = plottable2;
}
/** {@inheritDoc} */

View File

@@ -5,8 +5,10 @@ package org.rrd4j.data;
*
* <p>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.</p>
* @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);
}

View File

@@ -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<PercentElem>, Serializable {
@Override
public final int compare(PercentElem arg0, PercentElem arg1) {
if(Double.isNaN(arg0.value) && Double.isNaN(arg1.value))
if (Double.isNaN(arg0.value) && Double.isNaN(arg1.value))
return Long.signum(arg0.timestamp - arg1.timestamp);
else if(Double.isNaN(arg0.value))
else if (Double.isNaN(arg0.value))
return -1;
else if (Double.isNaN(arg1.value))
return +1;
@@ -344,12 +347,12 @@ public abstract class Variable {
protected Value fill(long[] timestamps, double[] values, long start, long end) {
// valuesSet will be a set with NaN packet at the start
SortedSet<PercentElem> valuesSet = new TreeSet<PercentElem>(new ComparPercentElemen());
for(int i = 0 ; i < values.length ; i++) {
for (int i = 0 ; i < values.length ; i++) {
valuesSet.add(new PercentElem(i, timestamps[i], values[i]));
}
//If not with nan, just drop all nan (inferior to min value)
if( ! withNaN) {
if (! withNaN) {
valuesSet = valuesSet.tailSet(new PercentElem(0, 0, Double.NEGATIVE_INFINITY ));
}
@@ -435,7 +438,7 @@ public abstract class Variable {
double lslslope;
double lslint;
for(int i = 0; i < values.length; i++) {
for (int i = 0; i < values.length; i++) {
double value = values[i];
if (!Double.isNaN(value)) {
@@ -449,7 +452,7 @@ public abstract class Variable {
lslstep++;
}
double divisor = (SUMx * SUMx - cnt * SUMxx);
if(cnt > 0 && divisor != 0) {
if (cnt > 0 && divisor != 0) {
/* Bestfit line by linear least squares method */
lslslope = (SUMx * SUMy - cnt * SUMxy) / divisor;
lslint = (SUMy - lslslope * SUMx) / cnt;
@@ -478,7 +481,7 @@ public abstract class Variable {
double SUMyy = 0.0;
double lslcorrel;
for(int i = 0; i < values.length; i++) {
for (int i = 0; i < values.length; i++) {
double value = values[i];
if (!Double.isNaN(value)) {
@@ -492,7 +495,7 @@ public abstract class Variable {
}
lslstep++;
}
if(cnt > 0) {
if (cnt > 0) {
/* Bestfit line by linear least squares method */
lslcorrel =
(SUMxy - (SUMx * SUMy) / cnt) /

View File

@@ -11,6 +11,6 @@ class CDef extends Source {
}
void requestData(DataProcessor dproc) {
dproc.addDatasource(name, rpnExpression);
dproc.datasource(name, rpnExpression);
}
}

View File

@@ -1,42 +1,29 @@
package org.rrd4j.graph;
import org.rrd4j.data.DataProcessor;
import java.net.URI;
import org.rrd4j.ConsolFun;
import org.rrd4j.core.RrdBackendFactory;
class Def extends Source {
private final String rrdPath, dsName;
private final URI rrdUri;
private final String dsName;
private final RrdBackendFactory backend;
private final ConsolFun consolFun;
Def(String name, String rrdPath, String dsName, ConsolFun consolFun) {
this(name, rrdPath, dsName, consolFun, (RrdBackendFactory)null);
}
@Deprecated
Def(String name, String rrdPath, String dsName, ConsolFun consolFun, String backend) {
Def(String name, URI rrdUri, String dsName, ConsolFun consolFun, RrdBackendFactory backend) {
super(name);
this.rrdPath = rrdPath;
this.dsName = dsName;
this.consolFun = consolFun;
this.backend = RrdBackendFactory.getFactory(backend);
}
Def(String name, String rrdPath, String dsName, ConsolFun consolFun, RrdBackendFactory backend) {
super(name);
this.rrdPath = rrdPath;
this.rrdUri = rrdUri;
this.dsName = dsName;
this.consolFun = consolFun;
this.backend = backend;
}
void requestData(DataProcessor dproc) {
if (backend == null) {
dproc.addDatasource(name, rrdPath, dsName, consolFun);
}
else {
dproc.addDatasource(name, rrdPath, dsName, consolFun, backend);
}
dproc.datasource(name, rrdUri, dsName, consolFun, backend);
}
}

View File

@@ -1,17 +1,17 @@
package org.rrd4j.graph;
import org.rrd4j.data.DataProcessor;
import org.rrd4j.data.Plottable;
import org.rrd4j.data.IPlottable;
class PDef extends Source {
private Plottable plottable;
private IPlottable plottable;
PDef(String name, Plottable plottable) {
PDef(String name, IPlottable plottable) {
super(name);
this.plottable = plottable;
}
void requestData(DataProcessor dproc) {
dproc.addDatasource(name, plottable);
dproc.datasource(name, plottable);
}
}

View File

@@ -45,7 +45,7 @@ class PrintText extends CommentText {
resolvedText = String.format(l, resolvedText, c);
} catch (Exception e) {
throw new RuntimeException("can't format '" + resolvedText + "'", e);
}
}
}
else {
resolvedText = "-";

View File

@@ -23,13 +23,18 @@ import org.rrd4j.graph.DownSampler.DataSet;
*/
public class RrdGraph implements RrdGraphConstants {
private static final double[] SENSIBLE_VALUES = {
1000.0, 900.0, 800.0, 750.0, 700.0, 600.0, 500.0, 400.0, 300.0, 250.0, 200.0, 125.0, 100.0,
90.0, 80.0, 75.0, 70.0, 60.0, 50.0, 40.0, 30.0, 25.0, 20.0, 10.0,
9.0, 8.0, 7.0, 6.0, 5.0, 4.0, 3.5, 3.0, 2.5, 2.0, 1.8, 1.5, 1.2, 1.0,
1000.0, 900.0, 800.0, 750.0, 700.0,
600.0, 500.0, 400.0, 300.0, 250.0,
200.0, 125.0, 100.0, 90.0, 80.0,
75.0, 70.0, 60.0, 50.0, 40.0, 30.0,
25.0, 20.0, 10.0, 9.0, 8.0,
7.0, 6.0, 5.0, 4.0, 3.5, 3.0,
2.5, 2.0, 1.8, 1.5, 1.2, 1.0,
0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1, 0.0, -1
};
private static final char[] SYMBOLS = {'a', 'f', 'p', 'n', 'µ', 'm', ' ', 'k', 'M', 'G', 'T', 'P', 'E'};
private static final int SYMBOLS_CENTER = 8;
private static final char[] SYMBOLS = {'y', 'z', 'a', 'f', 'p', 'n', 'µ', 'm', ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'};
final RrdGraphDef gdef;
final ImageParameters im;
@@ -122,13 +127,14 @@ public class RrdGraph implements RrdGraphConstants {
fetchData();
resolveTextElements();
if (gdef.shouldPlot() && !lazy) {
initializeLimits();
calculatePlotValues();
findMinMaxValues();
identifySiUnit();
expandValueRange();
removeOutOfRangeRules();
removeOutOfRangeSpans();
initializeLimits();
mapper = new Mapper(this);
placeLegends();
createImageWorker();
drawBackground();
@@ -436,8 +442,6 @@ public class RrdGraph implements RrdGraphConstants {
im.yorigin = PADDING_TOP + im.ysize;
}
mapper = new Mapper(this);
if (!gdef.onlyGraph && gdef.title != null) {
im.yorigin += getFontHeight(FONTTAG_TITLE) + PADDING_TITLE;
}
@@ -575,7 +579,6 @@ public class RrdGraph implements RrdGraphConstants {
im.unitsexponent = gdef.unitsExponent;
im.base = gdef.base;
if (!gdef.logarithmic) {
int symbcenter = 6;
double digits;
if (im.unitsexponent != Integer.MAX_VALUE) {
digits = Math.floor(im.unitsexponent / 3.0);
@@ -584,8 +587,8 @@ public class RrdGraph implements RrdGraphConstants {
digits = Math.floor(Math.log(Math.max(Math.abs(im.minval), Math.abs(im.maxval))) / Math.log(im.base));
}
im.magfact = Math.pow(im.base, digits);
if (((digits + symbcenter) < SYMBOLS.length) && ((digits + symbcenter) >= 0)) {
im.symbol = SYMBOLS[(int) digits + symbcenter];
if (((digits + SYMBOLS_CENTER) < SYMBOLS.length) && ((digits + SYMBOLS_CENTER) >= 0)) {
im.symbol = SYMBOLS[(int) digits + SYMBOLS_CENTER];
}
else {
im.symbol = '?';
@@ -655,7 +658,11 @@ public class RrdGraph implements RrdGraphConstants {
private void fetchData() throws IOException {
dproc = new DataProcessor(gdef.startTime, gdef.endTime);
dproc.setPoolUsed(gdef.poolUsed);
dproc.setPixelCount(im.xsize);
if (gdef.poolUsed) {
dproc.setPoolUsed(gdef.poolUsed);
dproc.setPool(gdef.getPool());
}
dproc.setTimeZone(gdef.tz);
if (gdef.step > 0) {
dproc.setStep(gdef.step);

View File

@@ -1,13 +1,39 @@
package org.rrd4j.graph;
import java.awt.*;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Stroke;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.net.URL;
import java.util.Calendar;
import java.util.Locale;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Function;
/**
* Class to represent various constants used for graphing. No methods are specified.
* <p>
* The fonts settings can be changed use some on the following properties, sorted by increased priority.
* <ol>
* <li><code>org.rrd4j.fonts.properties</code></li>
* <li><code>org.rrd4j.fonts.properties.url</code></li>
* <li><code>org.rrd4j.font.plain</code></li>
* <li><code>org.rrd4j.font.bold</code></li>
* <li><code>org.rrd4j.font.plain.url</code></li>
* <li><code>org.rrd4j.font.bold.url</code></li>
* </ol>
*
* If either <code>org.rrd4j.fonts.properties</code> or <code>org.rrd4j.fonts.properties.url</code> 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 (<code>org.rrd4j.fonts.url</code>, <code>org.rrd4j.font.plain.url</code> and
* <code>org.rrd4j.font.bold.url</code>) 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.
* <p>
* The default settings uses <code>org.rrd4j.fonts.properties</code> looking for the file <code>/rrd4jfonts.properties</code> 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 <code>/rrd4jfonts.properties</code>
*/
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<String, InputStream> fontStream = null;
String fontPath = fileProps.getProperty(type == Font.BOLD ? PROPERTYFONTBOLDURL : PROPERTYFONTPLAINURL);
if (fontPath!= null) {
fontStream = s -> {
try {
return new URL(s).openStream();
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
} else {
fontPath = fileProps.getProperty(type == Font.BOLD ? PROPERTYFONTBOLD : PROPERTYFONTPLAIN);
fontStream = RrdGraphConstants.class::getResourceAsStream;
}
try (InputStream fontstream = fontStream.apply(fontPath)) {
return Font.createFont(Font.TRUETYPE_FONT, fontstream).deriveFont((float)size);
} catch (FontFormatException | IOException e) {
throw new RuntimeException(e);
}

View File

@@ -7,7 +7,10 @@ import java.awt.Stroke;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.time.Instant;
import java.time.temporal.TemporalAmount;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
@@ -17,11 +20,13 @@ import java.util.TimeZone;
import javax.imageio.ImageIO;
import org.rrd4j.ConsolFun;
import org.rrd4j.core.DataHolder;
import org.rrd4j.core.FetchData;
import org.rrd4j.core.RrdBackendFactory;
import org.rrd4j.core.RrdDbPool;
import org.rrd4j.core.Util;
import org.rrd4j.data.DataProcessor;
import org.rrd4j.data.Plottable;
import org.rrd4j.data.IPlottable;
import org.rrd4j.data.Variable;
/**
@@ -52,7 +57,7 @@ import org.rrd4j.data.Variable;
* without forcing a newline, you can use the special tag \J at the end of
* the string to disable the auto justification.</p>
*/
public class RrdGraphDef implements RrdGraphConstants {
public class RrdGraphDef implements RrdGraphConstants, DataHolder {
/**
* <p>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;
}
}

View File

@@ -16,7 +16,7 @@ class TDef extends Source {
@Override
void requestData(DataProcessor dproc) {
dproc.addDatasource(name, dsName, fetchData);
dproc.datasource(name, dsName, fetchData);
}
}

View File

@@ -14,7 +14,7 @@ class VDef extends Source {
}
void requestData(DataProcessor dproc) {
dproc.addDatasource(name, defName, var);
dproc.datasource(name, defName, var);
}
}