forked from I2P_Developers/i2p.i2p
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:
@@ -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.
|
||||
|
||||
207
apps/jrobin/java/src/org/rrd4j/core/DataHolder.java
Normal file
207
apps/jrobin/java/src/org/rrd4j/core/DataHolder.java
Normal 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);
|
||||
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -202,7 +202,7 @@ public class XmlWriter implements AutoCloseable {
|
||||
}
|
||||
|
||||
private static String escape(String s) {
|
||||
return s.replaceAll("<", "<").replaceAll(">", ">");
|
||||
return s.replace("<", "<").replace(">", ">");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 ***/
|
||||
};
|
||||
|
||||
|
||||
@@ -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()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
20
apps/jrobin/java/src/org/rrd4j/data/IPlottable.java
Normal file
20
apps/jrobin/java/src/org/rrd4j/data/IPlottable.java
Normal 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);
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import java.util.Date;
|
||||
* Interpolation method handles NaN datasource
|
||||
* values gracefully.</p>
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public class LinearInterpolator extends Plottable {
|
||||
|
||||
/**
|
||||
|
||||
@@ -64,4 +64,3 @@ class Normalizer {
|
||||
return values;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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} */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) /
|
||||
|
||||
@@ -11,6 +11,6 @@ class CDef extends Source {
|
||||
}
|
||||
|
||||
void requestData(DataProcessor dproc) {
|
||||
dproc.addDatasource(name, rpnExpression);
|
||||
dproc.datasource(name, rpnExpression);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = "-";
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ class TDef extends Source {
|
||||
|
||||
@Override
|
||||
void requestData(DataProcessor dproc) {
|
||||
dproc.addDatasource(name, dsName, fetchData);
|
||||
dproc.datasource(name, dsName, fetchData);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ class VDef extends Source {
|
||||
}
|
||||
|
||||
void requestData(DataProcessor dproc) {
|
||||
dproc.addDatasource(name, defName, var);
|
||||
dproc.datasource(name, defName, var);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user