diff --git a/LICENSE.txt b/LICENSE.txt index 0f0e5f953494058954e3b7c350f5782f630877b0..67a4d76b4847aeeed4538dc4ecf4f7d9d60a137e 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -264,13 +264,12 @@ Applications: See licenses/LICENSE-Apache2.0.txt See licenses/LICENSE-ECLIPSE-1.0.html - JRobin 1.6.0-1 (jrobin.jar): + RRD4J 3.5 (jrobin.jar): Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. Copyright (c) 2011 The OpenNMS Group, Inc. + Copyright 2011 The RRD4J Authors. + See licenses/LICENSE-Apache2.0.txt See licenses/LICENSE-LGPLv2.1.txt - DeallocationHelper: - Copyright (c) 2006-2016 Julien Gouesse - See licenses/LICENSE-GPLv2.txt Ministreaming Lib (mstreaming.jar): By mihi. diff --git a/apps/jrobin/java/src/engine/misc/DeallocationHelper.java b/apps/jrobin/java/src/engine/misc/DeallocationHelper.java deleted file mode 100644 index 158b80b960a9fe4fc336ee1a10c718627052aa18..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/engine/misc/DeallocationHelper.java +++ /dev/null @@ -1,814 +0,0 @@ -/** - * Copyright (c) 2006-2016 Julien Gouesse This program is free software; you can - * redistribute it and/or modify it under the terms of the GNU General Public - * License as published by the Free Software Foundation; either version 2 of the - * License, or (at your option) any later version. This program is distributed - * in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received - * a copy of the GNU General Public License along with this program; if not, - * write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -package engine.misc; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.CharBuffer; -import java.nio.DoubleBuffer; -import java.nio.FloatBuffer; -import java.nio.IntBuffer; -import java.nio.LongBuffer; -import java.nio.ShortBuffer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import net.i2p.I2PAppContext; -import net.i2p.util.Log; - - -/** - * Helper to deallocate memory on the native heap allocated during the creation - * of a direct byte buffer. It supports numerous virtual machines including - * OpenJDK, Oracle/Sun Java, Android Dalvik Virtual Machine, Apache Harmony and - * GNU Classpath. This class uses the syntax of Java 1.7 but it can work - * correctly with Java 1.4 with a very few minor type changes when using the - * maps and the collections. It relies on lots of implementation details but - * it's robust enough to go on working (except when the implementors - * intentionally use a very general class to store the buffers) despite minor - * naming changes like those that occurred between Java 1.6 and Java 1.7. It - * supports Java 1.9 despite the move of the cleaner from the package sun.misc - * to jdk.internal.ref (in the module java.base). N.B: Releasing the native - * memory of a sliced direct NIO buffer, the one of a direct NIO buffer created - * with JNI or the one of any direct NIO buffer created by the virtual machine - * or by a framework not under your control doesn't prevent the calls to methods - * attempting to access such buffers. Those calls can throw an exception or - * crash the virtual machine depending on the implementations. - * - * @author Julien Gouesse - */ -public class DeallocationHelper { - - private final Log logger = I2PAppContext.getGlobalContext().logManager().getLog(DeallocationHelper.class); - - /** - * tool responsible for releasing the native memory of a deallocatable byte - * buffer - */ - public static abstract class Deallocator { - - protected final Log logger = I2PAppContext.getGlobalContext().logManager().getLog(DeallocationHelper.class); - - public Deallocator() { - super(); - } - - /** - * releases the native memory of a deallocatable byte buffer - * - * @param directByteBuffer - * deallocatable byte buffer - * - * @return <code>true</code> if the deallocation is successful, - * otherwise <code>false</code> - */ - public abstract boolean run(final ByteBuffer directByteBuffer); - } - - public static class OracleSunOpenJdkDeallocator extends Deallocator { - - private Method directByteBufferCleanerMethod; - - private Method cleanerCleanMethod; - - public OracleSunOpenJdkDeallocator() { - super(); - try { - final Class<?> directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); - directByteBufferCleanerMethod = directByteBufferClass.getDeclaredMethod("cleaner"); - /** - * The return type is sun.misc.Cleaner in Java <= 1.8, - * jdk.internal.ref.Cleaner in Java >= 1.9. Only the latter - * implements the Runnable interface. - */ - final Class<?> cleanerClass = directByteBufferCleanerMethod.getReturnType(); - if (Runnable.class.isAssignableFrom(cleanerClass)) { - cleanerCleanMethod = Runnable.class.getDeclaredMethod("run"); - } else { - cleanerCleanMethod = cleanerClass.getDeclaredMethod("clean"); - } - } catch (ClassNotFoundException | NoSuchMethodException e) { - logger.warn( - "The initialization of the deallocator for Oracle Java, Sun Java and OpenJDK has failed", e); - } - } - - @Override - public boolean run(final ByteBuffer directByteBuffer) { - boolean success = false; - if (directByteBufferCleanerMethod != null && cleanerCleanMethod != null) { - final boolean directByteBufferCleanerMethodWasAccessible = directByteBufferCleanerMethod.isAccessible(); - final boolean cleanerCleanMethodWasAccessible = cleanerCleanMethod.isAccessible(); - try { - // according to the Java documentation, by default, a reflected object is not accessible - directByteBufferCleanerMethod.setAccessible(true); - final Object cleaner = directByteBufferCleanerMethod.invoke(directByteBuffer); - if (cleaner != null) { - cleanerCleanMethod.setAccessible(true); - cleanerCleanMethod.invoke(cleaner); - success = true; - } - //} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - } catch (IllegalAccessException | RuntimeException | InvocationTargetException e) { - // Replaced with RuntimeException for OpenJDK 9b181 - // throws a java.lang.reflect.InaccessibleObjectException extends RuntimeException which is only in Java 9 - // WARNING: An illegal reflective access operation has occurred - // WARNING: Illegal reflective access by engine.misc.DeallocationHelper (file:/path/to/jrobin.jar) to field java.nio.DirectByteBuffer.att - // WARNING: Please consider reporting this to the maintainers of engine.misc.DeallocationHelper - // WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations - // WARNING: All illegal access operations will be denied in a future release - // Thread terminated unexpectedly: Shutdown task net.i2p.router.web.StatSummarizer$Shutdown - // java.lang.reflect.InaccessibleObjectException: Unable to make public void jdk.internal.ref.Cleaner.clean() accessible: module java.base does not "exports jdk.internal.ref" to unnamed module @381353a0 - // at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:337) - // at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:281) - // at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:198) - // at java.base/java.lang.reflect.Method.setAccessible(Method.java:192) - logger.warn("The deallocation of a direct NIO buffer has failed", e); - } finally { - directByteBufferCleanerMethod.setAccessible(directByteBufferCleanerMethodWasAccessible); - cleanerCleanMethod.setAccessible(cleanerCleanMethodWasAccessible); - } - } - return (success); - } - } - - public static class AndroidDeallocator extends Deallocator { - - private Method directByteBufferFreeMethod; - - public AndroidDeallocator() { - super(); - try { - final Class<?> directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); - directByteBufferFreeMethod = directByteBufferClass.getDeclaredMethod("free"); - } catch (ClassNotFoundException | NoSuchMethodException e) { - logger.warn("The initialization of the deallocator for Android has failed", e); - } - } - - @Override - public boolean run(final ByteBuffer directByteBuffer) { - boolean success = false; - if (directByteBufferFreeMethod != null) { - final boolean directByteBufferFreeMethodWasAccessible = directByteBufferFreeMethod.isAccessible(); - try { - directByteBufferFreeMethod.setAccessible(true); - directByteBufferFreeMethod.invoke(directByteBuffer); - success = true; - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - logger.warn("The deallocation of a direct NIO buffer has failed", e); - } finally { - directByteBufferFreeMethod.setAccessible(directByteBufferFreeMethodWasAccessible); - } - } - return (success); - } - } - - public static class GnuClasspathDeallocator extends Deallocator { - - private Method vmDirectByteBufferFreeMethod; - - private Field bufferAddressField; - - public GnuClasspathDeallocator() { - super(); - try { - final Class<?> vmDirectByteBufferClass = Class.forName("java.nio.VMDirectByteBuffer"); - final Class<?> gnuClasspathPointerClass = Class.forName("gnu.classpath.Pointer"); - vmDirectByteBufferFreeMethod = vmDirectByteBufferClass.getDeclaredMethod("free", - gnuClasspathPointerClass); - bufferAddressField = Buffer.class.getDeclaredField("address"); - } catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException e) { - logger.warn("The initialization of the deallocator for GNU Classpath has failed", e); - } - } - - @Override - public boolean run(final ByteBuffer directByteBuffer) { - boolean success = false; - if (vmDirectByteBufferFreeMethod != null && bufferAddressField != null) { - final boolean bufferAddressFieldWasAccessible = bufferAddressField.isAccessible(); - final boolean vmDirectByteBufferFreeMethodWasAccessible = vmDirectByteBufferFreeMethod.isAccessible(); - try { - bufferAddressField.setAccessible(true); - final Object address = bufferAddressField.get(directByteBuffer); - if (address != null) { - vmDirectByteBufferFreeMethod.setAccessible(true); - vmDirectByteBufferFreeMethod.invoke(null, address); - success = true; - } - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - logger.warn("The deallocation of a direct NIO buffer has failed", e); - } finally { - bufferAddressField.setAccessible(bufferAddressFieldWasAccessible); - vmDirectByteBufferFreeMethod.setAccessible(vmDirectByteBufferFreeMethodWasAccessible); - } - } - return (success); - } - } - - public static class ApacheHarmonyDeallocator extends Deallocator { - - private Method directByteBufferFreeMethod; - - public ApacheHarmonyDeallocator() { - super(); - try { - final Class<?> directByteBufferClass = Class.forName("java.nio.DirectByteBuffer"); - directByteBufferFreeMethod = directByteBufferClass.getDeclaredMethod("free"); - } catch (ClassNotFoundException | NoSuchMethodException e) { - logger.warn("The initialization of the deallocator for Apache Harmony has failed", e); - } - } - - @Override - public boolean run(final ByteBuffer directByteBuffer) { - boolean success = false; - if (directByteBufferFreeMethod != null) { - final boolean directByteBufferFreeMethodWasAccessible = directByteBufferFreeMethod.isAccessible(); - try { - directByteBufferFreeMethod.setAccessible(true); - directByteBufferFreeMethod.invoke(directByteBuffer); - success = true; - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - logger.warn("The deallocation of a direct NIO buffer has failed", e); - } finally { - directByteBufferFreeMethod.setAccessible(directByteBufferFreeMethodWasAccessible); - } - } - return (success); - } - } - - private Map<Class<?>, Field> attachmentOrByteBufferFieldMap; - - private Set<Class<?>> deallocatableBufferClassSet; - - private Deallocator deallocator; - - /** - * Default constructor - */ - public DeallocationHelper() { - this(false); - } - - /** - * Main constructor - * - * @param ignoreClassesAndFieldsHints - * <code>true</code> if the known implementation details should - * be ignored when looking for the classes and the fields used - * for the native memory of the direct buffers (they are then - * fully recomputed at runtime which is slower but safer), - * otherwise <code>false</code> - */ - public DeallocationHelper(final boolean ignoreClassesAndFieldsHints) { - super(); - final List<Buffer> buffersToDelete = new ArrayList<>(); - /** - * builds the map used to determine the names of the fields containing - * the direct byte buffers. The direct read only buffers and the sliced - * buffers and the direct buffers for other primitive types than bytes - * store their data into some direct byte buffers. Those direct byte - * buffers often are the only one accessing directly to the native - * memory. That's why it's necessary to find them when a developer - * passes a direct NIO buffer. The code below relies on numerous - * implementation details found in some classes not available in the - * public APIs, it's used to find the fields faster in most of the - * cases. The class names haven't changed since Java 1.4 unlike a few - * field names. - */ - final Map<String, String> attachmentOrByteBufferFieldNameMap = new HashMap<>(); - final String javaVendor = System.getProperty("java.vendor"); - final String javaVersion = System.getProperty("java.version"); - if (!ignoreClassesAndFieldsHints) { - if (javaVendor.equals("Sun Microsystems Inc.") || javaVendor.equals("Oracle Corporation")) { - final String java14to16DirectBufferAttachmentFieldName = "viewedBuffer"; - final String java17to19DirectBufferAttachmentFieldName = "att"; - final String byteBufferAsNonByteBufferByteBufferFieldName = "bb"; - final String[] directBufferClassnames = new String[] { "java.nio.DirectByteBuffer", - "java.nio.DirectByteBufferR", "java.nio.DirectCharBufferRS", "java.nio.DirectCharBufferRU", - "java.nio.DirectCharBufferS", "java.nio.DirectCharBufferU", "java.nio.DirectDoubleBufferRS", - "java.nio.DirectDoubleBufferRU", "java.nio.DirectDoubleBufferS", "java.nio.DirectDoubleBufferU", - "java.nio.DirectFloatBufferRS", "java.nio.DirectFloatBufferRU", "java.nio.DirectFloatBufferS", - "java.nio.DirectFloatBufferU", "java.nio.DirectIntBufferRS", "java.nio.DirectIntBufferRU", - "java.nio.DirectIntBufferS", "java.nio.DirectIntBufferU", "java.nio.DirectLongBufferRS", - "java.nio.DirectLongBufferRU", "java.nio.DirectLongBufferS", "java.nio.DirectLongBufferU", - "java.nio.DirectShortBufferRS", "java.nio.DirectShortBufferRU", "java.nio.DirectShortBufferS", - "java.nio.DirectShortBufferU" }; - final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.ByteBufferAsCharBufferB", - "java.nio.ByteBufferAsCharBufferL", "java.nio.ByteBufferAsCharBufferRB", - "java.nio.ByteBufferAsCharBufferRL", "java.nio.ByteBufferAsDoubleBufferB", - "java.nio.ByteBufferAsDoubleBufferL", "java.nio.ByteBufferAsDoubleBufferRB", - "java.nio.ByteBufferAsDoubleBufferRL", "java.nio.ByteBufferAsFloatBufferB", - "java.nio.ByteBufferAsFloatBufferL", "java.nio.ByteBufferAsFloatBufferRB", - "java.nio.ByteBufferAsFloatBufferRL", "java.nio.ByteBufferAsIntBufferB", - "java.nio.ByteBufferAsIntBufferL", "java.nio.ByteBufferAsIntBufferRB", - "java.nio.ByteBufferAsIntBufferRL", "java.nio.ByteBufferAsLongBufferB", - "java.nio.ByteBufferAsLongBufferL", "java.nio.ByteBufferAsLongBufferRB", - "java.nio.ByteBufferAsLongBufferRL", "java.nio.ByteBufferAsShortBufferB", - "java.nio.ByteBufferAsShortBufferL", "java.nio.ByteBufferAsShortBufferRB", - "java.nio.ByteBufferAsShortBufferRL" }; - final String[] javaVersionElements = System.getProperty("java.version").split("\\."); - int indexOfEarlyAccessSuffix = javaVersionElements[0].lastIndexOf("-ea"); - if (indexOfEarlyAccessSuffix != -1) { - // drops the "-ea" suffix from the major version number for - // an early access build - javaVersionElements[0] = javaVersionElements[0].substring(0, indexOfEarlyAccessSuffix); - } else { - indexOfEarlyAccessSuffix = javaVersionElements[0].lastIndexOf("-internal"); - if (indexOfEarlyAccessSuffix != -1) { - // drops the "-internal" suffix from the major version number for - // an early access build (Ubuntu) - javaVersionElements[0] = javaVersionElements[0].substring(0, indexOfEarlyAccessSuffix); - } else { - indexOfEarlyAccessSuffix = javaVersionElements[0].lastIndexOf("-Ubuntu"); - if (indexOfEarlyAccessSuffix != -1) { - // drops the "-Ubuntu suffix from the major version number for - // an early access build (Ubuntu) - javaVersionElements[0] = javaVersionElements[0].substring(0, indexOfEarlyAccessSuffix); - } - } - } - final int major, minor; - if (javaVersionElements.length >= 2) { - major = Integer.parseInt(javaVersionElements[0]); - int min; - try { - min = Integer.parseInt(javaVersionElements[1]); - } catch (NumberFormatException nfe) { - min = 7; - } - minor = min; - } else { - major = 1; - int min; - try { - min = Integer.parseInt(javaVersionElements[0]); - } catch (NumberFormatException nfe) { - min = 7; - } - minor = min; - } - final String directBufferAttachmentFieldName; - if (minor == 1 && major <= 6) - directBufferAttachmentFieldName = java14to16DirectBufferAttachmentFieldName; - else - directBufferAttachmentFieldName = java17to19DirectBufferAttachmentFieldName; - for (final String directBufferClassname : directBufferClassnames) - attachmentOrByteBufferFieldNameMap.put(directBufferClassname, directBufferAttachmentFieldName); - for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames) - attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname, - byteBufferAsNonByteBufferByteBufferFieldName); - } else if (javaVendor.equals("The Android Project")) { - final String byteBufferAsNonByteBufferByteBufferFieldName = "byteBuffer"; - final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.ByteBufferAsCharBuffer", - "java.nio.ByteBufferAsDoubleBuffer", "java.nio.ByteBufferAsFloatBuffer", - "java.nio.ByteBufferAsIntBuffer", "java.nio.ByteBufferAsLongBuffer", - "java.nio.ByteBufferAsShortBuffer" }; - for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames) - attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname, - byteBufferAsNonByteBufferByteBufferFieldName); - } else if (/* javaVendor.equals("Apple Inc.")|| */javaVendor.equals("Free Software Foundation, Inc.")) { - final String byteBufferAsNonByteBufferByteBufferFieldName = "bb"; - final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.CharViewBufferImpl", - "java.nio.DoubleViewBufferImpl", "java.nio.FloatViewBufferImpl", "java.nio.IntViewBufferImpl", - "java.nio.LongViewBufferImpl", "java.nio.ShortViewBufferImpl" }; - for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames) - attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname, - byteBufferAsNonByteBufferByteBufferFieldName); - } else if (javaVendor.contains("Apache")) { - final String byteBufferAsNonByteBufferByteBufferFieldName = "byteBuffer"; - final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.CharToByteBufferAdapter", - "java.nio.DoubleToByteBufferAdapter", "java.nio.FloatToByteBufferAdapter", - "java.nio.IntToByteBufferAdapter", "java.nio.LongToByteBufferAdapter", - "java.nio.ShortToByteBufferAdapter" }; - for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames) - attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname, - byteBufferAsNonByteBufferByteBufferFieldName); - } else if (javaVendor.equals("Jeroen Frijters")) {// TODO IKVM - } else if (javaVendor.contains("IBM")) {// TODO J9 - } - } - // checks if these classes are in the class library - if (!attachmentOrByteBufferFieldNameMap.isEmpty()) { - final List<String> classnamesToRemove = new ArrayList<>(); - for (final String classname : attachmentOrByteBufferFieldNameMap.keySet()) - try { - Class.forName(classname); - } catch (ClassNotFoundException cnfe) { - classnamesToRemove.add(classname); - } - for (final String classnameToRemove : classnamesToRemove) - attachmentOrByteBufferFieldNameMap.remove(classnameToRemove); - } - // builds the map used to determine the fields containing the direct - // byte buffers - attachmentOrByteBufferFieldMap = new HashMap<>(); - if (!attachmentOrByteBufferFieldNameMap.isEmpty()) - for (final Entry<String, String> attachmentOrByteBufferFieldNameEntry : attachmentOrByteBufferFieldNameMap - .entrySet()) { - final String classname = attachmentOrByteBufferFieldNameEntry.getKey(); - final String fieldname = attachmentOrByteBufferFieldNameEntry.getValue(); - try { - final Class<?> bufferClass = Class.forName(classname); - Field bufferField = null; - Class<?> bufferIntermediaryClass = bufferClass; - final List<Class<?>> intermediaryClassWithoutBufferList = new ArrayList<>(); - while (bufferIntermediaryClass != null) { - try { - bufferField = bufferIntermediaryClass.getDeclaredField(fieldname); - } catch (NoSuchFieldException nsfe) { - if (!bufferIntermediaryClass.equals(Object.class) - && !bufferIntermediaryClass.equals(Buffer.class)) - intermediaryClassWithoutBufferList.add(bufferIntermediaryClass); - } - bufferIntermediaryClass = bufferIntermediaryClass.getSuperclass(); - } - if (bufferField == null) { - final String superClassesMsg; - if (intermediaryClassWithoutBufferList.isEmpty()) - superClassesMsg = ""; - else if (intermediaryClassWithoutBufferList.size() == 1) - superClassesMsg = " and in its super class " - + intermediaryClassWithoutBufferList.get(0).getName(); - else { - final StringBuilder builder = new StringBuilder(); - builder.append(" and in its super classes"); - int classIndex = 0; - for (final Class<?> intermediaryClassWithoutBuffer : intermediaryClassWithoutBufferList) { - builder.append(' '); - builder.append(intermediaryClassWithoutBuffer.getName()); - if (classIndex < intermediaryClassWithoutBufferList.size() - 1) - builder.append(','); - classIndex++; - } - superClassesMsg = builder.toString(); - } - logger.warn("The field " + fieldname + " hasn't been found in the class " + classname - + superClassesMsg); - } else {// the field has been found, stores it into the map - attachmentOrByteBufferFieldMap.put(bufferClass, bufferField); - } - } catch (ClassNotFoundException cnfe) {// TODO The Java version - // isn't very useful - // under - // Android as it is - // always zero, rather - // use - // android.os.Build.VERSION.RELEASE - // to show something - // meaningful supported - // since the API level 1 - final String msg = "The class " + classname - + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor - + " Java version: " + javaVersion; - logger.warn(msg, cnfe); - } - } - // if a known implementation has drastically changed or if the current - // implementation is unknown - if (attachmentOrByteBufferFieldNameMap.isEmpty()) {// detects everything - // with the - // reflection API - // creates all - // possible kinds of - // direct NIO buffer - // that can contain - // buffers (sliced - // buffers and views) - final ByteBuffer slicedBigEndianReadOnlyDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2) - .order(ByteOrder.BIG_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice() - .asReadOnlyBuffer(); - final ByteBuffer slicedBigEndianReadWriteDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2) - .order(ByteOrder.BIG_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice(); - final CharBuffer bigEndianReadOnlyDirectCharBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asCharBuffer(); - final CharBuffer bigEndianReadWriteDirectCharBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asCharBuffer(); - final DoubleBuffer bigEndianReadOnlyDirectDoubleBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asDoubleBuffer(); - final DoubleBuffer bigEndianReadWriteDirectDoubleBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asDoubleBuffer(); - final FloatBuffer bigEndianReadOnlyDirectFloatBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asFloatBuffer(); - final FloatBuffer bigEndianReadWriteDirectFloatBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asFloatBuffer(); - final IntBuffer bigEndianReadOnlyDirectIntBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN) - .asReadOnlyBuffer().asIntBuffer(); - final IntBuffer bigEndianReadWriteDirectIntBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN) - .asIntBuffer(); - final LongBuffer bigEndianReadOnlyDirectLongBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asLongBuffer(); - final LongBuffer bigEndianReadWriteDirectLongBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asLongBuffer(); - final ShortBuffer bigEndianReadOnlyDirectShortBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asShortBuffer(); - final ShortBuffer bigEndianReadWriteDirectShortBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.BIG_ENDIAN).asShortBuffer(); - final ByteBuffer slicedLittleEndianReadOnlyDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2) - .order(ByteOrder.LITTLE_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice() - .asReadOnlyBuffer(); - final ByteBuffer slicedLittleEndianReadWriteDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2) - .order(ByteOrder.LITTLE_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice(); - final CharBuffer littleEndianReadOnlyDirectCharBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asCharBuffer(); - final CharBuffer littleEndianReadWriteDirectCharBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asCharBuffer(); - final DoubleBuffer littleEndianReadOnlyDirectDoubleBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asDoubleBuffer(); - final DoubleBuffer littleEndianReadWriteDirectDoubleBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer(); - final FloatBuffer littleEndianReadOnlyDirectFloatBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asFloatBuffer(); - final FloatBuffer littleEndianReadWriteDirectFloatBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer(); - final IntBuffer littleEndianReadOnlyDirectIntBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asIntBuffer(); - final IntBuffer littleEndianReadWriteDirectIntBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asIntBuffer(); - final LongBuffer littleEndianReadOnlyDirectLongBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asLongBuffer(); - final LongBuffer littleEndianReadWriteDirectLongBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asLongBuffer(); - final ShortBuffer littleEndianReadOnlyDirectShortBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asShortBuffer(); - final ShortBuffer littleEndianReadWriteDirectShortBuffer = ByteBuffer.allocateDirect(1) - .order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); - final List<Buffer> buffers = new ArrayList<>(); - buffers.add(slicedBigEndianReadOnlyDirectByteBuffer); - buffers.add(slicedBigEndianReadWriteDirectByteBuffer); - buffers.add(bigEndianReadOnlyDirectCharBuffer); - buffers.add(bigEndianReadWriteDirectCharBuffer); - buffers.add(bigEndianReadOnlyDirectDoubleBuffer); - buffers.add(bigEndianReadWriteDirectDoubleBuffer); - buffers.add(bigEndianReadOnlyDirectFloatBuffer); - buffers.add(bigEndianReadWriteDirectFloatBuffer); - buffers.add(bigEndianReadOnlyDirectIntBuffer); - buffers.add(bigEndianReadWriteDirectIntBuffer); - buffers.add(bigEndianReadOnlyDirectLongBuffer); - buffers.add(bigEndianReadWriteDirectLongBuffer); - buffers.add(bigEndianReadOnlyDirectShortBuffer); - buffers.add(bigEndianReadWriteDirectShortBuffer); - buffers.add(slicedLittleEndianReadOnlyDirectByteBuffer); - buffers.add(slicedLittleEndianReadWriteDirectByteBuffer); - buffers.add(littleEndianReadOnlyDirectCharBuffer); - buffers.add(littleEndianReadWriteDirectCharBuffer); - buffers.add(littleEndianReadOnlyDirectDoubleBuffer); - buffers.add(littleEndianReadWriteDirectDoubleBuffer); - buffers.add(littleEndianReadOnlyDirectFloatBuffer); - buffers.add(littleEndianReadWriteDirectFloatBuffer); - buffers.add(littleEndianReadOnlyDirectIntBuffer); - buffers.add(littleEndianReadWriteDirectIntBuffer); - buffers.add(littleEndianReadOnlyDirectLongBuffer); - buffers.add(littleEndianReadWriteDirectLongBuffer); - buffers.add(littleEndianReadOnlyDirectShortBuffer); - buffers.add(littleEndianReadWriteDirectShortBuffer); - // gets the fields to access the contained buffers - for (Buffer buffer : buffers) { - final Class<?> bufferClass = buffer.getClass(); - if (!attachmentOrByteBufferFieldMap.containsKey(bufferClass)) { - Field bufferField = null; - Class<?> bufferIntermediaryClass = bufferClass; - while (bufferIntermediaryClass != null && bufferField == null) { - for (final Field field : bufferIntermediaryClass.getDeclaredFields()) { - final boolean fieldWasAccessible = field.isAccessible(); - try { - field.setAccessible(true); - final Object fieldValue = field.get(buffer); - if (fieldValue != null && fieldValue instanceof Buffer) { - bufferField = field; - break; - } - } catch (IllegalAccessException iae) { - logger.warn("Cannot access the field " + field.getName() - + " of the class " + bufferIntermediaryClass.getName(), iae); - } finally { - field.setAccessible(fieldWasAccessible); - } - } - bufferIntermediaryClass = bufferIntermediaryClass.getSuperclass(); - } - if (bufferField != null) - attachmentOrByteBufferFieldMap.put(bufferClass, bufferField); - } - } - // cleans the mess - buffersToDelete.addAll(buffers); - } - // builds the set of classes whose instances can be deallocated - deallocatableBufferClassSet = new HashSet<>(); - if (javaVendor.equals("Sun Microsystems Inc.") || javaVendor.equals("Oracle Corporation") - || javaVendor.equals("The Android Project")) { - Class<?> directByteBufferClass = null; - final String directByteBufferClassName = "java.nio.DirectByteBuffer"; - try { - directByteBufferClass = Class.forName(directByteBufferClassName); - } catch (ClassNotFoundException cnfe) { - final String msg = "The class " + directByteBufferClassName - + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor - + " Java version: " + javaVersion; - logger.warn(msg, cnfe); - } - if (directByteBufferClass != null) - deallocatableBufferClassSet.add(directByteBufferClass); - } else if (/* javaVendor.equals("Apple Inc.")|| */javaVendor.equals("Free Software Foundation, Inc.")) { - Class<?> readOnlyDirectByteBufferClass = null; - final String readOnlyDirectByteBufferClassName = "java.nio.DirectByteBufferImpl.ReadOnly"; - try { - readOnlyDirectByteBufferClass = Class.forName(readOnlyDirectByteBufferClassName); - } catch (ClassNotFoundException cnfe) { - final String msg = "The class " + readOnlyDirectByteBufferClassName - + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor - + " Java version: " + javaVersion; - logger.warn(msg, cnfe); - } - if (readOnlyDirectByteBufferClass != null) - deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass); - Class<?> readWriteDirectByteBufferClass = null; - final String readWriteDirectByteBufferClassName = "java.nio.DirectByteBufferImpl.ReadWrite"; - try { - readWriteDirectByteBufferClass = Class.forName(readWriteDirectByteBufferClassName); - } catch (ClassNotFoundException cnfe) { - final String msg = "The class " + readWriteDirectByteBufferClassName - + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor - + " Java version: " + javaVersion; - logger.warn(msg, cnfe); - } - if (readWriteDirectByteBufferClass != null) - deallocatableBufferClassSet.add(readWriteDirectByteBufferClass); - } else if (javaVendor.contains("Apache")) { - Class<?> readOnlyDirectByteBufferClass = null; - final String readOnlyDirectByteBufferClassName = "java.nio.ReadOnlyDirectByteBuffer"; - try { - readOnlyDirectByteBufferClass = Class.forName(readOnlyDirectByteBufferClassName); - } catch (ClassNotFoundException cnfe) { - final String msg = "The class " + readOnlyDirectByteBufferClassName - + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor - + " Java version: " + javaVersion; - logger.warn(msg, cnfe); - } - if (readOnlyDirectByteBufferClass != null) - deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass); - Class<?> readWriteDirectByteBufferClass = null; - final String readWriteDirectByteBufferClassName = "java.nio.ReadWriteDirectByteBuffer"; - try { - readWriteDirectByteBufferClass = Class.forName(readWriteDirectByteBufferClassName); - } catch (ClassNotFoundException cnfe) { - final String msg = "The class " + readWriteDirectByteBufferClassName - + " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor - + " Java version: " + javaVersion; - logger.warn(msg, cnfe); - } - if (readWriteDirectByteBufferClass != null) - deallocatableBufferClassSet.add(readWriteDirectByteBufferClass); - } else if (javaVendor.equals("Jeroen Frijters")) {// TODO IKVM - } else if (javaVendor.contains("IBM")) {// TODO J9 - } - // if there is no known implementation class of the direct byte buffers - if (deallocatableBufferClassSet.isEmpty()) {// creates a read write - // direct byte buffer - final ByteBuffer dummyReadWriteDirectByteBuffer = ByteBuffer.allocateDirect(1); - // gets its class - final Class<?> readWriteDirectByteBufferClass = dummyReadWriteDirectByteBuffer.getClass(); - // stores this class - deallocatableBufferClassSet.add(readWriteDirectByteBufferClass); - // cleans the mess - buffersToDelete.add(dummyReadWriteDirectByteBuffer); - // creates a read only direct byte buffer - final ByteBuffer dummyReadOnlyDirectByteBuffer = ByteBuffer.allocateDirect(1).asReadOnlyBuffer(); - // gets its class - final Class<?> readOnlyDirectByteBufferClass = dummyReadOnlyDirectByteBuffer.getClass(); - // stores this class - deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass); - // cleans the mess - buffersToDelete.add(dummyReadOnlyDirectByteBuffer); - } - // builds the deallocator responsible for releasing the native memory of - // a deallocatable byte buffer - if (javaVendor.equals("Sun Microsystems Inc.") || javaVendor.equals("Oracle Corporation")) - deallocator = new OracleSunOpenJdkDeallocator(); - else if (javaVendor.equals("The Android Project")) - deallocator = new AndroidDeallocator(); - else if (/* javaVendor.equals("Apple Inc.")|| */javaVendor.equals("Free Software Foundation, Inc.")) - deallocator = new GnuClasspathDeallocator(); - else if (javaVendor.contains("Apache")) - deallocator = new ApacheHarmonyDeallocator(); - else if (javaVendor.equals("Jeroen Frijters")) {// TODO IKVM - deallocator = null; - } else if (javaVendor.contains("IBM")) {// TODO J9 - deallocator = null; - } else - deallocator = null; - // final cleanup - for (final Buffer bufferToDelete : buffersToDelete) - deallocate(bufferToDelete); - } - - public ByteBuffer findDeallocatableBuffer(Buffer buffer) { - final ByteBuffer deallocatableDirectByteBuffer; - // looks only for the direct buffers - if (buffer != null && buffer.isDirect()) {// looks for any contained - // buffer in the passed buffer - final Class<?> bufferClass = buffer.getClass(); - final Field attachmentOrByteBufferField = attachmentOrByteBufferFieldMap == null ? null - : attachmentOrByteBufferFieldMap.get(bufferClass); - final Buffer attachmentBufferOrByteBuffer; - if (attachmentOrByteBufferField == null) - attachmentBufferOrByteBuffer = null; - else { - Object attachedObjectOrByteBuffer; - final boolean attachedObjectOrByteBufferFieldWasAccessible = attachmentOrByteBufferField.isAccessible(); - try { - attachmentOrByteBufferField.setAccessible(true); - attachedObjectOrByteBuffer = attachmentOrByteBufferField.get(buffer); - } catch (IllegalArgumentException | IllegalAccessException iae) { - attachedObjectOrByteBuffer = null; - } finally { - attachmentOrByteBufferField.setAccessible(attachedObjectOrByteBufferFieldWasAccessible); - } - if (attachedObjectOrByteBuffer instanceof Buffer) - attachmentBufferOrByteBuffer = (Buffer) attachedObjectOrByteBuffer; - else - attachmentBufferOrByteBuffer = null; - } - // if there is no buffer inside the buffer given in input - if (attachmentBufferOrByteBuffer == null) {// if it's a direct byte - // buffer and if it's an - // instance of - // a deallocatable buffer - // class - if (buffer instanceof ByteBuffer && deallocatableBufferClassSet.contains(bufferClass)) - deallocatableDirectByteBuffer = (ByteBuffer) buffer; - else {// it's not a byte buffer or it's not a - // deallocatable buffer - deallocatableDirectByteBuffer = null; - final String bufferClassName = bufferClass.getName(); - logger.warn("No deallocatable buffer has been found for an instance of the class " - + bufferClassName + " whereas it is a direct NIO buffer"); - } - } else {// the passed buffer contains another buffer, looks for a - // deallocatable buffer inside it - deallocatableDirectByteBuffer = findDeallocatableBuffer(attachmentBufferOrByteBuffer); - } - } else {// there is no need to clean the heap based buffers - deallocatableDirectByteBuffer = null; - } - return deallocatableDirectByteBuffer; - } - - public void deallocate(final Buffer buffer) { - if (deallocator != null) { - final ByteBuffer deallocatableBuffer = findDeallocatableBuffer(buffer); - if (deallocatableBuffer != null) - deallocator.run(deallocatableBuffer); - } - } - - public Deallocator getDeallocator() { - return (deallocator); - } - - public void setDeallocator(Deallocator deallocator) { - this.deallocator = deallocator; - } - - public Map<Class<?>, Field> getAttachmentOrByteBufferFieldMap() { - return (attachmentOrByteBufferFieldMap); - } - - public void setAttachmentOrByteBufferFieldMap(Map<Class<?>, Field> attachmentOrByteBufferFieldMap) { - this.attachmentOrByteBufferFieldMap = attachmentOrByteBufferFieldMap; - } - - public Set<Class<?>> getDeallocatableBufferClassSet() { - return (deallocatableBufferClassSet); - } - - public void setDeallocatableBufferClassSet(Set<Class<?>> deallocatableBufferClassSet) { - this.deallocatableBufferClassSet = deallocatableBufferClassSet; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/ArcDef.java b/apps/jrobin/java/src/org/jrobin/core/ArcDef.java deleted file mode 100644 index 0c420193a2e1545069c0890797c948099662db88..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/ArcDef.java +++ /dev/null @@ -1,181 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -/** - * Class to represent single archive definition within the RRD. - * Archive definition consists of the following four elements: - * <p> - * <ul> - * <li>consolidation function - * <li>X-files factor - * <li>number of steps - * <li>number of rows. - * </ul> - * <p> - * For the complete explanation of all archive definition parameters, see RRDTool's - * <a href="../../../../man/rrdcreate.html" target="man">rrdcreate man page</a>. - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ - -public class ArcDef implements ConsolFuns { - /** - * array of valid consolidation function names - */ - public static final String CONSOL_FUNS[] = {CF_AVERAGE, CF_MAX, CF_MIN, CF_LAST}; - - private String consolFun; - private double xff; - private int steps, rows; - - /** - * Creates new archive definition object. This object should be passed as argument to - * {@link RrdDef#addArchive(ArcDef) addArchive()} method of - * {@link RrdDb RrdDb} object. - * <p> - * <p>For the complete explanation of all archive definition parameters, see RRDTool's - * <a href="../../../../man/rrdcreate.html" target="man">rrdcreate man page</a></p> - * - * @param consolFun Consolidation function. Allowed values are "AVERAGE", "MIN", - * "MAX" and "LAST" (these string constants are conveniently defined in the - * {@link ConsolFuns} class). - * @param xff X-files factor, between 0 and 1. - * @param steps Number of archive steps. - * @param rows Number of archive rows. - * @throws RrdException Thrown if any parameter has illegal value. - */ - public ArcDef(final String consolFun, final double xff, final int steps, final int rows) throws RrdException { - this.consolFun = consolFun; - this.xff = xff; - this.steps = steps; - this.rows = rows; - validate(); - } - - /** - * Returns consolidation function. - * - * @return Consolidation function. - */ - public String getConsolFun() { - return consolFun; - } - - /** - * Returns the X-files factor. - * - * @return X-files factor value. - */ - public double getXff() { - return xff; - } - - /** - * Returns the number of primary RRD steps which complete a single archive step. - * - * @return Number of steps. - */ - public int getSteps() { - return steps; - } - - /** - * Returns the number of rows (aggregated values) stored in the archive. - * - * @return Number of rows. - */ - public int getRows() { - return rows; - } - - private void validate() throws RrdException { - if (!isValidConsolFun(consolFun)) { - throw new RrdException("Invalid consolidation function specified: " + consolFun); - } - if (Double.isNaN(xff) || xff < 0.0 || xff >= 1.0) { - throw new RrdException("Invalid xff, must be >= 0 and < 1: " + xff); - } - if (steps < 1 || rows < 2) { - throw new RrdException("Invalid steps/rows settings: " + steps + "/" + rows + - ". Minimal values allowed are steps=1, rows=2"); - } - } - - /** - * Returns string representing archive definition (RRDTool format). - * - * @return String containing all archive definition parameters. - */ - public String dump() { - return "RRA:" + consolFun + ":" + xff + ":" + steps + ":" + rows; - } - - /** - * Checks if two archive definitions are equal. - * Archive definitions are considered equal if they have the same number of steps - * and the same consolidation function. It is not possible to create RRD with two - * equal archive definitions. - * - * @param obj Archive definition to compare with. - * @return <code>true</code> if archive definitions are equal, - * <code>false</code> otherwise. - */ - public boolean equals(final Object obj) { - if (obj instanceof ArcDef) { - final ArcDef arcObj = (ArcDef) obj; - return consolFun.equals(arcObj.consolFun) && steps == arcObj.steps; - } - return false; - } - - public int hashCode() { - return (consolFun.hashCode() + steps) * 53; - } - - /** - * Checks if function argument represents valid consolidation function name. - * - * @param consolFun Consolidation function to be checked - * @return <code>true</code> if <code>consolFun</code> is valid consolidation function, - * <code>false</code> otherwise. - */ - public static boolean isValidConsolFun(final String consolFun) { - for (final String cFun : CONSOL_FUNS) { - if (cFun.equals(consolFun)) { - return true; - } - } - return false; - } - - void setRows(final int rows) { - this.rows = rows; - } - - boolean exactlyEqual(final ArcDef def) { - return consolFun.equals(def.consolFun) && xff == def.xff && - steps == def.steps && rows == def.rows; - } - - public String toString() { - return "ArcDef@" + Integer.toHexString(hashCode()) + "[consolFun=" + consolFun + ",xff=" + xff + ",steps=" + steps + ",rows=" + rows + "]"; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/ArcState.java b/apps/jrobin/java/src/org/jrobin/core/ArcState.java deleted file mode 100644 index 71f6dd297ae3036f44ac7b20efe5d9b3cb98f462..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/ArcState.java +++ /dev/null @@ -1,140 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -/** - * Class to represent internal RRD archive state for a single datasource. Objects of this - * class are never manipulated directly, it's up to JRobin framework to manage - * internal arcihve states.<p> - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ -public class ArcState implements RrdUpdater { - private Archive parentArc; - - private RrdDouble accumValue; - private RrdLong nanSteps; - - ArcState(Archive parentArc, boolean shouldInitialize) throws IOException { - this.parentArc = parentArc; - accumValue = new RrdDouble(this); - nanSteps = new RrdLong(this); - if (shouldInitialize) { - Header header = parentArc.getParentDb().getHeader(); - long step = header.getStep(); - long lastUpdateTime = header.getLastUpdateTime(); - long arcStep = parentArc.getArcStep(); - long initNanSteps = (Util.normalize(lastUpdateTime, step) - - Util.normalize(lastUpdateTime, arcStep)) / step; - accumValue.set(Double.NaN); - nanSteps.set(initNanSteps); - } - } - - String dump() throws IOException { - return "accumValue:" + accumValue.get() + " nanSteps:" + nanSteps.get() + "\n"; - } - - void setNanSteps(long value) throws IOException { - nanSteps.set(value); - } - - /** - * Returns the number of currently accumulated NaN steps. - * - * @return Number of currently accumulated NaN steps. - * @throws IOException Thrown in case of I/O error - */ - public long getNanSteps() throws IOException { - return nanSteps.get(); - } - - void setAccumValue(double value) throws IOException { - accumValue.set(value); - } - - /** - * Returns the value accumulated so far. - * - * @return Accumulated value - * @throws IOException Thrown in case of I/O error - */ - public double getAccumValue() throws IOException { - return accumValue.get(); - } - - /** - * Returns the Archive object to which this ArcState object belongs. - * - * @return Parent Archive object. - */ - public Archive getParent() { - return parentArc; - } - - void appendXml(XmlWriter writer) throws IOException { - writer.startTag("ds"); - writer.writeTag("value", accumValue.get()); - writer.writeTag("unknown_datapoints", nanSteps.get()); - writer.closeTag(); // ds - } - - /** - * Copies object's internal state to another ArcState object. - * - * @param other New ArcState object to copy state to - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if supplied argument is not an ArcState object - */ - public void copyStateTo(RrdUpdater other) throws IOException, RrdException { - if (!(other instanceof ArcState)) { - throw new RrdException( - "Cannot copy ArcState object to " + other.getClass().getName()); - } - ArcState arcState = (ArcState) other; - arcState.accumValue.set(accumValue.get()); - arcState.nanSteps.set(nanSteps.get()); - } - - /** - * Returns the underlying storage (backend) object which actually performs all - * I/O operations. - * - * @return I/O backend object - */ - public RrdBackend getRrdBackend() { - return parentArc.getRrdBackend(); - } - - /** - * Required to implement RrdUpdater interface. You should never call this method directly. - * - * @return Allocator object - */ - public RrdAllocator getRrdAllocator() { - return parentArc.getRrdAllocator(); - } - - public String toString() { - return "ArcState@" + Integer.toHexString(hashCode()) + "[parentArc=" + parentArc + ",accumValue=" + accumValue + ",nanSteps=" + nanSteps + "]"; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/Archive.java b/apps/jrobin/java/src/org/jrobin/core/Archive.java deleted file mode 100644 index 470bc75eb79a73dda32fb44adc327cf141f54bb8..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/Archive.java +++ /dev/null @@ -1,418 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -/** - * Class to represent single RRD archive in a RRD with its internal state. - * Normally, you don't need methods to manipulate archive objects directly - * because JRobin framework does it automatically for you. - * <p> - * Each archive object consists of three parts: archive definition, archive state objects - * (one state object for each datasource) and round robin archives (one round robin for - * each datasource). API (read-only) is provided to access each of theese parts. - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ -public class Archive implements RrdUpdater, ConsolFuns { - private RrdDb parentDb; - // definition - private RrdString consolFun; - private RrdDouble xff; - private RrdInt steps, rows; - // state - private Robin[] robins; - private ArcState[] states; - - Archive(final RrdDb parentDb, final ArcDef arcDef) throws IOException { - final boolean shouldInitialize = arcDef != null; - this.parentDb = parentDb; - consolFun = new RrdString(this, true); // constant, may be cached - xff = new RrdDouble(this); - steps = new RrdInt(this, true); // constant, may be cached - rows = new RrdInt(this, true); // constant, may be cached - if (shouldInitialize) { - consolFun.set(arcDef.getConsolFun()); - xff.set(arcDef.getXff()); - steps.set(arcDef.getSteps()); - rows.set(arcDef.getRows()); - } - final int dsCount = parentDb.getHeader().getDsCount(); - states = new ArcState[dsCount]; - robins = new Robin[dsCount]; - final int numRows = rows.get(); - for (int i = 0; i < dsCount; i++) { - states[i] = new ArcState(this, shouldInitialize); - robins[i] = new Robin(this, numRows, shouldInitialize); - } - } - - // read from XML - Archive(final RrdDb parentDb, final DataImporter reader, final int arcIndex) throws IOException, RrdException,RrdException { - this(parentDb, new ArcDef( - reader.getConsolFun(arcIndex), reader.getXff(arcIndex), - reader.getSteps(arcIndex), reader.getRows(arcIndex))); - final int dsCount = parentDb.getHeader().getDsCount(); - for (int i = 0; i < dsCount; i++) { - // restore state - states[i].setAccumValue(reader.getStateAccumValue(arcIndex, i)); - states[i].setNanSteps(reader.getStateNanSteps(arcIndex, i)); - // restore robins - double[] values = reader.getValues(arcIndex, i); - robins[i].update(values); - } - } - - /** - * Returns archive time step in seconds. Archive step is equal to RRD step - * multiplied with the number of archive steps. - * - * @return Archive time step in seconds - * @throws IOException Thrown in case of I/O error. - */ - public long getArcStep() throws IOException { - final long step = parentDb.getHeader().getStep(); - return step * steps.get(); - } - - String dump() throws IOException { - final StringBuffer buffer = new StringBuffer("== ARCHIVE ==\n"); - buffer.append("RRA:").append(consolFun.get()).append(":").append(xff.get()).append(":").append(steps.get()). - append(":").append(rows.get()).append("\n"); - buffer.append("interval [").append(getStartTime()).append(", ").append(getEndTime()).append("]" + "\n"); - for (int i = 0; i < robins.length; i++) { - buffer.append(states[i].dump()); - buffer.append(robins[i].dump()); - } - return buffer.toString(); - } - - RrdDb getParentDb() { - return parentDb; - } - - public void archive(final int dsIndex, final double value, final long numStepUpdates) throws IOException { - final Robin robin = robins[dsIndex]; - final ArcState state = states[dsIndex]; - final long step = parentDb.getHeader().getStep(); - final long lastUpdateTime = parentDb.getHeader().getLastUpdateTime(); - long updateTime = Util.normalize(lastUpdateTime, step) + step; - final long arcStep = getArcStep(); - final String consolFunString = consolFun.get(); - final int numSteps = steps.get(); - final int numRows = rows.get(); - final double xffValue = xff.get(); - - // finish current step - long numUpdates = numStepUpdates; - while (numUpdates > 0) { - accumulate(state, value, consolFunString); - numUpdates--; - if (updateTime % arcStep == 0) { - finalizeStep(state, robin, consolFunString, numSteps, xffValue); - break; - } - else { - updateTime += step; - } - } - // update robin in bulk - final int bulkUpdateCount = (int) Math.min(numUpdates / numSteps, (long) numRows); - robin.bulkStore(value, bulkUpdateCount); - // update remaining steps - final long remainingUpdates = numUpdates % numSteps; - for (long i = 0; i < remainingUpdates; i++) { - accumulate(state, value, consolFunString); - } - } - - private void accumulate(final ArcState state, final double value, String consolFunString) throws IOException { - if (Double.isNaN(value)) { - state.setNanSteps(state.getNanSteps() + 1); - } - else { - final double accumValue = state.getAccumValue(); - if (consolFunString.equals(CF_MIN)) { - final double minValue = Util.min(accumValue, value); - if (minValue != accumValue) { - state.setAccumValue(minValue); - } - } - else if (consolFunString.equals(CF_MAX)) { - final double maxValue = Util.max(accumValue, value); - if (maxValue != accumValue) { - state.setAccumValue(maxValue); - } - } - else if (consolFunString.equals(CF_LAST)) { - state.setAccumValue(value); - } - else if (consolFunString.equals(CF_AVERAGE)) { - state.setAccumValue(Util.sum(accumValue, value)); - } - } - } - - private void finalizeStep(final ArcState state, final Robin robin, final String consolFunString, final long numSteps, final double xffValue) throws IOException { - final long nanSteps = state.getNanSteps(); - //double nanPct = (double) nanSteps / (double) arcSteps; - double accumValue = state.getAccumValue(); - if (nanSteps <= xffValue * numSteps && !Double.isNaN(accumValue)) { - if (consolFunString.equals(CF_AVERAGE)) { - accumValue /= (numSteps - nanSteps); - } - robin.store(accumValue); - } else { - robin.store(Double.NaN); - } - state.setAccumValue(Double.NaN); - state.setNanSteps(0); - } - - /** - * Returns archive consolidation function ("AVERAGE", "MIN", "MAX" or "LAST"). - * - * @return Archive consolidation function. - * @throws IOException Thrown in case of I/O error. - */ - public String getConsolFun() throws IOException { - return consolFun.get(); - } - - /** - * Returns archive X-files factor. - * - * @return Archive X-files factor (between 0 and 1). - * @throws IOException Thrown in case of I/O error. - */ - public double getXff() throws IOException { - return xff.get(); - } - - /** - * Returns the number of archive steps. - * - * @return Number of archive steps. - * @throws IOException Thrown in case of I/O error. - */ - public int getSteps() throws IOException { - return steps.get(); - } - - /** - * Returns the number of archive rows. - * - * @return Number of archive rows. - * @throws IOException Thrown in case of I/O error. - */ - public int getRows() throws IOException { - return rows.get(); - } - - /** - * Returns current starting timestamp. This value is not constant. - * - * @return Timestamp corresponding to the first archive row - * @throws IOException Thrown in case of I/O error. - */ - public long getStartTime() throws IOException { - final long endTime = getEndTime(); - final long arcStep = getArcStep(); - final long numRows = rows.get(); - return endTime - (numRows - 1) * arcStep; - } - - /** - * Returns current ending timestamp. This value is not constant. - * - * @return Timestamp corresponding to the last archive row - * @throws IOException Thrown in case of I/O error. - */ - public long getEndTime() throws IOException { - final long arcStep = getArcStep(); - final long lastUpdateTime = parentDb.getHeader().getLastUpdateTime(); - return Util.normalize(lastUpdateTime, arcStep); - } - - /** - * Returns the underlying archive state object. Each datasource has its - * corresponding ArcState object (archive states are managed independently - * for each RRD datasource). - * - * @param dsIndex Datasource index - * @return Underlying archive state object - */ - public ArcState getArcState(final int dsIndex) { - return states[dsIndex]; - } - - /** - * Returns the underlying round robin archive. Robins are used to store actual - * archive values on a per-datasource basis. - * - * @param dsIndex Index of the datasource in the RRD. - * @return Underlying round robin archive for the given datasource. - */ - public Robin getRobin(final int dsIndex) { - return robins[dsIndex]; - } - - FetchData fetchData(final FetchRequest request) throws IOException, RrdException { - final long arcStep = getArcStep(); - final long fetchStart = Util.normalize(request.getFetchStart(), arcStep); - long fetchEnd = Util.normalize(request.getFetchEnd(), arcStep); - if (fetchEnd < request.getFetchEnd()) { - fetchEnd += arcStep; - } - final long startTime = getStartTime(); - final long endTime = getEndTime(); - String[] dsToFetch = request.getFilter(); - if (dsToFetch == null) { - dsToFetch = parentDb.getDsNames(); - } - final int dsCount = dsToFetch.length; - final int ptsCount = (int) ((fetchEnd - fetchStart) / arcStep + 1); - final long[] timestamps = new long[ptsCount]; - final double[][] values = new double[dsCount][ptsCount]; - final long matchStartTime = Math.max(fetchStart, startTime); - final long matchEndTime = Math.min(fetchEnd, endTime); - double[][] robinValues = null; - if (matchStartTime <= matchEndTime) { - // preload robin values - final int matchCount = (int) ((matchEndTime - matchStartTime) / arcStep + 1); - final int matchStartIndex = (int) ((matchStartTime - startTime) / arcStep); - robinValues = new double[dsCount][]; - for (int i = 0; i < dsCount; i++) { - final int dsIndex = parentDb.getDsIndex(dsToFetch[i]); - robinValues[i] = robins[dsIndex].getValues(matchStartIndex, matchCount); - } - } - for (int ptIndex = 0; ptIndex < ptsCount; ptIndex++) { - final long time = fetchStart + ptIndex * arcStep; - timestamps[ptIndex] = time; - for (int i = 0; i < dsCount; i++) { - double value = Double.NaN; - if (time >= matchStartTime && time <= matchEndTime) { - // inbound time - final int robinValueIndex = (int) ((time - matchStartTime) / arcStep); - assert robinValues != null; - value = robinValues[i][robinValueIndex]; - } - values[i][ptIndex] = value; - } - } - final FetchData fetchData = new FetchData(this, request); - fetchData.setTimestamps(timestamps); - fetchData.setValues(values); - return fetchData; - } - - void appendXml(final XmlWriter writer) throws IOException { - writer.startTag("rra"); - writer.writeTag("cf", consolFun.get()); - writer.writeComment(getArcStep() + " seconds"); - writer.writeTag("pdp_per_row", steps.get()); - writer.writeTag("xff", xff.get()); - writer.startTag("cdp_prep"); - for (final ArcState state : states) { - state.appendXml(writer); - } - writer.closeTag(); // cdp_prep - writer.startTag("database"); - final long startTime = getStartTime(); - for (int i = 0; i < rows.get(); i++) { - final long time = startTime + i * getArcStep(); - writer.writeComment(Util.getDate(time) + " / " + time); - writer.startTag("row"); - for (final Robin robin : robins) { - writer.writeTag("v", robin.getValue(i)); - } - writer.closeTag(); // row - } - writer.closeTag(); // database - writer.closeTag(); // rra - } - - /** - * Copies object's internal state to another Archive object. - * - * @param other New Archive object to copy state to - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if supplied argument is not an Archive object - */ - public void copyStateTo(final RrdUpdater other) throws IOException, RrdException { - if (!(other instanceof Archive)) { - throw new RrdException("Cannot copy Archive object to " + other.getClass().getName()); - } - final Archive arc = (Archive) other; - if (!arc.consolFun.get().equals(consolFun.get())) { - throw new RrdException("Incompatible consolidation functions"); - } - if (arc.steps.get() != steps.get()) { - throw new RrdException("Incompatible number of steps"); - } - final int count = parentDb.getHeader().getDsCount(); - for (int i = 0; i < count; i++) { - final int j = Util.getMatchingDatasourceIndex(parentDb, i, arc.parentDb); - if (j >= 0) { - states[i].copyStateTo(arc.states[j]); - robins[i].copyStateTo(arc.robins[j]); - } - } - } - - /** - * Sets X-files factor to a new value. - * - * @param xff New X-files factor value. Must be >= 0 and < 1. - * @throws RrdException Thrown if invalid value is supplied - * @throws IOException Thrown in case of I/O error - */ - public void setXff(final double xff) throws RrdException, IOException { - if (xff < 0D || xff >= 1D) { - throw new RrdException("Invalid xff supplied (" + xff + "), must be >= 0 and < 1"); - } - this.xff.set(xff); - } - - /** - * Returns the underlying storage (backend) object which actually performs all - * I/O operations. - * - * @return I/O backend object - */ - public RrdBackend getRrdBackend() { - return parentDb.getRrdBackend(); - } - - /** - * Required to implement RrdUpdater interface. You should never call this method directly. - * - * @return Allocator object - */ - public RrdAllocator getRrdAllocator() { - return parentDb.getRrdAllocator(); - } - - public String toString() { - return "Archive@" + Integer.toHexString(hashCode()) + "[parentDb=" + parentDb + ",consolFun=" + consolFun + ",xff=" + xff + ",steps=" + steps + ",rows=" + rows + ",robins=" + robins + ",states=" + states + "]"; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/ConsolFuns.java b/apps/jrobin/java/src/org/jrobin/core/ConsolFuns.java deleted file mode 100644 index ec9f4bd7253eca658b7a7538a911e34ae15d2050..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/ConsolFuns.java +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core; - -/** - * Simple interface to represent available consolidation functions - */ -public interface ConsolFuns { - /** - * Constant to represent AVERAGE consolidation function - */ - public static final String CF_AVERAGE = "AVERAGE"; - - /** - * Constant to represent MIN consolidation function - */ - public static final String CF_MIN = "MIN"; - - /** - * Constant to represent MAX consolidation function - */ - public static final String CF_MAX = "MAX"; - - /** - * Constant to represent LAST consolidation function - */ - public static final String CF_LAST = "LAST"; - - /** - * Constant to represent FIRST consolidation function - */ - public static final String CF_FIRST = "FIRST"; - - /** - * Constant to represent TOTAL consolidation function - */ - public static final String CF_TOTAL = "TOTAL"; -} diff --git a/apps/jrobin/java/src/org/jrobin/core/DataImporter.java b/apps/jrobin/java/src/org/jrobin/core/DataImporter.java deleted file mode 100644 index 9055005838bf687b3f028e8314487c47b182158d..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/DataImporter.java +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -import org.jrobin.core.RrdException; - -abstract class DataImporter { - - // header - abstract String getVersion() throws RrdException, IOException; - - abstract long getLastUpdateTime() throws RrdException, IOException; - - abstract long getStep() throws RrdException, IOException; - - abstract int getDsCount() throws RrdException, IOException; - - abstract int getArcCount() throws RrdException, IOException; - - // datasource - abstract String getDsName(int dsIndex) throws RrdException, IOException; - - abstract String getDsType(int dsIndex) throws RrdException, IOException; - - abstract long getHeartbeat(int dsIndex) throws RrdException, IOException; - - abstract double getMinValue(int dsIndex) throws RrdException, IOException; - - abstract double getMaxValue(int dsIndex) throws RrdException, IOException; - - // datasource state - abstract double getLastValue(int dsIndex) throws RrdException, IOException; - - abstract double getAccumValue(int dsIndex) throws RrdException, IOException; - - abstract long getNanSeconds(int dsIndex) throws RrdException, IOException; - - // archive - abstract String getConsolFun(int arcIndex) throws RrdException, IOException; - - abstract double getXff(int arcIndex) throws RrdException, IOException; - - abstract int getSteps(int arcIndex) throws RrdException, IOException; - - abstract int getRows(int arcIndex) throws RrdException, IOException; - - // archive state - abstract double getStateAccumValue(int arcIndex, int dsIndex) throws RrdException, IOException; - - abstract int getStateNanSteps(int arcIndex, int dsIndex) throws RrdException, IOException; - - abstract double[] getValues(int arcIndex, int dsIndex) throws RrdException, IOException,RrdException; - - long getEstimatedSize() throws RrdException, IOException { - int dsCount = getDsCount(); - int arcCount = getArcCount(); - int rowCount = 0; - for (int i = 0; i < arcCount; i++) { - rowCount += getRows(i); - } - return RrdDef.calculateSize(dsCount, arcCount, rowCount); - } - - void release() throws RrdException, IOException { - // NOP - } - -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/core/Datasource.java b/apps/jrobin/java/src/org/jrobin/core/Datasource.java deleted file mode 100644 index 3aca8d3d45572919642584c7d3b9631a6b401d94..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/Datasource.java +++ /dev/null @@ -1,497 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -/** - * Class to represent single datasource within RRD. Each datasource object holds the - * following information: datasource definition (once set, never changed) and - * datasource state variables (changed whenever RRD gets updated). - * <p> - * Normally, you don't need to manipluate Datasource objects directly, it's up to - * JRobin framework to do it for you. - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ - -public class Datasource implements RrdUpdater, DsTypes { - private static final double MAX_32_BIT = Math.pow(2, 32); - private static final double MAX_64_BIT = Math.pow(2, 64); - - private RrdDb parentDb; - // definition - private RrdString dsName, dsType; - private RrdLong heartbeat; - private RrdDouble minValue, maxValue; - - // cache - private String m_primitiveDsName = null; - private String m_primitiveDsType = null; - - // state variables - private RrdDouble lastValue; - private RrdLong nanSeconds; - private RrdDouble accumValue; - - Datasource(final RrdDb parentDb, final DsDef dsDef) throws IOException { - boolean shouldInitialize = dsDef != null; - this.parentDb = parentDb; - dsName = new RrdString(this); - dsType = new RrdString(this); - heartbeat = new RrdLong(this); - minValue = new RrdDouble(this); - maxValue = new RrdDouble(this); - lastValue = new RrdDouble(this); - accumValue = new RrdDouble(this); - nanSeconds = new RrdLong(this); - if (shouldInitialize) { - dsName.set(dsDef.getDsName()); - m_primitiveDsName = null; - dsType.set(dsDef.getDsType()); - m_primitiveDsType = null; - heartbeat.set(dsDef.getHeartbeat()); - minValue.set(dsDef.getMinValue()); - maxValue.set(dsDef.getMaxValue()); - lastValue.set(Double.NaN); - accumValue.set(0.0); - final Header header = parentDb.getHeader(); - nanSeconds.set(header.getLastUpdateTime() % header.getStep()); - } - } - - Datasource(final RrdDb parentDb, final DataImporter reader, final int dsIndex) throws IOException, RrdException { - this(parentDb, null); - dsName.set(reader.getDsName(dsIndex)); - m_primitiveDsName = null; - dsType.set(reader.getDsType(dsIndex)); - m_primitiveDsType = null; - heartbeat.set(reader.getHeartbeat(dsIndex)); - minValue.set(reader.getMinValue(dsIndex)); - maxValue.set(reader.getMaxValue(dsIndex)); - lastValue.set(reader.getLastValue(dsIndex)); - accumValue.set(reader.getAccumValue(dsIndex)); - nanSeconds.set(reader.getNanSeconds(dsIndex)); - } - - String dump() throws IOException { - return "== DATASOURCE ==\n" + - "DS:" + dsName.get() + ":" + dsType.get() + ":" + - heartbeat.get() + ":" + minValue.get() + ":" + - maxValue.get() + "\nlastValue:" + lastValue.get() + - " nanSeconds:" + nanSeconds.get() + - " accumValue:" + accumValue.get() + "\n"; - } - - /** - * Returns datasource name. - * - * @return Datasource name - * @throws IOException Thrown in case of I/O error - */ - public String getDsName() throws IOException { - if (m_primitiveDsName == null) { - m_primitiveDsName = dsName.get(); - } - return m_primitiveDsName; - } - - /** - * Returns datasource type (GAUGE, COUNTER, DERIVE, ABSOLUTE). - * - * @return Datasource type. - * @throws IOException Thrown in case of I/O error - */ - public String getDsType() throws IOException { - if (m_primitiveDsType == null) { - m_primitiveDsType = dsType.get(); - } - return m_primitiveDsType; - } - - /** - * Returns datasource heartbeat - * - * @return Datasource heartbeat - * @throws IOException Thrown in case of I/O error - */ - - public long getHeartbeat() throws IOException { - return heartbeat.get(); - } - - /** - * Returns mimimal allowed value for this datasource. - * - * @return Minimal value allowed. - * @throws IOException Thrown in case of I/O error - */ - public double getMinValue() throws IOException { - return minValue.get(); - } - - /** - * Returns maximal allowed value for this datasource. - * - * @return Maximal value allowed. - * @throws IOException Thrown in case of I/O error - */ - public double getMaxValue() throws IOException { - return maxValue.get(); - } - - /** - * Returns last known value of the datasource. - * - * @return Last datasource value. - * @throws IOException Thrown in case of I/O error - */ - public double getLastValue() throws IOException { - return lastValue.get(); - } - - /** - * Returns value this datasource accumulated so far. - * - * @return Accumulated datasource value. - * @throws IOException Thrown in case of I/O error - */ - public double getAccumValue() throws IOException { - return accumValue.get(); - } - - /** - * Returns the number of accumulated NaN seconds. - * - * @return Accumulated NaN seconds. - * @throws IOException Thrown in case of I/O error - */ - public long getNanSeconds() throws IOException { - return nanSeconds.get(); - } - - void process(final long newTime, final double newValue) throws IOException, RrdException { - final Header header = parentDb.getHeader(); - final long step = header.getStep(); - final long oldTime = header.getLastUpdateTime(); - final long startTime = Util.normalize(oldTime, step); - final long endTime = startTime + step; - final double oldValue = lastValue.get(); - final double updateValue = calculateUpdateValue(oldTime, oldValue, newTime, newValue); - if (newTime < endTime) { - accumulate(oldTime, newTime, updateValue); - } - else { - // should store something - final long boundaryTime = Util.normalize(newTime, step); - accumulate(oldTime, boundaryTime, updateValue); - final double value = calculateTotal(startTime, boundaryTime); - // how many updates? - final long numSteps = (boundaryTime - endTime) / step + 1L; - // ACTION! - parentDb.archive(this, value, numSteps); - // cleanup - nanSeconds.set(0); - accumValue.set(0.0); - accumulate(boundaryTime, newTime, updateValue); - } - } - - private double calculateUpdateValue(final long oldTime, final double oldValue, final long newTime, final double newValue) throws IOException { - double updateValue = Double.NaN; - if (newTime - oldTime <= heartbeat.get()) { - final String type = dsType.get(); - if (type.equals(DT_GAUGE)) { - updateValue = newValue; - } - else if (type.equals(DT_ABSOLUTE)) { - if (!Double.isNaN(newValue)) { - updateValue = newValue / (newTime - oldTime); - } - } - else if (type.equals(DT_DERIVE)) { - if (!Double.isNaN(newValue) && !Double.isNaN(oldValue)) { - updateValue = (newValue - oldValue) / (newTime - oldTime); - } - } - else if (type.equals(DT_COUNTER)) { - if (!Double.isNaN(newValue) && !Double.isNaN(oldValue)) { - double diff = newValue - oldValue; - if (diff < 0) { - diff += MAX_32_BIT; - } - if (diff < 0) { - diff += MAX_64_BIT - MAX_32_BIT; - } - if (diff >= 0) { - updateValue = diff / (newTime - oldTime); - } - } - } - if (!Double.isNaN(updateValue)) { - final double minVal = minValue.get(); - final double maxVal = maxValue.get(); - if (!Double.isNaN(minVal) && updateValue < minVal) { - updateValue = Double.NaN; - } - if (!Double.isNaN(maxVal) && updateValue > maxVal) { - updateValue = Double.NaN; - } - } - } - lastValue.set(newValue); - return updateValue; - } - - private void accumulate(final long oldTime, final long newTime, final double updateValue) throws IOException { - if (Double.isNaN(updateValue)) { - nanSeconds.set(nanSeconds.get() + (newTime - oldTime)); - } - else { - accumValue.set(accumValue.get() + updateValue * (newTime - oldTime)); - } - } - - private double calculateTotal(final long startTime, final long boundaryTime) throws IOException { - double totalValue = Double.NaN; - final long validSeconds = boundaryTime - startTime - nanSeconds.get(); - if (nanSeconds.get() <= heartbeat.get() && validSeconds > 0) { - totalValue = accumValue.get() / validSeconds; - } - // IMPORTANT: - // if datasource name ends with "!", we'll send zeros instead of NaNs - // this might be handy from time to time - if (Double.isNaN(totalValue) && dsName.get().endsWith(DsDef.FORCE_ZEROS_FOR_NANS_SUFFIX)) { - totalValue = 0D; - } - return totalValue; - } - - void appendXml(final XmlWriter writer) throws IOException { - writer.startTag("ds"); - writer.writeTag("name", dsName.get()); - writer.writeTag("type", dsType.get()); - writer.writeTag("minimal_heartbeat", heartbeat.get()); - writer.writeTag("min", minValue.get()); - writer.writeTag("max", maxValue.get()); - writer.writeComment("PDP Status"); - writer.writeTag("last_ds", lastValue.get(), "UNKN"); - writer.writeTag("value", accumValue.get()); - writer.writeTag("unknown_sec", nanSeconds.get()); - writer.closeTag(); // ds - } - - /** - * Copies object's internal state to another Datasource object. - * - * @param other New Datasource object to copy state to - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if supplied argument is not a Datasource object - */ - public void copyStateTo(final RrdUpdater other) throws IOException, RrdException { - if (!(other instanceof Datasource)) { - throw new RrdException("Cannot copy Datasource object to " + other.getClass().getName()); - } - final Datasource datasource = (Datasource) other; - if (!datasource.dsName.get().equals(dsName.get())) { - throw new RrdException("Incomaptible datasource names"); - } - if (!datasource.dsType.get().equals(dsType.get())) { - throw new RrdException("Incomaptible datasource types"); - } - datasource.lastValue.set(lastValue.get()); - datasource.nanSeconds.set(nanSeconds.get()); - datasource.accumValue.set(accumValue.get()); - } - - /** - * Returns index of this Datasource object in the RRD. - * - * @return Datasource index in the RRD. - * @throws IOException Thrown in case of I/O error - */ - public int getDsIndex() throws IOException { - try { - return parentDb.getDsIndex(dsName.get()); - } - catch (final RrdException e) { - return -1; - } - } - - /** - * Sets datasource heartbeat to a new value. - * - * @param heartbeat New heartbeat value - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if invalid (non-positive) heartbeat value is specified. - */ - public void setHeartbeat(final long heartbeat) throws RrdException, IOException { - if (heartbeat < 1L) { - throw new RrdException("Invalid heartbeat specified: " + heartbeat); - } - this.heartbeat.set(heartbeat); - } - - /** - * Sets datasource name to a new value - * - * @param newDsName New datasource name - * @throws RrdException Thrown if invalid data source name is specified (name too long, or - * name already defined in the RRD - * @throws IOException Thrown in case of I/O error - */ - public void setDsName(final String newDsName) throws RrdException, IOException { - if (newDsName.length() > RrdString.STRING_LENGTH) { - throw new RrdException("Invalid datasource name specified: " + newDsName); - } - if (parentDb.containsDs(newDsName)) { - throw new RrdException("Datasource already defined in this RRD: " + newDsName); - } - dsName.set(newDsName); - m_primitiveDsName = null; - } - - public void setDsType(final String newDsType) throws RrdException, IOException { - if (!DsDef.isValidDsType(newDsType)) { - throw new RrdException("Invalid datasource type: " + newDsType); - } - // set datasource type - this.dsType.set(newDsType); - m_primitiveDsType = null; - // reset datasource status - lastValue.set(Double.NaN); - accumValue.set(0.0); - // reset archive status - final int dsIndex = parentDb.getDsIndex(dsName.get()); - final Archive[] archives = parentDb.getArchives(); - for (final Archive archive : archives) { - archive.getArcState(dsIndex).setAccumValue(Double.NaN); - } - } - - /** - * Sets minimum allowed value for this datasource. If <code>filterArchivedValues</code> - * argment is set to true, all archived values less then <code>minValue</code> will - * be fixed to NaN. - * - * @param minValue New minimal value. Specify <code>Double.NaN</code> if no minimal - * value should be set - * @param filterArchivedValues true, if archived datasource values should be fixed; - * false, otherwise. - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if invalid minValue was supplied (not less then maxValue) - */ - public void setMinValue(final double minValue, final boolean filterArchivedValues) throws IOException, RrdException { - final double maxValue = this.maxValue.get(); - if (!Double.isNaN(minValue) && !Double.isNaN(maxValue) && minValue >= maxValue) { - throw new RrdException("Invalid min/max values: " + minValue + "/" + maxValue); - } - this.minValue.set(minValue); - if (!Double.isNaN(minValue) && filterArchivedValues) { - final int dsIndex = getDsIndex(); - final Archive[] archives = parentDb.getArchives(); - for (final Archive archive : archives) { - archive.getRobin(dsIndex).filterValues(minValue, Double.NaN); - } - } - } - - /** - * Sets maximum allowed value for this datasource. If <code>filterArchivedValues</code> - * argment is set to true, all archived values greater then <code>maxValue</code> will - * be fixed to NaN. - * - * @param maxValue New maximal value. Specify <code>Double.NaN</code> if no max - * value should be set. - * @param filterArchivedValues true, if archived datasource values should be fixed; - * false, otherwise. - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if invalid maxValue was supplied (not greater then minValue) - */ - public void setMaxValue(final double maxValue, final boolean filterArchivedValues) throws IOException, RrdException { - final double minValue = this.minValue.get(); - if (!Double.isNaN(minValue) && !Double.isNaN(maxValue) && minValue >= maxValue) { - throw new RrdException("Invalid min/max values: " + minValue + "/" + maxValue); - } - this.maxValue.set(maxValue); - if (!Double.isNaN(maxValue) && filterArchivedValues) { - final int dsIndex = getDsIndex(); - final Archive[] archives = parentDb.getArchives(); - for (final Archive archive : archives) { - archive.getRobin(dsIndex).filterValues(Double.NaN, maxValue); - } - } - } - - /** - * Sets min/max values allowed for this datasource. If <code>filterArchivedValues</code> - * argment is set to true, all archived values less then <code>minValue</code> or - * greater then <code>maxValue</code> will be fixed to NaN. - * - * @param minValue New minimal value. Specify <code>Double.NaN</code> if no min - * value should be set. - * @param maxValue New maximal value. Specify <code>Double.NaN</code> if no max - * value should be set. - * @param filterArchivedValues true, if archived datasource values should be fixed; - * false, otherwise. - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if invalid min/max values were supplied - */ - public void setMinMaxValue(final double minValue, final double maxValue, final boolean filterArchivedValues) throws IOException, RrdException { - if (!Double.isNaN(minValue) && !Double.isNaN(maxValue) && minValue >= maxValue) { - throw new RrdException("Invalid min/max values: " + minValue + "/" + maxValue); - } - this.minValue.set(minValue); - this.maxValue.set(maxValue); - if (!(Double.isNaN(minValue) && Double.isNaN(maxValue)) && filterArchivedValues) { - final int dsIndex = getDsIndex(); - final Archive[] archives = parentDb.getArchives(); - for (final Archive archive : archives) { - archive.getRobin(dsIndex).filterValues(minValue, maxValue); - } - } - } - - /** - * Returns the underlying storage (backend) object which actually performs all - * I/O operations. - * - * @return I/O backend object - */ - public RrdBackend getRrdBackend() { - return parentDb.getRrdBackend(); - } - - /** - * Required to implement RrdUpdater interface. You should never call this method directly. - * - * @return Allocator object - */ - public RrdAllocator getRrdAllocator() { - return parentDb.getRrdAllocator(); - } - - public String toString() { - return getClass().getName() + "@" + Integer.toHexString(hashCode()) + "[parentDb=" + parentDb - + ",dsName=" + dsName + ",dsType=" + dsType + ",heartbeat=" + heartbeat - + ",minValue=" + minValue + ",maxValue=" + maxValue + "]"; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/DsDef.java b/apps/jrobin/java/src/org/jrobin/core/DsDef.java deleted file mode 100644 index 362c9d373ec3e659c0ac3fb3e315d3043d9ac8bc..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/DsDef.java +++ /dev/null @@ -1,205 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -/** - * Class to represent single data source definition within the RRD. - * Datasource definition consists of the following five elements: - * <p> - * <ul> - * <li>data source name - * <li>data soruce type - * <li>heartbeat - * <li>minimal value - * <li>maximal value - * </ul> - * <p> - * For the complete explanation of all source definition parameters, see RRDTool's - * <a href="../../../../man/rrdcreate.html" target="man">rrdcreate man page</a>. - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ -public class DsDef implements DsTypes { - /** - * array of valid source types - */ - public static final String[] DS_TYPES = {DT_GAUGE, DT_COUNTER, DT_DERIVE, DT_ABSOLUTE}; - static final String FORCE_ZEROS_FOR_NANS_SUFFIX = "!"; - - private String dsName, dsType; - private long heartbeat; - private double minValue, maxValue; - - /** - * Creates new data source definition object. This object should be passed as argument - * to {@link RrdDef#addDatasource(DsDef) addDatasource()} - * method of {@link RrdDb RrdDb} object. - * <p> - * For the complete explanation of all source definition parameters, see RRDTool's - * <a href="../../../../man/rrdcreate.html" target="man">rrdcreate man page</a>. - * <p> - * <b>IMPORTANT NOTE:</b> If datasource name ends with '!', corresponding archives will never - * store NaNs as datasource values. In that case, NaN datasource values will be silently - * replaced with zeros by the framework. - * - * @param dsName Data source name. - * @param dsType Data source type. Valid values are "COUNTER", "GAUGE", "DERIVE" - * and "ABSOLUTE" (these string constants are conveniently defined in the - * {@link DsTypes} class). - * @param heartbeat Hearbeat - * @param minValue Minimal value. Use <code>Double.NaN</code> if unknown. - * @param maxValue Maximal value. Use <code>Double.NaN</code> if unknown. - * @throws RrdException Thrown if any parameter has illegal value. - */ - public DsDef(final String dsName, final String dsType, final long heartbeat, final double minValue, final double maxValue) throws RrdException { - this.dsName = dsName; - this.dsType = dsType; - this.heartbeat = heartbeat; - this.minValue = minValue; - this.maxValue = maxValue; - validate(); - } - - /** - * Returns data source name. - * - * @return Data source name. - */ - public String getDsName() { - return dsName; - } - - /** - * Returns source type. - * - * @return Source type ("COUNTER", "GAUGE", "DERIVE" or "ABSOLUTE"). - */ - public String getDsType() { - return dsType; - } - - /** - * Returns source heartbeat. - * - * @return Source heartbeat. - */ - public long getHeartbeat() { - return heartbeat; - } - - /** - * Returns minimal calculated source value. - * - * @return Minimal value. - */ - public double getMinValue() { - return minValue; - } - - /** - * Returns maximal calculated source value. - * - * @return Maximal value. - */ - public double getMaxValue() { - return maxValue; - } - - private void validate() throws RrdException { - if (dsName == null) { - throw new RrdException("Null datasource name specified"); - } - if (dsName.length() == 0) { - throw new RrdException("Datasource name length equal to zero"); - } - if (dsName.length() > RrdPrimitive.STRING_LENGTH) { - throw new RrdException("Datasource name [" + dsName + "] to long (" + - dsName.length() + " chars found, only " + RrdPrimitive.STRING_LENGTH + " allowed"); - } - if (!isValidDsType(dsType)) { - throw new RrdException("Invalid datasource type specified: " + dsType); - } - if (heartbeat <= 0) { - throw new RrdException("Invalid heartbeat, must be positive: " + heartbeat); - } - if (!Double.isNaN(minValue) && !Double.isNaN(maxValue) && minValue >= maxValue) { - throw new RrdException("Invalid min/max values specified: " + - minValue + "/" + maxValue); - } - } - - /** - * Checks if function argument represents valid source type. - * - * @param dsType Source type to be checked. - * @return <code>true</code> if <code>dsType</code> is valid type, - * <code>false</code> otherwise. - */ - public static boolean isValidDsType(final String dsType) { - for (final String type : DS_TYPES) { - if (type.equals(dsType)) { - return true; - } - } - return false; - } - - /** - * Returns string representing source definition (RRDTool format). - * - * @return String containing all data source definition parameters. - */ - public String dump() { - return "DS:" + dsName + ":" + dsType + ":" + heartbeat + - ":" + Util.formatDouble(minValue, "U", false) + - ":" + Util.formatDouble(maxValue, "U", false); - } - - /** - * Checks if two datasource definitions are equal. - * Source definitions are treated as equal if they have the same source name. - * It is not possible to create RRD with two equal archive definitions. - * - * @param obj Archive definition to compare with. - * @return <code>true</code> if archive definitions are equal, - * <code>false</code> otherwise. - */ - public boolean equals(final Object obj) { - if (obj instanceof DsDef) { - final DsDef dsObj = (DsDef) obj; - return dsName.equals(dsObj.dsName); - } - return false; - } - - public int hashCode() { - return dsName.hashCode() * 47; - } - - boolean exactlyEqual(final DsDef def) { - return dsName.equals(def.dsName) && dsType.equals(def.dsType) && - heartbeat == def.heartbeat && Util.equal(minValue, def.minValue) && - Util.equal(maxValue, def.maxValue); - } - - public String toString() { - return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + "[" + dump() + "]"; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/DsTypes.java b/apps/jrobin/java/src/org/jrobin/core/DsTypes.java deleted file mode 100644 index 31330b043ca7888f9e4e43c5bde74ce2b5941c40..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/DsTypes.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core; - -/** - * Simple interface to represent available datasource types. - */ -public interface DsTypes { - /** - * Constant to represent GAUGE datasource type - */ - public static final String DT_GAUGE = "GAUGE"; - - /** - * Constant to represent COUNTER datasource type - */ - public static final String DT_COUNTER = "COUNTER"; - - /** - * Constant to represent DERIVE datasource type - */ - public static final String DT_DERIVE = "DERIVE"; - - /** - * Constant to represent ABSOLUTE datasource type - */ - public static final String DT_ABSOLUTE = "ABSOLUTE"; -} diff --git a/apps/jrobin/java/src/org/jrobin/core/FetchData.java b/apps/jrobin/java/src/org/jrobin/core/FetchData.java deleted file mode 100644 index cc57a87a42c436bc58c87d5d9ea7edb7efa996ee..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/FetchData.java +++ /dev/null @@ -1,529 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import org.jrobin.data.Aggregates; -import org.jrobin.data.DataProcessor; - -import java.io.ByteArrayOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -/** - * Class used to represent data fetched from the RRD. - * Object of this class is created when the method - * {@link FetchRequest#fetchData() fetchData()} is - * called on a {@link FetchRequest FetchRequest} object. - * <p> - * Data returned from the RRD is, simply, just one big table filled with - * timestamps and corresponding datasource values. - * Use {@link #getRowCount() getRowCount()} method to count the number - * of returned timestamps (table rows). - * <p> - * The first table column is filled with timestamps. Time intervals - * between consecutive timestamps are guaranteed to be equal. Use - * {@link #getTimestamps() getTimestamps()} method to get an array of - * timestamps returned. - * <p> - * Remaining columns are filled with datasource values for the whole timestamp range, - * on a column-per-datasource basis. Use {@link #getColumnCount() getColumnCount()} to find - * the number of datasources and {@link #getValues(int) getValues(i)} method to obtain - * all values for the i-th datasource. Returned datasource values correspond to - * the values returned with {@link #getTimestamps() getTimestamps()} method. - */ -public class FetchData implements ConsolFuns { - // anything fuuny will do - private static final String RPN_SOURCE_NAME = "WHERE THE SPEECHLES UNITE IN A SILENT ACCORD"; - - private FetchRequest request; - private String[] dsNames; - private long[] timestamps; - private double[][] values; - - private Archive matchingArchive; - private long arcStep; - private long arcEndTime; - - FetchData(Archive matchingArchive, FetchRequest request) throws IOException { - this.matchingArchive = matchingArchive; - this.arcStep = matchingArchive.getArcStep(); - this.arcEndTime = matchingArchive.getEndTime(); - this.dsNames = request.getFilter(); - if (this.dsNames == null) { - this.dsNames = matchingArchive.getParentDb().getDsNames(); - } - this.request = request; - } - - void setTimestamps(long[] timestamps) { - this.timestamps = timestamps; - } - - void setValues(double[][] values) { - this.values = values; - } - - /** - * Returns the number of rows fetched from the corresponding RRD. - * Each row represents datasource values for the specific timestamp. - * - * @return Number of rows. - */ - public int getRowCount() { - return timestamps.length; - } - - /** - * Returns the number of columns fetched from the corresponding RRD. - * This number is always equal to the number of datasources defined - * in the RRD. Each column represents values of a single datasource. - * - * @return Number of columns (datasources). - */ - public int getColumnCount() { - return dsNames.length; - } - - /** - * Returns an array of timestamps covering the whole range specified in the - * {@link FetchRequest FetchReguest} object. - * - * @return Array of equidistant timestamps. - */ - public long[] getTimestamps() { - return timestamps; - } - - /** - * Returns the step with which this data was fetched. - * - * @return Step as long. - */ - public long getStep() { - return timestamps[1] - timestamps[0]; - } - - /** - * Returns all archived values for a single datasource. - * Returned values correspond to timestamps - * returned with {@link #getTimestamps() getTimestamps()} method. - * - * @param dsIndex Datasource index. - * @return Array of single datasource values. - */ - public double[] getValues(int dsIndex) { - return values[dsIndex]; - } - - /** - * Returns all archived values for all datasources. - * Returned values correspond to timestamps - * returned with {@link #getTimestamps() getTimestamps()} method. - * - * @return Two-dimensional aray of all datasource values. - */ - public double[][] getValues() { - return values; - } - - /** - * Returns all archived values for a single datasource. - * Returned values correspond to timestamps - * returned with {@link #getTimestamps() getTimestamps()} method. - * - * @param dsName Datasource name. - * @return Array of single datasource values. - * @throws RrdException Thrown if no matching datasource name is found. - */ - public double[] getValues(String dsName) throws RrdException { - for (int dsIndex = 0; dsIndex < getColumnCount(); dsIndex++) { - if (dsName.equals(dsNames[dsIndex])) { - return getValues(dsIndex); - } - } - throw new RrdException("Datasource [" + dsName + "] not found"); - } - - /** - * Returns a set of values created by applying RPN expression to the fetched data. - * For example, if you have two datasources named <code>x</code> and <code>y</code> - * in this FetchData and you want to calculate values for <code>(x+y)/2</code> use something like: - * <p> - * <code>getRpnValues("x,y,+,2,/");</code> - * - * @param rpnExpression RRDTool-like RPN expression - * @return Calculated values - * @throws RrdException Thrown if invalid RPN expression is supplied - */ - public double[] getRpnValues(String rpnExpression) throws RrdException { - DataProcessor dataProcessor = createDataProcessor(rpnExpression); - return dataProcessor.getValues(RPN_SOURCE_NAME); - } - - /** - * Returns {@link FetchRequest FetchRequest} object used to create this FetchData object. - * - * @return Fetch request object. - */ - public FetchRequest getRequest() { - return request; - } - - /** - * Returns the first timestamp in this FetchData object. - * - * @return The smallest timestamp. - */ - public long getFirstTimestamp() { - return timestamps[0]; - } - - /** - * Returns the last timestamp in this FecthData object. - * - * @return The biggest timestamp. - */ - public long getLastTimestamp() { - return timestamps[timestamps.length - 1]; - } - - /** - * Returns Archive object which is determined to be the best match for the - * timestamps specified in the fetch request. All datasource values are obtained - * from round robin archives belonging to this archive. - * - * @return Matching archive. - */ - public Archive getMatchingArchive() { - return matchingArchive; - } - - /** - * Returns array of datasource names found in the corresponding RRD. If the request - * was filtered (data was fetched only for selected datasources), only datasources selected - * for fetching are returned. - * - * @return Array of datasource names. - */ - public String[] getDsNames() { - return dsNames; - } - - /** - * Retrieve the table index number of a datasource by name. Names are case sensitive. - * - * @param dsName Name of the datasource for which to find the index. - * @return Index number of the datasources in the value table. - */ - public int getDsIndex(String dsName) { - // Let's assume the table of dsNames is always small, so it is not necessary to use a hashmap for lookups - for (int i = 0; i < dsNames.length; i++) { - if (dsNames[i].equals(dsName)) { - return i; - } - } - return -1; // Datasource not found ! - } - - /** - * Dumps the content of the whole FetchData object. Useful for debugging. - * - * @return String containing the contents of this object, for debugging. - */ - public String dump() { - StringBuffer buffer = new StringBuffer(""); - for (int row = 0; row < getRowCount(); row++) { - buffer.append(timestamps[row]); - buffer.append(": "); - for (int dsIndex = 0; dsIndex < getColumnCount(); dsIndex++) { - buffer.append(Util.formatDouble(values[dsIndex][row], true)); - buffer.append(" "); - } - buffer.append("\n"); - } - return buffer.toString(); - } - - /** - * Returns string representing fetched data in a RRDTool-like form. - * - * @return Fetched data as a string in a rrdfetch-like output form. - */ - public String toString() { - // print header row - StringBuffer buff = new StringBuffer(); - buff.append(padWithBlanks("", 10)); - buff.append(" "); - for (String dsName : dsNames) { - buff.append(padWithBlanks(dsName, 18)); - } - buff.append("\n \n"); - for (int i = 0; i < timestamps.length; i++) { - buff.append(padWithBlanks("" + timestamps[i], 10)); - buff.append(":"); - for (int j = 0; j < dsNames.length; j++) { - double value = values[j][i]; - String valueStr = Double.isNaN(value) ? "nan" : Util.formatDouble(value); - buff.append(padWithBlanks(valueStr, 18)); - } - buff.append("\n"); - } - return buff.toString(); - } - - private static String padWithBlanks(String input, int width) { - StringBuffer buff = new StringBuffer(""); - int diff = width - input.length(); - while (diff-- > 0) { - buff.append(' '); - } - buff.append(input); - return buff.toString(); - } - - /** - * Returns single aggregated value from the fetched data for a single datasource. - * - * @param dsName Datasource name - * @param consolFun Consolidation function to be applied to fetched datasource values. - * Valid consolidation functions are "MIN", "MAX", "LAST", "FIRST", "AVERAGE" and "TOTAL" - * (these string constants are conveniently defined in the {@link ConsolFuns} class) - * @return MIN, MAX, LAST, FIRST, AVERAGE or TOTAL value calculated from the fetched data - * for the given datasource name - * @throws RrdException Thrown if the given datasource name cannot be found in fetched data. - */ - public double getAggregate(String dsName, String consolFun) throws RrdException { - DataProcessor dp = createDataProcessor(null); - return dp.getAggregate(dsName, consolFun); - } - - /** - * Returns aggregated value from the fetched data for a single datasource. - * Before applying aggregation functions, specified RPN expression is applied to fetched data. - * For example, if you have a gauge datasource named 'foots' but you want to find the maximum - * fetched value in meters use something like: - * <p> - * <code>getAggregate("foots", "MAX", "foots,0.3048,*");</code> - * - * @param dsName Datasource name - * @param consolFun Consolidation function (MIN, MAX, LAST, FIRST, AVERAGE or TOTAL) - * @param rpnExpression RRDTool-like RPN expression - * @return Aggregated value - * @throws RrdException Thrown if the given datasource name cannot be found in fetched data, or if - * invalid RPN expression is supplied - * @throws IOException Thrown in case of I/O error (unlikely to happen) - * @deprecated This method is preserved just for backward compatibility. - */ - public double getAggregate(String dsName, String consolFun, String rpnExpression) - throws RrdException, IOException { - // for backward compatibility - rpnExpression = rpnExpression.replaceAll("value", dsName); - return getRpnAggregate(rpnExpression, consolFun); - } - - /** - * Returns aggregated value for a set of values calculated by applying an RPN expression to the - * fetched data. For example, if you have two datasources named <code>x</code> and <code>y</code> - * in this FetchData and you want to calculate MAX value of <code>(x+y)/2</code> use something like: - * <p> - * <code>getRpnAggregate("x,y,+,2,/", "MAX");</code> - * - * @param rpnExpression RRDTool-like RPN expression - * @param consolFun Consolidation function (MIN, MAX, LAST, FIRST, AVERAGE or TOTAL) - * @return Aggregated value - * @throws RrdException Thrown if invalid RPN expression is supplied - */ - public double getRpnAggregate(String rpnExpression, String consolFun) throws RrdException { - DataProcessor dataProcessor = createDataProcessor(rpnExpression); - return dataProcessor.getAggregate(RPN_SOURCE_NAME, consolFun); - } - - /** - * Returns all aggregated values (MIN, MAX, LAST, FIRST, AVERAGE or TOTAL) calculated from the fetched data - * for a single datasource. - * - * @param dsName Datasource name. - * @return Simple object containing all aggregated values. - * @throws RrdException Thrown if the given datasource name cannot be found in the fetched data. - */ - public Aggregates getAggregates(String dsName) throws RrdException { - DataProcessor dataProcessor = createDataProcessor(null); - return dataProcessor.getAggregates(dsName); - } - - /** - * Returns all aggregated values for a set of values calculated by applying an RPN expression to the - * fetched data. For example, if you have two datasources named <code>x</code> and <code>y</code> - * in this FetchData and you want to calculate MIN, MAX, LAST, FIRST, AVERAGE and TOTAL value - * of <code>(x+y)/2</code> use something like: - * <p> - * <code>getRpnAggregates("x,y,+,2,/");</code> - * - * @param rpnExpression RRDTool-like RPN expression - * @return Object containing all aggregated values - * @throws RrdException Thrown if invalid RPN expression is supplied - * @throws IOException Thrown in case of I/O error - */ - public Aggregates getRpnAggregates(String rpnExpression) throws RrdException, IOException { - DataProcessor dataProcessor = createDataProcessor(rpnExpression); - return dataProcessor.getAggregates(RPN_SOURCE_NAME); - } - - /** - * Used by ISPs which charge for bandwidth utilization on a "95th percentile" basis. - * <p> - * The 95th percentile is the highest source value left when the top 5% of a numerically sorted set - * of source data is discarded. It is used as a measure of the peak value used when one discounts - * a fair amount for transitory spikes. This makes it markedly different from the average. - * <p> - * Read more about this topic at: - * <a href="http://www.red.net/support/resourcecentre/leasedline/percentile.php">Rednet</a> or<br> - * <a href="http://www.bytemark.co.uk/support/tech/95thpercentile.html">Bytemark</a>. - * - * @param dsName Datasource name - * @return 95th percentile of fetched source values - * @throws RrdException Thrown if invalid source name is supplied - */ - public double get95Percentile(String dsName) throws RrdException { - DataProcessor dataProcessor = createDataProcessor(null); - return dataProcessor.get95Percentile(dsName); - } - - /** - * Same as {@link #get95Percentile(String)}, but for a set of values calculated with the given - * RPN expression. - * - * @param rpnExpression RRDTool-like RPN expression - * @return 95-percentile - * @throws RrdException Thrown if invalid RPN expression is supplied - */ - public double getRpn95Percentile(String rpnExpression) throws RrdException { - DataProcessor dataProcessor = createDataProcessor(rpnExpression); - return dataProcessor.get95Percentile(RPN_SOURCE_NAME); - } - - /** - * Dumps fetch data to output stream in XML format. - * - * @param outputStream Output stream to dump fetch data to - * @throws IOException Thrown in case of I/O error - */ - public void exportXml(OutputStream outputStream) throws IOException { - XmlWriter writer = new XmlWriter(outputStream); - writer.startTag("fetch_data"); - writer.startTag("request"); - writer.writeTag("file", request.getParentDb().getPath()); - writer.writeComment(Util.getDate(request.getFetchStart())); - writer.writeTag("start", request.getFetchStart()); - writer.writeComment(Util.getDate(request.getFetchEnd())); - writer.writeTag("end", request.getFetchEnd()); - writer.writeTag("resolution", request.getResolution()); - writer.writeTag("cf", request.getConsolFun()); - writer.closeTag(); // request - writer.startTag("datasources"); - for (String dsName : dsNames) { - writer.writeTag("name", dsName); - } - writer.closeTag(); // datasources - writer.startTag("data"); - for (int i = 0; i < timestamps.length; i++) { - writer.startTag("row"); - writer.writeComment(Util.getDate(timestamps[i])); - writer.writeTag("timestamp", timestamps[i]); - writer.startTag("values"); - for (int j = 0; j < dsNames.length; j++) { - writer.writeTag("v", values[j][i]); - } - writer.closeTag(); // values - writer.closeTag(); // row - } - writer.closeTag(); // data - writer.closeTag(); // fetch_data - writer.flush(); - } - - /** - * Dumps fetch data to file in XML format. - * - * @param filepath Path to destination file - * @throws IOException Thrown in case of I/O error - */ - public void exportXml(String filepath) throws IOException { - OutputStream outputStream = null; - try { - outputStream = new FileOutputStream(filepath); - exportXml(outputStream); - } - finally { - if (outputStream != null) { - outputStream.close(); - } - } - } - - /** - * Dumps fetch data in XML format. - * - * @return String containing XML formatted fetch data - * @throws IOException Thrown in case of I/O error - */ - public String exportXml() throws IOException { - ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - exportXml(outputStream); - return outputStream.toString(); - } - - /** - * Returns the step of the corresponding RRA archive - * - * @return Archive step in seconds - */ - public long getArcStep() { - return arcStep; - } - - /** - * Returns the timestamp of the last populated slot in the corresponding RRA archive - * - * @return Timestamp in seconds - */ - public long getArcEndTime() { - return arcEndTime; - } - - private DataProcessor createDataProcessor(String rpnExpression) throws RrdException { - DataProcessor dataProcessor = new DataProcessor(request.getFetchStart(), request.getFetchEnd()); - for (String dsName : dsNames) { - dataProcessor.addDatasource(dsName, this); - } - if (rpnExpression != null) { - dataProcessor.addDatasource(RPN_SOURCE_NAME, rpnExpression); - try { - dataProcessor.processData(); - } - catch (IOException ioe) { - // highly unlikely, since all datasources have already calculated values - throw new RuntimeException("Impossible error: " + ioe); - } - } - return dataProcessor; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/FetchRequest.java b/apps/jrobin/java/src/org/jrobin/core/FetchRequest.java deleted file mode 100644 index 5722acd9759f472c94b8ba50a3b72530a8e07887..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/FetchRequest.java +++ /dev/null @@ -1,196 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; -import java.util.Set; - -/** - * Class to represent fetch request. For the complete explanation of all - * fetch parameters consult RRDTool's - * <a href="../../../../man/rrdfetch.html" target="man">rrdfetch man page</a>. - * <p> - * You cannot create <code>FetchRequest</code> directly (no public constructor - * is provided). Use {@link RrdDb#createFetchRequest(String, long, long, long) - * createFetchRequest()} method of your {@link RrdDb RrdDb} object. - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ -public class FetchRequest { - private RrdDb parentDb; - private String consolFun; - private long fetchStart; - private long fetchEnd; - private long resolution; - private String[] filter; - - public FetchRequest(RrdDb parentDb, String consolFun, long fetchStart, long fetchEnd, long resolution) throws RrdException { - this.parentDb = parentDb; - this.consolFun = consolFun; - this.fetchStart = fetchStart; - this.fetchEnd = fetchEnd; - this.resolution = resolution; - validate(); - } - - /** - * Sets request filter in order to fetch data only for - * the specified array of datasources (datasource names). - * If not set (or set to null), fetched data will - * containt values of all datasources defined in the corresponding RRD. - * To fetch data only from selected - * datasources, specify an array of datasource names as method argument. - * - * @param filter Array of datsources (datsource names) to fetch data from. - */ - public void setFilter(String[] filter) { - this.filter = filter; - } - - /** - * Sets request filter in order to fetch data only for - * the specified set of datasources (datasource names). - * If the filter is not set (or set to null), fetched data will - * containt values of all datasources defined in the corresponding RRD. - * To fetch data only from selected - * datasources, specify a set of datasource names as method argument. - * - * @param filter Set of datsource names to fetch data for. - */ - public void setFilter(Set<String> filter) { - this.filter = filter.toArray(new String[0]); - } - - /** - * Sets request filter in order to fetch data only for - * a single datasource (datasource name). - * If not set (or set to null), fetched data will - * containt values of all datasources defined in the corresponding RRD. - * To fetch data for a single datasource only, - * specify an array of datasource names as method argument. - * - * @param filter Array of datsources (datsource names) to fetch data from. - */ - public void setFilter(String filter) { - this.filter = (filter == null) ? null : (new String[] {filter}); - } - - /** - * Returns request filter. See {@link #setFilter(String[]) setFilter()} for - * complete explanation. - * - * @return Request filter (array of datasource names), null if not set. - */ - public String[] getFilter() { - return filter; - } - - /** - * Returns consolitation function to be used during the fetch process. - * - * @return Consolidation function. - */ - public String getConsolFun() { - return consolFun; - } - - /** - * Returns starting timestamp to be used for the fetch request. - * - * @return Starting timstamp in seconds. - */ - public long getFetchStart() { - return fetchStart; - } - - /** - * Returns ending timestamp to be used for the fetch request. - * - * @return Ending timestamp in seconds. - */ - public long getFetchEnd() { - return fetchEnd; - } - - /** - * Returns fetch resolution to be used for the fetch request. - * - * @return Fetch resolution in seconds. - */ - public long getResolution() { - return resolution; - } - - private void validate() throws RrdException { - if (!ArcDef.isValidConsolFun(consolFun)) { - throw new RrdException("Invalid consolidation function in fetch request: " + consolFun); - } - if (fetchStart < 0) { - throw new RrdException("Invalid start time in fetch request: " + fetchStart); - } - if (fetchEnd < 0) { - throw new RrdException("Invalid end time in fetch request: " + fetchEnd); - } - if (fetchStart > fetchEnd) { - throw new RrdException("Invalid start/end time in fetch request: " + fetchStart + - " > " + fetchEnd); - } - if (resolution <= 0) { - throw new RrdException("Invalid resolution in fetch request: " + resolution); - } - } - - /** - * Dumps the content of fetch request using the syntax of RRDTool's fetch command. - * - * @return Fetch request dump. - */ - public String dump() { - return "fetch \"" + parentDb.getRrdBackend().getPath() + - "\" " + consolFun + " --start " + fetchStart + " --end " + fetchEnd + - (resolution > 1 ? " --resolution " + resolution : ""); - } - - String getRrdToolCommand() { - return dump(); - } - - /** - * Returns data from the underlying RRD and puts it in a single - * {@link FetchData FetchData} object. - * - * @return FetchData object filled with timestamps and datasource values. - * @throws RrdException Thrown in case of JRobin specific error. - * @throws IOException Thrown in case of I/O error. - */ - public FetchData fetchData() throws RrdException, IOException { - return parentDb.fetchData(this); - } - - /** - * Returns the underlying RrdDb object. - * - * @return RrdDb object used to create this FetchRequest object. - */ - public RrdDb getParentDb() { - return parentDb; - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/core/Header.java b/apps/jrobin/java/src/org/jrobin/core/Header.java deleted file mode 100644 index faecb02a8f9f5e6e2cf6a3c88bf4da6056f862b5..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/Header.java +++ /dev/null @@ -1,222 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -/** - * Class to represent RRD header. Header information is mainly static (once set, it - * cannot be changed), with the exception of last update time (this value is changed whenever - * RRD gets updated). - * <p> - * Normally, you don't need to manipulate the Header object directly - JRobin framework - * does it for you. - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a>* - */ -public class Header implements RrdUpdater { - static final int SIGNATURE_LENGTH = 2; - static final String SIGNATURE = "JR"; - - static final String DEFAULT_SIGNATURE = "JRobin, version 0.1"; - static final String RRDTOOL_VERSION = "0001"; - - private RrdDb parentDb; - - private RrdString signature; - private RrdLong step; - private RrdInt dsCount, arcCount; - private RrdLong lastUpdateTime; - private Long m_primitiveStep = null; - private Integer m_primitiveDsCount = null; - private Integer m_primitiveArcCount = null; - - Header(final RrdDb parentDb, final RrdDef rrdDef) throws IOException { - final boolean shouldInitialize = rrdDef != null; - this.parentDb = parentDb; - signature = new RrdString(this); // NOT constant, may NOT be cached - step = new RrdLong(this, true); // constant, may be cached - dsCount = new RrdInt(this, true); // constant, may be cached - arcCount = new RrdInt(this, true); // constant, may be cached - lastUpdateTime = new RrdLong(this); - if (shouldInitialize) { - signature.set(DEFAULT_SIGNATURE); - step.set(rrdDef.getStep()); - dsCount.set(rrdDef.getDsCount()); - arcCount.set(rrdDef.getArcCount()); - lastUpdateTime.set(rrdDef.getStartTime()); - } - } - - Header(final RrdDb parentDb, final DataImporter reader) throws IOException, RrdException { - this(parentDb, (RrdDef) null); - final String version = reader.getVersion(); - final int intVersion = Integer.parseInt(version); - if (intVersion > 3) { - throw new RrdException("Could not unserialize xml version " + version); - } - signature.set(DEFAULT_SIGNATURE); - step.set(reader.getStep()); - dsCount.set(reader.getDsCount()); - arcCount.set(reader.getArcCount()); - lastUpdateTime.set(reader.getLastUpdateTime()); - } - - /** - * Returns RRD signature. Initially, the returned string will be - * of the form <b><i>JRobin, version x.x</i></b>. Note: RRD format did not - * change since Jrobin 1.0.0 release (and probably never will). - * - * @return RRD signature - * @throws IOException Thrown in case of I/O error - */ - public String getSignature() throws IOException { - return signature.get(); - } - - public String getInfo() throws IOException { - return getSignature().substring(SIGNATURE_LENGTH); - } - - public void setInfo(String info) throws IOException { - if (info != null && info.length() > 0) { - signature.set(SIGNATURE + info); - } - else { - signature.set(SIGNATURE); - } - } - - /** - * Returns the last update time of the RRD. - * - * @return Timestamp (Unix epoch, no milliseconds) corresponding to the last update time. - * @throws IOException Thrown in case of I/O error - */ - public long getLastUpdateTime() throws IOException { - return lastUpdateTime.get(); - } - - /** - * Returns primary RRD time step. - * - * @return Primary time step in seconds - * @throws IOException Thrown in case of I/O error - */ - public long getStep() throws IOException { - if (m_primitiveStep == null) { - m_primitiveStep = step.get(); - } - return m_primitiveStep; - } - - /** - * Returns the number of datasources defined in the RRD. - * - * @return Number of datasources defined - * @throws IOException Thrown in case of I/O error - */ - public int getDsCount() throws IOException { - if (m_primitiveDsCount == null) { - m_primitiveDsCount = dsCount.get(); - } - return m_primitiveDsCount; - } - - /** - * Returns the number of archives defined in the RRD. - * - * @return Number of archives defined - * @throws IOException Thrown in case of I/O error - */ - public int getArcCount() throws IOException { - if (m_primitiveArcCount == null) { - m_primitiveArcCount = arcCount.get(); - } - return m_primitiveArcCount; - } - - public void setLastUpdateTime(final long lastUpdateTime) throws IOException { - this.lastUpdateTime.set(lastUpdateTime); - } - - String dump() throws IOException { - return "== HEADER ==\n" + - "signature:" + getSignature() + - " lastUpdateTime:" + getLastUpdateTime() + - " step:" + getStep() + - " dsCount:" + getDsCount() + - " arcCount:" + getArcCount() + "\n"; - } - - void appendXml(XmlWriter writer) throws IOException { - writer.writeComment(signature.get()); - writer.writeTag("version", RRDTOOL_VERSION); - writer.writeComment("Seconds"); - writer.writeTag("step", step.get()); - writer.writeComment(Util.getDate(lastUpdateTime.get())); - writer.writeTag("lastupdate", lastUpdateTime.get()); - } - - /** - * Copies object's internal state to another Header object. - * - * @param other New Header object to copy state to - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if supplied argument is not a Header object - */ - public void copyStateTo(final RrdUpdater other) throws IOException, RrdException { - if (!(other instanceof Header)) { - throw new RrdException( "Cannot copy Header object to " + other.getClass().getName()); - } - final Header header = (Header) other; - header.signature.set(signature.get()); - header.lastUpdateTime.set(lastUpdateTime.get()); - } - - /** - * Returns the underlying storage (backend) object which actually performs all - * I/O operations. - * - * @return I/O backend object - */ - public RrdBackend getRrdBackend() { - return parentDb.getRrdBackend(); - } - - boolean isJRobinHeader() throws IOException { - return signature.get().startsWith(SIGNATURE); - } - - void validateHeader() throws IOException, RrdException { - if (!isJRobinHeader()) { - throw new RrdException("Invalid file header. File [" + parentDb.getCanonicalPath() + "] is not a JRobin RRD file"); - } - } - - /** - * Required to implement RrdUpdater interface. You should never call this method directly. - * - * @return Allocator object - */ - public RrdAllocator getRrdAllocator() { - return parentDb.getRrdAllocator(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/Robin.java b/apps/jrobin/java/src/org/jrobin/core/Robin.java deleted file mode 100644 index 623bc80a9462881030b6dbe22dd328e1262697c7..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/Robin.java +++ /dev/null @@ -1,266 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -/** - * Class to represent archive values for a single datasource. Robin class is the heart of - * the so-called "round robin database" concept. Basically, each Robin object is a - * fixed length array of double values. Each double value reperesents consolidated, archived - * value for the specific timestamp. When the underlying array of double values gets completely - * filled, new values will replace the oldest ones. - * <p> - * Robin object does not hold values in memory - such object could be quite large. - * Instead of it, Robin reads them from the backend I/O only when necessary. - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ -public class Robin implements RrdUpdater { - private Archive parentArc; - private RrdInt pointer; - private RrdDoubleArray values; - private int rows; - - Robin(Archive parentArc, int rows, boolean shouldInitialize) throws IOException { - this.parentArc = parentArc; - this.pointer = new RrdInt(this); - this.values = new RrdDoubleArray(this, rows); - this.rows = rows; - if (shouldInitialize) { - pointer.set(0); - values.set(0, Double.NaN, rows); - } - } - - /** - * Fetches all archived values. - * - * @return Array of double archive values, starting from the oldest one. - * @throws IOException Thrown in case of I/O specific error. - */ - public double[] getValues() throws IOException { - return getValues(0, rows); - } - - // stores single value - void store(double newValue) throws IOException { - int position = pointer.get(); - values.set(position, newValue); - pointer.set((position + 1) % rows); - } - - // stores the same value several times - void bulkStore(double newValue, int bulkCount) throws IOException { - assert bulkCount <= rows: "Invalid number of bulk updates: " + bulkCount + - " rows=" + rows; - int position = pointer.get(); - // update tail - int tailUpdateCount = Math.min(rows - position, bulkCount); - values.set(position, newValue, tailUpdateCount); - pointer.set((position + tailUpdateCount) % rows); - // do we need to update from the start? - int headUpdateCount = bulkCount - tailUpdateCount; - if (headUpdateCount > 0) { - values.set(0, newValue, headUpdateCount); - pointer.set(headUpdateCount); - } - } - - void update(double[] newValues) throws IOException { - assert rows == newValues.length: "Invalid number of robin values supplied (" + newValues.length + - "), exactly " + rows + " needed"; - pointer.set(0); - values.writeDouble(0, newValues); - } - - /** - * Updates archived values in bulk. - * - * @param newValues Array of double values to be stored in the archive - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if the length of the input array is different from the length of - * this archive - */ - public void setValues(double[] newValues) throws IOException, RrdException { - if (rows != newValues.length) { - throw new RrdException("Invalid number of robin values supplied (" + newValues.length + - "), exactly " + rows + " needed"); - } - update(newValues); - } - - /** - * (Re)sets all values in this archive to the same value. - * - * @param newValue New value - * @throws IOException Thrown in case of I/O error - */ - public void setValues(double newValue) throws IOException { - double[] values = new double[rows]; - for (int i = 0; i < values.length; i++) { - values[i] = newValue; - } - update(values); - } - - String dump() throws IOException { - StringBuffer buffer = new StringBuffer("Robin " + pointer.get() + "/" + rows + ": "); - double[] values = getValues(); - for (double value : values) { - buffer.append(Util.formatDouble(value, true)).append(" "); - } - buffer.append("\n"); - return buffer.toString(); - } - - /** - * Returns the i-th value from the Robin archive. - * - * @param index Value index - * @return Value stored in the i-th position (the oldest value has zero index) - * @throws IOException Thrown in case of I/O specific error. - */ - public double getValue(int index) throws IOException { - int arrayIndex = (pointer.get() + index) % rows; - return values.get(arrayIndex); - } - - /** - * Sets the i-th value in the Robin archive. - * - * @param index index in the archive (the oldest value has zero index) - * @param value value to be stored - * @throws IOException Thrown in case of I/O specific error. - */ - public void setValue(int index, double value) throws IOException { - int arrayIndex = (pointer.get() + index) % rows; - values.set(arrayIndex, value); - } - - double[] getValues(int index, int count) throws IOException { - assert count <= rows: "Too many values requested: " + count + " rows=" + rows; - int startIndex = (pointer.get() + index) % rows; - int tailReadCount = Math.min(rows - startIndex, count); - double[] tailValues = values.get(startIndex, tailReadCount); - if (tailReadCount < count) { - int headReadCount = count - tailReadCount; - double[] headValues = values.get(0, headReadCount); - double[] values = new double[count]; - int k = 0; - for (double tailValue : tailValues) { - values[k++] = tailValue; - } - for (double headValue : headValues) { - values[k++] = headValue; - } - return values; - } - else { - return tailValues; - } - } - - /** - * Returns the Archive object to which this Robin object belongs. - * - * @return Parent Archive object - */ - public Archive getParent() { - return parentArc; - } - - /** - * Returns the size of the underlying array of archived values. - * - * @return Number of stored values - */ - public int getSize() { - return rows; - } - - /** - * Copies object's internal state to another Robin object. - * - * @param other New Robin object to copy state to - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if supplied argument is not a Robin object - */ - public void copyStateTo(RrdUpdater other) throws IOException, RrdException { - if (!(other instanceof Robin)) { - throw new RrdException( - "Cannot copy Robin object to " + other.getClass().getName()); - } - Robin robin = (Robin) other; - int rowsDiff = rows - robin.rows; - if (rowsDiff == 0) { - // Identical dimensions. Do copy in BULK to speed things up - robin.pointer.set(pointer.get()); - robin.values.writeBytes(values.readBytes()); - } - else { - // different sizes - for (int i = 0; i < robin.rows; i++) { - int j = i + rowsDiff; - robin.store(j >= 0 ? getValue(j) : Double.NaN); - } - } - } - - /** - * Filters values stored in this archive based on the given boundary. - * Archived values found to be outside of <code>[minValue, maxValue]</code> interval (inclusive) - * will be silently replaced with <code>NaN</code>. - * - * @param minValue lower boundary - * @param maxValue upper boundary - * @throws IOException Thrown in case of I/O error - */ - public void filterValues(double minValue, double maxValue) throws IOException { - for (int i = 0; i < rows; i++) { - double value = values.get(i); - if (!Double.isNaN(minValue) && !Double.isNaN(value) && minValue > value) { - values.set(i, Double.NaN); - } - if (!Double.isNaN(maxValue) && !Double.isNaN(value) && maxValue < value) { - values.set(i, Double.NaN); - } - } - } - - /** - * Returns the underlying storage (backend) object which actually performs all - * I/O operations. - * - * @return I/O backend object - */ - public RrdBackend getRrdBackend() { - return parentArc.getRrdBackend(); - } - - /** - * Required to implement RrdUpdater interface. You should never call this method directly. - * - * @return Allocator object - */ - public RrdAllocator getRrdAllocator() { - return parentArc.getRrdAllocator(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdAllocator.java b/apps/jrobin/java/src/org/jrobin/core/RrdAllocator.java deleted file mode 100644 index f3b20586309419f46e888f0f6974fa984aeb7905..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdAllocator.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -class RrdAllocator { - private long allocationPointer = 0L; - - long allocate(long byteCount) throws IOException { - long pointer = allocationPointer; - allocationPointer += byteCount; - return pointer; - } -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdBackend.java b/apps/jrobin/java/src/org/jrobin/core/RrdBackend.java deleted file mode 100644 index d15c5857b89ad95ec0a807f59c370e23cdb2e422..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdBackend.java +++ /dev/null @@ -1,341 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -/** - * Base implementation class for all backend classes. Each Round Robin Database object - * ({@link RrdDb} object) is backed with a single RrdBackend object which performs - * actual I/O operations on the underlying storage. JRobin supports - * three different bakcends out of the box: - * <p> - * <ul> - * <li>{@link RrdFileBackend}: objects of this class are created from the - * {@link RrdFileBackendFactory} class. This was the default backend used in all - * JRobin releases prior to 1.4.0. It uses java.io.* package and - * RandomAccessFile class to store RRD data in files on the disk. - * <p> - * <li>{@link RrdNioBackend}: objects of this class are created from the - * {@link RrdNioBackendFactory} class. The backend uses java.io.* and java.nio.* - * classes (mapped ByteBuffer) to store RRD data in files on the disk. This backend is fast, very fast, - * but consumes a lot of memory (borrowed not from the JVM but from the underlying operating system - * directly). <b>This is the default backend used in JRobin since 1.4.0 release.</b> - * <p> - * <li>{@link RrdMemoryBackend}: objects of this class are created from the - * {@link RrdMemoryBackendFactory} class. This backend stores all data in memory. Once - * JVM exits, all data gets lost. The backend is extremely fast and memory hungry. - * </ul> - * <p> - * To create your own backend in order to provide some custom type of RRD storage, - * you should do the following: - * <p> - * <ul> - * <li>Create your custom RrdBackend class (RrdCustomBackend, for example) - * by extending RrdBackend class. You have to implement all abstract methods defined - * in the base class. - * <p> - * <li>Create your custom RrdBackendFactory class (RrdCustomBackendFactory, - * for example) by extending RrdBackendFactory class. You have to implement all - * abstract methods defined in the base class. Your custom factory class will actually - * create custom backend objects when necessary. - * <p> - * <li>Create instance of your custom RrdBackendFactory and register it as a regular - * factory available to JRobin framework. See javadoc for {@link RrdBackendFactory} to - * find out how to do this - * </ul> - */ -public abstract class RrdBackend { - private static boolean s_instanceCreated = false; - private String m_path = null; - private boolean m_readOnly = false; - - /** - * Creates backend for a RRD storage with the given path. - * - * @param path String identifying RRD storage. For files on the disk, this - * argument should represent file path. Other storage types might interpret - * this argument differently. - */ - protected RrdBackend(final String path) { - this(path, false); - } - - protected RrdBackend(final String path, final boolean readOnly) { - m_path = path; - m_readOnly = readOnly; - RrdBackend.setInstanceCreated(); - } - - /** - * Returns path to the storage. - * - * @return Storage path - */ - public String getPath() { - return m_path; - } - - /** - * Is the RRD ReadOnly? - * - * @return True if the RRD is read only, false if not. - */ - public boolean isReadOnly() { - return m_readOnly; - } - - /** - * Writes an array of bytes to the underlying storage starting from the given - * storage offset. - * - * @param offset Storage offset. - * @param b Array of bytes that should be copied to the underlying storage - * @throws IOException Thrown in case of I/O error - */ - protected abstract void write(long offset, byte[] b) throws IOException; - - /** - * Reads an array of bytes from the underlying storage starting from the given - * storage offset. - * - * @param offset Storage offset. - * @param b Array which receives bytes from the underlying storage - * @throws IOException Thrown in case of I/O error - */ - protected abstract void read(long offset, byte[] b) throws IOException; - - /** - * Returns the number of RRD bytes in the underlying storage. - * - * @return Number of RRD bytes in the storage. - * @throws IOException Thrown in case of I/O error. - */ - public abstract long getLength() throws IOException; - - /** - * Sets the number of bytes in the underlying RRD storage. - * This method is called only once, immediately after a new RRD storage gets created. - * - * @param length Length of the underlying RRD storage in bytes. - * @throws IOException Thrown in case of I/O error. - */ - protected abstract void setLength(long length) throws IOException; - - /** - * Closes the underlying backend. - * @throws IOException Thrown in case of I/O error. - */ - public void close() throws IOException { - } - - /** - * This method suggests the caching policy to the JRobin frontend (high-level) classes. If <code>true</code> - * is returned, frontent classes will cache frequently used parts of a RRD file in memory to improve - * performance. If <code>false</code> is returned, high level classes will never cache RRD file sections - * in memory. - * - * @return <code>true</code> if file caching is enabled, <code>false</code> otherwise. By default, the - * method returns <code>true</code> but it can be overriden in subclasses. - */ - protected boolean isCachingAllowed() { - return true; - } - - /** - * Reads all RRD bytes from the underlying storage - * - * @return RRD bytes - * @throws IOException Thrown in case of I/O error - */ - public final byte[] readAll() throws IOException { - final byte[] b = new byte[(int) getLength()]; - read(0, b); - return b; - } - - final void writeInt(final long offset, final int value) throws IOException { - write(offset, getIntBytes(value)); - } - - final void writeLong(final long offset, final long value) throws IOException { - write(offset, getLongBytes(value)); - } - - final void writeDouble(final long offset, final double value) throws IOException { - write(offset, getDoubleBytes(value)); - } - - final void writeDouble(final long offset, final double value, final int count) throws IOException { - final byte[] b = getDoubleBytes(value); - final byte[] image = new byte[8 * count]; - for (int i = 0, k = 0; i < count; i++) { - image[k++] = b[0]; - image[k++] = b[1]; - image[k++] = b[2]; - image[k++] = b[3]; - image[k++] = b[4]; - image[k++] = b[5]; - image[k++] = b[6]; - image[k++] = b[7]; - } - write(offset, image); - } - - final void writeDouble(final long offset, final double[] values) throws IOException { - final int count = values.length; - final byte[] image = new byte[8 * count]; - for (int i = 0, k = 0; i < count; i++) { - final byte[] b = getDoubleBytes(values[i]); - image[k++] = b[0]; - image[k++] = b[1]; - image[k++] = b[2]; - image[k++] = b[3]; - image[k++] = b[4]; - image[k++] = b[5]; - image[k++] = b[6]; - image[k++] = b[7]; - } - write(offset, image); - } - - final void writeString(final long offset, final String rawValue) throws IOException { - final String value = rawValue.trim(); - final byte[] b = new byte[RrdPrimitive.STRING_LENGTH * 2]; - for (int i = 0, k = 0; i < RrdPrimitive.STRING_LENGTH; i++) { - final char c = (i < value.length()) ? value.charAt(i) : ' '; - final byte[] cb = getCharBytes(c); - b[k++] = cb[0]; - b[k++] = cb[1]; - } - write(offset, b); - } - - final int readInt(final long offset) throws IOException { - final byte[] b = new byte[4]; - read(offset, b); - return getInt(b); - } - - final long readLong(final long offset) throws IOException { - final byte[] b = new byte[8]; - read(offset, b); - return getLong(b); - } - - final double readDouble(final long offset) throws IOException { - final byte[] b = new byte[8]; - read(offset, b); - return getDouble(b); - } - - final double[] readDouble(final long offset, final int count) throws IOException { - final int byteCount = 8 * count; - final byte[] image = new byte[byteCount]; - read(offset, image); - final double[] values = new double[count]; - for (int i = 0, k = -1; i < count; i++) { - final byte[] b = new byte[] { - image[++k], image[++k], image[++k], image[++k], - image[++k], image[++k], image[++k], image[++k] - }; - values[i] = getDouble(b); - } - return values; - } - - final String readString(final long offset) throws IOException { - final byte[] b = new byte[RrdPrimitive.STRING_LENGTH * 2]; - final char[] c = new char[RrdPrimitive.STRING_LENGTH]; - read(offset, b); - for (int i = 0, k = -1; i < RrdPrimitive.STRING_LENGTH; i++) { - final byte[] cb = new byte[] {b[++k], b[++k]}; - c[i] = getChar(cb); - } - return new String(c).trim(); - } - - // static helper methods - - private static byte[] getIntBytes(final int value) { - final byte[] b = new byte[4]; - b[0] = (byte) ((value >>> 24) & 0xFF); - b[1] = (byte) ((value >>> 16) & 0xFF); - b[2] = (byte) ((value >>> 8) & 0xFF); - b[3] = (byte) ((value) & 0xFF); - return b; - } - - private static byte[] getLongBytes(final long value) { - final byte[] b = new byte[8]; - b[0] = (byte) ((int) (value >>> 56) & 0xFF); - b[1] = (byte) ((int) (value >>> 48) & 0xFF); - b[2] = (byte) ((int) (value >>> 40) & 0xFF); - b[3] = (byte) ((int) (value >>> 32) & 0xFF); - b[4] = (byte) ((int) (value >>> 24) & 0xFF); - b[5] = (byte) ((int) (value >>> 16) & 0xFF); - b[6] = (byte) ((int) (value >>> 8) & 0xFF); - b[7] = (byte) ((int) (value) & 0xFF); - return b; - } - - private static byte[] getCharBytes(final char value) { - final byte[] b = new byte[2]; - b[0] = (byte) ((value >>> 8) & 0xFF); - b[1] = (byte) ((value) & 0xFF); - return b; - } - - private static byte[] getDoubleBytes(final double value) { - return getLongBytes(Double.doubleToLongBits(value)); - } - - private static int getInt(final byte[] b) { - assert b.length == 4: "Invalid number of bytes for integer conversion"; - return ((b[0] << 24) & 0xFF000000) + ((b[1] << 16) & 0x00FF0000) + - ((b[2] << 8) & 0x0000FF00) + (b[3] & 0x000000FF); - } - - private static long getLong(final byte[] b) { - assert b.length == 8: "Invalid number of bytes for long conversion"; - int high = getInt(new byte[] {b[0], b[1], b[2], b[3]}); - int low = getInt(new byte[] {b[4], b[5], b[6], b[7]}); - return ((long) (high) << 32) + (low & 0xFFFFFFFFL); - } - - private static char getChar(final byte[] b) { - assert b.length == 2: "Invalid number of bytes for char conversion"; - return (char) (((b[0] << 8) & 0x0000FF00) - + (b[1] & 0x000000FF)); - } - - private static double getDouble(final byte[] b) { - assert b.length == 8: "Invalid number of bytes for double conversion"; - return Double.longBitsToDouble(getLong(b)); - } - - private static void setInstanceCreated() { - s_instanceCreated = true; - } - - static boolean isInstanceCreated() { - return s_instanceCreated; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdBackendFactory.java b/apps/jrobin/java/src/org/jrobin/core/RrdBackendFactory.java deleted file mode 100644 index 42ebbd7610f38fc2f9094172df2c6e0115dbc161..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdBackendFactory.java +++ /dev/null @@ -1,221 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; -import java.util.HashMap; - -/** - * Base (abstract) backend factory class which holds references to all concrete - * backend factories and defines abstract methods which must be implemented in - * all concrete factory implementations. - * <p> - * Factory classes are used to create concrete {@link RrdBackend} implementations. - * Each factory creates unlimited number of specific backend objects. - * <p> - * JRobin supports four different backend types (backend factories) out of the box:<p> - * <ul> - * <li>{@link RrdFileBackend}: objects of this class are created from the - * {@link RrdFileBackendFactory} class. This was the default backend used in all - * JRobin releases before 1.4.0 release. It uses java.io.* package and RandomAccessFile class to store - * RRD data in files on the disk. - * <p> - * <li>{@link RrdSafeFileBackend}: objects of this class are created from the - * {@link RrdSafeFileBackendFactory} class. It uses java.io.* package and RandomAccessFile class to store - * RRD data in files on the disk. This backend is SAFE: - * it locks the underlying RRD file during update/fetch operations, and caches only static - * parts of a RRD file in memory. Therefore, this backend is safe to be used when RRD files should - * be shared <b>between several JVMs</b> at the same time. However, this backend is *slow* since it does - * not use fast java.nio.* package (it's still based on the RandomAccessFile class). - * <p> - * <li>{@link RrdNioBackend}: objects of this class are created from the - * {@link RrdNioBackendFactory} class. The backend uses java.io.* and java.nio.* - * classes (mapped ByteBuffer) to store RRD data in files on the disk. This is the default backend - * since 1.4.0 release. - * <p> - * <li>{@link RrdMemoryBackend}: objects of this class are created from the - * {@link RrdMemoryBackendFactory} class. This backend stores all data in memory. Once - * JVM exits, all data gets lost. The backend is extremely fast and memory hungry. - * </ul> - * <p> - * Each backend factory is identifed by its {@link #getFactoryName() name}. Constructors - * are provided in the {@link RrdDb} class to create RrdDb objects (RRD databases) - * backed with a specific backend. - * <p> - * See javadoc for {@link RrdBackend} to find out how to create your custom backends. - */ -public abstract class RrdBackendFactory { - private static final HashMap<String, RrdBackendFactory> factories = new HashMap<String, RrdBackendFactory>(); - private static RrdBackendFactory defaultFactory; - - static { - try { - RrdFileBackendFactory fileFactory = new RrdFileBackendFactory(); - registerFactory(fileFactory); - RrdJRobin14FileBackendFactory jrobin14Factory = new RrdJRobin14FileBackendFactory(); - registerFactory(jrobin14Factory); - RrdMemoryBackendFactory memoryFactory = new RrdMemoryBackendFactory(); - registerFactory(memoryFactory); - RrdNioBackendFactory nioFactory = new RrdNioBackendFactory(); - registerFactory(nioFactory); - RrdSafeFileBackendFactory safeFactory = new RrdSafeFileBackendFactory(); - registerFactory(safeFactory); - RrdNioByteBufferBackendFactory nioByteBufferFactory = new RrdNioByteBufferBackendFactory(); - registerFactory(nioByteBufferFactory); - selectDefaultFactory(); - } - catch (RrdException e) { - throw new RuntimeException("FATAL: Cannot register RRD backend factories: " + e); - } - } - - private static void selectDefaultFactory() throws RrdException { - setDefaultFactory("FILE"); - } - - /** - * Returns backend factory for the given backend factory name. - * - * @param name Backend factory name. Initially supported names are:<p> - * <ul> - * <li><b>FILE</b>: Default factory which creates backends based on the - * java.io.* package. RRD data is stored in files on the disk - * <li><b>SAFE</b>: Default factory which creates backends based on the - * java.io.* package. RRD data is stored in files on the disk. This backend - * is "safe". Being safe means that RRD files can be safely shared between - * several JVM's. - * <li><b>NIO</b>: Factory which creates backends based on the - * java.nio.* package. RRD data is stored in files on the disk - * <li><b>MEMORY</b>: Factory which creates memory-oriented backends. - * RRD data is stored in memory, it gets lost as soon as JVM exits. - * </ul> - * @return Backend factory for the given factory name - * @throws RrdException Thrown if no factory with the given name - * is available. - */ - public static synchronized RrdBackendFactory getFactory(final String name) throws RrdException { - final RrdBackendFactory factory = factories.get(name); - if (factory != null) { - return factory; - } - throw new RrdException("No backend factory found with the name specified [" + name + "]"); - } - - /** - * Registers new (custom) backend factory within the JRobin framework. - * - * @param factory Factory to be registered - * @throws RrdException Thrown if the name of the specified factory is already - * used. - */ - public static synchronized void registerFactory(final RrdBackendFactory factory) throws RrdException { - final String name = factory.getFactoryName(); - if (!factories.containsKey(name)) { - factories.put(name, factory); - } - else { - throw new RrdException("Backend factory of this name2 (" + name + ") already exists and cannot be registered"); - } - } - - /** - * Registers new (custom) backend factory within the JRobin framework and sets this - * factory as the default. - * - * @param factory Factory to be registered and set as default - * @throws RrdException Thrown if the name of the specified factory is already - * used. - */ - public static synchronized void registerAndSetAsDefaultFactory(final RrdBackendFactory factory) throws RrdException { - registerFactory(factory); - setDefaultFactory(factory.getFactoryName()); - } - - /** - * Returns the defaul backend factory. This factory is used to construct - * {@link RrdDb} objects if no factory is specified in the RrdDb constructor. - * - * @return Default backend factory. - */ - public static RrdBackendFactory getDefaultFactory() { - return defaultFactory; - } - - /** - * Replaces the default backend factory with a new one. This method must be called before - * the first RRD gets created. <p> - * - * @param factoryName Name of the default factory. Out of the box, JRobin supports four - * different RRD backends: "FILE" (java.io.* based), "SAFE" (java.io.* based - use this - * backend if RRD files may be accessed from several JVMs at the same time), - * "NIO" (java.nio.* based) and "MEMORY" (byte[] based). - * @throws RrdException Thrown if invalid factory name is supplied or not called before - * the first RRD is created. - */ - public static void setDefaultFactory(final String factoryName) throws RrdException { - // We will allow this only if no RRDs are created - if (!RrdBackend.isInstanceCreated()) { - defaultFactory = getFactory(factoryName); - } - else { - throw new RrdException("Could not change the default backend factory. This method must be called before the first RRD gets created"); - } - } - - /** - * Whether or not the RRD backend has created an instance yet. - * - * @return True if the backend instance is created, false if not. - */ - public static boolean isInstanceCreated() { - return RrdBackend.isInstanceCreated(); - } - - /** - * Creates RrdBackend object for the given storage path. - * - * @param path Storage path - * @param readOnly True, if the storage should be accessed in read/only mode. - * False otherwise. - * @return Backend object which handles all I/O operations for the given storage path - * @throws IOException Thrown in case of I/O error. - */ - protected abstract RrdBackend open(String path, boolean readOnly) throws IOException; - - /** - * Method to determine if a storage with the given path already exists. - * - * @param path Storage path - * @return True, if such storage exists, false otherwise. - * @throws IOException Thrown in case of I/O error. - */ - protected abstract boolean exists(String path) throws IOException; - - /** - * Returns the name (primary ID) for the factory. - * - * @return Name of the factory. - */ - public abstract String getFactoryName(); - - public String toString() { - return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + "[name=" + getFactoryName() + "]"; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdDb.java b/apps/jrobin/java/src/org/jrobin/core/RrdDb.java deleted file mode 100644 index 64544dc77e5ce311ea9460582a1942191ac9b788..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdDb.java +++ /dev/null @@ -1,1166 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Date; - -/** - * Main class used to create and manipulate round robin databases (RRDs). Use this class to perform - * update and fetch operations on exisiting RRDs, to create new RRD from - * the definition (object of class {@link org.jrobin.core.RrdDef RrdDef}) or - * from XML file (dumped content of RRDTool's or JRobin's RRD file). - * <p> - * Each RRD is backed with some kind of storage. For example, RRDTool supports only one kind of - * storage (disk file). On the contrary, JRobin gives you freedom to use other storage (backend) types - * even to create your own backend types for some special purposes. JRobin by default stores - * RRD data in files (as RRDTool), but you might choose to store RRD data in memory (this is - * supported in JRobin), to use java.nio.* instead of java.io.* package for file manipulation - * (also supported) or to store whole RRDs in the SQL database - * (you'll have to extend some classes to do this). - * <p> - * Note that JRobin uses binary format different from RRDTool's format. You cannot - * use this class to manipulate RRD files created with RRDTool. <b>However, if you perform - * the same sequence of create, update and fetch operations, you will get exactly the same - * results from JRobin and RRDTool.</b> - * <p> - * You will not be able to use JRobin API if you are not familiar with - * basic RRDTool concepts. Good place to start is the - * <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/tutorial/rrdtutorial.html">official RRD tutorial</a> - * and relevant RRDTool man pages: <a href="../../../../man/rrdcreate.html" target="man">rrdcreate</a>, - * <a href="../../../../man/rrdupdate.html" target="man">rrdupdate</a>, - * <a href="../../../../man/rrdfetch.html" target="man">rrdfetch</a> and - * <a href="../../../../man/rrdgraph.html" target="man">rrdgraph</a>. - * For RRDTool's advanced graphing capabilities (RPN extensions), also supported in JRobin, - * there is an excellent - * <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/tutorial/cdeftutorial.html" target="man">CDEF tutorial</a>. - * <p> - * - * @see RrdBackend - * @see RrdBackendFactory - */ -public class RrdDb implements RrdUpdater { - /** - * prefix to identify external XML file source used in various RrdDb constructors - */ - public static final String PREFIX_XML = "xml:/"; - /** - * prefix to identify external RRDTool file source used in various RrdDb constructors - */ - public static final String PREFIX_RRDTool = "rrdtool:/"; - - // static final String RRDTOOL = "rrdtool"; - static final int XML_INITIAL_BUFFER_CAPACITY = 100000; // bytes - - private RrdBackend backend; - private RrdAllocator allocator = new RrdAllocator(); - - private Header header; - private Datasource[] datasources; - private Archive[] archives; - - private boolean closed = false; - - /** - * Constructor used to create new RRD object from the definition. This RRD object will be backed - * with a storage (backend) of the default type. Initially, storage type defaults to "NIO" - * (RRD bytes will be put in a file on the disk). Default storage type can be changed with a static - * {@link RrdBackendFactory#setDefaultFactory(String)} method call. - * <p> - * New RRD file structure is specified with an object of class - * {@link org.jrobin.core.RrdDef <b>RrdDef</b>}. The underlying RRD storage is created as soon - * as the constructor returns. - * <p> - * Typical scenario: - * <p> - * <pre> - * // create new RRD definition - * RrdDef def = new RrdDef("test.rrd", 300); - * def.addDatasource("input", DsTypes.DT_COUNTER, 600, 0, Double.NaN); - * def.addDatasource("output", DsTypes.DT_COUNTER, 600, 0, Double.NaN); - * def.addArchive(ConsolFuns.CF_AVERAGE, 0.5, 1, 600); - * def.addArchive(ConsolFuns.CF_AVERAGE, 0.5, 6, 700); - * def.addArchive(ConsolFuns.CF_AVERAGE, 0.5, 24, 797); - * def.addArchive(ConsolFuns.CF_AVERAGE, 0.5, 288, 775); - * def.addArchive(ConsolFuns.CF_MAX, 0.5, 1, 600); - * def.addArchive(ConsolFuns.CF_MAX, 0.5, 6, 700); - * def.addArchive(ConsolFuns.CF_MAX, 0.5, 24, 797); - * def.addArchive(ConsolFuns.CF_MAX, 0.5, 288, 775); - * - * // RRD definition is now completed, create the database! - * RrdDb rrd = new RrdDb(def); - * // new RRD file has been created on your disk - * </pre> - * - * @param rrdDef Object describing the structure of the new RRD file. - * @throws IOException Thrown in case of I/O error. - * @throws RrdException Thrown if invalid RrdDef object is supplied. - */ - public RrdDb(RrdDef rrdDef) throws RrdException, IOException { - this(rrdDef, RrdFileBackendFactory.getDefaultFactory()); - } - - /** - * Constructor used to create new RRD object from the definition object but with a storage - * (backend) different from default. - * <p> - * JRobin uses <i>factories</i> to create RRD backend objecs. There are three different - * backend factories supplied with JRobin, and each factory has its unique name: - * <p> - * <ul> - * <li><b>FILE</b>: backends created from this factory will store RRD data to files by using - * java.io.* classes and methods - * <li><b>NIO</b>: backends created from this factory will store RRD data to files by using - * java.nio.* classes and methods - * <li><b>MEMORY</b>: backends created from this factory will store RRD data in memory. This might - * be useful in runtime environments which prohibit disk utilization, or for storing temporary, - * non-critical data (it gets lost as soon as JVM exits). - * </ul> - * <p> - * For example, to create RRD in memory, use the following code: - * <pre> - * RrdBackendFactory factory = RrdBackendFactory.getFactory("MEMORY"); - * RrdDb rrdDb = new RrdDb(rrdDef, factory); - * rrdDb.close(); - * </pre> - * <p> - * New RRD file structure is specified with an object of class - * {@link org.jrobin.core.RrdDef <b>RrdDef</b>}. The underlying RRD storage is created as soon - * as the constructor returns. - * - * @param rrdDef RRD definition object - * @param factory The factory which will be used to create storage for this RRD - * @throws RrdException Thrown if invalid factory or definition is supplied - * @throws IOException Thrown in case of I/O error - * @see RrdBackendFactory - */ - public RrdDb(RrdDef rrdDef, RrdBackendFactory factory) throws RrdException, IOException { - rrdDef.validate(); - String path = rrdDef.getPath(); - backend = factory.open(path, false); - try { - backend.setLength(rrdDef.getEstimatedSize()); - // create header - header = new Header(this, rrdDef); - // create datasources - DsDef[] dsDefs = rrdDef.getDsDefs(); - datasources = new Datasource[dsDefs.length]; - for (int i = 0; i < dsDefs.length; i++) { - datasources[i] = new Datasource(this, dsDefs[i]); - } - // create archives - ArcDef[] arcDefs = rrdDef.getArcDefs(); - archives = new Archive[arcDefs.length]; - for (int i = 0; i < arcDefs.length; i++) { - archives[i] = new Archive(this, arcDefs[i]); - } - } - catch (IOException e) { - backend.close(); - throw e; - } - } - - /** - * Constructor used to open already existing RRD. This RRD object will be backed - * with a storage (backend) of the default type (file on the disk). Constructor - * obtains read or read/write access to this RRD. - * - * @param path Path to existing RRD. - * @param readOnly Should be set to <code>false</code> if you want to update - * the underlying RRD. If you want just to fetch data from the RRD file - * (read-only access), specify <code>true</code>. If you try to update RRD file - * open in read-only mode (<code>m_readOnly</code> set to <code>true</code>), - * <code>IOException</code> will be thrown. - * @throws IOException Thrown in case of I/O error. - * @throws RrdException Thrown in case of JRobin specific error. - */ - public RrdDb(String path, boolean readOnly) throws IOException, RrdException { - this(path, readOnly, RrdBackendFactory.getDefaultFactory()); - } - - /** - * Constructor used to open already existing RRD backed - * with a storage (backend) different from default. Constructor - * obtains read or read/write access to this RRD. - * - * @param path Path to existing RRD. - * @param readOnly Should be set to <code>false</code> if you want to update - * the underlying RRD. If you want just to fetch data from the RRD file - * (read-only access), specify <code>true</code>. If you try to update RRD file - * open in read-only mode (<code>m_readOnly</code> set to <code>true</code>), - * <code>IOException</code> will be thrown. - * @param factory Backend factory which will be used for this RRD. - * @throws FileNotFoundException Thrown if the requested file does not exist. - * @throws IOException Thrown in case of general I/O error (bad RRD file, for example). - * @throws RrdException Thrown in case of JRobin specific error. - * @see RrdBackendFactory - */ - public RrdDb(String path, boolean readOnly, RrdBackendFactory factory) - throws FileNotFoundException, IOException, RrdException { - // opens existing RRD file - throw exception if the file does not exist... - if (!factory.exists(path)) { - throw new FileNotFoundException("Could not open " + path + " [non existent]"); - } - backend = factory.open(path, readOnly); - try { - // restore header - header = new Header(this, (RrdDef) null); - header.validateHeader(); - // restore datasources - int dsCount = header.getDsCount(); - datasources = new Datasource[dsCount]; - for (int i = 0; i < dsCount; i++) { - datasources[i] = new Datasource(this, null); - } - // restore archives - int arcCount = header.getArcCount(); - archives = new Archive[arcCount]; - for (int i = 0; i < arcCount; i++) { - archives[i] = new Archive(this, null); - } - } - catch (RrdException e) { - backend.close(); - throw e; - } - catch (IOException e) { - backend.close(); - throw e; - } - } - - /** - * <p>Constructor used to open already existing RRD in R/W mode, with a default storage - * (backend) type (file on the disk). - * - * @param path Path to existing RRD. - * @throws IOException Thrown in case of I/O error. - * @throws RrdException Thrown in case of JRobin specific error. - */ - public RrdDb(String path) throws IOException, RrdException { - this(path, false); - } - - /** - * <p>Constructor used to open already existing RRD in R/W mode with a storage (backend) type - * different from default.</p> - * - * @param path Path to existing RRD. - * @param factory Backend factory used to create this RRD. - * @throws IOException Thrown in case of I/O error. - * @throws RrdException Thrown in case of JRobin specific error. - * @see RrdBackendFactory - */ - public RrdDb(String path, RrdBackendFactory factory) throws IOException, RrdException { - this(path, false, factory); - } - - /** - * Constructor used to create RRD files from external file sources. - * Supported external file sources are: - * <p> - * <ul> - * <li>RRDTool/JRobin XML file dumps (i.e files created with <code>rrdtool dump</code> command). - * <li>RRDTool binary files. - * </ul> - * <p> - * Newly created RRD will be backed with a default storage (backend) type - * (file on the disk). - * <p> - * JRobin and RRDTool use the same format for XML dump and this constructor should be used to - * (re)create JRobin RRD files from XML dumps. First, dump the content of a RRDTool - * RRD file (use command line): - * <p> - * <pre> - * rrdtool dump original.rrd > original.xml - * </pre> - * <p> - * Than, use the file <code>original.xml</code> to create JRobin RRD file named - * <code>copy.rrd</code>: - * <p> - * <pre> - * RrdDb rrd = new RrdDb("copy.rrd", "original.xml"); - * </pre> - * <p> - * or: - * <p> - * <pre> - * RrdDb rrd = new RrdDb("copy.rrd", "xml:/original.xml"); - * </pre> - * <p> - * See documentation for {@link #dumpXml(java.lang.String) dumpXml()} method - * to see how to convert JRobin files to RRDTool's format. - * <p> - * To read RRDTool files directly, specify <code>rrdtool:/</code> prefix in the - * <code>externalPath</code> argument. For example, to create JRobin compatible file named - * <code>copy.rrd</code> from the file <code>original.rrd</code> created with RRDTool, use - * the following code: - * <p> - * <pre> - * RrdDb rrd = new RrdDb("copy.rrd", "rrdtool:/original.rrd"); - * </pre> - * <p> - * Note that the prefix <code>xml:/</code> or <code>rrdtool:/</code> is necessary to distinguish - * between XML and RRDTool's binary sources. If no prefix is supplied, XML format is assumed. - * - * @param rrdPath Path to a RRD file which will be created - * @param externalPath Path to an external file which should be imported, with an optional - * <code>xml:/</code> or <code>rrdtool:/</code> prefix. - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public RrdDb(String rrdPath, String externalPath) throws IOException, RrdException, RrdException { - this(rrdPath, externalPath, RrdBackendFactory.getDefaultFactory()); - } - - /** - * Constructor used to create RRD files from external file sources with a backend type - * different from default. Supported external file sources are: - * <p> - * <ul> - * <li>RRDTool/JRobin XML file dumps (i.e files created with <code>rrdtool dump</code> command). - * <li>RRDTool binary files. - * </ul> - * <p> - * JRobin and RRDTool use the same format for XML dump and this constructor should be used to - * (re)create JRobin RRD files from XML dumps. First, dump the content of a RRDTool - * RRD file (use command line): - * <p> - * <pre> - * rrdtool dump original.rrd > original.xml - * </pre> - * <p> - * Than, use the file <code>original.xml</code> to create JRobin RRD file named - * <code>copy.rrd</code>: - * <p> - * <pre> - * RrdDb rrd = new RrdDb("copy.rrd", "original.xml"); - * </pre> - * <p> - * or: - * <p> - * <pre> - * RrdDb rrd = new RrdDb("copy.rrd", "xml:/original.xml"); - * </pre> - * <p> - * See documentation for {@link #dumpXml(java.lang.String) dumpXml()} method - * to see how to convert JRobin files to RRDTool's format. - * <p> - * To read RRDTool files directly, specify <code>rrdtool:/</code> prefix in the - * <code>externalPath</code> argument. For example, to create JRobin compatible file named - * <code>copy.rrd</code> from the file <code>original.rrd</code> created with RRDTool, use - * the following code: - * <p> - * <pre> - * RrdDb rrd = new RrdDb("copy.rrd", "rrdtool:/original.rrd"); - * </pre> - * <p> - * Note that the prefix <code>xml:/</code> or <code>rrdtool:/</code> is necessary to distinguish - * between XML and RRDTool's binary sources. If no prefix is supplied, XML format is assumed. - * - * @param rrdPath Path to RRD which will be created - * @param externalPath Path to an external file which should be imported, with an optional - * <code>xml:/</code> or <code>rrdtool:/</code> prefix. - * @param factory Backend factory which will be used to create storage (backend) for this RRD. - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - * @see RrdBackendFactory - */ - public RrdDb(String rrdPath, String externalPath, RrdBackendFactory factory) - throws IOException, RrdException { - DataImporter reader; - if (externalPath.startsWith(PREFIX_RRDTool)) { - String rrdToolPath = externalPath.substring(PREFIX_RRDTool.length()); - reader = new RrdToolReader(rrdToolPath); - } - else if (externalPath.startsWith(PREFIX_XML)) { - externalPath = externalPath.substring(PREFIX_XML.length()); - reader = new XmlReader(externalPath); - } - else { - reader = new XmlReader(externalPath); - } - backend = factory.open(rrdPath, false); - try { - backend.setLength(reader.getEstimatedSize()); - // create header - header = new Header(this, reader); - // create datasources - datasources = new Datasource[reader.getDsCount()]; - for (int i = 0; i < datasources.length; i++) { - datasources[i] = new Datasource(this, reader, i); - } - // create archives - archives = new Archive[reader.getArcCount()]; - for (int i = 0; i < archives.length; i++) { - archives[i] = new Archive(this, reader, i); - } - reader.release(); - } - catch (RrdException e) { - backend.close(); - throw e; - } - catch (IOException e) { - backend.close(); - throw e; - } - } - - public RrdDb(final File file) throws IOException, RrdException { - this(file.getPath()); - } - - public RrdDb(final File file, final boolean readOnly) throws IOException, RrdException { - this(file.getPath(), readOnly); - } - - /** - * Closes RRD. No further operations are allowed on this RrdDb object. - * - * @throws IOException Thrown in case of I/O related error. - */ - public synchronized void close() throws IOException { - if (!closed) { - closed = true; - backend.close(); - } - } - - /** - * Returns true if the RRD is closed. - * - * @return true if closed, false otherwise - */ - public boolean isClosed() { - return closed; - } - - /** - * Returns RRD header. - * - * @return Header object - */ - public Header getHeader() { - return header; - } - - /** - * Returns Datasource object for the given datasource index. - * - * @param dsIndex Datasource index (zero based) - * @return Datasource object - */ - public Datasource getDatasource(int dsIndex) { - return datasources[dsIndex]; - } - - /** - * Returns Archive object for the given archive index. - * - * @param arcIndex Archive index (zero based) - * @return Archive object - */ - public Archive getArchive(int arcIndex) { - return archives[arcIndex]; - } - - /** - * Returns an array of datasource names defined in RRD. - * - * @return Array of datasource names. - * @throws IOException Thrown in case of I/O error. - */ - public String[] getDsNames() throws IOException { - int n = datasources.length; - String[] dsNames = new String[n]; - for (int i = 0; i < n; i++) { - dsNames[i] = datasources[i].getDsName(); - } - return dsNames; - } - - /** - * Creates new sample with the given timestamp and all datasource values set to - * 'unknown'. Use returned <code>Sample</code> object to specify - * datasource values for the given timestamp. See documentation for - * {@link org.jrobin.core.Sample Sample} for an explanation how to do this. - * <p> - * Once populated with data source values, call Sample's - * {@link org.jrobin.core.Sample#update() update()} method to actually - * store sample in the RRD associated with it. - * - * @param time Sample timestamp rounded to the nearest second (without milliseconds). - * @return Fresh sample with the given timestamp and all data source values set to 'unknown'. - * @throws IOException Thrown in case of I/O error. - */ - public Sample createSample(long time) throws IOException { - return new Sample(this, time); - } - - /** - * Creates new sample with the current timestamp and all data source values set to - * 'unknown'. Use returned <code>Sample</code> object to specify - * datasource values for the current timestamp. See documentation for - * {@link org.jrobin.core.Sample Sample} for an explanation how to do this. - * <p> - * Once populated with data source values, call Sample's - * {@link org.jrobin.core.Sample#update() update()} method to actually - * store sample in the RRD associated with it. - * - * @return Fresh sample with the current timestamp and all - * data source values set to 'unknown'. - * @throws IOException Thrown in case of I/O error. - */ - public Sample createSample() throws IOException { - return createSample(Util.getTime()); - } - - /** - * <p>Prepares fetch request to be executed on this RRD. Use returned - * <code>FetchRequest</code> object and its {@link org.jrobin.core.FetchRequest#fetchData() fetchData()} - * method to actually fetch data from the RRD file.</p> - * - * @param consolFun Consolidation function to be used in fetch request. Allowed values are - * "AVERAGE", "MIN", "MAX" and "LAST" (these constants are conveniently defined in the - * {@link ConsolFuns} class). - * @param fetchStart Starting timestamp for fetch request. - * @param fetchEnd Ending timestamp for fetch request. - * @param resolution Fetch resolution (see RRDTool's - * <a href="../../../../man/rrdfetch.html" target="man">rrdfetch man page</a> for an - * explanation of this parameter. - * @return Request object that should be used to actually fetch data from RRD. - * @throws RrdException In case of JRobin related error (invalid consolidation function or - * invalid time span). - */ - public FetchRequest createFetchRequest(String consolFun, long fetchStart, long fetchEnd, - long resolution) throws RrdException { - return new FetchRequest(this, consolFun, fetchStart, fetchEnd, resolution); - } - - /** - * <p>Prepares fetch request to be executed on this RRD. Use returned - * <code>FetchRequest</code> object and its {@link org.jrobin.core.FetchRequest#fetchData() fetchData()} - * method to actually fetch data from this RRD. Data will be fetched with the smallest - * possible resolution (see RRDTool's - * <a href="../../../../man/rrdfetch.html" target="man">rrdfetch man page</a> - * for the explanation of the resolution parameter).</p> - * - * @param consolFun Consolidation function to be used in fetch request. Allowed values are - * "AVERAGE", "MIN", "MAX" and "LAST" (these constants are conveniently defined in the - * {@link ConsolFuns} class). - * @param fetchStart Starting timestamp for fetch request. - * @param fetchEnd Ending timestamp for fetch request. - * @return Request object that should be used to actually fetch data from RRD. - * @throws RrdException In case of JRobin related error (invalid consolidation function or - * invalid time span). - */ - public FetchRequest createFetchRequest(String consolFun, long fetchStart, long fetchEnd) - throws RrdException { - return createFetchRequest(consolFun, fetchStart, fetchEnd, 1); - } - - synchronized void store(Sample sample) throws IOException, RrdException { - if (closed) { - throw new RrdException("RRD already closed, cannot store this sample"); - } - long newTime = sample.getTime(); - long lastTime = header.getLastUpdateTime(); - if (lastTime >= newTime) { - throw new RrdException("Bad sample timestamp " + newTime + - ". Last update time was " + lastTime + ", at least one second step is required"); - } - double[] newValues = sample.getValues(); - for (int i = 0; i < datasources.length; i++) { - double newValue = newValues[i]; - datasources[i].process(newTime, newValue); - } - header.setLastUpdateTime(newTime); - } - - synchronized FetchData fetchData(FetchRequest request) throws IOException, RrdException { - if (closed) { - throw new RrdException("RRD already closed, cannot fetch data"); - } - Archive archive = findMatchingArchive(request); - return archive.fetchData(request); - } - - public Archive findMatchingArchive(FetchRequest request) throws RrdException, IOException { - String consolFun = request.getConsolFun(); - long fetchStart = request.getFetchStart(); - long fetchEnd = request.getFetchEnd(); - long resolution = request.getResolution(); - Archive bestFullMatch = null, bestPartialMatch = null; - long bestStepDiff = 0, bestMatch = 0; - for (Archive archive : archives) { - if (archive.getConsolFun().equals(consolFun)) { - long arcStep = archive.getArcStep(); - long arcStart = archive.getStartTime() - arcStep; - long arcEnd = archive.getEndTime(); - long fullMatch = fetchEnd - fetchStart; - if (arcEnd >= fetchEnd && arcStart <= fetchStart) { - long tmpStepDiff = Math.abs(archive.getArcStep() - resolution); - - if (tmpStepDiff < bestStepDiff || bestFullMatch == null) { - bestStepDiff = tmpStepDiff; - bestFullMatch = archive; - } - } - else { - long tmpMatch = fullMatch; - - if (arcStart > fetchStart) { - tmpMatch -= (arcStart - fetchStart); - } - if (arcEnd < fetchEnd) { - tmpMatch -= (fetchEnd - arcEnd); - } - if (bestPartialMatch == null || bestMatch < tmpMatch) { - bestPartialMatch = archive; - bestMatch = tmpMatch; - } - } - } - } - if (bestFullMatch != null) { - return bestFullMatch; - } - else if (bestPartialMatch != null) { - return bestPartialMatch; - } - else { - throw new RrdException("RRD file does not contain RRA:" + consolFun + " archive"); - } - } - - /** - * Finds the archive that best matches to the start time (time period being start-time until now) - * and requested resolution. - * - * @param consolFun Consolidation function of the datasource. - * @param startTime Start time of the time period in seconds. - * @param resolution Requested fetch resolution. - * @return Reference to the best matching archive. - * @throws IOException Thrown in case of I/O related error. - */ - public Archive findStartMatchArchive(String consolFun, long startTime, long resolution) throws IOException { - long arcStep, diff; - int fallBackIndex = 0; - int arcIndex = -1; - long minDiff = Long.MAX_VALUE; - long fallBackDiff = Long.MAX_VALUE; - - for (int i = 0; i < archives.length; i++) { - if (archives[i].getConsolFun().equals(consolFun)) { - arcStep = archives[i].getArcStep(); - diff = Math.abs(resolution - arcStep); - - // Now compare start time, see if this archive encompasses the requested interval - if (startTime >= archives[i].getStartTime()) { - if (diff == 0) // Best possible match either way - { - return archives[i]; - } - else if (diff < minDiff) { - minDiff = diff; - arcIndex = i; - } - } - else if (diff < fallBackDiff) { - fallBackDiff = diff; - fallBackIndex = i; - } - } - } - - return (arcIndex >= 0 ? archives[arcIndex] : archives[fallBackIndex]); - } - - /** - * <p>Returns string representing complete internal RRD state. The returned - * string can be printed to <code>stdout</code> and/or used for debugging purposes.</p> - * - * @return String representing internal RRD state. - * @throws IOException Thrown in case of I/O related error. - */ - public synchronized String dump() throws IOException { - StringBuffer buffer = new StringBuffer(); - buffer.append(header.dump()); - for (Datasource datasource : datasources) { - buffer.append(datasource.dump()); - } - for (Archive archive : archives) { - buffer.append(archive.dump()); - } - return buffer.toString(); - } - - void archive(Datasource datasource, double value, long numUpdates) - throws IOException, RrdException { - int dsIndex = getDsIndex(datasource.getDsName()); - for (Archive archive : archives) { - archive.archive(dsIndex, value, numUpdates); - } - } - - /** - * <p>Returns internal index number for the given datasource name. This index is heavily - * used by jrobin.graph package and has no value outside of it.</p> - * - * @param dsName Data source name. - * @return Internal index of the given data source name in this RRD. - * @throws RrdException Thrown in case of JRobin related error (invalid data source name, - * for example) - * @throws IOException Thrown in case of I/O error. - */ - public int getDsIndex(String dsName) throws RrdException, IOException { - for (int i = 0; i < datasources.length; i++) { - if (datasources[i].getDsName().equals(dsName)) { - return i; - } - } - throw new RrdException("Unknown datasource name: " + dsName); - } - - /** - * Checks presence of a specific datasource. - * - * @param dsName Datasource name to check - * @return <code>true</code> if datasource is present in this RRD, <code>false</code> otherwise - * @throws IOException Thrown in case of I/O error. - */ - public boolean containsDs(String dsName) throws IOException { - for (Datasource datasource : datasources) { - if (datasource.getDsName().equals(dsName)) { - return true; - } - } - return false; - } - - Datasource[] getDatasources() { - return datasources; - } - - Archive[] getArchives() { - return archives; - } - - /** - * Writes the RRD content to OutputStream using XML format. This format - * is fully compatible with RRDTool's XML dump format and can be used for conversion - * purposes or debugging. - * - * @param destination Output stream to receive XML data - * @throws IOException Thrown in case of I/O related error - */ - public synchronized void dumpXml(OutputStream destination) throws IOException { - XmlWriter writer = new XmlWriter(destination); - writer.startTag("rrd"); - // dump header - header.appendXml(writer); - // dump datasources - for (Datasource datasource : datasources) { - datasource.appendXml(writer); - } - // dump archives - for (Archive archive : archives) { - archive.appendXml(writer); - } - writer.closeTag(); - writer.flush(); - } - - /** - * This method is just an alias for {@link #dumpXml(OutputStream) dumpXml} method. - * - * @param destination Output stream to receive XML data - * @throws IOException Thrown in case of I/O related error - */ - public synchronized void exportXml(OutputStream destination) throws IOException { - dumpXml(destination); - } - - /** - * Returns string representing internal RRD state in XML format. This format - * is fully compatible with RRDTool's XML dump format and can be used for conversion - * purposes or debugging. - * - * @return Internal RRD state in XML format. - * @throws IOException Thrown in case of I/O related error - * @throws RrdException Thrown in case of JRobin specific error - */ - public synchronized String getXml() throws IOException, RrdException { - ByteArrayOutputStream destination = new ByteArrayOutputStream(XML_INITIAL_BUFFER_CAPACITY); - dumpXml(destination); - return destination.toString(); - } - - /** - * This method is just an alias for {@link #getXml() getXml} method. - * - * @return Internal RRD state in XML format. - * @throws IOException Thrown in case of I/O related error - * @throws RrdException Thrown in case of JRobin specific error - */ - public synchronized String exportXml() throws IOException, RrdException { - return getXml(); - } - - /** - * Dumps internal RRD state to XML file. - * Use this XML file to convert your JRobin RRD to RRDTool format. - * <p> - * Suppose that you have a JRobin RRD file <code>original.rrd</code> and you want - * to convert it to RRDTool format. First, execute the following java code: - * <p> - * <code>RrdDb rrd = new RrdDb("original.rrd"); - * rrd.dumpXml("original.xml");</code> - * <p> - * Use <code>original.xml</code> file to create the corresponding RRDTool file - * (from your command line): - * <p> - * <code>rrdtool restore copy.rrd original.xml</code> - * - * @param filename Path to XML file which will be created. - * @throws IOException Thrown in case of I/O related error. - * @throws RrdException Thrown in case of JRobin related error. - */ - public synchronized void dumpXml(String filename) throws IOException, RrdException { - OutputStream outputStream = null; - try { - outputStream = new FileOutputStream(filename, false); - dumpXml(outputStream); - } - finally { - if (outputStream != null) { - outputStream.close(); - } - } - } - - /** - * This method is just an alias for {@link #dumpXml(String) dumpXml(String)} method. - * - * @param filename Path to XML file which will be created. - * @throws IOException Thrown in case of I/O related error - * @throws RrdException Thrown in case of JRobin specific error - */ - public synchronized void exportXml(String filename) throws IOException, RrdException { - dumpXml(filename); - } - - /** - * Returns time of last update operation as timestamp (in seconds). - * - * @return Last update time (in seconds). - * @throws IOException Thrown in case of I/O related error - */ - public synchronized long getLastUpdateTime() throws IOException { - return header.getLastUpdateTime(); - } - - /** - * Returns RRD definition object which can be used to create new RRD - * with the same creation parameters but with no data in it. - * <p> - * Example: - * <p> - * <pre> - * RrdDb rrd1 = new RrdDb("original.rrd"); - * RrdDef def = rrd1.getRrdDef(); - * // fix path - * def.setPath("empty_copy.rrd"); - * // create new RRD file - * RrdDb rrd2 = new RrdDb(def); - * </pre> - * - * @return RRD definition. - * @throws IOException Thrown in case of I/O related error. - * @throws RrdException Thrown in case of JRobin specific error. - */ - public synchronized RrdDef getRrdDef() throws RrdException, IOException { - // set header - long startTime = header.getLastUpdateTime(); - long step = header.getStep(); - String path = backend.getPath(); - RrdDef rrdDef = new RrdDef(path, startTime, step); - // add datasources - for (Datasource datasource : datasources) { - DsDef dsDef = new DsDef(datasource.getDsName(), - datasource.getDsType(), datasource.getHeartbeat(), - datasource.getMinValue(), datasource.getMaxValue()); - rrdDef.addDatasource(dsDef); - } - // add archives - for (Archive archive : archives) { - ArcDef arcDef = new ArcDef(archive.getConsolFun(), - archive.getXff(), archive.getSteps(), archive.getRows()); - rrdDef.addArchive(arcDef); - } - return rrdDef; - } - - protected void finalize() throws Throwable { - super.finalize(); - close(); - } - - /** - * Copies object's internal state to another RrdDb object. - * - * @param other New RrdDb object to copy state to - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if supplied argument is not a compatible RrdDb object - */ - public synchronized void copyStateTo(RrdUpdater other) throws IOException, RrdException { - if (!(other instanceof RrdDb)) { - throw new RrdException("Cannot copy RrdDb object to " + other.getClass().getName()); - } - RrdDb otherRrd = (RrdDb) other; - header.copyStateTo(otherRrd.header); - for (int i = 0; i < datasources.length; i++) { - int j = Util.getMatchingDatasourceIndex(this, i, otherRrd); - if (j >= 0) { - datasources[i].copyStateTo(otherRrd.datasources[j]); - } - } - for (int i = 0; i < archives.length; i++) { - int j = Util.getMatchingArchiveIndex(this, i, otherRrd); - if (j >= 0) { - archives[i].copyStateTo(otherRrd.archives[j]); - } - } - } - - /** - * Returns Datasource object corresponding to the given datasource name. - * - * @param dsName Datasource name - * @return Datasource object corresponding to the give datasource name or null - * if not found. - * @throws IOException Thrown in case of I/O error - */ - public Datasource getDatasource(String dsName) throws IOException { - try { - return getDatasource(getDsIndex(dsName)); - } - catch (RrdException e) { - return null; - } - } - - /** - * Returns index of Archive object with the given consolidation function and the number - * of steps. Exception is thrown if such archive could not be found. - * - * @param consolFun Consolidation function - * @param steps Number of archive steps - * @return Requested Archive object - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if no such archive could be found - */ - public int getArcIndex(String consolFun, int steps) throws RrdException, IOException { - for (int i = 0; i < archives.length; i++) { - if (archives[i].getConsolFun().equals(consolFun) && - archives[i].getSteps() == steps) { - return i; - } - } - throw new RrdException("Could not find archive " + consolFun + "/" + steps); - } - - /** - * Returns Archive object with the given consolidation function and the number - * of steps. - * - * @param consolFun Consolidation function - * @param steps Number of archive steps - * @return Requested Archive object or null if no such archive could be found - * @throws IOException Thrown in case of I/O error - */ - public Archive getArchive(String consolFun, int steps) throws IOException { - try { - return getArchive(getArcIndex(consolFun, steps)); - } - catch (RrdException e) { - return null; - } - } - - /** - * Returns canonical path to the underlying RRD file. Note that this method makes sense just for - * ordinary RRD files created on the disk - an exception will be thrown for RRD objects created in - * memory or with custom backends. - * - * @return Canonical path to RRD file; - * @throws IOException Thrown in case of I/O error or if the underlying backend is - * not derived from RrdFileBackend. - */ - public String getCanonicalPath() throws IOException { - if (backend instanceof RrdFileBackend) { - return ((RrdFileBackend) backend).getCanonicalPath(); - } - else { - throw new IOException("The underlying backend has no canonical path"); - } - } - - /** - * Returns path to this RRD. - * - * @return Path to this RRD. - */ - public String getPath() { - return backend.getPath(); - } - - /** - * Returns backend object for this RRD which performs actual I/O operations. - * - * @return RRD backend for this RRD. - */ - public RrdBackend getRrdBackend() { - return backend; - } - - /** - * Required to implement RrdUpdater interface. You should never call this method directly. - * - * @return Allocator object - */ - public RrdAllocator getRrdAllocator() { - return allocator; - } - - /** - * Returns an array of bytes representing the whole RRD. - * - * @return All RRD bytes - * @throws IOException Thrown in case of I/O related error. - */ - public synchronized byte[] getBytes() throws IOException { - return backend.readAll(); - } - - /** - * Sets default backend factory to be used. This method is just an alias for - * {@link RrdBackendFactory#setDefaultFactory(java.lang.String)}.<p> - * - * @param factoryName Name of the backend factory to be set as default. - * @throws RrdException Thrown if invalid factory name is supplied, or not called - * before the first backend object (before the first RrdDb object) is created. - */ - public static void setDefaultFactory(String factoryName) throws RrdException { - RrdBackendFactory.setDefaultFactory(factoryName); - } - - /** - * Returns an array of last datasource values. The first value in the array corresponds - * to the first datasource defined in the RrdDb and so on. - * - * @return Array of last datasource values - * @throws IOException Thrown in case of I/O error - */ - public synchronized double[] getLastDatasourceValues() throws IOException { - double[] values = new double[datasources.length]; - for (int i = 0; i < values.length; i++) { - values[i] = datasources[i].getLastValue(); - } - return values; - } - - /** - * Returns the last stored value for the given datasource. - * - * @param dsName Datasource name - * @return Last stored value for the given datasource - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown if no datasource in this RrdDb matches the given datasource name - */ - public synchronized double getLastDatasourceValue(String dsName) throws IOException, RrdException { - int dsIndex = getDsIndex(dsName); - return datasources[dsIndex].getLastValue(); - } - - /** - * Returns the number of datasources defined in the file - * - * @return The number of datasources defined in the file - */ - public int getDsCount() { - return datasources.length; - } - - /** - * Returns the number of RRA arcihves defined in the file - * - * @return The number of RRA arcihves defined in the file - */ - public int getArcCount() { - return archives.length; - } - - /** - * Returns the last time when some of the archives in this RRD was updated. This time is not the - * same as the {@link #getLastUpdateTime()} since RRD file can be updated without updating any of - * the archives. - * - * @return last time when some of the archives in this RRD was updated - * @throws IOException Thrown in case of I/O error - */ - public long getLastArchiveUpdateTime() throws IOException { - long last = 0; - for (Archive archive : archives) { - last = Math.max(last, archive.getEndTime()); - } - return last; - } - - public synchronized String getInfo() throws IOException { - return header.getInfo(); - } - - public synchronized void setInfo(String info) throws IOException { - header.setInfo(info); - } - - public static void main(String[] args) { - System.out.println("JRobin Java Library :: RRDTool choice for the Java world"); - System.out.println("=================================================================="); - System.out.println("JRobin base directory: " + Util.getJRobinHomeDirectory()); - long time = Util.getTime(); - System.out.println("Current timestamp: " + time + ": " + new Date(time * 1000L)); - System.out.println("------------------------------------------------------------------"); - System.out.println("For the latest information visit: http://www.jrobin.org"); - System.out.println("(C) 2003-2005 Sasa Markovic. All rights reserved."); - } - - public String toString() { - return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + "[" + new File(getPath()).getName() + "]"; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdDbPool.java b/apps/jrobin/java/src/org/jrobin/core/RrdDbPool.java deleted file mode 100644 index 3be890f3ea168476e0e7c487e5c129cad78494ec..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdDbPool.java +++ /dev/null @@ -1,932 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; -import java.util.HashMap; - -import org.jrobin.core.RrdException; - -/** - * This class should be used to synchronize access to RRD files - * in a multithreaded environment. This class should be also used to prevent openning of - * too many RRD files at the same time (thus avoiding operating system limits) - */ - -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. - */ - public static final int INITIAL_CAPACITY = 200; - private static RrdDbPool instance; - - private int capacity = INITIAL_CAPACITY; - private HashMap<String, RrdEntry> rrdMap = new HashMap<String, RrdEntry>(INITIAL_CAPACITY); - - /** - * Creates a single instance of the class on the first call, or returns already existing one. - * - * @return Single instance of this class - * @throws RrdException Thrown if the default RRD backend is not derived from the {@link RrdFileBackendFactory} - */ - public synchronized static RrdDbPool getInstance() throws RrdException { - if (instance == null) { - instance = new RrdDbPool(); - } - return instance; - } - - private RrdDbPool() throws RrdException { - RrdBackendFactory factory = RrdBackendFactory.getDefaultFactory(); - if (!(factory instanceof RrdFileBackendFactory)) { - throw new RrdException("Cannot create instance of " + getClass().getName() + " with " + - "a default backend factory not derived from RrdFileBackendFactory"); - } - } - - /** - * Requests a RrdDb reference for the given RRD file path.<p> - * <ul> - * <li>If the file 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. - * </ul> - * - * @param path Path to existing RRD file - * @return reference for the give RRD file - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public synchronized RrdDb requestRrdDb(String path) throws IOException, RrdException { - String canonicalPath = Util.getCanonicalPath(path); - while (!rrdMap.containsKey(canonicalPath) && rrdMap.size() >= capacity) { - try { - wait(); - } - catch (InterruptedException e) { - throw new RrdException(e); - } - } - if (rrdMap.containsKey(canonicalPath)) { - // already open, just increase usage count - RrdEntry entry = rrdMap.get(canonicalPath); - entry.count++; - return entry.rrdDb; - } - else { - // not open, open it now and add to the map - RrdDb rrdDb = new RrdDb(canonicalPath); - rrdMap.put(canonicalPath, new RrdEntry(rrdDb)); - return rrdDb; - } - } - - /** - * Requests a RrdDb reference for the given RRD file definition object.<p> - * <ul> - * <li>If the file 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. - * </ul> - * - * @param rrdDef Definition of the RRD file to be created - * @return Reference to the newly created RRD file - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public synchronized RrdDb requestRrdDb(RrdDef rrdDef) throws IOException, RrdException { - String canonicalPath = Util.getCanonicalPath(rrdDef.getPath()); - while (rrdMap.containsKey(canonicalPath) || rrdMap.size() >= capacity) { - try { - wait(); - } - catch (InterruptedException e) { - throw new RrdException(e); - } - } - RrdDb rrdDb = new RrdDb(rrdDef); - rrdMap.put(canonicalPath, new RrdEntry(rrdDb)); - return rrdDb; - } - - /** - * Requests a RrdDb reference for the given path. The file will be created from - * external data (from XML dump, RRD file or RRDTool's binary RRD file).<p> - * <ul> - * <li>If the file 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. - * </ul> - * - * @param path Path to RRD file which should be created - * @param sourcePath Path to external data which is to be converted to JRobin's native RRD file format - * @return Reference to the newly created RRD file - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public synchronized RrdDb requestRrdDb(String path, String sourcePath) - throws IOException, RrdException,RrdException { - String canonicalPath = Util.getCanonicalPath(path); - while (rrdMap.containsKey(canonicalPath) || rrdMap.size() >= capacity) { - try { - wait(); - } - catch (InterruptedException e) { - throw new RrdException(e); - } - } - RrdDb rrdDb = new RrdDb(canonicalPath, sourcePath); - rrdMap.put(canonicalPath, new RrdEntry(rrdDb)); - return rrdDb; - } - - /** - * 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. - * - * @param rrdDb RrdDb reference to be returned to the pool - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public synchronized void release(RrdDb rrdDb) throws IOException, RrdException { - // null pointer should not kill the thread, just ignore it - if (rrdDb == null) { - return; - } - String canonicalPath = Util.getCanonicalPath(rrdDb.getPath()); - if (!rrdMap.containsKey(canonicalPath)) { - throw new RrdException("Could not release [" + canonicalPath + "], the file was never requested"); - } - RrdEntry entry = rrdMap.get(canonicalPath); - if (--entry.count <= 0) { - // no longer used - rrdMap.remove(canonicalPath); - notifyAll(); - entry.rrdDb.close(); - } - } - - /** - * Returns the maximum number of simultaneously open RRD files. - * - * @return maximum number of simultaneously open RRD files - */ - public synchronized int getCapacity() { - return capacity; - } - - /** - * Sets the maximum number of simultaneously open RRD files. - * - * @param capacity Maximum number of simultaneously open RRD files. - */ - public synchronized void setCapacity(int capacity) { - this.capacity = capacity; - } - - /** - * Returns an array of open file names. - * - * @return Array with canonical paths to open RRD files held in the pool. - */ - public synchronized String[] getOpenFiles() { - return rrdMap.keySet().toArray(new String[0]); - } - - /** - * Returns the number of open RRD files. - * - * @return Number of currently open RRD files held in the pool. - */ - public synchronized int getOpenFileCount() { - return rrdMap.size(); - } - - private final static class RrdEntry { - RrdDb rrdDb; - int count; - - RrdEntry(final RrdDb rrdDb) { - this.rrdDb = rrdDb; - this.count = 1; - } - } -} - -// OLDER VERSION IS HERE - -///* ============================================================ -// * JRobin : Pure java implementation of RRDTool's functionality -// * ============================================================ -// * -// * Project Info: http://www.jrobin.org -// * Project Lead: Sasa Markovic (saxon@jrobin.org); -// * -// * (C) Copyright 2003-2005, by Sasa Markovic. -// * -// * Developers: Sasa Markovic (saxon@jrobin.org) -// * -// * -// * This library is free software; you can redistribute it and/or modify it under the terms -// * of the GNU Lesser General Public License as published by the Free Software Foundation; -// * either version 2.1 of the License, or (at your option) any later version. -// * -// * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -// * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -// * See the GNU Lesser General Public License for more details. -// * -// * You should have received a copy of the GNU Lesser General Public License along with this -// * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, -// * Boston, MA 02111-1307, USA. -// */ -//package org.jrobin.core; -// -//import java.io.IOException; -//import java.util.HashMap; -//import java.util.Iterator; -//import java.util.LinkedHashMap; -//import java.util.Set; -// -///** -// * Class to represent the pool of open RRD files.<p> -// * -// * To open already existing RRD file with JRobin, you have to create a -// * {@link org.jrobin.core.RrdDb RrdDb} object by specifying RRD file path -// * as constructor argument. This operation can be time consuming -// * especially with large RRD files with many datasources and -// * several long archives.<p> -// * -// * In a multithreaded environment you might probably need a reference to the -// * same RRD file from two different threads (RRD file updates are performed in -// * one thread but data fetching and graphing is performed in another one). To make -// * the RrdDb construction process more efficient it might be convenient to open all -// * RRD files in a centralized place. That's the purpose of RrdDbPool class.<p> -// * -// * How does it work? The typical usage scenario goes like this:<p> -// * -// * <pre> -// * // obtain instance to RrdDbPool object -// * RrdDbPool pool = RrdDbPool.getInstance(); -// * -// * // request a reference to RrdDb object -// * String path = "some_relative_or_absolute_path_to_any_RRD_file"; -// * RrdDb rrdDb = RrdDbPool.requestRrdDb(path); -// * -// * // reference obtained, do whatever you want with it... -// * ... -// * ... -// * -// * // once you don't need the reference, release it. -// * // DO NOT CALL rrdDb.close() - files no longer in use are eventually closed by the pool -// * pool.release(rrdDb); -// * </pre> -// * -// * It's that simple. When the reference is requested for the first time, RrdDbPool will open the RRD file -// * for you and make some internal note that the RRD file is used only once. When the reference -// * to the same file (same RRD file path) is requested for the second time, the same RrdDb -// * reference will be returned, and its usage count will be increased by one. When the -// * reference is released its usage count will be decremented by one.<p> -// * -// * When the reference count drops to zero, RrdDbPool will not close the underlying -// * RRD file immediatelly. Instead of it, it will be marked as 'eligible for closing'. -// * If someone request the same RRD file again (before it gets closed), the same -// * reference will be returned again.<p> -// * -// * RrdDbPool has a 'garbage collector' which runs in a separate, low-priority -// * thread and gets activated only when the number of RRD files kept in the -// * pool is too big (greater than number returned from {@link #getCapacity getCapacity()}). -// * Only RRD files with a reference count equal to zero -// * will be eligible for closing. Unreleased RrdDb references are never invalidated. -// * RrdDbPool object keeps track of the time when each RRD file -// * becomes eligible for closing so that the oldest RRD file gets closed first.<p> -// * -// * Initial RrdDbPool capacity is set to {@link #INITIAL_CAPACITY}. Use {@link #setCapacity(int)} -// * method to change it at any time.<p> -// * -// * <b>WARNING:</b>Never use close() method on the reference returned from the pool. -// * When the reference is no longer needed, return it to the pool with the -// * {@link #release(RrdDb) release()} method.<p> -// * -// * However, you are not forced to use RrdDbPool methods to obtain RrdDb references -// * to RRD files, 'ordinary' RrdDb constructors are still available. But RrdDbPool class -// * offers serious performance improvement especially in complex applications with many -// * threads and many simultaneously open RRD files.<p> -// * -// * The pool is thread-safe. Not that the {@link RrdDb} objects returned from the pool are -// * also thread-safe<p> -// * -// * You should know that each operating system has its own internal limit on the number -// * of simultaneously open files. The capacity of your RrdDbPool should be -// * reasonably smaller than the limit imposed by your operating system.<p> -// * -// * <b>WARNING:</b> The pool cannot be used to manipulate RrdDb objects -// * with {@link RrdBackend backends} different from default.<p> -// */ -//public class RrdDbPool implements Runnable { -// static final String GC_THREAD_NAME = "RrdDbPool GC thread"; -// static final String CLOSING_THREAD_NAME = "RrdDbPool closing thread"; -// private static final boolean DEBUG = false; -// -// // singleton pattern -// private static RrdDbPool ourInstance; -// private boolean closingOnExit = true; -// -// private Thread shutdownHook = new Thread(CLOSING_THREAD_NAME) { -// public void run() { -// try { -// close(); -// } -// catch (IOException e) { -// e.printStackTrace(); -// } -// } -// }; -// -// /** -// * Constant to represent the maximum number of internally open RRD files -// * which still does not force garbage collector (the process which closes RRD files) to run. -// */ -// public static final int INITIAL_CAPACITY = 500; -// private int capacity = INITIAL_CAPACITY, maxUsedCapacity; -// private boolean active = true; -// -// /** -// * Constant to represent the internal behaviour of the pool. -// * Defaults to <code>true</code> but can be changed at runtime. See -// * {@link #setLimitedCapacity(boolean)} for more information. -// */ -// public static final boolean LIMITED_CAPACITY = false; -// private boolean limitedCapacity = LIMITED_CAPACITY; -// -// /** -// * Constant to represent the priority of the background thread which closes excessive RRD files -// * which are no longer in use. -// */ -// public static final int GC_THREAD_PRIORITY = /** Thread.NORM_PRIORITY - */ 1; -// -// private HashMap<String, RrdEntry> rrdMap = new HashMap<String, RrdEntry>(INITIAL_CAPACITY); -// private LinkedHashMap<String, RrdEntry> rrdIdleMap = new LinkedHashMap<String, RrdEntry>(INITIAL_CAPACITY); -// private RrdBackendFactory factory; -// private int poolHitsCount = 0, poolRequestsCount = 0; -// -// /** -// * Returns an instance to RrdDbPool object. Only one such object may exist in each JVM. -// * -// * @return Instance to RrdDbPool object. -// */ -// public synchronized static RrdDbPool getInstance() { -// if (ourInstance == null) { -// ourInstance = new RrdDbPool(); -// ourInstance.startGarbageCollector(); -// } -// return ourInstance; -// } -// -// private RrdDbPool() { -// setClosingOnExit(closingOnExit); -// } -// -// /** -// * Checks the exiting behaviour of RrdDbPool. -// * @return <code>True</code>, if all RRD files are to be closed -// * when application invokes <code>System.exit()</code>. -// * <code>False</code> otherwise. The default behaviour is <code>true</code> -// * (all RRD files will be closed on exit). -// */ -// public synchronized boolean isClosingOnExit() { -// return closingOnExit; -// } -// -// /** -// * Sets the exiting behaviour of RrdDbPool. -// * @param closingOnExit <code>True</code>, if all RRD files are to be closed -// * when application invokes <code>System.exit()</code>. -// * <code>False</code> otherwise. The default behaviour is <code>true</code> -// * (all RRD files will be closed on exit). -// */ -// public synchronized void setClosingOnExit(boolean closingOnExit) { -// Runtime runtime = Runtime.getRuntime(); -// runtime.removeShutdownHook(shutdownHook); -// if(closingOnExit) { -// runtime.addShutdownHook(shutdownHook); -// } -// this.closingOnExit = closingOnExit; -// } -// -// private void startGarbageCollector() { -// Thread gcThread = new Thread(this, GC_THREAD_NAME); -// gcThread.setPriority(GC_THREAD_PRIORITY); -// gcThread.setDaemon(true); -// gcThread.start(); -// } -// -// /** -// * Returns a reference to an existing RRD file with the specified path. -// * If the file is already open in the pool, existing reference to it will be returned. -// * Otherwise, the file is open and a newly created reference to it is returned. -// * -// * @param path Relative or absolute path to a RRD file. -// * @return Reference to a RrdDb object (RRD file). -// * @throws IOException Thrown in case of I/O error. -// * @throws RrdException Thrown in case of JRobin specific error. -// */ -// public synchronized RrdDb requestRrdDb(String path) throws IOException, RrdException { -// proveActive(); -// poolRequestsCount++; -// String canonicalPath = getCanonicalPath(path); -// for(;;) { -// RrdEntry rrdEntry = rrdMap.get(canonicalPath); -// if (rrdEntry != null) { -// // already open, use it! -// reportUsage(canonicalPath, rrdEntry); -// poolHitsCount++; -//// debug("CACHED: " + rrdEntry.dump()); -// return rrdEntry.getRrdDb(); -// } -// else if(!limitedCapacity || rrdMap.size() < capacity) { -// // not found, open it -// RrdDb rrdDb = createRrdDb(path, null); -// rrdEntry = new RrdEntry(rrdDb); -// addRrdEntry(canonicalPath, rrdEntry); -//// debug("ADDED: " + rrdEntry.dump()); -// return rrdDb; -// } -// else { -// // we have to wait -// try { -// wait(); -// } -// catch (InterruptedException e) { -// throw new RrdException("Request for file '" + path + "' was interrupted"); -// } -// } -// } -// } -// -// /** -// * Returns a reference to a new RRD file. The new file will have the specified -// * relative or absolute path, and its contents will be provided from the specified -// * XML file (RRDTool comaptible). -// * -// * @param path Relative or absolute path to a new RRD file. -// * @param xmlPath Relative or absolute path to an existing XML dump file (RRDTool comaptible) -// * @return Reference to a RrdDb object (RRD file). -// * @throws IOException Thrown in case of I/O error. -// * @throws RrdException Thrown in case of JRobin specific error. -// */ -// public synchronized RrdDb requestRrdDb(String path, String xmlPath) -// throws IOException, RrdException { -// return requestNewRrdDb(path, xmlPath); -// } -// -// /** -// * Returns a reference to a new RRD file. The new file will be created based on the -// * definition contained in a RrdDef object. -// * -// * @param rrdDef RRD definition object -// * @return Reference to a RrdDb object (RRD file). -// * @throws IOException Thrown in case of I/O error. -// * @throws RrdException Thrown in case of JRobin specific error. -// */ -// public synchronized RrdDb requestRrdDb(RrdDef rrdDef) throws IOException, RrdException { -// return requestNewRrdDb(rrdDef.getPath(), rrdDef); -// } -// -// private RrdDb requestNewRrdDb(String path, Object creationDef) throws IOException, RrdException { -// proveActive(); -// poolRequestsCount++; -// String canonicalPath = getCanonicalPath(path); -// for(;;) { -// RrdEntry rrdEntry = rrdMap.get(canonicalPath); -// if(rrdEntry != null) { -// // already open -// removeIfIdle(canonicalPath, rrdEntry); -// } -// else if(!limitedCapacity || rrdMap.size() < capacity) { -// RrdDb rrdDb = createRrdDb(path, creationDef); -// RrdEntry newRrdEntry = new RrdEntry(rrdDb); -// addRrdEntry(canonicalPath, newRrdEntry); -//// debug("ADDED: " + newRrdEntry.dump()); -// return rrdDb; -// } -// else { -// // we have to wait -// try { -// wait(); -// } -// catch (InterruptedException e) { -// throw new RrdException("Request for file '" + path + "' was interrupted"); -// } -// } -// } -// } -// -// private RrdDb createRrdDb(String path, Object creationDef) throws RrdException, IOException { -// if(creationDef == null) { -// // existing RRD -// return new RrdDb(path, getFactory()); -// } -// else if(creationDef instanceof String) { -// // XML input -// return new RrdDb(path, (String) creationDef, getFactory()); -// } -// else if(creationDef instanceof RrdDef) { -// // RrdDef -// return new RrdDb((RrdDef) creationDef, getFactory()); -// } -// else { -// throw new RrdException("Unexpected input object type: " + -// creationDef.getClass().getName()); -// } -// } -// -// private void reportUsage(String canonicalPath, RrdEntry rrdEntry) { -// if (rrdEntry.reportUsage() == 1) { -// // must not be garbage collected -// rrdIdleMap.remove(canonicalPath); -// } -// } -// -// private void reportRelease(String canonicalPath, RrdEntry rrdEntry) { -// if (rrdEntry.reportRelease() == 0) { -// // ready to be garbage collected -// rrdIdleMap.put(canonicalPath, rrdEntry); -// } -// } -// -// private void addRrdEntry(String canonicalPath, RrdEntry newRrdEntry) { -// rrdMap.put(canonicalPath, newRrdEntry); -// maxUsedCapacity = Math.max(rrdMap.size(), maxUsedCapacity); -// // notify waiting threads -// notifyAll(); -// } -// -// private void removeIfIdle(String canonicalPath, RrdEntry rrdEntry) -// throws RrdException, IOException { -// // already open, check if active (not released) -// if (rrdEntry.isInUse()) { -// // not released, not allowed here -// throw new RrdException("Cannot create new RrdDb file: " + -// "File '" + canonicalPath + "' already in use"); -// } else { -// // open but released... safe to close it -//// debug("WILL BE RECREATED: " + rrdEntry.dump()); -// removeRrdEntry(canonicalPath, rrdEntry); -// } -// } -// -// private void removeRrdEntry(String canonicalPath, RrdEntry rrdEntry) throws IOException { -// rrdEntry.closeRrdDb(); -// rrdMap.remove(canonicalPath); -// rrdIdleMap.remove(canonicalPath); -//// debug("REMOVED: " + rrdEntry.dump()); -// } -// -// /** -// * Method used to report that the reference to a RRD file is no longer needed. File that -// * is no longer needed (all references to it are released) is marked 'eligible for -// * closing'. It will be eventually closed by the pool when the number of open RRD files -// * becomes too big. Most recently released files will be closed last. -// * -// * @param rrdDb Reference to RRD file that is no longer needed. -// * @throws IOException Thrown in case of I/O error. -// * @throws RrdException Thrown in case of JRobin specific error. -// */ -// public synchronized void release(RrdDb rrdDb) throws IOException, RrdException { -// proveActive(); -// if (rrdDb == null) { -// // we don't want NullPointerException -// return; -// } -// if (rrdDb.isClosed()) { -// throw new RrdException("File " + rrdDb.getPath() + " already closed"); -// } -// String canonicalPath = getCanonicalPath(rrdDb.getPath()); -// if (rrdMap.containsKey(canonicalPath)) { -// RrdEntry rrdEntry = rrdMap.get(canonicalPath); -// reportRelease(canonicalPath, rrdEntry); -//// debug("RELEASED: " + rrdEntry.dump()); -// } else { -// throw new RrdException("RRD file " + rrdDb.getPath() + " not in the pool"); -// } -// // notify waiting threads -// notifyAll(); -// } -// -// /** -// * This method runs garbage collector in a separate thread. If the number of -// * open RRD files kept in the pool is too big (greater than number -// * returned from {@link #getCapacity getCapacity()}), garbage collector will try -// * to close and remove RRD files with a reference count equal to zero. -// * Never call this method directly. -// */ -// public void run() { -//// debug("GC: started"); -// while (active) { -// synchronized (this) { -// if (rrdMap.size() >= capacity && rrdIdleMap.size() > 0) { -// try { -// String canonicalPath = rrdIdleMap.keySet().iterator().next(); -// RrdEntry rrdEntry = rrdIdleMap.get(canonicalPath); -//// debug("GC: closing " + rrdEntry.dump()); -// removeRrdEntry(canonicalPath, rrdEntry); -// } catch (IOException e) { -// e.printStackTrace(); -// } -// notifyAll(); -// } -// else { -// try { -//// debug("GC: waiting"); -// wait(); -//// debug("GC: running"); -// } catch (InterruptedException e) { -// e.printStackTrace(); -// } -// } -// } -// } -// } -// -// protected void finalize() throws IOException { -// close(); -// } -// -// /** -// * Clears the internal state of the pool entirely. All open RRD files are closed. -// * -// * @throws IOException Thrown in case of I/O related error. -// */ -// public synchronized void reset() throws IOException { -// Iterator<RrdEntry> it = rrdMap.values().iterator(); -// while (it.hasNext()) { -// RrdEntry rrdEntry = it.next(); -// rrdEntry.closeRrdDb(); -// } -// rrdMap.clear(); -// rrdIdleMap.clear(); -//// debug("Pool cleared"); -// } -// -// /** -// * Closes the pool and all RRD files currently held in the pool. -// * No further operations on the pool are allowed. -// * @throws IOException Thrown in case of I/O error. -// */ -// public synchronized void close() throws IOException { -// if(active) { -// active = false; -// reset(); -//// debug("The pool is closed."); -// } -// else { -//// debug("The pool is already closed!"); -// } -// } -// -// private static String getCanonicalPath(String path) throws IOException { -// return Util.getCanonicalPath(path); -// } -// -// static void debug(String msg) { -// if (DEBUG) { -// System.out.println("POOL: " + msg); -// } -// } -// -// /** -// * Returns the internal state of the pool. Useful for debugging purposes. -// * -// * @param dumpFiles <code>true</code>, if dumped information should contain paths to open files -// * currently held in the pool, <code>false</code> otherwise -// * @return Internal pool state (with an optional list of open RRD files and -// * the current number of usages for each one). -// * @throws IOException Thrown in case of I/O error. -// */ -// public synchronized String dump(boolean dumpFiles) throws IOException { -// StringBuffer buff = new StringBuffer(); -// buff.append("==== POOL DUMP ===========================\n"); -// buff.append("open=" + rrdMap.size() + ", idle=" + rrdIdleMap.size() + "\n"); -// buff.append("capacity=" + capacity + ", " + "maxUsedCapacity=" + maxUsedCapacity + "\n"); -// buff.append("hits=" + poolHitsCount + ", " + "requests=" + poolRequestsCount + "\n"); -// buff.append("efficiency=" + getPoolEfficiency() + "\n"); -// if(dumpFiles) { -// buff.append("---- CACHED FILES ------------------------\n"); -// Iterator<RrdEntry> it = rrdMap.values().iterator(); -// while (it.hasNext()) { -// RrdEntry rrdEntry = it.next(); -// buff.append(rrdEntry.dump() + "\n"); -// } -// } -// return buff.toString(); -// } -// -// /** -// * Returns the complete internal state of the pool. Useful for debugging purposes. -// * -// * @return Internal pool state (with a list of open RRD files and the current number of -// * usages for each one). -// * @throws IOException Thrown in case of I/O error. -// */ -// public synchronized String dump() throws IOException { -// return dump(true); -// } -// -// /** -// * Returns paths to all open files currently held in the pool. -// * @return An array containing open file paths. -// */ -// public synchronized String[] getCachedFilePaths() { -// Set<String> keySet = rrdMap.keySet(); -// int n = keySet.size(), i = 0; -// String[] files = new String[n]; -// Iterator<String> it = keySet.iterator(); -// while(it.hasNext()) { -// files[i++] = it.next(); -// } -// return files; -// } -// -// /** -// * Returns maximum number of internally open RRD files -// * which still does not force garbage collector to run. -// * -// * @return Desired nuber of open files held in the pool. -// */ -// public synchronized int getCapacity() { -// return capacity; -// } -// -// /** -// * Sets maximum number of internally open RRD files -// * which still does not force garbage collector to run. -// * -// * @param capacity Desired number of open files to hold in the pool -// */ -// public synchronized void setCapacity(int capacity) { -// this.capacity = capacity; -//// debug("Capacity set to: " + capacity); -// } -// -// private RrdBackendFactory getFactory() throws RrdException { -// if (factory == null) { -// factory = RrdBackendFactory.getDefaultFactory(); -// if (!(factory instanceof RrdFileBackendFactory)) { -// factory = null; -// throw new RrdException( -// "RrdDbPool cannot work with factories not derived from RrdFileBackendFactory"); -// } -// } -// return factory; -// } -// -// private class RrdEntry { -// private RrdDb rrdDb; -// private int usageCount = 1; -// -// public RrdEntry(RrdDb rrdDb) { -// this.rrdDb = rrdDb; -// } -// -// RrdDb getRrdDb() { -// return rrdDb; -// } -// -// int reportUsage() { -// assert usageCount >= 0: "Unexpected reportUsage count: " + usageCount; -// return ++usageCount; -// } -// -// int reportRelease() { -// assert usageCount > 0: "Unexpected reportRelease count: " + usageCount; -// return --usageCount; -// } -// -// boolean isInUse() { -// return usageCount > 0; -// } -// -// void closeRrdDb() throws IOException { -// rrdDb.close(); -// } -// -// String dump() throws IOException { -// String canonicalPath = getCanonicalPath(rrdDb.getPath()); -// return canonicalPath + " [" + usageCount + "]"; -// } -// } -// -// /** -// * Calculates pool's efficency ratio. The ratio is obtained by dividing the number of -// * RrdDb requests served from the internal pool of open RRD files -// * with the number of total RrdDb requests. -// * -// * @return Pool's efficiency ratio as a double between 1 (best) and 0 (worst). -// * If no RrdDb reference was ever requested, 1 would be returned. -// */ -// public synchronized double getPoolEfficiency() { -// if (poolRequestsCount == 0) { -// return 1.0; -// } -// double ratio = (double) poolHitsCount / (double) poolRequestsCount; -// // round to 3 decimal digits -// return Math.round(ratio * 1000.0) / 1000.0; -// } -// -// /** -// * Returns the number of RRD requests served from the internal pool of open RRD files -// * -// * @return The number of pool "hits". -// */ -// public synchronized int getPoolHitsCount() { -// return poolHitsCount; -// } -// -// /** -// * Returns the total number of RRD requests successfully served by this pool. -// * -// * @return Total number of RRD requests -// */ -// public synchronized int getPoolRequestsCount() { -// return poolRequestsCount; -// } -// -// /** -// * Returns the maximum number of open RRD files over the lifetime -// * of the pool. -// * @return maximum number of open RRD files. -// */ -// public synchronized int getMaxUsedCapacity() { -// return maxUsedCapacity; -// } -// -// /** -// * Checks the internal behaviour of the pool. See {@link #setLimitedCapacity(boolean)} for -// * more information. -// * -// * @return <code>true</code> if the pool is 'flexible' (by not imposing the strict -// * limit on the number of simultaneously open files), <code>false</code> otherwise. -// */ -// public synchronized boolean isLimitedCapacity() { -// return limitedCapacity; -// } -// -// /** -// * Sets the behaviour of the pool. If <code>true</code> is passed as argument, the pool will never -// * open more than {@link #getCapacity()} files at any time. If set to <code>false</code>, -// * the pool might keep more open files, but only for a short period of time. This method might be -// * useful if you want avoid OS limits when it comes to the number of simultaneously open files.<p> -// * -// * By default, the pool behaviour is 'flexible' (<code>limitedCapacity</code> property defaults -// * to false<p> -// * -// * @param limitedCapacity <code>true</code> if the pool should be 'flexible' (not imposing the strict -// * limit on the number of simultaneously open files), <code>false</code> otherwise. -// */ -// public synchronized void setLimitedCapacity(boolean limitedCapacity) { -// this.limitedCapacity = limitedCapacity; -// } -// -// private void proveActive() throws IOException { -// if(!active) { -// throw new IOException("RrdDbPool is already closed"); -// } -// } -// -// /** -// * Checks if the pool is active. You can request RrdDb references only from the active pool. The -// * pool is deactived when the {@link #close()} method is called. -// * @return <code>true</code> if active, <code>false</code> otherwise. -// */ -// public synchronized boolean isActive() { -// return active; -// } -//} -// diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdDef.java b/apps/jrobin/java/src/org/jrobin/core/RrdDef.java deleted file mode 100644 index e5369761d87f3b229f4c13ccb5078fb703d92c34..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdDef.java +++ /dev/null @@ -1,694 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.ByteArrayOutputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.*; - -/** - * Class to represent definition of new Round Robin Database (RRD). - * Object of this class is used to create - * new RRD from scratch - pass its reference as a <code>RrdDb</code> constructor - * argument (see documentation for {@link RrdDb RrdDb} class). <code>RrdDef</code> - * object <b>does not</b> actually create new RRD. It just holds all necessary - * information which will be used during the actual creation process. - * <p> - * RRD definition (RrdDef object) consists of the following elements: - * <p> - * <ul> - * <li> path to RRD that will be created - * <li> starting timestamp - * <li> step - * <li> one or more datasource definitions - * <li> one or more archive definitions - * </ul> - * RrdDef provides API to set all these elements. For the complete explanation of all - * RRD definition parameters, see RRDTool's - * <a href="../../../../man/rrdcreate.html" target="man">rrdcreate man page</a>. - * <p> - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ -public class RrdDef { - /** - * default RRD step to be used if not specified in constructor (300 seconds) - */ - public static final long DEFAULT_STEP = 300L; - /** - * if not specified in constructor, starting timestamp will be set to the - * current timestamp plus DEFAULT_INITIAL_SHIFT seconds (-10) - */ - public static final long DEFAULT_INITIAL_SHIFT = -10L; - - private String path; - private long startTime = Util.getTime() + DEFAULT_INITIAL_SHIFT; - private long step = DEFAULT_STEP; - private ArrayList<DsDef> dsDefs = new ArrayList<DsDef>(); - private ArrayList<ArcDef> arcDefs = new ArrayList<ArcDef>(); - - /** - * <p>Creates new RRD definition object with the given path. - * When this object is passed to - * <code>RrdDb</code> constructor, new RRD will be created using the - * specified path. </p> - * - * @param path Path to new RRD. - * @throws RrdException Thrown if name is invalid (null or empty). - */ - public RrdDef(final String path) throws RrdException { - if (path == null || path.length() == 0) { - throw new RrdException("No path specified"); - } - this.path = path; - } - - /** - * <p>Creates new RRD definition object with the given path and step.</p> - * - * @param path Path to new RRD. - * @param step RRD step. - * @throws RrdException Thrown if supplied parameters are invalid. - */ - public RrdDef(final String path, final long step) throws RrdException { - this(path); - if (step <= 0) { - throw new RrdException("Invalid RRD step specified: " + step); - } - this.step = step; - } - - /** - * <p>Creates new RRD definition object with the given path, starting timestamp - * and step.</p> - * - * @param path Path to new RRD. - * @param startTime RRD starting timestamp. - * @param step RRD step. - * @throws RrdException Thrown if supplied parameters are invalid. - */ - public RrdDef(final String path, final long startTime, final long step) throws RrdException { - this(path, step); - if (startTime < 0) { - throw new RrdException("Invalid RRD start time specified: " + startTime); - } - this.startTime = startTime; - } - - /** - * Returns path for the new RRD - * - * @return path to the new RRD which should be created - */ - public String getPath() { - return path; - } - - /** - * Returns starting timestamp for the RRD that should be created. - * - * @return RRD starting timestamp - */ - public long getStartTime() { - return startTime; - } - - /** - * Returns time step for the RRD that will be created. - * - * @return RRD step - */ - public long getStep() { - return step; - } - - /** - * Sets path to RRD. - * - * @param path to new RRD. - */ - public void setPath(final String path) { - this.path = path; - } - - /** - * Sets RRD's starting timestamp. - * - * @param startTime starting timestamp. - */ - public void setStartTime(final long startTime) { - this.startTime = startTime; - } - - /** - * Sets RRD's starting timestamp. - * - * @param date starting date - */ - public void setStartTime(final Date date) { - this.startTime = Util.getTimestamp(date); - } - - /** - * Sets RRD's starting timestamp. - * - * @param gc starting date - */ - public void setStartTime(final Calendar gc) { - this.startTime = Util.getTimestamp(gc); - } - - /** - * Sets RRD's time step. - * - * @param step RRD time step. - */ - public void setStep(final long step) { - this.step = step; - } - - /** - * Adds single datasource definition represented with object of class <code>DsDef</code>. - * - * @param dsDef Datasource definition. - * @throws RrdException Thrown if new datasource definition uses already used data - * source name. - */ - public void addDatasource(final DsDef dsDef) throws RrdException { - if (dsDefs.contains(dsDef)) { - throw new RrdException("Datasource already defined: " + dsDef.dump()); - } - dsDefs.add(dsDef); - } - - /** - * Adds single datasource to RRD definition by specifying its data source name, source type, - * heartbeat, minimal and maximal value. For the complete explanation of all data - * source definition parameters see RRDTool's - * <a href="../../../../man/rrdcreate.html" target="man">rrdcreate man page</a>. - * <p> - * <b>IMPORTANT NOTE:</b> If datasource name ends with '!', corresponding archives will never - * store NaNs as datasource values. In that case, NaN datasource values will be silently - * replaced with zeros by the framework. - * - * @param dsName Data source name. - * @param dsType Data source type. Valid types are "COUNTER", - * "GAUGE", "DERIVE" and "ABSOLUTE" (these string constants are conveniently defined in - * the {@link DsTypes} class). - * @param heartbeat Data source heartbeat. - * @param minValue Minimal acceptable value. Use <code>Double.NaN</code> if unknown. - * @param maxValue Maximal acceptable value. Use <code>Double.NaN</code> if unknown. - * @throws RrdException Thrown if new datasource definition uses already used data - * source name. - */ - public void addDatasource(final String dsName, final String dsType, final long heartbeat, final double minValue, final double maxValue) throws RrdException { - addDatasource(new DsDef(dsName, dsType, heartbeat, minValue, maxValue)); - } - - /** - * Adds single datasource to RRD definition from a RRDTool-like - * datasource definition string. The string must have six elements separated with colons - * (:) in the following order: - * <p> - * <pre> - * DS:name:type:heartbeat:minValue:maxValue - * </pre> - * For example: - * <p> - * <pre> - * DS:input:COUNTER:600:0:U - * </pre> - * For more information on datasource definition parameters see <code>rrdcreate</code> - * man page. - * - * @param rrdToolDsDef Datasource definition string with the syntax borrowed from RRDTool. - * @throws RrdException Thrown if invalid string is supplied. - */ - public void addDatasource(final String rrdToolDsDef) throws RrdException { - final RrdException rrdException = new RrdException("Wrong rrdtool-like datasource definition: " + rrdToolDsDef); - final StringTokenizer tokenizer = new StringTokenizer(rrdToolDsDef, ":"); - if (tokenizer.countTokens() != 6) { - throw rrdException; - } - final String[] tokens = new String[6]; - for (int curTok = 0; tokenizer.hasMoreTokens(); curTok++) { - tokens[curTok] = tokenizer.nextToken(); - } - if (!tokens[0].equalsIgnoreCase("DS")) { - throw rrdException; - } - final String dsName = tokens[1]; - final String dsType = tokens[2]; - long dsHeartbeat; - try { - dsHeartbeat = Long.parseLong(tokens[3]); - } - catch (final NumberFormatException nfe) { - throw rrdException; - } - double minValue = Double.NaN; - if (!tokens[4].equalsIgnoreCase("U")) { - try { - minValue = Double.parseDouble(tokens[4]); - } - catch (final NumberFormatException nfe) { - throw rrdException; - } - } - double maxValue = Double.NaN; - if (!tokens[5].equalsIgnoreCase("U")) { - try { - maxValue = Double.parseDouble(tokens[5]); - } - catch (final NumberFormatException nfe) { - throw rrdException; - } - } - addDatasource(new DsDef(dsName, dsType, dsHeartbeat, minValue, maxValue)); - } - - /** - * Adds data source definitions to RRD definition in bulk. - * - * @param dsDefs Array of data source definition objects. - * @throws RrdException Thrown if duplicate data source name is used. - */ - public void addDatasource(final DsDef[] dsDefs) throws RrdException { - for (final DsDef dsDef : dsDefs) { - addDatasource(dsDef); - } - } - - /** - * Adds single archive definition represented with object of class <code>ArcDef</code>. - * - * @param arcDef Archive definition. - * @throws RrdException Thrown if archive with the same consolidation function - * and the same number of steps is already added. - */ - public void addArchive(final ArcDef arcDef) throws RrdException { - if (arcDefs.contains(arcDef)) { - throw new RrdException("Archive already defined: " + arcDef.dump()); - } - arcDefs.add(arcDef); - } - - /** - * Adds archive definitions to RRD definition in bulk. - * - * @param arcDefs Array of archive definition objects - * @throws RrdException Thrown if RRD definition already contains archive with - * the same consolidation function and the same number of steps. - */ - public void addArchive(final ArcDef[] arcDefs) throws RrdException { - for (final ArcDef arcDef : arcDefs) { - addArchive(arcDef); - } - } - - /** - * Adds single archive definition by specifying its consolidation function, X-files factor, - * number of steps and rows. For the complete explanation of all archive - * definition parameters see RRDTool's - * <a href="../../../../man/rrdcreate.html" target="man">rrdcreate man page</a>. - * <p> - * - * @param consolFun Consolidation function. Valid values are "AVERAGE", - * "MIN", "MAX" and "LAST" (these constants are conveniently defined in the - * {@link ConsolFuns} class) - * @param xff X-files factor. Valid values are between 0 and 1. - * @param steps Number of archive steps - * @param rows Number of archive rows - * @throws RrdException Thrown if archive with the same consolidation function - * and the same number of steps is already added. - */ - public void addArchive(final String consolFun, final double xff, final int steps, final int rows) throws RrdException { - addArchive(new ArcDef(consolFun, xff, steps, rows)); - } - - /** - * Adds single archive to RRD definition from a RRDTool-like - * archive definition string. The string must have five elements separated with colons - * (:) in the following order: - * <p> - * <pre> - * RRA:consolidationFunction:XFilesFactor:steps:rows - * </pre> - * For example: - * <p> - * <pre> - * RRA:AVERAGE:0.5:10:1000 - * </pre> - * For more information on archive definition parameters see <code>rrdcreate</code> - * man page. - * - * @param rrdToolArcDef Archive definition string with the syntax borrowed from RRDTool. - * @throws RrdException Thrown if invalid string is supplied. - */ - public void addArchive(final String rrdToolArcDef) throws RrdException { - final RrdException rrdException = new RrdException("Wrong rrdtool-like archive definition: " + rrdToolArcDef); - final StringTokenizer tokenizer = new StringTokenizer(rrdToolArcDef, ":"); - if (tokenizer.countTokens() != 5) { - throw rrdException; - } - final String[] tokens = new String[5]; - for (int curTok = 0; tokenizer.hasMoreTokens(); curTok++) { - tokens[curTok] = tokenizer.nextToken(); - } - if (!tokens[0].equalsIgnoreCase("RRA")) { - throw rrdException; - } - final String consolFun = tokens[1]; - double xff; - try { - xff = Double.parseDouble(tokens[2]); - } - catch (final NumberFormatException nfe) { - throw rrdException; - } - int steps; - try { - steps = Integer.parseInt(tokens[3]); - } - catch (final NumberFormatException nfe) { - throw rrdException; - } - int rows; - try { - rows = Integer.parseInt(tokens[4]); - } - catch (final NumberFormatException nfe) { - throw rrdException; - } - addArchive(new ArcDef(consolFun, xff, steps, rows)); - } - - void validate() throws RrdException { - if (dsDefs.size() == 0) { - throw new RrdException("No RRD datasource specified. At least one is needed."); - } - if (arcDefs.size() == 0) { - throw new RrdException("No RRD archive specified. At least one is needed."); - } - } - - /** - * Returns all data source definition objects specified so far. - * - * @return Array of data source definition objects - */ - public DsDef[] getDsDefs() { - return dsDefs.toArray(new DsDef[0]); - } - - /** - * Returns all archive definition objects specified so far. - * - * @return Array of archive definition objects. - */ - public ArcDef[] getArcDefs() { - return arcDefs.toArray(new ArcDef[0]); - } - - /** - * Returns number of defined datasources. - * - * @return Number of defined datasources. - */ - public int getDsCount() { - return dsDefs.size(); - } - - /** - * Returns number of defined archives. - * - * @return Number of defined archives. - */ - public int getArcCount() { - return arcDefs.size(); - } - - /** - * Returns string that represents all specified RRD creation parameters. Returned string - * has the syntax of RRDTool's <code>create</code> command. - * - * @return Dumped content of <code>RrdDb</code> object. - */ - public String dump() { - final StringBuffer buffer = new StringBuffer("create \""); - buffer.append(path).append("\""); - buffer.append(" --start ").append(getStartTime()); - buffer.append(" --step ").append(getStep()).append(" "); - for (final DsDef dsDef : dsDefs) { - buffer.append(dsDef.dump()).append(" "); - } - for (final ArcDef arcDef : arcDefs) { - buffer.append(arcDef.dump()).append(" "); - } - return buffer.toString().trim(); - } - - String getRrdToolCommand() { - return dump(); - } - - void removeDatasource(final String dsName) throws RrdException { - for (int i = 0; i < dsDefs.size(); i++) { - final DsDef dsDef = dsDefs.get(i); - if (dsDef.getDsName().equals(dsName)) { - dsDefs.remove(i); - return; - } - } - throw new RrdException("Could not find datasource named '" + dsName + "'"); - } - - void saveSingleDatasource(final String dsName) { - final Iterator<DsDef> it = dsDefs.iterator(); - while (it.hasNext()) { - final DsDef dsDef = it.next(); - if (!dsDef.getDsName().equals(dsName)) { - it.remove(); - } - } - } - - void removeArchive(final String consolFun, final int steps) throws RrdException { - final ArcDef arcDef = findArchive(consolFun, steps); - if (!arcDefs.remove(arcDef)) { - throw new RrdException("Could not remove archive " + consolFun + "/" + steps); - } - } - - ArcDef findArchive(final String consolFun, final int steps) throws RrdException { - for (final ArcDef arcDef : arcDefs) { - if (arcDef.getConsolFun().equals(consolFun) && arcDef.getSteps() == steps) { - return arcDef; - } - } - throw new RrdException("Could not find archive " + consolFun + "/" + steps); - } - - /** - * Exports RrdDef object to output stream in XML format. Generated XML code can be parsed - * with {@link RrdDefTemplate} class. - * - * @param out Output stream - */ - public void exportXmlTemplate(final OutputStream out) { - final XmlWriter xml = new XmlWriter(out); - xml.startTag("rrd_def"); - xml.writeTag("path", getPath()); - xml.writeTag("step", getStep()); - xml.writeTag("start", getStartTime()); - for (final DsDef dsDef : getDsDefs()) { - xml.startTag("datasource"); - xml.writeTag("name", dsDef.getDsName()); - xml.writeTag("type", dsDef.getDsType()); - xml.writeTag("heartbeat", dsDef.getHeartbeat()); - xml.writeTag("min", dsDef.getMinValue(), "U"); - xml.writeTag("max", dsDef.getMaxValue(), "U"); - xml.closeTag(); // datasource - } - for (ArcDef arcDef : getArcDefs()) { - xml.startTag("archive"); - xml.writeTag("cf", arcDef.getConsolFun()); - xml.writeTag("xff", arcDef.getXff()); - xml.writeTag("steps", arcDef.getSteps()); - xml.writeTag("rows", arcDef.getRows()); - xml.closeTag(); // archive - } - xml.closeTag(); // rrd_def - xml.flush(); - } - - /** - * Exports RrdDef object to string in XML format. Generated XML string can be parsed - * with {@link RrdDefTemplate} class. - * - * @return XML formatted string representing this RrdDef object - */ - public String exportXmlTemplate() { - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - exportXmlTemplate(out); - return out.toString(); - } - - /** - * Exports RrdDef object to a file in XML format. Generated XML code can be parsed - * with {@link RrdDefTemplate} class. - * - * @param filePath path to the file - * @throws IOException if an I/O error occurs. - */ - public void exportXmlTemplate(final String filePath) throws IOException { - final FileOutputStream out = new FileOutputStream(filePath, false); - exportXmlTemplate(out); - out.close(); - } - - /** - * Returns the number of storage bytes required to create RRD from this - * RrdDef object. - * - * @return Estimated byte count of the underlying RRD storage. - */ - public long getEstimatedSize() { - final int dsCount = dsDefs.size(); - final int arcCount = arcDefs.size(); - int rowsCount = 0; - for (final ArcDef arcDef : arcDefs) { - rowsCount += arcDef.getRows(); - } - return calculateSize(dsCount, arcCount, rowsCount); - } - - static long calculateSize(final int dsCount, final int arcCount, final int rowsCount) { - return (24L + 48L * dsCount + 16L * arcCount + - 20L * dsCount * arcCount + 8L * dsCount * rowsCount) + - (1L + 2L * dsCount + arcCount) * 2L * RrdPrimitive.STRING_LENGTH; - } - - /** - * Compares the current RrdDef with another. RrdDefs are considered equal if:<p> - * <ul> - * <li>RRD steps match - * <li>all datasources have exactly the same definition in both RrdDef objects (datasource names, - * types, heartbeat, min and max values must match) - * <li>all archives have exactly the same definition in both RrdDef objects (archive consolidation - * functions, X-file factors, step and row counts must match) - * </ul> - * - * @param obj The second RrdDef object - * @return true if RrdDefs match exactly, false otherwise - */ - public boolean equals(final Object obj) { - if (obj == null || !(obj instanceof RrdDef)) { - return false; - } - final RrdDef rrdDef2 = (RrdDef) obj; - // check primary RRD step - if (step != rrdDef2.step) { - return false; - } - // check datasources - final DsDef[] dsDefs = getDsDefs(); - final DsDef[] dsDefs2 = rrdDef2.getDsDefs(); - if (dsDefs.length != dsDefs2.length) { - return false; - } - for (final DsDef dsDef : dsDefs) { - boolean matched = false; - for (final DsDef dsDef2 : dsDefs2) { - if (dsDef.exactlyEqual(dsDef2)) { - matched = true; - break; - } - } - // this datasource could not be matched - if (!matched) { - return false; - } - } - // check archives - final ArcDef[] arcDefs = getArcDefs(); - final ArcDef[] arcDefs2 = rrdDef2.getArcDefs(); - if (arcDefs.length != arcDefs2.length) { - return false; - } - for (final ArcDef arcDef : arcDefs) { - boolean matched = false; - for (final ArcDef arcDef2 : arcDefs2) { - if (arcDef.exactlyEqual(arcDef2)) { - matched = true; - break; - } - } - // this archive could not be matched - if (!matched) { - return false; - } - } - // everything matches - return true; - } - - public int hashCode() { - int hashCode = (int)step; - for (final DsDef dsDef : dsDefs) { - hashCode *= dsDef.hashCode(); - } - for (final ArcDef arcDef : arcDefs) { - hashCode *= arcDef.hashCode(); - } - return hashCode; - } - - /** - * Removes all datasource definitions. - */ - public void removeDatasources() { - dsDefs.clear(); - } - - /** - * Removes all RRA archive definitions. - */ - public void removeArchives() { - arcDefs.clear(); - } - - public String toString() { - return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + "[arcDefs=[" + join(getArcDefs()) + "],dsDefs=[" + join(getDsDefs()) + "]]"; - } - - private String join(final Object[] objs) { - final StringBuffer sb = new StringBuffer(); - for (int i = 0; i < objs.length; i++) { - sb.append(objs[i]); - if (i != (objs.length - 1)) { - sb.append(","); - } - } - return sb.toString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdDefTemplate.java b/apps/jrobin/java/src/org/jrobin/core/RrdDefTemplate.java deleted file mode 100644 index 7e667a80723982da144d79c8d0d86f0d9ce2a759..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdDefTemplate.java +++ /dev/null @@ -1,229 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core; - -import org.w3c.dom.Node; -import org.xml.sax.InputSource; - -import java.io.File; -import java.io.IOException; -import java.util.Calendar; - -/** - * Class used to create an arbitrary number of {@link RrdDef} (RRD definition) objects - * from a single XML template. XML template can be supplied as an XML InputSource, - * XML file or XML formatted string. - * <p> - * Here is an example of a properly formatted XML template with all available - * options in it (unwanted options can be removed): - * <pre> - * <rrd_def> - * <path>test.rrd</path> - * <!-- not mandatory --> - * <start>1000123456</start> - * <!-- not mandatory --> - * <step>300</step> - * <!-- at least one datasource must be supplied --> - * <datasource> - * <name>input</name> - * <type>COUNTER</type> - * <heartbeat>300</heartbeat> - * <min>0</min> - * <max>U</max> - * </datasource> - * <datasource> - * <name>temperature</name> - * <type>GAUGE</type> - * <heartbeat>400</heartbeat> - * <min>U</min> - * <max>1000</max> - * </datasource> - * <!-- at least one archive must be supplied --> - * <archive> - * <cf>AVERAGE</cf> - * <xff>0.5</xff> - * <steps>1</steps> - * <rows>600</rows> - * </archive> - * <archive> - * <cf>MAX</cf> - * <xff>0.6</xff> - * <steps>6</steps> - * <rows>7000</rows> - * </archive> - * </rrd_def> - * </pre> - * Notes on the template syntax:<p> - * <ul> - * <li>There is a strong relation between the XML template syntax and the syntax of - * {@link RrdDef} class methods. If you are not sure what some XML tag means, check javadoc - * for the corresponding class. - * <li>starting timestamp can be supplied either as a long integer - * (like: 1000243567) or as an ISO formatted string (like: 2004-02-21 12:25:45) - * <li>whitespaces are not harmful - * <li>floating point values: anything that cannot be parsed will be treated as Double.NaN - * (like: U, unknown, 12r.23) - * <li>comments are allowed. - * </ul> - * Any template value (text between <code><some_tag></code> and - * <code></some_tag></code>) can be replaced with - * a variable of the following form: <code>${variable_name}</code>. Use - * {@link XmlTemplate#setVariable(String, String) setVariable()} - * methods from the base class to replace template variables with real values - * at runtime. - * <p> - * Typical usage scenario:<p> - * <ul> - * <li>Create your XML template and save it to a file (template.xml, for example) - * <li>Replace hardcoded template values with variables if you want to change them during runtime. - * For example, RRD path should not be hardcoded in the template - you probably want to create - * many different RRD files from the same XML template. For example, your XML - * template could start with: - * <pre> - * <rrd_def> - * <path>${path}</path> - * <step>300</step> - * ... - * </pre> - * <li>In your Java code, create RrdDefTemplate object using your XML template file: - * <pre> - * RrdDefTemplate t = new RrdDefTemplate(new File(template.xml)); - * </pre> - * <li>Then, specify real values for template variables: - * <pre> - * t.setVariable("path", "demo/test.rrd"); - * </pre> - * <li>Once all template variables are set, just use the template object to create RrdDef - * object. This object is actually used to create JRobin RRD files: - * <pre> - * RrdDef def = t.getRrdDef(); - * RrdDb rrd = new RrdDb(def); - * rrd.close(); - * </pre> - * </ul> - * You should create new RrdDefTemplate object only once for each XML template. Single template - * object can be reused to create as many RrdDef objects as needed, with different values - * specified for template variables. XML synatax check is performed only once - the first - * definition object gets created relatively slowly, but it will be created much faster next time. - */ -public class RrdDefTemplate extends XmlTemplate { - /** - * Creates RrdDefTemplate object from any parsable XML input source. Read general information - * for this class to find an example of a properly formatted RrdDef XML source. - * - * @param xmlInputSource Xml input source - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of XML related error (parsing error, for example) - */ - public RrdDefTemplate(InputSource xmlInputSource) throws IOException, RrdException { - super(xmlInputSource); - } - - /** - * Creates RrdDefTemplate object from the string containing XML template. - * Read general information for this class to see an example of a properly formatted XML source. - * - * @param xmlString String containing XML template - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of XML related error (parsing error, for example) - */ - public RrdDefTemplate(String xmlString) throws IOException, RrdException { - super(xmlString); - } - - /** - * Creates RrdDefTemplate object from the file containing XML template. - * Read general information for this class to see an example of a properly formatted XML source. - * - * @param xmlFile File object representing file with XML template - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of XML related error (parsing error, for example) - */ - public RrdDefTemplate(File xmlFile) throws IOException, RrdException { - super(xmlFile); - } - - /** - * Returns RrdDef object constructed from the underlying XML template. Before this method - * is called, values for all non-optional placeholders must be supplied. To specify - * placeholder values at runtime, use some of the overloaded - * {@link XmlTemplate#setVariable(String, String) setVariable()} methods. Once this method - * returns, all placeholder values are preserved. To remove them all, call inhereted - * {@link XmlTemplate#clearValues() clearValues()} method explicitly.<p> - * - * @return RrdDef object constructed from the underlying XML template, - * with all placeholders replaced with real values. This object can be passed to the constructor - * of the new RrdDb object. - * @throws RrdException Thrown (in most cases) if the value for some placeholder - * was not supplied through {@link XmlTemplate#setVariable(String, String) setVariable()} - * method call - */ - public RrdDef getRrdDef() throws RrdException { - if (!root.getTagName().equals("rrd_def")) { - throw new RrdException("XML definition must start with <rrd_def>"); - } - validateTagsOnlyOnce(root, new String[] { - "path", "start", "step", "datasource*", "archive*" - }); - // PATH must be supplied or exception is thrown - String path = getChildValue(root, "path"); - RrdDef rrdDef = new RrdDef(path); - try { - String startStr = getChildValue(root, "start"); - Calendar startGc = Util.getCalendar(startStr); - rrdDef.setStartTime(startGc); - } - catch (RrdException e) { - // START is not mandatory - } - try { - long step = getChildValueAsLong(root, "step"); - rrdDef.setStep(step); - } - catch (RrdException e) { - // STEP is not mandatory - } - // datsources - Node[] dsNodes = getChildNodes(root, "datasource"); - for (Node dsNode : dsNodes) { - validateTagsOnlyOnce(dsNode, new String[] { - "name", "type", "heartbeat", "min", "max" - }); - String name = getChildValue(dsNode, "name"); - String type = getChildValue(dsNode, "type"); - long heartbeat = getChildValueAsLong(dsNode, "heartbeat"); - double min = getChildValueAsDouble(dsNode, "min"); - double max = getChildValueAsDouble(dsNode, "max"); - rrdDef.addDatasource(name, type, heartbeat, min, max); - } - // archives - Node[] arcNodes = getChildNodes(root, "archive"); - for (Node arcNode : arcNodes) { - validateTagsOnlyOnce(arcNode, new String[] { - "cf", "xff", "steps", "rows" - }); - String consolFun = getChildValue(arcNode, "cf"); - double xff = getChildValueAsDouble(arcNode, "xff"); - int steps = getChildValueAsInt(arcNode, "steps"); - int rows = getChildValueAsInt(arcNode, "rows"); - rrdDef.addArchive(consolFun, xff, steps, rows); - } - return rrdDef; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdDouble.java b/apps/jrobin/java/src/org/jrobin/core/RrdDouble.java deleted file mode 100644 index 06b27d76b20f50ba344aeac03be803ad77419607..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdDouble.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -class RrdDouble extends RrdPrimitive { - private double cache; - private boolean cached = false; - - RrdDouble(final RrdUpdater updater, final boolean isConstant) throws IOException { - super(updater, RrdDouble.RRD_DOUBLE, isConstant); - } - - RrdDouble(final RrdUpdater updater) throws IOException { - super(updater, RrdDouble.RRD_DOUBLE, false); - } - - void set(final double value) throws IOException { - if (!isCachingAllowed()) { - writeDouble(value); - } - // caching allowed - else if (!cached || !Util.equal(cache, value)) { - // update cache - writeDouble(cache = value); - cached = true; - } - } - - double get() throws IOException { - return cached ? cache : readDouble(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdDoubleArray.java b/apps/jrobin/java/src/org/jrobin/core/RrdDoubleArray.java deleted file mode 100644 index 03f71dc8d1e984f154ffa3403be258227c0e495e..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdDoubleArray.java +++ /dev/null @@ -1,52 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -class RrdDoubleArray extends RrdPrimitive { - private int length; - - RrdDoubleArray(final RrdUpdater updater, final int length) throws IOException { - super(updater, RrdPrimitive.RRD_DOUBLE, length, false); - this.length = length; - } - - void set(final int index, final double value) throws IOException { - set(index, value, 1); - } - - void set(final int index, final double value, final int count) throws IOException { - // rollovers not allowed! - assert index + count <= length: "Invalid robin index supplied: index=" + index +", count=" + count + ", length=" + length; - writeDouble(index, value, count); - } - - double get(final int index) throws IOException { - assert index < length: "Invalid index supplied: " + index + ", length=" + length; - return readDouble(index); - } - - double[] get(final int index, final int count) throws IOException { - assert index + count <= length: "Invalid index/count supplied: " + index + "/" + count + " (length=" + length + ")"; - return readDouble(index, count); - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdException.java b/apps/jrobin/java/src/org/jrobin/core/RrdException.java deleted file mode 100644 index 3ba6ae4d62e419fc39d4855a61399c94b3989127..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdException.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -/** - * Class to represent various JRobin checked exceptions. - * JRobin code can throw only <code>RrdException</code> - * (for various JRobin related errors) or <code>IOException</code> - * (for various I/O errors). - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ -public class RrdException extends Exception { - private static final long serialVersionUID = 6999702149227009855L; - - public RrdException() { - super(); - } - - public RrdException(final String message) { - super(message); - } - - public RrdException(final Throwable cause) { - super(cause); - } - - public RrdException(final String message, final Throwable cause) { - super(message, cause); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdFileBackend.java b/apps/jrobin/java/src/org/jrobin/core/RrdFileBackend.java deleted file mode 100644 index ee213f6a118a710a37d0c1c0825d048c531c11d7..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdFileBackend.java +++ /dev/null @@ -1,125 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; -import java.io.RandomAccessFile; - -/** - * JRobin backend which is used to store RRD data to ordinary files on the disk. This was the - * default factory before 1.4.0 version. - * <p> - * This backend is based on the RandomAccessFile class (java.io.* package). - */ -public class RrdFileBackend extends RrdBackend { - /** - * radnom access file handle - */ - protected RandomAccessFile file; - - /** - * Creates RrdFileBackend object for the given file path, backed by RandomAccessFile object. - * - * @param path Path to a file - * @param readOnly True, if file should be open in a read-only mode. False otherwise - * @throws IOException Thrown in case of I/O error - */ - protected RrdFileBackend(final String path, final boolean readOnly) throws IOException { - super(path, readOnly); - this.file = new RandomAccessFile(path, readOnly ? "r" : "rw"); - } - - /** - * Closes the underlying RRD file. - * - * @throws IOException Thrown in case of I/O error - */ - public void close() throws IOException { - file.close(); - } - - /** - * Returns canonical path to the file on the disk. - * - * @param path File path - * @return Canonical file path - * @throws IOException Thrown in case of I/O error - */ - public static String getCanonicalPath(String path) throws IOException { - return Util.getCanonicalPath(path); - } - - /** - * Returns canonical path to the file on the disk. - * - * @return Canonical file path - * @throws IOException Thrown in case of I/O error - */ - public String getCanonicalPath() throws IOException { - return RrdFileBackend.getCanonicalPath(getPath()); - } - - /** - * Writes bytes to the underlying RRD file on the disk - * - * @param offset Starting file offset - * @param b Bytes to be written. - * @throws IOException Thrown in case of I/O error - */ - protected void write(long offset, byte[] b) throws IOException { - file.seek(offset); - file.write(b); - } - - /** - * Reads a number of bytes from the RRD file on the disk - * - * @param offset Starting file offset - * @param b Buffer which receives bytes read from the file. - * @throws IOException Thrown in case of I/O error. - */ - protected void read(long offset, byte[] b) throws IOException { - file.seek(offset); - if (file.read(b) != b.length) { - throw new IOException("Not enough bytes available in file " + getPath()); - } - } - - /** - * Returns RRD file length. - * - * @return File length. - * @throws IOException Thrown in case of I/O error. - */ - public long getLength() throws IOException { - return file.length(); - } - - /** - * Sets length of the underlying RRD file. This method is called only once, immediately - * after a new RRD file gets created. - * - * @param length Length of the RRD file - * @throws IOException Thrown in case of I/O error. - */ - protected void setLength(long length) throws IOException { - file.setLength(length); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdFileBackendFactory.java b/apps/jrobin/java/src/org/jrobin/core/RrdFileBackendFactory.java deleted file mode 100644 index e89959616f7237ad4532bf4c2d38cdc2896f94d9..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdFileBackendFactory.java +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -/** - * Factory class which creates actual {@link RrdFileBackend} objects. This was the default - * backend factory in JRobin before 1.4.0 release. - */ -public class RrdFileBackendFactory extends RrdBackendFactory { - /** - * factory name, "FILE" - */ - public static final String NAME = "FILE"; - - /** - * Creates RrdFileBackend object for the given file path. - * - * @param path File path - * @param readOnly True, if the file should be accessed in read/only mode. - * False otherwise. - * @return RrdFileBackend object which handles all I/O operations for the given file path - * @throws IOException Thrown in case of I/O error. - */ - protected RrdBackend open(String path, boolean readOnly) throws IOException { - return new RrdFileBackend(path, readOnly); - } - - /** - * Method to determine if a file with the given path already exists. - * - * @param path File path - * @return True, if such file exists, false otherwise. - */ - protected boolean exists(String path) { - return Util.fileExists(path); - } - - /** - * Returns the name of this factory. - * - * @return Factory name (equals to string "FILE") - */ - public String getFactoryName() { - return NAME; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdInt.java b/apps/jrobin/java/src/org/jrobin/core/RrdInt.java deleted file mode 100644 index 3213d541c9391f4b1e97f32c007e3ead5a7545f2..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdInt.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -class RrdInt extends RrdPrimitive { - private int cache; - private boolean cached = false; - - RrdInt(final RrdUpdater updater, final boolean isConstant) throws IOException { - super(updater, RrdPrimitive.RRD_INT, isConstant); - } - - RrdInt(final RrdUpdater updater) throws IOException { - this(updater, false); - } - - void set(final int value) throws IOException { - if (!isCachingAllowed()) { - writeInt(value); - } - // caching allowed - else if (!cached || cache != value) { - // update cache - writeInt(cache = value); - cached = true; - } - } - - int get() throws IOException { - return cached ? cache : readInt(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdJRobin14FileBackend.java b/apps/jrobin/java/src/org/jrobin/core/RrdJRobin14FileBackend.java deleted file mode 100644 index 7e8ba8b09eefe3a0f3a4f284f907c92a1ad7f4fa..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdJRobin14FileBackend.java +++ /dev/null @@ -1,207 +0,0 @@ -/* ============================================================ - * JRobin : Pure java implementation of RRDTool's functionality - * ============================================================ - * - * Project Info: http://www.jrobin.org - * Project Lead: Sasa Markovic (saxon@jrobin.org); - * - * (C) Copyright 2003, by Sasa Markovic. - * - * Developers: Sasa Markovic (saxon@jrobin.org) - * Arne Vandamme (cobralord@jrobin.org) - * - * This library is free software; you can redistribute it and/or modify it under the terms - * of the GNU Lesser General Public License as published by the Free Software Foundation; - * either version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with this - * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. - */ - -package org.jrobin.core; - -import java.io.IOException; -import java.io.RandomAccessFile; -import java.nio.channels.FileLock; -import java.util.HashSet; -import java.util.Set; - -/** - * JRobin backend which is used to store RRD data to ordinary files on the disk. This was the - * default factory before 1.4.0 version. - * <p> - * This backend is based on the RandomAccessFile class (java.io.* package). - */ -public class RrdJRobin14FileBackend extends RrdBackend { - private static final long LOCK_DELAY = 100; // 0.1sec - - private static Set<String> m_openFiles = new HashSet<String>(); - - public static enum LockMode { - EXCEPTION_IF_LOCKED, - WAIT_IF_LOCKED, - NO_LOCKS - }; - - /** locking mode */ - protected LockMode m_lockMode; - - /** random access file handle */ - protected RandomAccessFile m_file; - /** file lock */ - protected FileLock m_fileLock; - - /** - * Creates RrdFileBackend object for the given file path, backed by RandomAccessFile object. - * @param path Path to a file - * @param readOnly True, if file should be open in a read-only mode. False otherwise - * @param lockMode Locking mode: Exception if locked, Wait if locked, or no locks. - * @throws IOException Thrown in case of I/O error - */ - protected RrdJRobin14FileBackend(String path, boolean readOnly, LockMode lockMode) throws IOException { - super(path, readOnly); - m_lockMode = lockMode; - m_file = new RandomAccessFile(path, readOnly ? "r" : "rw"); - try { - lockFile(); - registerWriter(); - } catch(final IOException ioe) { - close(); - throw ioe; - } - System.err.println(String.format("backend initialized with path=%s, readOnly=%s, lockMode=%s", path, Boolean.valueOf(readOnly), lockMode)); - } - - private void lockFile() throws IOException { - switch (m_lockMode) { - case EXCEPTION_IF_LOCKED: - m_fileLock = m_file.getChannel().tryLock(); - if (m_fileLock == null) { - // could not obtain lock - throw new IOException("Access denied. " + "File [" + getPath() + "] already locked"); - } - break; - case WAIT_IF_LOCKED: - while (m_fileLock == null) { - m_fileLock = m_file.getChannel().tryLock(); - if (m_fileLock == null) { - // could not obtain lock, wait a little, than try again - try { - Thread.sleep(LOCK_DELAY); - } - catch (final InterruptedException e) { - Thread.currentThread().interrupt(); - } - } - } - break; - case NO_LOCKS: - break; - } - } - - private void registerWriter() throws IOException { - if (!isReadOnly()) { - final String canonicalPath = Util.getCanonicalPath(getPath()); - synchronized (m_openFiles) { - if (m_openFiles.contains(canonicalPath)) { - throw new IOException("File \"" + getPath() + "\" already open for R/W access. " + - "You cannot open the same file for R/W access twice"); - } - else { - m_openFiles.add(canonicalPath); - } - } - } - } - - /** - * Closes the underlying RRD file. - * - * @throws IOException Thrown in case of I/O error - */ - public void close() throws IOException { - unregisterWriter(); - try { - unlockFile(); - } finally { - m_file.close(); - } - } - - private void unlockFile() throws IOException { - if (m_fileLock != null) { - m_fileLock.release(); - } - } - - private void unregisterWriter() throws IOException { - if (!isReadOnly()) { - synchronized (m_openFiles) { - m_openFiles.remove(Util.getCanonicalPath(getPath())); - } - } - } - - /** - * Returns canonical path to the file on the disk. - * - * @return Canonical file path - * @throws IOException Thrown in case of I/O error - */ - public String getCanonicalPath() throws IOException { - return Util.getCanonicalPath(getPath()); - } - - /** - * Writes bytes to the underlying RRD file on the disk - * - * @param offset Starting file offset - * @param b Bytes to be written. - * @throws IOException Thrown in case of I/O error - */ - protected void write(final long offset, final byte[] b) throws IOException { - m_file.seek(offset); - m_file.write(b); - } - - /** - * Reads a number of bytes from the RRD file on the disk - * - * @param offset Starting file offset - * @param b Buffer which receives bytes read from the file. - * @throws IOException Thrown in case of I/O error. - */ - protected void read(final long offset, final byte[] b) throws IOException { - m_file.seek(offset); - if (m_file.read(b) != b.length) { - throw new IOException("Not enough bytes available in file " + getPath()); - } - } - - /** - * Returns RRD file length. - * - * @return File length. - * @throws IOException Thrown in case of I/O error. - */ - public long getLength() throws IOException { - return m_file.length(); - } - - /** - * Sets length of the underlying RRD file. This method is called only once, immediately - * after a new RRD file gets created. - * - * @param length Length of the RRD file - * @throws IOException Thrown in case of I/O error. - */ - protected void setLength(final long length) throws IOException { - m_file.setLength(length); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdJRobin14FileBackendFactory.java b/apps/jrobin/java/src/org/jrobin/core/RrdJRobin14FileBackendFactory.java deleted file mode 100644 index 910394e71fc4c4f5dbc2ae0d1d03e66d8455c6ea..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdJRobin14FileBackendFactory.java +++ /dev/null @@ -1,81 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -import org.jrobin.core.RrdJRobin14FileBackend.LockMode; - -/** - * Factory class which creates actual {@link RrdFileBackend} objects. This was the default - * backend factory in JRobin before 1.4.0 release. - */ -public class RrdJRobin14FileBackendFactory extends RrdBackendFactory { - /** - * factory name, "FILE" - */ - public static final String NAME = "14FILE"; - private LockMode m_lockMode = LockMode.NO_LOCKS; - - public RrdJRobin14FileBackendFactory() { - super(); - } - - public RrdJRobin14FileBackendFactory(final LockMode lockMode) { - super(); - m_lockMode = lockMode; - } - - /** - * Creates RrdFileBackend object for the given file path. - * - * @param path File path - * @param readOnly True, if the file should be accessed in read/only mode. - * False otherwise. - * @return RrdFileBackend object which handles all I/O operations for the given file path - * @throws IOException Thrown in case of I/O error. - */ - protected RrdBackend open(final String path, final boolean readOnly) throws IOException { - return new RrdJRobin14FileBackend(path, readOnly, m_lockMode); - } - - /** - * Method to determine if a file with the given path already exists. - * - * @param path File path - * @return True, if such file exists, false otherwise. - */ - protected boolean exists(final String path) { - return Util.fileExists(path); - } - - /** - * Returns the name of this factory. - * - * @return Factory name (equals to string "FILE") - */ - public String getFactoryName() { - return NAME; - } - - public String toString() { - return getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()) + "[name=" + getFactoryName() + ",lockMode=" + m_lockMode + "]"; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdLong.java b/apps/jrobin/java/src/org/jrobin/core/RrdLong.java deleted file mode 100644 index 7b07b17303aa40e52b08354c60a7c3b3409d8351..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdLong.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -class RrdLong extends RrdPrimitive { - private long cache; - private boolean cached = false; - - RrdLong(final RrdUpdater updater, final boolean isConstant) throws IOException { - super(updater, RrdPrimitive.RRD_LONG, isConstant); - } - - RrdLong(final RrdUpdater updater) throws IOException { - this(updater, false); - } - - void set(final long value) throws IOException { - if (!isCachingAllowed()) { - writeLong(value); - } - // caching allowed - else if (!cached || cache != value) { - // update cache - writeLong(cache = value); - cached = true; - } - } - - long get() throws IOException { - return cached ? cache : readLong(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdMemoryBackend.java b/apps/jrobin/java/src/org/jrobin/core/RrdMemoryBackend.java deleted file mode 100644 index 9387c00cded75de5cdb4f36b67d52fb8e48f61e1..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdMemoryBackend.java +++ /dev/null @@ -1,119 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -/** - * Backend to be used to store all RRD bytes in memory.<p> - */ -public class RrdMemoryBackend extends RrdBackend { - private static final ReadWriteLock m_readWritelock = new ReentrantReadWriteLock(); - private static final Lock m_readLock = m_readWritelock.readLock(); - private static final Lock m_writeLock = m_readWritelock.writeLock(); - - private byte[] buffer = new byte[0]; - - protected RrdMemoryBackend(String path) { - super(path); - } - - protected void write(final long offset, final byte[] b) { - m_writeLock.lock(); - try { - int pos = (int) offset; - for (final byte singleByte : b) { - buffer[pos++] = singleByte; - } - } finally { - m_writeLock.unlock(); - } - } - - protected void read(final long offset, final byte[] b) throws IOException { - m_readLock.lock(); - try { - int pos = (int) offset; - if (pos + b.length <= buffer.length) { - for (int i = 0; i < b.length; i++) { - b[i] = buffer[pos++]; - } - } - else { - throw new IOException("Not enough bytes available in memory " + getPath()); - } - } finally { - m_readLock.unlock(); - } - } - - /** - * Returns the number of RRD bytes held in memory. - * - * @return Number of all RRD bytes. - */ - public long getLength() { - m_readLock.lock(); - try { - return buffer.length; - } finally { - m_readLock.unlock(); - } - } - - /** - * Reserves a memory section as a RRD storage. - * - * @param newLength Number of bytes held in memory. - * @throws IOException Thrown in case of I/O error. - */ - protected void setLength(final long newLength) throws IOException { - m_writeLock.lock(); - try { - if (newLength > Integer.MAX_VALUE) { - throw new IOException("Cannot create this big memory backed RRD"); - } - buffer = new byte[(int) newLength]; - } finally { - m_writeLock.unlock(); - } - } - - /** - * This method is required by the base class definition, but it does not - * releases any memory resources at all. - */ - public void close() { - // NOP - } - - /** - * This method is overridden to disable high-level caching in frontend JRobin classes. - * - * @return Always returns <code>false</code>. There is no need to cache anything in high-level classes - * since all RRD bytes are already in memory. - */ - protected boolean isCachingAllowed() { - return false; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdMemoryBackendFactory.java b/apps/jrobin/java/src/org/jrobin/core/RrdMemoryBackendFactory.java deleted file mode 100644 index e326deecd51df8245c55f2384809ea25dfc142b7..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdMemoryBackendFactory.java +++ /dev/null @@ -1,93 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.util.HashMap; - -/** - * Factory class which creates actual {@link RrdMemoryBackend} objects. JRobin's support - * for in-memory RRDs is still experimental. You should know that all active RrdMemoryBackend - * objects are held in memory, each backend object stores RRD data in one big byte array. This - * implementation is therefore quite basic and memory hungry but runs very fast. - * <p> - * Calling {@link RrdDb#close() close()} on RrdDb objects does not release any memory at all - * (RRD data must be available for the next <code>new RrdDb(path)</code> call. To release allocated - * memory, you'll have to call {@link #delete(String) delete(path)} method of this class. - */ -public class RrdMemoryBackendFactory extends RrdBackendFactory { - /** - * factory name, "MEMORY" - */ - public static final String NAME = "MEMORY"; - private HashMap<String, RrdMemoryBackend> backends = new HashMap<String, RrdMemoryBackend>(); - - /** - * Creates RrdMemoryBackend object. - * - * @param id Since this backend holds all data in memory, this argument is interpreted - * as an ID for this memory-based storage. - * @param readOnly This parameter is ignored - * @return RrdMemoryBackend object which handles all I/O operations - */ - protected synchronized RrdBackend open(String id, boolean readOnly) { - RrdMemoryBackend backend; - if (backends.containsKey(id)) { - backend = backends.get(id); - } - else { - backend = new RrdMemoryBackend(id); - backends.put(id, backend); - } - return backend; - } - - /** - * Method to determine if a memory storage with the given ID already exists. - * - * @param id Memory storage ID. - * @return True, if such storage exists, false otherwise. - */ - protected synchronized boolean exists(String id) { - return backends.containsKey(id); - } - - /** - * Removes the storage with the given ID from the memory. - * - * @param id Storage ID - * @return True, if the storage with the given ID is deleted, false otherwise. - */ - public boolean delete(String id) { - if (backends.containsKey(id)) { - backends.remove(id); - return true; - } - return false; - } - - /** - * Returns the name of this factory. - * - * @return Factory name (equals to "MEMORY"). - */ - public String getFactoryName() { - return NAME; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdNioBackend.java b/apps/jrobin/java/src/org/jrobin/core/RrdNioBackend.java deleted file mode 100644 index 73213b36e7bc51afe38ead0ba3edafe61d18683f..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdNioBackend.java +++ /dev/null @@ -1,208 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; -import java.nio.MappedByteBuffer; -import java.nio.channels.FileChannel; - -import net.i2p.util.SystemVersion; - -import engine.misc.DeallocationHelper; - -/** - * JRobin backend which is used to store RRD data to ordinary disk files by - * using fast java.nio.* package. This is the default backend engine since - * JRobin 1.4.0. - */ -@SuppressWarnings("restriction") -public class RrdNioBackend extends RrdFileBackend { - private final SyncManager m_syncManager; - private MappedByteBuffer m_byteBuffer = null; - // Too many ominous warnings from Java 9 - private static final DeallocationHelper _dHelper = SystemVersion.isJava9() ? null : new DeallocationHelper(); - - /** - * Creates RrdFileBackend object for the given file path, backed by - * java.nio.* classes. This constructor will create a - * {@link SyncManager} for each instance, which is very inefficient. - * It is recommended that you instead use the - * {@link #RrdNioBackend(String, boolean, SyncManager)} - * constructor instead. - * - * @param path - * Path to a JRB file. - * @param readOnly - * True, if file should be open in a read-only mode. False - * otherwise - * @param syncPeriod - * How often (in seconds) to sync MMAP'd RRD data to disk - * @throws IOException - * Thrown in case of I/O error - */ - protected RrdNioBackend(final String path, final boolean readOnly, final int syncPeriod) throws IOException { - this(path, readOnly, new SyncManager(syncPeriod)); - } - - /** - * Creates RrdFileBackend object for the given file path, backed by - * java.nio.* classes. - * - * @param path - * Path to a file - * @param readOnly - * True, if file should be open in a read-only mode. False - * otherwise. - * @param syncManager - * An object for managing synchronization of NIO-backed RRDs, - * generally owned by the backend factory. If null, MMAP'd - * data will only be synchronized to disk upon unmap. Note - * that if the file is opened read-only, the SyncManager is - * ignored. {@link RrdNioBackend#unmapFile() unmapFile()} - * @throws IOException - * Thrown in case of I/O error - */ - protected RrdNioBackend(final String path, final boolean readOnly, final SyncManager syncManager) throws IOException { - super(path, readOnly); - m_syncManager = syncManager; - - try { - mapFile(); - } catch (final IOException ioe) { - stopSchedule(); - super.close(); - throw ioe; - } - } - - private void mapFile() throws IOException { - if (!isReadOnly()) { - startSchedule(); - } - final long length = getLength(); - if (length > 0) { - final FileChannel.MapMode mapMode = isReadOnly() ? FileChannel.MapMode.READ_ONLY : FileChannel.MapMode.READ_WRITE; - m_byteBuffer = file.getChannel().map(mapMode, 0, length); - } - } - - private void unmapFile() { - if (!isReadOnly()) { - stopSchedule(); - } - if (_dHelper != null && m_byteBuffer != null) { - _dHelper.deallocate(m_byteBuffer); - m_byteBuffer = null; - } - } - - private void startSchedule() { - if (m_syncManager != null) { - m_syncManager.add(this); - } - } - - private synchronized void stopSchedule() { - if (m_syncManager != null) { - m_syncManager.remove(this); - } - sync(); - } - - @Override - protected void finalize() throws Throwable { - stopSchedule(); - super.finalize(); - } - - /** - * Sets length of the underlying RRD file. This method is called only - * once, immediately after a new RRD file gets created. - * - * @param newLength - * Length of the RRD file - * @throws IOException - * Thrown in case of I/O error. - */ - protected synchronized void setLength(final long newLength) throws IOException { - unmapFile(); - super.setLength(newLength); - mapFile(); - } - - /** - * Writes bytes to the underlying RRD file on the disk - * - * @param offset - * Starting file offset - * @param b - * Bytes to be written. - */ - protected synchronized void write(final long offset, final byte[] b) throws IOException { - if (m_byteBuffer != null) { - m_byteBuffer.position((int) offset); - m_byteBuffer.put(b); - } else { - throw new IOException("Write failed, file " + getPath() + " not mapped for I/O"); - } - } - - /** - * Reads a number of bytes from the RRD file on the disk - * - * @param offset - * Starting file offset - * @param b - * Buffer which receives bytes read from the file. - */ - protected synchronized void read(final long offset, final byte[] b) throws IOException { - if (m_byteBuffer != null) { - m_byteBuffer.position((int) offset); - m_byteBuffer.get(b); - } else { - throw new IOException("Read failed, file " + getPath() + " not mapped for I/O"); - } - } - - /** - * Closes the underlying RRD file. - * - * @throws IOException - * Thrown in case of I/O error - */ - public synchronized void close() throws IOException { - // cancel synchronization - try { - unmapFile(); - } finally { - super.close(); - } - } - - /** - * This method forces all data cached in memory but not yet stored in the - * file, to be stored in it. - */ - protected synchronized void sync() { - if (m_byteBuffer != null) { - m_byteBuffer.force(); - } - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdNioBackendFactory.java b/apps/jrobin/java/src/org/jrobin/core/RrdNioBackendFactory.java deleted file mode 100644 index 2855cf37463c4be518b1c8e7b97f0aa05d1c1316..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdNioBackendFactory.java +++ /dev/null @@ -1,107 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -/** - * Factory class which creates actual {@link RrdNioBackend} objects. This is - * the default factory since 1.4.0 version - */ -public class RrdNioBackendFactory extends RrdFileBackendFactory { - /** - * Period in seconds between consecutive synchronizations when sync-mode - * is set to SYNC_BACKGROUND. By default in-memory cache will be - * transferred to the disc every 300 seconds (5 minutes). Default value - * can be changed via {@link #setSyncPeriod(int)} method. - */ - public static final int DEFAULT_SYNC_PERIOD = 300; // seconds - - private static SyncManager s_syncManager = new SyncManager(DEFAULT_SYNC_PERIOD); - - /** - * factory name, "NIO" - */ - public static final String NAME = "NIO"; - - /** - * Returns time between two consecutive background synchronizations. If - * not changed via {@link #setSyncPeriod(int)} method call, defaults to - * {@link #DEFAULT_SYNC_PERIOD}. See {@link #setSyncPeriod(int)} for more - * information. - * - * @return Time in seconds between consecutive background - * synchronizations. - */ - public static int getSyncPeriod() { - return s_syncManager.getSyncPeriod(); - } - - /** - * Sets time between consecutive background synchronizations. - * - * @param syncPeriod - * Time in seconds between consecutive background - * synchronizations. - */ - public synchronized static void setSyncPeriod(final int syncPeriod) { - s_syncManager.setSyncPeriod(syncPeriod); - } - - /** - * Creates RrdNioBackend object for the given file path. - * - * @param path - * File path - * @param readOnly - * True, if the file should be accessed in read/only mode. - * False otherwise. - * @return RrdNioBackend object which handles all I/O operations for the - * given file path - * @throws IOException - * Thrown in case of I/O error. - */ - protected RrdBackend open(final String path, final boolean readOnly) throws IOException { - return new RrdNioBackend(path, readOnly, s_syncManager); - } - - public void shutdown() { - s_syncManager.shutdown(); - } - - /** - * Returns the name of this factory. - * - * @return Factory name (equals to string "NIO") - */ - public String getFactoryName() { - return NAME; - } - - @Override - protected void finalize() throws Throwable { - shutdown(); - super.finalize(); - } - - SyncManager getSyncManager() { - return s_syncManager; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdNioByteBufferBackend.java b/apps/jrobin/java/src/org/jrobin/core/RrdNioByteBufferBackend.java deleted file mode 100644 index b9dd5fca78bb757387d7bf3403415d7b27351edb..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdNioByteBufferBackend.java +++ /dev/null @@ -1,136 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReadWriteLock; -import java.util.concurrent.locks.ReentrantReadWriteLock; - -/** - * JRobin backend which is used to store RRD data to ordinary disk files - * by using fast java.nio.* package. This is the default backend engine since JRobin 1.4.0. - */ -public class RrdNioByteBufferBackend extends RrdFileBackend { - - private ByteBuffer m_byteBuffer; - - private FileChannel m_ch; - - private static final ReadWriteLock m_readWritelock = new ReentrantReadWriteLock(); - private static final Lock m_readLock = m_readWritelock.readLock(); - private static final Lock m_writeLock = m_readWritelock.writeLock(); - - /** - * Creates RrdFileBackend object for the given file path, backed by java.nio.* classes. - * - * @param path Path to a file - * @param readOnly True, if file should be open in a read-only mode. False otherwise - * @throws IOException Thrown in case of I/O error - */ - protected RrdNioByteBufferBackend(final String path, final boolean readOnly) throws IOException, IllegalStateException { - super(path, readOnly); - - if (file != null) { - m_ch = file.getChannel(); - m_byteBuffer = ByteBuffer.allocate((int) m_ch.size()); - m_ch.read(m_byteBuffer, 0); - } else { - throw new IllegalStateException("File in base class is null."); - } - } - - /** - * Sets length of the underlying RRD file. This method is called only once, immediately - * after a new RRD file gets created. - * - * @param newLength Length of the RRD file - * @throws IOException Thrown in case of I/O error. - */ - @Override - protected void setLength(final long newLength) throws IOException { - m_writeLock.lock(); - try { - super.setLength(newLength); - m_ch = file.getChannel(); - m_byteBuffer = ByteBuffer.allocate((int) newLength); - m_ch.read(m_byteBuffer, 0); - m_byteBuffer.position(0); - } finally { - m_writeLock.unlock(); - } - } - - /** - * Writes bytes to the underlying RRD file on the disk - * - * @param offset Starting file offset - * @param b Bytes to be written. - */ - @Override - protected void write(final long offset, final byte[] b) { - m_writeLock.lock(); - try { - m_byteBuffer.position((int) offset); - m_byteBuffer.put(b); - } finally { - m_writeLock.unlock(); - } - } - - /** - * Reads a number of bytes from the RRD file on the disk - * - * @param offset Starting file offset - * @param b Buffer which receives bytes read from the file. - */ - @Override - protected void read(final long offset, final byte[] b) { - m_readLock.lock(); - try { - m_byteBuffer.position((int) offset); - m_byteBuffer.get(b); - } finally { - m_readLock.unlock(); - } - } - - /** - * Closes the underlying RRD file. - * - * @throws IOException Thrown in case of I/O error - */ - public void close() throws IOException { - m_writeLock.lock(); - try { - m_byteBuffer.position(0); - - if (!isReadOnly()) m_ch.write(m_byteBuffer, 0); - //just calling close here because the super calls close - //on the File object and Java calls close on the channel - super.close(); - } finally { - m_writeLock.unlock(); - } - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdNioByteBufferBackendFactory.java b/apps/jrobin/java/src/org/jrobin/core/RrdNioByteBufferBackendFactory.java deleted file mode 100644 index 9f63fdfcaf265f7ac354cbcf77bdf35553cc2fed..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdNioByteBufferBackendFactory.java +++ /dev/null @@ -1,54 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -/** - * Factory class which creates actual {@link RrdNioBackend} objects. - */ -public class RrdNioByteBufferBackendFactory extends RrdFileBackendFactory { - - public static final String NAME = "MNIO"; - - /** - * Creates RrdNioByteBufferBackend object for the given file path. - * - * @param path File path - * @param readOnly True, if the file should be accessed in read/only mode. - * False otherwise. - * @return RrdNioBackend object which handles all I/O operations for the given file path - * @throws IOException Thrown in case of I/O error. - */ - @Override - protected RrdBackend open(String path, boolean readOnly) throws IOException { - return new RrdNioByteBufferBackend(path, readOnly); - } - - /** - * Returns the name of this factory. - * - * @return Factory name (equals to string "NIOBB") - */ - @Override - public String getFactoryName() { - return NAME; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdPrimitive.java b/apps/jrobin/java/src/org/jrobin/core/RrdPrimitive.java deleted file mode 100644 index 714804010976456d314e60ef088d9af0e9c81c38..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdPrimitive.java +++ /dev/null @@ -1,111 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -abstract class RrdPrimitive { - static final int STRING_LENGTH = 20; - static final int RRD_INT = 0, RRD_LONG = 1, RRD_DOUBLE = 2, RRD_STRING = 3; - static final int[] RRD_PRIM_SIZES = {4, 8, 8, 2 * STRING_LENGTH}; - - private RrdBackend backend; - private int byteCount; - private final long pointer; - private final boolean cachingAllowed; - - RrdPrimitive(final RrdUpdater updater, final int type, final boolean isConstant) throws IOException { - this(updater, type, 1, isConstant); - } - - RrdPrimitive(final RrdUpdater updater, final int type, final int count, final boolean isConstant) throws IOException { - this.backend = updater.getRrdBackend(); - this.byteCount = RRD_PRIM_SIZES[type] * count; - this.pointer = updater.getRrdAllocator().allocate(byteCount); - this.cachingAllowed = isConstant || backend.isCachingAllowed(); - } - - final byte[] readBytes() throws IOException { - final byte[] b = new byte[byteCount]; - backend.read(pointer, b); - return b; - } - - final void writeBytes(final byte[] b) throws IOException { - assert b.length == byteCount: "Invalid number of bytes supplied to RrdPrimitive.write method"; - backend.write(pointer, b); - } - - final int readInt() throws IOException { - return backend.readInt(pointer); - } - - final void writeInt(final int value) throws IOException { - backend.writeInt(pointer, value); - } - - final long readLong() throws IOException { - return backend.readLong(pointer); - } - - final void writeLong(final long value) throws IOException { - backend.writeLong(pointer, value); - } - - final double readDouble() throws IOException { - return backend.readDouble(pointer); - } - - final double readDouble(final int index) throws IOException { - final long offset = pointer + ((long)index * (long)RRD_PRIM_SIZES[RRD_DOUBLE]); - return backend.readDouble(offset); - } - - final double[] readDouble(final int index, final int count) throws IOException { - final long offset = pointer + ((long)index * (long)RRD_PRIM_SIZES[RRD_DOUBLE]); - return backend.readDouble(offset, count); - } - - final void writeDouble(final double value) throws IOException { - backend.writeDouble(pointer, value); - } - - final void writeDouble(final int index, final double value, final int count) throws IOException { - final long offset = pointer + ((long)index * (long)RRD_PRIM_SIZES[RRD_DOUBLE]); - backend.writeDouble(offset, value, count); - } - - final void writeDouble(final int index, final double[] values) throws IOException { - final long offset = pointer + ((long)index * (long)RRD_PRIM_SIZES[RRD_DOUBLE]); - backend.writeDouble(offset, values); - } - - final String readString() throws IOException { - return backend.readString(pointer); - } - - final void writeString(final String value) throws IOException { - backend.writeString(pointer, value); - } - - final boolean isCachingAllowed() { - return cachingAllowed; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdSafeFileBackend.java b/apps/jrobin/java/src/org/jrobin/core/RrdSafeFileBackend.java deleted file mode 100644 index 3be8bcb006a046a59f69403151d2ecae904f8dd4..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdSafeFileBackend.java +++ /dev/null @@ -1,137 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; -import java.nio.channels.FileLock; -import java.nio.channels.FileChannel; - -/** - * JRobin backend which is used to store RRD data to ordinary files on the disk. This backend - * is SAFE: it locks the underlying RRD file during update/fetch operations, and caches only static - * parts of a RRD file in memory. Therefore, this backend is safe to be used when RRD files should - * be shared between several JVMs at the same time. However, this backend is a little bit slow - * since it does not use fast java.nio.* package (it's still based on the RandomAccessFile class). - */ -public class RrdSafeFileBackend extends RrdFileBackend { - private static final Counters counters = new Counters(); - - private FileLock m_lock; - - /** - * Creates RrdFileBackend object for the given file path, backed by RandomAccessFile object. - * - * @param path Path to a file - * @param lockWaitTime lock waiting time in milliseconds - * @param lockRetryPeriod lock retry period in milliseconds - * @throws IOException Thrown in case of I/O error - */ - public RrdSafeFileBackend(final String path, final long lockWaitTime, final long lockRetryPeriod) throws IOException { - super(path, false); - try { - lockFile(lockWaitTime, lockRetryPeriod); - } - catch (final IOException ioe) { - super.close(); - throw ioe; - } - } - - private void lockFile(final long lockWaitTime, final long lockRetryPeriod) throws IOException { - final long entryTime = System.currentTimeMillis(); - final FileChannel channel = file.getChannel(); - m_lock = channel.tryLock(0, Long.MAX_VALUE, false); - if (m_lock != null) { - counters.registerQuickLock(); - return; - } - do { - try { - Thread.sleep(lockRetryPeriod); - } - catch (final InterruptedException e) { - Thread.currentThread().interrupt(); - } - m_lock = channel.tryLock(0, Long.MAX_VALUE, false); - if (m_lock != null) { - counters.registerDelayedLock(); - return; - } - } while (System.currentTimeMillis() - entryTime <= lockWaitTime); - counters.registerError(); - throw new IOException("Could not obtain exclusive m_lock on file: " + getPath() + "] after " + lockWaitTime + " milliseconds"); - } - - public void close() throws IOException { - try { - if (m_lock != null) { - m_lock.release(); - m_lock = null; - counters.registerUnlock(); - } - } - finally { - super.close(); - } - } - - /** - * Defines the caching policy for this backend. - * - * @return <code>false</code> - */ - protected boolean isCachingAllowed() { - return false; - } - - public static String getLockInfo() { - return counters.getInfo(); - } - - static class Counters { - long locks, quickLocks, unlocks, locked, errors; - - synchronized void registerQuickLock() { - locks++; - quickLocks++; - locked++; - } - - synchronized void registerDelayedLock() { - locks++; - locked++; - } - - synchronized void registerUnlock() { - unlocks++; - locked--; - } - - synchronized void registerError() { - errors++; - } - - synchronized String getInfo() { - return "LOCKS=" + locks + ", " + "UNLOCKS=" + unlocks + ", " + - "DELAYED_LOCKS=" + (locks - quickLocks) + ", " + "LOCKED=" + locked + ", " + - "ERRORS=" + errors; - } - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdSafeFileBackendFactory.java b/apps/jrobin/java/src/org/jrobin/core/RrdSafeFileBackendFactory.java deleted file mode 100644 index ae6fb4e9c4a322fceeed6148b704bd2fd25143a4..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdSafeFileBackendFactory.java +++ /dev/null @@ -1,100 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core; - -import java.io.IOException; - -/** - * Factory class which creates actual {@link RrdSafeFileBackend} objects. - */ -public class RrdSafeFileBackendFactory extends RrdFileBackendFactory { - /** - * Default time (in milliseconds) this backend will wait for a file lock. - */ - public static final long LOCK_WAIT_TIME = 3000L; - private static long lockWaitTime = LOCK_WAIT_TIME; - - /** - * Default time between two consecutive file locking attempts. - */ - public static final long LOCK_RETRY_PERIOD = 50L; - private static long lockRetryPeriod = LOCK_RETRY_PERIOD; - - /** - * factory name, "SAFE" - */ - public static final String NAME = "SAFE"; - - /** - * Creates RrdSafeFileBackend object for the given file path. - * - * @param path File path - * @param readOnly This parameter is ignored - * @return RrdSafeFileBackend object which handles all I/O operations for the given file path - * @throws IOException Thrown in case of I/O error. - */ - protected RrdBackend open(String path, boolean readOnly) throws IOException { - return new RrdSafeFileBackend(path, lockWaitTime, lockRetryPeriod); - } - - /** - * Returns the name of this factory. - * - * @return Factory name (equals to string "SAFE") - */ - public String getFactoryName() { - return NAME; - } - - /** - * Returns time this backend will wait for a file lock. - * - * @return Time (in milliseconds) this backend will wait for a file lock. - */ - public static long getLockWaitTime() { - return lockWaitTime; - } - - /** - * Sets time this backend will wait for a file lock. - * - * @param lockWaitTime Maximum lock wait time (in milliseconds) - */ - public static void setLockWaitTime(long lockWaitTime) { - RrdSafeFileBackendFactory.lockWaitTime = lockWaitTime; - } - - /** - * Returns time between two consecutive file locking attempts. - * - * @return Time (im milliseconds) between two consecutive file locking attempts. - */ - public static long getLockRetryPeriod() { - return lockRetryPeriod; - } - - /** - * Sets time between two consecutive file locking attempts. - * - * @param lockRetryPeriod time (in milliseconds) between two consecutive file locking attempts. - */ - public static void setLockRetryPeriod(long lockRetryPeriod) { - RrdSafeFileBackendFactory.lockRetryPeriod = lockRetryPeriod; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdString.java b/apps/jrobin/java/src/org/jrobin/core/RrdString.java deleted file mode 100644 index 14be148e60c6689eae718d7e76fa9090c947f3a5..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdString.java +++ /dev/null @@ -1,49 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -class RrdString extends RrdPrimitive { - private String cache; - - RrdString(final RrdUpdater updater, final boolean isConstant) throws IOException { - super(updater, RrdPrimitive.RRD_STRING, isConstant); - } - - RrdString(final RrdUpdater updater) throws IOException { - this(updater, false); - } - - void set(final String value) throws IOException { - if (!isCachingAllowed()) { - writeString(value); - } - // caching allowed - else if (cache == null || !cache.equals(value)) { - // update cache - writeString(cache = value); - } - } - - String get() throws IOException { - return (cache != null) ? cache : readString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdToolReader.java b/apps/jrobin/java/src/org/jrobin/core/RrdToolReader.java deleted file mode 100644 index 97f9c121eed99512e5cc411d766164b60ee0fd3c..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdToolReader.java +++ /dev/null @@ -1,124 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core; - -import java.io.IOException; - -import org.jrobin.core.jrrd.RRDatabase; - -class RrdToolReader extends DataImporter { - private RRDatabase rrd; - - RrdToolReader(String rrdPath) throws IOException,RrdException { - rrd = new RRDatabase(rrdPath); - } - - String getVersion() { - return rrd.getHeader().getVersion(); - } - - long getLastUpdateTime() { - return Util.getTimestamp(rrd.getLastUpdate()); - } - - long getStep() { - return rrd.getHeader().getPDPStep(); - } - - int getDsCount() { - return rrd.getHeader().getDSCount(); - } - - int getArcCount() throws RrdException, IOException { - return rrd.getNumArchives(); - } - - String getDsName(int dsIndex) { - return rrd.getDataSource(dsIndex).getName(); - } - - String getDsType(int dsIndex) { - return rrd.getDataSource(dsIndex).getType().toString(); - } - - long getHeartbeat(int dsIndex) { - return rrd.getDataSource(dsIndex).getMinimumHeartbeat(); - } - - double getMinValue(int dsIndex) { - return rrd.getDataSource(dsIndex).getMinimum(); - } - - double getMaxValue(int dsIndex) { - return rrd.getDataSource(dsIndex).getMaximum(); - } - - double getLastValue(int dsIndex) { - String valueStr = rrd.getDataSource(dsIndex).getPDPStatusBlock().getLastReading(); - return Util.parseDouble(valueStr); - } - - double getAccumValue(int dsIndex) { - return rrd.getDataSource(dsIndex).getPDPStatusBlock().getValue(); - } - - long getNanSeconds(int dsIndex) { - return rrd.getDataSource(dsIndex).getPDPStatusBlock().getUnknownSeconds(); - } - - String getConsolFun(int arcIndex) { - return rrd.getArchive(arcIndex).getType().toString(); - } - - double getXff(int arcIndex) { - return rrd.getArchive(arcIndex).getXff(); - } - - int getSteps(int arcIndex) { - return rrd.getArchive(arcIndex).getPdpCount(); - } - - int getRows(int arcIndex) throws RrdException, IOException { - return rrd.getArchive(arcIndex).getRowCount(); - } - - double getStateAccumValue(int arcIndex, int dsIndex) throws RrdException, IOException { - return rrd.getArchive(arcIndex).getCDPStatusBlock(dsIndex).getValue(); - } - - int getStateNanSteps(int arcIndex, int dsIndex) throws RrdException, IOException { - return rrd.getArchive(arcIndex).getCDPStatusBlock(dsIndex).getUnknownDatapoints(); - } - - double[] getValues(int arcIndex, int dsIndex) throws RrdException, IOException,RrdException { - return rrd.getArchive(arcIndex).getValues()[dsIndex]; - } - - void release() throws IOException { - if (rrd != null) { - rrd.close(); - rrd = null; - } - } - - protected void finalize() throws Throwable { - super.finalize(); - release(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdToolkit.java b/apps/jrobin/java/src/org/jrobin/core/RrdToolkit.java deleted file mode 100644 index 6e68348d62cb91d9d90039addadd5e3487ba2eff..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdToolkit.java +++ /dev/null @@ -1,658 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.File; -import java.io.IOException; -import java.util.List; -import java.util.LinkedList; -import java.util.Arrays; - -/** - * Class used to perform various complex operations on RRD files. Use an instance of the - * RrdToolkit class to: - * <p> - * <ul> - * <li>add datasource to a RRD file. - * <li>add archive to a RRD file. - * <li>remove datasource from a RRD file. - * <li>remove archive from a RRD file. - * </ul> - * All these operations can be performed on the copy of the original RRD file, or on the - * original file itself (with possible backup file creation). - * <p> - * <b><u>IMPORTANT</u></b>: NEVER use methods found in this class on 'live' RRD files - * (files which are currently in use). - */ -public class RrdToolkit { - /** - * Creates a new RRD file with one more datasource in it. RRD file is created based on the - * existing one (the original RRD file is not modified at all). All data from - * the original RRD file is copied to the new one. - * - * @param sourcePath path to a RRD file to import data from (will not be modified) - * @param destPath path to a new RRD file (will be created) - * @param newDatasource Datasource definition to be added to the new RRD file - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void addDatasource(String sourcePath, String destPath, DsDef newDatasource) - throws IOException, RrdException { - if (Util.sameFilePath(sourcePath, destPath)) { - throw new RrdException("Source and destination paths are the same"); - } - RrdDb rrdSource = new RrdDb(sourcePath); - try { - RrdDef rrdDef = rrdSource.getRrdDef(); - rrdDef.setPath(destPath); - rrdDef.addDatasource(newDatasource); - RrdDb rrdDest = new RrdDb(rrdDef); - try { - rrdSource.copyStateTo(rrdDest); - } - finally { - rrdDest.close(); - } - } - finally { - rrdSource.close(); - } - } - - /** - * <p>Adds one more datasource to a RRD file.</p> - * <p>WARNING: This method is potentialy dangerous! It will modify your RRD file. - * It is highly recommended to preserve the original RRD file (<i>saveBackup</i> - * should be set to <code>true</code>). The backup file will be created in the same - * directory as the original one with <code>.bak</code> extension added to the - * original name.</p> - * <p>Before applying this method, be sure that the specified RRD file is not in use - * (not open)</p> - * - * @param sourcePath path to a RRD file to add datasource to. - * @param newDatasource Datasource definition to be added to the RRD file - * @param saveBackup true, if backup of the original file should be created; - * false, otherwise - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void addDatasource(String sourcePath, DsDef newDatasource, boolean saveBackup) - throws IOException, RrdException { - String destPath = Util.getTmpFilename(); - addDatasource(sourcePath, destPath, newDatasource); - copyFile(destPath, sourcePath, saveBackup); - } - - /** - * Creates a new RRD file with one datasource removed. RRD file is created based on the - * existing one (the original RRD file is not modified at all). All remaining data from - * the original RRD file is copied to the new one. - * - * @param sourcePath path to a RRD file to import data from (will not be modified) - * @param destPath path to a new RRD file (will be created) - * @param dsName Name of the Datasource to be removed from the new RRD file - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void removeDatasource(String sourcePath, String destPath, String dsName) - throws IOException, RrdException { - if (Util.sameFilePath(sourcePath, destPath)) { - throw new RrdException("Source and destination paths are the same"); - } - RrdDb rrdSource = new RrdDb(sourcePath); - try { - RrdDef rrdDef = rrdSource.getRrdDef(); - rrdDef.setPath(destPath); - rrdDef.removeDatasource(dsName); - RrdDb rrdDest = new RrdDb(rrdDef); - try { - rrdSource.copyStateTo(rrdDest); - } - finally { - rrdDest.close(); - } - } - finally { - rrdSource.close(); - } - } - - /** - * <p>Removes single datasource from a RRD file.</p> - * <p>WARNING: This method is potentialy dangerous! It will modify your RRD file. - * It is highly recommended to preserve the original RRD file (<i>saveBackup</i> - * should be set to <code>true</code>). The backup file will be created in the same - * directory as the original one with <code>.bak</code> extension added to the - * original name.</p> - * <p>Before applying this method, be sure that the specified RRD file is not in use - * (not open)</p> - * - * @param sourcePath path to a RRD file to remove datasource from. - * @param dsName Name of the Datasource to be removed from the RRD file - * @param saveBackup true, if backup of the original file should be created; - * false, otherwise - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void removeDatasource(String sourcePath, String dsName, boolean saveBackup) - throws IOException, RrdException { - String destPath = Util.getTmpFilename(); - removeDatasource(sourcePath, destPath, dsName); - copyFile(destPath, sourcePath, saveBackup); - } - - /** - * Renames single datasource in the given RRD file. - * - * @param sourcePath Path to a RRD file - * @param oldDsName Old datasource name - * @param newDsName New datasource name - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error (invalid path or datasource names, - * for example) - */ - public static void renameDatasource(String sourcePath, String oldDsName, String newDsName) - throws IOException, RrdException { - RrdDb rrd = new RrdDb(sourcePath); - try { - if (rrd.containsDs(oldDsName)) { - Datasource datasource = rrd.getDatasource(oldDsName); - datasource.setDsName(newDsName); - } - else { - throw new RrdException("Could not find datasource [" + oldDsName + "] in file " + sourcePath); - } - } - finally { - rrd.close(); - } - } - - /** - * Updates single or all datasource names in the specified RRD file - * by appending '!' (if not already present). Datasources with names ending with '!' - * will never store NaNs in RRA archives (zero value will be used instead). Might be useful - * from time to time - * - * @param sourcePath Path to a RRD file - * @param dsName Datasource name or null if you want to rename all datasources - * @return Number of datasources successfully renamed - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error (invalid path or datasource name, - * for example) - */ - public static int forceZerosForNans(String sourcePath, String dsName) throws IOException, RrdException { - RrdDb rrd = new RrdDb(sourcePath); - try { - Datasource[] datasources; - if (dsName == null) { - datasources = rrd.getDatasources(); - } - else { - if (rrd.containsDs(dsName)) { - datasources = new Datasource[] {rrd.getDatasource(dsName)}; - } - else { - throw new RrdException("Could not find datasource [" + dsName + "] in file " + sourcePath); - } - } - int count = 0; - for (Datasource datasource : datasources) { - String currentDsName = datasource.getDsName(); - if (!currentDsName.endsWith(DsDef.FORCE_ZEROS_FOR_NANS_SUFFIX)) { - datasource.setDsName(currentDsName + DsDef.FORCE_ZEROS_FOR_NANS_SUFFIX); - count++; - } - } - return count; - } - finally { - rrd.close(); - } - } - - /** - * Creates a new RRD file with one more archive in it. RRD file is created based on the - * existing one (the original RRD file is not modified at all). All data from - * the original RRD file is copied to the new one. - * - * @param sourcePath path to a RRD file to import data from (will not be modified) - * @param destPath path to a new RRD file (will be created) - * @param newArchive Archive definition to be added to the new RRD file - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void addArchive(String sourcePath, String destPath, ArcDef newArchive) - throws IOException, RrdException { - if (Util.sameFilePath(sourcePath, destPath)) { - throw new RrdException("Source and destination paths are the same"); - } - RrdDb rrdSource = new RrdDb(sourcePath); - try { - RrdDef rrdDef = rrdSource.getRrdDef(); - rrdDef.setPath(destPath); - rrdDef.addArchive(newArchive); - RrdDb rrdDest = new RrdDb(rrdDef); - try { - rrdSource.copyStateTo(rrdDest); - } - finally { - rrdDest.close(); - } - } - finally { - rrdSource.close(); - } - } - - /** - * <p>Adds one more archive to a RRD file.</p> - * <p>WARNING: This method is potentialy dangerous! It will modify your RRD file. - * It is highly recommended to preserve the original RRD file (<i>saveBackup</i> - * should be set to <code>true</code>). The backup file will be created in the same - * directory as the original one with <code>.bak</code> extension added to the - * original name.</p> - * <p>Before applying this method, be sure that the specified RRD file is not in use - * (not open)</p> - * - * @param sourcePath path to a RRD file to add datasource to. - * @param newArchive Archive definition to be added to the RRD file - * @param saveBackup true, if backup of the original file should be created; - * false, otherwise - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void addArchive(String sourcePath, ArcDef newArchive, boolean saveBackup) - throws IOException, RrdException { - String destPath = Util.getTmpFilename(); - addArchive(sourcePath, destPath, newArchive); - copyFile(destPath, sourcePath, saveBackup); - } - - /** - * Creates a new RRD file with one archive removed. RRD file is created based on the - * existing one (the original RRD file is not modified at all). All relevant data from - * the original RRD file is copied to the new one. - * - * @param sourcePath path to a RRD file to import data from (will not be modified) - * @param destPath path to a new RRD file (will be created) - * @param consolFun Consolidation function of Archive which should be removed - * @param steps Number of steps for Archive which should be removed - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void removeArchive(String sourcePath, String destPath, String consolFun, int steps) - throws IOException, RrdException { - if (Util.sameFilePath(sourcePath, destPath)) { - throw new RrdException("Source and destination paths are the same"); - } - RrdDb rrdSource = new RrdDb(sourcePath); - try { - RrdDef rrdDef = rrdSource.getRrdDef(); - rrdDef.setPath(destPath); - rrdDef.removeArchive(consolFun, steps); - RrdDb rrdDest = new RrdDb(rrdDef); - try { - rrdSource.copyStateTo(rrdDest); - } - finally { - rrdDest.close(); - } - } - finally { - rrdSource.close(); - } - } - - /** - * <p>Removes one archive from a RRD file.</p> - * <p>WARNING: This method is potentialy dangerous! It will modify your RRD file. - * It is highly recommended to preserve the original RRD file (<i>saveBackup</i> - * should be set to <code>true</code>). The backup file will be created in the same - * directory as the original one with <code>.bak</code> extension added to the - * original name.</p> - * <p>Before applying this method, be sure that the specified RRD file is not in use - * (not open)</p> - * - * @param sourcePath path to a RRD file to add datasource to. - * @param consolFun Consolidation function of Archive which should be removed - * @param steps Number of steps for Archive which should be removed - * @param saveBackup true, if backup of the original file should be created; - * false, otherwise - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void removeArchive(String sourcePath, String consolFun, int steps, - boolean saveBackup) throws IOException, RrdException { - String destPath = Util.getTmpFilename(); - removeArchive(sourcePath, destPath, consolFun, steps); - copyFile(destPath, sourcePath, saveBackup); - } - - private static void copyFile(String sourcePath, String destPath, boolean saveBackup) - throws IOException { - File source = new File(sourcePath); - File dest = new File(destPath); - if (saveBackup) { - String backupPath = getBackupPath(destPath); - File backup = new File(backupPath); - deleteFile(backup); - if (!dest.renameTo(backup)) { - throw new IOException("Could not create backup file " + backupPath); - } - } - deleteFile(dest); - if (!source.renameTo(dest)) { - throw new IOException("Could not create file " + destPath + " from " + sourcePath); - } - } - - private static String getBackupPath(String destPath) { - StringBuffer sb = new StringBuffer(destPath); - do { - sb.append(".bak"); - } while (Util.fileExists(sb.toString())); - return sb.toString(); - } - - /** - * Sets datasource heartbeat to a new value. - * - * @param sourcePath Path to exisiting RRD file (will be updated) - * @param datasourceName Name of the datasource in the specified RRD file - * @param newHeartbeat New datasource heartbeat - * @throws RrdException Thrown in case of JRobin specific error - * @throws IOException Thrown in case of I/O error - */ - public static void setDsHeartbeat(String sourcePath, String datasourceName, - long newHeartbeat) throws RrdException, IOException { - RrdDb rrd = new RrdDb(sourcePath); - try { - Datasource ds = rrd.getDatasource(datasourceName); - ds.setHeartbeat(newHeartbeat); - } - finally { - rrd.close(); - } - } - - /** - * Sets datasource heartbeat to a new value. - * - * @param sourcePath Path to exisiting RRD file (will be updated) - * @param dsIndex Index of the datasource in the specified RRD file - * @param newHeartbeat New datasource heartbeat - * @throws RrdException Thrown in case of JRobin specific error - * @throws IOException Thrown in case of I/O error - */ - public static void setDsHeartbeat(String sourcePath, int dsIndex, long newHeartbeat) - throws RrdException, IOException { - RrdDb rrd = new RrdDb(sourcePath); - try { - Datasource ds = rrd.getDatasource(dsIndex); - ds.setHeartbeat(newHeartbeat); - } - finally { - rrd.close(); - } - } - - /** - * Sets datasource min value to a new value - * - * @param sourcePath Path to exisiting RRD file (will be updated) - * @param datasourceName Name of the datasource in the specified RRD file - * @param newMinValue New min value for the datasource - * @param filterArchivedValues set to <code>true</code> if archived values less than - * <code>newMinValue</code> should be set to NaN; set to false, otherwise. - * @throws RrdException Thrown in case of JRobin specific error - * @throws IOException Thrown in case of I/O error - */ - public static void setDsMinValue(String sourcePath, String datasourceName, - double newMinValue, boolean filterArchivedValues) throws RrdException, IOException { - RrdDb rrd = new RrdDb(sourcePath); - try { - Datasource ds = rrd.getDatasource(datasourceName); - ds.setMinValue(newMinValue, filterArchivedValues); - } - finally { - rrd.close(); - } - } - - /** - * Sets datasource max value to a new value. - * - * @param sourcePath Path to exisiting RRD file (will be updated) - * @param datasourceName Name of the datasource in the specified RRD file - * @param newMaxValue New max value for the datasource - * @param filterArchivedValues set to <code>true</code> if archived values greater than - * <code>newMaxValue</code> should be set to NaN; set to false, otherwise. - * @throws RrdException Thrown in case of JRobin specific error - * @throws IOException Thrown in case of I/O error - */ - public static void setDsMaxValue(String sourcePath, String datasourceName, - double newMaxValue, boolean filterArchivedValues) throws RrdException, IOException { - RrdDb rrd = new RrdDb(sourcePath); - try { - Datasource ds = rrd.getDatasource(datasourceName); - ds.setMaxValue(newMaxValue, filterArchivedValues); - } - finally { - rrd.close(); - } - } - - /** - * Updates valid value range for the given datasource. - * - * @param sourcePath Path to exisiting RRD file (will be updated) - * @param datasourceName Name of the datasource in the specified RRD file - * @param newMinValue New min value for the datasource - * @param newMaxValue New max value for the datasource - * @param filterArchivedValues set to <code>true</code> if archived values outside - * of the specified min/max range should be replaced with NaNs. - * @throws RrdException Thrown in case of JRobin specific error - * @throws IOException Thrown in case of I/O error - */ - public static void setDsMinMaxValue(String sourcePath, String datasourceName, - double newMinValue, double newMaxValue, boolean filterArchivedValues) - throws RrdException, IOException { - RrdDb rrd = new RrdDb(sourcePath); - try { - Datasource ds = rrd.getDatasource(datasourceName); - ds.setMinMaxValue(newMinValue, newMaxValue, filterArchivedValues); - } - finally { - rrd.close(); - } - } - - /** - * Sets single archive's X-files factor to a new value. - * - * @param sourcePath Path to existing RRD file (will be updated) - * @param consolFun Consolidation function of the target archive - * @param steps Number of sptes of the target archive - * @param newXff New X-files factor for the target archive - * @throws RrdException Thrown in case of JRobin specific error - * @throws IOException Thrown in case of I/O error - */ - public static void setArcXff(String sourcePath, String consolFun, int steps, - double newXff) throws RrdException, IOException { - RrdDb rrd = new RrdDb(sourcePath); - try { - Archive arc = rrd.getArchive(consolFun, steps); - arc.setXff(newXff); - } - finally { - rrd.close(); - } - } - - /** - * Creates new RRD file based on the existing one, but with a different - * size (number of rows) for a single archive. The archive to be resized - * is identified by its consolidation function and the number of steps. - * - * @param sourcePath Path to the source RRD file (will not be modified) - * @param destPath Path to the new RRD file (will be created) - * @param consolFun Consolidation function of the archive to be resized - * @param numSteps Number of steps of the archive to be resized - * @param newRows New archive size (number of archive rows) - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void resizeArchive(String sourcePath, String destPath, String consolFun, - int numSteps, int newRows) - throws IOException, RrdException { - if (Util.sameFilePath(sourcePath, destPath)) { - throw new RrdException("Source and destination paths are the same"); - } - if (newRows < 2) { - throw new RrdException("New arcihve size must be at least 2"); - } - RrdDb rrdSource = new RrdDb(sourcePath); - try { - RrdDef rrdDef = rrdSource.getRrdDef(); - ArcDef arcDef = rrdDef.findArchive(consolFun, numSteps); - if (arcDef.getRows() != newRows) { - arcDef.setRows(newRows); - rrdDef.setPath(destPath); - RrdDb rrdDest = new RrdDb(rrdDef); - try { - rrdSource.copyStateTo(rrdDest); - } - finally { - rrdDest.close(); - } - } - } - finally { - rrdSource.close(); - } - } - - /** - * Modifies existing RRD file, by resizing its chosen archive. The archive to be resized - * is identified by its consolidation function and the number of steps. - * - * @param sourcePath Path to the RRD file (will be modified) - * @param consolFun Consolidation function of the archive to be resized - * @param numSteps Number of steps of the archive to be resized - * @param newRows New archive size (number of archive rows) - * @param saveBackup true, if backup of the original file should be created; - * false, otherwise - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void resizeArchive(String sourcePath, String consolFun, - int numSteps, int newRows, boolean saveBackup) - throws IOException, RrdException { - String destPath = Util.getTmpFilename(); - resizeArchive(sourcePath, destPath, consolFun, numSteps, newRows); - copyFile(destPath, sourcePath, saveBackup); - } - - private static void deleteFile(File file) throws IOException { - if (file.exists() && !file.delete()) { - throw new IOException("Could not delete file: " + file.getCanonicalPath()); - } - } - - /** - * Splits single RRD file with several datasources into a number of smaller RRD files - * with a single datasource in it. All archived values are preserved. If - * you have a RRD file named 'traffic.rrd' with two datasources, 'in' and 'out', this - * method will create two files (with a single datasource, in the same directory) - * named 'in-traffic.rrd' and 'out-traffic.rrd'. - * - * @param sourcePath Path to a RRD file with multiple datasources defined - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin specific error - */ - public static void split(String sourcePath) throws IOException, RrdException { - RrdDb rrdSource = new RrdDb(sourcePath); - try { - String[] dsNames = rrdSource.getDsNames(); - for (String dsName : dsNames) { - RrdDef rrdDef = rrdSource.getRrdDef(); - rrdDef.setPath(createSplitPath(dsName, sourcePath)); - rrdDef.saveSingleDatasource(dsName); - RrdDb rrdDest = new RrdDb(rrdDef); - try { - rrdSource.copyStateTo(rrdDest); - } - finally { - rrdDest.close(); - } - } - } - finally { - rrdSource.close(); - } - } - - /** - * Returns list of canonical file names with the specified extension in the given directory. This - * method is not RRD related, but might come handy to create a quick list of all RRD files - * in the given directory. - * - * @param directory Source directory - * @param extension File extension (like ".rrd", ".jrb", ".rrd.jrb") - * @param resursive true if all subdirectories should be traversed for the same extension, false otherwise - * @return Array of sorted canonical file names with the given extension - * @throws IOException Thrown in case of I/O error - */ - public static String[] getCanonicalPaths(String directory, final String extension, boolean resursive) - throws IOException { - File baseDir = new File(directory); - if (!baseDir.isDirectory()) { - throw new IOException("Not a directory: " + directory); - } - List<String> fileList = new LinkedList<String>(); - traverseDirectory(new File(directory), extension, resursive, fileList); - String[] result = fileList.toArray(new String[fileList.size()]); - Arrays.sort(result); - return result; - } - - private static void traverseDirectory(File directory, String extension, boolean recursive, List<String> list) - throws IOException { - File[] files = directory.listFiles(); - for (File file : files) { - if (file.isDirectory() && recursive) { - // traverse subdirectories only if recursive flag is specified - traverseDirectory(file, extension, recursive, list); - } - else if (file.isFile() && file.getName().endsWith(extension)) { - list.add(file.getCanonicalPath()); - } - } - } - - private static String createSplitPath(String dsName, String sourcePath) { - File file = new File(sourcePath); - String newName = dsName + "-" + file.getName(); - String path = file.getAbsolutePath(); - String parentDir = path.substring(0, 1 + path.lastIndexOf(Util.getFileSeparator())); - return parentDir + newName; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/RrdUpdater.java b/apps/jrobin/java/src/org/jrobin/core/RrdUpdater.java deleted file mode 100644 index 065cec1b019813eea3a908635ab8e538dde798dd..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/RrdUpdater.java +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; - -interface RrdUpdater { - public RrdBackend getRrdBackend(); - - public void copyStateTo(RrdUpdater updater) throws IOException, RrdException; - - public RrdAllocator getRrdAllocator(); -} diff --git a/apps/jrobin/java/src/org/jrobin/core/Sample.java b/apps/jrobin/java/src/org/jrobin/core/Sample.java deleted file mode 100644 index 43212d8f6efc78b269266121332bbdad9a6e2aa7..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/Sample.java +++ /dev/null @@ -1,295 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.io.IOException; -import java.util.Date; -import java.util.StringTokenizer; - -/** - * Class to represent data source values for the given timestamp. Objects of this - * class are never created directly (no public constructor is provided). To learn more how - * to update RRDs, see RRDTool's - * <a href="../../../../man/rrdupdate.html" target="man">rrdupdate man page</a>. - * <p> - * To update a RRD with JRobin use the following procedure: - * <p> - * <ol> - * <li>Obtain empty Sample object by calling method {@link RrdDb#createSample(long) - * createSample()} on respective {@link RrdDb RrdDb} object. - * <li>Adjust Sample timestamp if necessary (see {@link #setTime(long) setTime()} method). - * <li>Supply data source values (see {@link #setValue(String, double) setValue()}). - * <li>Call Sample's {@link #update() update()} method. - * </ol> - * <p> - * Newly created Sample object contains all data source values set to 'unknown'. - * You should specifify only 'known' data source values. However, if you want to specify - * 'unknown' values too, use <code>Double.NaN</code>. - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ -public class Sample { - private RrdDb parentDb; - private long time; - private String[] dsNames; - private double[] values; - - Sample(final RrdDb parentDb, final long time) throws IOException { - this.parentDb = parentDb; - this.time = time; - this.dsNames = parentDb.getDsNames(); - values = new double[dsNames.length]; - clearCurrentValues(); - } - - private Sample clearCurrentValues() { - for (int i = 0; i < values.length; i++) { - values[i] = Double.NaN; - } - return this; - } - - /** - * Sets single data source value in the sample. - * - * @param dsName Data source name. - * @param value Data source value. - * @return This <code>Sample</code> object - * @throws RrdException Thrown if invalid data source name is supplied. - */ - public Sample setValue(final String dsName, final double value) throws RrdException { - for (int i = 0; i < values.length; i++) { - if (dsNames[i].equals(dsName)) { - values[i] = value; - return this; - } - } - throw new RrdException("Datasource " + dsName + " not found"); - } - - /** - * Sets single datasource value using data source index. Data sources are indexed by - * the order specified during RRD creation (zero-based). - * - * @param i Data source index - * @param value Data source values - * @return This <code>Sample</code> object - * @throws RrdException Thrown if data source index is invalid. - */ - public Sample setValue(final int i, final double value) throws RrdException { - if (i < values.length) { - values[i] = value; - return this; - } - else { - throw new RrdException("Sample datasource index " + i + " out of bounds"); - } - } - - /** - * Sets some (possibly all) data source values in bulk. Data source values are - * assigned in the order of their definition inside the RRD. - * - * @param values Data source values. - * @return This <code>Sample</code> object - * @throws RrdException Thrown if the number of supplied values is zero or greater - * than the number of data sources defined in the RRD. - */ - public Sample setValues(final double[] values) throws RrdException { - if (values.length <= this.values.length) { - System.arraycopy(values, 0, this.values, 0, values.length); - return this; - } - else { - throw new RrdException("Invalid number of values specified (found " + values.length + ", only " + dsNames.length + " allowed)"); - } - } - - /** - * Returns all current data source values in the sample. - * - * @return Data source values. - */ - public double[] getValues() { - return values; - } - - /** - * Returns sample timestamp (in seconds, without milliseconds). - * - * @return Sample timestamp. - */ - public long getTime() { - return time; - } - - /** - * Sets sample timestamp. Timestamp should be defined in seconds (without milliseconds). - * - * @param time New sample timestamp. - * @return This <code>Sample</code> object - */ - public Sample setTime(final long time) { - this.time = time; - return this; - } - - /** - * Returns an array of all data source names. If you try to set value for the data source - * name not in this array, an exception is thrown. - * - * @return Acceptable data source names. - */ - public String[] getDsNames() { - return dsNames; - } - - /** - * Sets sample timestamp and data source values in a fashion similar to RRDTool. - * Argument string should be composed in the following way: - * <code>timestamp:value1:value2:...:valueN</code>. - * <p> - * You don't have to supply all datasource values. Unspecified values will be treated - * as unknowns. To specify unknown value in the argument string, use letter 'U'. - * - * @param timeAndValues String made by concatenating sample timestamp with corresponding - * data source values delmited with colons. For example:<p> - * <pre> - * 1005234132:12.2:35.6:U:24.5 - * NOW:12.2:35.6:U:24.5 - * </pre> - * 'N' stands for the current timestamp (can be replaced with 'NOW')<p> - * Method will throw an exception if timestamp is invalid (cannot be parsed as Long, and is not 'N' - * or 'NOW'). Datasource value which cannot be parsed as 'double' will be silently set to NaN.<p> - * @return This <code>Sample</code> object - * @throws RrdException Thrown if too many datasource values are supplied - */ - public Sample set(final String timeAndValues) throws RrdException { - final StringTokenizer tokenizer = new StringTokenizer(timeAndValues, ":", false); - final int tokenCount = tokenizer.countTokens(); - if (tokenCount > values.length + 1) { - throw new RrdException("Invalid number of values specified (found " + values.length + ", " + dsNames.length + " allowed)"); - } - final String timeToken = tokenizer.nextToken(); - try { - time = Long.parseLong(timeToken); - } - catch (final NumberFormatException nfe) { - if (timeToken.equalsIgnoreCase("N") || timeToken.equalsIgnoreCase("NOW")) { - time = Util.getTime(); - } - else { - throw new RrdException("Invalid sample timestamp: " + timeToken); - } - } - for (int i = 0; tokenizer.hasMoreTokens(); i++) { - try { - values[i] = Double.parseDouble(tokenizer.nextToken()); - } - catch (final NumberFormatException nfe) { - // NOP, value is already set to NaN - } - } - return this; - } - - /** - * Stores sample in the corresponding RRD. If the update operation succeedes, - * all datasource values in the sample will be set to Double.NaN (unknown) values. - * - * @throws IOException Thrown in case of I/O error. - * @throws RrdException Thrown in case of JRobin related error. - */ - public void update() throws IOException, RrdException { - parentDb.store(this); - clearCurrentValues(); - } - - /** - * <p>Creates sample with the timestamp and data source values supplied - * in the argument string and stores sample in the corresponding RRD. - * This method is just a shortcut for:</p> - * <pre> - * set(timeAndValues); - * update(); - * </pre> - * - * @param timeAndValues String made by concatenating sample timestamp with corresponding - * data source values delmited with colons. For example:<br> - * <code>1005234132:12.2:35.6:U:24.5</code><br> - * <code>NOW:12.2:35.6:U:24.5</code> - * @throws IOException Thrown in case of I/O error. - * @throws RrdException Thrown in case of JRobin related error. - */ - public void setAndUpdate(final String timeAndValues) throws IOException, RrdException { - set(timeAndValues); - update(); - } - - /** - * Dumps sample content using the syntax of RRDTool's update command. - * - * @return Sample dump. - */ - public String dump() { - final StringBuffer buffer = new StringBuffer("update \""); - buffer.append(parentDb.getRrdBackend().getPath()).append("\" ").append(time); - for (final double value : values) { - buffer.append(":"); - buffer.append(Util.formatDouble(value, "U", false)); - } - return buffer.toString(); - } - - String getRrdToolCommand() { - return dump(); - } - - public String toString() { - return getClass().getSimpleName() + "@" + "[parentDb=" + parentDb + ",time=" + new Date(time * 1000L) + ",dsNames=[" + printList(dsNames) + "],values=[" + printList(values) + "]]"; - } - - private String printList(final Object[] dsNames) { - if (dsNames == null) return "null"; - final StringBuffer sb = new StringBuffer(); - for (int i = 0; i < dsNames.length; i++) { - if (i == dsNames.length - 1) { - sb.append(dsNames[i]); - } else { - sb.append(dsNames[i]).append(", "); - } - } - return sb.toString(); - } - - private String printList(final double[] values) { - if (values == null) return "null"; - final StringBuffer sb = new StringBuffer(); - for (int i = 0; i < values.length; i++) { - if (i == values.length - 1) { - sb.append(values[i]); - } else { - sb.append(values[i]).append(", "); - } - } - return sb.toString(); - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/core/SyncManager.java b/apps/jrobin/java/src/org/jrobin/core/SyncManager.java deleted file mode 100644 index 71bba51cb229f9e119de0778e4ef08e1cfcff1a1..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/SyncManager.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.jrobin.core; - -import java.util.HashMap; -import java.util.Map; -import java.util.Timer; -import java.util.TimerTask; - - -public final class SyncManager { - private int m_syncPeriod = RrdNioBackendFactory.DEFAULT_SYNC_PERIOD; - private Timer m_timer = null; - private Map<RrdNioBackend,TimerTask> m_tasks = new HashMap<RrdNioBackend,TimerTask>(); - - public SyncManager(final int syncPeriod) { - m_syncPeriod = syncPeriod; - } - - public int getSyncPeriod() { - return m_syncPeriod; - } - - public void setSyncPeriod(final int syncPeriod) { - m_syncPeriod = syncPeriod; - synchronized(m_tasks) { - final Timer oldTimer = m_timer; - m_timer = new SyncTimer(); - for (final RrdNioBackend backend : m_tasks.keySet()) { - m_tasks.get(backend).cancel(); - scheduleTask(backend); - } - cancelTimer(oldTimer); - } - } - - public void add(final RrdNioBackend rrdNioBackend) { - synchronized(m_tasks) { - if (m_tasks.size() == 0) { - m_timer = new SyncTimer(); - } - scheduleTask(rrdNioBackend); - } - } - - public void remove(final RrdNioBackend rrdNioBackend) { - synchronized (m_tasks) { - final TimerTask oldTask = m_tasks.remove(rrdNioBackend); - if (oldTask != null) oldTask.cancel(); - if (m_tasks.size() == 0) { - cancelTimer(m_timer); - m_timer = null; - } - } - } - - public void shutdown() { - synchronized(m_tasks) { - for (final Map.Entry<RrdNioBackend, TimerTask> entry : m_tasks.entrySet()) { - entry.getValue().cancel(); - } - cancelTimer(m_timer); - } - } - - private void cancelTimer(final Timer timer) { - if (timer == null) return; - timer.cancel(); - timer.purge(); - } - - private void scheduleTask(final RrdNioBackend rrdNioBackend) { - final TimerTask task = new SyncTimerTask(rrdNioBackend); - if (m_tasks.containsKey(rrdNioBackend)) { - m_tasks.get(rrdNioBackend).cancel(); - } - m_tasks.put(rrdNioBackend, task); - m_timer.schedule(task, getSyncPeriod() * 1000L, getSyncPeriod() * 1000L); - } - - Timer getTimer() { - return m_timer; - } -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/core/SyncTimer.java b/apps/jrobin/java/src/org/jrobin/core/SyncTimer.java deleted file mode 100644 index a9fcc3e1e382b9c6365252f91540cae45b1a263d..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/SyncTimer.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.jrobin.core; - -import java.util.Timer; -import java.util.concurrent.atomic.AtomicInteger; - -public class SyncTimer extends Timer { - private static AtomicInteger m_serialNumber = new AtomicInteger(); - - public SyncTimer() { - super("SyncManager-" + m_serialNumber.getAndIncrement(), true); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/SyncTimerTask.java b/apps/jrobin/java/src/org/jrobin/core/SyncTimerTask.java deleted file mode 100644 index 2d7bf676a944920832e16f38058b5485a04288ff..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/SyncTimerTask.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.jrobin.core; - -import java.util.TimerTask; - -public final class SyncTimerTask extends TimerTask { - private final RrdNioBackend m_rrdNioBackend; - - SyncTimerTask(final RrdNioBackend rrdNioBackend) { - m_rrdNioBackend = rrdNioBackend; - } - - @Override public void run() { - m_rrdNioBackend.sync(); - } -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/core/Util.java b/apps/jrobin/java/src/org/jrobin/core/Util.java deleted file mode 100644 index 567a701793ac8494fc429cdb2264fbee07b96339..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/Util.java +++ /dev/null @@ -1,757 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import org.jrobin.core.timespec.TimeParser; -import org.jrobin.core.timespec.TimeSpec; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import java.awt.*; -import java.io.*; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; - -/** - * Class defines various utility functions used in JRobin. - * - * @author <a href="mailto:saxon@jrobin.org">Sasa Markovic</a> - */ -public class Util { - - public static final long MAX_LONG = Long.MAX_VALUE; - public static final long MIN_LONG = -Long.MAX_VALUE; - - public static final double MAX_DOUBLE = Double.MAX_VALUE; - public static final double MIN_DOUBLE = -Double.MAX_VALUE; - - // pattern RRDTool uses to format doubles in XML files - static final String PATTERN = "0.0000000000E00"; - // directory under $USER_HOME used for demo graphs storing - static final String JROBIN_DIR = "jrobin-demo"; - - static final DecimalFormat df; - - static { - df = (DecimalFormat) NumberFormat.getNumberInstance(Locale.ENGLISH); - df.applyPattern(PATTERN); - df.setPositivePrefix("+"); - } - - /** - * Converts an array of long primitives to an array of doubles. - * - * @param array input array of long values. - * @return Same array but with all values as double. - */ - public static double[] toDoubleArray(final long[] array) { - double[] values = new double[ array.length ]; - for (int i = 0; i < array.length; i++) { - values[i] = array[i]; - } - return values; - } - - /** - * Returns current timestamp in seconds (without milliseconds). Returned timestamp - * is obtained with the following expression: - * <p> - * <code>(System.currentTimeMillis() + 500L) / 1000L</code> - * - * @return Current timestamp - */ - public static long getTime() { - return (System.currentTimeMillis() + 500L) / 1000L; - } - - /** - * Just an alias for {@link #getTime()} method. - * - * @return Current timestamp (without milliseconds) - */ - public static long getTimestamp() { - return getTime(); - } - - /** - * Rounds the given timestamp to the nearest whole "step". Rounded value is obtained - * from the following expression: - * <p> - * <code>timestamp - timestamp % step;</code> - * - * @param timestamp Timestamp in seconds - * @param step Step in seconds - * @return "Rounded" timestamp - */ - public static long normalize(long timestamp, long step) { - return timestamp - timestamp % step; - } - - /** - * Returns the greater of two double values, but treats NaN as the smallest possible - * value. Note that <code>Math.max()</code> behaves differently for NaN arguments. - * - * @param x an argument - * @param y another argument - * @return the lager of arguments - */ - public static double max(double x, double y) { - return Double.isNaN(x) ? y : Double.isNaN(y) ? x : Math.max(x, y); - } - - /** - * Returns the smaller of two double values, but treats NaN as the greatest possible - * value. Note that <code>Math.min()</code> behaves differently for NaN arguments. - * - * @param x an argument - * @param y another argument - * @return the smaller of arguments - */ - public static double min(double x, double y) { - return Double.isNaN(x) ? y : Double.isNaN(y) ? x : Math.min(x, y); - } - - /** - * Calculates sum of two doubles, but treats NaNs as zeros. - * - * @param x First double - * @param y Second double - * @return Sum(x,y) calculated as <code>Double.isNaN(x)? y: Double.isNaN(y)? x: x + y;</code> - */ - public static double sum(double x, double y) { - return Double.isNaN(x) ? y : Double.isNaN(y) ? x : x + y; - } - - static String formatDouble(double x, String nanString, boolean forceExponents) { - if (Double.isNaN(x)) { - return nanString; - } - if (forceExponents) { - return df.format(x); - } - return "" + x; - } - - static String formatDouble(double x, boolean forceExponents) { - return formatDouble(x, "" + Double.NaN, forceExponents); - } - - /** - * Formats double as a string using exponential notation (RRDTool like). Used for debugging - * throught the project. - * - * @param x value to be formatted - * @return string like "+1.234567E+02" - */ - public static String formatDouble(double x) { - return formatDouble(x, true); - } - - /** - * Returns <code>Date</code> object for the given timestamp (in seconds, without - * milliseconds) - * - * @param timestamp Timestamp in seconds. - * @return Corresponding Date object. - */ - public static Date getDate(long timestamp) { - return new Date(timestamp * 1000L); - } - - /** - * Returns <code>Calendar</code> object for the given timestamp - * (in seconds, without milliseconds) - * - * @param timestamp Timestamp in seconds. - * @return Corresponding Calendar object. - */ - public static Calendar getCalendar(long timestamp) { - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(timestamp * 1000L); - return calendar; - } - - /** - * Returns <code>Calendar</code> object for the given Date object - * - * @param date Date object - * @return Corresponding Calendar object. - */ - public static Calendar getCalendar(Date date) { - Calendar calendar = Calendar.getInstance(); - calendar.setTime(date); - return calendar; - } - - /** - * Returns timestamp (unix epoch) for the given Date object - * - * @param date Date object - * @return Corresponding timestamp (without milliseconds) - */ - public static long getTimestamp(final Date date) { - // round to whole seconds, ignore milliseconds - return (date.getTime() + 499L) / 1000L; - } - - /** - * Returns timestamp (unix epoch) for the given Calendar object - * - * @param gc Calendar object - * @return Corresponding timestamp (without milliseconds) - */ - public static long getTimestamp(final Calendar gc) { - return getTimestamp(gc.getTime()); - } - - /** - * Returns timestamp (unix epoch) for the given year, month, day, hour and minute. - * - * @param year Year - * @param month Month (zero-based) - * @param day Day in month - * @param hour Hour - * @param min Minute - * @return Corresponding timestamp - */ - public static long getTimestamp(final int year, final int month, final int day, final int hour, final int min) { - final Calendar calendar = Calendar.getInstance(); - calendar.clear(); - calendar.set(year, month, day, hour, min); - return Util.getTimestamp(calendar); - } - - /** - * Returns timestamp (unix epoch) for the given year, month and day. - * - * @param year Year - * @param month Month (zero-based) - * @param day Day in month - * @return Corresponding timestamp - */ - public static long getTimestamp(int year, int month, int day) { - return Util.getTimestamp(year, month, day, 0, 0); - } - - /** - * Parses at-style time specification and returns the corresponding timestamp. For example:<p> - * <pre> - * long t = Util.getTimestamp("now-1d"); - * </pre> - * - * @param atStyleTimeSpec at-style time specification. For the complete explanation of the syntax - * allowed see RRDTool's <code>rrdfetch</code> man page.<p> - * @return timestamp in seconds since epoch. - * @throws RrdException Thrown if invalid time specification is supplied. - */ - public static long getTimestamp(final String atStyleTimeSpec) throws RrdException { - final TimeSpec timeSpec = new TimeParser(atStyleTimeSpec).parse(); - return timeSpec.getTimestamp(); - } - - /** - * Parses two related at-style time specifications and returns corresponding timestamps. For example:<p> - * <pre> - * long[] t = Util.getTimestamps("end-1d","now"); - * </pre> - * - * @param atStyleTimeSpec1 Starting at-style time specification. For the complete explanation of the syntax - * allowed see RRDTool's <code>rrdfetch</code> man page.<p> - * @param atStyleTimeSpec2 Ending at-style time specification. For the complete explanation of the syntax - * allowed see RRDTool's <code>rrdfetch</code> man page.<p> - * @return An array of two longs representing starting and ending timestamp in seconds since epoch. - * @throws RrdException Thrown if any input time specification is invalid. - */ - public static long[] getTimestamps(final String atStyleTimeSpec1, final String atStyleTimeSpec2) throws RrdException { - final TimeSpec timeSpec1 = new TimeParser(atStyleTimeSpec1).parse(); - final TimeSpec timeSpec2 = new TimeParser(atStyleTimeSpec2).parse(); - return TimeSpec.getTimestamps(timeSpec1, timeSpec2); - } - - /** - * Parses input string as a double value. If the value cannot be parsed, Double.NaN - * is returned (NumberFormatException is never thrown). - * - * @param valueStr String representing double value - * @return a double corresponding to the input string - */ - public static double parseDouble(final String valueStr) { - double value; - try { - value = Double.parseDouble(valueStr); - } - catch (final NumberFormatException nfe) { - value = Double.NaN; - } - return value; - } - - /** - * Checks if a string can be parsed as double. - * - * @param s Input string - * @return <code>true</code> if the string can be parsed as double, <code>false</code> otherwise - */ - public static boolean isDouble(final String s) { - try { - Double.parseDouble(s); - return true; - } - catch (final NumberFormatException nfe) { - return false; - } - } - - /** - * Parses input string as a boolean value. The parser is case insensitive. - * - * @param valueStr String representing boolean value - * @return <code>true</code>, if valueStr equals to 'true', 'on', 'yes', 'y' or '1'; - * <code>false</code> in all other cases. - */ - public static boolean parseBoolean(final String valueStr) { - return valueStr.equalsIgnoreCase("true") || - valueStr.equalsIgnoreCase("on") || - valueStr.equalsIgnoreCase("yes") || - valueStr.equalsIgnoreCase("y") || - valueStr.equalsIgnoreCase("1"); - } - - /** - * Parses input string as color. The color string should be of the form #RRGGBB (no alpha specified, - * opaque color) or #RRGGBBAA (alpa specified, transparent colors). Leading character '#' is - * optional. - * - * @param valueStr Input string, for example #FFAA24, #AABBCC33, 010203 or ABC13E4F - * @return Paint object - * @throws RrdException If the input string is not 6 or 8 characters long (without optional '#') - */ - public static Paint parseColor(final String valueStr) throws RrdException { - final String c = valueStr.startsWith("#") ? valueStr.substring(1) : valueStr; - if (c.length() != 6 && c.length() != 8) { - throw new RrdException("Invalid color specification: " + valueStr); - } - final String r = c.substring(0, 2), g = c.substring(2, 4), b = c.substring(4, 6); - if (c.length() == 6) { - return new Color(Integer.parseInt(r, 16), Integer.parseInt(g, 16), Integer.parseInt(b, 16)); - } - else { - final String a = c.substring(6); - return new Color(Integer.parseInt(r, 16), Integer.parseInt(g, 16), - Integer.parseInt(b, 16), Integer.parseInt(a, 16)); - } - } - - /** - * Returns file system separator string. - * - * @return File system separator ("/" on Unix, "\" on Windows) - */ - public static String getFileSeparator() { - return System.getProperty("file.separator"); - } - - /** - * Returns path to user's home directory. - * - * @return Path to users home directory, with file separator appended. - */ - public static String getUserHomeDirectory() { - return System.getProperty("user.home") + getFileSeparator(); - } - - /** - * Returns path to directory used for placement of JRobin demo graphs and creates it - * if necessary. - * - * @return Path to demo directory (defaults to $HOME/jrobin/) if directory exists or - * was successfully created. Null if such directory could not be created. - */ - public static String getJRobinDemoDirectory() { - final String homeDirPath = getUserHomeDirectory() + JROBIN_DIR + getFileSeparator(); - final File homeDirFile = new File(homeDirPath); - return (homeDirFile.exists() || homeDirFile.mkdirs()) ? homeDirPath : null; - } - - /** - * Returns full path to the file stored in the demo directory of JRobin - * - * @param filename Partial path to the file stored in the demo directory of JRobin - * (just name and extension, without parent directories) - * @return Full path to the file - */ - public static String getJRobinDemoPath(final String filename) { - final String demoDir = getJRobinDemoDirectory(); - if (demoDir != null) { - return demoDir + filename; - } - else { - return null; - } - } - - static boolean sameFilePath(final String path1, final String path2) throws IOException { - final File file1 = new File(path1); - final File file2 = new File(path2); - return file1.getCanonicalPath().equals(file2.getCanonicalPath()); - } - - static int getMatchingDatasourceIndex(final RrdDb rrd1, final int dsIndex, final RrdDb rrd2) throws IOException { - final String dsName = rrd1.getDatasource(dsIndex).getDsName(); - try { - return rrd2.getDsIndex(dsName); - } - catch (final RrdException e) { - return -1; - } - } - - static int getMatchingArchiveIndex(final RrdDb rrd1, final int arcIndex, final RrdDb rrd2) throws IOException { - final Archive archive = rrd1.getArchive(arcIndex); - final String consolFun = archive.getConsolFun(); - final int steps = archive.getSteps(); - try { - return rrd2.getArcIndex(consolFun, steps); - } - catch (final RrdException e) { - return -1; - } - } - - static String getTmpFilename() throws IOException { - return File.createTempFile("JROBIN_", ".tmp").getCanonicalPath(); - } - - static final String ISO_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; // ISO - - /** - * Creates Calendar object from a string. The string should represent - * either a long integer (UNIX timestamp in seconds without milliseconds, - * like "1002354657") or a human readable date string in the format "yyyy-MM-dd HH:mm:ss" - * (like "2004-02-25 12:23:45"). - * - * @param timeStr Input string - * @return Calendar object - */ - public static Calendar getCalendar(final String timeStr) { - // try to parse it as long - try { - return Util.getCalendar(Long.parseLong(timeStr)); - } - catch (final NumberFormatException nfe) { - // not a long timestamp, try to parse it as data - final SimpleDateFormat df = new SimpleDateFormat(ISO_DATE_FORMAT); - df.setLenient(false); - try { - return Util.getCalendar(df.parse(timeStr)); - } - catch (final ParseException pe) { - throw new IllegalArgumentException("Time/date not in " + ISO_DATE_FORMAT + " format: " + timeStr); - } - } - } - - /** - * Various DOM utility functions - */ - public static class Xml { - public static Node[] getChildNodes(final Node parentNode) { - return getChildNodes(parentNode, null); - } - - public static Node[] getChildNodes(final Node parentNode, final String childName) { - final ArrayList<Node> nodes = new ArrayList<Node>(); - final NodeList nodeList = parentNode.getChildNodes(); - for (int i = 0; i < nodeList.getLength(); i++) { - final Node node = nodeList.item(i); - if (childName == null || node.getNodeName().equals(childName)) { - nodes.add(node); - } - } - return nodes.toArray(new Node[0]); - } - - public static Node getFirstChildNode(final Node parentNode, final String childName) throws RrdException { - final Node[] childs = getChildNodes(parentNode, childName); - if (childs.length > 0) { - return childs[0]; - } - throw new RrdException("XML Error, no such child: " + childName); - } - - public static boolean hasChildNode(final Node parentNode, final String childName) { - final Node[] childs = getChildNodes(parentNode, childName); - return childs.length > 0; - } - - // -- Wrapper around getChildValue with trim - public static String getChildValue(final Node parentNode, final String childName) throws RrdException { - return getChildValue(parentNode, childName, true); - } - - public static String getChildValue(final Node parentNode, final String childName, final boolean trim) throws RrdException { - final NodeList children = parentNode.getChildNodes(); - for (int i = 0; i < children.getLength(); i++) { - final Node child = children.item(i); - if (child.getNodeName().equals(childName)) { - return getValue(child, trim); - } - } - throw new RrdException("XML Error, no such child: " + childName); - } - - // -- Wrapper around getValue with trim - public static String getValue(final Node node) { - return getValue(node, true); - } - - public static String getValue(final Node node, final boolean trimValue) { - String value = null; - final Node child = node.getFirstChild(); - if (child != null) { - value = child.getNodeValue(); - if (value != null && trimValue) { - value = value.trim(); - } - } - return value; - } - - public static int getChildValueAsInt(final Node parentNode, final String childName) throws RrdException { - final String valueStr = getChildValue(parentNode, childName); - return Integer.parseInt(valueStr); - } - - public static int getValueAsInt(final Node node) { - return Integer.parseInt(getValue(node)); - } - - public static long getChildValueAsLong(final Node parentNode, final String childName) throws RrdException { - final String valueStr = getChildValue(parentNode, childName); - return Long.parseLong(valueStr); - } - - public static long getValueAsLong(final Node node) { - return Long.parseLong(getValue(node)); - } - - public static double getChildValueAsDouble(final Node parentNode, final String childName) throws RrdException { - return Util.parseDouble(getChildValue(parentNode, childName)); - } - - public static double getValueAsDouble(final Node node) { - return Util.parseDouble(getValue(node)); - } - - public static boolean getChildValueAsBoolean(final Node parentNode, final String childName) throws RrdException { - return Util.parseBoolean(getChildValue(parentNode, childName)); - } - - public static boolean getValueAsBoolean(final Node node) { - return Util.parseBoolean(getValue(node)); - } - - public static Element getRootElement(final InputSource inputSource) throws RrdException, IOException { - final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setValidating(false); - factory.setNamespaceAware(false); - try { - final DocumentBuilder builder = factory.newDocumentBuilder(); - final Document doc = builder.parse(inputSource); - return doc.getDocumentElement(); - } - catch (final ParserConfigurationException e) { - throw new RrdException(e); - } - catch (final SAXException e) { - throw new RrdException(e); - } - } - - public static Element getRootElement(final String xmlString) throws RrdException, IOException { - return getRootElement(new InputSource(new StringReader(xmlString))); - } - - public static Element getRootElement(final File xmlFile) throws RrdException, IOException { - Reader reader = null; - try { - reader = new FileReader(xmlFile); - return getRootElement(new InputSource(reader)); - } - finally { - if (reader != null) { - reader.close(); - } - } - } - } - - private static long lastLap = System.currentTimeMillis(); - - /** - * Function used for debugging purposes and performance bottlenecks detection. - * Probably of no use for end users of JRobin. - * - * @return String representing time in seconds since last - * <code>getLapTime()</code> method call. - */ - public static String getLapTime() { - final long newLap = System.currentTimeMillis(); - final double seconds = (newLap - lastLap) / 1000.0; - lastLap = newLap; - return "[" + seconds + " sec]"; - } - - /** - * Returns the root directory of the JRobin distribution. Useful in some demo applications, - * probably of no use anywhere else. - * <p> - * The function assumes that all JRobin .class files are placed under - * the <root>/classes subdirectory and that all jars (libraries) are placed in the - * <root>/lib subdirectory (the original JRobin directory structure). - * - * @return absolute path to JRobin's home directory - */ - public static String getJRobinHomeDirectory() { - final String className = Util.class.getName().replace('.', '/'); - String uri = Util.class.getResource("/" + className + ".class").toString(); - //System.out.println(uri); - if (uri.startsWith("file:/")) { - uri = uri.substring(6); - File file = new File(uri); - // let's go 5 steps backwards - for (int i = 0; i < 5; i++) { - file = file.getParentFile(); - } - uri = file.getAbsolutePath(); - } - else if (uri.startsWith("jar:file:/")) { - uri = uri.substring(9, uri.lastIndexOf('!')); - File file = new File(uri); - // let's go 2 steps backwards - for (int i = 0; i < 2; i++) { - file = file.getParentFile(); - } - uri = file.getAbsolutePath(); - } - else { - uri = null; - } - return uri; - } - - /** - * Compares two doubles but treats all NaNs as equal. - * In Java (by default) Double.NaN == Double.NaN always returns <code>false</code> - * - * @param x the first value - * @param y the second value - * @return <code>true</code> if x and y are both equal to Double.NaN, or if x == y. <code>false</code> otherwise - */ - public static boolean equal(final double x, final double y) { - return (Double.isNaN(x) && Double.isNaN(y)) || (x == y); - } - - /** - * Returns canonical file path for the given file path - * - * @param path Absolute or relative file path - * @return Canonical file path - * @throws IOException Thrown if canonical file path could not be resolved - */ - public static String getCanonicalPath(final String path) throws IOException { - return new File(path).getCanonicalPath(); - } - - /** - * Returns last modification time for the given file. - * - * @param file File object representing file on the disk - * @return Last modification time in seconds (without milliseconds) - */ - public static long getLastModified(final String file) { - return (new File(file).lastModified() + 500L) / 1000L; - } - - /** - * Checks if the file with the given file name exists - * - * @param filename File name - * @return <code>true</code> if file exists, <code>false</code> otherwise - */ - public static boolean fileExists(final String filename) { - return new File(filename).exists(); - } - - /** - * Finds max value for an array of doubles (NaNs are ignored). If all values in the array - * are NaNs, NaN is returned. - * - * @param values Array of double values - * @return max value in the array (NaNs are ignored) - */ - public static double max(final double[] values) { - double max = Double.NaN; - for (final double value : values) { - max = Util.max(max, value); - } - return max; - } - - /** - * Finds min value for an array of doubles (NaNs are ignored). If all values in the array - * are NaNs, NaN is returned. - * - * @param values Array of double values - * @return min value in the array (NaNs are ignored) - */ - public static double min(final double[] values) { - double min = Double.NaN; - for (final double value : values) { - min = Util.min(min, value); - } - return min; - } - - /** - * Equivalent of the C-style sprintf function. Sorry, it works only in Java5. - * - * @param format Format string - * @param args Arbitrary list of arguments - * @return Formatted string - */ - public static String sprintf(final String format, final Object ... args) { - final String fmt = format.replaceAll("([^%]|^)%([^a-zA-Z%]*)l(f|g|e)", "$1%$2$3"); - return String.format(fmt, args); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/XmlReader.java b/apps/jrobin/java/src/org/jrobin/core/XmlReader.java deleted file mode 100644 index c373287bb00d1b29a0889a54799e084315eb78d3..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/XmlReader.java +++ /dev/null @@ -1,132 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import org.w3c.dom.Element; -import org.w3c.dom.Node; - -import java.io.File; -import java.io.IOException; - -class XmlReader extends DataImporter { - - private Element root; - private Node[] dsNodes, arcNodes; - - XmlReader(String xmlFilePath) throws IOException, RrdException { - root = Util.Xml.getRootElement(new File(xmlFilePath)); - dsNodes = Util.Xml.getChildNodes(root, "ds"); - arcNodes = Util.Xml.getChildNodes(root, "rra"); - } - - String getVersion() throws RrdException { - return Util.Xml.getChildValue(root, "version"); - } - - long getLastUpdateTime() throws RrdException { - return Util.Xml.getChildValueAsLong(root, "lastupdate"); - } - - long getStep() throws RrdException { - return Util.Xml.getChildValueAsLong(root, "step"); - } - - int getDsCount() { - return dsNodes.length; - } - - int getArcCount() { - return arcNodes.length; - } - - String getDsName(int dsIndex) throws RrdException { - return Util.Xml.getChildValue(dsNodes[dsIndex], "name"); - } - - String getDsType(int dsIndex) throws RrdException { - return Util.Xml.getChildValue(dsNodes[dsIndex], "type"); - } - - long getHeartbeat(int dsIndex) throws RrdException { - return Util.Xml.getChildValueAsLong(dsNodes[dsIndex], "minimal_heartbeat"); - } - - double getMinValue(int dsIndex) throws RrdException { - return Util.Xml.getChildValueAsDouble(dsNodes[dsIndex], "min"); - } - - double getMaxValue(int dsIndex) throws RrdException { - return Util.Xml.getChildValueAsDouble(dsNodes[dsIndex], "max"); - } - - double getLastValue(int dsIndex) throws RrdException { - return Util.Xml.getChildValueAsDouble(dsNodes[dsIndex], "last_ds"); - } - - double getAccumValue(int dsIndex) throws RrdException { - return Util.Xml.getChildValueAsDouble(dsNodes[dsIndex], "value"); - } - - long getNanSeconds(int dsIndex) throws RrdException { - return Util.Xml.getChildValueAsLong(dsNodes[dsIndex], "unknown_sec"); - } - - String getConsolFun(int arcIndex) throws RrdException { - return Util.Xml.getChildValue(arcNodes[arcIndex], "cf"); - } - - double getXff(int arcIndex) throws RrdException { - return Util.Xml.getChildValueAsDouble(arcNodes[arcIndex], "xff"); - } - - int getSteps(int arcIndex) throws RrdException { - return Util.Xml.getChildValueAsInt(arcNodes[arcIndex], "pdp_per_row"); - } - - double getStateAccumValue(int arcIndex, int dsIndex) throws RrdException { - Node cdpNode = Util.Xml.getFirstChildNode(arcNodes[arcIndex], "cdp_prep"); - Node[] dsNodes = Util.Xml.getChildNodes(cdpNode, "ds"); - return Util.Xml.getChildValueAsDouble(dsNodes[dsIndex], "value"); - } - - int getStateNanSteps(int arcIndex, int dsIndex) throws RrdException { - Node cdpNode = Util.Xml.getFirstChildNode(arcNodes[arcIndex], "cdp_prep"); - Node[] dsNodes = Util.Xml.getChildNodes(cdpNode, "ds"); - return Util.Xml.getChildValueAsInt(dsNodes[dsIndex], "unknown_datapoints"); - } - - int getRows(int arcIndex) throws RrdException { - Node dbNode = Util.Xml.getFirstChildNode(arcNodes[arcIndex], "database"); - Node[] rows = Util.Xml.getChildNodes(dbNode, "row"); - return rows.length; - } - - double[] getValues(int arcIndex, int dsIndex) throws RrdException { - Node dbNode = Util.Xml.getFirstChildNode(arcNodes[arcIndex], "database"); - Node[] rows = Util.Xml.getChildNodes(dbNode, "row"); - double[] values = new double[rows.length]; - for (int i = 0; i < rows.length; i++) { - Node[] vNodes = Util.Xml.getChildNodes(rows[i], "v"); - Node vNode = vNodes[dsIndex]; - values[i] = Util.parseDouble(vNode.getFirstChild().getNodeValue().trim()); - } - return values; - } -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/core/XmlTemplate.java b/apps/jrobin/java/src/org/jrobin/core/XmlTemplate.java deleted file mode 100644 index 595bf68a284adf934986a99ffc3fe69e465a1071..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/XmlTemplate.java +++ /dev/null @@ -1,342 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.xml.sax.InputSource; - -import java.awt.*; -import java.io.File; -import java.io.IOException; -import java.util.*; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** - * Class used as a base class for various XML template related classes. Class provides - * methods for XML source parsing and XML tree traversing. XML source may have unlimited - * number of placeholders (variables) in the format <code>${variable_name}</code>. - * Methods are provided to specify variable values at runtime. - * Note that this class has limited functionality: XML source gets parsed, and variable - * values are collected. You have to extend this class to do something more useful.<p> - */ -public abstract class XmlTemplate { - private static final String PATTERN_STRING = "\\$\\{(\\w+)\\}"; - private static final Pattern PATTERN = Pattern.compile(PATTERN_STRING); - - protected Element root; - private HashMap<String, Object> valueMap = new HashMap<String, Object>(); - private HashSet<Node> validatedNodes = new HashSet<Node>(); - - protected XmlTemplate(InputSource xmlSource) throws IOException, RrdException { - root = Util.Xml.getRootElement(xmlSource); - } - - protected XmlTemplate(String xmlString) throws IOException, RrdException { - root = Util.Xml.getRootElement(xmlString); - } - - protected XmlTemplate(File xmlFile) throws IOException, RrdException { - root = Util.Xml.getRootElement(xmlFile); - } - - /** - * Removes all placeholder-value mappings. - */ - public void clearValues() { - valueMap.clear(); - } - - /** - * Sets value for a single XML template variable. Variable name should be specified - * without leading '${' and ending '}' placeholder markers. For example, for a placeholder - * <code>${start}</code>, specify <code>start</code> for the <code>name</code> parameter. - * - * @param name variable name - * @param value value to be set in the XML template - */ - public void setVariable(String name, String value) { - valueMap.put(name, value); - } - - /** - * Sets value for a single XML template variable. Variable name should be specified - * without leading '${' and ending '}' placeholder markers. For example, for a placeholder - * <code>${start}</code>, specify <code>start</code> for the <code>name</code> parameter. - * - * @param name variable name - * @param value value to be set in the XML template - */ - public void setVariable(String name, int value) { - valueMap.put(name, value); - } - - /** - * Sets value for a single XML template variable. Variable name should be specified - * without leading '${' and ending '}' placeholder markers. For example, for a placeholder - * <code>${start}</code>, specify <code>start</code> for the <code>name</code> parameter. - * - * @param name variable name - * @param value value to be set in the XML template - */ - public void setVariable(String name, long value) { - valueMap.put(name, value); - } - - /** - * Sets value for a single XML template variable. Variable name should be specified - * without leading '${' and ending '}' placeholder markers. For example, for a placeholder - * <code>${start}</code>, specify <code>start</code> for the <code>name</code> parameter. - * - * @param name variable name - * @param value value to be set in the XML template - */ - public void setVariable(String name, double value) { - valueMap.put(name, value); - } - - /** - * Sets value for a single XML template variable. Variable name should be specified - * without leading '${' and ending '}' placeholder markers. For example, for a placeholder - * <code>${start}</code>, specify <code>start</code> for the <code>name</code> parameter. - * - * @param name variable name - * @param value value to be set in the XML template - */ - public void setVariable(String name, Color value) { - String r = byteToHex(value.getRed()); - String g = byteToHex(value.getGreen()); - String b = byteToHex(value.getBlue()); - String a = byteToHex(value.getAlpha()); - valueMap.put(name, "#" + r + g + b + a); - } - - private String byteToHex(int i) { - String s = Integer.toHexString(i); - while (s.length() < 2) { - s = "0" + s; - } - return s; - } - - /** - * Sets value for a single XML template variable. Variable name should be specified - * without leading '${' and ending '}' placeholder markers. For example, for a placeholder - * <code>${start}</code>, specify <code>start</code> for the <code>name</code> parameter. - * - * @param name variable name - * @param value value to be set in the XML template - */ - public void setVariable(String name, Date value) { - setVariable(name, Util.getTimestamp(value)); - } - - /** - * Sets value for a single XML template variable. Variable name should be specified - * without leading '${' and ending '}' placeholder markers. For example, for a placeholder - * <code>${start}</code>, specify <code>start</code> for the <code>name</code> parameter. - * - * @param name variable name - * @param value value to be set in the XML template - */ - public void setVariable(String name, Calendar value) { - setVariable(name, Util.getTimestamp(value)); - } - - /** - * Sets value for a single XML template variable. Variable name should be specified - * without leading '${' and ending '}' placeholder markers. For example, for a placeholder - * <code>${start}</code>, specify <code>start</code> for the <code>name</code> parameter. - * - * @param name variable name - * @param value value to be set in the XML template - */ - public void setVariable(String name, boolean value) { - valueMap.put(name, "" + value); - } - - /** - * Searches the XML template to see if there are variables in there that - * will need to be set. - * - * @return True if variables were detected, false if not. - */ - public boolean hasVariables() { - return PATTERN.matcher(root.toString()).find(); - } - - /** - * Returns the list of variables that should be set in this template. - * - * @return List of variable names as an array of strings. - */ - public String[] getVariables() { - ArrayList<String> list = new ArrayList<String>(); - Matcher m = PATTERN.matcher(root.toString()); - - while (m.find()) { - String var = m.group(1); - if (!list.contains(var)) { - list.add(var); - } - } - - return list.toArray(new String[list.size()]); - } - - protected static Node[] getChildNodes(Node parentNode, String childName) { - return Util.Xml.getChildNodes(parentNode, childName); - } - - protected static Node[] getChildNodes(Node parentNode) { - return Util.Xml.getChildNodes(parentNode, null); - } - - protected static Node getFirstChildNode(Node parentNode, String childName) throws RrdException { - return Util.Xml.getFirstChildNode(parentNode, childName); - } - - protected boolean hasChildNode(Node parentNode, String childName) { - return Util.Xml.hasChildNode(parentNode, childName); - } - - protected String getChildValue(Node parentNode, String childName) throws RrdException { - return getChildValue(parentNode, childName, true); - } - - protected String getChildValue(Node parentNode, String childName, boolean trim) throws RrdException { - String value = Util.Xml.getChildValue(parentNode, childName, trim); - return resolveMappings(value); - } - - protected String getValue(Node parentNode) { - return getValue(parentNode, true); - } - - protected String getValue(Node parentNode, boolean trim) { - String value = Util.Xml.getValue(parentNode, trim); - return resolveMappings(value); - } - - private String resolveMappings(String templateValue) { - if (templateValue == null) { - return null; - } - Matcher matcher = PATTERN.matcher(templateValue); - StringBuffer result = new StringBuffer(); - int lastMatchEnd = 0; - while (matcher.find()) { - String var = matcher.group(1); - if (valueMap.containsKey(var)) { - // mapping found - result.append(templateValue.substring(lastMatchEnd, matcher.start())); - result.append(valueMap.get(var).toString()); - lastMatchEnd = matcher.end(); - } - else { - // no mapping found - this is illegal - // throw runtime exception - throw new IllegalArgumentException("No mapping found for template variable ${" + var + "}"); - } - } - result.append(templateValue.substring(lastMatchEnd)); - return result.toString(); - } - - protected int getChildValueAsInt(Node parentNode, String childName) throws RrdException { - String valueStr = getChildValue(parentNode, childName); - return Integer.parseInt(valueStr); - } - - protected int getValueAsInt(Node parentNode) { - String valueStr = getValue(parentNode); - return Integer.parseInt(valueStr); - } - - protected long getChildValueAsLong(Node parentNode, String childName) throws RrdException { - String valueStr = getChildValue(parentNode, childName); - return Long.parseLong(valueStr); - } - - protected long getValueAsLong(Node parentNode) { - String valueStr = getValue(parentNode); - return Long.parseLong(valueStr); - } - - protected double getChildValueAsDouble(Node parentNode, String childName) throws RrdException { - String valueStr = getChildValue(parentNode, childName); - return Util.parseDouble(valueStr); - } - - protected double getValueAsDouble(Node parentNode) { - String valueStr = getValue(parentNode); - return Util.parseDouble(valueStr); - } - - protected boolean getChildValueAsBoolean(Node parentNode, String childName) throws RrdException { - String valueStr = getChildValue(parentNode, childName); - return Util.parseBoolean(valueStr); - } - - protected boolean getValueAsBoolean(Node parentNode) { - String valueStr = getValue(parentNode); - return Util.parseBoolean(valueStr); - } - - protected Paint getValueAsColor(Node parentNode) throws RrdException { - String rgbStr = getValue(parentNode); - return Util.parseColor(rgbStr); - } - - protected boolean isEmptyNode(Node node) { - // comment node or empty text node - return node.getNodeName().equals("#comment") || - (node.getNodeName().equals("#text") && node.getNodeValue().trim().length() == 0); - } - - protected void validateTagsOnlyOnce(Node parentNode, String[] allowedChildNames) throws RrdException { - // validate node only once - if (validatedNodes.contains(parentNode)) { - return; - } - Node[] childs = getChildNodes(parentNode); - main: - for (Node child : childs) { - String childName = child.getNodeName(); - for (int j = 0; j < allowedChildNames.length; j++) { - if (allowedChildNames[j].equals(childName)) { - // only one such tag is allowed - allowedChildNames[j] = "<--removed-->"; - continue main; - } - else if (allowedChildNames[j].equals(childName + "*")) { - // several tags allowed - continue main; - } - } - if (!isEmptyNode(child)) { - throw new RrdException("Unexpected tag encountered: <" + childName + ">"); - } - } - // everything is OK - validatedNodes.add(parentNode); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/XmlWriter.java b/apps/jrobin/java/src/org/jrobin/core/XmlWriter.java deleted file mode 100644 index bda0ea080d0b6e5ef5b46b19d4ebb084ec3ae59d..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/XmlWriter.java +++ /dev/null @@ -1,205 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core; - -import java.awt.*; -import java.io.File; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.util.Stack; - -/** - * Extremely simple utility class used to create XML documents. - */ -public class XmlWriter { - static final String INDENT_STR = " "; - - private PrintWriter writer; - private StringBuffer indent = new StringBuffer(""); - private Stack<String> openTags = new Stack<String>(); - - /** - * Creates XmlWriter with the specified output stream to send XML code to. - * - * @param stream Output stream which receives XML code - */ - public XmlWriter(OutputStream stream) { - writer = new PrintWriter(stream, true); - } - - /** - * Opens XML tag - * - * @param tag XML tag name - */ - public void startTag(String tag) { - writer.println(indent + "<" + tag + ">"); - openTags.push(tag); - indent.append(INDENT_STR); - } - - /** - * Closes the corresponding XML tag - */ - public void closeTag() { - String tag = openTags.pop(); - indent.setLength(indent.length() - INDENT_STR.length()); - writer.println(indent + "</" + tag + ">"); - } - - /** - * Writes <tag>value</tag> to output stream - * - * @param tag XML tag name - * @param value value to be placed between <code><tag></code> and <code></tag></code> - */ - public void writeTag(String tag, Object value) { - if (value != null) { - writer.println(indent + "<" + tag + ">" + - escape(value.toString()) + "</" + tag + ">"); - } - else { - writer.println(indent + "<" + tag + "></" + tag + ">"); - } - } - - /** - * Writes <tag>value</tag> to output stream - * - * @param tag XML tag name - * @param value value to be placed between <code><tag></code> and <code></tag></code> - */ - public void writeTag(String tag, int value) { - writeTag(tag, "" + value); - } - - /** - * Writes <tag>value</tag> to output stream - * - * @param tag XML tag name - * @param value value to be placed between <code><tag></code> and <code></tag></code> - */ - public void writeTag(String tag, long value) { - writeTag(tag, "" + value); - } - - /** - * Writes <tag>value</tag> to output stream - * - * @param tag XML tag name - * @param value value to be placed between <code><tag></code> and <code></tag></code> - * @param nanString string to display if the value is NaN. - */ - public void writeTag(String tag, double value, String nanString) { - writeTag(tag, Util.formatDouble(value, nanString, true)); - } - - /** - * Writes <tag>value</tag> to output stream - * - * @param tag XML tag name - * @param value value to be placed between <code><tag></code> and <code></tag></code> - */ - public void writeTag(String tag, double value) { - writeTag(tag, Util.formatDouble(value, true)); - } - - /** - * Writes <tag>value</tag> to output stream - * - * @param tag XML tag name - * @param value value to be placed between <code><tag></code> and <code></tag></code> - */ - public void writeTag(String tag, boolean value) { - writeTag(tag, "" + value); - } - - /** - * Writes <tag>value</tag> to output stream - * - * @param tag XML tag name - * @param value value to be placed between <code><tag></code> and <code></tag></code> - */ - public void writeTag(String tag, Color value) { - int rgb = value.getRGB() & 0xFFFFFF; - writeTag(tag, "#" + Integer.toHexString(rgb).toUpperCase()); - } - - /** - * Writes <tag>value</tag> to output stream - * - * @param tag XML tag name - * @param value value to be placed between <code><tag></code> and <code></tag></code> - */ - public void writeTag(String tag, Font value) { - startTag(tag); - writeTag("name", value.getName()); - int style = value.getStyle(); - if ((style & Font.BOLD) != 0 && (style & Font.ITALIC) != 0) { - writeTag("style", "BOLDITALIC"); - } - else if ((style & Font.BOLD) != 0) { - writeTag("style", "BOLD"); - } - else if ((style & Font.ITALIC) != 0) { - writeTag("style", "ITALIC"); - } - else { - writeTag("style", "PLAIN"); - } - writeTag("size", value.getSize()); - closeTag(); - } - - /** - * Writes <tag>value</tag> to output stream - * - * @param tag XML tag name - * @param value value to be placed between <code><tag></code> and <code></tag></code> - */ - public void writeTag(String tag, File value) { - writeTag(tag, value.getPath()); - } - - /** - * Flushes the output stream - */ - public void flush() { - writer.flush(); - } - - protected void finalize() throws Throwable { - super.finalize(); - writer.close(); - } - - /** - * Writes XML comment to output stream - * - * @param comment comment string - */ - public void writeComment(Object comment) { - writer.println(indent + "<!-- " + escape(comment.toString()) + " -->"); - } - - private static String escape(String s) { - return s.replaceAll("<", "<").replaceAll(">", ">"); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/Archive.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/Archive.java deleted file mode 100644 index 92da227094f973b8759dc82c2dd8505c3f955ab1..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/Archive.java +++ /dev/null @@ -1,426 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -import java.io.IOException; -import java.io.PrintStream; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.Iterator; - -import org.jrobin.core.RrdException; - -/** - * Instances of this class model an archive section of an RRD file. - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class Archive { - - RRDatabase db; - long offset; - long dataOffset; - long size; - ConsolidationFunctionType type; - int rowCount; - int pdpCount; - double xff; - ArrayList<CDPStatusBlock> cdpStatusBlocks; - int currentRow; - - private double[][] values; - - Archive(RRDatabase db) throws IOException,RrdException { - - this.db = db; - - RRDFile file = db.rrdFile; - - offset = file.getFilePointer(); - type = - ConsolidationFunctionType.get(file.readString(Constants.CF_NAM_SIZE)); - rowCount = file.readInt(); - pdpCount = file.readInt(); - - file.align(); - - xff = file.readDouble(); - - // Skip rest of rra_def_t.par[] - file.align(); - file.skipBytes(72); - - size = file.getFilePointer() - offset; - } - - /** - * Returns the type of function used to calculate the consolidated data point. - * - * @return the type of function used to calculate the consolidated data point. - */ - public ConsolidationFunctionType getType() { - return type; - } - - void loadCDPStatusBlocks(RRDFile file, int numBlocks) throws IOException, RrdException { - - cdpStatusBlocks = new ArrayList<CDPStatusBlock>(); - - for (int i = 0; i < numBlocks; i++) { - cdpStatusBlocks.add(new CDPStatusBlock(file)); - } - } - - /** - * Returns the <code>CDPStatusBlock</code> at the specified position in this archive. - * - * @param index index of <code>CDPStatusBlock</code> to return. - * @return the <code>CDPStatusBlock</code> at the specified position in this archive. - */ - public CDPStatusBlock getCDPStatusBlock(int index) { - return cdpStatusBlocks.get(index); - } - - /** - * Returns an iterator over the CDP status blocks in this archive in proper sequence. - * - * @return an iterator over the CDP status blocks in this archive in proper sequence. - * @see CDPStatusBlock - */ - public Iterator<CDPStatusBlock> getCDPStatusBlocks() { - return cdpStatusBlocks.iterator(); - } - - void loadCurrentRow(RRDFile file) throws IOException,RrdException { - currentRow = file.readInt(); - } - - void loadData(RRDFile file, int dsCount) throws IOException { - - dataOffset = file.getFilePointer(); - - // Skip over the data to position ourselves at the start of the next archive - file.skipBytes(8 * rowCount * dsCount); - } - - DataChunk loadData(DataChunk chunk) throws IOException,RrdException { - - Calendar end = Calendar.getInstance(); - Calendar start = (Calendar) end.clone(); - - start.add(Calendar.DATE, -1); - - loadData(chunk, start.getTime().getTime() / 1000, - end.getTime().getTime() / 1000); - return chunk; - } - - void loadData(DataChunk chunk, long startTime, long endTime) - throws IOException,RrdException { - - long pointer; - - if (chunk.start < 0) { - pointer = currentRow + 1; - } - else { - pointer = currentRow + chunk.start + 1; - } - - db.rrdFile.ras.seek(dataOffset + (pointer * 8)); - //cat.debug("Archive Base: " + dataOffset + " Archive Pointer: " + pointer); - //cat.debug("Start Offset: " + chunk.start + " End Offset: " - // + (rowCount - chunk.end)); - - double[][] data = chunk.data; - - /* - * This is also terrible - cleanup - CT - */ - int row = 0; - for (int i = chunk.start; i < rowCount - chunk.end; i++, row++) { - if (i < 0) { // no valid data yet - for (int ii = 0; ii < chunk.dsCount; ii++) { - data[row][ii] = Double.NaN; - } - } - else if (i >= rowCount) { // past valid data area - for (int ii = 0; ii < chunk.dsCount; ii++) { - data[row][ii] = Double.NaN; - } - } - else { // inside the valid are but the pointer has to be wrapped - if (pointer >= rowCount) { - pointer -= rowCount; - - db.rrdFile.ras.seek(dataOffset + (pointer * 8)); - } - - for (int ii = 0; ii < chunk.dsCount; ii++) { - data[row][ii] = db.rrdFile.readDouble(); - } - - pointer++; - } - } - } - - void printInfo(PrintStream s, NumberFormat numberFormat, int index) { - - StringBuffer sb = new StringBuffer("rra["); - - sb.append(index); - s.print(sb); - s.print("].cf = \""); - s.print(type); - s.println("\""); - s.print(sb); - s.print("].rows = "); - s.println(rowCount); - s.print(sb); - s.print("].pdp_per_row = "); - s.println(pdpCount); - s.print(sb); - s.print("].xff = "); - s.println(xff); - sb.append("].cdp_prep["); - - int cdpIndex = 0; - - for (Iterator<CDPStatusBlock> i = cdpStatusBlocks.iterator(); i.hasNext();) { - CDPStatusBlock cdp = i.next(); - - s.print(sb); - s.print(cdpIndex); - s.print("].value = "); - - double value = cdp.value; - - s.println(Double.isNaN(value) - ? "NaN" - : numberFormat.format(value)); - s.print(sb); - s.print(cdpIndex++); - s.print("].unknown_datapoints = "); - s.println(cdp.unknownDatapoints); - } - } - - void toXml(PrintStream s) throws RrdException { - - try { - s.println("\t<rra>"); - s.print("\t\t<cf> "); - s.print(type); - s.println(" </cf>"); - s.print("\t\t<pdp_per_row> "); - s.print(pdpCount); - s.print(" </pdp_per_row> <!-- "); - s.print(db.header.pdpStep * pdpCount); - s.println(" seconds -->"); - s.print("\t\t<xff> "); - s.print(xff); - s.println(" </xff>"); - s.println(); - s.println("\t\t<cdp_prep>"); - - for (int i = 0; i < cdpStatusBlocks.size(); i++) { - cdpStatusBlocks.get(i).toXml(s); - } - - s.println("\t\t</cdp_prep>"); - s.println("\t\t<database>"); - - long timer = -(rowCount - 1); - int counter = 0; - int row = currentRow; - - db.rrdFile.ras.seek(dataOffset + (row + 1) * 16); - - long lastUpdate = db.lastUpdate.getTime() / 1000; - int pdpStep = db.header.pdpStep; - NumberFormat numberFormat = new DecimalFormat("0.0000000000E0"); - SimpleDateFormat dateFormat = - new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); - - while (counter++ < rowCount) { - row++; - - if (row == rowCount) { - row = 0; - - db.rrdFile.ras.seek(dataOffset); - } - - long now = (lastUpdate - lastUpdate % (pdpCount * pdpStep)) - + (timer * pdpCount * pdpStep); - - timer++; - - s.print("\t\t\t<!-- "); - s.print(dateFormat.format(new Date(now * 1000))); - s.print(" / "); - s.print(now); - s.print(" --> "); - - for (int col = 0; col < db.header.dsCount; col++) { - s.print("<v> "); - - double value = db.rrdFile.readDouble(); - - // NumberFormat doesn't know how to handle NaN - if (Double.isNaN(value)) { - s.print("NaN"); - } - else { - s.print(numberFormat.format(value)); - } - - s.print(" </v>"); - } - - s.println("</row>"); - } - - s.println("\t\t</database>"); - s.println("\t</rra>"); - } - catch (IOException e) { // Is the best thing to do here? - throw new RuntimeException(e.getMessage()); - } - } - - /* - // THIS IS THE ORIGINAL CODE: BUGGY! Replaced by Sasa Markovic with a new method - // Funny: the bug will appear only if dsCount != 2 :) - public double[][] getValuesOriginal() throws IOException { - if (values != null) { - return values; - } - values = new double[db.header.dsCount][rowCount]; - int row = currentRow; - db.rrdFile.ras.seek(dataOffset + (row + 1) * 16); // <----- BUG (resolved below) - for (int counter = 0; counter < rowCount; counter++) { - row++; - if (row == rowCount) { - row = 0; - db.rrdFile.ras.seek(dataOffset); - } - for (int col = 0; col < db.header.dsCount; col++) { - double value = db.rrdFile.readDouble(); - values[col][counter] = value; - } - } - return values; - } - */ - - // Resolved bug from the original method (see above) - public double[][] getValues() throws IOException,RrdException { - // OK PART - if (values != null) { - return values; - } - values = new double[db.header.dsCount][rowCount]; - int row = currentRow; - // HERE ARE THE DRAGONS! - db.rrdFile.ras.seek(dataOffset + (row + 1) * db.header.dsCount * 8); - // OK, TOO! - for (int counter = 0; counter < rowCount; counter++) { - row++; - if (row == rowCount) { - row = 0; - db.rrdFile.ras.seek(dataOffset); - } - for (int col = 0; col < db.header.dsCount; col++) { - double value = db.rrdFile.readDouble(); - values[col][counter] = value; - } - } - return values; - } - - /** - * Returns the number of primary data points required for a consolidated - * data point in this archive. - * - * @return the number of primary data points required for a consolidated - * data point in this archive. - */ - public int getPdpCount() { - return pdpCount; - } - - /** - * Returns the number of entries in this archive. - * - * @return the number of entries in this archive. - */ - public int getRowCount() { - return rowCount; - } - - /** - * Returns the X-Files Factor for this archive. - * - * @return the X-Files Factor for this archive. - */ - public double getXff() { - return xff; - } - - /** - * Returns a summary the contents of this archive. - * - * @return a summary of the information contained in this archive. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("[Archive: OFFSET=0x"); - - sb.append(Long.toHexString(offset)); - sb.append(", SIZE=0x"); - sb.append(Long.toHexString(size)); - sb.append(", type="); - sb.append(type); - sb.append(", rowCount="); - sb.append(rowCount); - sb.append(", pdpCount="); - sb.append(pdpCount); - sb.append(", xff="); - sb.append(xff); - sb.append(", currentRow="); - sb.append(currentRow); - sb.append("]"); - - for (Iterator<CDPStatusBlock> i = cdpStatusBlocks.iterator(); i.hasNext();) { - CDPStatusBlock cdp = i.next(); - - sb.append("\n\t\t"); - sb.append(cdp.toString()); - } - - return sb.toString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/CDPStatusBlock.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/CDPStatusBlock.java deleted file mode 100644 index f46ab808af3ce4dda8a0600e86fda311a4769f87..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/CDPStatusBlock.java +++ /dev/null @@ -1,98 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -import java.io.IOException; -import java.io.PrintStream; - -import org.jrobin.core.RrdException; - -/** - * Instances of this class model the consolidation data point status from an RRD file. - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class CDPStatusBlock { - - long offset; - long size; - int unknownDatapoints; - double value; - - CDPStatusBlock(RRDFile file) throws IOException, RrdException { - - offset = file.getFilePointer(); - value = file.readDouble(); - unknownDatapoints = file.readInt(); - file.align(8); - // Skip rest of cdp_prep_t.scratch - file.skipBytes(64); - - size = file.getFilePointer() - offset; - } - - /** - * Returns the number of unknown primary data points that were integrated. - * - * @return the number of unknown primary data points that were integrated. - */ - public int getUnknownDatapoints() { - return unknownDatapoints; - } - - /** - * Returns the value of this consolidated data point. - * - * @return the value of this consolidated data point. - */ - public double getValue() { - return value; - } - - void toXml(PrintStream s) { - - s.print("\t\t\t<ds><value> "); - s.print(value); - s.print(" </value> <unknown_datapoints> "); - s.print(unknownDatapoints); - s.println(" </unknown_datapoints></ds>"); - } - - /** - * Returns a summary the contents of this CDP status block. - * - * @return a summary of the information contained in the CDP status block. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("[CDPStatusBlock: OFFSET=0x"); - - sb.append(Long.toHexString(offset)); - sb.append(", SIZE=0x"); - sb.append(Long.toHexString(size)); - sb.append(", unknownDatapoints="); - sb.append(unknownDatapoints); - sb.append(", value="); - sb.append(value); - sb.append("]"); - - return sb.toString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/ConsolidationFunctionType.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/ConsolidationFunctionType.java deleted file mode 100644 index e5f98da739a4e3cd6ca84b3b2084de1d0c15fb82..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/ConsolidationFunctionType.java +++ /dev/null @@ -1,142 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -/** - * Class ConsolidationFunctionType - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class ConsolidationFunctionType { - - private static final int _AVERAGE = 0; - private static final String STR_AVERAGE = "AVERAGE"; - - /** - * Field AVERAGE - */ - public static final ConsolidationFunctionType AVERAGE = new ConsolidationFunctionType(_AVERAGE); - private static final int _MIN = 1; - private static final String STR_MIN = "MIN"; - - /** - * Field MIN - */ - public static final ConsolidationFunctionType MIN = new ConsolidationFunctionType(_MIN); - private static final int _MAX = 2; - private static final String STR_MAX = "MAX"; - - /** - * Field MAX - */ - public static final ConsolidationFunctionType MAX = new ConsolidationFunctionType(_MAX); - private static final int _LAST = 3; - private static final String STR_LAST = "LAST"; - - /** - * Field LAST - */ - public static final ConsolidationFunctionType LAST = new ConsolidationFunctionType(_LAST); - private int type; - - private ConsolidationFunctionType(int type) { - this.type = type; - } - - /** - * Returns a <code>ConsolidationFunctionType</code> with the given name. - * - * @param s name of the <code>ConsolidationFunctionType</code> required. - * @return a <code>ConsolidationFunctionType</code> with the given name. - */ - public static ConsolidationFunctionType get(final String s) { - - if (STR_AVERAGE.equalsIgnoreCase(s)) { - return AVERAGE; - } - else if (STR_MIN.equalsIgnoreCase(s)) { - return MIN; - } - else if (STR_MAX.equalsIgnoreCase(s)) { - return MAX; - } - else if (STR_LAST.equalsIgnoreCase(s)) { - return LAST; - } - else { - throw new IllegalArgumentException("Invalid ConsolidationFunctionType: " + s); - } - } - - /** - * Compares this object against the specified object. - * - * @return <code>true</code> if the objects are the same, - * <code>false</code> otherwise. - */ - public boolean equals(final Object o) { - - if (!(o instanceof ConsolidationFunctionType)) { - throw new IllegalArgumentException("Not a ConsolidationFunctionType"); - } - - return (((ConsolidationFunctionType) o).type == type) - ? true - : false; - } - - public int hashCode() { - return type * 93; - } - - /** - * Returns a string representation of this object. - * - * @return a string representation of this object. - */ - public String toString() { - - String strType; - - switch (type) { - - case _AVERAGE: - strType = STR_AVERAGE; - break; - - case _MIN: - strType = STR_MIN; - break; - - case _MAX: - strType = STR_MAX; - break; - - case _LAST: - strType = STR_LAST; - break; - - default : - throw new RuntimeException("This should never happen"); - } - - return strType; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/Constants.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/Constants.java deleted file mode 100644 index c7f6ca3a531950c5759d80c6b923fcfe75a98337..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/Constants.java +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -interface Constants { - - int DS_NAM_SIZE = 20; - int DST_SIZE = 20; - int CF_NAM_SIZE = 20; - int LAST_DS_LEN = 30; - static String COOKIE = "RRD"; - static String VERSION = "0001"; - static String VERSION3 = "0003"; - double FLOAT_COOKIE = 8.642135E130; - static byte[] FLOAT_COOKIE_BIG_ENDIAN = {0x5B, 0x1F, 0x2B, 0x43, - (byte) 0xC7, (byte) 0xC0, 0x25, - 0x2F}; - static byte[] FLOAT_COOKIE_LITTLE_ENDIAN = {0x2F, 0x25, (byte) 0xC0, - (byte) 0xC7, 0x43, 0x2B, 0x1F, - 0x5B}; -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/DataChunk.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/DataChunk.java deleted file mode 100644 index 48b5a6aa6737bf7a0dcecdabe78692e6a1102749..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/DataChunk.java +++ /dev/null @@ -1,74 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -/** - * Models a chunk of result data from an RRDatabase. - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class DataChunk { - - private static final String NEWLINE = System.getProperty("line.separator"); - long startTime; - int start; - int end; - long step; - int dsCount; - double[][] data; - int rows; - - DataChunk(long startTime, int start, int end, long step, int dsCount, int rows) { - this.startTime = startTime; - this.start = start; - this.end = end; - this.step = step; - this.dsCount = dsCount; - this.rows = rows; - data = new double[rows][dsCount]; - } - - /** - * Returns a summary of the contents of this data chunk. The first column is - * the time (RRD format) and the following columns are the data source - * values. - * - * @return a summary of the contents of this data chunk. - */ - public String toString() { - - StringBuffer sb = new StringBuffer(); - long time = startTime; - - for (int row = 0; row < rows; row++, time += step) { - sb.append(time); - sb.append(": "); - - for (int ds = 0; ds < dsCount; ds++) { - sb.append(data[row][ds]); - sb.append(" "); - } - - sb.append(NEWLINE); - } - - return sb.toString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/DataSource.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/DataSource.java deleted file mode 100644 index ac90eca33105d8006e4c3a2513ecc1e9c8c18dc5..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/DataSource.java +++ /dev/null @@ -1,224 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -import java.io.IOException; -import java.io.PrintStream; -import java.text.NumberFormat; - -import org.jrobin.core.RrdException; - -/** - * Instances of this class model a data source in an RRD file. - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class DataSource { - - long offset; - long size; - String name; - DataSourceType type; - int minimumHeartbeat; - double minimum; - double maximum; - PDPStatusBlock pdpStatusBlock; - - DataSource(RRDFile file) throws IOException,RrdException { - - offset = file.getFilePointer(); - name = file.readString(Constants.DS_NAM_SIZE); - type = DataSourceType.get(file.readString(Constants.DST_SIZE)); - - file.align(8); - - minimumHeartbeat = file.readInt(true); - - file.align(8); - - minimum = file.readDouble(); - maximum = file.readDouble(); - - // Skip rest of ds_def_t.par[] - file.align(); - file.skipBytes(56); - - size = file.getFilePointer() - offset; - } - - void loadPDPStatusBlock(RRDFile file) throws IOException,RrdException { - pdpStatusBlock = new PDPStatusBlock(file); - } - - /** - * Returns the primary data point status block for this data source. - * - * @return the primary data point status block for this data source. - */ - public PDPStatusBlock getPDPStatusBlock() { - return pdpStatusBlock; - } - - /** - * Returns the minimum required heartbeat for this data source. - * - * @return the minimum required heartbeat for this data source. - */ - public int getMinimumHeartbeat() { - return minimumHeartbeat; - } - - /** - * Returns the minimum value input to this data source can have. - * - * @return the minimum value input to this data source can have. - */ - public double getMinimum() { - return minimum; - } - - /** - * Returns the type this data source is. - * - * @return the type this data source is. - * @see DataSourceType - */ - public DataSourceType getType() { - return type; - } - - /** - * Returns the maximum value input to this data source can have. - * - * @return the maximum value input to this data source can have. - */ - public double getMaximum() { - return maximum; - } - - /** - * Returns the name of this data source. - * - * @return the name of this data source. - */ - public String getName() { - return name; - } - - void printInfo(PrintStream s, NumberFormat numberFormat) { - - StringBuffer sb = new StringBuffer("ds["); - - sb.append(name); - s.print(sb); - s.print("].type = \""); - s.print(type); - s.println("\""); - s.print(sb); - s.print("].minimal_heartbeat = "); - s.println(minimumHeartbeat); - s.print(sb); - s.print("].min = "); - s.println(Double.isNaN(minimum) - ? "NaN" - : numberFormat.format(minimum)); - s.print(sb); - s.print("].max = "); - s.println(Double.isNaN(maximum) - ? "NaN" - : numberFormat.format(maximum)); - s.print(sb); - s.print("].last_ds = "); - s.println(pdpStatusBlock.lastReading); - s.print(sb); - s.print("].value = "); - - double value = pdpStatusBlock.value; - - s.println(Double.isNaN(value) - ? "NaN" - : numberFormat.format(value)); - s.print(sb); - s.print("].unknown_sec = "); - s.println(pdpStatusBlock.unknownSeconds); - } - - void toXml(PrintStream s) { - - s.println("\t<ds>"); - s.print("\t\t<name> "); - s.print(name); - s.println(" </name>"); - s.print("\t\t<type> "); - s.print(type); - s.println(" </type>"); - s.print("\t\t<minimal_heartbeat> "); - s.print(minimumHeartbeat); - s.println(" </minimal_heartbeat>"); - s.print("\t\t<min> "); - s.print(minimum); - s.println(" </min>"); - s.print("\t\t<max> "); - s.print(maximum); - s.println(" </max>"); - s.println(); - s.println("\t\t<!-- PDP Status -->"); - s.print("\t\t<last_ds> "); - s.print(pdpStatusBlock.lastReading); - s.println(" </last_ds>"); - s.print("\t\t<value> "); - s.print(pdpStatusBlock.value); - s.println(" </value>"); - s.print("\t\t<unknown_sec> "); - s.print(pdpStatusBlock.unknownSeconds); - s.println(" </unknown_sec>"); - s.println("\t</ds>"); - s.println(); - } - - /** - * Returns a summary the contents of this data source. - * - * @return a summary of the information contained in this data source. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("[DataSource: OFFSET=0x"); - - sb.append(Long.toHexString(offset)); - sb.append(", SIZE=0x"); - sb.append(Long.toHexString(size)); - sb.append(", name="); - sb.append(name); - sb.append(", type="); - sb.append(type.toString()); - sb.append(", minHeartbeat="); - sb.append(minimumHeartbeat); - sb.append(", min="); - sb.append(minimum); - sb.append(", max="); - sb.append(maximum); - sb.append("]"); - sb.append("\n\t\t"); - sb.append(pdpStatusBlock.toString()); - - return sb.toString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/DataSourceType.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/DataSourceType.java deleted file mode 100644 index 336e115b81bfa1779e4cd0d7bef1e1c6e6d5d101..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/DataSourceType.java +++ /dev/null @@ -1,143 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -/** - * Class DataSourceType - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class DataSourceType { - - private static final int _COUNTER = 0; - private static final String STR_COUNTER = "COUNTER"; - - /** - * Field COUNTER - */ - public static final DataSourceType COUNTER = new DataSourceType(_COUNTER); - private static final int _ABSOLUTE = 1; - private static final String STR_ABSOLUTE = "ABSOLUTE"; - - /** - * Field ABSOLUTE - */ - public static final DataSourceType ABSOLUTE = new DataSourceType(_ABSOLUTE); - private static final int _GAUGE = 2; - private static final String STR_GAUGE = "GAUGE"; - - /** - * Field GAUGE - */ - public static final DataSourceType GAUGE = new DataSourceType(_GAUGE); - private static final int _DERIVE = 3; - private static final String STR_DERIVE = "DERIVE"; - - /** - * Field DERIVE - */ - public static final DataSourceType DERIVE = new DataSourceType(_DERIVE); - private int type; - - private DataSourceType(final int type) { - this.type = type; - } - - /** - * Returns a <code>DataSourceType</code> with the given name. - * - * @param s name of the <code>DataSourceType</code> required. - * @return a <code>DataSourceType</code> with the given name. - */ - public static DataSourceType get(final String s) { - - if (STR_COUNTER.equalsIgnoreCase(s)) { - return COUNTER; - } - else if (STR_ABSOLUTE.equalsIgnoreCase(s)) { - return ABSOLUTE; - } - else if (STR_GAUGE.equalsIgnoreCase(s)) { - return GAUGE; - } - else if (STR_DERIVE.equalsIgnoreCase(s)) { - return DERIVE; - } - else { - throw new IllegalArgumentException("Invalid DataSourceType"); - } - } - - /** - * Compares this object against the specified object. - * - * @return <code>true</code> if the objects are the same, - * <code>false</code> otherwise. - */ - public boolean equals(final Object obj) { - - if (!(obj instanceof DataSourceType)) { - throw new IllegalArgumentException("Not a DataSourceType"); - } - - return (((DataSourceType) obj).type == type) - ? true - : false; - } - - public int hashCode() { - return type * 37; - } - - /** - * Returns a string representation of this object. - * - * @return a string representation of this object. - */ - public String toString() { - - String strType; - - switch (type) { - - case _COUNTER: - strType = STR_COUNTER; - break; - - case _ABSOLUTE: - strType = STR_ABSOLUTE; - break; - - case _GAUGE: - strType = STR_GAUGE; - break; - - case _DERIVE: - strType = STR_DERIVE; - break; - - default : - // Don't you just hate it when you see a line like this? - throw new RuntimeException("This should never happen"); - } - - return strType; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/Header.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/Header.java deleted file mode 100644 index c301e3acebcf6fdaef437a0b133f3974b50f235d..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/Header.java +++ /dev/null @@ -1,131 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -import java.io.IOException; - -import org.jrobin.core.RrdException; - -/** - * Instances of this class model the header section of an RRD file. - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class Header implements Constants { - - static final long offset = 0; - long size; - String version; - int intVersion; - int dsCount; - int rraCount; - int pdpStep; - - Header(RRDFile file) throws IOException,RrdException { - - if (!file.readString(4).equals(COOKIE)) { - throw new IOException("Invalid COOKIE"); - } - - version = file.readString(5); - intVersion = Integer.parseInt(version); - if( intVersion > 3 ) { - throw new IOException("Unsupported RRD version (" + version + ")"); - } - - file.align(); - - // Consume the FLOAT_COOKIE - file.readDouble(); - - dsCount = file.readInt(); - rraCount = file.readInt(); - pdpStep = file.readInt(); - - // Skip rest of stat_head_t.par - file.align(); - file.skipBytes(80); - - size = file.getFilePointer() - offset; - } - - /** - * Returns the version of the database. - * - * @return the version of the database. - */ - public String getVersion() { - return version; - } - - public int getIntVersion() { - return intVersion; - } - - /** - * Returns the number of <code>DataSource</code>s in the database. - * - * @return the number of <code>DataSource</code>s in the database. - */ - public int getDSCount() { - return dsCount; - } - - /** - * Returns the number of <code>Archive</code>s in the database. - * - * @return the number of <code>Archive</code>s in the database. - */ - public int getRRACount() { - return rraCount; - } - - /** - * Returns the primary data point interval in seconds. - * - * @return the primary data point interval in seconds. - */ - public int getPDPStep() { - return pdpStep; - } - - /** - * Returns a summary the contents of this header. - * - * @return a summary of the information contained in this header. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("[Header: OFFSET=0x00, SIZE=0x"); - - sb.append(Long.toHexString(size)); - sb.append(", version="); - sb.append(version); - sb.append(", dsCount="); - sb.append(dsCount); - sb.append(", rraCount="); - sb.append(rraCount); - sb.append(", pdpStep="); - sb.append(pdpStep); - sb.append("]"); - - return sb.toString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/Main.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/Main.java deleted file mode 100644 index c7f17b7a8983cc8e9cdd2fad7df425fac505f1ac..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/Main.java +++ /dev/null @@ -1,76 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -import java.io.IOException; - -import org.jrobin.core.RrdException; - -/** - * Show some of the things jRRD can do. - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class Main { - - public Main(String rrdFile) { - - RRDatabase rrd = null; - DataChunk chunk = null; - - try { - rrd = new RRDatabase(rrdFile); - chunk = rrd.getData(ConsolidationFunctionType.AVERAGE); - } catch (Exception e) { - e.printStackTrace(); - - return; - } - - try { - rrd.toXml(System.out); - } catch (RrdException e) { - e.printStackTrace(); - return; - } - // Dump the database as XML. - rrd.printInfo(System.out); // Dump the database header information. - System.out.println(rrd); // Dump a summary of the contents of the database. - System.out.println(chunk); // Dump the chunk. - - try { - rrd.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - static void usage(int status) { - System.err.println("Usage: " + Main.class.getName() + " rrdfile"); - System.exit(status); - } - - public static void main(String[] args) { - if (args.length != 1) { - usage(1); - } - new Main(args[0]); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/PDPStatusBlock.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/PDPStatusBlock.java deleted file mode 100644 index 449897bf67d43d8b0f35f42672991589c771a9b6..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/PDPStatusBlock.java +++ /dev/null @@ -1,108 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -import java.io.IOException; - -import org.jrobin.core.RrdException; - -/** - * Instances of this class model the primary data point status from an RRD file. - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class PDPStatusBlock { - - long offset; - long size; - String lastReading; - int unknownSeconds; - double value; - - PDPStatusBlock(RRDFile file) throws IOException,RrdException { - - offset = file.getFilePointer(); - lastReading = file.readString(Constants.LAST_DS_LEN); - - file.align(4); - - unknownSeconds = file.readInt(); - - file.align(8); //8 bytes per scratch value in pdp_prep; align on that - - value = file.readDouble(); - - // Skip rest of pdp_prep_t.par[] - file.skipBytes(64); - - size = file.getFilePointer() - offset; - } - - /** - * Returns the last reading from the data source. - * - * @return the last reading from the data source. - */ - public String getLastReading() { - return lastReading; - } - - /** - * Returns the current value of the primary data point. - * - * @return the current value of the primary data point. - */ - public double getValue() { - return value; - } - - /** - * Returns the number of seconds of the current primary data point is - * unknown data. - * - * @return the number of seconds of the current primary data point is unknown data. - */ - public int getUnknownSeconds() { - return unknownSeconds; - } - - /** - * Returns a summary the contents of this PDP status block. - * - * @return a summary of the information contained in this PDP status block. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("[PDPStatus: OFFSET=0x"); - - sb.append(Long.toHexString(offset)); - sb.append(", SIZE=0x"); - sb.append(Long.toHexString(size)); - sb.append(", lastReading="); - sb.append(lastReading); - sb.append(", unknownSeconds="); - sb.append(unknownSeconds); - sb.append(", value="); - sb.append(value); - sb.append("]"); - - return sb.toString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDFile.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDFile.java deleted file mode 100644 index 7badf305e21282dce4b605d424958dc132895e61..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDFile.java +++ /dev/null @@ -1,245 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -import java.io.ByteArrayInputStream; -import java.io.DataInputStream; -import java.io.File; -import java.io.IOException; -import java.io.RandomAccessFile; - -import org.jrobin.core.RrdException; - -/** - * This class is a quick hack to read information from an RRD file. Writing - * to RRD files is not currently supported. As I said, this is a quick hack. - * Some thought should be put into the overall design of the file IO. - * <p> - * Currently this can read RRD files that were generated on Solaris (Sparc) - * and Linux (x86). - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class RRDFile implements Constants { - - boolean bigEndian; - boolean debug; - int alignment; - RandomAccessFile ras; - byte[] buffer; - - RRDFile(String name) throws IOException, RrdException { - this(new File(name)); - } - - RRDFile(File file) throws IOException, RrdException { - - ras = new RandomAccessFile(file, "r"); - buffer = new byte[128]; - - this.debug = false; - initDataLayout(file); - } - - private void initDataLayout(File file) throws IOException, RrdException { - - if (file.exists()) { // Load the data formats from the file - int bytes = ras.read(buffer, 0, 24); - if (bytes < 24) { - throw new RrdException("Invalid RRD file"); - } - - int index; - - if ((index = indexOf(FLOAT_COOKIE_BIG_ENDIAN, buffer)) != -1) { - bigEndian = true; - } - else if ((index = indexOf(FLOAT_COOKIE_LITTLE_ENDIAN, buffer)) - != -1) { - bigEndian = false; - } - else { - throw new RrdException("Invalid RRD file"); - } - - switch (index) { - - case 12: - alignment = 4; - break; - - case 16: - alignment = 8; - break; - - default : - throw new RuntimeException("Unsupported architecture - neither 32-bit nor 64-bit, or maybe the file is corrupt"); - } - } - else { // Default to data formats for this hardware architecture - } - - ras.seek(0); // Reset file pointer to start of file - } - - private int indexOf(byte[] pattern, byte[] array) { - return (new String(array)).indexOf(new String(pattern)); - } - - boolean isBigEndian() { - return bigEndian; - } - - int getAlignment() { - return alignment; - } - - double readDouble() throws IOException, RrdException { - if(debug) { - System.out.print("Read 8 bytes (Double) from offset "+ras.getFilePointer()+":"); - } - - //double value; - byte[] tx = new byte[8]; - - if(ras.read(buffer, 0, 8) != 8) { - throw new RrdException("Invalid RRD file"); - } - - if (bigEndian) { - tx = buffer; - } - else { - for (int i = 0; i < 8; i++) { - tx[7 - i] = buffer[i]; - } - } - - DataInputStream reverseDis = - new DataInputStream(new ByteArrayInputStream(tx)); - - Double result = reverseDis.readDouble(); - if(this.debug) { - System.out.println(result); - } - return result; - } - - int readInt() throws IOException, RrdException { - return readInt(false); - } - - /** - * Reads the next integer (4 or 8 bytes depending on alignment), advancing the file pointer - * and returns it - * If the alignment is 8-bytes (64-bit), then 8 bytes are read, but only the lower 4-bytes (32-bits) are - * returned. The upper 4 bytes are ignored. - * - * @return the 32-bit integer read from the file - * @throws IOException - A file access error - * @throws RrdException - Not enough bytes were left in the file to read the integer. - */ - int readInt(boolean dump) throws IOException, RrdException { - //An integer is "alignment" bytes long - 4 bytes on 32-bit, 8 on 64-bit. - if(this.debug) { - System.out.print("Read "+alignment+" bytes (int) from offset "+ras.getFilePointer()+":"); - } - - if(ras.read(buffer, 0, alignment) != alignment) { - throw new RrdException("Invalid RRD file"); - } - - int value; - - if (bigEndian) { - if(alignment == 8) { - //For big-endian, the low 4-bytes of the 64-bit integer are the last 4 bytes - value = (0xFF & buffer[7]) | ((0xFF & buffer[6]) << 8) - | ((0xFF & buffer[5]) << 16) | ((0xFF & buffer[4]) << 24); - } else { - value = (0xFF & buffer[3]) | ((0xFF & buffer[2]) << 8) - | ((0xFF & buffer[1]) << 16) | ((0xFF & buffer[0]) << 24); - } - } - else { - //For little-endian, there's no difference between 4 and 8 byte alignment. - // The first 4 bytes are the low end of a 64-bit number - value = (0xFF & buffer[0]) | ((0xFF & buffer[1]) << 8) - | ((0xFF & buffer[2]) << 16) | ((0xFF & buffer[3]) << 24); - } - - if(this.debug) { - System.out.println(value); - } - return value; - } - - String readString(int maxLength) throws IOException, RrdException { - if(this.debug) { - System.out.print("Read "+maxLength+" bytes (string) from offset "+ras.getFilePointer()+":"); - } - maxLength = ras.read(buffer, 0, maxLength); - if(maxLength == -1) { - throw new RrdException("Invalid RRD file"); - } - - String result = new String(buffer, 0, maxLength).trim(); - if(this.debug) { - System.out.println( result +":"); - } - return result; - } - - void skipBytes(final int n) throws IOException { - int bytesSkipped = ras.skipBytes(n); - if(this.debug) { - System.out.println("Skipping "+bytesSkipped+" bytes"); - } - } - - int align(int boundary) throws IOException { - - int skip = (int) (boundary - (ras.getFilePointer() % boundary)) % boundary; - - if (skip != 0) { - skip = ras.skipBytes(skip); - } - if(this.debug) { - System.out.println("Aligning to boundary "+ boundary +". Offset is now "+ras.getFilePointer()); - } - return skip; - } - - int align() throws IOException { - return align(alignment); - } - - long info() throws IOException { - return ras.getFilePointer(); - } - - long getFilePointer() throws IOException { - return ras.getFilePointer(); - } - - void close() throws IOException { - ras.close(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDatabase.java b/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDatabase.java deleted file mode 100644 index 0a39f1f1616a79264f42f40bac8ad42595b471c0..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/jrrd/RRDatabase.java +++ /dev/null @@ -1,508 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.jrrd; - -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.text.DecimalFormat; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.Iterator; - -import org.jrobin.core.RrdException; - -/** - * Instances of this class model - * <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/">Round Robin Database</a> - * (RRD) files. - * - * @author <a href="mailto:ciaran@codeloop.com">Ciaran Treanor</a> - * @version $Revision$ - */ -public class RRDatabase { - - RRDFile rrdFile; - - // RRD file name - private String name; - Header header; - ArrayList<DataSource> dataSources; - ArrayList<Archive> archives; - Date lastUpdate; - - /** - * Creates a database to read from. - * - * @param name the filename of the file to read from. - * @throws IOException if an I/O error occurs. - */ - public RRDatabase(String name) throws IOException,RrdException { - this(new File(name)); - } - - /** - * Creates a database to read from. - * - * @param file the file to read from. - * @throws IOException if an I/O error occurs. - */ - public RRDatabase(File file) throws IOException,RrdException { - - name = file.getName(); - rrdFile = new RRDFile(file); - header = new Header(rrdFile); - - // Load the data sources - dataSources = new ArrayList<DataSource>(); - - for (int i = 0; i < header.dsCount; i++) { - DataSource ds = new DataSource(rrdFile); - - dataSources.add(ds); - } - - // Load the archives - archives = new ArrayList<Archive>(); - - for (int i = 0; i < header.rraCount; i++) { - Archive archive = new Archive(this); - - archives.add(archive); - } - - rrdFile.align(); - - long timestamp = (long)(rrdFile.readInt()) * 1000; - if(header.getIntVersion() >= 3) { - //Version 3 has an additional microsecond field - int microSeconds = rrdFile.readInt(); - timestamp += (microSeconds/1000); //Date only does up to milliseconds - } - lastUpdate = new Date( timestamp ); - // Load PDPStatus(s) - for (int i = 0; i < header.dsCount; i++) { - DataSource ds = dataSources.get(i); - - ds.loadPDPStatusBlock(rrdFile); - } - - // Load CDPStatus(s) - for (int i = 0; i < header.rraCount; i++) { - Archive archive = archives.get(i); - - archive.loadCDPStatusBlocks(rrdFile, header.dsCount); - } - - // Load current row information for each archive - for (int i = 0; i < header.rraCount; i++) { - Archive archive = archives.get(i); - - archive.loadCurrentRow(rrdFile); - } - - // Now load the data - for (int i = 0; i < header.rraCount; i++) { - Archive archive = archives.get(i); - - archive.loadData(rrdFile, header.dsCount); - } - } - - /** - * Returns the <code>Header</code> for this database. - * - * @return the <code>Header</code> for this database. - */ - public Header getHeader() { - return header; - } - - /** - * Returns the date this database was last updated. To convert this date to - * the form returned by <code>rrdtool last</code> call Date.getTime() and - * divide the result by 1000. - * - * @return the date this database was last updated. - */ - public Date getLastUpdate() { - return lastUpdate; - } - - /** - * Returns the <code>DataSource</code> at the specified position in this database. - * - * @param index index of <code>DataSource</code> to return. - * @return the <code>DataSource</code> at the specified position in this database - */ - public DataSource getDataSource(int index) { - return dataSources.get(index); - } - - /** - * Returns an iterator over the data sources in this database in proper sequence. - * - * @return an iterator over the data sources in this database in proper sequence. - */ - public Iterator<DataSource> getDataSources() { - return dataSources.iterator(); - } - - /** - * Returns the <code>Archive</code> at the specified position in this database. - * - * @param index index of <code>Archive</code> to return. - * @return the <code>Archive</code> at the specified position in this database. - */ - public Archive getArchive(int index) { - return archives.get(index); - } - - /** - * Returns an iterator over the archives in this database in proper sequence. - * - * @return an iterator over the archives in this database in proper sequence. - */ - public Iterator<Archive> getArchives() { - return archives.iterator(); - } - - /** - * Returns the number of archives in this database. - * - * @return the number of archives in this database. - */ - public int getNumArchives() { - return header.rraCount; - } - - /** - * Returns an iterator over the archives in this database of the given type - * in proper sequence. - * - * @param type the consolidation function that should have been applied to - * the data. - * @return an iterator over the archives in this database of the given type - * in proper sequence. - */ - public Iterator<Archive> getArchives(ConsolidationFunctionType type) { - return getArchiveList(type).iterator(); - } - - ArrayList<Archive> getArchiveList(ConsolidationFunctionType type) { - - ArrayList<Archive> subset = new ArrayList<Archive>(); - - for (int i = 0; i < archives.size(); i++) { - Archive archive = archives.get(i); - - if (archive.getType().equals(type)) { - subset.add(archive); - } - } - - return subset; - } - - /** - * Closes this database stream and releases any associated system resources. - * - * @throws IOException if an I/O error occurs. - */ - public void close() throws IOException { - rrdFile.close(); - } - - /** - * Outputs the header information of the database to the given print stream - * using the default number format. The default format for <code>double</code> - * is 0.0000000000E0. - * - * @param s the PrintStream to print the header information to. - */ - public void printInfo(PrintStream s) { - - NumberFormat numberFormat = new DecimalFormat("0.0000000000E0"); - - printInfo(s, numberFormat); - } - - /** - * Returns data from the database corresponding to the given consolidation - * function and a step size of 1. - * - * @param type the consolidation function that should have been applied to - * the data. - * @return the raw data. - * @throws RrdException if there was a problem locating a data archive with - * the requested consolidation function. - * @throws IOException if there was a problem reading data from the database. - */ - public DataChunk getData(ConsolidationFunctionType type) - throws RrdException, IOException { - return getData(type, 1L); - } - - /** - * Returns data from the database corresponding to the given consolidation - * function. - * - * @param type the consolidation function that should have been applied to - * the data. - * @param step the step size to use. - * @return the raw data. - * @throws RrdException if there was a problem locating a data archive with - * the requested consolidation function. - * @throws IOException if there was a problem reading data from the database. - */ - public DataChunk getData(ConsolidationFunctionType type, long step) - throws RrdException, IOException { - - ArrayList<Archive> possibleArchives = getArchiveList(type); - - if (possibleArchives.size() == 0) { - throw new RrdException("Database does not contain an Archive of consolidation function type " - + type); - } - - Calendar endCal = Calendar.getInstance(); - - endCal.set(Calendar.MILLISECOND, 0); - - Calendar startCal = (Calendar) endCal.clone(); - - startCal.add(Calendar.DATE, -1); - - long end = endCal.getTime().getTime() / 1000; - long start = startCal.getTime().getTime() / 1000; - Archive archive = findBestArchive(start, end, step, possibleArchives); - - // Tune the parameters - step = header.pdpStep * archive.pdpCount; - start -= start % step; - - if (end % step != 0) { - end += step - end % step; - } - - int rows = (int) ((end - start) / step + 1); - - //cat.debug("start " + start + " end " + end + " step " + step + " rows " - // + rows); - - // Find start and end offsets - // This is terrible - some of this should be encapsulated in Archive - CT. - long lastUpdateLong = lastUpdate.getTime() / 1000; - long archiveEndTime = lastUpdateLong - (lastUpdateLong % step); - long archiveStartTime = archiveEndTime - (step * (archive.rowCount - 1)); - int startOffset = (int) ((start - archiveStartTime) / step); - int endOffset = (int) ((archiveEndTime - end) / step); - - //cat.debug("start " + archiveStartTime + " end " + archiveEndTime - // + " startOffset " + startOffset + " endOffset " - // + (archive.rowCount - endOffset)); - - DataChunk chunk = new DataChunk(start, startOffset, endOffset, step, - header.dsCount, rows); - - archive.loadData(chunk); - - return chunk; - } - - /* - * This is almost a verbatim copy of the original C code by Tobias Oetiker. - * I need to put more of a Java style on it - CT - */ - private Archive findBestArchive(long start, long end, long step, - ArrayList<Archive> archives) { - - Archive archive = null; - Archive bestFullArchive = null; - Archive bestPartialArchive = null; - long lastUpdateLong = lastUpdate.getTime() / 1000; - int firstPart = 1; - int firstFull = 1; - long bestMatch = 0; - //long bestPartRRA = 0; - long bestStepDiff = 0; - long tmpStepDiff = 0; - - for (int i = 0; i < archives.size(); i++) { - archive = archives.get(i); - - long calEnd = lastUpdateLong - - (lastUpdateLong - % (archive.pdpCount * header.pdpStep)); - long calStart = calEnd - - (archive.pdpCount * archive.rowCount - * header.pdpStep); - long fullMatch = end - start; - - if ((calEnd >= end) && (calStart < start)) { // Best full match - tmpStepDiff = Math.abs(step - (header.pdpStep * archive.pdpCount)); - - if ((firstFull != 0) || (tmpStepDiff < bestStepDiff)) { - firstFull = 0; - bestStepDiff = tmpStepDiff; - bestFullArchive = archive; - } - } - else { // Best partial match - long tmpMatch = fullMatch; - - if (calStart > start) { - tmpMatch -= calStart - start; - } - - if (calEnd < end) { - tmpMatch -= end - calEnd; - } - - if ((firstPart != 0) || (bestMatch < tmpMatch)) { - firstPart = 0; - bestMatch = tmpMatch; - bestPartialArchive = archive; - } - } - } - - // See how the matching went - // optimise this - if (firstFull == 0) { - archive = bestFullArchive; - } - else if (firstPart == 0) { - archive = bestPartialArchive; - } - - return archive; - } - - /** - * Outputs the header information of the database to the given print stream - * using the given number format. The format is almost identical to that - * produced by - * <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/manual/rrdinfo.html">rrdtool info</a> - * - * @param s the PrintStream to print the header information to. - * @param numberFormat the format to print <code>double</code>s as. - */ - public void printInfo(PrintStream s, NumberFormat numberFormat) { - - s.print("filename = \""); - s.print(name); - s.println("\""); - s.print("rrd_version = \""); - s.print(header.version); - s.println("\""); - s.print("step = "); - s.println(header.pdpStep); - s.print("last_update = "); - s.println(lastUpdate.getTime() / 1000); - - for (Iterator<DataSource> i = dataSources.iterator(); i.hasNext();) { - DataSource ds = i.next(); - - ds.printInfo(s, numberFormat); - } - - int index = 0; - - for (Iterator<Archive> i = archives.iterator(); i.hasNext();) { - Archive archive = i.next(); - - archive.printInfo(s, numberFormat, index++); - } - } - - /** - * Outputs the content of the database to the given print stream - * as a stream of XML. The XML format is almost identical to that produced by - * <a href="http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/manual/rrddump.html">rrdtool dump</a> - * - * @param s the PrintStream to send the XML to. - */ - public void toXml(PrintStream s) throws RrdException { - - s.println("<!--"); - s.println(" -- Round Robin RRDatabase Dump "); - s.println(" -- Generated by jRRD <ciaran@codeloop.com>"); - s.println(" -->"); - s.println("<rrd>"); - s.print("\t<version> "); - s.print(header.version); - s.println(" </version>"); - s.print("\t<step> "); - s.print(header.pdpStep); - s.println(" </step> <!-- Seconds -->"); - s.print("\t<lastupdate> "); - s.print(lastUpdate.getTime() / 1000); - s.print(" </lastupdate> <!-- "); - s.print(lastUpdate.toString()); - s.println(" -->"); - s.println(); - - for (int i = 0; i < header.dsCount; i++) { - DataSource ds = dataSources.get(i); - - ds.toXml(s); - } - - s.println("<!-- Round Robin Archives -->"); - - for (int i = 0; i < header.rraCount; i++) { - Archive archive = archives.get(i); - - archive.toXml(s); - } - - s.println("</rrd>"); - } - - /** - * Returns a summary the contents of this database. - * - * @return a summary of the information contained in this database. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("\n"); - - sb.append(header.toString()); - - for (Iterator<DataSource> i = dataSources.iterator(); i.hasNext();) { - DataSource ds = i.next(); - - sb.append("\n\t"); - sb.append(ds.toString()); - } - - for (Iterator<Archive> i = archives.iterator(); i.hasNext();) { - Archive archive = i.next(); - - sb.append("\n\t"); - sb.append(archive.toString()); - } - - return sb.toString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/timespec/Epoch.java b/apps/jrobin/java/src/org/jrobin/core/timespec/Epoch.java deleted file mode 100644 index 7a5c70f34bd061f6865ad8688d7c26e6c9da02af..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/timespec/Epoch.java +++ /dev/null @@ -1,187 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.timespec; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; - -/** - * Small swing-based utility to convert timestamps (seconds since epoch) to readable dates and vice versa. - * Supports at-style time specification (like "now-2d", "noon yesterday") and other human-readable - * data formats:<p> - * <ul> - * <li>MM/dd/yy HH:mm:ss - * <li>dd.MM.yy HH:mm:ss - * <li>dd.MM.yy HH:mm:ss - * <li>MM/dd/yy HH:mm - * <li>dd.MM.yy HH:mm - * <li>yy-MM-dd HH:mm - * <li>MM/dd/yy - * <li>dd.MM.yy - * <li>yy-MM-dd - * <li>HH:mm MM/dd/yy - * <li>HH:mm dd.MM.yy - * <li>HH:mm yy-MM-dd - * <li>HH:mm:ss MM/dd/yy - * <li>HH:mm:ss dd.MM.yy - * <li>HH:mm:ss yy-MM-dd - * </ul> - * The current timestamp is displayed in the title bar :)<p> - */ -public class Epoch extends JFrame { - private static final long serialVersionUID = 1L; - private static final String[] supportedFormats = { - "MM/dd/yy HH:mm:ss", "dd.MM.yy HH:mm:ss", "yy-MM-dd HH:mm:ss", "MM/dd/yy HH:mm", - "dd.MM.yy HH:mm", "yy-MM-dd HH:mm", "MM/dd/yy", "dd.MM.yy", "yy-MM-dd", "HH:mm MM/dd/yy", - "HH:mm dd.MM.yy", "HH:mm yy-MM-dd", "HH:mm:ss MM/dd/yy", "HH:mm:ss dd.MM.yy", "HH:mm:ss yy-MM-dd" - }; - - private static final SimpleDateFormat[] parsers = new SimpleDateFormat[supportedFormats.length]; - private static final String helpText; - - private Timer timer = new Timer(1000, new ActionListener() { - public void actionPerformed(ActionEvent e) { - showTimestamp(); - } - }); - - static { - for (int i = 0; i < parsers.length; i++) { - parsers[i] = new SimpleDateFormat(supportedFormats[i]); - parsers[i].setLenient(true); - } - StringBuffer tooltipBuff = new StringBuffer("<html><b>Supported input formats:</b><br>"); - for (String supportedFormat : supportedFormats) { - tooltipBuff.append(supportedFormat).append("<br>"); - } - tooltipBuff.append("<b>AT-style time specification</b><br>"); - tooltipBuff.append("timestamp<br><br>"); - tooltipBuff.append("Copyright (C) 2003-2005 Sasa Markovic, All Rights Reserved</html>"); - helpText = tooltipBuff.toString(); - } - - private JLabel topLabel = new JLabel("Enter timestamp or readable date:"); - private JTextField inputField = new JTextField(25); - private JButton convertButton = new JButton("Convert"); - private JButton helpButton = new JButton("Help"); - - private static final SimpleDateFormat OUTPUT_DATE_FORMAT = - new SimpleDateFormat("MM/dd/yy HH:mm:ss EEE"); - - Epoch() { - super("Epoch"); - constructUI(); - timer.start(); - } - - private void constructUI() { - JPanel c = (JPanel) getContentPane(); - c.setLayout(new BorderLayout(3, 3)); - c.add(topLabel, BorderLayout.NORTH); - c.add(inputField, BorderLayout.WEST); - c.add(convertButton, BorderLayout.CENTER); - convertButton.setToolTipText(helpText); - convertButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - convert(); - } - }); - c.add(helpButton, BorderLayout.EAST); - helpButton.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent e) { - JOptionPane.showMessageDialog(helpButton, helpText, "Epoch Help", JOptionPane.INFORMATION_MESSAGE); - } - }); - inputField.requestFocus(); - getRootPane().setDefaultButton(convertButton); - setResizable(false); - setDefaultCloseOperation(EXIT_ON_CLOSE); - pack(); - centerOnScreen(); - setVisible(true); - } - - void centerOnScreen() { - Toolkit t = Toolkit.getDefaultToolkit(); - Dimension screenSize = t.getScreenSize(); - Dimension frameSize = getPreferredSize(); - double x = (screenSize.getWidth() - frameSize.getWidth()) / 2; - double y = (screenSize.getHeight() - frameSize.getHeight()) / 2; - setLocation((int) x, (int) y); - } - - private void convert() { - String time = inputField.getText().trim(); - if (time.length() > 0) { - // try simple timestamp - try { - long timestamp = Long.parseLong(time); - Date date = new Date(timestamp * 1000L); - formatDate(date); - } - catch (NumberFormatException nfe) { - // failed, try as a date - try { - inputField.setText("" + parseDate(time)); - } - catch (RrdException e) { - inputField.setText("Could not convert, sorry"); - } - } - } - } - - private void showTimestamp() { - long timestamp = Util.getTime(); - setTitle(timestamp + " seconds since epoch"); - } - - void formatDate(Date date) { - inputField.setText(OUTPUT_DATE_FORMAT.format(date)); - } - - private long parseDate(String time) throws RrdException { - for (SimpleDateFormat parser : parsers) { - try { - return Util.getTimestamp(parser.parse(time)); - } - catch (ParseException e) { - // NOP - } - } - return new TimeParser(time).parse().getTimestamp(); - } - - /** - * Main method which runs this utility. - * - * @param args Not used. - */ - public static void main(String[] args) { - new Epoch(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/timespec/TimeParser.java b/apps/jrobin/java/src/org/jrobin/core/timespec/TimeParser.java deleted file mode 100644 index b957ecc140847b2fcac0283c7f3776d1c7716a62..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/timespec/TimeParser.java +++ /dev/null @@ -1,443 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -/* - * Java port of Tobi's original parsetime.c routine - */ -package org.jrobin.core.timespec; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; - -/** - * 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. - */ -public class TimeParser { - private static final int PREVIOUS_OP = -1; - - TimeToken token; - TimeScanner scanner; - TimeSpec spec; - - int op = TimeToken.PLUS; - int prev_multiplier = -1; - - /** - * Constructs TimeParser instance from the given input string. - * - * @param dateString at-style time specification (read rrdfetch man page - * for the complete explanation) - */ - public TimeParser(String dateString) { - scanner = new TimeScanner(dateString); - spec = new TimeSpec(dateString); - } - - private void expectToken(int desired, String errorMessage) throws RrdException { - token = scanner.nextToken(); - if (token.id != desired) { - throw new RrdException(errorMessage); - } - } - - private void plusMinus(int doop) throws RrdException { - if (doop >= 0) { - op = doop; - expectToken(TimeToken.NUMBER, "There should be number after " + - (op == TimeToken.PLUS ? '+' : '-')); - prev_multiplier = -1; /* reset months-minutes guessing mechanics */ - } - int delta = Integer.parseInt(token.value); - token = scanner.nextToken(); - if (token.id == TimeToken.MONTHS_MINUTES) { - /* hard job to guess what does that -5m means: -5mon or -5min? */ - switch (prev_multiplier) { - case TimeToken.DAYS: - case TimeToken.WEEKS: - case TimeToken.MONTHS: - case TimeToken.YEARS: - token = scanner.resolveMonthsMinutes(TimeToken.MONTHS); - break; - case TimeToken.SECONDS: - case TimeToken.MINUTES: - case TimeToken.HOURS: - token = scanner.resolveMonthsMinutes(TimeToken.MINUTES); - break; - default: - if (delta < 6) { - token = scanner.resolveMonthsMinutes(TimeToken.MONTHS); - } - else { - token = scanner.resolveMonthsMinutes(TimeToken.MINUTES); - } - } - } - prev_multiplier = token.id; - delta *= (op == TimeToken.PLUS) ? +1 : -1; - switch (token.id) { - case TimeToken.YEARS: - spec.dyear += delta; - break; - case TimeToken.MONTHS: - spec.dmonth += delta; - break; - case TimeToken.WEEKS: - delta *= 7; - spec.dday += delta; - break; - case TimeToken.DAYS: - spec.dday += delta; - break; - case TimeToken.HOURS: - spec.dhour += delta; - break; - case TimeToken.MINUTES: - spec.dmin += delta; - break; - case TimeToken.SECONDS: - default: // default is 'seconds' - spec.dsec += delta; - break; - } - // unreachable statement - // throw new RrdException("Well-known time unit expected after " + delta); - } - - /** - * Try and read a "timeofday" specification. This method will be called - * when we see a plain number at the start of a time, which means we could be - * reading a time, or a day. If it turns out to be a date, then this method restores - * the scanner state to what it was at entry, and returns without setting anything. - * @throws RrdException - */ - private void timeOfDay() throws RrdException { - int hour, 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 */ - if (token.value.length() > 2) { - //Definitely not an hour specification; probably a date or something. Give up now - return; - } - hour = Integer.parseInt(token.value); - token = scanner.nextToken(); - if (token.id == TimeToken.SLASH) { - /* guess we are looking at a date */ - token = scanner.restoreState(); - return; - } - if (token.id == TimeToken.COLON || token.id == TimeToken.DOT) { - expectToken(TimeToken.NUMBER, "Parsing HH:MM or HH.MM syntax, expecting MM as number, got none"); - minute = Integer.parseInt(token.value); - if (minute > 59) { - throw new RrdException("Parsing HH:MM or HH.MM syntax, got MM = " + - minute + " (>59!)"); - } - token = scanner.nextToken(); - if(token.id == TimeToken.DOT) { - //Oh look, another dot; must have actually been a date in DD.MM.YYYY format. Give up and return - token = scanner.restoreState(); - return; - } - - } - /* check if an AM or PM specifier was given */ - if (token.id == TimeToken.AM || token.id == TimeToken.PM) { - if (hour > 12) { - throw new RrdException("There cannot be more than 12 AM or PM hours"); - } - if (token.id == TimeToken.PM) { - if (hour != 12) { - /* 12:xx PM is 12:xx, not 24:xx */ - hour += 12; - } - } - else { - if (hour == 12) { - /* 12:xx AM is 00:xx, not 12:xx */ - hour = 0; - } - } - token = scanner.nextToken(); - } - else if (hour > 23) { - /* guess it was not a time then, probably a date ... */ - token = scanner.restoreState(); - return; - } - - spec.hour = hour; - spec.min = minute; - spec.sec = 0; - if (spec.hour == 24) { - spec.hour = 0; - spec.day++; - } - } - - private void assignDate(long mday, long mon, long year) throws RrdException { - if (year > 138) { - if (year > 1970) { - year -= 1900; - } - else { - throw new RrdException("Invalid year " + year + - " (should be either 00-99 or >1900)"); - } - } - 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 RrdException("Won't handle dates before epoch (01/01/1970), sorry"); - } - spec.year = (int) year; - spec.month = (int) mon; - spec.day = (int) mday; - } - - private void day() throws RrdException { - long mday = 0, wday, mon, year = spec.year; - switch (token.id) { - case TimeToken.YESTERDAY: - spec.day--; - token = scanner.nextToken(); - break; - case TimeToken.TODAY: /* force ourselves to stay in today - no further processing */ - token = scanner.nextToken(); - break; - case TimeToken.TOMORROW: - spec.day++; - token = scanner.nextToken(); - break; - case TimeToken.JAN: - case TimeToken.FEB: - case TimeToken.MAR: - case TimeToken.APR: - case TimeToken.MAY: - case TimeToken.JUN: - case TimeToken.JUL: - case TimeToken.AUG: - case TimeToken.SEP: - case TimeToken.OCT: - case TimeToken.NOV: - case TimeToken.DEC: - /* do month mday [year] */ - mon = (token.id - TimeToken.JAN); - expectToken(TimeToken.NUMBER, "the day of the month should follow month name"); - mday = Long.parseLong(token.value); - token = scanner.nextToken(); - if (token.id == TimeToken.NUMBER) { - year = Long.parseLong(token.value); - token = scanner.nextToken(); - } - else { - year = spec.year; - } - assignDate(mday, mon, year); - break; - case TimeToken.SUN: - case TimeToken.MON: - case TimeToken.TUE: - case TimeToken.WED: - case TimeToken.THU: - case TimeToken.FRI: - case TimeToken.SAT: - /* do a particular day of the week */ - wday = (token.id - TimeToken.SUN); - spec.day += (wday - spec.wday); - token = scanner.nextToken(); - break; - case TimeToken.NUMBER: - /* get numeric <sec since 1970>, MM/DD/[YY]YY, or DD.MM.[YY]YY */ - // int tlen = token.value.length(); - mon = Long.parseLong(token.value); - if (mon > 10L * 365L * 24L * 60L * 60L) { - spec.localtime(mon); - token = scanner.nextToken(); - break; - } - if (mon > 19700101 && mon < 24000101) { /*works between 1900 and 2400 */ - year = mon / 10000; - mday = mon % 100; - mon = (mon / 100) % 100; - token = scanner.nextToken(); - } - else { - token = scanner.nextToken(); - if (mon <= 31 && (token.id == TimeToken.SLASH || token.id == TimeToken.DOT)) { - int sep = token.id; - expectToken(TimeToken.NUMBER, "there should be " + - (sep == TimeToken.DOT ? "month" : "day") + - " number after " + - (sep == TimeToken.DOT ? '.' : '/')); - mday = Long.parseLong(token.value); - token = scanner.nextToken(); - if (token.id == sep) { - expectToken(TimeToken.NUMBER, "there should be year number after " + - (sep == TimeToken.DOT ? '.' : '/')); - year = Long.parseLong(token.value); - token = scanner.nextToken(); - } - /* flip months and days for European timing */ - if (sep == TimeToken.DOT) { - long x = mday; - mday = mon; - mon = x; - } - } - } - mon--; - if (mon < 0 || mon > 11) { - throw new RrdException("Did you really mean month " + (mon + 1)); - } - if (mday < 1 || mday > 31) { - throw new RrdException("I'm afraid that " + mday + - " is not a valid day of the month"); - } - assignDate(mday, mon, year); - break; - } - } - - /** - * Parses the input string specified in the constructor. - * - * @return Object representing parsed date/time. - * @throws RrdException Thrown if the date string cannot be parsed. - */ - public TimeSpec parse() throws RrdException { - long now = Util.getTime(); - int hr = 0; - /* this MUST be initialized to zero for midnight/noon/teatime */ - /* establish the default time reference */ - spec.localtime(now); - token = scanner.nextToken(); - switch (token.id) { - case TimeToken.PLUS: - case TimeToken.MINUS: - break; /* jump to OFFSET-SPEC part */ - case TimeToken.START: - spec.type = TimeSpec.TYPE_START; - /* FALLTHRU */ - case TimeToken.END: - if (spec.type != TimeSpec.TYPE_START) { - spec.type = TimeSpec.TYPE_END; - } - /* FALLTHRU */ - case TimeToken.EPOCH: - /* FALLTHRU */ - case TimeToken.NOW: - int time_reference = token.id; - if (token.id != TimeToken.NOW) { - spec.year = spec.month = spec.day = spec.hour = spec.min = spec.sec = 0; - } - token = scanner.nextToken(); - if (token.id == TimeToken.PLUS || token.id == TimeToken.MINUS) { - break; - } - if (time_reference == TimeToken.START || time_reference == TimeToken.END) { - throw new RrdException("Words 'start' or 'end' MUST be followed by +|- offset"); - } - else if (token.id != TimeToken.EOF) { - throw new RrdException("If 'now' or 'epoch' is followed by a token it must be +|- offset"); - } - break; - /* Only absolute time specifications below */ - case TimeToken.NUMBER: - timeOfDay(); - //Keep going; there might be a date after the time of day, which day() will pick up - /* fix month parsing */ - case TimeToken.JAN: - case TimeToken.FEB: - case TimeToken.MAR: - case TimeToken.APR: - case TimeToken.MAY: - case TimeToken.JUN: - case TimeToken.JUL: - case TimeToken.AUG: - case TimeToken.SEP: - case TimeToken.OCT: - case TimeToken.NOV: - case TimeToken.DEC: - case TimeToken.TODAY: - case TimeToken.YESTERDAY: - case TimeToken.TOMORROW: - day(); - if (token.id != TimeToken.NUMBER) { - break; - } - //Allows (but does not require) the time to be specified after the day. This extends the rrdfetch specifiation - timeOfDay(); - break; - - /* evil coding for TEATIME|NOON|MIDNIGHT - we've initialized - * hr to zero up above, then fall into this case in such a - * way so we add +12 +4 hours to it for teatime, +12 hours - * to it for noon, and nothing at all for midnight, then - * set our rettime to that hour before leaping into the - * month scanner - */ - case TimeToken.TEATIME: - hr += 4; - /* FALLTHRU */ - case TimeToken.NOON: - hr += 12; - /* FALLTHRU */ - case TimeToken.MIDNIGHT: - spec.hour = hr; - spec.min = 0; - spec.sec = 0; - token = scanner.nextToken(); - day(); - break; - default: - throw new RrdException("Unparsable time: " + token.value); - } - - /* - * the OFFSET-SPEC part - * - * (NOTE, the sc_tokid was prefetched for us by the previous code) - */ - if (token.id == TimeToken.PLUS || token.id == TimeToken.MINUS) { - scanner.setContext(false); - while (token.id == TimeToken.PLUS || token.id == TimeToken.MINUS || - token.id == TimeToken.NUMBER) { - if (token.id == TimeToken.NUMBER) { - plusMinus(PREVIOUS_OP); - } - else { - plusMinus(token.id); - } - token = scanner.nextToken(); - /* We will get EOF eventually but that's OK, since - token() will return us as many EOFs as needed */ - } - } - /* now we should be at EOF */ - if (token.id != TimeToken.EOF) { - throw new RrdException("Unparsable trailing text: " + token.value); - } - return spec; - } -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/core/timespec/TimeScanner.java b/apps/jrobin/java/src/org/jrobin/core/timespec/TimeScanner.java deleted file mode 100644 index 2895ae55d60ebc140a89f42de049baecdc03b0c7..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/timespec/TimeScanner.java +++ /dev/null @@ -1,205 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.core.timespec; - -class TimeScanner { - private String dateString; - - private int pos, pos_save; - 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("tomorrow", TimeToken.TOMORROW), - new TimeToken("yesterday", TimeToken.YESTERDAY), - new TimeToken("today", TimeToken.TODAY), - new TimeToken("now", TimeToken.NOW), - new TimeToken("n", TimeToken.NOW), - new TimeToken("start", TimeToken.START), - new TimeToken("s", TimeToken.START), - new TimeToken("end", TimeToken.END), - new TimeToken("e", TimeToken.END), - new TimeToken("jan", TimeToken.JAN), - new TimeToken("feb", TimeToken.FEB), - new TimeToken("mar", TimeToken.MAR), - new TimeToken("apr", TimeToken.APR), - new TimeToken("may", TimeToken.MAY), - new TimeToken("jun", TimeToken.JUN), - new TimeToken("jul", TimeToken.JUL), - new TimeToken("aug", TimeToken.AUG), - new TimeToken("sep", TimeToken.SEP), - new TimeToken("oct", TimeToken.OCT), - new TimeToken("nov", TimeToken.NOV), - new TimeToken("dec", TimeToken.DEC), - new TimeToken("january", TimeToken.JAN), - new TimeToken("february", TimeToken.FEB), - new TimeToken("march", TimeToken.MAR), - new TimeToken("april", TimeToken.APR), - new TimeToken("may", TimeToken.MAY), - new TimeToken("june", TimeToken.JUN), - new TimeToken("july", TimeToken.JUL), - new TimeToken("august", TimeToken.AUG), - new TimeToken("september", TimeToken.SEP), - new TimeToken("october", TimeToken.OCT), - new TimeToken("november", TimeToken.NOV), - new TimeToken("december", TimeToken.DEC), - new TimeToken("sunday", TimeToken.SUN), - new TimeToken("sun", TimeToken.SUN), - new TimeToken("monday", TimeToken.MON), - new TimeToken("mon", TimeToken.MON), - new TimeToken("tuesday", TimeToken.TUE), - new TimeToken("tue", TimeToken.TUE), - new TimeToken("wednesday", TimeToken.WED), - new TimeToken("wed", TimeToken.WED), - new TimeToken("thursday", TimeToken.THU), - new TimeToken("thu", TimeToken.THU), - new TimeToken("friday", TimeToken.FRI), - new TimeToken("fri", TimeToken.FRI), - new TimeToken("saturday", TimeToken.SAT), - new TimeToken("sat", TimeToken.SAT), - new TimeToken("epoch", TimeToken.EPOCH), - 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) */ - 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("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("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(null, 0) /*** SENTINEL ***/ - }; - - TimeToken[] specials = WORDS; - - public TimeScanner(String dateString) { - this.dateString = dateString; - } - - void setContext(boolean parsingWords) { - specials = parsingWords ? WORDS : MULTIPLIERS; - } - - TimeToken nextToken() { - StringBuffer buffer = new StringBuffer(""); - while (pos < dateString.length()) { - char c = dateString.charAt(pos++); - if (Character.isWhitespace(c) || c == '_' || c == ',') { - continue; - } - buffer.append(c); - if (Character.isDigit(c)) { - // pick as many digits as possible - while (pos < dateString.length()) { - char next = dateString.charAt(pos); - if (Character.isDigit(next)) { - buffer.append(next); - pos++; - } - else { - break; - } - } - String value = buffer.toString(); - return token = new TimeToken(value, TimeToken.NUMBER); - } - if (Character.isLetter(c)) { - // pick as many letters as possible - while (pos < dateString.length()) { - char next = dateString.charAt(pos); - if (Character.isLetter(next)) { - buffer.append(next); - pos++; - } - else { - break; - } - } - String value = buffer.toString(); - return token = new TimeToken(value, parseToken(value)); - } - switch (c) { - case ':': - return token = new TimeToken(":", TimeToken.COLON); - case '.': - return token = new TimeToken(".", TimeToken.DOT); - case '+': - return token = new TimeToken("+", TimeToken.PLUS); - case '-': - return token = new TimeToken("-", TimeToken.MINUS); - case '/': - return token = new TimeToken("/", TimeToken.SLASH); - default: - pos--; - return token = new TimeToken(null, TimeToken.EOF); - } - } - return token = new TimeToken(null, TimeToken.EOF); - } - - TimeToken resolveMonthsMinutes(int newId) { - assert token.id == TimeToken.MONTHS_MINUTES; - assert newId == TimeToken.MONTHS || newId == TimeToken.MINUTES; - return token = new TimeToken(token.value, newId); - } - - void saveState() { - token_save = token; - pos_save = pos; - } - - TimeToken restoreState() { - pos = pos_save; - return token = token_save; - } - - private int parseToken(String arg) { - for (int i = 0; specials[i].value != null; i++) { - if (specials[i].value.equalsIgnoreCase(arg)) { - return specials[i].id; - } - } - return TimeToken.ID; - } -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/core/timespec/TimeSpec.java b/apps/jrobin/java/src/org/jrobin/core/timespec/TimeSpec.java deleted file mode 100644 index 79b18878d96a88b3143cc4719c3e9301db748b68..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/timespec/TimeSpec.java +++ /dev/null @@ -1,161 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core.timespec; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; - -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; - -/** - * Simple class to represent time obtained by parsing at-style date specification (described - * in detail on the rrdfetch man page. See javadoc for {@link org.jrobin.core.timespec.TimeParser} - * for more information. - */ -public class TimeSpec { - static final int TYPE_ABSOLUTE = 0; - static final int TYPE_START = 1; - static final int TYPE_END = 2; - - int type = TYPE_ABSOLUTE; - int year, month, day, hour, min, sec; - int wday; - int dyear, dmonth, dday, dhour, dmin, dsec; - - String dateString; - - TimeSpec context; - - TimeSpec(String dateString) { - this.dateString = dateString; - } - - void localtime(long timestamp) { - GregorianCalendar date = new GregorianCalendar(); - date.setTime(new Date(timestamp * 1000L)); - year = date.get(Calendar.YEAR) - 1900; - month = date.get(Calendar.MONTH); - day = date.get(Calendar.DAY_OF_MONTH); - hour = date.get(Calendar.HOUR_OF_DAY); - min = date.get(Calendar.MINUTE); - sec = date.get(Calendar.SECOND); - wday = date.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY; - } - - GregorianCalendar getTime() throws RrdException { - GregorianCalendar gc; - // absoulte time, this is easy - if (type == TYPE_ABSOLUTE) { - gc = new GregorianCalendar(year + 1900, month, day, hour, min, sec); - } - // relative time, we need a context to evaluate it - else if (context != null && context.type == TYPE_ABSOLUTE) { - gc = context.getTime(); - } - // how would I guess what time it was? - else { - throw new RrdException("Relative times like '" + - dateString + "' require proper absolute context to be evaluated"); - } - gc.add(Calendar.YEAR, dyear); - gc.add(Calendar.MONTH, dmonth); - gc.add(Calendar.DAY_OF_MONTH, dday); - gc.add(Calendar.HOUR_OF_DAY, dhour); - gc.add(Calendar.MINUTE, dmin); - gc.add(Calendar.SECOND, dsec); - return gc; - } - - /** - * Returns the corresponding timestamp (seconds since Epoch). Example:<p> - * <pre> - * TimeParser p = new TimeParser("now-1day"); - * TimeSpec ts = p.parse(); - * System.out.println("Timestamp was: " + ts.getTimestamp(); - * </pre> - * - * @return Timestamp (in seconds, no milliseconds) - * @throws RrdException Thrown if this TimeSpec object does not represent absolute time. - */ - public long getTimestamp() throws RrdException { - return Util.getTimestamp(getTime()); - } - - String dump() { - return (type == TYPE_ABSOLUTE ? "ABSTIME" : type == TYPE_START ? "START" : "END") + - ": " + year + "/" + month + "/" + day + - "/" + hour + "/" + min + "/" + sec + " (" + - dyear + "/" + dmonth + "/" + dday + - "/" + dhour + "/" + dmin + "/" + dsec + ")"; - } - - /** - * Use this static method to resolve relative time references and obtain the corresponding - * Calendar objects. Example:<p> - * <pre> - * TimeParser pStart = new TimeParser("now-1month"); // starting time - * TimeParser pEnd = new TimeParser("start+1week"); // ending time - * TimeSpec specStart = pStart.parse(); - * TimeSpec specEnd = pEnd.parse(); - * GregorianCalendar[] gc = TimeSpec.getTimes(specStart, specEnd); - * </pre> - * - * @param spec1 Starting time specification - * @param spec2 Ending time specification - * @return Two element array containing Calendar objects - * @throws RrdException Thrown if relative time references cannot be resolved - */ - public static Calendar[] getTimes(TimeSpec spec1, TimeSpec spec2) throws RrdException { - if (spec1.type == TYPE_START || spec2.type == TYPE_END) { - throw new RrdException("Recursive time specifications not allowed"); - } - spec1.context = spec2; - spec2.context = spec1; - return new Calendar[] { - spec1.getTime(), - spec2.getTime() - }; - } - - /** - * Use this static method to resolve relative time references and obtain the corresponding - * timestamps (seconds since epoch). Example:<p> - * <pre> - * TimeParser pStart = new TimeParser("now-1month"); // starting time - * TimeParser pEnd = new TimeParser("start+1week"); // ending time - * TimeSpec specStart = pStart.parse(); - * TimeSpec specEnd = pEnd.parse(); - * long[] ts = TimeSpec.getTimestamps(specStart, specEnd); - * </pre> - * - * @param spec1 Starting time specification - * @param spec2 Ending time specification - * @return array containing two timestamps (in seconds since epoch) - * @throws RrdException Thrown if relative time references cannot be resolved - */ - public static long[] getTimestamps(TimeSpec spec1, TimeSpec spec2) throws RrdException { - Calendar[] gcs = getTimes(spec1, spec2); - return new long[] { - Util.getTimestamp(gcs[0]), Util.getTimestamp(gcs[1]) - }; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/core/timespec/TimeToken.java b/apps/jrobin/java/src/org/jrobin/core/timespec/TimeToken.java deleted file mode 100644 index 64b2057e710c4ef446c264124766561dae1ef6e9..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/core/timespec/TimeToken.java +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.core.timespec; - -class TimeToken { - public static final int MIDNIGHT = 1; - public static final int NOON = 2; - public static final int TEATIME = 3; - public static final int PM = 4; - public static final int AM = 5; - public static final int YESTERDAY = 6; - public static final int TODAY = 7; - public static final int TOMORROW = 8; - public static final int NOW = 9; - public static final int START = 10; - public static final int END = 11; - public static final int SECONDS = 12; - public static final int MINUTES = 13; - public static final int HOURS = 14; - public static final int DAYS = 15; - public static final int WEEKS = 16; - public static final int MONTHS = 17; - public static final int YEARS = 18; - public static final int MONTHS_MINUTES = 19; - public static final int NUMBER = 20; - public static final int PLUS = 21; - public static final int MINUS = 22; - public static final int DOT = 23; - public static final int COLON = 24; - public static final int SLASH = 25; - public static final int ID = 26; - public static final int JUNK = 27; - public static final int JAN = 28; - public static final int FEB = 29; - public static final int MAR = 30; - public static final int APR = 31; - public static final int MAY = 32; - public static final int JUN = 33; - public static final int JUL = 34; - public static final int AUG = 35; - public static final int SEP = 36; - public static final int OCT = 37; - public static final int NOV = 38; - public static final int DEC = 39; - public static final int SUN = 40; - public static final int MON = 41; - public static final int TUE = 42; - public static final int WED = 43; - public static final int THU = 44; - public static final int FRI = 45; - public static final int SAT = 46; - public static final int EPOCH = 46; - public static final int EOF = -1; - - final String value; /* token name */ - final int id; /* token id */ - - public TimeToken(String value, int id) { - this.value = value; - this.id = id; - } - - public String toString() { - return value + " [" + id + "]"; - } -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/data/Aggregates.java b/apps/jrobin/java/src/org/jrobin/data/Aggregates.java deleted file mode 100644 index f2194b593519e118634e9b8c7b9bee5bcfb0ef9d..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/Aggregates.java +++ /dev/null @@ -1,188 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -import org.jrobin.core.ConsolFuns; -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; - -/** - * Simple class which holds aggregated values (MIN, MAX, FIRST, LAST, AVERAGE and TOTAL). You - * don't need to create objects of this class directly. Objects of this class are returned from - * <code>getAggregates()</code> method in - * {@link org.jrobin.core.FetchData#getAggregates(String) FetchData} and - * {@link DataProcessor#getAggregates(String)} DataProcessor} classes. - */ -public class Aggregates implements ConsolFuns { - double min = Double.NaN, max = Double.NaN; - double first = Double.NaN, last = Double.NaN; - double average = Double.NaN, total = Double.NaN; - double stdev = Double.NaN, lslslope = Double.NaN; - double lslint = Double.NaN, lslcorrel = Double.NaN; - - Aggregates() { - // NOP; - } - - /** - * Returns the minimal value - * - * @return Minimal value - */ - public double getMin() { - return min; - } - - /** - * Returns the maximum value - * - * @return Maximum value - */ - public double getMax() { - return max; - } - - /** - * Returns the first falue - * - * @return First value - */ - public double getFirst() { - return first; - } - - /** - * Returns the last value - * - * @return Last value - */ - public double getLast() { - return last; - } - - /** - * Returns average - * - * @return Average value - */ - public double getAverage() { - return average; - } - - /** - * Returns total value - * - * @return Total value - */ - public double getTotal() { - return total; - } - - /** - * Returns stdev value - * - * @return Stdev value - */ - public double getStdev() { - return stdev; - } - - /** - * Returns Least Squares Line Slope value - * - * @return lslslope value - */ - public double getLSLSlope() { - return stdev; - } - - /** - * Returns Least Squares Line y-intercept value - * - * @return lslint value - */ - public double getLSLInt() { - return lslint; - } - - /** - * Returns Least Squares Line Correlation Coefficient - * - * @return lslcorrel value - */ - public double getLSLCorrel() { - return lslcorrel; - } - - /** - * Returns single aggregated value for the give consolidation function - * - * @param consolFun Consolidation function: MIN, MAX, FIRST, LAST, AVERAGE, TOTAL. These constants - * are conveniently defined in the {@link org.jrobin.core.ConsolFuns ConsolFuns} interface. - * @return Aggregated value - * @throws RrdException Thrown if unsupported consolidation function is supplied - */ - public double getAggregate(String consolFun) throws RrdException { - if (consolFun.equals(CF_AVERAGE)) { - return average; - } - else if (consolFun.equals(CF_FIRST)) { - return first; - } - else if (consolFun.equals(CF_LAST)) { - return last; - } - else if (consolFun.equals(CF_MAX)) { - return max; - } - else if (consolFun.equals(CF_MIN)) { - return min; - } - else if (consolFun.equals(CF_TOTAL)) { - return total; - } - else if (consolFun.equals("STDEV")) { - return stdev; - } - else if (consolFun.equals("LSLSLOPE")) { - return lslslope; - } - else if (consolFun.equals("LSLINT")) { - return lslint; - } - else if (consolFun.equals("LSLCORREL")) { - return lslcorrel; - } - else { - throw new RrdException("Unknown consolidation function: " + consolFun); - } - } - - /** - * Returns String representing all aggregated values. Just for debugging purposes. - * - * @return String containing all aggregated values - */ - public String dump() { - return "MIN=" + Util.formatDouble(min) + ", MAX=" + Util.formatDouble(max) + "\n" + - "FIRST=" + Util.formatDouble(first) + ", LAST=" + Util.formatDouble(last) + "\n" + - "AVERAGE=" + Util.formatDouble(average) + ", TOTAL=" + Util.formatDouble(total); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/Aggregator.java b/apps/jrobin/java/src/org/jrobin/data/Aggregator.java deleted file mode 100644 index 05ceccbbc9f34b8021a57c6cd7b929f3d47f1fe1..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/Aggregator.java +++ /dev/null @@ -1,159 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -import org.jrobin.core.ConsolFuns; -import org.jrobin.core.Util; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -class Aggregator implements ConsolFuns { - private long timestamps[], step; - private double[] values; - - Aggregator(long[] timestamps, double[] values) { - assert timestamps.length == values.length: "Incompatible timestamps/values arrays (unequal lengths)"; - assert timestamps.length >= 2: "At least two timestamps must be supplied"; - this.timestamps = timestamps; - this.values = values; - this.step = timestamps[1] - timestamps[0]; - } - - Aggregates getAggregates(long tStart, long tEnd) { - Aggregates agg = new Aggregates(); - int cnt = 0; - int lslstep = 0; - boolean firstFound = false; - double SUMx, SUMy, SUMxy, SUMxx, SUMyy; - SUMx = 0.0; - SUMy = 0.0; - SUMxy = 0.0; - SUMxx = 0.0; - SUMyy = 0.0; - - for (int i = 0; i < timestamps.length; i++) { - long left = Math.max(timestamps[i] - step, tStart); - long right = Math.min(timestamps[i], tEnd); - long delta = right - left; - - // delta is only >= 0 when the timestamp for a given buck is within the range of tStart and tEnd - if (delta >= 0) { - double value = values[i]; - agg.min = Util.min(agg.min, value); - agg.max = Util.max(agg.max, value); - if (!firstFound) { - agg.first = value; - firstFound = true; - agg.last = value; - } else if (delta >= step) { // an entire bucket is included in this range - agg.last = value; - - /* - * Algorithmically, we're only updating last if it's either the first - * bucket encountered, or it's a "full" bucket. - - if ( !isInRange(tEnd, left, right) || - (isInRange(tEnd, left, right) && !Double.isNaN(value)) - ) { - agg.last = value; - } - */ - - } - if (!Double.isNaN(value)) { - cnt++; - SUMx += lslstep; - SUMxx += lslstep * lslstep; - SUMy = Util.sum(SUMy, value); - SUMxy = Util.sum(SUMxy, lslstep * value); - SUMyy = Util.sum(SUMyy, value * value); - } - lslstep ++; - } - } - agg.average = cnt > 0 ? (SUMy / cnt) : Double.NaN; - - // Work on STDEV - if (cnt > 0) { - double stdevSum = 0.0; - for (int i = 0; i < timestamps.length; i++) { - long left = Math.max(timestamps[i] - step, tStart); - long right = Math.min(timestamps[i], tEnd); - long delta = right - left; - - // delta is only >= 0 when the timestamp for a given buck is within the range of tStart and tEnd - if (delta >= 0) { - double value = values[i]; - if (!Double.isNaN(value)) { - stdevSum = Util.sum(stdevSum, Math.pow((value - agg.average), 2.0)); - } - } - } - agg.stdev = Math.pow(stdevSum / cnt, 0.5); - - /* Bestfit line by linear least squares method */ - agg.lslslope = (SUMx * SUMy - cnt * SUMxy) / (SUMx * SUMx - cnt * SUMxx); - agg.lslint = (SUMy - agg.lslslope * SUMx) / cnt; - agg.lslcorrel = - (SUMxy - (SUMx * SUMy) / cnt) / - Math.sqrt((SUMxx - (SUMx * SUMx) / cnt) * (SUMyy - (SUMy * SUMy) / cnt)); - } - agg.total = SUMy * step; - - return agg; - } - - double getPercentile(long tStart, long tEnd, double percentile) { - return getPercentile(tStart, tEnd, percentile, false); - } - - double getPercentile(long tStart, long tEnd, double percentile, boolean includenan) { - List<Double> valueList = new ArrayList<Double>(); - // create a list of included datasource values (different from NaN) - for (int i = 0; i < timestamps.length; i++) { - long left = Math.max(timestamps[i] - step, tStart); - long right = Math.min(timestamps[i], tEnd); - if (right > left && (!Double.isNaN(values[i]) || includenan)) { - valueList.add(values[i]); - } - } - // create an array to work with - int count = valueList.size(); - if (count > 1) { - double[] valuesCopy = new double[count]; - for (int i = 0; i < count; i++) { - valuesCopy[i] = valueList.get(i); - } - // sort array - Arrays.sort(valuesCopy); - // skip top (100% - percentile) values - double topPercentile = (100.0 - percentile) / 100.0; - count -= (int) Math.ceil(count * topPercentile); - // if we have anything left... - if (count > 0) { - return valuesCopy[count - 1]; - } - } - // not enough data available - return Double.NaN; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/CDef.java b/apps/jrobin/java/src/org/jrobin/data/CDef.java deleted file mode 100644 index 639c36d0c59410b1f89e31e1c6b4228f3eebf8bc..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/CDef.java +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -class CDef extends Source { - private String rpnExpression; - - CDef(String name, String rpnExpression) { - super(name); - this.rpnExpression = rpnExpression; - } - - String getRpnExpression() { - return rpnExpression; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/CubicSplineInterpolator.java b/apps/jrobin/java/src/org/jrobin/data/CubicSplineInterpolator.java deleted file mode 100644 index d86666805398af5a4266faacd75e797c04edb19f..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/CubicSplineInterpolator.java +++ /dev/null @@ -1,196 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.data; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; - -import java.util.Calendar; -import java.util.Date; - -/** - * Class used to interpolate datasource values from the collection of (timestamp, values) - * points using natural cubic spline interpolation. - * <p> - * <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. - */ -public class CubicSplineInterpolator extends Plottable { - private double[] x; - private double[] y; - - // second derivates come here - private double[] y2; - - // internal spline variables - private int n, klo, khi; - - /** - * Creates cubic spline interpolator from arrays of timestamps and corresponding - * datasource values. - * - * @param timestamps timestamps in seconds - * @param values corresponding datasource values - * @throws RrdException Thrown if supplied arrays do not contain at least 3 values, or if - * timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN. - */ - public CubicSplineInterpolator(long[] timestamps, double[] values) throws RrdException { - this.x = new double[timestamps.length]; - for (int i = 0; i < timestamps.length; i++) { - this.x[i] = timestamps[i]; - } - this.y = values; - validate(); - spline(); - } - - /** - * Creates cubic spline interpolator from arrays of Date objects and corresponding - * datasource values. - * - * @param dates Array of Date objects - * @param values corresponding datasource values - * @throws RrdException Thrown if supplied arrays do not contain at least 3 values, or if - * timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN. - */ - public CubicSplineInterpolator(Date[] dates, double[] values) throws RrdException { - this.x = new double[dates.length]; - for (int i = 0; i < dates.length; i++) { - this.x[i] = Util.getTimestamp(dates[i]); - } - this.y = values; - validate(); - spline(); - } - - /** - * Creates cubic spline interpolator from arrays of GregorianCalendar objects and corresponding - * datasource values. - * - * @param dates Array of GregorianCalendar objects - * @param values corresponding datasource values - * @throws RrdException Thrown if supplied arrays do not contain at least 3 values, or if - * timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN. - */ - public CubicSplineInterpolator(Calendar[] dates, double[] values) throws RrdException { - this.x = new double[dates.length]; - for (int i = 0; i < dates.length; i++) { - this.x[i] = Util.getTimestamp(dates[i]); - } - this.y = values; - validate(); - spline(); - } - - /** - * Creates cubic spline interpolator for an array of 2D-points. - * - * @param x x-axis point coordinates - * @param y y-axis point coordinates - * @throws RrdException Thrown if supplied arrays do not contain at least 3 values, or if - * timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN. - */ - public CubicSplineInterpolator(double[] x, double[] y) throws RrdException { - this.x = x; - this.y = y; - validate(); - spline(); - } - - private void validate() throws RrdException { - boolean ok = true; - if (x.length != y.length || x.length < 3) { - ok = false; - } - for (int i = 0; i < x.length - 1 && ok; i++) { - if (x[i] >= x[i + 1] || Double.isNaN(y[i])) { - ok = false; - } - } - if (!ok) { - throw new RrdException("Invalid plottable data supplied"); - } - } - - private void spline() { - n = x.length; - y2 = new double[n]; - double[] u = new double[n - 1]; - y2[0] = y2[n - 1] = 0.0; - u[0] = 0.0; // natural spline - for (int i = 1; i <= n - 2; i++) { - double sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); - double p = sig * y2[i - 1] + 2.0; - y2[i] = (sig - 1.0) / p; - u[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]); - u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; - } - for (int k = n - 2; k >= 0; k--) { - y2[k] = y2[k] * y2[k + 1] + u[k]; - } - // prepare everything for getValue() - klo = 0; - khi = n - 1; - } - - /** - * Calculates spline-interpolated y-value for the corresponding x-value. Call - * this if you need spline-interpolated values in your code. - * - * @param xval x-value - * @return inteprolated y-value - */ - public double getValue(double xval) { - if (xval < x[0] || xval > x[n - 1]) { - return Double.NaN; - } - if (xval < x[klo] || xval > x[khi]) { - // out of bounds - klo = 0; - khi = n - 1; - } - while (khi - klo > 1) { - // find bounding interval using bisection method - int k = (khi + klo) >>> 1; - if (x[k] > xval) { - khi = k; - } - else { - klo = k; - } - } - double h = x[khi] - x[klo]; - double a = (x[khi] - xval) / h; - double b = (xval - x[klo]) / h; - return a * y[klo] + b * y[khi] + - ((a * a * a - a) * y2[klo] + (b * b * b - b) * y2[khi]) * (h * h) / 6.0; - } - - /** - * Method overriden from the base class. This method will be called by the framework. Call - * this method only if you need spline-interpolated values in your code. - * - * @param timestamp timestamp in seconds - * @return inteprolated datasource value - */ - public double getValue(long timestamp) { - return getValue((double) timestamp); - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/data/DataProcessor.java b/apps/jrobin/java/src/org/jrobin/data/DataProcessor.java deleted file mode 100644 index a258068342deaf12ea6f13250a794223b44f6ede..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/DataProcessor.java +++ /dev/null @@ -1,936 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -import org.jrobin.core.*; - -import java.io.IOException; -import java.util.*; - -/** - * 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), - * SDEF (static datasources - extension of JRobin) and PDEF (plottables, see - * {@link Plottable Plottable} for more information. - * <p> - * Typical class usage: - * <p> - * <pre> - * final long t1 = ... - * final long t2 = ... - * DataProcessor dp = new DataProcessor(t1, t2); - * // DEF datasource - * dp.addDatasource("x", "demo.rrd", "some_source", "AVERAGE"); - * // DEF datasource - * dp.addDatasource("y", "demo.rrd", "some_other_source", "AVERAGE"); - * // CDEF datasource, z = (x + y) / 2 - * dp.addDatasource("z", "x,y,+,2,/"); - * // ACTION! - * dp.processData(); - * // Dump calculated values - * System.out.println(dp.dump()); - * </pre> - */ -public class DataProcessor implements ConsolFuns { - /** - * Constant representing the default number of pixels on a JRobin graph (will be used if - * no other value is specified with {@link #setStep(long) setStep()} method. - */ - public static final int DEFAULT_PIXEL_COUNT = 600; - private static final double DEFAULT_PERCENTILE = 95.0; // % - - private int pixelCount = DEFAULT_PIXEL_COUNT; - - /** - * 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 final long tStart; - private long tEnd, timestamps[]; - private long lastRrdArchiveUpdateTime = 0; - // this will be adjusted later - private long step = 0; - // resolution to be used for RRD fetch operation - private long fetchRequestResolution = 1; - - // the order is important, ordinary HashMap is unordered - private Map<String, Source> sources = new LinkedHashMap<String, Source>(); - - private Def[] defSources; - - /** - * Creates new DataProcessor object for the given time span. Ending timestamp may be set to zero. - * In that case, the class will try to find the optimal ending timestamp based on the last update time of - * RRD files processed with the {@link #processData()} method. - * - * @param t1 Starting timestamp in seconds without milliseconds - * @param t2 Ending timestamp in seconds without milliseconds - * @throws RrdException Thrown if invalid timestamps are supplied - */ - public DataProcessor(long t1, long t2) throws RrdException { - if ((t1 < t2 && t1 > 0 && t2 > 0) || (t1 > 0 && t2 == 0)) { - this.tStart = t1; - this.tEnd = t2; - } - else { - throw new RrdException("Invalid timestamps specified: " + t1 + ", " + t2); - } - } - - /** - * Creates new DataProcessor object for the given time span. Ending date may be set to null. - * In that case, the class will try to find optimal ending date based on the last update time of - * RRD files processed with the {@link #processData()} method. - * - * @param d1 Starting date - * @param d2 Ending date - * @throws RrdException Thrown if invalid timestamps are supplied - */ - public DataProcessor(Date d1, Date d2) throws RrdException { - this(Util.getTimestamp(d1), d2 != null ? Util.getTimestamp(d2) : 0); - } - - /** - * Creates new DataProcessor object for the given time span. Ending date may be set to null. - * In that case, the class will try to find optimal ending date based on the last update time of - * RRD files processed with the {@link #processData()} method. - * - * @param gc1 Starting Calendar date - * @param gc2 Ending Calendar date - * @throws RrdException Thrown if invalid timestamps are supplied - */ - public DataProcessor(Calendar gc1, Calendar gc2) throws RrdException { - this(Util.getTimestamp(gc1), gc2 != null ? Util.getTimestamp(gc2) : 0); - } - - /** - * Returns boolean value representing {@link org.jrobin.core.RrdDbPool RrdDbPool} usage policy. - * - * @return true, if the pool will be used internally to fetch data from RRD files, false otherwise. - */ - public boolean isPoolUsed() { - return poolUsed; - } - - /** - * Sets the {@link org.jrobin.core.RrdDbPool RrdDbPool} usage policy. - * - * @param poolUsed true, if the pool should be used to fetch data from RRD files, false otherwise. - */ - public void setPoolUsed(boolean poolUsed) { - this.poolUsed = poolUsed; - } - - /** - * Sets the number of pixels (target graph width). This number is used only to calculate pixel coordinates - * for JRobin graphs (methods {@link #getValuesPerPixel(String)} and {@link #getTimestampsPerPixel()}), - * but has influence neither on datasource values calculated with the - * {@link #processData()} method nor on aggregated values returned from {@link #getAggregates(String)} - * 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. - */ - public void setPixelCount(int pixelCount) { - this.pixelCount = pixelCount; - } - - /** - * Returns the number of pixels (target graph width). See {@link #setPixelCount(int)} for more information. - * - * @return Target graph width - */ - public int getPixelCount() { - return pixelCount; - } - - /** - * Roughly corresponds to the --step option in RRDTool's graph/xport commands. Here is an explanation borrowed - * from RRDTool: - * <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> - * 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). - */ - 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. - * - * @return Step used for data processing. - */ - public long getStep() { - return step; - } - - /** - * Returns desired RRD archive step (reslution) in seconds to be used while fetching data - * from RRD files. In other words, this value will used as the last parameter of - * {@link RrdDb#createFetchRequest(String, long, long, long) RrdDb.createFetchRequest()} method - * when this method is called internally by this DataProcessor. - * - * @return Desired archive step (fetch resolution) in seconds. - */ - public long getFetchRequestResolution() { - return fetchRequestResolution; - } - - /** - * Sets desired RRD archive step in seconds to be used internally while fetching data - * from RRD files. In other words, this value will used as the last parameter of - * {@link RrdDb#createFetchRequest(String, long, long, long) RrdDb.createFetchRequest()} method - * when this method is called internally by this DataProcessor. If this method is never called, fetch - * request resolution defaults to 1 (smallest possible archive step will be chosen automatically). - * - * @param fetchRequestResolution Desired archive step (fetch resoltuion) in seconds. - */ - public void setFetchRequestResolution(long fetchRequestResolution) { - this.fetchRequestResolution = fetchRequestResolution; - } - - /** - * Returns ending timestamp. Basically, this value is equal to the ending timestamp - * specified in the constructor. However, if the ending timestamps was zero, it - * will be replaced with the real timestamp when the {@link #processData()} method returns. The real - * value will be calculated from the last update times of processed RRD files. - * - * @return Ending timestamp in seconds - */ - public long getEndingTimestamp() { - return tEnd; - } - - /** - * Returns consolidated timestamps created with the {@link #processData()} method. - * - * @return array of timestamps in seconds - * @throws RrdException thrown if timestamps are not calculated yet - */ - public long[] getTimestamps() throws RrdException { - if (timestamps == null) { - throw new RrdException("Timestamps not calculated yet"); - } - else { - return timestamps; - } - } - - /** - * Returns calculated values for a single datasource. Corresponding timestamps can be obtained from - * the {@link #getTimestamps()} method. - * - * @param sourceName Datasource name - * @return an array of datasource values - * @throws RrdException Thrown if invalid datasource name is specified, - * or if datasource values are not yet calculated (method {@link #processData()} - * was not called) - */ - public double[] getValues(String sourceName) throws RrdException { - Source source = getSource(sourceName); - double[] values = source.getValues(); - if (values == null) { - throw new RrdException("Values not available for source [" + sourceName + "]"); - } - return values; - } - - /** - * Returns single aggregated value for a single datasource. - * - * @param sourceName Datasource name - * @param consolFun Consolidation function to be applied to fetched datasource values. - * Valid consolidation functions are MIN, MAX, LAST, FIRST, AVERAGE and TOTAL - * (these string constants are conveniently defined in the {@link ConsolFuns} class) - * @return MIN, MAX, LAST, FIRST, AVERAGE or TOTAL value calculated from the data - * for the given datasource name - * @throws RrdException Thrown if invalid datasource name is specified, - * or if datasource values are not yet calculated (method {@link #processData()} - * was not called) - */ - public double getAggregate(String sourceName, String consolFun) throws RrdException { - Source source = getSource(sourceName); - return source.getAggregates(tStart, tEnd).getAggregate(consolFun); - } - - /** - * Returns all (MIN, MAX, LAST, FIRST, AVERAGE and TOTAL) aggregated values for a single datasource. - * - * @param sourceName Datasource name - * @return Object containing all aggregated values - * @throws RrdException Thrown if invalid datasource name is specified, - * or if datasource values are not yet calculated (method {@link #processData()} - * was not called) - */ - public Aggregates getAggregates(String sourceName) throws RrdException { - Source source = getSource(sourceName); - return source.getAggregates(tStart, tEnd); - } - - /** - * This method is just an alias for {@link #getPercentile(String)} method. - * <p> - * Used by ISPs which charge for bandwidth utilization on a "95th percentile" basis. - * <p> - * The 95th percentile is the highest source value left when the top 5% of a numerically sorted set - * of source data is discarded. It is used as a measure of the peak value used when one discounts - * a fair amount for transitory spikes. This makes it markedly different from the average. - * <p> - * Read more about this topic at - * <a href="http://www.red.net/support/resourcecentre/leasedline/percentile.php">Rednet</a> or - * <a href="http://www.bytemark.co.uk/support/tech/95thpercentile.html">Bytemark</a>. - * - * @param sourceName Datasource name - * @return 95th percentile of fetched source values - * @throws RrdException Thrown if invalid source name is supplied - */ - public double get95Percentile(String sourceName) throws RrdException { - return getPercentile(sourceName); - } - - /** - * Used by ISPs which charge for bandwidth utilization on a "95th percentile" basis. - * <p> - * The 95th percentile is the highest source value left when the top 5% of a numerically sorted set - * of source data is discarded. It is used as a measure of the peak value used when one discounts - * a fair amount for transitory spikes. This makes it markedly different from the average. - * <p> - * Read more about this topic at - * <a href="http://www.red.net/support/resourcecentre/leasedline/percentile.php">Rednet</a> or - * <a href="http://www.bytemark.co.uk/support/tech/95thpercentile.html">Bytemark</a>. - * - * @param sourceName Datasource name - * @return 95th percentile of fetched source values - * @throws RrdException Thrown if invalid source name is supplied - */ - public double getPercentile(String sourceName) throws RrdException { - return getPercentile(sourceName, DEFAULT_PERCENTILE); - } - - /** - * The same as {@link #getPercentile(String)} but with a possibility to define custom percentile boundary - * (different from 95). - * - * @param sourceName Datasource name. - * @param percentile Boundary percentile. Value of 95 (%) is suitable in most cases, but you are free - * to provide your own percentile boundary between zero and 100. - * @return Requested percentile of fetched source values - * @throws RrdException Thrown if invalid sourcename is supplied, or if the percentile value makes no sense. - */ - public double getPercentile(String sourceName, double percentile) throws RrdException { - if (percentile <= 0.0 || percentile > 100.0) { - throw new RrdException("Invalid percentile [" + percentile + "], should be between 0 and 100"); - } - Source source = getSource(sourceName); - return source.getPercentile(tStart, tEnd, percentile); - } - - /** - * Returns array of datasource names defined in this DataProcessor. - * - * @return array of datasource names - */ - public String[] getSourceNames() { - return sources.keySet().toArray(new String[0]); - } - - /** - * Returns an array of all datasource values for all datasources. Each row in this two-dimensional - * array represents an array of calculated values for a single datasource. The order of rows is the same - * as the order in which datasources were added to this DataProcessor object. - * - * @return All datasource values for all datasources. The first index is the index of the datasource, - * the second index is the index of the datasource value. The number of datasource values is equal - * to the number of timestamps returned with {@link #getTimestamps()} method. - * @throws RrdException Thrown if invalid datasource name is specified, - * or if datasource values are not yet calculated (method {@link #processData()} - * was not called) - */ - public double[][] getValues() throws RrdException { - String[] names = getSourceNames(); - double[][] values = new double[names.length][]; - for (int i = 0; i < names.length; i++) { - values[i] = getValues(names[i]); - } - return values; - } - - private Source getSource(String sourceName) throws RrdException { - Source source = sources.get(sourceName); - if (source != null) { - return source; - } - throw new RrdException("Unknown source: " + sourceName); - } - - ///////////////////////////////////////////////////////////////// - // DATASOURCE DEFINITIONS - ///////////////////////////////////////////////////////////////// - - /** - * Adds a custom, {@link org.jrobin.data.Plottable plottable} datasource (<b>PDEF</b>). - * The datapoints should be made available by a class extending - * {@link org.jrobin.data.Plottable Plottable} class. - * <p> - * - * @param name source name. - * @param plottable class that extends Plottable class and is suited for graphing. - */ - public void addDatasource(String name, Plottable plottable) { - PDef pDef = new PDef(name, plottable); - sources.put(name, pDef); - } - - /** - * 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> - * <p> - * JRobin supports the following RPN functions, operators and constants: +, -, *, /, - * %, SIN, COS, LOG, EXP, FLOOR, CEIL, ROUND, POW, ABS, SQRT, RANDOM, LT, LE, GT, GE, EQ, - * IF, MIN, MAX, LIMIT, DUP, EXC, POP, UN, UNKN, NOW, TIME, PI, E, - * AND, OR, XOR, PREV, PREV(sourceName), INF, NEGINF, STEP, YEAR, MONTH, DATE, - * HOUR, MINUTE, SECOND, WEEK, SIGN and RND. - * <p> - * JRobin 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://people.ee.ethz.ch/~oetiker/webtools/rrdtool/manual/rrdgraph.html" target="man"> - * rrdgraph man page</a>. - * - * @param name source name. - * @param rpnExpression RPN expression containig comma (or space) delimited simple and complex - * source names, RPN constants, functions and operators. - */ - public void addDatasource(String name, String rpnExpression) { - CDef cDef = new CDef(name, rpnExpression); - sources.put(name, cDef); - } - - /** - * Adds static source (<b>SDEF</b>). Static sources are the result of a consolidation function applied - * to *any* other source that has been defined previously. - * - * @param name source name. - * @param defName Name of the datasource to calculate the value from. - * @param consolFun Consolidation function to use for value calculation - */ - public void addDatasource(String name, String defName, String consolFun) { - SDef sDef = new SDef(name, defName, consolFun); - sources.put(name, sDef); - } - - /** - * <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 - * file ("AVERAGE", "MIN", "MAX" or "LAST" - these string constants are conveniently defined - * in the {@link org.jrobin.core.ConsolFuns ConsolFuns} class). - */ - public void addDatasource(String name, String file, String dsName, String consolFunc) { - Def def = new Def(name, file, dsName, consolFunc); - 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 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.jrobin.core.ConsolFuns ConsolFuns} class). - * @param backend Name of the RrdBackendFactory that should be used for this RrdDb. - */ - public void addDatasource(String name, String file, String dsName, String consolFunc, String backend) { - Def def = new Def(name, file, dsName, consolFunc, backend); - sources.put(name, def); - } - - /** - * Adds DEF datasource with datasource values already available in the FetchData object. This method is - * used internally by JRobin and probably has no purpose outside of it. - * - * @param name Source name. - * @param fetchData Fetched data containing values for the given source name. - */ - public void addDatasource(String name, FetchData fetchData) { - Def def = new Def(name, fetchData); - sources.put(name, def); - } - - /** - * Creates a new VDEF datasource that performs a percentile calculation on an - * another named datasource to yield a single 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 sourceName - the datasource from which to extract the percentile. Must be a previously - * defined virtual datasource - * @param percentile - the percentile to extract from the source datasource - */ - public void addDatasource(String name, String sourceName, double percentile) { - Source source = sources.get(sourceName); - sources.put(name, new PercentileDef(name, source, percentile)); - } - - /** - * Creates a new VDEF datasource that performs a percentile calculation on an - * another named datasource to yield a single 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 sourceName - the datasource from which to extract the percentile. Must be a previously - * defined virtual datasource - * @param percentile - the percentile to extract from the source datasource - * @param ignorenan - true if we include Double.NaN - */ - public void addDatasource(String name, String sourceName, double percentile, boolean ignorenan) { - Source source = sources.get(sourceName); - sources.put(name, new PercentileDef(name, source, percentile, ignorenan)); - } - - ///////////////////////////////////////////////////////////////// - // CALCULATIONS - ///////////////////////////////////////////////////////////////// - - /** - * Method that should be called once all datasources are defined. Data will be fetched from - * RRD files, RPN expressions will be calculated, etc. - * - * @throws IOException Thrown in case of I/O error (while fetching data from RRD files) - * @throws RrdException Thrown in case of JRobin specific error - */ - public void processData() throws IOException, RrdException { - extractDefs(); - fetchRrdData(); - fixZeroEndingTimestamp(); - chooseOptimalStep(); - createTimestamps(); - assignTimestampsToSources(); - normalizeRrdValues(); - calculateNonRrdSources(); - } - - /** - * Method used to calculate datasource values which should be presented on the graph - * based on the desired graph width. Each value returned represents a single pixel on the graph. - * Corresponding timestamp can be found in the array returned from {@link #getTimestampsPerPixel()} - * method. - * - * @param sourceName Datasource name - * @param pixelCount Graph width - * @return Per-pixel datasource values - * @throws RrdException Thrown if datasource values are not yet calculated (method {@link #processData()} - * was not called) - */ - public double[] getValuesPerPixel(String sourceName, int pixelCount) throws RrdException { - setPixelCount(pixelCount); - return getValuesPerPixel(sourceName); - } - - /** - * Method used to calculate datasource values which should be presented on the graph - * based on the graph width set with a {@link #setPixelCount(int)} method call. - * Each value returned represents a single pixel on the graph. Corresponding timestamp can be - * found in the array returned from {@link #getTimestampsPerPixel()} method. - * - * @param sourceName Datasource name - * @return Per-pixel datasource values - * @throws RrdException Thrown if datasource values are not yet calculated (method {@link #processData()} - * was not called) - */ - public double[] getValuesPerPixel(String sourceName) throws RrdException { - double[] values = getValues(sourceName); - double[] pixelValues = new double[pixelCount]; - Arrays.fill(pixelValues, Double.NaN); - long span = tEnd - tStart; - // this is the ugliest nested loop I have ever made - for (int pix = 0, ref = 0; pix < pixelCount; pix++) { - double t = tStart + (double) (span * pix) / (double) (pixelCount - 1); - while (ref < timestamps.length) { - if (t <= timestamps[ref] - step) { - // too left, nothing to do, already NaN - break; - } - else if (t <= timestamps[ref]) { - // in brackets, get this value - pixelValues[pix] = values[ref]; - break; - } - else { - // too right - ref++; - } - } - } - return pixelValues; - } - - /** - * Calculates timestamps which correspond to individual pixels on the graph. - * - * @param pixelCount Graph width - * @return Array of timestamps - */ - public long[] getTimestampsPerPixel(int pixelCount) { - setPixelCount(pixelCount); - return getTimestampsPerPixel(); - } - - /** - * Calculates timestamps which correspond to individual pixels on the graph - * based on the graph width set with a {@link #setPixelCount(int)} method call. - * - * @return Array of timestamps - */ - public long[] getTimestampsPerPixel() { - long[] times = new long[pixelCount]; - long span = tEnd - tStart; - for (int i = 0; i < pixelCount; i++) { - times[i] = Math.round(tStart + (double) (span * i) / (double) (pixelCount - 1)); - } - return times; - } - - /** - * Dumps timestamps and values of all datasources in a tabelar form. Very useful for debugging. - * - * @return Dumped object content. - * @throws RrdException Thrown if nothing is calculated so far (the method {@link #processData()} - * was not called). - */ - public String dump() throws RrdException { - String[] names = getSourceNames(); - double[][] values = getValues(); - StringBuilder buffer = new StringBuilder(); - buffer.append(format("timestamp", 12)); - for (String name : names) { - buffer.append(format(name, 20)); - } - buffer.append("\n"); - for (int i = 0; i < timestamps.length; i++) { - buffer.append(format("" + timestamps[i], 12)); - for (int j = 0; j < names.length; j++) { - buffer.append(format(Util.formatDouble(values[j][i]), 20)); - } - buffer.append("\n"); - } - return buffer.toString(); - } - - /** - * Returns time when last RRD archive was updated (all RRD files are considered). - * - * @return Last archive update time for all RRD files in this DataProcessor - */ - public long getLastRrdArchiveUpdateTime() { - return lastRrdArchiveUpdateTime; - } - - // 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()]); - } - - private void fetchRrdData() throws IOException, RrdException { - 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()); - } - } - // now we have everything - RrdDb rrd = null; - try { - rrd = getRrd(defSources[i]); - lastRrdArchiveUpdateTime = Math.max(lastRrdArchiveUpdateTime, rrd.getLastArchiveUpdateTime()); - FetchRequest req = rrd.createFetchRequest(defSources[i].getConsolFun(), - tStart, tEndFixed, fetchRequestResolution); - req.setFilter(dsNames); - FetchData data = req.fetchData(); - defSources[i].setFetchData(data); - for (int j = i + 1; j < defSources.length; j++) { - if (defSources[i].isCompatibleWith(defSources[j])) { - defSources[j].setFetchData(data); - } - } - } - finally { - if (rrd != null) { - releaseRrd(rrd, defSources[i]); - } - } - } - } - } - - private void fixZeroEndingTimestamp() throws RrdException { - if (tEnd == 0) { - if (defSources.length == 0) { - throw new RrdException("Could not adjust zero ending timestamp, no DEF source provided"); - } - tEnd = defSources[0].getArchiveEndTime(); - for (int i = 1; i < defSources.length; i++) { - tEnd = Math.min(tEnd, defSources[i].getArchiveEndTime()); - } - if (tEnd <= tStart) { - throw new RrdException("Could not resolve zero ending timestamp."); - } - } - } - - // Tricky and ugly. Should be redesigned some time in the future - private void chooseOptimalStep() { - long newStep = Long.MAX_VALUE; - for (Def defSource : defSources) { - long fetchStep = defSource.getFetchStep(), tryStep = fetchStep; - if (step > 0) { - tryStep = Math.min(newStep, (((step - 1) / fetchStep) + 1) * fetchStep); - } - newStep = Math.min(newStep, tryStep); - } - if (newStep != Long.MAX_VALUE) { - // step resolved from a RRD file - step = newStep; - } - else { - // choose step based on the number of pixels (useful for plottable datasources) - step = Math.max((tEnd - tStart) / pixelCount, 1); - } - } - - private void createTimestamps() { - long t1 = Util.normalize(tStart, step); - long t2 = Util.normalize(tEnd, step); - if (t2 < tEnd) { - t2 += step; - } - int count = (int) (((t2 - t1) / step) + 1); - timestamps = new long[count]; - for (int i = 0; i < count; i++) { - timestamps[i] = t1; - t1 += step; - } - } - - private void assignTimestampsToSources() { - for (Source src : sources.values()) { - src.setTimestamps(timestamps); - } - } - - private void normalizeRrdValues() throws RrdException { - Normalizer normalizer = new Normalizer(timestamps); - for (Def def : defSources) { - long[] rrdTimestamps = def.getRrdTimestamps(); - double[] rrdValues = def.getRrdValues(); - double[] values = normalizer.normalize(rrdTimestamps, rrdValues); - def.setValues(values); - } - } - - private void calculateNonRrdSources() throws RrdException { - for (Source source : sources.values()) { - if (source instanceof SDef) { - calculateSDef((SDef) source); - } - else if (source instanceof CDef) { - calculateCDef((CDef) source); - } - else if (source instanceof PDef) { - calculatePDef((PDef) source); - } - else if (source instanceof PercentileDef) { - calculatePercentileDef((PercentileDef) source); - } - } - } - - private void calculatePDef(PDef pdef) { - pdef.calculateValues(); - } - - private void calculateCDef(CDef cDef) throws RrdException { - RpnCalculator calc = new RpnCalculator(cDef.getRpnExpression(), cDef.getName(), this); - cDef.setValues(calc.calculateValues()); - } - - private void calculateSDef(SDef sDef) throws RrdException { - String defName = sDef.getDefName(); - String consolFun = sDef.getConsolFun(); - Source source = getSource(defName); - if (consolFun.equals("MAXIMUM")) { consolFun = "MAX"; } - else if (consolFun.equals("MINIMUM")) { consolFun = "MIN"; } - double value = source.getAggregates(tStart, tEnd).getAggregate(consolFun); - sDef.setValue(value); - } - - //Yeah, this is different from the other calculation methods - // Frankly, this is how it *should* be done, and the other methods will - // be refactored to this design (and the instanceof's removed) at some point - private void calculatePercentileDef(PercentileDef def) throws RrdException { - def.calculate(tStart, tEnd); - } - - - private RrdDb getRrd(Def def) throws IOException, RrdException { - String path = def.getPath(), backend = def.getBackend(); - if (poolUsed && backend == null) { - return RrdDbPool.getInstance().requestRrdDb(path); - } - else if (backend != null) { - return new RrdDb(path, true, RrdBackendFactory.getFactory(backend)); - } - else { - return new RrdDb(path, true); - } - } - - private void releaseRrd(RrdDb rrd, Def def) throws IOException, RrdException { - String backend = def.getBackend(); - if (poolUsed && backend == null) { - RrdDbPool.getInstance().release(rrd); - } - else { - rrd.close(); - } - } - - private static String format(String s, int length) { - StringBuilder b = new StringBuilder(s); - for (int i = 0; i < length - s.length(); i++) { - b.append(' '); - } - return b.toString(); - } - - /** - * Cute little demo. Uses demo.rrd file previously created by basic JRobin demo. - * - * @param args Not used - * @throws IOException if an I/O error occurs. - * @throws RrdException Thrown if internal jrobin error occurs. - */ - public static void main(String[] args) throws IOException, RrdException { - // time span - long t1 = Util.getTimestamp(2003, 4, 1); - long t2 = Util.getTimestamp(2003, 5, 1); - System.out.println("t1 = " + t1); - System.out.println("t2 = " + t2); - - // RRD file to use - String rrdPath = Util.getJRobinDemoPath("demo.rrd"); - - // constructor - DataProcessor dp = new DataProcessor(t1, t2); - - // uncomment and run again - //dp.setFetchRequestResolution(86400); - - // uncomment and run again - //dp.setStep(86500); - - // datasource definitions - dp.addDatasource("X", rrdPath, "sun", "AVERAGE"); - dp.addDatasource("Y", rrdPath, "shade", "AVERAGE"); - dp.addDatasource("Z", "X,Y,+,2,/"); - dp.addDatasource("DERIVE[Z]", "Z,PREV(Z),-,STEP,/"); - dp.addDatasource("TREND[Z]", "DERIVE[Z],SIGN"); - dp.addDatasource("AVG[Z]", "Z", "AVERAGE"); - dp.addDatasource("DELTA", "Z,AVG[Z],-"); - - // action - long laptime = System.currentTimeMillis(); - //dp.setStep(86400); - dp.processData(); - System.out.println("Data processed in " + (System.currentTimeMillis() - laptime) + " milliseconds\n---"); - System.out.println(dp.dump()); - - // aggregates - System.out.println("\nAggregates for X"); - Aggregates agg = dp.getAggregates("X"); - System.out.println(agg.dump()); - System.out.println("\nAggregates for Y"); - agg = dp.getAggregates("Y"); - System.out.println(agg.dump()); - - // 95-percentile - System.out.println("\n95-percentile for X: " + Util.formatDouble(dp.get95Percentile("X"))); - System.out.println("95-percentile for Y: " + Util.formatDouble(dp.get95Percentile("Y"))); - - // lastArchiveUpdateTime - System.out.println("\nLast archive update time was: " + dp.getLastRrdArchiveUpdateTime()); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/Def.java b/apps/jrobin/java/src/org/jrobin/data/Def.java deleted file mode 100644 index defd84fce05b7a60bbaf42085571604a60371ffc..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/Def.java +++ /dev/null @@ -1,113 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -import org.jrobin.core.FetchData; -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; - -import java.io.IOException; - -class Def extends Source { - private String path, dsName, consolFun, backend; - private FetchData fetchData; - - Def(String name, FetchData fetchData) { - this(name, null, name, null, null); - setFetchData(fetchData); - } - - Def(String name, String path, String dsName, String consolFunc) { - this(name, path, dsName, consolFunc, null); - } - - Def(String name, String path, String dsName, String consolFunc, String backend) { - super(name); - this.path = path; - this.dsName = dsName; - this.consolFun = consolFunc; - this.backend = backend; - } - - String getPath() { - return path; - } - - String getCanonicalPath() throws IOException { - return Util.getCanonicalPath(path); - } - - String getDsName() { - return dsName; - } - - String getConsolFun() { - return consolFun; - } - - String getBackend() { - return backend; - } - - boolean isCompatibleWith(Def def) throws IOException { - return getCanonicalPath().equals(def.getCanonicalPath()) && - getConsolFun().equals(def.consolFun) && - ((backend == null && def.backend == null) || - (backend != null && def.backend != null && backend.equals(def.backend))); - } - - void setFetchData(FetchData fetchData) { - this.fetchData = fetchData; - } - - long[] getRrdTimestamps() { - return fetchData.getTimestamps(); - } - - double[] getRrdValues() throws RrdException { - return fetchData.getValues(dsName); - } - - long getArchiveEndTime() { - return fetchData.getArcEndTime(); - } - - long getFetchStep() { - return fetchData.getStep(); - } - - Aggregates getAggregates(long tStart, long tEnd) throws RrdException { - long[] t = getRrdTimestamps(); - double[] v = getRrdValues(); - Aggregator agg = new Aggregator(t, v); - return agg.getAggregates(tStart, tEnd); - } - - double getPercentile(long tStart, long tEnd, double percentile) throws RrdException { - long[] t = getRrdTimestamps(); - double[] v = getRrdValues(); - Aggregator agg = new Aggregator(t, v); - return agg.getPercentile(tStart, tEnd, percentile); - } - - boolean isLoaded() { - return fetchData != null; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/LinearInterpolator.java b/apps/jrobin/java/src/org/jrobin/data/LinearInterpolator.java deleted file mode 100644 index b64434517515a01cd2a898a4cb77b806195e3de3..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/LinearInterpolator.java +++ /dev/null @@ -1,248 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.data; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; - -import java.util.Calendar; -import java.util.Date; - -/** - * Class used to interpolate datasource values from the collection of (timestamp, values) - * points. This class is suitable for linear interpolation only. - * <p> - * Interpolation algorithm returns different values based on the value passed to - * {@link #setInterpolationMethod(int) setInterpolationMethod()}. If not set, interpolation - * method defaults to standard linear interpolation ({@link #INTERPOLATE_LINEAR}). - * Interpolation method handles NaN datasource - * values gracefully. - */ -public class LinearInterpolator extends Plottable { - /** - * constant used to specify LEFT interpolation. - * See {@link #setInterpolationMethod(int) setInterpolationMethod()} for explanation. - */ - public static final int INTERPOLATE_LEFT = 0; - /** - * constant used to specify RIGHT interpolation. - * See {@link #setInterpolationMethod(int) setInterpolationMethod()} for explanation. - */ - public static final int INTERPOLATE_RIGHT = 1; - /** - * constant used to specify LINEAR interpolation (default interpolation method). - * See {@link #setInterpolationMethod(int) setInterpolationMethod()} for explanation. - */ - public static final int INTERPOLATE_LINEAR = 2; - /** - * constant used to specify LINEAR REGRESSION as interpolation method. - * See {@link #setInterpolationMethod(int) setInterpolationMethod()} for explanation. - */ - public static final int INTERPOLATE_REGRESSION = 3; - - private int lastIndexUsed = 0; - private int interpolationMethod = INTERPOLATE_LINEAR; - - private long[] timestamps; - private double[] values; - - // used only if INTERPOLATE_BESTFIT is specified - double b0 = Double.NaN, b1 = Double.NaN; - - /** - * Creates LinearInterpolator from arrays of timestamps and corresponding datasource values. - * - * @param timestamps timestamps in seconds - * @param values corresponding datasource values - * @throws RrdException Thrown if supplied arrays do not contain at least two values, or if - * timestamps are not ordered, or array lengths are not equal. - */ - public LinearInterpolator(long[] timestamps, double[] values) throws RrdException { - this.timestamps = timestamps; - this.values = values; - validate(); - } - - /** - * Creates LinearInterpolator from arrays of timestamps and corresponding datasource values. - * - * @param dates Array of Date objects - * @param values corresponding datasource values - * @throws RrdException Thrown if supplied arrays do not contain at least two values, or if - * timestamps are not ordered, or array lengths are not equal. - */ - public LinearInterpolator(Date[] dates, double[] values) throws RrdException { - this.values = values; - timestamps = new long[dates.length]; - for (int i = 0; i < dates.length; i++) { - timestamps[i] = Util.getTimestamp(dates[i]); - } - validate(); - } - - /** - * Creates LinearInterpolator from arrays of timestamps and corresponding datasource values. - * - * @param dates array of GregorianCalendar objects - * @param values corresponding datasource values - * @throws RrdException Thrown if supplied arrays do not contain at least two values, or if - * timestamps are not ordered, or array lengths are not equal. - */ - public LinearInterpolator(Calendar[] dates, double[] values) throws RrdException { - this.values = values; - timestamps = new long[dates.length]; - for (int i = 0; i < dates.length; i++) { - timestamps[i] = Util.getTimestamp(dates[i]); - } - validate(); - } - - private void validate() throws RrdException { - boolean ok = true; - if (timestamps.length != values.length || timestamps.length < 2) { - ok = false; - } - for (int i = 0; i < timestamps.length - 1 && ok; i++) { - if (timestamps[i] >= timestamps[i + 1]) { - ok = false; - } - } - if (!ok) { - throw new RrdException("Invalid plottable data supplied"); - } - } - - /** - * Sets interpolation method to be used. Suppose that we have two timestamp/value pairs:<br> - * <code>(t, 100)</code> and <code>(t + 100, 300)</code>. Here are the results interpolator - * returns for t + 50 seconds, for various <code>interpolationMethods</code>: - * <p> - * <ul> - * <li><code>INTERPOLATE_LEFT: 100</code> - * <li><code>INTERPOLATE_RIGHT: 300</code> - * <li><code>INTERPOLATE_LINEAR: 200</code> - * </ul> - * If not set, interpolation method defaults to <code>INTERPOLATE_LINEAR</code>. - * <p> - * The fourth available interpolation method is INTERPOLATE_REGRESSION. This method uses - * simple linear regression to interpolate supplied data with a simple straight line which does not - * necessarily pass through all data points. The slope of the best-fit line will be chosen so that the - * total square distance of real data points from from the best-fit line is at minimum. - * <p> - * The full explanation of this inteprolation method can be found - * <a href="http://www.tufts.edu/~gdallal/slr.htm">here</a>. - * - * @param interpolationMethod Should be <code>INTERPOLATE_LEFT</code>, - * <code>INTERPOLATE_RIGHT</code>, <code>INTERPOLATE_LINEAR</code> or - * <code>INTERPOLATE_REGRESSION</code>. Any other value will be interpreted as - * INTERPOLATE_LINEAR (default). - */ - public void setInterpolationMethod(int interpolationMethod) { - switch (interpolationMethod) { - case INTERPOLATE_REGRESSION: - calculateBestFitLine(); - this.interpolationMethod = interpolationMethod; - break; - case INTERPOLATE_LEFT: - case INTERPOLATE_RIGHT: - case INTERPOLATE_LINEAR: - this.interpolationMethod = interpolationMethod; - break; - default: - this.interpolationMethod = INTERPOLATE_LINEAR; - } - } - - private void calculateBestFitLine() { - int count = timestamps.length, validCount = 0; - double ts = 0.0, vs = 0.0; - for (int i = 0; i < count; i++) { - if (!Double.isNaN(values[i])) { - ts += timestamps[i]; - vs += values[i]; - validCount++; - } - } - if (validCount <= 1) { - // just one not-NaN point - b0 = b1 = Double.NaN; - return; - } - ts /= validCount; - vs /= validCount; - double s1 = 0, s2 = 0; - for (int i = 0; i < count; i++) { - if (!Double.isNaN(values[i])) { - double dt = timestamps[i] - ts; - double dv = values[i] - vs; - s1 += dt * dv; - s2 += dt * dt; - } - } - b1 = s1 / s2; - b0 = vs - b1 * ts; - } - - /** - * Method overriden from the base class. This method will be called by the framework. Call - * this method only if you need interpolated values in your code. - * - * @param timestamp timestamp in seconds - * @return inteprolated datasource value - */ - public double getValue(long timestamp) { - if (interpolationMethod == INTERPOLATE_REGRESSION) { - return b0 + b1 * timestamp; - } - int count = timestamps.length; - // check if out of range - if (timestamp < timestamps[0] || timestamp > timestamps[count - 1]) { - return Double.NaN; - } - // find matching segment - int startIndex = lastIndexUsed; - if (timestamp < timestamps[lastIndexUsed]) { - // backward reading, shift to the first timestamp - startIndex = 0; - } - for (int i = startIndex; i < count; i++) { - if (timestamps[i] == timestamp) { - return values[i]; - } - if (i < count - 1 && timestamps[i] < timestamp && timestamp < timestamps[i + 1]) { - // matching segment found - lastIndexUsed = i; - switch (interpolationMethod) { - case INTERPOLATE_LEFT: - return values[i]; - case INTERPOLATE_RIGHT: - return values[i + 1]; - case INTERPOLATE_LINEAR: - double slope = (values[i + 1] - values[i]) / - (timestamps[i + 1] - timestamps[i]); - return values[i] + slope * (timestamp - timestamps[i]); - default: - return Double.NaN; - } - } - } - // should not be here ever, but let's satisfy the compiler - return Double.NaN; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/Normalizer.java b/apps/jrobin/java/src/org/jrobin/data/Normalizer.java deleted file mode 100644 index 34c177e741e6cb96a3b0aac0b71fd1dafc9069ae..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/Normalizer.java +++ /dev/null @@ -1,80 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -import org.jrobin.core.Util; - -import java.util.Arrays; - -class Normalizer { - final private long[] timestamps; - final int count; - final long step; - - Normalizer(long[] timestamps) { - this.timestamps = timestamps; - this.step = timestamps[1] - timestamps[0]; - this.count = timestamps.length; - } - - double[] normalize(long[] rawTimestamps, double[] rawValues) { - int rawCount = rawTimestamps.length; - long rawStep = rawTimestamps[1] - rawTimestamps[0]; - // check if we have a simple match - if (rawCount == count && rawStep == step && rawTimestamps[0] == timestamps[0]) { - return getCopyOf(rawValues); - } - // reset all normalized values to NaN - double[] values = new double[count]; - Arrays.fill(values, Double.NaN); - for (int rawSeg = 0, seg = 0; rawSeg < rawCount && seg < count; rawSeg++) { - double rawValue = rawValues[rawSeg]; - if (!Double.isNaN(rawValue)) { - long rawLeft = rawTimestamps[rawSeg] - rawStep; - while (seg < count && rawLeft >= timestamps[seg]) { - seg++; - } - boolean overlap = true; - for (int fillSeg = seg; overlap && fillSeg < count; fillSeg++) { - long left = timestamps[fillSeg] - step; - long t1 = Math.max(rawLeft, left); - long t2 = Math.min(rawTimestamps[rawSeg], timestamps[fillSeg]); - if (t1 < t2) { - values[fillSeg] = Util.sum(values[fillSeg], (t2 - t1) * rawValues[rawSeg]); - } - else { - overlap = false; - } - } - } - } - for (int seg = 0; seg < count; seg++) { - values[seg] /= step; - } - return values; - } - - private static double[] getCopyOf(double[] rawValues) { - int n = rawValues.length; - double[] values = new double[n]; - System.arraycopy(rawValues, 0, values, 0, n); - return values; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/PDef.java b/apps/jrobin/java/src/org/jrobin/data/PDef.java deleted file mode 100644 index b6bb1f315cced45760058efcf34dfac6a6856777..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/PDef.java +++ /dev/null @@ -1,38 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -class PDef extends Source { - private final Plottable plottable; - - PDef(String name, Plottable plottable) { - super(name); - this.plottable = plottable; - } - - void calculateValues() { - long[] times = getTimestamps(); - double[] vals = new double[times.length]; - for (int i = 0; i < times.length; i++) { - vals[i] = plottable.getValue(times[i]); - } - setValues(vals); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/PercentileDef.java b/apps/jrobin/java/src/org/jrobin/data/PercentileDef.java deleted file mode 100644 index 853f4d9501ba1b73df59b85b14c15bafbc155ada..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/PercentileDef.java +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Craig Miskell - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.data; - -import org.jrobin.core.RrdException; - -public class PercentileDef extends Source { - - private Source m_source; - - private double m_value; - - private double m_percentile; - - @SuppressWarnings("unused") - private boolean m_ignorenan; - - PercentileDef(String name, Source source, double percentile) { - this(name, source, percentile, false); - } - - PercentileDef(String name, Source source, double percentile, boolean ignorenan) { - super(name); - - m_percentile = percentile; - m_ignorenan = ignorenan; - m_source = source; - - //The best we can do at this point; until this object has it's value realized over a - // particular time period (with calculate()), there's not much else to do - this.setValue(Double.NaN); - } - - /** - * Realize the calculation of this definition, over the given time period - * - * @param tStart the time period start - * @param tEnd the time period end - * @throws RrdException Thrown if we cannot get a percentile value for the time period. - */ - public void calculate(long tStart, long tEnd) throws RrdException { - if(m_source != null) { - this.setValue(m_source.getPercentile(tStart, tEnd, m_percentile)); - } - } - - /** - * Takes the given value and puts it in each position in the 'values' array. - * @param value - */ - private void setValue(double value) { - this.m_value = value; - long[] times = getTimestamps(); - if( times != null ) { - int count = times.length; - double[] values = new double[count]; - for (int i = 0; i < count; i++) { - values[i] = m_value; - } - setValues(values); - } - } - - @Override - void setTimestamps(long[] timestamps) { - super.setTimestamps(timestamps); - //And now also call setValue with the current value, to sort out "values" - setValue(m_value); - } - - /** - * Same as SDef; the aggregates of a static value are all just the - * same static value. - * - * Assumes this def has been realized by calling calculate(), otherwise - * the aggregated values will be NaN - */ - @Override - Aggregates getAggregates(long tStart, long tEnd) throws RrdException { - Aggregates agg = new Aggregates(); - agg.first = agg.last = agg.min = agg.max = agg.average = m_value; - agg.total = m_value * (tEnd - tStart); - return agg; - } - - /** - * Returns just the calculated percentile; the "Xth" percentile of a static value is - * the static value itself. - * - * Assumes this def has been realized by calling calculate(), otherwise - * the aggregated values will be NaN - */ - @Override - double getPercentile(long tStart, long tEnd, double percentile) - throws RrdException { - return m_value; - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/data/Plottable.java b/apps/jrobin/java/src/org/jrobin/data/Plottable.java deleted file mode 100644 index b8c879608eb559865055ea7075ffc49462bdd858..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/Plottable.java +++ /dev/null @@ -1,37 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.data; - -/** - * <p>Interface to be used for custom datasources. - * 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> - */ -public abstract class Plottable { - /** - * 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) { - return Double.NaN; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/RpnCalculator.java b/apps/jrobin/java/src/org/jrobin/data/RpnCalculator.java deleted file mode 100644 index 6e0dfbb93cd695bd99e16cf73cfc2604e45e5bf0..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/RpnCalculator.java +++ /dev/null @@ -1,832 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -import java.util.Arrays; -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; - -import java.util.Calendar; -import java.util.StringTokenizer; -import java.util.TimeZone; - -class RpnCalculator { - private static final byte TKN_VAR = 0; - private static final byte TKN_NUM = 1; - private static final byte TKN_PLUS = 2; - private static final byte TKN_MINUS = 3; - private static final byte TKN_MULT = 4; - private static final byte TKN_DIV = 5; - private static final byte TKN_MOD = 6; - private static final byte TKN_SIN = 7; - private static final byte TKN_COS = 8; - private static final byte TKN_LOG = 9; - private static final byte TKN_EXP = 10; - private static final byte TKN_FLOOR = 11; - private static final byte TKN_CEIL = 12; - private static final byte TKN_ROUND = 13; - private static final byte TKN_POW = 14; - private static final byte TKN_ABS = 15; - private static final byte TKN_SQRT = 16; - private static final byte TKN_RANDOM = 17; - private static final byte TKN_LT = 18; - private static final byte TKN_LE = 19; - private static final byte TKN_GT = 20; - private static final byte TKN_GE = 21; - private static final byte TKN_EQ = 22; - private static final byte TKN_IF = 23; - private static final byte TKN_MIN = 24; - private static final byte TKN_MAX = 25; - private static final byte TKN_LIMIT = 26; - private static final byte TKN_DUP = 27; - private static final byte TKN_EXC = 28; - private static final byte TKN_POP = 29; - private static final byte TKN_UN = 30; - private static final byte TKN_UNKN = 31; - private static final byte TKN_NOW = 32; - private static final byte TKN_TIME = 33; - private static final byte TKN_PI = 34; - private static final byte TKN_E = 35; - private static final byte TKN_AND = 36; - private static final byte TKN_OR = 37; - private static final byte TKN_XOR = 38; - private static final byte TKN_PREV = 39; - private static final byte TKN_INF = 40; - private static final byte TKN_NEGINF = 41; - private static final byte TKN_STEP = 42; - private static final byte TKN_YEAR = 43; - private static final byte TKN_MONTH = 44; - private static final byte TKN_DATE = 45; - private static final byte TKN_HOUR = 46; - private static final byte TKN_MINUTE = 47; - private static final byte TKN_SECOND = 48; - private static final byte TKN_WEEK = 49; - private static final byte TKN_SIGN = 50; - private static final byte TKN_RND = 51; - private static final byte TKN_ADDNAN = 52; - private static final byte TKN_NE = 53; - private static final byte TKN_ISINF = 54; - private static final byte TKN_ATAN = 55; - private static final byte TKN_ATAN2 = 56; - private static final byte TKN_DEG2RAD = 57; - private static final byte TKN_RAD2DEG = 58; - private static final byte TKN_COUNT = 59; - private static final byte TKN_SORT = 60; - private static final byte TKN_REV = 61; - private static final byte TKN_AVG = 62; - private static final byte TKN_LTIME = 63; - private static final byte TKN_TREND = 64; - private static final byte TKN_TRENDNAN = 65; - private static final byte TKN_PREDICT = 66; - private static final byte TKN_PREDICTSIGMA = 67; - - private String rpnExpression; - private String sourceName; - private DataProcessor dataProcessor; - - private Token[] tokens; - private RpnStack stack = new RpnStack(); - private double[] calculatedValues; - private long[] timestamps; - private double timeStep; - - RpnCalculator(String rpnExpression, String sourceName, DataProcessor dataProcessor) throws RrdException { - this.rpnExpression = rpnExpression; - this.sourceName = sourceName; - this.dataProcessor = dataProcessor; - this.timestamps = dataProcessor.getTimestamps(); - this.timeStep = this.timestamps[1] - this.timestamps[0]; - this.calculatedValues = new double[this.timestamps.length]; - StringTokenizer st = new StringTokenizer(rpnExpression, ", "); - tokens = new Token[st.countTokens()]; - for (int i = 0; st.hasMoreTokens(); i++) { - tokens[i] = createToken(st.nextToken()); - } - } - - private Token createToken(String parsedText) throws RrdException { - Token token = new Token(); - if (Util.isDouble(parsedText)) { - token.id = TKN_NUM; - token.number = Util.parseDouble(parsedText); - } - else if (parsedText.equals("+")) { - token.id = TKN_PLUS; - } - else if (parsedText.equals("-")) { - token.id = TKN_MINUS; - } - else if (parsedText.equals("*")) { - token.id = TKN_MULT; - } - else if (parsedText.equals("/")) { - token.id = TKN_DIV; - } - else if (parsedText.equals("%")) { - token.id = TKN_MOD; - } - else if (parsedText.equals("SIN")) { - token.id = TKN_SIN; - } - else if (parsedText.equals("COS")) { - token.id = TKN_COS; - } - else if (parsedText.equals("LOG")) { - token.id = TKN_LOG; - } - else if (parsedText.equals("EXP")) { - token.id = TKN_EXP; - } - else if (parsedText.equals("FLOOR")) { - token.id = TKN_FLOOR; - } - else if (parsedText.equals("CEIL")) { - token.id = TKN_CEIL; - } - else if (parsedText.equals("ROUND")) { - token.id = TKN_ROUND; - } - else if (parsedText.equals("POW")) { - token.id = TKN_POW; - } - else if (parsedText.equals("ABS")) { - token.id = TKN_ABS; - } - else if (parsedText.equals("SQRT")) { - token.id = TKN_SQRT; - } - else if (parsedText.equals("RANDOM")) { - token.id = TKN_RANDOM; - } - else if (parsedText.equals("LT")) { - token.id = TKN_LT; - } - else if (parsedText.equals("LE")) { - token.id = TKN_LE; - } - else if (parsedText.equals("GT")) { - token.id = TKN_GT; - } - else if (parsedText.equals("GE")) { - token.id = TKN_GE; - } - else if (parsedText.equals("EQ")) { - token.id = TKN_EQ; - } - else if (parsedText.equals("IF")) { - token.id = TKN_IF; - } - else if (parsedText.equals("MIN")) { - token.id = TKN_MIN; - } - else if (parsedText.equals("MAX")) { - token.id = TKN_MAX; - } - else if (parsedText.equals("LIMIT")) { - token.id = TKN_LIMIT; - } - else if (parsedText.equals("DUP")) { - token.id = TKN_DUP; - } - else if (parsedText.equals("EXC")) { - token.id = TKN_EXC; - } - else if (parsedText.equals("POP")) { - token.id = TKN_POP; - } - else if (parsedText.equals("UN")) { - token.id = TKN_UN; - } - else if (parsedText.equals("UNKN")) { - token.id = TKN_UNKN; - } - else if (parsedText.equals("NOW")) { - token.id = TKN_NOW; - } - else if (parsedText.equals("TIME")) { - token.id = TKN_TIME; - } - else if (parsedText.equals("LTIME")) { - token.id = TKN_LTIME; - } - else if (parsedText.equals("PI")) { - token.id = TKN_PI; - } - else if (parsedText.equals("E")) { - token.id = TKN_E; - } - else if (parsedText.equals("AND")) { - token.id = TKN_AND; - } - else if (parsedText.equals("OR")) { - token.id = TKN_OR; - } - else if (parsedText.equals("XOR")) { - token.id = TKN_XOR; - } - else if (parsedText.equals("PREV")) { - token.id = TKN_PREV; - token.variable = sourceName; - token.values = calculatedValues; - } - else if (parsedText.startsWith("PREV(") && parsedText.endsWith(")")) { - token.id = TKN_PREV; - token.variable = parsedText.substring(5, parsedText.length() - 1); - token.values = dataProcessor.getValues(token.variable); - } - else if (parsedText.equals("INF")) { - token.id = TKN_INF; - } - else if (parsedText.equals("NEGINF")) { - token.id = TKN_NEGINF; - } - else if (parsedText.equals("STEP")) { - token.id = TKN_STEP; - } - else if (parsedText.equals("YEAR")) { - token.id = TKN_YEAR; - } - else if (parsedText.equals("MONTH")) { - token.id = TKN_MONTH; - } - else if (parsedText.equals("DATE")) { - token.id = TKN_DATE; - } - else if (parsedText.equals("HOUR")) { - token.id = TKN_HOUR; - } - else if (parsedText.equals("MINUTE")) { - token.id = TKN_MINUTE; - } - else if (parsedText.equals("SECOND")) { - token.id = TKN_SECOND; - } - else if (parsedText.equals("WEEK")) { - token.id = TKN_WEEK; - } - else if (parsedText.equals("SIGN")) { - token.id = TKN_SIGN; - } - else if (parsedText.equals("RND")) { - token.id = TKN_RND; - } - else if (parsedText.equals("ADDNAN")) { - token.id = TKN_ADDNAN; - } - else if (parsedText.equals("NE")) { - token.id = TKN_NE; - } - else if (parsedText.equals("ISINF")) { - token.id = TKN_ISINF; - } - else if (parsedText.equals("ATAN")) { - token.id = TKN_ATAN; - } - else if (parsedText.equals("ATAN2")) { - token.id = TKN_ATAN2; - } - else if (parsedText.equals("DEG2RAD")) { - token.id = TKN_DEG2RAD; - } - else if (parsedText.equals("RAD2DEG")) { - token.id = TKN_RAD2DEG; - } - else if (parsedText.equals("COUNT")) { - token.id = TKN_COUNT; - } - else if (parsedText.equals("SORT")) { - token.id = TKN_SORT; - } - else if (parsedText.equals("REV")) { - token.id = TKN_REV; - } - else if (parsedText.equals("AVG")) { - token.id = TKN_AVG; - } - else if (parsedText.equals("TREND")) { - token.id = TKN_TREND; - } - else if (parsedText.equals("TRENDNAN")) { - token.id = TKN_TRENDNAN; - } - else if (parsedText.equals("PREDICT")) { - token.id = TKN_PREDICT; - } - else if (parsedText.equals("PREDICTSIGMA")) { - token.id = TKN_PREDICTSIGMA; - } - else { - token.id = TKN_VAR; - token.variable = parsedText; - token.values = dataProcessor.getValues(token.variable); - } - return token; - } - - double[] calculateValues() throws RrdException { - TimeZone tz = TimeZone.getDefault(); - for (int slot = 0; slot < timestamps.length; slot++) { - resetStack(); - int token_rpi = -1; - for (int rpi = 0; rpi < tokens.length; rpi++) { - Token token = tokens[rpi]; - double x1, x2, x3; - switch (token.id) { - case TKN_NUM: - push(token.number); - break; - case TKN_VAR: - push(token.values[slot]); - token_rpi = rpi; - break; - case TKN_COUNT: - push(slot+1); - break; - case TKN_PLUS: - push(pop() + pop()); - break; - case TKN_MINUS: - x2 = pop(); - x1 = pop(); - push(x1 - x2); - break; - case TKN_MULT: - push(pop() * pop()); - break; - case TKN_DIV: - x2 = pop(); - x1 = pop(); - push(x1 / x2); - break; - case TKN_MOD: - x2 = pop(); - x1 = pop(); - push(x1 % x2); - break; - case TKN_SIN: - push(Math.sin(pop())); - break; - case TKN_COS: - push(Math.cos(pop())); - break; - case TKN_ATAN: - push(Math.atan(pop())); - break; - case TKN_ATAN2: - x2 = pop(); - x1 = pop(); - push(Math.atan2(x1, x2)); - break; - case TKN_LOG: - push(Math.log(pop())); - break; - case TKN_EXP: - push(Math.exp(pop())); - break; - case TKN_FLOOR: - push(Math.floor(pop())); - break; - case TKN_CEIL: - push(Math.ceil(pop())); - break; - case TKN_ROUND: - push(Math.round(pop())); - break; - case TKN_POW: - x2 = pop(); - x1 = pop(); - push(Math.pow(x1, x2)); - break; - case TKN_ABS: - push(Math.abs(pop())); - break; - case TKN_SQRT: - push(Math.sqrt(pop())); - break; - case TKN_RANDOM: - push(Math.random()); - break; - case TKN_LT: - x2 = pop(); - x1 = pop(); - push(x1 < x2 ? 1 : 0); - break; - case TKN_LE: - x2 = pop(); - x1 = pop(); - push(x1 <= x2 ? 1 : 0); - break; - case TKN_GT: - x2 = pop(); - x1 = pop(); - push(x1 > x2 ? 1 : 0); - break; - case TKN_GE: - x2 = pop(); - x1 = pop(); - push(x1 >= x2 ? 1 : 0); - break; - case TKN_EQ: - x2 = pop(); - x1 = pop(); - push(x1 == x2 ? 1 : 0); - break; - case TKN_NE: - x2 = pop(); - x1 = pop(); - push(x1 != x2 ? 1 : 0); - break; - case TKN_IF: - x3 = pop(); - x2 = pop(); - x1 = pop(); - push(x1 != 0 ? x2 : x3); - break; - case TKN_MIN: - push(Math.min(pop(), pop())); - break; - case TKN_MAX: - push(Math.max(pop(), pop())); - break; - case TKN_LIMIT: - x3 = pop(); - x2 = pop(); - x1 = pop(); - push(x1 < x2 || x1 > x3 ? Double.NaN : x1); - break; - case TKN_DUP: - push(peek()); - break; - case TKN_EXC: - x2 = pop(); - x1 = pop(); - push(x2); - push(x1); - break; - case TKN_POP: - pop(); - break; - case TKN_UN: - push(Double.isNaN(pop()) ? 1 : 0); - break; - case TKN_ISINF: - push(Double.isInfinite(pop()) ? 1 : 0); - break; - case TKN_UNKN: - push(Double.NaN); - break; - case TKN_NOW: - push(Util.getTime()); - break; - case TKN_TIME: - push(timestamps[slot]); - break; - case TKN_LTIME: - push(timestamps[slot] + (tz.getOffset(timestamps[slot]) / 1000L)); - break; - case TKN_PI: - push(Math.PI); - break; - case TKN_E: - push(Math.E); - break; - case TKN_AND: - x2 = pop(); - x1 = pop(); - push((x1 != 0 && x2 != 0) ? 1 : 0); - break; - case TKN_OR: - x2 = pop(); - x1 = pop(); - push((x1 != 0 || x2 != 0) ? 1 : 0); - break; - case TKN_XOR: - x2 = pop(); - x1 = pop(); - push(((x1 != 0 && x2 == 0) || (x1 == 0 && x2 != 0)) ? 1 : 0); - break; - case TKN_PREV: - push((slot == 0) ? Double.NaN : token.values[slot - 1]); - break; - case TKN_INF: - push(Double.POSITIVE_INFINITY); - break; - case TKN_NEGINF: - push(Double.NEGATIVE_INFINITY); - break; - case TKN_STEP: - push(timeStep); - break; - case TKN_YEAR: - push(getCalendarField(pop(), Calendar.YEAR)); - break; - case TKN_MONTH: - push(getCalendarField(pop(), Calendar.MONTH)); - break; - case TKN_DATE: - push(getCalendarField(pop(), Calendar.DAY_OF_MONTH)); - break; - case TKN_HOUR: - push(getCalendarField(pop(), Calendar.HOUR_OF_DAY)); - break; - case TKN_MINUTE: - push(getCalendarField(pop(), Calendar.MINUTE)); - break; - case TKN_SECOND: - push(getCalendarField(pop(), Calendar.SECOND)); - break; - case TKN_WEEK: - push(getCalendarField(pop(), Calendar.WEEK_OF_YEAR)); - break; - case TKN_SIGN: - x1 = pop(); - push(Double.isNaN(x1) ? Double.NaN : x1 > 0 ? +1 : x1 < 0 ? -1 : 0); - break; - case TKN_RND: - push(Math.floor(pop() * Math.random())); - break; - case TKN_ADDNAN: - x2 = pop(); - x1 = pop(); - if (Double.isNaN(x1)) { - push(x2); - } else if (Double.isNaN(x2)) { - push(x1); - } else { - push(x1+x2); - } - break; - case TKN_DEG2RAD: - push(Math.toRadians(pop())); - break; - case TKN_RAD2DEG: - push(Math.toDegrees(pop())); - break; - case TKN_SORT: - { - int n = (int) pop(); - double[] array = new double[n]; - for(int i = 0; i < n; i++) { - array[i] = pop(); - } - Arrays.sort(array); - for (int i = 0; i < n; i++) { - push(array[i]); - } - } - break; - case TKN_REV: - { - int n = (int) pop(); - double[] array = new double[n]; - for(int i = 0; i < n; i++) { - array[i] = pop(); - } - for (int i = 0; i < n; i++) { - push(array[i]); - } - } - break; - case TKN_AVG: - { - int count = 0; - int n = (int) pop(); - double sum = 0.0; - while (n > 0) { - x1 = pop(); - n--; - - if (Double.isNaN(x1)) { - continue; - } - - sum += x1; - count++; - } - if (count > 0) { - push(sum / count); - } else { - push(Double.NaN); - } - } - break; - case TKN_TREND: - case TKN_TRENDNAN: - { - int dur = (int) pop(); - pop(); - /* - * OK, so to match the output from rrdtool, we have to go *forward* 2 timeperiods. - * So at t[59] we use the average of t[1]..t[61] - * - */ - - if ((slot+1) < Math.ceil(dur / timeStep)) { - push(Double.NaN); - } else { - double[] vals = dataProcessor.getValues(tokens[token_rpi].variable); - boolean ignorenan = token.id == TKN_TRENDNAN; - double accum = 0.0; - int count = 0; - - int start = (int) (Math.ceil(dur / timeStep)); - int row = 2; - while ((slot + row) > vals.length) { - row --; - } - - for(; start > 0; start--) { - double val = vals[slot + row - start]; - if (ignorenan || !Double.isNaN(val)) { - accum = Util.sum(accum, val); - ++count; - } - } - //System.err.printf("t[%d]: %1.10e / %d\n", slot, (count == 0) ? Double.NaN : (accum / count), count); - push((count == 0) ? Double.NaN : (accum / count)); - } - } - break; - case TKN_PREDICT: - case TKN_PREDICTSIGMA: - { - pop(); // Clear the value of our variable - - /* the local averaging window (similar to trend, but better here, as we get better statistics thru numbers)*/ - int locstepsize = (int) pop(); - /* the number of shifts and range-checking*/ - int num_shifts = (int) pop(); - double[] multipliers; - - // handle negative shifts special - if (num_shifts < 0) { - multipliers = new double[1]; - multipliers[0] = pop(); - } else { - multipliers = new double[num_shifts]; - for(int i = 0; i < num_shifts; i++) { - multipliers[i] = pop(); - } - } - - /* the real calculation */ - double val = Double.NaN; - - /* the info on the datasource */ - double[] vals = dataProcessor.getValues(tokens[rpi-1].variable); - - int locstep = (int) Math.ceil((float) locstepsize / (float) timeStep); - - /* the sums */ - double sum = 0; - double sum2 = 0; - int count = 0; - - /* now loop for each position */ - int doshifts = Math.abs(num_shifts); - for (int loop = 0; loop < doshifts; loop++) { - /* calculate shift step */ - int shiftstep = 1; - if (num_shifts < 0) { - shiftstep = loop * (int) multipliers[0]; - } else { - shiftstep = (int) multipliers[loop]; - } - if (shiftstep < 0) { - throw new RrdException("negative shift step not allowed: " + shiftstep); - } - shiftstep = (int) Math.ceil((float) shiftstep / (float) timeStep); - /* loop all local shifts */ - for (int i = 0; i <= locstep; i++) { - - int offset = shiftstep + i; - if ((offset >= 0) && (offset < slot)) { - /* get the value */ - val = vals[slot - offset]; - - /* and handle the non NAN case only*/ - if (!Double.isNaN(val)) { - sum = Util.sum(sum, val); - sum2 = Util.sum(sum2, val * val); - count++; - } - } - } - } - /* do the final calculations */ - val = Double.NaN; - if (token.id == TKN_PREDICT) { /* the average */ - if (count > 0) { - val = sum / (double) count; - } - } else { - if (count > 1) { /* the sigma case */ - val = count * sum2 - sum * sum; - if (val < 0) { - val = Double.NaN; - } else { - val = Math.sqrt(val / ((float) count * ((float) count - 1.0))); - } - } - } - push(val); - } - break; - default: - throw new RrdException("Unexpected RPN token encountered, token.id=" + token.id); - } - } - calculatedValues[slot] = pop(); - // check if stack is empty only on the first try - if (slot == 0 && !isStackEmpty()) { - throw new RrdException("Stack not empty at the end of calculation. " + - "Probably bad RPN expression [" + rpnExpression + "]"); - } - } - return calculatedValues; - } - - private double getCalendarField(double timestamp, int field) { - Calendar calendar = Util.getCalendar((long) timestamp); - return calendar.get(field); - } - - private void push(double x) throws RrdException { - stack.push(x); - } - - private double pop() throws RrdException { - return stack.pop(); - } - - private double peek() throws RrdException { - return stack.peek(); - } - - private void resetStack() { - stack.reset(); - } - - private boolean isStackEmpty() { - return stack.isEmpty(); - } - - private static final class RpnStack { - private static final int MAX_STACK_SIZE = 1000; - private double[] stack = new double[MAX_STACK_SIZE]; - private int pos = 0; - - void push(final double x) throws RrdException { - if (pos >= MAX_STACK_SIZE) { - throw new RrdException("PUSH failed, RPN stack full [" + MAX_STACK_SIZE + "]"); - } - stack[pos++] = x; - } - - double pop() throws RrdException { - if (pos <= 0) { - throw new RrdException("POP failed, RPN stack is empty "); - } - return stack[--pos]; - } - - double peek() throws RrdException { - if (pos <= 0) { - throw new RrdException("PEEK failed, RPN stack is empty "); - } - return stack[pos - 1]; - } - - void reset() { - pos = 0; - } - - boolean isEmpty() { - return pos <= 0; - } - } - - private static final class Token { - byte id = -1; - double number = Double.NaN; - String variable = null; - double[] values = null; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/SDef.java b/apps/jrobin/java/src/org/jrobin/data/SDef.java deleted file mode 100644 index 7d92be14333e3a242bc3af6f7eaf32d3d5d257cd..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/SDef.java +++ /dev/null @@ -1,63 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -import org.jrobin.core.RrdException; - -class SDef extends Source { - private String defName; - private String consolFun; - private double value; - - SDef(String name, String defName, String consolFun) { - super(name); - this.defName = defName; - this.consolFun = consolFun; - } - - String getDefName() { - return defName; - } - - String getConsolFun() { - return consolFun; - } - - void setValue(double value) { - this.value = value; - int count = getTimestamps().length; - double[] values = new double[count]; - for (int i = 0; i < count; i++) { - values[i] = value; - } - setValues(values); - } - - Aggregates getAggregates(long tStart, long tEnd) throws RrdException { - Aggregates agg = new Aggregates(); - agg.first = agg.last = agg.min = agg.max = agg.average = value; - agg.total = value * (tEnd - tStart); - return agg; - } - - double getPercentile(long tStart, long tEnd, double percentile) throws RrdException { - return value; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/Source.java b/apps/jrobin/java/src/org/jrobin/data/Source.java deleted file mode 100644 index 302b70670ebc62304e9d262cd674fcebc88e4b29..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/Source.java +++ /dev/null @@ -1,68 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.data; - -import org.jrobin.core.ConsolFuns; -import org.jrobin.core.RrdException; - -abstract class Source implements ConsolFuns { - final private String name; - protected double[] values; - protected long[] timestamps; - - Source(String name) { - this.name = name; - } - - String getName() { - return name; - } - - void setValues(double[] values) { - this.values = values; - } - - void setTimestamps(long[] timestamps) { - this.timestamps = timestamps; - } - - double[] getValues() { - return values; - } - - long[] getTimestamps() { - return timestamps; - } - - Aggregates getAggregates(long tStart, long tEnd) throws RrdException { - Aggregator agg = new Aggregator(timestamps, values); - return agg.getAggregates(tStart, tEnd); - } - - double getPercentile(long tStart, long tEnd, double percentile) throws RrdException { - Aggregator agg = new Aggregator(timestamps, values); - return agg.getPercentile(tStart, tEnd, percentile, false); - } - - double getPercentile(long tStart, long tEnd, double percentile, boolean includenan) throws RrdException { - Aggregator agg = new Aggregator(timestamps, values); - return agg.getPercentile(tStart, tEnd, percentile, includenan); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/data/package.html b/apps/jrobin/java/src/org/jrobin/data/package.html deleted file mode 100644 index 809736855d30efdd12b701fbc551cc5cc0537a08..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/data/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<html> - <body> - JRobin data management. - </body> -</html> \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/graph/Area.java b/apps/jrobin/java/src/org/jrobin/graph/Area.java deleted file mode 100644 index 73845e3a0b83e2a18249ec03a6ae26b85f8dd123..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/Area.java +++ /dev/null @@ -1,27 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.*; - -class Area extends SourcedPlotElement { - Area(String srcName, Paint color) { - super(srcName, color); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/CDef.java b/apps/jrobin/java/src/org/jrobin/graph/CDef.java deleted file mode 100644 index 39bb6148194201cfab65f3cffb082c16575e0818..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/CDef.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.data.DataProcessor; - -class CDef extends Source { - private final String rpnExpression; - - CDef(String name, String rpnExpression) { - super(name); - this.rpnExpression = rpnExpression; - } - - void requestData(DataProcessor dproc) { - dproc.addDatasource(name, rpnExpression); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/CommentText.java b/apps/jrobin/java/src/org/jrobin/graph/CommentText.java deleted file mode 100644 index 5031b88d9474b1b18264c663c355dda19ec7b386..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/CommentText.java +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.core.RrdException; -import org.jrobin.data.DataProcessor; - -class CommentText implements RrdGraphConstants { - private final String text; // original text - - String resolvedText; // resolved text - String marker; // end-of-text marker - boolean enabled; // hrule and vrule comments can be disabled at runtime - int x, y; // coordinates, evaluated later - - CommentText(String text) { - this.text = text; - } - - void resolveText(DataProcessor dproc, ValueScaler valueScaler) throws RrdException { - resolvedText = text; - marker = ""; - if (resolvedText != null) { - for (String mark : MARKERS) { - if (resolvedText.endsWith(mark)) { - marker = mark; - resolvedText = resolvedText.substring(0, resolvedText.length() - marker.length()); - trimIfGlue(); - break; - } - } - } - enabled = resolvedText != null; - } - - void trimIfGlue() { - if (marker.equals(GLUE_MARKER)) { - resolvedText = resolvedText.replaceFirst("\\s+$", ""); - } - } - - boolean isPrint() { - return false; - } - - boolean isValidGraphElement() { - return !isPrint() && enabled; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/Def.java b/apps/jrobin/java/src/org/jrobin/graph/Def.java deleted file mode 100644 index 06072fb5db84efe96686ee2599f51112f2b0e34a..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/Def.java +++ /dev/null @@ -1,47 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.graph; - -import org.jrobin.data.DataProcessor; - -class Def extends Source { - private final String rrdPath, dsName, consolFun, backend; - - Def(String name, String rrdPath, String dsName, String consolFun) { - this(name, rrdPath, dsName, consolFun, null); - } - - Def(String name, String rrdPath, String dsName, String consolFun, String backend) { - super(name); - this.rrdPath = rrdPath; - 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); - } - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/GifEncoder.java b/apps/jrobin/java/src/org/jrobin/graph/GifEncoder.java deleted file mode 100644 index a90d171925e1901c205705a0b2d5d45fb183f412..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/GifEncoder.java +++ /dev/null @@ -1,728 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -/////////////////////////////////////////////////////////////////// -// GifEncoder from J.M.G. Elliott -// http://jmge.net/java/gifenc/ -/////////////////////////////////////////////////////////////////// - -package org.jrobin.graph; - -import java.awt.*; -import java.awt.image.PixelGrabber; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Vector; - -class GifEncoder { - private Dimension dispDim = new Dimension(0, 0); - private GifColorTable colorTable; - private int bgIndex = 0; - private int loopCount = 1; - private String theComments; - private Vector<Gif89Frame> vFrames = new Vector<Gif89Frame>(); - - GifEncoder() { - colorTable = new GifColorTable(); - } - - GifEncoder(Image static_image) throws IOException { - this(); - addFrame(static_image); - } - - GifEncoder(Color[] colors) { - colorTable = new GifColorTable(colors); - } - - GifEncoder(Color[] colors, int width, int height, byte ci_pixels[]) - throws IOException { - this(colors); - addFrame(width, height, ci_pixels); - } - - int getFrameCount() { - return vFrames.size(); - } - - Gif89Frame getFrameAt(int index) { - return isOk(index) ? vFrames.elementAt(index) : null; - } - - void addFrame(Gif89Frame gf) throws IOException { - accommodateFrame(gf); - vFrames.addElement(gf); - } - - void addFrame(Image image) throws IOException { - addFrame(new DirectGif89Frame(image)); - } - - void addFrame(int width, int height, byte ci_pixels[]) - throws IOException { - addFrame(new IndexGif89Frame(width, height, ci_pixels)); - } - - void insertFrame(int index, Gif89Frame gf) throws IOException { - accommodateFrame(gf); - vFrames.insertElementAt(gf, index); - } - - void setTransparentIndex(int index) { - colorTable.setTransparent(index); - } - - void setLogicalDisplay(Dimension dim, int background) { - dispDim = new Dimension(dim); - bgIndex = background; - } - - void setLoopCount(int count) { - loopCount = count; - } - - void setComments(String comments) { - theComments = comments; - } - - void setUniformDelay(int interval) { - for (int i = 0; i < vFrames.size(); ++i) { - vFrames.elementAt(i).setDelay(interval); - } - } - - void encode(OutputStream out) throws IOException { - int nframes = getFrameCount(); - boolean is_sequence = nframes > 1; - colorTable.closePixelProcessing(); - Put.ascii("GIF89a", out); - writeLogicalScreenDescriptor(out); - colorTable.encode(out); - if (is_sequence && loopCount != 1) { - writeNetscapeExtension(out); - } - if (theComments != null && theComments.length() > 0) { - writeCommentExtension(out); - } - for (int i = 0; i < nframes; ++i) { - vFrames.elementAt(i).encode( - out, is_sequence, colorTable.getDepth(), colorTable.getTransparent() - ); - } - out.write((int) ';'); - out.flush(); - } - - private void accommodateFrame(Gif89Frame gf) throws IOException { - dispDim.width = Math.max(dispDim.width, gf.getWidth()); - dispDim.height = Math.max(dispDim.height, gf.getHeight()); - colorTable.processPixels(gf); - } - - private void writeLogicalScreenDescriptor(OutputStream os) throws IOException { - Put.leShort(dispDim.width, os); - Put.leShort(dispDim.height, os); - os.write(0xf0 | colorTable.getDepth() - 1); - os.write(bgIndex); - os.write(0); - } - - - private void writeNetscapeExtension(OutputStream os) throws IOException { - os.write((int) '!'); - os.write(0xff); - os.write(11); - Put.ascii("NETSCAPE2.0", os); - os.write(3); - os.write(1); - Put.leShort(loopCount > 1 ? loopCount - 1 : 0, os); - os.write(0); - } - - - private void writeCommentExtension(OutputStream os) throws IOException { - os.write((int) '!'); - os.write(0xfe); - int remainder = theComments.length() % 255; - int nsubblocks_full = theComments.length() / 255; - int nsubblocks = nsubblocks_full + (remainder > 0 ? 1 : 0); - int ibyte = 0; - for (int isb = 0; isb < nsubblocks; ++isb) { - int size = isb < nsubblocks_full ? 255 : remainder; - os.write(size); - Put.ascii(theComments.substring(ibyte, ibyte + size), os); - ibyte += size; - } - os.write(0); - } - - - private boolean isOk(int frame_index) { - return frame_index >= 0 && frame_index < vFrames.size(); - } -} - -class DirectGif89Frame extends Gif89Frame { - private int[] argbPixels; - - DirectGif89Frame(Image img) throws IOException { - PixelGrabber pg = new PixelGrabber(img, 0, 0, -1, -1, true); - String errmsg = null; - try { - if (!pg.grabPixels()) { - errmsg = "can't grab pixels from image"; - } - } - catch (InterruptedException e) { - errmsg = "interrupted grabbing pixels from image"; - } - if (errmsg != null) { - throw new IOException(errmsg + " (" + getClass().getName() + ")"); - } - theWidth = pg.getWidth(); - theHeight = pg.getHeight(); - argbPixels = (int[]) pg.getPixels(); - ciPixels = new byte[argbPixels.length]; - } - - DirectGif89Frame(int width, int height, int argb_pixels[]) { - theWidth = width; - theHeight = height; - argbPixels = new int[theWidth * theHeight]; - System.arraycopy(argb_pixels, 0, argbPixels, 0, argbPixels.length); - ciPixels = new byte[argbPixels.length]; - } - - Object getPixelSource() { - return argbPixels; - } -} - - -class GifColorTable { - private int[] theColors = new int[256]; - private int colorDepth; - private int transparentIndex = -1; - private int ciCount = 0; - private ReverseColorMap ciLookup; - - GifColorTable() { - ciLookup = new ReverseColorMap(); - } - - GifColorTable(Color[] colors) { - int n2copy = Math.min(theColors.length, colors.length); - for (int i = 0; i < n2copy; ++i) { - theColors[i] = colors[i].getRGB(); - } - } - - int getDepth() { - return colorDepth; - } - - int getTransparent() { - return transparentIndex; - } - - void setTransparent(int color_index) { - transparentIndex = color_index; - } - - void processPixels(Gif89Frame gf) throws IOException { - if (gf instanceof DirectGif89Frame) { - filterPixels((DirectGif89Frame) gf); - } - else { - trackPixelUsage((IndexGif89Frame) gf); - } - } - - void closePixelProcessing() { - colorDepth = computeColorDepth(ciCount); - } - - void encode(OutputStream os) throws IOException { - int palette_size = 1 << colorDepth; - for (int i = 0; i < palette_size; ++i) { - os.write(theColors[i] >> 16 & 0xff); - os.write(theColors[i] >> 8 & 0xff); - os.write(theColors[i] & 0xff); - } - } - - private void filterPixels(DirectGif89Frame dgf) throws IOException { - if (ciLookup == null) { - throw new IOException("RGB frames require palette autodetection"); - } - int[] argb_pixels = (int[]) dgf.getPixelSource(); - byte[] ci_pixels = dgf.getPixelSink(); - int npixels = argb_pixels.length; - for (int i = 0; i < npixels; ++i) { - int argb = argb_pixels[i]; - if ((argb >>> 24) < 0x80) { - if (transparentIndex == -1) { - transparentIndex = ciCount; - } - else if (argb != theColors[transparentIndex]) { - ci_pixels[i] = (byte) transparentIndex; - continue; - } - } - int color_index = ciLookup.getPaletteIndex(argb & 0xffffff); - if (color_index == -1) { - if (ciCount == 256) { - throw new IOException("can't encode as GIF (> 256 colors)"); - } - theColors[ciCount] = argb; - ciLookup.put(argb & 0xffffff, ciCount); - ci_pixels[i] = (byte) ciCount; - ++ciCount; - } - else { - ci_pixels[i] = (byte) color_index; - } - } - } - - private void trackPixelUsage(IndexGif89Frame igf) { - byte[] ci_pixels = (byte[]) igf.getPixelSource(); - int npixels = ci_pixels.length; - for (int i = 0; i < npixels; ++i) { - if (ci_pixels[i] >= ciCount) { - ciCount = ci_pixels[i] + 1; - } - } - } - - private int computeColorDepth(int colorcount) { - if (colorcount <= 2) { - return 1; - } - if (colorcount <= 4) { - return 2; - } - if (colorcount <= 16) { - return 4; - } - return 8; - } -} - -class ReverseColorMap { - private static class ColorRecord { - int rgb; - int ipalette; - - ColorRecord(int rgb, int ipalette) { - this.rgb = rgb; - this.ipalette = ipalette; - } - } - - private static final int HCAPACITY = 2053; - private ColorRecord[] hTable = new ColorRecord[HCAPACITY]; - - int getPaletteIndex(int rgb) { - ColorRecord rec; - for (int itable = rgb % hTable.length; - (rec = hTable[itable]) != null && rec.rgb != rgb; - itable = ++itable % hTable.length - ) { - ; - } - if (rec != null) { - return rec.ipalette; - } - return -1; - } - - - void put(int rgb, int ipalette) { - int itable; - for (itable = rgb % hTable.length; - hTable[itable] != null; - itable = ++itable % hTable.length - ) { - ; - } - hTable[itable] = new ColorRecord(rgb, ipalette); - } -} - -abstract class Gif89Frame { - static final int DM_UNDEFINED = 0; - static final int DM_LEAVE = 1; - static final int DM_BGCOLOR = 2; - static final int DM_REVERT = 3; - int theWidth = -1; - int theHeight = -1; - byte[] ciPixels; - - private Point thePosition = new Point(0, 0); - private boolean isInterlaced; - private int csecsDelay; - private int disposalCode = DM_LEAVE; - - void setPosition(Point p) { - thePosition = new Point(p); - } - - void setInterlaced(boolean b) { - isInterlaced = b; - } - - void setDelay(int interval) { - csecsDelay = interval; - } - - void setDisposalMode(int code) { - disposalCode = code; - } - - Gif89Frame() { - } - - abstract Object getPixelSource(); - - int getWidth() { - return theWidth; - } - - int getHeight() { - return theHeight; - } - - byte[] getPixelSink() { - return ciPixels; - } - - void encode(OutputStream os, boolean epluribus, int color_depth, - int transparent_index) throws IOException { - writeGraphicControlExtension(os, epluribus, transparent_index); - writeImageDescriptor(os); - new GifPixelsEncoder( - theWidth, theHeight, ciPixels, isInterlaced, color_depth - ).encode(os); - } - - private void writeGraphicControlExtension(OutputStream os, boolean epluribus, - int itransparent) throws IOException { - int transflag = itransparent == -1 ? 0 : 1; - if (transflag == 1 || epluribus) { - os.write((int) '!'); - os.write(0xf9); - os.write(4); - os.write((disposalCode << 2) | transflag); - Put.leShort(csecsDelay, os); - os.write(itransparent); - os.write(0); - } - } - - private void writeImageDescriptor(OutputStream os) throws IOException { - os.write((int) ','); - Put.leShort(thePosition.x, os); - Put.leShort(thePosition.y, os); - Put.leShort(theWidth, os); - Put.leShort(theHeight, os); - os.write(isInterlaced ? 0x40 : 0); - } -} - -class GifPixelsEncoder { - private static final int EOF = -1; - private int imgW, imgH; - private byte[] pixAry; - private boolean wantInterlaced; - private int initCodeSize; - private int countDown; - private int xCur, yCur; - private int curPass; - - GifPixelsEncoder(int width, int height, byte[] pixels, boolean interlaced, - int color_depth) { - imgW = width; - imgH = height; - pixAry = pixels; - wantInterlaced = interlaced; - initCodeSize = Math.max(2, color_depth); - } - - void encode(OutputStream os) throws IOException { - os.write(initCodeSize); - - countDown = imgW * imgH; - xCur = yCur = curPass = 0; - - compress(initCodeSize + 1, os); - - os.write(0); - } - - private void bumpPosition() { - ++xCur; - if (xCur == imgW) { - xCur = 0; - if (!wantInterlaced) { - ++yCur; - } - else { - switch (curPass) { - case 0: - yCur += 8; - if (yCur >= imgH) { - ++curPass; - yCur = 4; - } - break; - case 1: - yCur += 8; - if (yCur >= imgH) { - ++curPass; - yCur = 2; - } - break; - case 2: - yCur += 4; - if (yCur >= imgH) { - ++curPass; - yCur = 1; - } - break; - case 3: - yCur += 2; - break; - } - } - } - } - - private int nextPixel() { - if (countDown == 0) { - return EOF; - } - --countDown; - byte pix = pixAry[yCur * imgW + xCur]; - bumpPosition(); - return pix & 0xff; - } - - static final int BITS = 12; - static final int HSIZE = 5003; - int n_bits; - int maxbits = BITS; - int maxcode; - int maxmaxcode = 1 << BITS; - - final int MAXCODE(int n_bits) { - return (1 << n_bits) - 1; - } - - int[] htab = new int[HSIZE]; - int[] codetab = new int[HSIZE]; - int hsize = HSIZE; - int free_ent = 0; - boolean clear_flg = false; - int g_init_bits; - int ClearCode; - int EOFCode; - - void compress(int init_bits, OutputStream outs) throws IOException { - int fcode; - int i /* = 0 */; - int c; - int ent; - int disp; - int hsize_reg; - int hshift; - g_init_bits = init_bits; - clear_flg = false; - n_bits = g_init_bits; - maxcode = MAXCODE(n_bits); - ClearCode = 1 << (init_bits - 1); - EOFCode = ClearCode + 1; - free_ent = ClearCode + 2; - - char_init(); - ent = nextPixel(); - hshift = 0; - for (fcode = hsize; fcode < 65536; fcode *= 2) { - ++hshift; - } - hshift = 8 - hshift; - hsize_reg = hsize; - cl_hash(hsize_reg); - output(ClearCode, outs); - outer_loop: - while ((c = nextPixel()) != EOF) { - fcode = (c << maxbits) + ent; - i = (c << hshift) ^ ent; - if (htab[i] == fcode) { - ent = codetab[i]; - continue; - } - else if (htab[i] >= 0) { - disp = hsize_reg - i; - if (i == 0) { - disp = 1; - } - do { - if ((i -= disp) < 0) { - i += hsize_reg; - } - - if (htab[i] == fcode) { - ent = codetab[i]; - continue outer_loop; - } - } while (htab[i] >= 0); - } - output(ent, outs); - ent = c; - if (free_ent < maxmaxcode) { - codetab[i] = free_ent++; - htab[i] = fcode; - } - else { - cl_block(outs); - } - } - output(ent, outs); - output(EOFCode, outs); - } - - int cur_accum = 0; - int cur_bits = 0; - int masks[] = {0x0000, 0x0001, 0x0003, 0x0007, 0x000F, - 0x001F, 0x003F, 0x007F, 0x00FF, - 0x01FF, 0x03FF, 0x07FF, 0x0FFF, - 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF}; - - void output(int code, OutputStream outs) throws IOException { - cur_accum &= masks[cur_bits]; - if (cur_bits > 0) { - cur_accum |= (code << cur_bits); - } - else { - cur_accum = code; - } - - cur_bits += n_bits; - - while (cur_bits >= 8) { - char_out((byte) (cur_accum & 0xff), outs); - cur_accum >>= 8; - cur_bits -= 8; - } - if (free_ent > maxcode || clear_flg) { - if (clear_flg) { - maxcode = MAXCODE(n_bits = g_init_bits); - clear_flg = false; - } - else { - ++n_bits; - if (n_bits == maxbits) { - maxcode = maxmaxcode; - } - else { - maxcode = MAXCODE(n_bits); - } - } - } - if (code == EOFCode) { - - while (cur_bits > 0) { - char_out((byte) (cur_accum & 0xff), outs); - cur_accum >>= 8; - cur_bits -= 8; - } - flush_char(outs); - } - } - - - void cl_block(OutputStream outs) throws IOException { - cl_hash(hsize); - free_ent = ClearCode + 2; - clear_flg = true; - - output(ClearCode, outs); - } - - - void cl_hash(int hsize) { - for (int i = 0; i < hsize; ++i) { - htab[i] = -1; - } - } - - int a_count; - - void char_init() { - a_count = 0; - } - - byte[] accum = new byte[256]; - - void char_out(byte c, OutputStream outs) throws IOException { - accum[a_count++] = c; - if (a_count >= 254) { - flush_char(outs); - } - } - - void flush_char(OutputStream outs) throws IOException { - if (a_count > 0) { - outs.write(a_count); - outs.write(accum, 0, a_count); - a_count = 0; - } - } -} - -class IndexGif89Frame extends Gif89Frame { - - IndexGif89Frame(int width, int height, byte ci_pixels[]) { - theWidth = width; - theHeight = height; - ciPixels = new byte[theWidth * theHeight]; - System.arraycopy(ci_pixels, 0, ciPixels, 0, ciPixels.length); - } - - Object getPixelSource() { - return ciPixels; - } -} - - -final class Put { - static void ascii(String s, OutputStream os) throws IOException { - byte[] bytes = new byte[s.length()]; - for (int i = 0; i < bytes.length; ++i) { - bytes[i] = (byte) s.charAt(i); - } - os.write(bytes); - } - - static void leShort(int i16, OutputStream os) throws IOException { - os.write(i16 & 0xff); - os.write(i16 >> 8 & 0xff); - } -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/graph/HRule.java b/apps/jrobin/java/src/org/jrobin/graph/HRule.java deleted file mode 100644 index 163d59a21748fe1605b43557c44e3bce07847e80..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/HRule.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.graph; - -import java.awt.*; - -class HRule extends Rule { - final double value; - - HRule(double value, Paint color, LegendText legend, float width) { - super(color, legend, width); - this.value = value; - } - - void setLegendVisibility(double minval, double maxval, boolean forceLegend) { - legend.enabled &= (forceLegend || (value >= minval && value <= maxval)); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/ImageParameters.java b/apps/jrobin/java/src/org/jrobin/graph/ImageParameters.java deleted file mode 100644 index ddc55b181d3a0da44222f6fad81be2ac58e37ff0..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/ImageParameters.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -class ImageParameters { - long start, end; - double minval, maxval; - int unitsexponent; - double base; - double magfact; - char symbol; - double ygridstep; - int ylabfact; - double decimals; - int quadrant; - double scaledstep; - int xsize; - int ysize; - int xorigin; - int yorigin; - int unitslength; - int xgif, ygif; - String unit; -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/ImageWorker.java b/apps/jrobin/java/src/org/jrobin/graph/ImageWorker.java deleted file mode 100644 index 7a5fd53c337e51f2b70e84b3b1e48b3d6dc416d1..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/ImageWorker.java +++ /dev/null @@ -1,224 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.*; -import java.awt.font.LineMetrics; -import java.awt.geom.AffineTransform; -import java.awt.image.BufferedImage; -import java.io.*; -import java.util.Iterator; -import javax.imageio.ImageIO; -import javax.imageio.ImageWriteParam; -import javax.imageio.ImageWriter; - -class ImageWorker { - private static final String DUMMY_TEXT = "Dummy"; - - private BufferedImage img; - private Graphics2D gd; - private int imgWidth, imgHeight; - private AffineTransform aftInitial; - - ImageWorker(int width, int height) { - resize(width, height); - } - - void resize(int width, int height) { - if (gd != null) { - gd.dispose(); - } - this.imgWidth = width; - this.imgHeight = height; - this.img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); - this.gd = img.createGraphics(); - this.aftInitial = gd.getTransform(); - this.setAntiAliasing(false); - } - - void clip(int x, int y, int width, int height) { - gd.setClip(x, y, width, height); - } - - void transform(int x, int y, double angle) { - gd.translate(x, y); - gd.rotate(angle); - } - - void reset() { - gd.setTransform(aftInitial); - gd.setClip(0, 0, imgWidth, imgHeight); - } - - void fillRect(int x, int y, int width, int height, Paint paint) { - gd.setPaint(paint); - gd.fillRect(x, y, width, height); - } - - void fillPolygon(int[] x, int[] y, Paint paint) { - gd.setPaint(paint); - gd.fillPolygon(x, y, x.length); - } - - void fillPolygon(double[] x, double yBottom, double[] yTop, Paint paint) { - gd.setPaint(paint); - PathIterator path = new PathIterator(yTop); - for (int[] pos = path.getNextPath(); pos != null; pos = path.getNextPath()) { - int start = pos[0], end = pos[1], n = end - start; - int[] xDev = new int[n + 2], yDev = new int[n + 2]; - for (int i = start; i < end; i++) { - xDev[i - start] = (int) x[i]; - yDev[i - start] = (int) yTop[i]; - } - xDev[n] = xDev[n - 1]; - xDev[n + 1] = xDev[0]; - yDev[n] = yDev[n + 1] = (int) yBottom; - gd.fillPolygon(xDev, yDev, xDev.length); - gd.drawPolygon(xDev, yDev, xDev.length); - } - } - - void fillPolygon(double[] x, double[] yBottom, double[] yTop, Paint paint) { - gd.setPaint(paint); - PathIterator path = new PathIterator(yTop); - for (int[] pos = path.getNextPath(); pos != null; pos = path.getNextPath()) { - int start = pos[0], end = pos[1], n = end - start; - int[] xDev = new int[n * 2], yDev = new int[n * 2]; - for (int i = start; i < end; i++) { - int ix1 = i - start, ix2 = n * 2 - 1 - i + start; - xDev[ix1] = xDev[ix2] = (int) x[i]; - yDev[ix1] = (int) yTop[i]; - yDev[ix2] = (int) yBottom[i]; - } - gd.fillPolygon(xDev, yDev, xDev.length); - gd.drawPolygon(xDev, yDev, xDev.length); - } - } - - void drawLine(int x1, int y1, int x2, int y2, Paint paint, Stroke stroke) { - gd.setStroke(stroke); - gd.setPaint(paint); - gd.drawLine(x1, y1, x2, y2); - } - - void drawPolyline(int[] x, int[] y, Paint paint, Stroke stroke) { - gd.setStroke(stroke); - gd.setPaint(paint); - gd.drawPolyline(x, y, x.length); - } - - void drawPolyline(double[] x, double[] y, Paint paint, Stroke stroke) { - gd.setPaint(paint); - gd.setStroke(stroke); - PathIterator path = new PathIterator(y); - for (int[] pos = path.getNextPath(); pos != null; pos = path.getNextPath()) { - int start = pos[0], end = pos[1]; - int[] xDev = new int[end - start], yDev = new int[end - start]; - for (int i = start; i < end; i++) { - xDev[i - start] = (int) x[i]; - yDev[i - start] = (int) y[i]; - } - gd.drawPolyline(xDev, yDev, xDev.length); - } - } - - void drawString(String text, int x, int y, Font font, Paint paint) { - gd.setFont(font); - gd.setPaint(paint); - gd.drawString(text, x, y); - } - - double getFontAscent(Font font) { - LineMetrics lm = font.getLineMetrics(DUMMY_TEXT, gd.getFontRenderContext()); - return lm.getAscent(); - } - - double getFontHeight(Font font) { - LineMetrics lm = font.getLineMetrics(DUMMY_TEXT, gd.getFontRenderContext()); - return lm.getAscent() + lm.getDescent(); - } - - double getStringWidth(String text, Font font) { - return font.getStringBounds(text, 0, text.length(), gd.getFontRenderContext()).getBounds().getWidth(); - } - - void setAntiAliasing(boolean enable) { - gd.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - enable ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); - gd.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON); - gd.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); - } - - void dispose() { - gd.dispose(); - } - - void saveImage(OutputStream stream, String type, float quality) throws IOException { - if (type.equalsIgnoreCase("png")) { - ImageIO.write(img, "png", stream); - } - else if (type.equalsIgnoreCase("gif")) { - GifEncoder gifEncoder = new GifEncoder(img); - gifEncoder.encode(stream); - } - else if (type.equalsIgnoreCase("jpg") || type.equalsIgnoreCase("jpeg")) { - Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpg"); - ImageWriter writer = iter.next(); - ImageWriteParam iwp = writer.getDefaultWriteParam(); - - iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); - iwp.setCompressionQuality(quality); - writer.setOutput(stream); - writer.write(img); - writer.dispose(); - } - else { - throw new IOException("Unsupported image format: " + type); - } - stream.flush(); - } - - byte[] saveImage(String path, String type, float quality) throws IOException { - byte[] bytes = getImageBytes(type, quality); - RandomAccessFile f = new RandomAccessFile(path, "rw"); - try { - f.write(bytes); - return bytes; - } finally { - f.close(); - } - } - - byte[] getImageBytes(String type, float quality) throws IOException { - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - try { - saveImage(stream, type, quality); - return stream.toByteArray(); - } finally { - stream.close(); - } - } - - public void loadImage(String imageFile) throws IOException { - BufferedImage wpImage = ImageIO.read(new File(imageFile)); - TexturePaint paint = new TexturePaint(wpImage, new Rectangle(0, 0, wpImage.getWidth(), wpImage.getHeight())); - gd.setPaint(paint); - gd.fillRect(0, 0, wpImage.getWidth(), wpImage.getHeight()); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/LegendComposer.java b/apps/jrobin/java/src/org/jrobin/graph/LegendComposer.java deleted file mode 100644 index 85a9b0e18ede4827a3693b509f0ebecb733d6f28..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/LegendComposer.java +++ /dev/null @@ -1,172 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.util.ArrayList; -import java.util.List; - -class LegendComposer implements RrdGraphConstants { - private RrdGraphDef gdef; - private ImageWorker worker; - private int legX, legY, legWidth; - private double interlegendSpace; - private double leading; - private double smallLeading; - private double boxSpace; - - LegendComposer(RrdGraph rrdGraph, int legX, int legY, int legWidth) { - this.gdef = rrdGraph.gdef; - this.worker = rrdGraph.worker; - this.legX = legX; - this.legY = legY; - this.legWidth = legWidth; - interlegendSpace = rrdGraph.getInterlegendSpace(); - leading = rrdGraph.getLeading(); - smallLeading = rrdGraph.getSmallLeading(); - boxSpace = rrdGraph.getBoxSpace(); - } - - int placeComments() { - Line line = new Line(); - for (CommentText comment : gdef.comments) { - if (comment.isValidGraphElement()) { - if (!line.canAccomodate(comment)) { - line.layoutAndAdvance(false); - line.clear(); - } - line.add(comment); - } - } - line.layoutAndAdvance(true); - worker.dispose(); - return legY; - } - - class Line { - private String lastMarker; - private double width; - private int spaceCount; - private boolean noJustification; - private List<CommentText> comments = new ArrayList<CommentText>(); - - Line() { - clear(); - } - - void clear() { - lastMarker = ""; - width = 0; - spaceCount = 0; - noJustification = false; - comments.clear(); - } - - boolean canAccomodate(CommentText comment) { - // always accommodate if empty - if (comments.size() == 0) { - return true; - } - // cannot accommodate if the last marker was \j, \l, \r, \c, \s - if (lastMarker.equals(ALIGN_LEFT_MARKER) || lastMarker.equals(ALIGN_CENTER_MARKER) || - lastMarker.equals(ALIGN_RIGHT_MARKER) || lastMarker.equals(ALIGN_JUSTIFIED_MARKER) || - lastMarker.equals(VERTICAL_SPACING_MARKER)) { - return false; - } - // cannot accommodate if line would be too long - double commentWidth = getCommentWidth(comment); - if (!lastMarker.equals(GLUE_MARKER)) { - commentWidth += interlegendSpace; - } - return width + commentWidth <= legWidth; - } - - void add(CommentText comment) { - double commentWidth = getCommentWidth(comment); - if (comments.size() > 0 && !lastMarker.equals(GLUE_MARKER)) { - commentWidth += interlegendSpace; - spaceCount++; - } - width += commentWidth; - lastMarker = comment.marker; - noJustification |= lastMarker.equals(NO_JUSTIFICATION_MARKER); - comments.add(comment); - } - - void layoutAndAdvance(boolean isLastLine) { - if (comments.size() > 0) { - if (lastMarker.equals(ALIGN_LEFT_MARKER)) { - placeComments(legX, interlegendSpace); - } - else if (lastMarker.equals(ALIGN_RIGHT_MARKER)) { - placeComments(legX + legWidth - width, interlegendSpace); - } - else if (lastMarker.equals(ALIGN_CENTER_MARKER)) { - placeComments(legX + (legWidth - width) / 2.0, interlegendSpace); - } - else if (lastMarker.equals(ALIGN_JUSTIFIED_MARKER)) { - // anything to justify? - if (spaceCount > 0) { - placeComments(legX, (legWidth - width) / spaceCount + interlegendSpace); - } - else { - placeComments(legX, interlegendSpace); - } - } - else if (lastMarker.equals(VERTICAL_SPACING_MARKER)) { - placeComments(legX, interlegendSpace); - } - else { - // nothing specified, align with respect to '\J' - if (noJustification || isLastLine) { - placeComments(legX, interlegendSpace); - } - else { - placeComments(legX, (legWidth - width) / spaceCount + interlegendSpace); - } - } - if (lastMarker.equals(VERTICAL_SPACING_MARKER)) { - legY += smallLeading; - } - else { - legY += leading; - } - } - } - - private double getCommentWidth(CommentText comment) { - double commentWidth = worker.getStringWidth(comment.resolvedText, gdef.getFont(FONTTAG_LEGEND)); - if (comment instanceof LegendText) { - commentWidth += boxSpace; - } - return commentWidth; - } - - private void placeComments(double xStart, double space) { - double x = xStart; - for (CommentText comment : comments) { - comment.x = (int) x; - comment.y = legY; - x += getCommentWidth(comment); - if (!comment.marker.equals(GLUE_MARKER)) { - x += space; - } - } - } - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/LegendText.java b/apps/jrobin/java/src/org/jrobin/graph/LegendText.java deleted file mode 100644 index da2efb79ccc431a223b71a207ff20920a5e13bab..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/LegendText.java +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.*; - -class LegendText extends CommentText { - final Paint legendColor; - - LegendText(Paint legendColor, String text) { - super(text); - this.legendColor = legendColor; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/Line.java b/apps/jrobin/java/src/org/jrobin/graph/Line.java deleted file mode 100644 index 76ce08bc41c631beec8c2915caec0af4a14d3b01..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/Line.java +++ /dev/null @@ -1,30 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.*; - -class Line extends SourcedPlotElement { - final float width; - - Line(String srcName, Paint color, float width) { - super(srcName, color); - this.width = width; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/Mapper.java b/apps/jrobin/java/src/org/jrobin/graph/Mapper.java deleted file mode 100644 index e0b2f8f9c65865f6569bb74d5d81a147dc47beca..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/Mapper.java +++ /dev/null @@ -1,72 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -class Mapper { - private RrdGraphDef gdef; - private ImageParameters im; - private double pixieX, pixieY; - - Mapper(RrdGraph rrdGraph) { - this(rrdGraph.gdef, rrdGraph.im); - } - - Mapper(RrdGraphDef gdef, ImageParameters im) { - this.gdef = gdef; - this.im = im; - pixieX = (double) im.xsize / (double) (im.end - im.start); - if (!gdef.logarithmic) { - pixieY = (double) im.ysize / (im.maxval - im.minval); - } - else { - pixieY = (double) im.ysize / (Math.log10(im.maxval) - Math.log10(im.minval)); - } - } - - int xtr(double mytime) { - return (int) ((double) im.xorigin + pixieX * (mytime - im.start)); - } - - int ytr(double value) { - double yval; - if (!gdef.logarithmic) { - yval = im.yorigin - pixieY * (value - im.minval) + 0.5; - } - else { - if (value < im.minval) { - yval = im.yorigin; - } - else { - yval = im.yorigin - pixieY * (Math.log10(value) - Math.log10(im.minval)) + 0.5; - } - } - if (!gdef.rigid) { - return (int) yval; - } - else if ((int) yval > im.yorigin) { - return im.yorigin + 2; - } - else if ((int) yval < im.yorigin - im.ysize) { - return im.yorigin - im.ysize - 2; - } - else { - return (int) yval; - } - } -} \ No newline at end of file diff --git a/apps/jrobin/java/src/org/jrobin/graph/Normalizer.java b/apps/jrobin/java/src/org/jrobin/graph/Normalizer.java deleted file mode 100644 index 6a3ce265dcf624bf69464ca5bcdae2902cb4d540..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/Normalizer.java +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ - -package org.jrobin.graph; - -import org.jrobin.core.Util; - -import java.util.Arrays; - -class Normalizer { - final private double[] timestamps; - final int count; - final double step; - - Normalizer(long tStart, long tEnd, int count) { - this.count = count; - this.step = (tEnd - tStart) / Double.valueOf(count - 1); - this.timestamps = new double[count]; - for (int i = 0; i < count; i++) { - this.timestamps[i] = tStart + ((double) i / (double) (count - 1)) * (tEnd - tStart); - } - } - - double[] getTimestamps() { - return timestamps; - } - - double[] normalize(long[] rawTimestamps, double[] rawValues) { - int rawCount = rawTimestamps.length; - long rawStep = rawTimestamps[1] - rawTimestamps[0]; - // check if we have a simple match - if (rawCount == count && rawStep == step && rawTimestamps[0] == timestamps[0]) { - return getCopyOf(rawValues); - } - // reset all normalized values to NaN - double[] values = new double[count]; - Arrays.fill(values, Double.NaN); - for (int rawSeg = 0, seg = 0; rawSeg < rawCount && seg < count; rawSeg++) { - double rawValue = rawValues[rawSeg]; - if (!Double.isNaN(rawValue)) { - long rawLeft = rawTimestamps[rawSeg] - rawStep; - while (seg < count && rawLeft >= timestamps[seg]) { - seg++; - } - boolean overlap = true; - for (int fillSeg = seg; overlap && fillSeg < count; fillSeg++) { - double left = timestamps[fillSeg] - step; - double t1 = Math.max(rawLeft, left); - double t2 = Math.min(rawTimestamps[rawSeg], timestamps[fillSeg]); - if (t1 < t2) { - values[fillSeg] = Util.sum(values[fillSeg], (t2 - t1) * rawValues[rawSeg]); - } - else { - overlap = false; - } - } - } - } - for (int seg = 0; seg < count; seg++) { - values[seg] /= step; - } - return values; - } - - private static double[] getCopyOf(double[] rawValues) { - int n = rawValues.length; - double[] values = new double[n]; - System.arraycopy(rawValues, 0, values, 0, n); - return values; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/PDef.java b/apps/jrobin/java/src/org/jrobin/graph/PDef.java deleted file mode 100644 index 875e88a476b771ccaa12ccad981e8157ed04dec1..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/PDef.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.data.DataProcessor; -import org.jrobin.data.Plottable; - -class PDef extends Source { - private Plottable plottable; - - PDef(String name, Plottable plottable) { - super(name); - this.plottable = plottable; - } - - void requestData(DataProcessor dproc) { - dproc.addDatasource(name, plottable); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/PathIterator.java b/apps/jrobin/java/src/org/jrobin/graph/PathIterator.java deleted file mode 100644 index 3e7055f16cea2309893594c0b8d357d95a30a7f5..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/PathIterator.java +++ /dev/null @@ -1,48 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -class PathIterator { - private double[] y; - private int pos = 0; - - PathIterator(double[] y) { - this.y = y; - } - - int[] getNextPath() { - while (pos < y.length) { - if (Double.isNaN(y[pos])) { - pos++; - } - else { - int endPos = pos + 1; - while (endPos < y.length && !Double.isNaN(y[endPos])) { - endPos++; - } - int[] result = {pos, endPos}; - pos = endPos; - if (result[1] - result[0] >= 2) { - return result; - } - } - } - return null; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/PercentileDef.java b/apps/jrobin/java/src/org/jrobin/graph/PercentileDef.java deleted file mode 100644 index 43e38053f25801010a625a9563f8a4298d041b7c..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/PercentileDef.java +++ /dev/null @@ -1,46 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2011 Craig Miskell - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.data.DataProcessor; -import org.jrobin.graph.Source; - -public class PercentileDef extends Source { - private String m_sourceName; - - private double m_percentile; - - private boolean m_includenan; - - PercentileDef(String name, String sourceName, double percentile) { - this(name, sourceName, percentile, false); - } - - PercentileDef(String name, String sourceName, double percentile, boolean includenan) { - super(name); - m_sourceName = sourceName; - m_percentile = percentile; - m_includenan = includenan; - } - - @Override - void requestData(DataProcessor dproc) { - dproc.addDatasource(name, m_sourceName, m_percentile, m_includenan); - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/PlotElement.java b/apps/jrobin/java/src/org/jrobin/graph/PlotElement.java deleted file mode 100644 index 5217434e86a73fd23ec16e6cd526056a4bb25d61..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/PlotElement.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.*; - -class PlotElement { - final Paint color; - - PlotElement(Paint color) { - this.color = color; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/PrintText.java b/apps/jrobin/java/src/org/jrobin/graph/PrintText.java deleted file mode 100644 index ee6875a79bb02f6eafff14089bfa86eeca5f8bfb..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/PrintText.java +++ /dev/null @@ -1,62 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; -import org.jrobin.data.DataProcessor; - -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -class PrintText extends CommentText { - static final String UNIT_MARKER = "([^%]?)%(s|S)"; - static final Pattern UNIT_PATTERN = Pattern.compile(UNIT_MARKER); - - private final String srcName, consolFun; - private final boolean includedInGraph; - - PrintText(String srcName, String consolFun, String text, boolean includedInGraph) { - super(text); - this.srcName = srcName; - this.consolFun = consolFun; - this.includedInGraph = includedInGraph; - } - - boolean isPrint() { - return !includedInGraph; - } - - void resolveText(DataProcessor dproc, ValueScaler valueScaler) throws RrdException { - super.resolveText(dproc, valueScaler); - if (resolvedText != null) { - double value = dproc.getAggregate(srcName, consolFun); - Matcher matcher = UNIT_PATTERN.matcher(resolvedText); - if (matcher.find()) { - // unit specified - ValueScaler.Scaled scaled = valueScaler.scale(value, matcher.group(2).equals("s")); - resolvedText = resolvedText.substring(0, matcher.start()) + - matcher.group(1) + scaled.unit + resolvedText.substring(matcher.end()); - value = scaled.value; - } - resolvedText = Util.sprintf(resolvedText, value); - trimIfGlue(); - } - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/RrdGraph.java b/apps/jrobin/java/src/org/jrobin/graph/RrdGraph.java deleted file mode 100644 index 6e1d2f886869337bdc44cf841238d4f59200c831..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/RrdGraph.java +++ /dev/null @@ -1,677 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; -import org.jrobin.data.DataProcessor; - -import javax.swing.*; -import java.awt.*; -import java.io.IOException; - -/** - * Class which actually creates JRobin graphs (does the hard work). - */ -public class RrdGraph implements RrdGraphConstants { - RrdGraphDef gdef; - ImageParameters im = new ImageParameters(); - DataProcessor dproc; - ImageWorker worker; - Mapper mapper; - RrdGraphInfo info = new RrdGraphInfo(); - private String signature; - - /** - * Creates graph from the corresponding {@link RrdGraphDef} object. - * - * @param gdef Graph definition - * @throws IOException Thrown in case of I/O error - * @throws RrdException Thrown in case of JRobin related error - */ - public RrdGraph(RrdGraphDef gdef) throws IOException, RrdException { - this.gdef = gdef; - signature = gdef.getSignature(); - worker = new ImageWorker(100, 100); // Dummy worker, just to start with something - try { - createGraph(); - } - finally { - worker.dispose(); - worker = null; - dproc = null; - } - } - - /** - * Returns complete graph information in a single object. - * - * @return Graph information (width, height, filename, image bytes, etc...) - */ - public RrdGraphInfo getRrdGraphInfo() { - return info; - } - - private void createGraph() throws RrdException, IOException { - boolean lazy = lazyCheck(); - if (!lazy || gdef.printStatementCount() != 0) { - fetchData(); - resolveTextElements(); - if (gdef.shouldPlot() && !lazy) { - calculatePlotValues(); - findMinMaxValues(); - identifySiUnit(); - expandValueRange(); - removeOutOfRangeRules(); - initializeLimits(); - placeLegends(); - createImageWorker(); - drawBackground(); - drawData(); - drawGrid(); - drawAxis(); - drawText(); - drawLegend(); - drawRules(); - gator(); - drawOverlay(); - saveImage(); - } - } - collectInfo(); - } - - private void collectInfo() { - info.filename = gdef.filename; - info.width = im.xgif; - info.height = im.ygif; - for (CommentText comment : gdef.comments) { - if (comment instanceof PrintText) { - PrintText pt = (PrintText) comment; - if (pt.isPrint()) { - info.addPrintLine(pt.resolvedText); - } - } - } - if (gdef.imageInfo != null) { - info.imgInfo = Util.sprintf(gdef.imageInfo, gdef.filename, im.xgif, im.ygif); - } - } - - private void saveImage() throws IOException { - if (!gdef.filename.equals("-")) { - info.bytes = worker.saveImage(gdef.filename, gdef.imageFormat, gdef.imageQuality); - } - else { - info.bytes = worker.getImageBytes(gdef.imageFormat, gdef.imageQuality); - } - } - - private void drawOverlay() throws IOException { - if (gdef.overlayImage != null) { - worker.loadImage(gdef.overlayImage); - } - } - - private void gator() { - if (!gdef.onlyGraph && gdef.showSignature) { - Font font = gdef.getFont(FONTTAG_WATERMARK); - int x = (int) (im.xgif - 2 - worker.getFontAscent(font)); - int y = 4; - worker.transform(x, y, Math.PI / 2); - worker.drawString(signature, 0, 0, font, Color.LIGHT_GRAY); - worker.reset(); - } - } - - private void drawRules() { - worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2); - for (PlotElement pe : gdef.plotElements) { - if (pe instanceof HRule) { - HRule hr = (HRule) pe; - if (hr.value >= im.minval && hr.value <= im.maxval) { - int y = mapper.ytr(hr.value); - worker.drawLine(im.xorigin, y, im.xorigin + im.xsize, y, hr.color, new BasicStroke(hr.width)); - } - } - else if (pe instanceof VRule) { - VRule vr = (VRule) pe; - if (vr.timestamp >= im.start && vr.timestamp <= im.end) { - int x = mapper.xtr(vr.timestamp); - worker.drawLine(x, im.yorigin, x, im.yorigin - im.ysize, vr.color, new BasicStroke(vr.width)); - } - } - } - worker.reset(); - } - - private void drawText() { - if (!gdef.onlyGraph) { - if (gdef.title != null) { - int x = im.xgif / 2 - (int) (worker.getStringWidth(gdef.title, gdef.getFont(FONTTAG_TITLE)) / 2); - int y = PADDING_TOP + (int) worker.getFontAscent(gdef.getFont(FONTTAG_TITLE)); - worker.drawString(gdef.title, x, y, gdef.getFont(FONTTAG_TITLE), gdef.colors[COLOR_FONT]); - } - if (gdef.verticalLabel != null) { - int x = PADDING_LEFT; - int y = im.yorigin - im.ysize / 2 + (int) worker.getStringWidth(gdef.verticalLabel, gdef.getFont(FONTTAG_UNIT)) / 2; - int ascent = (int) worker.getFontAscent(gdef.getFont(FONTTAG_UNIT)); - worker.transform(x, y, -Math.PI / 2); - worker.drawString(gdef.verticalLabel, 0, ascent, gdef.getFont(FONTTAG_UNIT), gdef.colors[COLOR_FONT]); - worker.reset(); - } - } - } - - private void drawGrid() { - if (!gdef.onlyGraph) { - Paint shade1 = gdef.colors[COLOR_SHADEA], shade2 = gdef.colors[COLOR_SHADEB]; - Stroke borderStroke = new BasicStroke(1); - worker.drawLine(0, 0, im.xgif - 1, 0, shade1, borderStroke); - worker.drawLine(1, 1, im.xgif - 2, 1, shade1, borderStroke); - worker.drawLine(0, 0, 0, im.ygif - 1, shade1, borderStroke); - worker.drawLine(1, 1, 1, im.ygif - 2, shade1, borderStroke); - worker.drawLine(im.xgif - 1, 0, im.xgif - 1, im.ygif - 1, shade2, borderStroke); - worker.drawLine(0, im.ygif - 1, im.xgif - 1, im.ygif - 1, shade2, borderStroke); - worker.drawLine(im.xgif - 2, 1, im.xgif - 2, im.ygif - 2, shade2, borderStroke); - worker.drawLine(1, im.ygif - 2, im.xgif - 2, im.ygif - 2, shade2, borderStroke); - if (gdef.drawXGrid) { - new TimeAxis(this).draw(); - } - if (gdef.drawYGrid) { - boolean ok; - if (gdef.altYMrtg) { - ok = new ValueAxisMrtg(this).draw(); - } - else if (gdef.logarithmic) { - ok = new ValueAxisLogarithmic(this).draw(); - } - else { - ok = new ValueAxis(this).draw(); - } - if (!ok) { - String msg = "No Data Found"; - worker.drawString(msg, - im.xgif / 2 - (int) worker.getStringWidth(msg, gdef.getFont(FONTTAG_TITLE)) / 2, - (2 * im.yorigin - im.ysize) / 2, - gdef.getFont(FONTTAG_TITLE), gdef.colors[COLOR_FONT]); - } - } - } - } - - private void drawData() throws RrdException { - worker.setAntiAliasing(gdef.antiAliasing); - worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2); - double areazero = mapper.ytr((im.minval > 0.0) ? im.minval : (im.maxval < 0.0) ? im.maxval : 0.0); - double[] x = xtr(dproc.getTimestamps()), lastY = null; - // draw line, area and stack - for (PlotElement plotElement : gdef.plotElements) { - if (plotElement instanceof SourcedPlotElement) { - SourcedPlotElement source = (SourcedPlotElement) plotElement; - double[] y = ytr(source.getValues()); - if (source instanceof Line) { - worker.drawPolyline(x, y, source.color, new BasicStroke(((Line) source).width)); - } - else if (source instanceof Area) { - worker.fillPolygon(x, areazero, y, source.color); - } - else if (source instanceof Stack) { - Stack stack = (Stack) source; - float width = stack.getParentLineWidth(); - if (width >= 0F) { - // line - worker.drawPolyline(x, y, stack.color, new BasicStroke(width)); - } - else { - // area - worker.fillPolygon(x, lastY, y, stack.color); - worker.drawPolyline(x, lastY, stack.getParentColor(), new BasicStroke(0)); - } - } - else { - // should not be here - throw new RrdException("Unknown plot source: " + source.getClass().getName()); - } - lastY = y; - } - } - worker.reset(); - worker.setAntiAliasing(false); - } - - private void drawAxis() { - if (!gdef.onlyGraph) { - Paint gridColor = gdef.colors[COLOR_GRID]; - Paint fontColor = gdef.colors[COLOR_FONT]; - Paint arrowColor = gdef.colors[COLOR_ARROW]; - Stroke stroke = new BasicStroke(1); - worker.drawLine(im.xorigin + im.xsize, im.yorigin, im.xorigin + im.xsize, im.yorigin - im.ysize, - gridColor, stroke); - worker.drawLine(im.xorigin, im.yorigin - im.ysize, im.xorigin + im.xsize, im.yorigin - im.ysize, - gridColor, stroke); - worker.drawLine(im.xorigin - 4, im.yorigin, im.xorigin + im.xsize + 4, im.yorigin, - fontColor, stroke); - worker.drawLine(im.xorigin, im.yorigin, im.xorigin, im.yorigin - im.ysize, - gridColor, stroke); - worker.drawLine(im.xorigin + im.xsize + 4, im.yorigin - 3, im.xorigin + im.xsize + 4, im.yorigin + 3, - arrowColor, stroke); - worker.drawLine(im.xorigin + im.xsize + 4, im.yorigin - 3, im.xorigin + im.xsize + 9, im.yorigin, - arrowColor, stroke); - worker.drawLine(im.xorigin + im.xsize + 4, im.yorigin + 3, im.xorigin + im.xsize + 9, im.yorigin, - arrowColor, stroke); - } - } - - private void drawBackground() throws IOException { - worker.fillRect(0, 0, im.xgif, im.ygif, gdef.colors[COLOR_BACK]); - if (gdef.backgroundImage != null) { - worker.loadImage(gdef.backgroundImage); - } - worker.fillRect(im.xorigin, im.yorigin - im.ysize, im.xsize, im.ysize, gdef.colors[COLOR_CANVAS]); - } - - private void createImageWorker() { - worker.resize(im.xgif, im.ygif); - } - - private void placeLegends() { - if (!gdef.noLegend && !gdef.onlyGraph) { - int border = (int) (getSmallFontCharWidth() * PADDING_LEGEND); - LegendComposer lc = new LegendComposer(this, border, im.ygif, im.xgif - 2 * border); - im.ygif = lc.placeComments() + PADDING_BOTTOM; - } - } - - private void initializeLimits() throws RrdException { - im.xsize = gdef.width; - im.ysize = gdef.height; - im.unitslength = gdef.unitsLength; - if (gdef.onlyGraph) { - if (im.ysize > 64) { - throw new RrdException("Cannot create graph only, height too big"); - } - im.xorigin = 0; - } - else { - im.xorigin = (int) (PADDING_LEFT + im.unitslength * getSmallFontCharWidth()); - } - if (gdef.verticalLabel != null) { - im.xorigin += getFontHeight(FONTTAG_UNIT); - } - if (gdef.onlyGraph) { - im.yorigin = im.ysize; - } - else { - im.yorigin = PADDING_TOP + im.ysize; - } - mapper = new Mapper(this); - if (gdef.title != null) { - im.yorigin += getFontHeight(FONTTAG_TITLE) + PADDING_TITLE; - } - if (gdef.onlyGraph) { - im.xgif = im.xsize; - im.ygif = im.yorigin; - } - else { - im.xgif = PADDING_RIGHT + im.xsize + im.xorigin; - im.ygif = im.yorigin + (int) (PADDING_PLOT * getFontHeight(FONTTAG_DEFAULT)); - } - } - - private void removeOutOfRangeRules() { - for (PlotElement plotElement : gdef.plotElements) { - if (plotElement instanceof HRule) { - ((HRule) plotElement).setLegendVisibility(im.minval, im.maxval, gdef.forceRulesLegend); - } - else if (plotElement instanceof VRule) { - ((VRule) plotElement).setLegendVisibility(im.start, im.end, gdef.forceRulesLegend); - } - } - } - - private void expandValueRange() { - im.ygridstep = (gdef.valueAxisSetting != null) ? gdef.valueAxisSetting.gridStep : Double.NaN; - im.ylabfact = (gdef.valueAxisSetting != null) ? gdef.valueAxisSetting.labelFactor : 0; - if (!gdef.rigid && !gdef.logarithmic) { - double sensiblevalues[] = { - 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 - }; - double scaled_min, scaled_max, adj; - if (Double.isNaN(im.ygridstep)) { - if (gdef.altYMrtg) { /* mrtg */ - im.decimals = Math.ceil(Math.log10(Math.max(Math.abs(im.maxval), Math.abs(im.minval)))); - im.quadrant = 0; - if (im.minval < 0) { - im.quadrant = 2; - if (im.maxval <= 0) { - im.quadrant = 4; - } - } - switch (im.quadrant) { - case 2: - im.scaledstep = Math.ceil(50 * Math.pow(10, -(im.decimals)) * Math.max(Math.abs(im.maxval), - Math.abs(im.minval))) * Math.pow(10, im.decimals - 2); - scaled_min = -2 * im.scaledstep; - scaled_max = 2 * im.scaledstep; - break; - case 4: - im.scaledstep = Math.ceil(25 * Math.pow(10, - -(im.decimals)) * Math.abs(im.minval)) * Math.pow(10, im.decimals - 2); - scaled_min = -4 * im.scaledstep; - scaled_max = 0; - break; - default: /* quadrant 0 */ - im.scaledstep = Math.ceil(25 * Math.pow(10, -(im.decimals)) * im.maxval) * - Math.pow(10, im.decimals - 2); - scaled_min = 0; - scaled_max = 4 * im.scaledstep; - break; - } - im.minval = scaled_min; - im.maxval = scaled_max; - } - else if (gdef.altAutoscale) { - /* measure the amplitude of the function. Make sure that - graph boundaries are slightly higher then max/min vals - so we can see amplitude on the graph */ - double delt, fact; - - delt = im.maxval - im.minval; - adj = delt * 0.1; - fact = 2.0 * Math.pow(10.0, - Math.floor(Math.log10(Math.max(Math.abs(im.minval), Math.abs(im.maxval)))) - 2); - if (delt < fact) { - adj = (fact - delt) * 0.55; - } - im.minval -= adj; - im.maxval += adj; - } - else if (gdef.altAutoscaleMax) { - /* measure the amplitude of the function. Make sure that - graph boundaries are slightly higher than max vals - so we can see amplitude on the graph */ - adj = (im.maxval - im.minval) * 0.1; - im.maxval += adj; - } - else { - scaled_min = im.minval / im.magfact; - scaled_max = im.maxval / im.magfact; - for (int i = 1; sensiblevalues[i] > 0; i++) { - if (sensiblevalues[i - 1] >= scaled_min && sensiblevalues[i] <= scaled_min) { - im.minval = sensiblevalues[i] * im.magfact; - } - if (-sensiblevalues[i - 1] <= scaled_min && -sensiblevalues[i] >= scaled_min) { - im.minval = -sensiblevalues[i - 1] * im.magfact; - } - if (sensiblevalues[i - 1] >= scaled_max && sensiblevalues[i] <= scaled_max) { - im.maxval = sensiblevalues[i - 1] * im.magfact; - } - if (-sensiblevalues[i - 1] <= scaled_max && -sensiblevalues[i] >= scaled_max) { - im.maxval = -sensiblevalues[i] * im.magfact; - } - } - } - } - else { - im.minval = (double) im.ylabfact * im.ygridstep * - Math.floor(im.minval / ((double) im.ylabfact * im.ygridstep)); - im.maxval = (double) im.ylabfact * im.ygridstep * - Math.ceil(im.maxval / ((double) im.ylabfact * im.ygridstep)); - } - - } - } - - private void identifySiUnit() { - im.unitsexponent = gdef.unitsExponent; - im.base = gdef.base; - if (!gdef.logarithmic) { - final char symbol[] = {'a', 'f', 'p', 'n', 'u', 'm', ' ', 'k', 'M', 'G', 'T', 'P', 'E'}; - int symbcenter = 6; - double digits; - if (im.unitsexponent != Integer.MAX_VALUE) { - digits = Math.floor(im.unitsexponent / 3.0); - } - else { - 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) < symbol.length) && ((digits + symbcenter) >= 0)) { - im.symbol = symbol[(int) digits + symbcenter]; - } - else { - im.symbol = '?'; - } - } - } - - private void findMinMaxValues() { - double minval = Double.NaN, maxval = Double.NaN; - for (PlotElement pe : gdef.plotElements) { - if (pe instanceof SourcedPlotElement) { - minval = Util.min(((SourcedPlotElement) pe).getMinValue(), minval); - maxval = Util.max(((SourcedPlotElement) pe).getMaxValue(), maxval); - } - } - if (Double.isNaN(minval)) { - minval = 0D; - } - if (Double.isNaN(maxval)) { - maxval = 1D; - } - im.minval = gdef.minValue; - im.maxval = gdef.maxValue; - /* adjust min and max values */ - if (Double.isNaN(im.minval) || ((!gdef.logarithmic && !gdef.rigid) && im.minval > minval)) { - im.minval = minval; - } - if (Double.isNaN(im.maxval) || (!gdef.rigid && im.maxval < maxval)) { - if (gdef.logarithmic) { - im.maxval = maxval * 1.1; - } - else { - im.maxval = maxval; - } - } - /* make sure min is smaller than max */ - if (im.minval > im.maxval) { - im.minval = 0.99 * im.maxval; - } - /* make sure min and max are not equal */ - if (Math.abs(im.minval - im.maxval) < .0000001) { - im.maxval *= 1.01; - if (!gdef.logarithmic) { - im.minval *= 0.99; - } - /* make sure min and max are not both zero */ - if (im.maxval == 0.0) { - im.maxval = 1.0; - } - } - } - - private void calculatePlotValues() throws RrdException { - for (PlotElement pe : gdef.plotElements) { - if (pe instanceof SourcedPlotElement) { - ((SourcedPlotElement) pe).assignValues(dproc); - } - } - } - - private void resolveTextElements() throws RrdException { - ValueScaler valueScaler = new ValueScaler(gdef.base); - for (CommentText comment : gdef.comments) { - comment.resolveText(dproc, valueScaler); - } - } - - private void fetchData() throws RrdException, IOException { - dproc = new DataProcessor(gdef.startTime, gdef.endTime); - dproc.setPoolUsed(gdef.poolUsed); - if (gdef.step > 0) { - dproc.setStep(gdef.step); - } - for (Source src : gdef.sources) { - src.requestData(dproc); - } - dproc.processData(); - //long[] t = dproc.getTimestamps(); - //im.start = t[0]; - //im.end = t[t.length - 1]; - im.start = gdef.startTime; - im.end = gdef.endTime; - } - - private boolean lazyCheck() { - // redraw if lazy option is not set or file does not exist - if (!gdef.lazy || !Util.fileExists(gdef.filename)) { - return false; // 'false' means 'redraw' - } - // redraw if not enough time has passed - long secPerPixel = (gdef.endTime - gdef.startTime) / gdef.width; - long elapsed = Util.getTimestamp() - Util.getLastModified(gdef.filename); - return elapsed <= secPerPixel; - } - - private void drawLegend() { - if (!gdef.onlyGraph && !gdef.noLegend) { - int ascent = (int) worker.getFontAscent(gdef.getFont(FONTTAG_LEGEND)); - int box = (int) getBox(), boxSpace = (int) (getBoxSpace()); - for (CommentText c : gdef.comments) { - if (c.isValidGraphElement()) { - int x = c.x, y = c.y + ascent; - if (c instanceof LegendText) { - // draw with BOX - worker.fillRect(x, y - box, box, box, gdef.colors[COLOR_FRAME]); - worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, gdef.colors[COLOR_CANVAS]); - worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, ((LegendText) c).legendColor); - worker.drawString(c.resolvedText, x + boxSpace, y, gdef.getFont(FONTTAG_LEGEND), gdef.colors[COLOR_FONT]); - } - else { - worker.drawString(c.resolvedText, x, y, gdef.getFont(FONTTAG_LEGEND), gdef.colors[COLOR_FONT]); - } - } - } - } - } - - // helper methods - - double getFontHeight(int fonttag) { - return worker.getFontHeight(gdef.getFont(fonttag)); - } - - double getFontCharWidth(int fonttag) { - return worker.getStringWidth("a", gdef.getFont(fonttag)); - } - - double getSmallFontHeight() { - return getFontHeight(FONTTAG_LEGEND); - } - - @SuppressWarnings("unused") - private double getTitleFontHeight() { - return getFontHeight(FONTTAG_TITLE); - } - - private double getSmallFontCharWidth() { - return getFontCharWidth(FONTTAG_LEGEND); - } - - double getInterlegendSpace() { - return getFontCharWidth(FONTTAG_LEGEND) * LEGEND_INTERSPACING; - } - - double getLeading() { - return getFontHeight(FONTTAG_LEGEND) * LEGEND_LEADING; - } - - double getSmallLeading() { - return getFontHeight(FONTTAG_LEGEND) * LEGEND_LEADING_SMALL; - } - - double getBoxSpace() { - return Math.ceil(getFontHeight(FONTTAG_LEGEND) * LEGEND_BOX_SPACE); - } - - private double getBox() { - return getFontHeight(FONTTAG_LEGEND) * LEGEND_BOX; - } - - double[] xtr(long[] timestamps) { - /* - double[] timestampsDev = new double[timestamps.length]; - for (int i = 0; i < timestamps.length; i++) { - timestampsDev[i] = mapper.xtr(timestamps[i]); - } - return timestampsDev; - */ - double[] timestampsDev = new double[2 * timestamps.length - 1]; - for (int i = 0, j = 0; i < timestamps.length; i += 1, j += 2) { - timestampsDev[j] = mapper.xtr(timestamps[i]); - if (i < timestamps.length - 1) { - timestampsDev[j + 1] = timestampsDev[j]; - } - } - return timestampsDev; - } - - double[] ytr(double[] values) { - /* - double[] valuesDev = new double[values.length]; - for (int i = 0; i < values.length; i++) { - if (Double.isNaN(values[i])) { - valuesDev[i] = Double.NaN; - } - else { - valuesDev[i] = mapper.ytr(values[i]); - } - } - return valuesDev; - */ - double[] valuesDev = new double[2 * values.length - 1]; - for (int i = 0, j = 0; i < values.length; i += 1, j += 2) { - if (Double.isNaN(values[i])) { - valuesDev[j] = Double.NaN; - } - else { - valuesDev[j] = mapper.ytr(values[i]); - } - if (j > 0) { - valuesDev[j - 1] = valuesDev[j]; - } - } - return valuesDev; - } - - /** - * Renders this graph onto graphing device - * - * @param g Graphics handle - */ - public void render(Graphics g) { - byte[] imageData = getRrdGraphInfo().getBytes(); - ImageIcon image = new ImageIcon(imageData); - image.paintIcon(null, g, 0, 0); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/RrdGraphConstants.java b/apps/jrobin/java/src/org/jrobin/graph/RrdGraphConstants.java deleted file mode 100644 index 87e6fafed3a13ad0b5382664f377ea40c399df29..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/RrdGraphConstants.java +++ /dev/null @@ -1,368 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.*; -import java.util.Calendar; -import java.util.Locale; - -/** - * Class to represent various constants used for graphing. No methods are specified. - */ -public interface RrdGraphConstants { - /** - * Default graph starting time - */ - String DEFAULT_START = "end-1d"; - /** - * Default graph ending time - */ - String DEFAULT_END = "now"; - - /** - * Constant to represent second - */ - int SECOND = Calendar.SECOND; - /** - * Constant to represent minute - */ - int MINUTE = Calendar.MINUTE; - /** - * Constant to represent hour - */ - int HOUR = Calendar.HOUR_OF_DAY; - /** - * Constant to represent day - */ - int DAY = Calendar.DAY_OF_MONTH; - /** - * Constant to represent week - */ - int WEEK = Calendar.WEEK_OF_YEAR; - /** - * Constant to represent month - */ - int MONTH = Calendar.MONTH; - /** - * Constant to represent year - */ - int YEAR = Calendar.YEAR; - - /** - * Constant to represent Monday - */ - int MONDAY = Calendar.MONDAY; - /** - * Constant to represent Tuesday - */ - int TUESDAY = Calendar.TUESDAY; - /** - * Constant to represent Wednesday - */ - int WEDNESDAY = Calendar.WEDNESDAY; - /** - * Constant to represent Thursday - */ - int THURSDAY = Calendar.THURSDAY; - /** - * Constant to represent Friday - */ - int FRIDAY = Calendar.FRIDAY; - /** - * Constant to represent Saturday - */ - int SATURDAY = Calendar.SATURDAY; - /** - * Constant to represent Sunday - */ - int SUNDAY = Calendar.SUNDAY; - - /** - * Index of the canvas color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} - */ - int COLOR_CANVAS = 0; - /** - * Index of the background color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} - */ - int COLOR_BACK = 1; - /** - * Index of the top-left graph shade color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} - */ - int COLOR_SHADEA = 2; - /** - * Index of the bottom-right graph shade color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} - */ - int COLOR_SHADEB = 3; - /** - * Index of the minor grid color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} - */ - int COLOR_GRID = 4; - /** - * Index of the major grid color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} - */ - int COLOR_MGRID = 5; - /** - * Index of the font color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} - */ - int COLOR_FONT = 6; - /** - * Index of the frame color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} - */ - int COLOR_FRAME = 7; - /** - * Index of the arrow color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} - */ - int COLOR_ARROW = 8; - - /** - * Allowed color names which can be used in {@link RrdGraphDef#setColor(String, java.awt.Paint)} method - */ - String[] COLOR_NAMES = { - "canvas", "back", "shadea", "shadeb", "grid", "mgrid", "font", "frame", "arrow" - }; - - /** - * Default first day of the week (obtained from the default locale) - */ - int FIRST_DAY_OF_WEEK = Calendar.getInstance(Locale.getDefault()).getFirstDayOfWeek(); - - /** - * Default graph canvas color - */ - Color DEFAULT_CANVAS_COLOR = Color.WHITE; - /** - * Default graph background color - */ - Color DEFAULT_BACK_COLOR = new Color(245, 245, 245); - /** - * Default top-left graph shade color - */ - Color DEFAULT_SHADEA_COLOR = new Color(200, 200, 200); - /** - * Default bottom-right graph shade color - */ - Color DEFAULT_SHADEB_COLOR = new Color(150, 150, 150); - /** - * Default minor grid color - */ - Color DEFAULT_GRID_COLOR = new Color(171, 171, 171, 95); - // Color DEFAULT_GRID_COLOR = new Color(140, 140, 140); - /** - * Default major grid color - */ - Color DEFAULT_MGRID_COLOR = new Color(255, 91, 91, 95); - // Color DEFAULT_MGRID_COLOR = new Color(130, 30, 30); - /** - * Default font color - */ - Color DEFAULT_FONT_COLOR = Color.BLACK; - /** - * Default frame color - */ - Color DEFAULT_FRAME_COLOR = Color.BLACK; - /** - * Default arrow color - */ - Color DEFAULT_ARROW_COLOR = Color.RED; - - /** - * Constant to represent left alignment marker - */ - String ALIGN_LEFT_MARKER = "\\l"; - /** - * Constant to represent centered alignment marker - */ - String ALIGN_CENTER_MARKER = "\\c"; - /** - * Constant to represent right alignment marker - */ - String ALIGN_RIGHT_MARKER = "\\r"; - /** - * Constant to represent justified alignment marker - */ - String ALIGN_JUSTIFIED_MARKER = "\\j"; - /** - * Constant to represent "glue" marker - */ - String GLUE_MARKER = "\\g"; - /** - * Constant to represent vertical spacing marker - */ - String VERTICAL_SPACING_MARKER = "\\s"; - /** - * Constant to represent no justification markers - */ - String NO_JUSTIFICATION_MARKER = "\\J"; - /** - * Used internally - */ - String[] MARKERS = { - ALIGN_LEFT_MARKER, ALIGN_CENTER_MARKER, ALIGN_RIGHT_MARKER, - ALIGN_JUSTIFIED_MARKER, GLUE_MARKER, VERTICAL_SPACING_MARKER, NO_JUSTIFICATION_MARKER - }; - - /** - * Constant to represent in-memory image name - */ - String IN_MEMORY_IMAGE = "-"; - - /** - * Default units length - */ - int DEFAULT_UNITS_LENGTH = 9; - /** - * Default graph width - */ - int DEFAULT_WIDTH = 400; - /** - * Default graph height - */ - int DEFAULT_HEIGHT = 100; - /** - * Default image format - */ - String DEFAULT_IMAGE_FORMAT = "gif"; - /** - * Default image quality, used only for jpeg graphs - */ - float DEFAULT_IMAGE_QUALITY = 0.8F; // only for jpegs, not used for png/gif - /** - * Default value base - */ - double DEFAULT_BASE = 1000; - - /** - * Default font name, determined based on the current operating system - */ - String DEFAULT_FONT_NAME = System.getProperty("os.name").toLowerCase().contains("windows") ? - "Lucida Sans Typewriter" : "Monospaced"; - - /** - * Default graph small font - */ - String DEFAULT_MONOSPACE_FONT_FILE = "DejaVuSansMono.ttf"; - - /** - * Default graph large font - */ - String DEFAULT_PROPORTIONAL_FONT_FILE = "DejaVuSans-Bold.ttf"; - - /** - * Used internally - */ - double LEGEND_LEADING = 1.2; // chars - /** - * Used internally - */ - double LEGEND_LEADING_SMALL = 0.7; // chars - /** - * Used internally - */ - double LEGEND_BOX_SPACE = 1.2; // chars - /** - * Used internally - */ - double LEGEND_BOX = 0.7; // chars - /** - * Used internally - */ - int LEGEND_INTERSPACING = 2; // chars - /** - * Used internally - */ - int PADDING_LEFT = 0; // pix - absent vertical label provides padding here - /** - * Used internally - */ - int PADDING_TOP = 5; // pix -- additional top pixels added by frame border - /** - * Used internally - */ - int PADDING_TITLE = 7; // pix - /** - * Used internally - */ - int PADDING_RIGHT = 20; // pix - /** - * Used internally - */ - double PADDING_PLOT = 1.7; //chars - /** - * Used internally - */ - double PADDING_LEGEND = 2.1; // chars - /** - * Used internally - */ - int PADDING_BOTTOM = 6; // pix - /** - * Used internally - */ - int PADDING_VLABEL = 8; // pix - - /** - * Stroke used to draw grid - */ - // solid line - //Stroke GRID_STROKE = new BasicStroke(1); - - // dotted line - Stroke GRID_STROKE = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, new float[] {1, 1}, 0); - /** - * Stroke used to draw ticks - */ - Stroke TICK_STROKE = new BasicStroke(1); - - /** - * Index of the default font. Used in {@link RrdGraphDef#setFont(int, java.awt.Font)} - */ - int FONTTAG_DEFAULT = 0; - - /** - * Index of the title font. Used in {@link RrdGraphDef#setFont(int, java.awt.Font)} - */ - int FONTTAG_TITLE = 1; - - /** - * Index of the axis label font. Used in {@link RrdGraphDef#setFont(int, java.awt.Font)} - */ - int FONTTAG_AXIS = 2; - - /** - * Index of the vertical unit label font. Used in {@link RrdGraphDef#setFont(int, java.awt.Font)} - */ - int FONTTAG_UNIT = 3; - - /** - * Index of the graph legend font. Used in {@link RrdGraphDef#setFont(int, java.awt.Font)} - */ - int FONTTAG_LEGEND = 4; - - /** - * Index of the edge watermark font. Used in {@link RrdGraphDef#setFont(int, java.awt.Font)} - */ - int FONTTAG_WATERMARK = 5; - - /** - * Allowed font tag names which can be used in {@link RrdGraphDef#setFont(String, java.awt.Font)} method - */ - String[] FONTTAG_NAMES = { - "DEFAULT", "TITLE", "AXIS", "UNIT", "LEGEND", "WATERMARK" - }; -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/RrdGraphDef.java b/apps/jrobin/java/src/org/jrobin/graph/RrdGraphDef.java deleted file mode 100644 index 6f4e966a395d4c99534e14885c1efaf37a55b66f..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/RrdGraphDef.java +++ /dev/null @@ -1,1223 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; -import org.jrobin.data.Plottable; - -import java.awt.*; -import java.io.File; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -/** - * Class which should be used to define new JRobin graph. Once constructed and populated with data - * object of this class should be passed to the constructor of the {@link RrdGraph} class which - * will actually create the graph. - * <p> - * The text printed below the actual graph can be formated by appending - * special escaped characters at the end of a text. When ever such a - * character occurs, all pending text is pushed onto the graph according to - * the character specified. - * <p> - * Valid markers are: \j for justified, \l for left aligned, \r for right - * aligned and \c for centered. - * <p> - * Normally there are two space characters inserted between every two - * items printed into the graph. The space following a string can be - * suppressed by putting a \g at the end of the string. The \g also squashes - * any space inside the string if it is at the very end of the string. - * This can be used in connection with %s to suppress empty unit strings. - * <p> - * A special case is COMMENT:\s this inserts some additional vertical - * space before placing the next row of legends. - * <p> - * When text has to be formated without special instructions from your - * side, RRDTool will automatically justify the text as soon as one string - * goes over the right edge. If you want to prevent the justification - * without forcing a newline, you can use the special tag \J at the end of - * the string to disable the auto justification. - */ -public class RrdGraphDef implements RrdGraphConstants { - boolean poolUsed = false; // ok - boolean antiAliasing = false; // ok - String filename = RrdGraphConstants.IN_MEMORY_IMAGE; // ok - long startTime, endTime; // ok - TimeAxisSetting timeAxisSetting = null; // ok - ValueAxisSetting valueAxisSetting = null; // ok - boolean altYGrid = false; // ok - boolean noMinorGrid = false; // ok - boolean altYMrtg = false; // ok - boolean altAutoscale = false; // ok - boolean altAutoscaleMax = false; // ok - int unitsExponent = Integer.MAX_VALUE; // ok - int unitsLength = DEFAULT_UNITS_LENGTH; // ok - String verticalLabel = null; // ok - int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT; // ok - boolean interlaced = false; // ok - String imageInfo = null; // ok - String imageFormat = DEFAULT_IMAGE_FORMAT; // ok - float imageQuality = DEFAULT_IMAGE_QUALITY; // ok - String backgroundImage = null; // ok - String overlayImage = null; // ok - String unit = null; // ok - String signature = "Created with JRobin"; // ok - boolean lazy = false; // ok - double minValue = Double.NaN; // ok - double maxValue = Double.NaN; // ok - boolean rigid = false; // ok - double base = DEFAULT_BASE; // ok - boolean logarithmic = false; // ok - Paint[] colors = new Paint[]{ - // ok - DEFAULT_CANVAS_COLOR, - DEFAULT_BACK_COLOR, - DEFAULT_SHADEA_COLOR, - DEFAULT_SHADEB_COLOR, - DEFAULT_GRID_COLOR, - DEFAULT_MGRID_COLOR, - DEFAULT_FONT_COLOR, - DEFAULT_FRAME_COLOR, - DEFAULT_ARROW_COLOR - }; - boolean noLegend = false; // ok - boolean onlyGraph = false; // ok - boolean forceRulesLegend = false; // ok - String title = null; // ok - long step = 0; // ok - Font[] fonts = new Font[FONTTAG_NAMES.length]; - boolean drawXGrid = true; // ok - boolean drawYGrid = true; // ok - int firstDayOfWeek = FIRST_DAY_OF_WEEK; // ok - boolean showSignature = true; - File fontDir = null; - - List<Source> sources = new ArrayList<Source>(); - List<CommentText> comments = new ArrayList<CommentText>(); - List<PlotElement> plotElements = new ArrayList<PlotElement>(); - - /** - * Creates RrdGraphDef object and sets default time span (default ending time is 'now', - * default starting time is 'end-1day'. - */ - public RrdGraphDef() { - try { - setTimeSpan(Util.getTimestamps(DEFAULT_START, DEFAULT_END)); - } catch (RrdException e) { - throw new RuntimeException(e); - } - - String fontdirProperty = System.getProperty("jrobin.fontdir"); - if (fontdirProperty != null && fontdirProperty.length() != 0) { - fontDir = new File(fontdirProperty); - } - - fonts[FONTTAG_DEFAULT] = new Font(DEFAULT_FONT_NAME, Font.PLAIN, 8); - fonts[FONTTAG_TITLE] = new Font(DEFAULT_FONT_NAME, Font.PLAIN, 9); - fonts[FONTTAG_AXIS] = new Font(DEFAULT_FONT_NAME, Font.PLAIN, 7); - fonts[FONTTAG_UNIT] = new Font(DEFAULT_FONT_NAME, Font.PLAIN, 8); - fonts[FONTTAG_LEGEND] = new Font(DEFAULT_FONT_NAME, Font.PLAIN, 8); - fonts[FONTTAG_WATERMARK] = new Font(DEFAULT_FONT_NAME, Font.PLAIN, 1).deriveFont(5.5F); - } - - protected Font getFontFromResourceName(String name) { - Font font = null; - Exception exception = null; - URL file = null; - - if (fontDir != null) { - try { - file = new URL("file://" + new File(fontDir, name).getAbsolutePath()); - } catch (MalformedURLException e) { - // fall through to the jar - exception = e; - } - } - if (file == null) { - file = this.getClass().getResource(name); - } - - if (file != null) { - // System.err.println("Found a font URL: " + file.toExternalForm()); - try { - InputStream fontStream = file.openStream(); - font = Font.createFont(Font.TRUETYPE_FONT, fontStream); - fontStream.close(); - } catch (Exception e) { - exception = e; - } - } - else { - // we can't find our fonts, fall back to the system font - System.err.println("An error occurred loading the font '" + name + "'. Falling back to the default."); - if (exception != null) { - System.err.println(exception.getLocalizedMessage()); - } - font = new Font(DEFAULT_FONT_NAME, Font.PLAIN, 10); - } - - if (font == null) { - font = new Font(null, Font.PLAIN, 10); - } - return font; - } - - /** - * Sets the signature string that runs along the right-side of the graph. - * Defaults to "Created with JRobin". - * - * @param signature the string to print - */ - public void setSignature(String signature) { - this.signature = signature; - } - - /** - * Gets the signature string that runs along the right-side of the graph. - * - * @return the signature string - */ - public String getSignature() { - return this.signature; - } - - /** - * 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 - */ - public void setStartTime(long time) { - this.startTime = time; - if (time <= 0) { - this.startTime += Util.getTime(); - } - } - - /** - * 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 - */ - public void setEndTime(long time) { - this.endTime = time; - if (time <= 0) { - this.endTime += Util.getTime(); - } - } - - /** - * 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 - */ - public void setTimeSpan(long startTime, long endTime) { - setStartTime(startTime); - setEndTime(endTime); - } - - /** - * Sets starting and ending time for the for the graph. Timestamps in seconds since epoch are - * required. - * - * @param timestamps Array of timestamps. The first array item will be chosen for the starting - * timestamp. The last array item will be chosen for the ending timestamp. - */ - public void setTimeSpan(long[] timestamps) { - setTimeSpan(timestamps[0], timestamps[timestamps.length - 1]); - } - - /** - * Sets RrdDbPool usage policy (defaults to true). If set to true, - * {@link org.jrobin.core.RrdDbPool RrdDbPool} will be used to - * access individual RRD files. If set to false, RRD files will be accessed directly. - * - * @param poolUsed true, if RrdDbPool class should be used. False otherwise. - */ - public void setPoolUsed(boolean poolUsed) { - this.poolUsed = poolUsed; - } - - /** - * Sets the name of the graph to generate. Since JRobin outputs GIFs, PNGs, - * and JPEGs it's recommended that the filename end in either .gif, - * .png or .jpg. JRobin does not enforce this, however. If the filename is - * set to '-' the image will be created only in memory (no file will be created). - * PNG and GIF formats are recommended but JPEGs should be avoided. - * - * @param filename Path to the image file - */ - public void setFilename(String filename) { - this.filename = filename; - } - - /** - * Configures x-axis grid and labels. The x-axis label is quite complex to configure. - * So if you don't have very special needs, you can rely on the autoconfiguration to - * get this right. - * <p> - * Otherwise, you have to configure three elements making up the x-axis labels - * and grid. The base grid, the major grid and the labels. - * The configuration is based on the idea that you first specify a well - * known amount of time and then say how many times - * it has to pass between each minor/major grid line or label. For the label - * you have to define two additional items: The precision of the label - * in seconds and the format used to generate the text - * of the label. - * <p> - * For example, if you wanted a graph with a base grid every 10 minutes and a major - * one every hour, with labels every hour you would use the following - * x-axis definition. - * <p> - * <pre> - * setTimeAxis(RrdGraphConstants.MINUTE, 10, - * RrdGraphConstants.HOUR, 1, - * RrdGraphConstants.HOUR, 1, - * 0, "%H:%M") - * </pre> - * <p> - * The precision in this example is 0 because the %X format is exact. - * If the label was the name of the day, we would have had a precision - * of 24 hours, because when you say something like 'Monday' you mean - * the whole day and not Monday morning 00:00. Thus the label should - * be positioned at noon. By defining a precision of 24 hours or - * rather 86400 seconds, you make sure that this happens. - * - * @param minorUnit Minor grid unit. Minor grid, major grid and label units - * can be one of the following constants defined in - * {@link RrdGraphConstants}: {@link RrdGraphConstants#SECOND SECOND}, - * {@link RrdGraphConstants#MINUTE MINUTE}, {@link RrdGraphConstants#HOUR HOUR}, - * {@link RrdGraphConstants#DAY DAY}, {@link RrdGraphConstants#WEEK WEEK}, - * {@link RrdGraphConstants#MONTH MONTH}, {@link RrdGraphConstants#YEAR YEAR}. - * @param minorUnitCount Number of minor grid units between minor grid lines. - * @param majorUnit Major grid unit. - * @param majorUnitCount Number of major grid units between major grid lines. - * @param labelUnit Label unit. - * @param labelUnitCount Number of label units between labels. - * @param labelSpan Label precision - * @param simpleDateFormat Date format (SimpleDateFormat pattern of strftime-like pattern) - */ - public void setTimeAxis(int minorUnit, int minorUnitCount, int majorUnit, int majorUnitCount, - int labelUnit, int labelUnitCount, int labelSpan, String simpleDateFormat) { - timeAxisSetting = new TimeAxisSetting(minorUnit, minorUnitCount, majorUnit, majorUnitCount, - labelUnit, labelUnitCount, labelSpan, simpleDateFormat); - } - - /** - * Sets vertical axis grid and labels. Makes vertical grid lines appear - * at gridStep interval. Every labelFactor*gridStep, a major grid line is printed, - * along with label showing the value of the grid line. - * - * @param gridStep Minor grid step - * @param labelFactor Specifies how many minor minor grid steps will appear between labels - * (major grid lines) - */ - public void setValueAxis(double gridStep, int labelFactor) { - valueAxisSetting = new ValueAxisSetting(gridStep, labelFactor); - } - - /** - * Places Y grid dynamically based on graph Y range. Algorithm ensures - * that you always have grid, that there are enough but not too many - * grid lines and the grid is metric. That is grid lines are placed - * every 1, 2, 5 or 10 units. - * - * @param altYGrid true, if Y grid should be calculated dynamically (defaults to false) - */ - public void setAltYGrid(boolean altYGrid) { - this.altYGrid = altYGrid; - } - - /** - * Use this method to turn off minor grid lines (printed by default) - * - * @param noMinorGrid true, to turn off, false to turn on (default) - */ - public void setNoMinorGrid(boolean noMinorGrid) { - this.noMinorGrid = noMinorGrid; - } - - /** - * Use this method to request MRTG-like graph (false by default) - * - * @param altYMrtg true, to create MRTG-like graph, false otherwise (default) - */ - public void setAltYMrtg(boolean altYMrtg) { - this.altYMrtg = altYMrtg; - } - - /** - * Computes Y range based on function absolute minimum and maximum - * values. Default algorithm uses predefined set of ranges. This is - * good in many cases but it fails miserably when you need to graph - * something like 260 + 0.001 * sin(x). Default algorithm will use Y - * range from 250 to 300 and on the graph you will see almost straight - * line. With --alt-autoscale Y range will be from slightly less the - * 260 - 0.001 to slightly more then 260 + 0.001 and periodic behavior - * will be seen. - * - * @param altAutoscale true to request alternative autoscaling, false otherwise - * (default). - */ - public void setAltAutoscale(boolean altAutoscale) { - this.altAutoscale = altAutoscale; - } - - /** - * Computes Y range based on function absolute minimum and maximum - * values. Where setAltAutoscale(true) will modify both the absolute maximum AND - * minimum values, this option will only affect the maximum value. The - * minimum value, if not defined elsewhere, will be 0. This - * option can be useful when graphing router traffic when the WAN line - * uses compression, and thus the throughput may be higher than the - * WAN line speed. - * - * @param altAutoscaleMax true to request alternative autoscaling, false - * otherwise (default) - */ - public void setAltAutoscaleMax(boolean altAutoscaleMax) { - this.altAutoscaleMax = altAutoscaleMax; - } - - /** - * Sets the 10**unitsExponent scaling of the y-axis values. Normally - * values will be scaled to the appropriate units (k, M, etc.). However - * you may wish to display units always in k (Kilo, 10e3) even if - * the data is in the M (Mega, 10e6) range for instance. Value should - * be an integer which is a multiple of 3 between -18 and 18, inclu- - * sive. It is the exponent on the units you which to use. For example, - * use 3 to display the y-axis values in k (Kilo, 10e3, thou- - * sands), use -6 to display the y-axis values in u (Micro, 10e-6, - * millionths). Use a value of 0 to prevent any scaling of the y-axis - * values. - * - * @param unitsExponent the 10**unitsExponent value for scaling y-axis values. - */ - public void setUnitsExponent(int unitsExponent) { - this.unitsExponent = unitsExponent; - } - - /** - * Sets the character width on the left side of the graph for - * y-axis values. - * - * @param unitsLength Number of characters on the left side of the graphs - * reserved for vertical axis labels. - */ - public void setUnitsLength(int unitsLength) { - this.unitsLength = unitsLength; - } - - /** - * Sets vertical label on the left side of the graph. This is normally used - * to specify the units used. - * - * @param verticalLabel Vertical axis label - */ - public void setVerticalLabel(String verticalLabel) { - this.verticalLabel = verticalLabel; - } - - /** - * Sets width of the drawing area within the graph. This affects the total - * size of the image. - * - * @param width Width of the drawing area. - */ - public void setWidth(int width) { - this.width = width; - } - - /** - * Sets height of the drawing area within the graph. This affects the total - * size of the image. - * - * @param height Height of the drawing area. - */ - public void setHeight(int height) { - this.height = height; - } - - /** - * Creates interlaced GIF image (currently not supported, - * method is present only for RRDTool comaptibility). - * - * @param interlaced true, if GIF image should be interlaced. - */ - public void setInterlaced(boolean interlaced) { - this.interlaced = interlaced; - } - - /** - * Creates additional image information. - * After the image has been created, the graph function uses imageInfo - * format string (printf-like) to create output similar to - * the {@link #print(String, String, String)} function. - * The format string is supplied with the following parameters: - * filename, xsize and ysize (in that particular order). - * <p> - * For example, in order to generate an IMG tag - * suitable for including the graph into a web page, the command - * would look like this: - * <pre> - * setImageInfo("<IMG SRC='/img/%s' WIDTH='%d' HEIGHT='%d' ALT='Demo'>"); - * </pre> - * - * @param imageInfo Image info format. Use %s placeholder for filename, %d placeholder for - * image width and height. - */ - public void setImageInfo(String imageInfo) { - this.imageInfo = imageInfo; - } - - /** - * Sets image format. - * - * @param imageFormat "PNG", "GIF" or "JPG". - */ - public void setImageFormat(String imageFormat) { - this.imageFormat = imageFormat; - } - - /** - * Sets background image - currently, only PNG images can be used as background. - * - * @param backgroundImage Path to background image - */ - public void setBackgroundImage(String backgroundImage) { - this.backgroundImage = backgroundImage; - } - - /** - * Sets overlay image - currently, only PNG images can be used as overlay. Overlay image is - * printed on the top of the image, once it is completely created. - * - * @param overlayImage Path to overlay image - */ - public void setOverlayImage(String overlayImage) { - this.overlayImage = overlayImage; - } - - /** - * Sets unit to be displayed on y axis. It is wise to use only short units on graph, however. - * - * @param unit Unit description - */ - public void setUnit(String unit) { - this.unit = unit; - } - - /** - * Creates graph only if the current graph is out of date or not existent. - * - * @param lazy true, if graph should be 'lazy', false otherwise (defualt) - */ - public void setLazy(boolean lazy) { - this.lazy = lazy; - } - - /** - * Sets the lower limit of a graph. But rather, this is the - * maximum lower bound of a graph. For example, the value -100 will - * result in a graph that has a lower limit of -100 or less. Use this - * method to expand graphs down. - * - * @param minValue Minimal value displayed on the graph - */ - public void setMinValue(double minValue) { - this.minValue = minValue; - } - - /** - * Defines the value normally located at the upper border of the - * graph. If the graph contains higher values, the upper border will - * move upwards to accommodate these values as well. - * <p> - * If you want to define an upper-limit which will not move in any - * event you have to use {@link #setRigid(boolean)} method as well. - * - * @param maxValue Maximal value displayed on the graph. - */ - public void setMaxValue(double maxValue) { - this.maxValue = maxValue; - } - - /** - * Sets rigid boundaries mode. Normally JRObin will automatically expand - * the lower and upper limit if the graph contains a value outside the - * valid range. With the <code>true</code> argument you can disable this behavior. - * - * @param rigid true if uper and lower limits should not be expanded to accomodate - * values outside of the specified range. False otherwise (default). - */ - public void setRigid(boolean rigid) { - this.rigid = rigid; - } - - /** - * Sets default base for magnitude scaling. If you are graphing memory - * (and NOT network traffic) this switch should be set to 1024 so that 1Kb is 1024 byte. - * For traffic measurement, 1 kb/s is 1000 b/s. - * - * @param base Base value (defaults to 1000.0) - */ - public void setBase(double base) { - this.base = base; - } - - /** - * Sets logarithmic y-axis scaling. - * - * @param logarithmic true, for logarithmic scaling, false otherwise (default). - */ - public void setLogarithmic(boolean logarithmic) { - this.logarithmic = logarithmic; - } - - /** - * Overrides the colors for the standard elements of the graph. The colorTag - * must be one of the following constants defined in the - * {@link RrdGraphConstants}: - * {@link RrdGraphConstants#COLOR_BACK COLOR_BACK} background, - * {@link RrdGraphConstants#COLOR_CANVAS COLOR_CANVAS} canvas, - * {@link RrdGraphConstants#COLOR_SHADEA COLOR_SHADEA} left/top border, - * {@link RrdGraphConstants#COLOR_SHADEB COLOR_SHADEB} right/bottom border, - * {@link RrdGraphConstants#COLOR_GRID COLOR_GRID} major grid, - * {@link RrdGraphConstants#COLOR_MGRID COLOR_MGRID} minor grid, - * {@link RrdGraphConstants#COLOR_FONT COLOR_FONT} font, - * {@link RrdGraphConstants#COLOR_FRAME COLOR_FRAME} axis of the graph, - * {@link RrdGraphConstants#COLOR_ARROW COLOR_ARROW} arrow. This method can - * be called multiple times to set several colors. - * - * @param colorTag Color tag, as explained above. - * @param color Any color (paint) you like - * @throws RrdException Thrown if invalid colorTag is supplied. - */ - public void setColor(int colorTag, Paint color) throws RrdException { - if (colorTag >= 0 && colorTag < colors.length) { - colors[colorTag] = color; - } - else { - throw new RrdException("Invalid color index specified: " + colorTag); - } - } - - /** - * Overrides the colors for the standard elements of the graph by element name. - * See {@link #setColor(int, java.awt.Paint)} for full explanation. - * - * @param colorName One of the following strings: "BACK", "CANVAS", "SHADEA", "SHADEB", - * "GRID", "MGRID", "FONT", "FRAME", "ARROW" - * @param color Any color (paint) you like - * @throws RrdException Thrown if invalid element name is supplied. - */ - public void setColor(String colorName, Paint color) throws RrdException { - setColor(getColorTagByName(colorName), color); - } - - private static int getColorTagByName(String colorName) throws RrdException { - for (int i = 0; i < COLOR_NAMES.length; i++) { - if (COLOR_NAMES[i].equalsIgnoreCase(colorName)) { - return i; - } - } - throw new RrdException("Unknown color name specified: " + colorName); - } - - /** - * Suppress generation of legend, only render the graph. - * - * @param noLegend true if graph legend should be omitted. False otherwise (default). - */ - public void setNoLegend(boolean noLegend) { - this.noLegend = noLegend; - } - - /** - * Suppresses anything but the graph, works only for height < 64. - * - * @param onlyGraph true if only graph should be created, false otherwise (default). - */ - public void setOnlyGraph(boolean onlyGraph) { - this.onlyGraph = onlyGraph; - } - - /** - * Force the generation of HRULE and VRULE legend even if those HRULE - * or VRULE will not be drawn because out of graph boundaries. - * - * @param forceRulesLegend true if rule legend should be always printed, - * false otherwise (default). - */ - public void setForceRulesLegend(boolean forceRulesLegend) { - this.forceRulesLegend = forceRulesLegend; - } - - /** - * Defines a title to be written into the graph. - * - * @param title Graph title. - */ - public void setTitle(String title) { - this.title = title; - } - - /** - * Suggests which time step should be used by JRobin while processing data from RRD files. - * - * @param step Desired time step (don't use this method if you don't know what you're doing). - */ - public void setStep(long step) { - this.step = step; - } - - /** - * Get the default small font for graphing. - * - * @return the font - */ - public Font getSmallFont() { - return this.fonts[FONTTAG_DEFAULT]; - } - - /** - * Get the default large font for graphing. - * - * @return the font - */ - public Font getLargeFont() { - return this.fonts[FONTTAG_TITLE]; - } - - /** - * Sets default font for graphing. Note that JRobin will behave unpredictably if proportional - * font is selected. - * - * @param smallFont Default font for graphing. Use only monospaced fonts. - * @throws RrdException Thrown if invalid fontTag is supplied. - */ - public void setSmallFont(final Font smallFont) throws RrdException{ - this.setFont(FONTTAG_DEFAULT, smallFont); - } - - /** - * Sets title font. - * - * @param largeFont Font to be used for graph title. - * @throws RrdException Thrown if invalid fontTag is supplied. - */ - public void setLargeFont(final Font largeFont) throws RrdException { - this.setFont(FONTTAG_TITLE, largeFont); - } - - /** - * Sets font to be used for a specific font tag. The fontTag - * must be one of the following constants defined in the - * {@link RrdGraphConstants}: - * {@link RrdGraphConstants#FONTTAG_DEFAULT FONTTAG_DEFAULT} default font,, - * {@link RrdGraphConstants#FONTTAG_TITLE FONTTAG_TITLE} title, - * {@link RrdGraphConstants#FONTTAG_AXIS FONTTAG_AXIS} grid axis,, - * {@link RrdGraphConstants#FONTTAG_UNIT FONTTAG_UNIT} vertical unit label,, - * {@link RrdGraphConstants#FONTTAG_LEGEND FONTTAG_LEGEND} legend, - * {@link RrdGraphConstants#FONTTAG_WATERMARK FONTTAG_WATERMARK} watermark. - * This method can be called multiple times to set several fonts. - * - * @param fontTag Font tag, as explained above. - * @param font Font to be used for tag - * @throws RrdException Thrown if invalid fontTag is supplied. - */ - public void setFont(final int fontTag, final Font font) throws RrdException { - this.setFont(fontTag, font, false); - } - - /** - * Sets font. - * - * @param fontTag Font tag, as explained above. - * @param font Font to be used for tag - * @param setAll Boolean to flag whether to set all fonts if fontTag == FONTTAG_DEFAULT - * @throws RrdException Thrown if invalid fontTag is supplied. - */ - public void setFont(final int fontTag, final Font font, final boolean setAll) throws RrdException { - this.setFont(fontTag, font, setAll, false); - } - - /** - * Sets font. - * - * @param fontTag Font tag, as explained above. - * @param font Font to be used for tag - * @param setAll Boolean to flag whether to set all fonts if fontTag == FONTTAG_DEFAULT - * @param keepSizes Boolean to flag whether to keep original font sizes if setting all fonts. - */ - public void setFont(final int fontTag, final Font font, final boolean setAll, final boolean keepSizes) { - if (fontTag == FONTTAG_DEFAULT && setAll) { - if (keepSizes) { - this.fonts[FONTTAG_DEFAULT] = font.deriveFont(this.fonts[FONTTAG_DEFAULT].getSize()); - this.fonts[FONTTAG_TITLE] = font.deriveFont(this.fonts[FONTTAG_TITLE].getSize()); - this.fonts[FONTTAG_AXIS] = font.deriveFont(this.fonts[FONTTAG_AXIS].getSize()); - this.fonts[FONTTAG_UNIT] = font.deriveFont(this.fonts[FONTTAG_UNIT].getSize()); - this.fonts[FONTTAG_LEGEND] = font.deriveFont(this.fonts[FONTTAG_LEGEND].getSize()); - this.fonts[FONTTAG_WATERMARK] = font.deriveFont(this.fonts[FONTTAG_WATERMARK].getSize()); - } else { - this.fonts[FONTTAG_DEFAULT] = font; - this.fonts[FONTTAG_TITLE] = null; - this.fonts[FONTTAG_AXIS] = null; - this.fonts[FONTTAG_UNIT] = null; - this.fonts[FONTTAG_LEGEND] = null; - this.fonts[FONTTAG_WATERMARK] = null; - } - } else { - this.fonts[fontTag] = font; - } - } - - /** - * Sets font. - * - * @param fontTag Font tag as String, as explained in {@link RrdGraphDef#setFont setFont(int, java.awt.Font)}. - * @param font Font to be used for tag - * @throws RrdException Thrown if invalid fontTag is supplied. - */ - public void setFont(final String fontTag, final Font font) throws RrdException { - this.setFont(getFontTagByName(fontTag), font); - } - - /** - * Sets font. - * - * @param fontTag Font tag as String, as explained in {@link RrdGraphDef#setFont setFont(int, java.awt.Font)}. - * @param font Font to be used for tag - * @param setAll Boolean to flag whether to set all fonts if fontTag == FONTTAG_DEFAULT - * @throws RrdException Thrown if invalid fontTag is supplied. - */ - public void setFont(final String fontTag, final Font font, final boolean setAll) throws RrdException { - this.setFont(getFontTagByName(fontTag), font, setAll); - } - - /** - * Sets font. - * - * @param fontTag Font tag as String, as explained in {@link RrdGraphDef#setFont setFont(int, java.awt.Font)}. - * @param font Font to be used for tag - * @param setAll Boolean to flag whether to set all fonts if fontTag == FONTTAG_DEFAULT - * @param keepSizes Boolean to flag whether to keep original font sizes if setting all fonts. - * @throws RrdException Thrown if invalid fontTag is supplied. - */ - public void setFont(final String fontTag, final Font font, final boolean setAll, final boolean keepSizes) throws RrdException { - this.setFont(getFontTagByName(fontTag), font, setAll, keepSizes); - } - - private static int getFontTagByName(String tagName) throws RrdException { - for (int i = 0; i < FONTTAG_NAMES.length; i++) { - if (FONTTAG_NAMES[i].equalsIgnoreCase(tagName)) { - return i; - } - } - throw new RrdException("Unknown tag name specified: " + tagName); - } - - public Font getFont(int tag) { - return this.fonts[tag] == null ? this.fonts[FONTTAG_DEFAULT] : this.fonts[tag]; - } - - /** - * Defines virtual datasource. This datasource can then be used - * in other methods like {@link #datasource(String, String)} or - * {@link #gprint(String, 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) - */ - public void datasource(String name, String rrdPath, String dsName, String consolFun) { - sources.add(new Def(name, rrdPath, dsName, consolFun)); - } - - /** - * Defines virtual datasource. This datasource can then be used - * in other methods like {@link #datasource(String, String)} or - * {@link #gprint(String, 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. - */ - public void datasource(String name, String rrdPath, String dsName, String consolFun, String backend) { - sources.add(new Def(name, rrdPath, dsName, consolFun, 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. - */ - public void datasource(String name, String rpnExpression) { - sources.add(new CDef(name, rpnExpression)); - } - - /** - * Creates a new (static) virtual datasource. The value of the datasource is constant. This value is - * evaluated by applying the given consolidation function to another virtual datasource. - * - * @param name Source name - * @param defName Other source name - * @param consolFun Consolidation function to be applied to other datasource. - */ - public void datasource(String name, String defName, String consolFun) { - sources.add(new SDef(name, defName, consolFun)); - } - - /** - * Creates a new (plottable) datasource. Datasource values are obtained from the given plottable - * object. - * - * @param name Source name. - * @param plottable Plottable object. - */ - public void datasource(String name, Plottable plottable) { - sources.add(new PDef(name, plottable)); - } - - /** - * Creates a new static virtual datasource that performs a percentile calculation on an - * another named datasource to yield a single value. - * <p> - * Requires that the other datasource has already been defined otherwise it throws an exception - * (we need to look at the existing data source to extract the required data) - * - * @param name - the new virtual datasource name - * @param sourceName - the datasource from which to extract the percentile. Must be a previously - * defined virtula datasource - * @param percentile - the percentile to extract from the source datasource - */ - public void datasource(String name, String sourceName, double percentile) { - sources.add(new PercentileDef(name, sourceName, percentile)); - } - - /** - * Creates a new static virtual datasource that performs a percentile calculation on an - * another named datasource to yield a single value. - * <p> - * Requires that the other datasource has already been defined otherwise it throws an exception - * (we need to look at the existing data source to extract the required data) - * - * @param name - the new virtual datasource name - * @param sourceName - the datasource from which to extract the percentile. Must be a previously - * defined virtula datasource - * @param percentile - the percentile to extract from the source datasource - * @param includenan - whether to include NaNs in the percentile calculations. - */ - public void datasource(String name, String sourceName, double percentile, boolean includenan) { - sources.add(new PercentileDef(name, sourceName, percentile, includenan)); - } - - /** - * Calculates the chosen consolidation function CF over the given datasource - * and creates the result by using the given format string. In - * the format string there should be a '%[l]f', '%[l]g' or '%[l]e' marker in - * the place where the number should be printed. - * <p> - * If an additional '%s' is found AFTER the marker, the value will be - * scaled and an appropriate SI magnitude unit will be printed in - * place of the '%s' marker. The scaling will take the '--base' argument - * into consideration! - * <p> - * If a '%S' is used instead of a '%s', then instead of calculating - * the appropriate SI magnitude unit for this value, the previously - * calculated SI magnitude unit will be used. This is useful if you - * want all the values in a print statement to have the same SI magnitude - * unit. If there was no previous SI magnitude calculation made, - * then '%S' behaves like a '%s', unless the value is 0, in which case - * it does not remember a SI magnitude unit and a SI magnitude unit - * will only be calculated when the next '%s' is seen or the next '%S' - * for a non-zero value. - * <p> - * Print results are collected in the {@link RrdGraphInfo} object which is retrieved - * from the {@link RrdGraph object} once the graph is created. - * - * @param srcName Virtual source name - * @param consolFun Consolidation function to be applied to the source - * @param format Format string (like "average = %10.3f %s") - */ - public void print(String srcName, String consolFun, String format) { - comments.add(new PrintText(srcName, consolFun, format, false)); - } - - /** - * This method does basically the same thing as {@link #print(String, String, String)}, - * but the result is printed on the graph itself, below the chart area. - * - * @param srcName Virtual source name - * @param consolFun Consolidation function to be applied to the source - * @param format Format string (like "average = %10.3f %s") - */ - public void gprint(String srcName, String consolFun, String format) { - comments.add(new PrintText(srcName, consolFun, format, true)); - } - - /** - * Comment to be printed on the graph. - * - * @param text Comment text - */ - public void comment(String text) { - comments.add(new CommentText(text)); - } - - /** - * Draws a horizontal rule into the graph and optionally adds a legend - * - * @param value Position of the rule - * @param color Rule color - * @param legend Legend text. If null, legend text will be omitted. - */ - public void hrule(double value, Paint color, String legend) { - hrule(value, color, legend, 1.0F); - } - - /** - * Draws a horizontal rule into the graph and optionally adds a legend - * - * @param value Position of the rule - * @param color Rule color - * @param legend Legend text. If null, legend text will be omitted. - * @param width Rule width - */ - public void hrule(double value, Paint color, String legend, float width) { - LegendText legendText = new LegendText(color, legend); - comments.add(legendText); - plotElements.add(new HRule(value, color, legendText, width)); - } - - /** - * Draws a vertical rule into the graph and optionally adds a legend - * - * @param timestamp Position of the rule (seconds since epoch) - * @param color Rule color - * @param legend Legend text. Use null to omit the text. - */ - public void vrule(long timestamp, Paint color, String legend) { - vrule(timestamp, color, legend, 1.0F); - } - - /** - * Draws a vertical rule into the graph and optionally adds a legend - * - * @param timestamp Position of the rule (seconds since epoch) - * @param color Rule color - * @param legend Legend text. Use null to omit the text. - * @param width Rule width - */ - public void vrule(long timestamp, Paint color, String legend, float width) { - LegendText legendText = new LegendText(color, legend); - comments.add(legendText); - plotElements.add(new VRule(timestamp, color, legendText, width)); - } - - /** - * Plots requested data as a line, using the color and the line width specified. - * - * @param srcName Virtual source name - * @param color Line color - * @param legend Legend text - * @param width Line width (default: 1.0F) - */ - public void line(String srcName, Paint color, String legend, float width) { - if (legend != null) { - comments.add(new LegendText(color, legend)); - } - plotElements.add(new Line(srcName, color, width)); - } - - /** - * Plots requested data as a line, using the color specified. Line width is assumed to be - * 1.0F. - * - * @param srcName Virtual source name - * @param color Line color - * @param legend Legend text - */ - public void line(String srcName, Paint color, String legend) { - line(srcName, color, legend, 1F); - } - - /** - * Plots requested data in the form of the filled area starting from zero, - * using the color specified. - * - * @param srcName Virtual source name. - * @param color Color of the filled area. - * @param legend Legend text. - */ - public void area(String srcName, Paint color, String legend) { - area(srcName, color); - if ((legend != null) && (legend.length() > 0)) { - LegendText legendText = new LegendText(color, legend); - comments.add(legendText); - } - } - - /** - * Plots requested data in the form of the filled area starting from zero, - * using the color specified. - * - * @param srcName Virtual source name. - * @param color Color of the filled area. - */ - public void area(String srcName, Paint color) { - plotElements.add(new Area(srcName, color)); - } - - /** - * Does the same as {@link #line(String, java.awt.Paint, String)}, - * but the graph gets stacked on top of the - * previous LINE, AREA or STACK graph. Depending on the type of the - * previous graph, the STACK will be either a LINE or an AREA. This - * obviously implies that the first STACK must be preceded by an AREA - * or LINE. - * <p> - * Note, that when you STACK onto *UNKNOWN* data, JRobin will not - * draw any graphics ... *UNKNOWN* is not zero. - * - * @param srcName Virtual source name - * @param color Stacked graph color - * @param legend Legend text - * @throws RrdException Thrown if this STACK has no previously defined AREA, STACK or LINE - * graph bellow it. - */ - public void stack(String srcName, Paint color, String legend) throws RrdException { - // find parent AREA or LINE - SourcedPlotElement parent = null; - for (int i = plotElements.size() - 1; i >= 0; i--) { - PlotElement plotElement = plotElements.get(i); - if (plotElement instanceof SourcedPlotElement) { - parent = (SourcedPlotElement) plotElement; - break; - } - } - if (parent == null) { - throw new RrdException("You have to stack graph onto something (line or area)"); - } - else { - LegendText legendText = new LegendText(color, legend); - comments.add(legendText); - plotElements.add(new Stack(parent, srcName, color)); - } - } - - /** - * Sets visibility of the X-axis grid. - * - * @param drawXGrid True if X-axis grid should be created (default), false otherwise. - */ - public void setDrawXGrid(boolean drawXGrid) { - this.drawXGrid = drawXGrid; - } - - /** - * Sets visibility of the Y-axis grid. - * - * @param drawYGrid True if Y-axis grid should be created (default), false otherwise. - */ - public void setDrawYGrid(boolean drawYGrid) { - this.drawYGrid = drawYGrid; - } - - /** - * Sets image quality. Relevant only for JPEG images. - * - * @param imageQuality (0F=worst, 1F=best). - */ - public void setImageQuality(float imageQuality) { - this.imageQuality = imageQuality; - } - - /** - * Controls if the chart area of the image should be antialiased or not. - * - * @param antiAliasing use true to turn antialiasing on, false to turn it off (default) - */ - public void setAntiAliasing(boolean antiAliasing) { - this.antiAliasing = antiAliasing; - } - - /** - * Shows or hides graph signature (gator) in the top right corner of the graph - * - * @param showSignature true, if signature should be seen (default), false otherwise - */ - public void setShowSignature(boolean showSignature) { - this.showSignature = showSignature; - } - - /** - * Sets first day of the week. - * - * @param firstDayOfWeek One of the following constants: - * {@link RrdGraphConstants#MONDAY MONDAY}, - * {@link RrdGraphConstants#TUESDAY TUESDAY}, - * {@link RrdGraphConstants#WEDNESDAY WEDNESDAY}, - * {@link RrdGraphConstants#THURSDAY THURSDAY}, - * {@link RrdGraphConstants#FRIDAY FRIDAY}, - * {@link RrdGraphConstants#SATURDAY SATURDAY}, - * {@link RrdGraphConstants#SUNDAY SUNDAY} - */ - public void setFirstDayOfWeek(int firstDayOfWeek) { - this.firstDayOfWeek = firstDayOfWeek; - } - - // helper methods - - int printStatementCount() { - int count = 0; - for (CommentText comment : comments) { - if (comment instanceof PrintText) { - if (comment.isPrint()) { - count++; - } - } - } - return count; - } - - boolean shouldPlot() { - if (plotElements.size() > 0) { - return true; - } - for (CommentText comment : comments) { - if (comment.isValidGraphElement()) { - return true; - } - } - return false; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/RrdGraphDefTemplate.java b/apps/jrobin/java/src/org/jrobin/graph/RrdGraphDefTemplate.java deleted file mode 100644 index 7b0c7f1c51f8574d9fb96379773f8e403bc5eb53..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/RrdGraphDefTemplate.java +++ /dev/null @@ -1,982 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; -import org.jrobin.core.XmlTemplate; -import org.w3c.dom.Node; -import org.xml.sax.InputSource; - -import java.awt.*; -import java.io.File; -import java.io.IOException; - -/** - * Class used to create an arbitrary number of RrdGraphDef (graph definition) objects - * from a single XML template. XML template can be supplied as an XML InputSource, - * XML file or XML formatted string. - * <p> - * Here is an example of a properly formatted XML template with all available options in it - * (unwanted options can be removed/ignored): - * <p> - * <pre> - * <rrd_graph_def> - * <!-- use '-' to represent in-memory graph --> - * <filename>test.png</filename> - * <!-- - * starting and ending timestamps can be specified by - * using at-style time specification, or by specifying - * exact timestamps since epoch (without milliseconds) - * --> - * <span> - * <start>now - 1d</start> - * <end>now</end> - * </span> - * <options> - * <!-- - * specify 'true' if you want to use RrdDbPool while - * creating graph - * --> - * <use_pool>false</use_pool> - * <anti_aliasing>true</anti_aliasing> - * <time_grid> - * <show_grid>true</show_grid> - * <!-- allowed units: second, minute, hour, day, week, month, year --> - * <minor_grid_unit>minute</minor_grid_unit> - * <minor_grid_unit_count>60</minor_grid_unit_count> - * <major_grid_unit>hour</major_grid_unit> - * <major_grid_unit_count>2</major_grid_unit_count> - * <label_unit>hour</label_unit> - * <label_unit_count>2</label_unit_count> - * <label_span>1200</label_span> - * <!-- use SimpleDateFormat or strftime-like format to format labels --> - * <label_format>dd-MMM-yy</label_format> - * </time_grid> - * <value_grid> - * <show_grid>true</show_grid> - * <grid_step>100.0</grid_step> - * <label_factor>5</label_factor> - * </value_grid> - * <no_minor_grid>true</no_minor_grid> - * <alt_y_grid>true</alt_y_grid> - * <alt_y_mrtg>true</alt_y_mrtg> - * <alt_autoscale>true</alt_autoscale> - * <alt_autoscale_max>true</alt_autoscale_max> - * <units_exponent>3</units_exponent> - * <units_length>13</units_length> - * <vertical_label>Speed (kbits/sec)</vertical_label> - * <width>444</width> - * <height>222</height> - * <interlaced>true</interlaced> - * <image_info>filename = %s, width=%d, height=%d</image_info> - * <image_format>png</image_format> - * <image_quality>0.8</image_quality> - * <background_image>luka.png</background_image> - * <overlay_image>luka.png</overlay_image> - * <unit>kilos</unit> - * <lazy>false</lazy> - * <min_value>0</min_value> - * <max_value>5000</max_value> - * <rigid>true</rigid> - * <base>1000</base> - * <logarithmic>false</logarithmic> - * <colors> - * <canvas>#FFFFFF</canvas> - * <back>#FFFFFF</back> - * <shadea>#AABBCC</shadea> - * <shadeb>#DDDDDD</shadeb> - * <grid>#FF0000</grid> - * <mgrid>#00FF00</mgrid> - * <font>#FFFFFF</font> - * <frame>#EE00FF</frame> - * <arrow>#FF0000</arrow> - * </colors> - * <no_legend>false</no_legend> - * <only_graph>false</only_graph> - * <force_rules_legend>false</force_rules_legend> - * <title>This is a title</title> - * <step>300</step> - * <fonts> - * <small_font> - * <name>Courier</name> - * <style>bold italic</style> - * <size>12</size> - * </small_font> - * <large_font> - * <name>Courier</name> - * <style>plain</style> - * <size>11</size> - * </large_font> - * </fonts> - * <first_day_of_week>SUNDAY</first_day_of_week> - * </options> - * <datasources> - * <def> - * <name>x</name> - * <rrd>test.rrd</rrd> - * <source>sun</source> - * <cf>AVERAGE</cf> - * <backend>FILE</backend> - * </def> - * <def> - * <name>y</name> - * <rrd>test.rrd</rrd> - * <source>shade</source> - * <cf>AVERAGE</cf> - * </def> - * <cdef> - * <name>x_plus_y</name> - * <rpn>x,y,+</rpn> - * </cdef> - * <cdef> - * <name>x_minus_y</name> - * <rpn>x,y,-</rpn> - * </cdef> - * <sdef> - * <name>x_avg</name> - * <source>x</source> - * <cf>AVERAGE</cf> - * </sdef> - * <sdef> - * <name>y_max</name> - * <source>y</source> - * <cf>MAX</cf> - * </sdef> - * </datasources> - * <graph> - * <area> - * <datasource>x</datasource> - * <color>#FF0000</color> - * <legend>X value\r</legend> - * </area> - * <stack> - * <datasource>y</datasource> - * <color>#00FF00</color> - * <legend>Y value\r</legend> - * </stack> - * <line> - * <datasource>x</datasource> - * <color>#FF0000</color> - * <legend>X value\r</legend> - * <width>2</width> - * </line> - * <print> - * <datasource>x</datasource> - * <cf>AVERAGE</cf> - * <format>Average is %7.3f\c</format> - * </print> - * <gprint> - * <datasource>y</datasource> - * <cf>MAX</cf> - * <format>Max is %7.3f\c</format> - * </gprint> - * <hrule> - * <value>1250</value> - * <color>#0000FF</color> - * <legend>This is a horizontal rule</legend> - * </hrule> - * <vrule> - * <time>now-6h</time> - * <color>#0000FF</color> - * <legend>This is a vertical rule</legend> - * </vrule> - * <comment>Simple comment</comment> - * <comment>One more comment\c</comment> - * </graph> - * </rrd_graph_def> - * </pre> - * Notes on the template syntax: - * <p> - * <ul> - * <li>There is a strong relation between the XML template syntax and the syntax of - * {@link RrdGraphDef} class methods. If you are not sure what some XML tag means, check javadoc - * for the corresponding class method. - * <li>hard-coded timestamps in templates should be long integeres - * (like: 1000243567) or at-style formatted strings - * <li>whitespaces are not harmful - * <li>use <code>true</code>, <code>on</code>, <code>yes</code>, <code>y</code>, - * or <code>1</code> to specify boolean <code>true</code> value (anything else will - * be treated as <code>false</code>). - * <li>floating point values: anything that cannot be parsed will be treated as Double.NaN - * (like: U, unknown, 12r.23) - * <li>use #RRGGBB or #RRGGBBAA format to specify colors. - * <li>valid font styles are: PLAIN, ITALIC, BOLD, BOLDITALIC - * <li>comments are allowed. - * </ul> - * Any template value (text between <code><some_tag></code> and - * <code></some_tag></code>) can be replaced with - * a variable of the following form: <code>${variable_name}</code>. Use - * {@link XmlTemplate#setVariable(String, String) setVariable()} - * methods from the base class to replace - * template variables with real values at runtime. - * <p> - * Typical usage scenario: - * <p> - * <ul> - * <li>Create your XML template and save it to a file (template.xml, for example) - * <li>Replace template values with variables if you want to change them during runtime. - * For example, time span should not be hard-coded in the template - you probably want to create - * many different graphs with different time spans from the same XML template. - * For example, your XML template could start with: - * <pre> - * <rrd_graph_def> - * ... - * <span> - * <start>${start}</start> - * <end>${end}</end> - * </span> - * ... - * </pre> - * <li>In your Java code, create RrdGraphDefTemplate object using your XML template file: - * <pre> - * RrdGraphDefTemplate t = new RrdGraphDefTemplate(new File(template.xml)); - * </pre> - * <li>Then, specify real values for template variables: - * <pre> - * t.setVariable("start", new GregorianCalendar(2004, 2, 25)); - * t.setVariable("end", new GregorianCalendar(2004, 2, 26)); - * </pre> - * <li>Once all template variables are set, just use the template object to create RrdGraphDef - * object. This object is actually used to create JRobin grahps: - * <pre> - * RrdGraphDef gdef = t.getRrdGraphDef(); - * RrdGraph g = new RrdGraph(gdef); - * </pre> - * </ul> - * You should create new RrdGraphDefTemplate object only once for each XML template. Single template - * object can be reused to create as many RrdGraphDef objects as needed, with different values - * specified for template variables. XML synatax check is performed only once - the first graph - * definition object gets created relatively slowly, but it will be created much faster next time. - */ -public class RrdGraphDefTemplate extends XmlTemplate implements RrdGraphConstants { - static final Color BLIND_COLOR = new Color(0, 0, 0, 0); - - private RrdGraphDef rrdGraphDef; - - /** - * Creates template object from any parsable XML source - * - * @param inputSource XML source - * @throws IOException thrown in case of I/O error - * @throws RrdException usually thrown in case of XML related error - */ - public RrdGraphDefTemplate(InputSource inputSource) throws IOException, RrdException { - super(inputSource); - } - - /** - * Creates template object from the file containing XML template code - * - * @param xmlFile file containing XML template - * @throws IOException thrown in case of I/O error - * @throws RrdException usually thrown in case of XML related error - */ - public RrdGraphDefTemplate(File xmlFile) throws IOException, RrdException { - super(xmlFile); - } - - /** - * Creates template object from the string containing XML template code - * - * @param xmlString string containing XML template - * @throws IOException thrown in case of I/O error - * @throws RrdException usually thrown in case of XML related error - */ - public RrdGraphDefTemplate(String xmlString) throws IOException, RrdException { - super(xmlString); - } - - /** - * Creates RrdGraphDef object which can be used to create RrdGraph - * object (actual JRobin graphs). Before this method is called, all template variables (if any) - * must be resolved (replaced with real values). - * See {@link XmlTemplate#setVariable(String, String) setVariable()} method information to - * understand how to supply values for template variables. - * - * @return Graph definition which can be used to create RrdGraph object (actual JRobin graphs) - * @throws RrdException Thrown if parsed XML template contains invalid (unrecognized) tags - */ - public RrdGraphDef getRrdGraphDef() throws RrdException { - // basic check - if (!root.getTagName().equals("rrd_graph_def")) { - throw new RrdException("XML definition must start with <rrd_graph_def>"); - } - validateTagsOnlyOnce(root, new String[] {"filename", "span", "options", "datasources", "graph"}); - rrdGraphDef = new RrdGraphDef(); - // traverse all nodes - Node[] childNodes = getChildNodes(root); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("filename")) { - resolveFilename(childNode); - } - // SPAN - else if (nodeName.equals("span")) { - resolveSpan(childNode); - } - // OPTIONS - else if (nodeName.equals("options")) { - resolveOptions(childNode); - } - // DATASOURCES - else if (nodeName.equals("datasources")) { - resolveDatasources(childNode); - } - // GRAPH ELEMENTS - else if (nodeName.equals("graph")) { - resolveGraphElements(childNode); - } - } - return rrdGraphDef; - } - - private void resolveGraphElements(Node graphNode) throws RrdException { - validateTagsOnlyOnce(graphNode, new String[] {"area*", "line*", "stack*", - "print*", "gprint*", "hrule*", "vrule*", "comment*"}); - Node[] childNodes = getChildNodes(graphNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("area")) { - resolveArea(childNode); - } - else if (nodeName.equals("line")) { - resolveLine(childNode); - } - else if (nodeName.equals("stack")) { - resolveStack(childNode); - } - else if (nodeName.equals("print")) { - resolvePrint(childNode, false); - } - else if (nodeName.equals("gprint")) { - resolvePrint(childNode, true); - } - else if (nodeName.equals("hrule")) { - resolveHRule(childNode); - } - else if (nodeName.equals("vrule")) { - resolveVRule(childNode); - } - else if (nodeName.equals("comment")) { - rrdGraphDef.comment(getValue(childNode)); - } - } - } - - private void resolveVRule(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"time", "color", "legend"}); - long timestamp = Long.MIN_VALUE; - Paint color = null; - String legend = null; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("time")) { - timestamp = Util.getTimestamp(getValue(childNode)); - } - else if (nodeName.equals("color")) { - color = getValueAsColor(childNode); - } - else if (nodeName.equals("legend")) { - legend = getValue(childNode); - } - } - if (timestamp != Long.MIN_VALUE && color != null) { - rrdGraphDef.vrule(timestamp, color, legend); - } - else { - throw new RrdException("Incomplete VRULE settings"); - } - } - - private void resolveHRule(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"value", "color", "legend"}); - double value = Double.NaN; - Paint color = null; - String legend = null; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("value")) { - value = getValueAsDouble(childNode); - } - else if (nodeName.equals("color")) { - color = getValueAsColor(childNode); - } - else if (nodeName.equals("legend")) { - legend = getValue(childNode); - } - } - if (!Double.isNaN(value) && color != null) { - rrdGraphDef.hrule(value, color, legend); - } - else { - throw new RrdException("Incomplete HRULE settings"); - } - } - - private void resolvePrint(Node parentNode, boolean isInGraph) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"datasource", "cf", "format"}); - String datasource = null, cf = null, format = null; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("datasource")) { - datasource = getValue(childNode); - } - else if (nodeName.equals("cf")) { - cf = getValue(childNode); - } - else if (nodeName.equals("format")) { - format = getValue(childNode); - } - } - if (datasource != null && cf != null && format != null) { - if (isInGraph) { - rrdGraphDef.gprint(datasource, cf, format); - } - else { - rrdGraphDef.print(datasource, cf, format); - } - } - else { - throw new RrdException("Incomplete " + (isInGraph ? "GRPINT" : "PRINT") + " settings"); - } - } - - private void resolveStack(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"datasource", "color", "legend"}); - String datasource = null, legend = null; - Paint color = null; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("datasource")) { - datasource = getValue(childNode); - } - else if (nodeName.equals("color")) { - color = getValueAsColor(childNode); - } - else if (nodeName.equals("legend")) { - legend = getValue(childNode); - } - } - if (datasource != null) { - if (color != null) { - rrdGraphDef.stack(datasource, color, legend); - } - else { - rrdGraphDef.stack(datasource, BLIND_COLOR, legend); - } - } - else { - throw new RrdException("Incomplete STACK settings"); - } - } - - private void resolveLine(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"datasource", "color", "legend", "width"}); - String datasource = null, legend = null; - Paint color = null; - float width = 1.0F; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("datasource")) { - datasource = getValue(childNode); - } - else if (nodeName.equals("color")) { - color = getValueAsColor(childNode); - } - else if (nodeName.equals("legend")) { - legend = getValue(childNode); - } - else if (nodeName.equals("width")) { - width = (float) getValueAsDouble(childNode); - } - } - if (datasource != null) { - if (color != null) { - rrdGraphDef.line(datasource, color, legend, width); - } - else { - rrdGraphDef.line(datasource, BLIND_COLOR, legend, width); - } - } - else { - throw new RrdException("Incomplete LINE settings"); - } - } - - private void resolveArea(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"datasource", "color", "legend"}); - String datasource = null, legend = null; - Paint color = null; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("datasource")) { - datasource = getValue(childNode); - } - else if (nodeName.equals("color")) { - color = getValueAsColor(childNode); - } - else if (nodeName.equals("legend")) { - legend = getValue(childNode); - } - } - if (datasource != null) { - if (color != null) { - rrdGraphDef.area(datasource, color, legend); - } - else { - rrdGraphDef.area(datasource, BLIND_COLOR, legend); - } - } - else { - throw new RrdException("Incomplete AREA settings"); - } - } - - private void resolveDatasources(Node datasourcesNode) throws RrdException { - validateTagsOnlyOnce(datasourcesNode, new String[] {"def*", "cdef*", "sdef*"}); - Node[] childNodes = getChildNodes(datasourcesNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("def")) { - resolveDef(childNode); - } - else if (nodeName.equals("cdef")) { - resolveCDef(childNode); - } - else if (nodeName.equals("sdef")) { - resolveSDef(childNode); - } - } - } - - private void resolveSDef(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"name", "source", "cf"}); - String name = null, source = null, cf = null; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("name")) { - name = getValue(childNode); - } - else if (nodeName.equals("source")) { - source = getValue(childNode); - } - else if (nodeName.equals("cf")) { - cf = getValue(childNode); - } - } - if (name != null && source != null && cf != null) { - rrdGraphDef.datasource(name, source, cf); - } - else { - throw new RrdException("Incomplete SDEF settings"); - } - } - - private void resolveCDef(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"name", "rpn"}); - String name = null, rpn = null; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("name")) { - name = getValue(childNode); - } - else if (nodeName.equals("rpn")) { - rpn = getValue(childNode); - } - } - if (name != null && rpn != null) { - rrdGraphDef.datasource(name, rpn); - } - else { - throw new RrdException("Incomplete CDEF settings"); - } - } - - private void resolveDef(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"name", "rrd", "source", "cf", "backend"}); - String name = null, rrd = null, source = null, cf = null, backend = null; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("name")) { - name = getValue(childNode); - } - else if (nodeName.equals("rrd")) { - rrd = getValue(childNode); - } - else if (nodeName.equals("source")) { - source = getValue(childNode); - } - else if (nodeName.equals("cf")) { - cf = getValue(childNode); - } - else if (nodeName.equals("backend")) { - backend = getValue(childNode); - } - } - if (name != null && rrd != null && source != null && cf != null) { - rrdGraphDef.datasource(name, rrd, source, cf, backend); - } - else { - throw new RrdException("Incomplete DEF settings"); - } - } - - private void resolveFilename(Node filenameNode) { - String filename = getValue(filenameNode); - rrdGraphDef.setFilename(filename); - } - - private void resolveSpan(Node spanNode) throws RrdException { - validateTagsOnlyOnce(spanNode, new String[] {"start", "end"}); - String startStr = getChildValue(spanNode, "start"); - String endStr = getChildValue(spanNode, "end"); - long[] span = Util.getTimestamps(startStr, endStr); - rrdGraphDef.setStartTime(span[0]); - rrdGraphDef.setEndTime(span[1]); - } - - private void resolveOptions(Node rootOptionNode) throws RrdException { - validateTagsOnlyOnce(rootOptionNode, new String[] { - "anti_aliasing", "use_pool", "time_grid", "value_grid", "alt_y_grid", "alt_y_mrtg", - "no_minor_grid", "alt_autoscale", "alt_autoscale_max", "units_exponent", "units_length", - "vertical_label", "width", "height", "interlaced", "image_info", "image_format", - "image_quality", "background_image", "overlay_image", "unit", "lazy", - "min_value", "max_value", "rigid", "base", "logarithmic", "colors", - "no_legend", "only_graph", "force_rules_legend", "title", "step", "fonts", - "first_day_of_week", "signature" - }); - Node[] optionNodes = getChildNodes(rootOptionNode); - for (Node optionNode : optionNodes) { - String option = optionNode.getNodeName(); - if (option.equals("use_pool")) { - rrdGraphDef.setPoolUsed(getValueAsBoolean(optionNode)); - } - else if (option.equals("anti_aliasing")) { - rrdGraphDef.setAntiAliasing(getValueAsBoolean(optionNode)); - } - else if (option.equals("time_grid")) { - resolveTimeGrid(optionNode); - } - else if (option.equals("value_grid")) { - resolveValueGrid(optionNode); - } - else if (option.equals("no_minor_grid")) { - rrdGraphDef.setNoMinorGrid(getValueAsBoolean(optionNode)); - } - else if (option.equals("alt_y_grid")) { - rrdGraphDef.setAltYGrid(getValueAsBoolean(optionNode)); - } - else if (option.equals("alt_y_mrtg")) { - rrdGraphDef.setAltYMrtg(getValueAsBoolean(optionNode)); - } - else if (option.equals("alt_autoscale")) { - rrdGraphDef.setAltAutoscale(getValueAsBoolean(optionNode)); - } - else if (option.equals("alt_autoscale_max")) { - rrdGraphDef.setAltAutoscaleMax(getValueAsBoolean(optionNode)); - } - else if (option.equals("units_exponent")) { - rrdGraphDef.setUnitsExponent(getValueAsInt(optionNode)); - } - else if (option.equals("units_length")) { - rrdGraphDef.setUnitsLength(getValueAsInt(optionNode)); - } - else if (option.equals("vertical_label")) { - rrdGraphDef.setVerticalLabel(getValue(optionNode)); - } - else if (option.equals("width")) { - rrdGraphDef.setWidth(getValueAsInt(optionNode)); - } - else if (option.equals("height")) { - rrdGraphDef.setHeight(getValueAsInt(optionNode)); - } - else if (option.equals("interlaced")) { - rrdGraphDef.setInterlaced(getValueAsBoolean(optionNode)); - } - else if (option.equals("image_info")) { - rrdGraphDef.setImageInfo(getValue(optionNode)); - } - else if (option.equals("image_format")) { - rrdGraphDef.setImageFormat(getValue(optionNode)); - } - else if (option.equals("image_quality")) { - rrdGraphDef.setImageQuality((float) getValueAsDouble(optionNode)); - } - else if (option.equals("background_image")) { - rrdGraphDef.setBackgroundImage(getValue(optionNode)); - } - else if (option.equals("overlay_image")) { - rrdGraphDef.setOverlayImage(getValue(optionNode)); - } - else if (option.equals("unit")) { - rrdGraphDef.setUnit(getValue(optionNode)); - } - else if (option.equals("lazy")) { - rrdGraphDef.setLazy(getValueAsBoolean(optionNode)); - } - else if (option.equals("min_value")) { - rrdGraphDef.setMinValue(getValueAsDouble(optionNode)); - } - else if (option.equals("max_value")) { - rrdGraphDef.setMaxValue(getValueAsDouble(optionNode)); - } - else if (option.equals("rigid")) { - rrdGraphDef.setRigid(getValueAsBoolean(optionNode)); - } - else if (option.equals("base")) { - rrdGraphDef.setBase(getValueAsDouble(optionNode)); - } - else if (option.equals("logarithmic")) { - rrdGraphDef.setLogarithmic(getValueAsBoolean(optionNode)); - } - else if (option.equals("colors")) { - resolveColors(optionNode); - } - else if (option.equals("no_legend")) { - rrdGraphDef.setNoLegend(getValueAsBoolean(optionNode)); - } - else if (option.equals("only_graph")) { - rrdGraphDef.setOnlyGraph(getValueAsBoolean(optionNode)); - } - else if (option.equals("force_rules_legend")) { - rrdGraphDef.setForceRulesLegend(getValueAsBoolean(optionNode)); - } - else if (option.equals("title")) { - rrdGraphDef.setTitle(getValue(optionNode)); - } - else if (option.equals("step")) { - rrdGraphDef.setStep(getValueAsLong(optionNode)); - } - else if (option.equals("fonts")) { - resolveFonts(optionNode); - } - else if (option.equals("first_day_of_week")) { - int dayIndex = resolveFirstDayOfWeek(getValue(optionNode)); - rrdGraphDef.setFirstDayOfWeek(dayIndex); - } - else if (option.equals("signature")) { - rrdGraphDef.setShowSignature(getValueAsBoolean(optionNode)); - } - } - } - - private int resolveFirstDayOfWeek(String firstDayOfWeek) throws RrdException { - if (firstDayOfWeek.equalsIgnoreCase("sunday")) { - return SUNDAY; - } - else if (firstDayOfWeek.equalsIgnoreCase("monday")) { - return MONDAY; - } - else if (firstDayOfWeek.equalsIgnoreCase("tuesday")) { - return TUESDAY; - } - else if (firstDayOfWeek.equalsIgnoreCase("wednesday")) { - return WEDNESDAY; - } - else if (firstDayOfWeek.equalsIgnoreCase("thursday")) { - return THURSDAY; - } - else if (firstDayOfWeek.equalsIgnoreCase("friday")) { - return FRIDAY; - } - else if (firstDayOfWeek.equalsIgnoreCase("saturday")) { - return SATURDAY; - } - throw new RrdException("Never heard for this day of week: " + firstDayOfWeek); - } - - private void resolveFonts(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"small_font", "large_font"}); - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("small_font")) { - rrdGraphDef.setSmallFont(resolveFont(childNode)); - } - else if (nodeName.equals("large_font")) { - rrdGraphDef.setLargeFont(resolveFont(childNode)); - } - } - } - - private Font resolveFont(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"name", "style", "size"}); - String name = null, style = null; - int size = 0; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("name")) { - name = getValue(childNode); - } - else if (nodeName.equals("style")) { - style = getValue(childNode).toLowerCase(); - } - else if (nodeName.equals("size")) { - size = getValueAsInt(childNode); - } - } - if (name != null && style != null && size > 0) { - boolean isItalic = style.contains("italic"), isBold = style.contains("bold"); - int fstyle = Font.PLAIN; - if (isItalic && isBold) { - fstyle = Font.BOLD + Font.ITALIC; - } - else if (isItalic) { - fstyle = Font.ITALIC; - } - else if (isBold) { - fstyle = Font.BOLD; - } - return new Font(name, fstyle, size); - } - else { - throw new RrdException("Incomplete font specification"); - } - } - - private void resolveColors(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, COLOR_NAMES); - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String colorName = childNode.getNodeName(); - rrdGraphDef.setColor(colorName, getValueAsColor(childNode)); - } - } - - private void resolveValueGrid(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] {"show_grid", "grid_step", "label_factor"}); - boolean showGrid = true; - double gridStep = Double.NaN; - int NOT_SET = Integer.MIN_VALUE, labelFactor = NOT_SET; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("show_grid")) { - showGrid = getValueAsBoolean(childNode); - } - else if (nodeName.equals("grid_step")) { - gridStep = getValueAsDouble(childNode); - } - else if (nodeName.equals("label_factor")) { - labelFactor = getValueAsInt(childNode); - } - } - rrdGraphDef.setDrawYGrid(showGrid); - if (!Double.isNaN(gridStep) && labelFactor != NOT_SET) { - rrdGraphDef.setValueAxis(gridStep, labelFactor); - } - else if (!Double.isNaN(gridStep) || labelFactor != NOT_SET) { - throw new RrdException("Incomplete value axis settings"); - } - } - - private void resolveTimeGrid(Node parentNode) throws RrdException { - validateTagsOnlyOnce(parentNode, new String[] { - "show_grid", "minor_grid_unit", - "minor_grid_unit_count", "major_grid_unit", - "major_grid_unit_count", "label_unit", "label_unit_count", - "label_span", "label_format" - }); - boolean showGrid = true; - final int NOT_SET = Integer.MIN_VALUE; - int minorGridUnit = NOT_SET, minorGridUnitCount = NOT_SET, - majorGridUnit = NOT_SET, majorGridUnitCount = NOT_SET, - labelUnit = NOT_SET, labelUnitCount = NOT_SET, labelSpan = NOT_SET; - String labelFormat = null; - Node[] childNodes = getChildNodes(parentNode); - for (Node childNode : childNodes) { - String nodeName = childNode.getNodeName(); - if (nodeName.equals("show_grid")) { - showGrid = getValueAsBoolean(childNode); - } - else if (nodeName.equals("minor_grid_unit")) { - minorGridUnit = resolveTimeUnit(getValue(childNode)); - } - else if (nodeName.equals("minor_grid_unit_count")) { - minorGridUnitCount = getValueAsInt(childNode); - } - else if (nodeName.equals("major_grid_unit")) { - majorGridUnit = resolveTimeUnit(getValue(childNode)); - } - else if (nodeName.equals("major_grid_unit_count")) { - majorGridUnitCount = getValueAsInt(childNode); - } - else if (nodeName.equals("label_unit")) { - labelUnit = resolveTimeUnit(getValue(childNode)); - } - else if (nodeName.equals("label_unit_count")) { - labelUnitCount = getValueAsInt(childNode); - } - else if (nodeName.equals("label_span")) { - labelSpan = getValueAsInt(childNode); - } - else if (nodeName.equals("label_format")) { - labelFormat = getValue(childNode); - } - } - rrdGraphDef.setDrawXGrid(showGrid); - if (minorGridUnit != NOT_SET && minorGridUnitCount != NOT_SET && - majorGridUnit != NOT_SET && majorGridUnitCount != NOT_SET && - labelUnit != NOT_SET && labelUnitCount != NOT_SET && labelSpan != NOT_SET && labelFormat != null) { - rrdGraphDef.setTimeAxis(minorGridUnit, minorGridUnitCount, majorGridUnit, majorGridUnitCount, - labelUnit, labelUnitCount, labelSpan, labelFormat); - } - else if (minorGridUnit != NOT_SET || minorGridUnitCount != NOT_SET || - majorGridUnit != NOT_SET || majorGridUnitCount != NOT_SET || - labelUnit != NOT_SET || labelUnitCount != NOT_SET || labelSpan != NOT_SET || labelFormat != null) { - throw new RrdException("Incomplete time axis settings"); - } - } - - private int resolveTimeUnit(String unit) throws RrdException { - if (unit.equalsIgnoreCase("second")) { - return RrdGraphConstants.SECOND; - } - else if (unit.equalsIgnoreCase("minute")) { - return RrdGraphConstants.MINUTE; - } - else if (unit.equalsIgnoreCase("hour")) { - return RrdGraphConstants.HOUR; - } - else if (unit.equalsIgnoreCase("day")) { - return RrdGraphConstants.DAY; - } - else if (unit.equalsIgnoreCase("week")) { - return RrdGraphConstants.WEEK; - } - else if (unit.equalsIgnoreCase("month")) { - return RrdGraphConstants.MONTH; - } - else if (unit.equalsIgnoreCase("year")) { - return RrdGraphConstants.YEAR; - } - throw new RrdException("Unknown time unit specified: " + unit); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/RrdGraphInfo.java b/apps/jrobin/java/src/org/jrobin/graph/RrdGraphInfo.java deleted file mode 100644 index 469eb2efededf4128bee1229c2e3456129b13434..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/RrdGraphInfo.java +++ /dev/null @@ -1,128 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.util.ArrayList; -import java.util.List; - -/** - * Class to represent successfully created JRobin graph. Objects of this class are created by method - * {@link RrdGraph#getRrdGraphInfo()}. - */ -public class RrdGraphInfo { - String filename; - int width, height; - byte[] bytes; - String imgInfo; - private List<String> printLines = new ArrayList<String>(); - - RrdGraphInfo() { - // cannot instantiate this class - } - - void addPrintLine(String printLine) { - printLines.add(printLine); - } - - /** - * Returns filename of the graph - * - * @return filename of the graph. '-' denotes in-memory graph (no file created) - */ - public String getFilename() { - return filename; - } - - /** - * Returns total graph width - * - * @return total graph width - */ - public int getWidth() { - return width; - } - - /** - * Returns total graph height - * - * @return total graph height - */ - public int getHeight() { - return height; - } - - /** - * Returns graph bytes - * - * @return Graph bytes - */ - public byte[] getBytes() { - return bytes; - } - - /** - * Returns PRINT lines requested by {@link RrdGraphDef#print(String, String, String)} method. - * - * @return An array of formatted PRINT lines - */ - public String[] getPrintLines() { - return printLines.toArray(new String[printLines.size()]); - } - - /** - * Returns image information requested by {@link RrdGraphDef#setImageInfo(String)} method - * - * @return Image information - */ - public String getImgInfo() { - return imgInfo; - } - - /** - * Returns the number of bytes in the graph file - * - * @return Length of the graph file - */ - public int getByteCount() { - return bytes != null ? bytes.length : 0; - } - - /** - * Dumps complete graph information. Useful for debugging purposes. - * - * @return String containing complete graph information - */ - public String dump() { - StringBuffer b = new StringBuffer(); - b.append("filename = \"").append(getFilename()).append("\"\n"); - b.append("width = ").append(getWidth()).append(", height = ").append(getHeight()).append("\n"); - b.append("byteCount = ").append(getByteCount()).append("\n"); - b.append("imginfo = \"").append(getImgInfo()).append("\"\n"); - String[] plines = getPrintLines(); - if (plines.length == 0) { - b.append("No print lines found\n"); - } - else { - for (int i = 0; i < plines.length; i++) { - b.append("print[").append(i).append("] = \"").append(plines[i]).append("\"\n"); - } - } - return b.toString(); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/Rule.java b/apps/jrobin/java/src/org/jrobin/graph/Rule.java deleted file mode 100644 index 3dccdad8ca22d1301e6eafc7b148b10a500f3043..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/Rule.java +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.*; - -class Rule extends PlotElement { - final LegendText legend; - final float width; - - Rule(Paint color, LegendText legend, float width) { - super(color); - this.legend = legend; - this.width = width; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/SDef.java b/apps/jrobin/java/src/org/jrobin/graph/SDef.java deleted file mode 100644 index 09f857b76d5270a2c377f79112f82b1e9ed9d72a..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/SDef.java +++ /dev/null @@ -1,35 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.data.DataProcessor; - -class SDef extends Source { - private String defName, consolFun; - - SDef(String name, String defName, String consolFun) { - super(name); - this.defName = defName; - this.consolFun = consolFun; - } - - void requestData(DataProcessor dproc) { - dproc.addDatasource(name, defName, consolFun); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/Source.java b/apps/jrobin/java/src/org/jrobin/graph/Source.java deleted file mode 100644 index 733c9c464d0aab680f9056bf22065bf7c5b999dd..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/Source.java +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.data.DataProcessor; - -abstract class Source { - final String name; - - Source(String name) { - this.name = name; - } - - abstract void requestData(DataProcessor dproc); -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/SourcedPlotElement.java b/apps/jrobin/java/src/org/jrobin/graph/SourcedPlotElement.java deleted file mode 100644 index fdcd81e24b1a7b211c9ed61441a685e7b2e4ffe4..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/SourcedPlotElement.java +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.core.RrdException; -import org.jrobin.core.Util; -import org.jrobin.data.DataProcessor; - -import java.awt.*; - -class SourcedPlotElement extends PlotElement { - final String srcName; - double[] values; - - SourcedPlotElement(String srcName, Paint color) { - super(color); - this.srcName = srcName; - } - - void assignValues(DataProcessor dproc) throws RrdException { - values = dproc.getValues(srcName); - } - - double[] getValues() { - return values; - } - - double getMinValue() { - return Util.min(values); - } - - double getMaxValue() { - return Util.max(values); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/Stack.java b/apps/jrobin/java/src/org/jrobin/graph/Stack.java deleted file mode 100644 index a4eaff55bc5d21f7d9d6aa92caf84bdba02331e3..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/Stack.java +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.core.RrdException; -import org.jrobin.data.DataProcessor; - -import java.awt.*; - -class Stack extends SourcedPlotElement { - private final SourcedPlotElement parent; - - Stack(SourcedPlotElement parent, String srcName, Paint color) { - super(srcName, color); - this.parent = parent; - } - - void assignValues(DataProcessor dproc) throws RrdException { - double[] parentValues = parent.getValues(); - double[] procValues = dproc.getValues(srcName); - values = new double[procValues.length]; - for (int i = 0; i < values.length; i++) { - values[i] = parentValues[i] + procValues[i]; - } - } - - float getParentLineWidth() { - if (parent instanceof Line) { - return ((Line) parent).width; - } - else if (parent instanceof Area) { - return -1F; - } - else /* if(parent instanceof Stack) */ { - return ((Stack) parent).getParentLineWidth(); - } - } - - Paint getParentColor() { - return parent.color; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/TimeAxis.java b/apps/jrobin/java/src/org/jrobin/graph/TimeAxis.java deleted file mode 100644 index 5a19f851dd7c543ce3ffebd0be394200ab93a743..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/TimeAxis.java +++ /dev/null @@ -1,225 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.*; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.Locale; - -class TimeAxis implements RrdGraphConstants { - private static final TimeAxisSetting[] tickSettings = { - new TimeAxisSetting(0, SECOND, 30, MINUTE, 5, MINUTE, 5, 0, "HH:mm"), - new TimeAxisSetting(2, MINUTE, 1, MINUTE, 5, MINUTE, 5, 0, "HH:mm"), - new TimeAxisSetting(5, MINUTE, 2, MINUTE, 10, MINUTE, 10, 0, "HH:mm"), - new TimeAxisSetting(10, MINUTE, 5, MINUTE, 20, MINUTE, 20, 0, "HH:mm"), - new TimeAxisSetting(30, MINUTE, 10, HOUR, 1, HOUR, 1, 0, "HH:mm"), - new TimeAxisSetting(60, MINUTE, 30, HOUR, 2, HOUR, 2, 0, "HH:mm"), - new TimeAxisSetting(180, HOUR, 1, HOUR, 6, HOUR, 6, 0, "HH:mm"), - new TimeAxisSetting(600, HOUR, 6, DAY, 1, DAY, 1, 24 * 3600, "EEE"), - new TimeAxisSetting(1800, HOUR, 12, DAY, 1, DAY, 2, 24 * 3600, "EEE"), - new TimeAxisSetting(3600, DAY, 1, WEEK, 1, WEEK, 1, 7 * 24 * 3600, "'Week 'w"), - new TimeAxisSetting(3 * 3600, WEEK, 1, MONTH, 1, WEEK, 2, 7 * 24 * 3600, "'Week 'w"), - new TimeAxisSetting(6 * 3600, MONTH, 1, MONTH, 1, MONTH, 1, 30 * 24 * 3600, "MMM"), - new TimeAxisSetting(48 * 3600, MONTH, 1, MONTH, 3, MONTH, 3, 30 * 24 * 3600, "MMM"), - new TimeAxisSetting(10 * 24 * 3600, YEAR, 1, YEAR, 1, YEAR, 1, 365 * 24 * 3600, "yy"), - new TimeAxisSetting(-1, MONTH, 0, MONTH, 0, MONTH, 0, 0, "") - }; - - private TimeAxisSetting tickSetting; - private RrdGraph rrdGraph; - private double secPerPix; - private Calendar calendar; - - TimeAxis(RrdGraph rrdGraph) { - this.rrdGraph = rrdGraph; - if (rrdGraph.im.xsize > 0) { - this.secPerPix = (rrdGraph.im.end - rrdGraph.im.start) / Double.valueOf(rrdGraph.im.xsize); - } - this.calendar = Calendar.getInstance(Locale.getDefault()); - this.calendar.setFirstDayOfWeek(rrdGraph.gdef.firstDayOfWeek); - } - - void draw() { - chooseTickSettings(); - if (tickSetting == null) { - return; - } - drawMinor(); - drawMajor(); - drawLabels(); - } - - private void drawMinor() { - if (!rrdGraph.gdef.noMinorGrid) { - adjustStartingTime(tickSetting.minorUnit, tickSetting.minorUnitCount); - Paint color = rrdGraph.gdef.colors[COLOR_GRID]; - int y0 = rrdGraph.im.yorigin, y1 = y0 - rrdGraph.im.ysize; - for (int status = getTimeShift(); status <= 0; status = getTimeShift()) { - if (status == 0) { - long time = calendar.getTime().getTime() / 1000L; - int x = rrdGraph.mapper.xtr(time); - rrdGraph.worker.drawLine(x, y0 - 1, x, y0 + 1, color, TICK_STROKE); - rrdGraph.worker.drawLine(x, y0, x, y1, color, GRID_STROKE); - } - findNextTime(tickSetting.minorUnit, tickSetting.minorUnitCount); - } - } - } - - private void drawMajor() { - adjustStartingTime(tickSetting.majorUnit, tickSetting.majorUnitCount); - Paint color = rrdGraph.gdef.colors[COLOR_MGRID]; - int y0 = rrdGraph.im.yorigin, y1 = y0 - rrdGraph.im.ysize; - for (int status = getTimeShift(); status <= 0; status = getTimeShift()) { - if (status == 0) { - long time = calendar.getTime().getTime() / 1000L; - int x = rrdGraph.mapper.xtr(time); - rrdGraph.worker.drawLine(x, y0 - 2, x, y0 + 2, color, TICK_STROKE); - rrdGraph.worker.drawLine(x, y0, x, y1, color, GRID_STROKE); - } - findNextTime(tickSetting.majorUnit, tickSetting.majorUnitCount); - } - } - - private void drawLabels() { - // escape strftime like format string - String labelFormat = tickSetting.format.replaceAll("([^%]|^)%([^%t])", "$1%t$2"); - Font font = rrdGraph.gdef.getFont(FONTTAG_AXIS); - Paint color = rrdGraph.gdef.colors[COLOR_FONT]; - adjustStartingTime(tickSetting.labelUnit, tickSetting.labelUnitCount); - int y = rrdGraph.im.yorigin + (int) rrdGraph.worker.getFontHeight(font) + 2; - for (int status = getTimeShift(); status <= 0; status = getTimeShift()) { - String label = formatLabel(labelFormat, calendar.getTime()); - long time = calendar.getTime().getTime() / 1000L; - int x1 = rrdGraph.mapper.xtr(time); - int x2 = rrdGraph.mapper.xtr(time + tickSetting.labelSpan); - int labelWidth = (int) rrdGraph.worker.getStringWidth(label, font); - int x = x1 + (x2 - x1 - labelWidth) / 2; - if (x >= rrdGraph.im.xorigin && x + labelWidth <= rrdGraph.im.xorigin + rrdGraph.im.xsize) { - rrdGraph.worker.drawString(label, x, y, font, color); - } - findNextTime(tickSetting.labelUnit, tickSetting.labelUnitCount); - } - } - - private static String formatLabel(String format, Date date) { - if (format.contains("%")) { - // strftime like format string - return String.format(format, date); - } - else { - // simple date format - return new SimpleDateFormat(format).format(date); - } - } - - private void findNextTime(int timeUnit, int timeUnitCount) { - switch (timeUnit) { - case SECOND: - calendar.add(Calendar.SECOND, timeUnitCount); - break; - case MINUTE: - calendar.add(Calendar.MINUTE, timeUnitCount); - break; - case HOUR: - calendar.add(Calendar.HOUR_OF_DAY, timeUnitCount); - break; - case DAY: - calendar.add(Calendar.DAY_OF_MONTH, timeUnitCount); - break; - case WEEK: - calendar.add(Calendar.DAY_OF_MONTH, 7 * timeUnitCount); - break; - case MONTH: - calendar.add(Calendar.MONTH, timeUnitCount); - break; - case YEAR: - calendar.add(Calendar.YEAR, timeUnitCount); - break; - } - } - - private int getTimeShift() { - long time = calendar.getTime().getTime() / 1000L; - return (time < rrdGraph.im.start) ? -1 : (time > rrdGraph.im.end) ? +1 : 0; - } - - private void adjustStartingTime(int timeUnit, int timeUnitCount) { - calendar.setTime(new Date(rrdGraph.im.start * 1000L)); - switch (timeUnit) { - case SECOND: - calendar.add(Calendar.SECOND, -(calendar.get(Calendar.SECOND) % timeUnitCount)); - break; - case MINUTE: - calendar.set(Calendar.SECOND, 0); - calendar.add(Calendar.MINUTE, -(calendar.get(Calendar.MINUTE) % timeUnitCount)); - break; - case HOUR: - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.add(Calendar.HOUR_OF_DAY, -(calendar.get(Calendar.HOUR_OF_DAY) % timeUnitCount)); - break; - case DAY: - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.HOUR_OF_DAY, 0); - break; - case WEEK: - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.HOUR_OF_DAY, 0); - int diffDays = calendar.get(Calendar.DAY_OF_WEEK) - calendar.getFirstDayOfWeek(); - if (diffDays < 0) { - diffDays += 7; - } - calendar.add(Calendar.DAY_OF_MONTH, -diffDays); - break; - case MONTH: - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.HOUR_OF_DAY, 0); - calendar.set(Calendar.DAY_OF_MONTH, 1); - calendar.add(Calendar.MONTH, -(calendar.get(Calendar.MONTH) % timeUnitCount)); - break; - case YEAR: - calendar.set(Calendar.SECOND, 0); - calendar.set(Calendar.MINUTE, 0); - calendar.set(Calendar.HOUR_OF_DAY, 0); - calendar.set(Calendar.DAY_OF_MONTH, 1); - calendar.set(Calendar.MONTH, 0); - calendar.add(Calendar.YEAR, -(calendar.get(Calendar.YEAR) % timeUnitCount)); - break; - } - } - - - private void chooseTickSettings() { - if (rrdGraph.gdef.timeAxisSetting != null) { - tickSetting = new TimeAxisSetting(rrdGraph.gdef.timeAxisSetting); - } - else { - for (int i = 0; tickSettings[i].secPerPix >= 0 && secPerPix > tickSettings[i].secPerPix; i++) { - tickSetting = tickSettings[i]; - } - } - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/TimeAxisSetting.java b/apps/jrobin/java/src/org/jrobin/graph/TimeAxisSetting.java deleted file mode 100644 index ab955e77378cff999c8a333d987571f2c6d7384f..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/TimeAxisSetting.java +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -class TimeAxisSetting { - final long secPerPix; - final int minorUnit, minorUnitCount, majorUnit, majorUnitCount; - final int labelUnit, labelUnitCount, labelSpan; - final String format; - - TimeAxisSetting(long secPerPix, int minorUnit, int minorUnitCount, int majorUnit, int majorUnitCount, - int labelUnit, int labelUnitCount, int labelSpan, String format) { - this.secPerPix = secPerPix; - this.minorUnit = minorUnit; - this.minorUnitCount = minorUnitCount; - this.majorUnit = majorUnit; - this.majorUnitCount = majorUnitCount; - this.labelUnit = labelUnit; - this.labelUnitCount = labelUnitCount; - this.labelSpan = labelSpan; - this.format = format; - } - - TimeAxisSetting(TimeAxisSetting s) { - this.secPerPix = s.secPerPix; - this.minorUnit = s.minorUnit; - this.minorUnitCount = s.minorUnitCount; - this.majorUnit = s.majorUnit; - this.majorUnitCount = s.majorUnitCount; - this.labelUnit = s.labelUnit; - this.labelUnitCount = s.labelUnitCount; - this.labelSpan = s.labelSpan; - this.format = s.format; - } - - TimeAxisSetting(int minorUnit, int minorUnitCount, int majorUnit, int majorUnitCount, - int labelUnit, int labelUnitCount, int labelSpan, String format) { - this(0, minorUnit, minorUnitCount, majorUnit, majorUnitCount, - labelUnit, labelUnitCount, labelSpan, format); - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/VRule.java b/apps/jrobin/java/src/org/jrobin/graph/VRule.java deleted file mode 100644 index a3178b18044ff6a083fd725cb8cfe1454237dd5c..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/VRule.java +++ /dev/null @@ -1,34 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.*; - -class VRule extends Rule { - final long timestamp; - - VRule(long timestamp, Paint color, LegendText legend, float width) { - super(color, legend, width); - this.timestamp = timestamp; - } - - void setLegendVisibility(long minval, long maxval, boolean forceLegend) { - legend.enabled &= (forceLegend || (timestamp >= minval && timestamp <= maxval)); - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/ValueAxis.java b/apps/jrobin/java/src/org/jrobin/graph/ValueAxis.java deleted file mode 100644 index 29e4e0dedffb3133e16dbdfec81b64d043f36115..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/ValueAxis.java +++ /dev/null @@ -1,269 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import java.awt.Font; -import java.awt.Paint; - -import org.jrobin.core.Util; - -class ValueAxis implements RrdGraphConstants { - private static final YLab[] ylab = { - new YLab(0.1, 1, 2, 5, 10), - new YLab(0.2, 1, 5, 10, 20), - new YLab(0.5, 1, 2, 4, 10), - new YLab(1.0, 1, 2, 5, 10), - new YLab(2.0, 1, 5, 10, 20), - new YLab(5.0, 1, 2, 4, 10), - new YLab(10.0, 1, 2, 5, 10), - new YLab(20.0, 1, 5, 10, 20), - new YLab(50.0, 1, 2, 4, 10), - new YLab(100.0, 1, 2, 5, 10), - new YLab(200.0, 1, 5, 10, 20), - new YLab(500.0, 1, 2, 4, 10), - new YLab(1000.0, 1, 2, 5, 10), - new YLab(2000.0, 1, 5, 10, 20), - new YLab(5000.0, 1, 2, 4, 10), - new YLab(10000.0, 1, 2, 5, 10), - new YLab(20000.0, 1, 5, 10, 20), - new YLab(50000.0, 1, 2, 4, 10), - new YLab(100000.0, 1, 2, 5, 10), - new YLab(0.0, 0, 0, 0, 0) - }; - - //private RrdGraph rrdGraph; - private ImageParameters im; - private ImageWorker worker; - private RrdGraphDef gdef; - private Mapper mapper; - - ValueAxis(RrdGraph rrdGraph) { - this(rrdGraph.im, rrdGraph.worker, rrdGraph.gdef, rrdGraph.mapper); - } - - ValueAxis(ImageParameters im, ImageWorker worker, RrdGraphDef gdef, Mapper mapper) { - this.im = im; - this.gdef = gdef; - this.worker = worker; - this.mapper = mapper; - } - - boolean draw() { - Font font = gdef.getFont(FONTTAG_AXIS); - Paint gridColor = gdef.colors[COLOR_GRID]; - Paint mGridColor = gdef.colors[COLOR_MGRID]; - Paint fontColor = gdef.colors[COLOR_FONT]; - int labelOffset = (int) (worker.getFontAscent(font) / 2); - int labfact = 2; - double range = im.maxval - im.minval; - double scaledrange = range / im.magfact; - double gridstep; - if (Double.isNaN(scaledrange)) { - return false; - } - String labfmt = null; - if (Double.isNaN(im.ygridstep)) { - if (gdef.altYGrid) { - /* find the value with max number of digits. Get number of digits */ - int decimals = (int) Math.ceil(Math.log10(Math.max(Math.abs(im.maxval), - Math.abs(im.minval)))); - if (decimals <= 0) /* everything is small. make place for zero */ { - decimals = 1; - } - int fractionals = (int) Math.floor(Math.log10(range)); - if (fractionals < 0) /* small amplitude. */ { - labfmt = Util.sprintf("%%%d.%df", decimals - fractionals + 1, -fractionals + 1); - } - else { - labfmt = Util.sprintf("%%%d.1f", decimals + 1); - } - gridstep = Math.pow(10, fractionals); - if (gridstep == 0) /* range is one -> 0.1 is reasonable scale */ { - gridstep = 0.1; - } - /* should have at least 5 lines but no more then 15 */ - if (range / gridstep < 5) { - gridstep /= 10; - } - if (range / gridstep > 15) { - gridstep *= 10; - } - if (range / gridstep > 5) { - labfact = 1; - if (range / gridstep > 8) { - labfact = 2; - } - } - else { - gridstep /= 5; - labfact = 5; - } - } - else { - //Start looking for a minimum of 3 labels, but settle for 2 or 1 if need be - int minimumLabelCount = 3; - YLab selectedYLab = null; - while(selectedYLab == null) { - selectedYLab = findYLab(minimumLabelCount); - minimumLabelCount--; - } - gridstep = selectedYLab.grid * im.magfact; - labfact = findLabelFactor(selectedYLab); - } - } - else { - gridstep = im.ygridstep; - labfact = im.ylabfact; - } - int x0 = im.xorigin, x1 = x0 + im.xsize; - int sgrid = (int) (im.minval / gridstep - 1); - int egrid = (int) (im.maxval / gridstep + 1); - double scaledstep = gridstep / im.magfact; - for (int i = sgrid; i <= egrid; i++) { - int y = this.mapper.ytr(gridstep * i); - if (y >= im.yorigin - im.ysize && y <= im.yorigin) { - if (i % labfact == 0) { - String graph_label; - if (i == 0 || im.symbol == ' ') { - if (scaledstep < 1) { - if (i != 0 && gdef.altYGrid) { - graph_label = Util.sprintf(labfmt, scaledstep * i); - } - else { - graph_label = Util.sprintf("%4.1f", scaledstep * i); - } - } - else { - graph_label = Util.sprintf("%4.0f", scaledstep * i); - } - } - else { - if (scaledstep < 1) { - graph_label = Util.sprintf("%4.1f %c", scaledstep * i, im.symbol); - } - else { - graph_label = Util.sprintf("%4.0f %c", scaledstep * i, im.symbol); - } - } - int length = (int) (worker.getStringWidth(graph_label, font)); - worker.drawString(graph_label, x0 - length - PADDING_VLABEL, y + labelOffset, font, fontColor); - worker.drawLine(x0 - 2, y, x0 + 2, y, mGridColor, TICK_STROKE); - worker.drawLine(x1 - 2, y, x1 + 2, y, mGridColor, TICK_STROKE); - worker.drawLine(x0, y, x1, y, mGridColor, GRID_STROKE); - } - else if (!(gdef.noMinorGrid)) { - worker.drawLine(x0 - 1, y, x0 + 1, y, gridColor, TICK_STROKE); - worker.drawLine(x1 - 1, y, x1 + 1, y, gridColor, TICK_STROKE); - worker.drawLine(x0, y, x1, y, gridColor, GRID_STROKE); - } - } - } - return true; - } - -/** -* Finds an acceptable YLab object for the current graph -* If the graph covers positive and negative on the y-axis, then -* desiredMinimumLabelCount is checked as well, to ensure the chosen YLab definition - * will result in the required number of labels -* - * Returns null if none are acceptable (none the right size or with -* enough labels) -*/ -private YLab findYLab(int desiredMinimumLabelCount) { - double scaledrange = this.getScaledRange(); - int labelFactor; - //Check each YLab definition to see if it's acceptable - for (int i = 0; ylab[i].grid > 0; i++) { - YLab thisYLab = ylab[i]; - //First cut is whether this gridstep would give enough space per gridline - if (this.getPixelsPerGridline(thisYLab) > 5 ) { - //Yep; now we might have to check the number of labels - if(im.minval < 0.0 && im.maxval > 0.0) { - //The graph covers positive and negative values, so we need the - // desiredMinimumLabelCount number of labels, which is going to - // usually be 3, then maybe 2, then only as a last resort, 1. - // So, we need to find out what the label factor would be - // if we chose this ylab definition - labelFactor = findLabelFactor(thisYLab); - if(labelFactor == -1) { - //Default to too many to satisfy the label count test, unless we're looking for just 1 - // in which case be sure to satisfy the label count test - labelFactor = desiredMinimumLabelCount==1?1:desiredMinimumLabelCount+1; - } - //Adding one? Think fenceposts (need one more than just dividing length by space between) - int labelCount = ((int)(scaledrange/thisYLab.grid)/labelFactor)+1; - if(labelCount > desiredMinimumLabelCount) { - return thisYLab; //Enough pixels, *and* enough labels - } - - } else { - //Only positive or negative on the graph y-axis. No need to - // care about the label count. - return thisYLab; - } - } - } - - double val = 1; - while(val < scaledrange) { - val = val * 10; - } - return new YLab(val/10, 1, 2, 5, 10); -} - -/** - * Find the smallest labelFactor acceptable (can fit labels) for the given YLab definition - * Returns the label factor if one is ok, otherwise returns -1 if none are acceptable - */ -private int findLabelFactor(YLab thisYLab) { - int pixel = this.getPixelsPerGridline(thisYLab); - int fontHeight = (int) Math.ceil(worker.getFontHeight(gdef.getFont(FONTTAG_AXIS))); - for (int j = 0; j < 4; j++) { - if (pixel * thisYLab.lfac[j] >= 2 * fontHeight) { - return thisYLab.lfac[j]; - } - } - return -1; -} - -/** - * Finds the number of pixels per gridline that the given YLab definition will result in - */ -private int getPixelsPerGridline(YLab thisYLab) { - double scaledrange = this.getScaledRange(); - return (int) (im.ysize / (scaledrange / thisYLab.grid)); -} - -private double getScaledRange() { - double range = im.maxval - im.minval; - return range / im.magfact; -} - - - static class YLab { - double grid; - int[] lfac; - - YLab(double grid, int lfac1, int lfac2, int lfac3, int lfac4) { - this.grid = grid; - lfac = new int[] {lfac1, lfac2, lfac3, lfac4}; - } - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/ValueAxisLogarithmic.java b/apps/jrobin/java/src/org/jrobin/graph/ValueAxisLogarithmic.java deleted file mode 100644 index 68ffc0f453ed616100180d7c168cc9d18a8b0635..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/ValueAxisLogarithmic.java +++ /dev/null @@ -1,121 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.core.Util; - -import java.awt.*; - -class ValueAxisLogarithmic implements RrdGraphConstants { - private static final double[][] yloglab = { - {1e9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1e3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {1e1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - /* { 1e1, 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, */ - {1e1, 1, 2.5, 5, 7.5, 0, 0, 0, 0, 0, 0, 0}, - {1e1, 1, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0}, - {1e1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - }; - - private RrdGraph rrdGraph; - private ImageParameters im; - private ImageWorker worker; - private RrdGraphDef gdef; - - ValueAxisLogarithmic(RrdGraph rrdGraph) { - this.rrdGraph = rrdGraph; - this.im = rrdGraph.im; - this.gdef = rrdGraph.gdef; - this.worker = rrdGraph.worker; - } - - boolean draw() { - Font font = gdef.getFont(FONTTAG_AXIS); - Paint gridColor = gdef.colors[COLOR_GRID]; - Paint mGridColor = gdef.colors[COLOR_MGRID]; - Paint fontColor = gdef.colors[COLOR_FONT]; - int fontHeight = (int) Math.ceil(worker.getFontHeight(font)); - int labelOffset = (int) (worker.getFontAscent(font) / 2); - - double pixpex = (double) im.ysize / (Math.log10(im.maxval) - Math.log10(im.minval)); - if (Double.isNaN(pixpex)) { - return false; - } - double minstep, pixperstep; - int minoridx = 0, majoridx = 0; - for (int i = 0; yloglab[i][0] > 0; i++) { - minstep = Math.log10(yloglab[i][0]); - for (int ii = 1; yloglab[i][ii + 1] > 0; ii++) { - if (yloglab[i][ii + 2] == 0) { - minstep = Math.log10(yloglab[i][ii + 1]) - Math.log10(yloglab[i][ii]); - break; - } - } - pixperstep = pixpex * minstep; - if (pixperstep > 5) { - minoridx = i; - } - if (pixperstep > 2 * fontHeight) { - majoridx = i; - } - } - int x0 = im.xorigin, x1 = x0 + im.xsize; - for (double value = Math.pow(10, Math.log10(im.minval) - - Math.log10(im.minval) % Math.log10(yloglab[minoridx][0])); - value <= im.maxval; - value *= yloglab[minoridx][0]) { - if (value < im.minval) { - continue; - } - int i = 0; - while (yloglab[minoridx][++i] > 0) { - int y = rrdGraph.mapper.ytr(value * yloglab[minoridx][i]); - if (y <= im.yorigin - im.ysize) { - break; - } - worker.drawLine(x0 - 1, y, x0 + 1, y, gridColor, TICK_STROKE); - worker.drawLine(x1 - 1, y, x1 + 1, y, gridColor, TICK_STROKE); - worker.drawLine(x0, y, x1, y, gridColor, GRID_STROKE); - } - } - for (double value = Math.pow(10, Math.log10(im.minval) - - (Math.log10(im.minval) % Math.log10(yloglab[majoridx][0]))); - value <= im.maxval; - value *= yloglab[majoridx][0]) { - if (value < im.minval) { - continue; - } - int i = 0; - while (yloglab[majoridx][++i] > 0) { - int y = rrdGraph.mapper.ytr(value * yloglab[majoridx][i]); - if (y <= im.yorigin - im.ysize) { - break; - } - worker.drawLine(x0 - 2, y, x0 + 2, y, mGridColor, TICK_STROKE); - worker.drawLine(x1 - 2, y, x1 + 2, y, mGridColor, TICK_STROKE); - worker.drawLine(x0, y, x1, y, mGridColor, GRID_STROKE); - String graph_label = Util.sprintf("%3.0e", value * yloglab[majoridx][i]); - int length = (int) (worker.getStringWidth(graph_label, font)); - worker.drawString(graph_label, x0 - length - PADDING_VLABEL, y + labelOffset, font, fontColor); - } - } - return true; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/ValueAxisMrtg.java b/apps/jrobin/java/src/org/jrobin/graph/ValueAxisMrtg.java deleted file mode 100644 index 9788519ccfd9fbd03ab23288969b6a8199a6be61..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/ValueAxisMrtg.java +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -import org.jrobin.core.Util; - -import java.awt.*; - -class ValueAxisMrtg implements RrdGraphConstants { - private ImageParameters im; - private ImageWorker worker; - private RrdGraphDef gdef; - - ValueAxisMrtg(RrdGraph rrdGraph) { - this.im = rrdGraph.im; - this.gdef = rrdGraph.gdef; - this.worker = rrdGraph.worker; - im.unit = gdef.unit; - } - - boolean draw() { - Font font = gdef.getFont(FONTTAG_AXIS); - Paint mGridColor = gdef.colors[COLOR_MGRID]; - Paint fontColor = gdef.colors[COLOR_FONT]; - int labelOffset = (int) (worker.getFontAscent(font) / 2); - - if (Double.isNaN((im.maxval - im.minval) / im.magfact)) { - return false; - } - - int xLeft = im.xorigin; - int xRight = im.xorigin + im.xsize; - String labfmt; - if (im.scaledstep / im.magfact * Math.max(Math.abs(im.quadrant), Math.abs(4 - im.quadrant)) <= 1.0) { - labfmt = "%5.2f"; - } - else { - labfmt = Util.sprintf("%%4.%df", 1 - ((im.scaledstep / im.magfact > 10.0 || Math.ceil(im.scaledstep / im.magfact) == im.scaledstep / im.magfact) ? 1 : 0)); - } - if (im.symbol != ' ' || im.unit != null) { - labfmt += " "; - } - if (im.symbol != ' ') { - labfmt += im.symbol; - } - if (im.unit != null) { - labfmt += im.unit; - } - for (int i = 0; i <= 4; i++) { - int y = im.yorigin - im.ysize * i / 4; - if (y >= im.yorigin - im.ysize && y <= im.yorigin) { - String graph_label = Util.sprintf(labfmt, im.scaledstep / im.magfact * (i - im.quadrant)); - int length = (int) (worker.getStringWidth(graph_label, font)); - worker.drawString(graph_label, xLeft - length - PADDING_VLABEL, y + labelOffset, font, fontColor); - worker.drawLine(xLeft - 2, y, xLeft + 2, y, mGridColor, TICK_STROKE); - worker.drawLine(xRight - 2, y, xRight + 2, y, mGridColor, TICK_STROKE); - worker.drawLine(xLeft, y, xRight, y, mGridColor, GRID_STROKE); - } - } - return true; - } - -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/ValueAxisSetting.java b/apps/jrobin/java/src/org/jrobin/graph/ValueAxisSetting.java deleted file mode 100644 index 272763438c186309da460eca85300da09a4b7add..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/ValueAxisSetting.java +++ /dev/null @@ -1,29 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -class ValueAxisSetting { - final double gridStep; - final int labelFactor; - - ValueAxisSetting(double gridStep, int labelFactor) { - this.gridStep = gridStep; - this.labelFactor = labelFactor; - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/ValueScaler.java b/apps/jrobin/java/src/org/jrobin/graph/ValueScaler.java deleted file mode 100644 index a63a76e6c47819e7e3f96afc589495666f9ab0ef..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/ValueScaler.java +++ /dev/null @@ -1,88 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2001-2005 Sasa Markovic and Ciaran Treanor. - * Copyright (c) 2011 The OpenNMS Group, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - *******************************************************************************/ -package org.jrobin.graph; - -class ValueScaler { - static final String UNIT_UNKNOWN = "?"; - static final String UNIT_SYMBOLS[] = { - "a", "f", "p", "n", "u", "m", " ", "k", "M", "G", "T", "P", "E" - }; - static final int SYMB_CENTER = 6; - - private final double base; - private double magfact = -1; // nothing scaled before, rescale - private String unit; - - ValueScaler(double base) { - this.base = base; - } - - Scaled scale(double value, boolean mustRescale) { - Scaled scaled; - if (mustRescale) { - scaled = rescale(value); - } - else if (magfact >= 0) { - // already scaled, need not rescale - scaled = new Scaled(value / magfact, unit); - } - else { - // scaling not requested, but never scaled before - must rescale anyway - scaled = rescale(value); - // if zero, scale again on the next try - if (scaled.value == 0.0 || Double.isNaN(scaled.value)) { - magfact = -1.0; - } - } - return scaled; - } - - private Scaled rescale(double value) { - int sindex; - if (value == 0.0 || Double.isNaN(value)) { - sindex = 0; - magfact = 1.0; - } - else { - sindex = (int) (Math.floor(Math.log(Math.abs(value)) / Math.log(base))); - magfact = Math.pow(base, sindex); - } - if (sindex <= SYMB_CENTER && sindex >= -SYMB_CENTER) { - unit = UNIT_SYMBOLS[sindex + SYMB_CENTER]; - } - else { - unit = UNIT_UNKNOWN; - } - return new Scaled(value / magfact, unit); - } - - static class Scaled { - double value; - String unit; - - public Scaled(double value, String unit) { - this.value = value; - this.unit = unit; - } - - void dump() { - System.out.println("[" + value + unit + "]"); - } - } -} diff --git a/apps/jrobin/java/src/org/jrobin/graph/package.html b/apps/jrobin/java/src/org/jrobin/graph/package.html deleted file mode 100644 index 5b9630221f8b60d3e6156351a9a5cea2f43d0bd9..0000000000000000000000000000000000000000 --- a/apps/jrobin/java/src/org/jrobin/graph/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<html> - <body> - JRobin graph capabilities. - </body> -</html> \ No newline at end of file diff --git a/apps/jrobin/java/src/org/rrd4j/ConsolFun.java b/apps/jrobin/java/src/org/rrd4j/ConsolFun.java new file mode 100644 index 0000000000000000000000000000000000000000..b7012ac1794ca8db0a358012e05afc15f67a8748 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/ConsolFun.java @@ -0,0 +1,72 @@ +package org.rrd4j; + +import org.rrd4j.data.Variable; + +/** + * Enumeration of available consolidation functions. Note that data aggregation inevitably leads to + * loss of precision and information. The trick is to pick the aggregate function such that the interesting + * properties of your data are kept across the aggregation process. + */ +public enum ConsolFun { + /** + * The average of the data points is stored. + */ + AVERAGE { + @Override + public Variable getVariable() { + return new Variable.AVERAGE(); + } + }, + + /** + * The smallest of the data points is stored. + */ + MIN { + @Override + public Variable getVariable() { + return new Variable.MIN(); + } + }, + + /** + * The largest of the data points is stored. + */ + MAX { + @Override + public Variable getVariable() { + return new Variable.MAX(); + } + }, + + /** + * The last data point is used. + */ + LAST { + @Override + public Variable getVariable() { + return new Variable.LAST(); + } + }, + + /** + * The fist data point is used. + */ + FIRST { + @Override + public Variable getVariable() { + return new Variable.FIRST(); + } + }, + + /** + * The total of the data points is stored. + */ + TOTAL { + @Override + public Variable getVariable() { + return new Variable.TOTAL(); + } + }; + + public abstract Variable getVariable(); +} diff --git a/apps/jrobin/java/src/org/rrd4j/DsType.java b/apps/jrobin/java/src/org/rrd4j/DsType.java new file mode 100644 index 0000000000000000000000000000000000000000..744cb8dda602a8a1f3abfabeed37dfdb132ac117 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/DsType.java @@ -0,0 +1,26 @@ +package org.rrd4j; + +/** + * Enumeration of available datasource types. + */ +public enum DsType { + /** + * Is for things like temperatures or number of people in a room or the value of a RedHat share. + */ + GAUGE, + + /** + * Is for continuous incrementing counters like the ifInOctets counter in a router. + */ + COUNTER, + + /** + * Will store the derivative of the line going from the last to the current value of the data source. + */ + DERIVE, + + /** + * Is for counters which get reset upon reading. + */ + ABSOLUTE +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/Aggregates.java b/apps/jrobin/java/src/org/rrd4j/data/Aggregates.java new file mode 100644 index 0000000000000000000000000000000000000000..e29d6334170c71da543c77d26dc0657c79fb0ff7 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/Aggregates.java @@ -0,0 +1,114 @@ +package org.rrd4j.data; + +import org.rrd4j.ConsolFun; +import org.rrd4j.core.Util; + +/** + * Simple class which holds aggregated values (MIN, MAX, FIRST, LAST, AVERAGE and TOTAL). You + * don't need to create objects of this class directly. Objects of this class are returned from + * <code>getAggregates()</code> method in + * {@link org.rrd4j.core.FetchData#getAggregates(String) FetchData} and + * {@link org.rrd4j.data.DataProcessor#getAggregates(String)} DataProcessor classes. + * + * @deprecated This class is deprecated. Uses instance of {@link org.rrd4j.data.Variable}, used with {@link org.rrd4j.data.DataProcessor#addDatasource(String, String, Variable)}. + */ +@Deprecated +public class Aggregates { + double min = Double.NaN, max = Double.NaN; + double first = Double.NaN, last = Double.NaN; + double average = Double.NaN, total = Double.NaN; + + /** + * Returns the minimal value + * + * @return Minimal value + */ + public double getMin() { + return min; + } + + /** + * Returns the maximum value + * + * @return Maximum value + */ + public double getMax() { + return max; + } + + /** + * Returns the first value + * + * @return First value + */ + public double getFirst() { + return first; + } + + /** + * Returns the last value + * + * @return Last value + */ + public double getLast() { + return last; + } + + /** + * Returns average + * + * @return Average value + */ + public double getAverage() { + return average; + } + + /** + * Returns total value + * + * @return Total value + */ + public double getTotal() { + return total; + } + + + /** + * Returns single aggregated value for the give consolidation function + * + * @param consolFun Consolidation function: MIN, MAX, FIRST, LAST, AVERAGE, TOTAL. These constants + * are conveniently defined in the {@link org.rrd4j.ConsolFun ConsolFun} interface. + * @return Aggregated value + * @throws java.lang.IllegalArgumentException Thrown if unsupported consolidation function is supplied + */ + public double getAggregate(ConsolFun consolFun) { + switch (consolFun) { + case AVERAGE: + return average; + case FIRST: + return first; + case LAST: + return last; + case MAX: + return max; + case MIN: + return min; + case TOTAL: + return total; + } + throw new IllegalArgumentException("Unknown consolidation function: " + consolFun); + } + + /** + * Returns String representing all aggregated values. Just for debugging purposes. + * + * @return String containing all aggregated values + */ + public String dump() { + StringBuilder bl = new StringBuilder(); + for(ConsolFun cf: ConsolFun.values()) { + bl.append(cf.name() + '=' + Util.formatDouble(this.getAggregate(cf))); + } + return bl.toString(); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/Aggregator.java b/apps/jrobin/java/src/org/rrd4j/data/Aggregator.java new file mode 100644 index 0000000000000000000000000000000000000000..bfbc8f6dd847217d408815e0f615bc031b11015d --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/Aggregator.java @@ -0,0 +1,93 @@ +package org.rrd4j.data; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +class Aggregator { + private final long timestamps[], step; + private final double[] values; + + Aggregator(long[] timestamps, double[] values) { + assert timestamps.length == values.length : "Incompatible timestamps/values arrays (unequal lengths)"; + assert timestamps.length >= 2 : "At least two timestamps must be supplied"; + this.timestamps = timestamps; + this.values = values; + this.step = timestamps[1] - timestamps[0]; + } + + @Deprecated + Aggregates getAggregates(long tStart, long tEnd) { + Aggregates agg = new Aggregates(); + long totalSeconds = 0; + int cnt = 0; + + for (int i = 0; i < timestamps.length; i++) { + long left = Math.max(timestamps[i] - step, tStart); + long right = Math.min(timestamps[i], tEnd); + long delta = right - left; + + // delta is only > 0 when the time stamp for a given buck is within the range of tStart and tEnd + if (delta > 0) { + double value = values[i]; + + if (!Double.isNaN(value)) { + totalSeconds += delta; + cnt++; + + if (cnt == 1) { + agg.last = agg.first = agg.total = agg.min = agg.max = value; + } + else { + if (delta >= step) { // an entire bucket is included in this range + agg.last = value; + } + + agg.min = Math.min(agg.min, value); + agg.max = Math.max(agg.max, value); + agg.total += value; + + } + } + } + } + + if(cnt > 0) { + agg.average = agg.total / totalSeconds; + } + + return agg; + } + + double getPercentile(long tStart, long tEnd, double percentile) { + List<Double> valueList = new ArrayList<Double>(); + // create a list of included datasource values (different from NaN) + for (int i = 0; i < timestamps.length; i++) { + long left = Math.max(timestamps[i] - step, tStart); + long right = Math.min(timestamps[i], tEnd); + if (right > left && !Double.isNaN(values[i])) { + valueList.add(Double.valueOf(values[i])); + } + } + // create an array to work with + int count = valueList.size(); + if (count > 1) { + double[] valuesCopy = new double[count]; + for (int i = 0; i < count; i++) { + valuesCopy[i] = valueList.get(i).doubleValue(); + } + // sort array + Arrays.sort(valuesCopy); + // skip top (100% - percentile) values + double topPercentile = (100.0 - percentile) / 100.0; + count -= (int) Math.ceil(count * topPercentile); + // if we have anything left... + if (count > 0) { + return valuesCopy[count - 1]; + } + } + // not enough data available + return Double.NaN; + } +} + diff --git a/apps/jrobin/java/src/org/rrd4j/data/CDef.java b/apps/jrobin/java/src/org/rrd4j/data/CDef.java new file mode 100644 index 0000000000000000000000000000000000000000..75301674e59366cb71f5596ebffd015793aaadeb --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/CDef.java @@ -0,0 +1,20 @@ +package org.rrd4j.data; + +class CDef extends Source implements NonRrdSource { + private final String rpnExpression; + + CDef(String name, String rpnExpression) { + super(name); + this.rpnExpression = rpnExpression; + } + + String getRpnExpression() { + return rpnExpression; + } + + /** {@inheritDoc} */ + public void calculate(long tStart, long tEnd, DataProcessor dataProcessor) { + RpnCalculator calc = new RpnCalculator(rpnExpression, getName(), dataProcessor); + setValues(calc.calculateValues()); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/CubicSplineInterpolator.java b/apps/jrobin/java/src/org/rrd4j/data/CubicSplineInterpolator.java new file mode 100644 index 0000000000000000000000000000000000000000..94d851615ab138754a7ed351d94a9d899bec61fb --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/CubicSplineInterpolator.java @@ -0,0 +1,177 @@ +package org.rrd4j.data; + +import org.rrd4j.core.Util; + +import java.util.Calendar; +import java.util.Date; + +/** + * Class used to interpolate datasource values from the collection of (timestamp, values) + * points using natural cubic spline interpolation. + * <p> + * + * <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. + */ +public class CubicSplineInterpolator extends Plottable { + private double[] x; + private double[] y; + + // second derivates come here + private double[] y2; + + // internal spline variables + private int n, klo, khi; + + /** + * Creates cubic spline interpolator from arrays of timestamps and corresponding + * datasource values. + * + * @param timestamps timestamps in seconds + * @param values corresponding datasource values + * @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least 3 values, or if + * timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN. + */ + public CubicSplineInterpolator(long[] timestamps, double[] values) { + this.x = new double[timestamps.length]; + for (int i = 0; i < timestamps.length; i++) { + this.x[i] = timestamps[i]; + } + this.y = values; + validate(); + spline(); + } + + /** + * Creates cubic spline interpolator from arrays of Date objects and corresponding + * datasource values. + * + * @param dates Array of Date objects + * @param values corresponding datasource values + * @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least 3 values, or if + * timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN. + */ + public CubicSplineInterpolator(Date[] dates, double[] values) { + this.x = new double[dates.length]; + for (int i = 0; i < dates.length; i++) { + this.x[i] = Util.getTimestamp(dates[i]); + } + this.y = values; + validate(); + spline(); + } + + /** + * Creates cubic spline interpolator from arrays of GregorianCalendar objects and corresponding + * datasource values. + * + * @param dates Array of GregorianCalendar objects + * @param values corresponding datasource values + * @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least 3 values, or if + * timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN. + */ + public CubicSplineInterpolator(Calendar[] dates, double[] values) { + this.x = new double[dates.length]; + for (int i = 0; i < dates.length; i++) { + this.x[i] = Util.getTimestamp(dates[i]); + } + this.y = values; + validate(); + spline(); + } + + /** + * Creates cubic spline interpolator for an array of 2D-points. + * + * @param x x-axis point coordinates + * @param y y-axis point coordinates + * @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least 3 values, or if + * timestamps are not ordered, or array lengths are not equal, or some datasource value is NaN. + */ + public CubicSplineInterpolator(double[] x, double[] y) { + this.x = x; + this.y = y; + validate(); + spline(); + } + + private void validate() { + boolean ok = true; + if (x.length != y.length || x.length < 3) { + ok = false; + } + for (int i = 0; i < x.length - 1 && ok; i++) { + if (x[i] >= x[i + 1] || Double.isNaN(y[i])) { + ok = false; + } + } + if (!ok) { + throw new IllegalArgumentException("Invalid plottable data supplied"); + } + } + + private void spline() { + n = x.length; + y2 = new double[n]; + double[] u = new double[n - 1]; + y2[0] = y2[n - 1] = 0.0; + u[0] = 0.0; // natural spline + for (int i = 1; i <= n - 2; i++) { + double sig = (x[i] - x[i - 1]) / (x[i + 1] - x[i - 1]); + double p = sig * y2[i - 1] + 2.0; + y2[i] = (sig - 1.0) / p; + u[i] = (y[i + 1] - y[i]) / (x[i + 1] - x[i]) - (y[i] - y[i - 1]) / (x[i] - x[i - 1]); + u[i] = (6.0 * u[i] / (x[i + 1] - x[i - 1]) - sig * u[i - 1]) / p; + } + for (int k = n - 2; k >= 0; k--) { + y2[k] = y2[k] * y2[k + 1] + u[k]; + } + // prepare everything for getValue() + klo = 0; + khi = n - 1; + } + + /** + * Calculates spline-interpolated y-value for the corresponding x-value. Call + * this if you need spline-interpolated values in your code. + * + * @param xval x-value + * @return inteprolated y-value + */ + public double getValue(double xval) { + if (xval < x[0] || xval > x[n - 1]) { + return Double.NaN; + } + if (xval < x[klo] || xval > x[khi]) { + // out of bounds + klo = 0; + khi = n - 1; + } + while (khi - klo > 1) { + // find bounding interval using bisection method + int k = (khi + klo) / 2; + if (x[k] > xval) { + khi = k; + } + else { + klo = k; + } + } + double h = x[khi] - x[klo]; + double a = (x[khi] - xval) / h; + double b = (xval - x[klo]) / h; + return a * y[klo] + b * y[khi] + + ((a * a * a - a) * y2[klo] + (b * b * b - b) * y2[khi]) * (h * h) / 6.0; + } + + /** + * {@inheritDoc} + * + * Method overridden from the base class. This method will be called by the framework. Call + * this method only if you need spline-interpolated values in your code. + */ + public double getValue(long timestamp) { + return getValue((double)timestamp); + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/DataProcessor.java b/apps/jrobin/java/src/org/rrd4j/data/DataProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..7780f782c7906c1f0e398c35c288ad052972ba59 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/DataProcessor.java @@ -0,0 +1,901 @@ +package org.rrd4j.data; + +import org.rrd4j.ConsolFun; +import org.rrd4j.core.FetchData; +import org.rrd4j.core.FetchRequest; +import org.rrd4j.core.RrdBackendFactory; +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), + * SDEF (static datasources - extension of Rrd4j) and PDEF (plottables, see + * {@link org.rrd4j.data.Plottable Plottable} for more information.</p> + * + * <p>Typical class usage:</p> + * <pre> + * final long t1 = ... + * final long t2 = ... + * DataProcessor dp = new DataProcessor(t1, t2); + * // DEF datasource + * dp.addDatasource("x", "demo.rrd", "some_source", "AVERAGE"); + * // DEF datasource + * dp.addDatasource("y", "demo.rrd", "some_other_source", "AVERAGE"); + * // CDEF datasource, z = (x + y) / 2 + * dp.addDatasource("z", "x,y,+,2,/"); + * // ACTION! + * dp.processData(); + * // Dump calculated values + * System.out.println(dp.dump()); + * </pre> + */ +public class DataProcessor { + + /** + * 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. + */ + 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; + + /** + * 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 lastRrdArchiveUpdateTime = 0; + // this will be adjusted later + private long step = 0; + // resolution to be used for RRD fetch operation + private long fetchRequestResolution = 1; + // The timezone to use + private TimeZone tz = TimeZone.getDefault(); + + // the order is important, ordinary HashMap is unordered + private Map<String, Source> sources = new LinkedHashMap<String, Source>(); + + private Def[] defSources; + + /** + * Creates new DataProcessor object for the given time span. Ending timestamp may be set to zero. + * In that case, the class will try to find the optimal ending timestamp based on the last update time of + * RRD files processed with the {@link #processData()} method. + * + * @param t1 Starting timestamp in seconds without milliseconds + * @param t2 Ending timestamp in seconds without milliseconds + */ + public DataProcessor(long t1, long t2) { + if ((t1 < t2 && t1 > 0 && t2 > 0) || (t1 > 0 && t2 == 0)) { + this.tStart = t1; + this.tEnd = t2; + } + else { + throw new IllegalArgumentException("Invalid timestamps specified: " + t1 + ", " + t2); + } + } + + /** + * Creates new DataProcessor object for the given time span. Ending date may be set to null. + * In that case, the class will try to find optimal ending date based on the last update time of + * RRD files processed with the {@link #processData()} method. + * + * @param d1 Starting date + * @param d2 Ending date + */ + public DataProcessor(Date d1, Date d2) { + this(Util.getTimestamp(d1), d2 != null ? Util.getTimestamp(d2) : 0); + } + + /** + * Creates new DataProcessor object for the given time span. Ending date may be set to null. + * In that case, the class will try to find optimal ending date based on the last update time of + * RRD files processed with the {@link #processData()} method. + * + * It use the time zone for starting calendar date. + * + * @param gc1 Starting Calendar date + * @param gc2 Ending Calendar date + */ + public DataProcessor(Calendar gc1, Calendar gc2) { + this(Util.getTimestamp(gc1), gc2 != null ? Util.getTimestamp(gc2) : 0); + this.tz = gc1.getTimeZone(); + } + + /** + * 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. + */ + public boolean isPoolUsed() { + return poolUsed; + } + + /** + * Sets the {@link org.rrd4j.core.RrdDbPool RrdDbPool} usage policy. + * + * @param poolUsed true, if the pool should be used to fetch data from RRD files, false otherwise. + */ + public void setPoolUsed(boolean poolUsed) { + this.poolUsed = poolUsed; + } + + public RrdDbPool getPool() { + return pool; + } + + /** + * 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 + */ + public void setPool(RrdDbPool pool) { + this.pool = pool; + } + + + /** + * <p>Sets the number of pixels (target graph width). This number is used only to calculate pixel coordinates + * for Rrd4j graphs (methods {@link #getValuesPerPixel(String)} and {@link #getTimestampsPerPixel()}), + * but has influence neither on datasource values calculated with the + * {@link #processData()} method nor on aggregated values returned from {@link #getAggregates(String)} + * 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. + */ + public void setPixelCount(int pixelCount) { + this.pixelCount = pixelCount; + } + + /** + * Returns the number of pixels (target graph width). See {@link #setPixelCount(int)} for more information. + * + * @return Target graph width + */ + public int getPixelCount() { + return pixelCount; + } + + /** + * <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). + */ + 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. + * + * @return Step used for data processing. + */ + public long getStep() { + return step; + } + + /** + * Returns desired RRD archive step (resolution) in seconds to be used while fetching data + * from RRD files. In other words, this value will used as the last parameter of + * {@link org.rrd4j.core.RrdDb#createFetchRequest(ConsolFun, long, long, long) RrdDb.createFetchRequest()} method + * when this method is called internally by this DataProcessor. + * + * @return Desired archive step (fetch resolution) in seconds. + */ + public long getFetchRequestResolution() { + return fetchRequestResolution; + } + + /** + * Sets desired RRD archive step in seconds to be used internally while fetching data + * from RRD files. In other words, this value will used as the last parameter of + * {@link org.rrd4j.core.RrdDb#createFetchRequest(ConsolFun, long, long, long) RrdDb.createFetchRequest()} method + * when this method is called internally by this DataProcessor. If this method is never called, fetch + * request resolution defaults to 1 (smallest possible archive step will be chosen automatically). + * + * @param fetchRequestResolution Desired archive step (fetch resolution) in seconds. + */ + public void setFetchRequestResolution(long fetchRequestResolution) { + this.fetchRequestResolution = fetchRequestResolution; + } + + public TimeZone getTimeZone() { + return tz; + } + + public void setTimeZone(TimeZone tz) { + this.tz = tz; + } + + /** + * Returns ending timestamp. Basically, this value is equal to the ending timestamp + * specified in the constructor. However, if the ending timestamps was zero, it + * will be replaced with the real timestamp when the {@link #processData()} method returns. The real + * value will be calculated from the last update times of processed RRD files. + * + * @return Ending timestamp in seconds + */ + public long getEndingTimestamp() { + return tEnd; + } + + /** + * Returns consolidated timestamps created with the {@link #processData()} method. + * + * @return array of timestamps in seconds + */ + public long[] getTimestamps() { + if (timestamps == null) { + throw new IllegalArgumentException("Timestamps not calculated yet"); + } + else { + return timestamps; + } + } + + /** + * Returns calculated values for a single datasource. Corresponding timestamps can be obtained from + * the {@link #getTimestamps()} method. + * + * @param sourceName Datasource name + * @return an array of datasource values + * @throws java.lang.IllegalArgumentException Thrown if invalid datasource name is specified, + * or if datasource values are not yet calculated (method {@link #processData()} + * was not called) + */ + public double[] getValues(String sourceName) { + Source source = getSource(sourceName); + double[] values = source.getValues(); + if (values == null) { + throw new IllegalArgumentException("Values not available for source [" + sourceName + "]"); + } + return values; + } + + /** + * Returns single aggregated value for a single datasource. + * + * @param sourceName Datasource name + * @param consolFun Consolidation function to be applied to fetched datasource values. + * Valid consolidation functions are MIN, MAX, LAST, FIRST, AVERAGE and TOTAL + * (these string constants are conveniently defined in the {@link org.rrd4j.ConsolFun} class) + * @throws java.lang.IllegalArgumentException Thrown if invalid datasource name is specified, + * or if datasource values are not yet calculated (method {@link #processData()} + * was not called) + * @return a aggregate value as a double calculated from the source. + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public double getAggregate(String sourceName, ConsolFun consolFun) { + Variable v = consolFun.getVariable(); + Source source = getSource(sourceName); + v.calculate(source, tStart, tEnd); + return v.getValue().value; + } + + /** + * Returns all (MIN, MAX, LAST, FIRST, AVERAGE and TOTAL) aggregated values for a single datasource. + * + * @param sourceName Datasource name + * @return Object containing all aggregated values + * @throws java.lang.IllegalArgumentException Thrown if invalid datasource name is specified, + * or if datasource values are not yet calculated (method {@link #processData()} + * was not called) + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public Aggregates getAggregates(String sourceName) { + Source source = getSource(sourceName); + return source.getAggregates(tStart, tEnd); + } + + /** + * Extract the variable value from an already define Variable datasource (a VDEF) + * + * @param sourceName Datasource name + * @return A combined time and value extracted calculated from the datasource + */ + public Variable.Value getVariable(String sourceName) { + Source source = getSource(sourceName); + if( source instanceof VDef) { + return ((VDef) source).getValue(); + } + else { + throw new IllegalArgumentException(String.format("%s is not a Variable source", source.getName())); + } + } + + /** + * Returns single aggregated value for a single datasource. + * + * @param sourceName Datasource name + * @param var variable that will generate value + * @return A combined time and value extracted calculated from the datasource + */ + public Variable.Value getVariable(String sourceName, Variable var) { + Source source = getSource(sourceName); + var.calculate(source, tStart, tEnd); + return var.getValue(); + } + + /** + * This method is just an alias for {@link #getPercentile(String)} method. + * + * Used by ISPs which charge for bandwidth utilization on a "95th percentile" basis.<p> + * + * The 95th percentile is the highest source value left when the top 5% of a numerically sorted set + * of source data is discarded. It is used as a measure of the peak value used when one discounts + * a fair amount for transitory spikes. This makes it markedly different from the average.<p> + * + * Read more about this topic at + * <a href="http://www.red.net/support/resourcecentre/leasedline/percentile.php">Rednet</a> or + * <a href="http://www.bytemark.co.uk/support/tech/95thpercentile.html">Bytemark</a>. + * + * @param sourceName Datasource name + * @return 95th percentile of fetched source values + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public double get95Percentile(String sourceName) { + return getPercentile(sourceName); + } + + /** + * Used by ISPs which charge for bandwidth utilization on a "95th percentile" basis.<p> + * + * The 95th percentile is the highest source value left when the top 5% of a numerically sorted set + * of source data is discarded. It is used as a measure of the peak value used when one discounts + * a fair amount for transitory spikes. This makes it markedly different from the average.<p> + * + * Read more about this topic at + * <a href="http://www.red.net/support/resourcecentre/leasedline/percentile.php">Rednet</a> or + * <a href="http://www.bytemark.co.uk/support/tech/95thpercentile.html">Bytemark</a>. + * + * @param sourceName Datasource name + * @return 95th percentile of fetched source values + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public double getPercentile(String sourceName) { + return getPercentile(sourceName, DEFAULT_PERCENTILE); + } + + /** + * The same as {@link #getPercentile(String)} but with a possibility to define custom percentile boundary + * (different from 95). + * + * @param sourceName Datasource name. + * @param percentile Boundary percentile. Value of 95 (%) is suitable in most cases, but you are free + * to provide your own percentile boundary between zero and 100. + * @return Requested percentile of fetched source values + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public double getPercentile(String sourceName, double percentile) { + if (percentile <= 0.0 || percentile > 100.0) { + throw new IllegalArgumentException("Invalid percentile [" + percentile + "], should be between 0 and 100"); + } + Source source = getSource(sourceName); + return source.getPercentile(tStart, tEnd, percentile); + } + + /** + * Returns array of datasource names defined in this DataProcessor. + * + * @return array of datasource names + */ + public String[] getSourceNames() { + return sources.keySet().toArray(new String[sources.keySet().size()]); + } + + /** + * Returns an array of all datasource values for all datasources. Each row in this two-dimensional + * array represents an array of calculated values for a single datasource. The order of rows is the same + * as the order in which datasources were added to this DataProcessor object. + * + * @return All datasource values for all datasources. The first index is the index of the datasource, + * the second index is the index of the datasource value. The number of datasource values is equal + * to the number of timestamps returned with {@link #getTimestamps()} method. + * @throws java.lang.IllegalArgumentException Thrown if invalid datasource name is specified, + * or if datasource values are not yet calculated (method {@link #processData()} + * was not called) + */ + public double[][] getValues() { + String[] names = getSourceNames(); + double[][] values = new double[names.length][]; + for (int i = 0; i < names.length; i++) { + values[i] = getValues(names[i]); + } + return values; + } + + Source getSource(String sourceName) { + Source source = sources.get(sourceName); + if (source != null) { + return source; + } + throw new IllegalArgumentException("Unknown source: " + sourceName); + } + + ///////////////////////////////////////////////////////////////// + // DATASOURCE DEFINITIONS + ///////////////////////////////////////////////////////////////// + + /** + * 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. + */ + public void addDatasource(String name, Plottable plottable) { + PDef pDef = new PDef(name, plottable); + sources.put(name, pDef); + } + + /** + * <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. + */ + public void addDatasource(String name, String rpnExpression) { + CDef cDef = new CDef(name, rpnExpression); + sources.put(name, cDef); + } + + /** + * Adds static source (<b>SDEF</b>). Static sources are the result of a consolidation function applied + * to <em>any</em> other source that has been defined previously. + * + * @param name source name. + * @param defName Name of the datasource to calculate the value from. + * @param consolFun Consolidation function to use for value calculation + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public void addDatasource(String name, String defName, ConsolFun consolFun) { + VDef sDef = new VDef(name, defName, consolFun.getVariable()); + sources.put(name, sDef); + } + + /** + * Creates a datasource that performs a percentile calculation on an + * another named datasource to yield a single 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 sourceName - the datasource from which to extract the percentile. Must be a previously + * defined virtual datasource + * @param percentile - the percentile to extract from the source datasource + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public void addDatasource(String name, String sourceName, double percentile) { + sources.put(name, new VDef(name, sourceName, new Variable.PERCENTILE(percentile))); + } + + /** + * Creates a datasource that performs a variable calculation on an + * another named datasource to yield a single combined timestampe/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 + */ + public void addDatasource(String name, String defName, Variable var) { + VDef sDef = new VDef(name, defName, var); + sources.put(name, sDef); + } + + /** + * <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 + */ + public void addDatasource(String name, String file, String dsName, ConsolFun consolFunc) { + Def def = new Def(name, file, dsName, consolFunc); + 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 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. + * @deprecated uses {@link #addDatasource(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)); + 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 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. + */ + public void addDatasource(String name, String file, String dsName, ConsolFun consolFunc, RrdBackendFactory backend) { + Def def = new Def(name, file, dsName, consolFunc, backend); + 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. + * + * @param name Source name. + * @param fetchData Fetched data containing values for the given source name. + */ + public void addDatasource(String name, FetchData fetchData) { + Def def = new Def(name, 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. + */ + public void addDatasource(String name, String dsName, FetchData fetchData) { + Def def = new Def(name, dsName, fetchData); + sources.put(name, def); + } + + ///////////////////////////////////////////////////////////////// + // CALCULATIONS + ///////////////////////////////////////////////////////////////// + + /** + * Method that should be called once all datasources are defined. Data will be fetched from + * RRD files, RPN expressions will be calculated, etc. + * + * @throws java.io.IOException Thrown in case of I/O error (while fetching data from RRD files) + */ + public void processData() throws IOException { + extractDefs(); + fetchRrdData(); + fixZeroEndingTimestamp(); + chooseOptimalStep(); + createTimestamps(); + assignTimestampsToSources(); + normalizeRrdValues(); + calculateNonRrdSources(); + } + + /** + * Method used to calculate datasource values which should be presented on the graph + * based on the desired graph width. Each value returned represents a single pixel on the graph. + * Corresponding timestamp can be found in the array returned from {@link #getTimestampsPerPixel()} + * method. + * + * @param sourceName Datasource name + * @param pixelCount Graph width + * @return Per-pixel datasource values + * @throws java.lang.IllegalArgumentException Thrown if datasource values are not yet calculated (method {@link #processData()} + * was not called) + */ + public double[] getValuesPerPixel(String sourceName, int pixelCount) { + setPixelCount(pixelCount); + return getValuesPerPixel(sourceName); + } + + /** + * Method used to calculate datasource values which should be presented on the graph + * based on the graph width set with a {@link #setPixelCount(int)} method call. + * Each value returned represents a single pixel on the graph. Corresponding timestamp can be + * found in the array returned from {@link #getTimestampsPerPixel()} method. + * + * @param sourceName Datasource name + * @return Per-pixel datasource values + * @throws java.lang.IllegalArgumentException Thrown if datasource values are not yet calculated (method {@link #processData()} + * was not called) + */ + public double[] getValuesPerPixel(String sourceName) { + double[] values = getValues(sourceName); + double[] pixelValues = new double[pixelCount]; + Arrays.fill(pixelValues, Double.NaN); + long span = tEnd - tStart; + // this is the ugliest nested loop I have ever made + for (int pix = 0, ref = 0; pix < pixelCount; pix++) { + double t = tStart + (double) (span * pix) / (double) (pixelCount - 1); + while (ref < timestamps.length) { + if (t <= timestamps[ref] - step) { + // too left, nothing to do, already NaN + break; + } + else if (t <= timestamps[ref]) { + // in brackets, get this value + pixelValues[pix] = values[ref]; + break; + } + else { + // too right + ref++; + } + } + } + return pixelValues; + } + + /** + * Calculates timestamps which correspond to individual pixels on the graph. + * + * @param pixelCount Graph width + * @return Array of timestamps + */ + public long[] getTimestampsPerPixel(int pixelCount) { + setPixelCount(pixelCount); + return getTimestampsPerPixel(); + } + + /** + * Calculates timestamps which correspond to individual pixels on the graph + * based on the graph width set with a {@link #setPixelCount(int)} method call. + * + * @return Array of timestamps + */ + public long[] getTimestampsPerPixel() { + long[] times = new long[pixelCount]; + long span = tEnd - tStart; + for (int i = 0; i < pixelCount; i++) { + times[i] = Math.round(tStart + (double) (span * i) / (double) (pixelCount - 1)); + } + return times; + } + + /** + * Dumps timestamps and values of all datasources in a tabular form. Very useful for debugging. + * + * @return Dumped object content. + */ + public String dump() { + String[] names = getSourceNames(); + double[][] values = getValues(); + StringBuilder buffer = new StringBuilder(); + buffer.append(format("timestamp", 12)); + for (String name : names) { + buffer.append(format(name, 20)); + } + buffer.append("\n"); + for (int i = 0; i < timestamps.length; i++) { + buffer.append(format(Long.toString(timestamps[i]), 12)); + for (int j = 0; j < names.length; j++) { + buffer.append(format(Util.formatDouble(values[j][i]), 20)); + } + buffer.append("\n"); + } + return buffer.toString(); + } + + /** + * Returns time when last RRD archive was updated (all RRD files are considered). + * + * @return Last archive update time for all RRD files in this DataProcessor + */ + public long getLastRrdArchiveUpdateTime() { + return lastRrdArchiveUpdateTime; + } + + // 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()]); + } + + 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()); + } + } + // 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); + req.setFilter(dsNames); + FetchData data = req.fetchData(); + defSources[i].setFetchData(data); + for (int j = i + 1; j < defSources.length; j++) { + if (defSources[i].isCompatibleWith(defSources[j])) { + defSources[j].setFetchData(data); + } + } + } + } + } + } + + private void fixZeroEndingTimestamp() { + if (tEnd == 0) { + if (defSources.length == 0) { + throw new IllegalStateException("Could not adjust zero ending timestamp, no DEF source provided"); + } + tEnd = defSources[0].getArchiveEndTime(); + for (int i = 1; i < defSources.length; i++) { + tEnd = Math.min(tEnd, defSources[i].getArchiveEndTime()); + } + if (tEnd <= tStart) { + throw new IllegalStateException("Could not resolve zero ending timestamp."); + } + } + } + + // Tricky and ugly. Should be redesigned some time in the future + private void chooseOptimalStep() { + long newStep = Long.MAX_VALUE; + for (Def defSource : defSources) { + long fetchStep = defSource.getFetchStep(), tryStep = fetchStep; + if (step > 0) { + tryStep = Math.min(newStep, (((step - 1) / fetchStep) + 1) * fetchStep); + } + newStep = Math.min(newStep, tryStep); + } + if (newStep != Long.MAX_VALUE) { + // step resolved from a RRD file + step = newStep; + } + else { + // choose step based on the number of pixels (useful for plottable datasources) + step = Math.max((tEnd - tStart) / pixelCount, 1); + } + } + + private void createTimestamps() { + long t1 = Util.normalize(tStart, step); + long t2 = Util.normalize(tEnd, step); + if (t2 < tEnd) { + t2 += step; + } + int count = (int) (((t2 - t1) / step) + 1); + timestamps = new long[count]; + for (int i = 0; i < count; i++) { + timestamps[i] = t1; + t1 += step; + } + } + + private void assignTimestampsToSources() { + for (Source src : sources.values()) { + src.setTimestamps(timestamps); + } + } + + private void normalizeRrdValues() { + Normalizer normalizer = new Normalizer(timestamps); + for (Def def : defSources) { + long[] rrdTimestamps = def.getRrdTimestamps(); + double[] rrdValues = def.getRrdValues(); + def.setValues(normalizer.normalize(rrdTimestamps, rrdValues)); + } + } + + private void calculateNonRrdSources() { + for (Source source : sources.values()) { + if (source instanceof NonRrdSource) { + ((NonRrdSource)source).calculate(tStart, tEnd, this); + } + } + } + + 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++) { + b.append(' '); + } + return b.toString(); + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/Def.java b/apps/jrobin/java/src/org/rrd4j/data/Def.java new file mode 100644 index 0000000000000000000000000000000000000000..8123343d03cdc8d88cbfef27de638784060cd435 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/Def.java @@ -0,0 +1,114 @@ +package org.rrd4j.data; + +import org.rrd4j.ConsolFun; +import org.rrd4j.core.FetchData; +import org.rrd4j.core.RrdBackendFactory; +import org.rrd4j.core.Util; + +import java.io.IOException; + +class Def extends Source { + private final String path; + private final String dsName; + private final RrdBackendFactory backend; + private final ConsolFun consolFun; + private FetchData fetchData; + + Def(String name, FetchData fetchData) { + this(name, name, fetchData); + } + + Def(String name, String dsName, FetchData fetchData) { + this(name, + fetchData.getRequest().getParentDb().getPath(), + 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) { + super(name); + this.path = path; + this.dsName = dsName; + this.consolFun = consolFunc; + this.backend = backend; + } + + String getPath() { + return path; + } + + String getCanonicalPath() throws IOException { + return Util.getCanonicalPath(path); + } + + String getDsName() { + return dsName; + } + + ConsolFun getConsolFun() { + return consolFun; + } + + RrdBackendFactory getBackend() { + return backend; + } + + boolean isCompatibleWith(Def def) throws IOException { + return getCanonicalPath().equals(def.getCanonicalPath()) && + getConsolFun() == def.consolFun && + ((backend == null && def.backend == null) || + (backend != null && def.backend != null && backend.equals(def.backend))); + } + + void setFetchData(FetchData fetchData) { + this.fetchData = fetchData; + } + + long[] getRrdTimestamps() { + return fetchData.getTimestamps(); + } + + double[] getRrdValues() { + return fetchData.getValues(dsName); + } + + long getArchiveEndTime() { + return fetchData.getArcEndTime(); + } + + long getFetchStep() { + return fetchData.getStep(); + } + + /* (non-Javadoc) + * @see org.rrd4j.data.Source#getAggregates(long, long) + */ + @Override + @Deprecated + Aggregates getAggregates(long tStart, long tEnd) { + long[] t = getRrdTimestamps(); + double[] v = getRrdValues(); + return new Aggregator(t, v).getAggregates(tStart, tEnd); + } + + /* (non-Javadoc) + * @see org.rrd4j.data.Source#getPercentile(long, long, double) + */ + @Override + @Deprecated + double getPercentile(long tStart, long tEnd, double percentile) { + long[] t = getRrdTimestamps(); + double[] v = getRrdValues(); + return new Aggregator(t, v).getPercentile(tStart, tEnd, percentile); + } + + boolean isLoaded() { + return fetchData != null; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/LinearInterpolator.java b/apps/jrobin/java/src/org/rrd4j/data/LinearInterpolator.java new file mode 100644 index 0000000000000000000000000000000000000000..53eb262681020c111b097fed8f91af18e0251942 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/LinearInterpolator.java @@ -0,0 +1,273 @@ +package org.rrd4j.data; + +import org.rrd4j.core.Util; + +import java.util.Calendar; +import java.util.Date; + +/** + * <p>Class used to interpolate datasource values from the collection of (timestamp, values) + * points. This class is suitable for linear interpolation only.</p> + * + * <p>Interpolation algorithm returns different values based on the value passed to + * {@link #setInterpolationMethod(Method) setInterpolationMethod()}. If not set, interpolation + * method defaults to standard linear interpolation ({@link org.rrd4j.data.LinearInterpolator.Method#LINEAR}). + * Interpolation method handles NaN datasource + * values gracefully.</p> + */ +public class LinearInterpolator extends Plottable { + + /** + * constant used to specify LEFT interpolation. + * See {@link #setInterpolationMethod(int) setInterpolationMethod()} for explanation. + */ + public static final int INTERPOLATE_LEFT = 0; + /** + * constant used to specify RIGHT interpolation. + * See {@link #setInterpolationMethod(int) setInterpolationMethod()} for explanation. + */ + public static final int INTERPOLATE_RIGHT = 1; + /** + * constant used to specify LINEAR interpolation (default interpolation method). + * See {@link #setInterpolationMethod(int) setInterpolationMethod()} for explanation. + */ + public static final int INTERPOLATE_LINEAR = 2; + /** + * constant used to specify LINEAR REGRESSION as interpolation method. + * See {@link #setInterpolationMethod(int) setInterpolationMethod()} for explanation. + */ + public static final int INTERPOLATE_REGRESSION = 3; + + /** + * A enumeration of interpolation methods + * @author Fabrice Bacchella + * + */ + public enum Method { + LEFT, + RIGHT, + LINEAR, + REGRESSION; + } + + private int lastIndexUsed = 0; + private Method interpolationMethod = Method.LINEAR; + + private long[] timestamps; + private double[] values; + + // used only if INTERPOLATE_BESTFIT is specified + double b0 = Double.NaN; + double b1 = Double.NaN; + + /** + * Creates LinearInterpolator from arrays of timestamps and corresponding datasource values. + * + * @param timestamps timestamps in seconds + * @param values corresponding datasource values + * @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least two values, or if + * timestamps are not ordered, or array lengths are not equal. + */ + public LinearInterpolator(long[] timestamps, double[] values) { + this.timestamps = timestamps; + this.values = values; + validate(); + } + + /** + * Creates LinearInterpolator from arrays of timestamps and corresponding datasource values. + * + * @param dates Array of Date objects + * @param values corresponding datasource values + * @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least two values, or if + * timestamps are not ordered, or array lengths are not equal. + */ + public LinearInterpolator(Date[] dates, double[] values) { + this.values = values; + timestamps = new long[dates.length]; + for (int i = 0; i < dates.length; i++) { + timestamps[i] = Util.getTimestamp(dates[i]); + } + validate(); + } + + /** + * Creates LinearInterpolator from arrays of timestamps and corresponding datasource values. + * + * @param dates array of GregorianCalendar objects + * @param values corresponding datasource values + * @throws java.lang.IllegalArgumentException Thrown if supplied arrays do not contain at least two values, or if + * timestamps are not ordered, or array lengths are not equal. + */ + public LinearInterpolator(Calendar[] dates, double[] values) { + this.values = values; + timestamps = new long[dates.length]; + for (int i = 0; i < dates.length; i++) { + timestamps[i] = Util.getTimestamp(dates[i]); + } + validate(); + } + + private void validate() { + boolean ok = true; + if (timestamps.length != values.length || timestamps.length < 2) { + ok = false; + } + for (int i = 0; i < timestamps.length - 1 && ok; i++) { + if (timestamps[i] >= timestamps[i + 1]) { + ok = false; + } + } + if (!ok) { + throw new IllegalArgumentException("Invalid plottable data supplied"); + } + } + + /** + * <p>Sets interpolation method to be used. Suppose that we have two timestamp/value pairs:<br> + * <code>(t, 100)</code> and <code>(t + 100, 300)</code>. Here are the results interpolator + * returns for t + 50 seconds, for various <code>interpolationMethods</code>:</p> + * + * <ul> + * <li><code>INTERPOLATE_LEFT: 100</code> + * <li><code>INTERPOLATE_RIGHT: 300</code> + * <li><code>INTERPOLATE_LINEAR: 200</code> + * </ul> + * <p>If not set, interpolation method defaults to <code>INTERPOLATE_LINEAR</code>.</p> + * + * <p>The fourth available interpolation method is INTERPOLATE_REGRESSION. This method uses + * simple linear regression to interpolate supplied data with a simple straight line which does not + * necessarily pass through all data points. The slope of the best-fit line will be chosen so that the + * total square distance of real data points from from the best-fit line is at minimum.</p> + * + * <p>This method is deprecated, one should use {@link #setInterpolationMethod(Method) setInterpolationMethod()} instead.</p> + * + * <p>The full explanation of this interpolation method can be found + * <a href="http://www.JerryDallal.com/LHSP/slr.htm">here</a>.</p> + * + * @param interpolationMethod Should be <code>INTERPOLATE_LEFT</code>, + * <code>INTERPOLATE_RIGHT</code>, <code>INTERPOLATE_LINEAR</code> or + * <code>INTERPOLATE_REGRESSION</code>. Any other value will be interpreted as + * INTERPOLATE_LINEAR (default). + * @deprecated uses {@link #setInterpolationMethod(Method)} instead. + */ + @Deprecated + public void setInterpolationMethod(int interpolationMethod) { + if (interpolationMethod >= Method.values().length || interpolationMethod < 0) { + setInterpolationMethod(Method.LINEAR); + } else { + setInterpolationMethod(Method.values()[interpolationMethod]); + } + } + + /** + * <p>Sets interpolation method to be used. Suppose that we have two timestamp/value pairs:<br> + * <code>(t, 100)</code> and <code>(t + 100, 300)</code>. Here are the results interpolator + * returns for t + 50 seconds, for various <code>interpolationMethods</code>:</p> + * + * <ul> + * <li><code>LEFT: 100</code> + * <li><code>RIGHT: 300</code> + * <li><code>LINEAR: 200</code> + * </ul> + * <p>If not set, interpolation method defaults to <code>INTERPOLATE_LINEAR</code>.</p> + * + * <p>The fourth available interpolation method is REGRESSION. This method uses + * simple linear regression to interpolate supplied data with a simple straight line which does not + * necessarily pass through all data points. The slope of the best-fit line will be chosen so that the + * total square distance of real data points from from the best-fit line is at minimum.</p> + * + * <p>The full explanation of this interpolation method can be found + * <a href="http://www.JerryDallal.com/LHSP/slr.htm">here</a>.</p> + * + * @param interpolationMethod a method from {@link org.rrd4j.data.LinearInterpolator.Method}. + */ + public void setInterpolationMethod(Method interpolationMethod) { + if (interpolationMethod == Method.REGRESSION) { + calculateBestFitLine(); + } + this.interpolationMethod = interpolationMethod; + } + + private void calculateBestFitLine() { + int count = timestamps.length; + int validCount = 0; + double ts = 0.0; + double vs = 0.0; + + for (int i = 0; i < count; i++) { + if (!Double.isNaN(values[i])) { + ts += timestamps[i]; + vs += values[i]; + validCount++; + } + } + if (validCount <= 1) { + // just one not-NaN point + b0 = b1 = Double.NaN; + return; + } else { + ts /= validCount; + vs /= validCount; + } + double s1 = 0; + double s2 = 0; + for (int i = 0; i < count; i++) { + if (!Double.isNaN(values[i])) { + double dt = timestamps[i] - ts; + double dv = values[i] - vs; + s1 += dt * dv; + s2 += dt * dt; + } + } + b1 = s2 != 0 ? s1 / s2 : Double.NaN; + b0 = vs - b1 * ts; + } + + /** + * {@inheritDoc} + * + * Method overridden from the base class. This method will be called by the framework. Call + * this method only if you need interpolated values in your code. + */ + @Override + public double getValue(long timestamp) { + if (interpolationMethod == Method.REGRESSION) { + return b0 + b1 * timestamp; + } + int count = timestamps.length; + // check if out of range + if (timestamp < timestamps[0] || timestamp > timestamps[count - 1]) { + return Double.NaN; + } + // find matching segment + int startIndex = lastIndexUsed; + if (timestamp < timestamps[lastIndexUsed]) { + // backward reading, shift to the first timestamp + startIndex = 0; + } + for (int i = startIndex; i < count; i++) { + if (timestamps[i] == timestamp) { + return values[i]; + } + if (i < count - 1 && timestamps[i] < timestamp && timestamp < timestamps[i + 1]) { + // matching segment found + lastIndexUsed = i; + switch (interpolationMethod) { + case LEFT: + return values[i]; + case RIGHT: + return values[i + 1]; + case LINEAR: + double slope = (values[i + 1] - values[i]) / + (timestamps[i + 1] - timestamps[i]); + return values[i] + slope * (timestamp - timestamps[i]); + default: + return Double.NaN; + } + } + } + // should not be here ever, but let's satisfy the compiler + return Double.NaN; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/NonRrdSource.java b/apps/jrobin/java/src/org/rrd4j/data/NonRrdSource.java new file mode 100644 index 0000000000000000000000000000000000000000..9b61636a0303d59d054c935404f05262553b0bc4 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/NonRrdSource.java @@ -0,0 +1,12 @@ +package org.rrd4j.data; + +interface NonRrdSource { + /** + * <p>calculate.</p> + * + * @param tStart a long. + * @param tEnd a long. + * @param dataProcessor a {@link org.rrd4j.data.DataProcessor} object. + */ + void calculate(long tStart, long tEnd, DataProcessor dataProcessor); +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/Normalizer.java b/apps/jrobin/java/src/org/rrd4j/data/Normalizer.java new file mode 100644 index 0000000000000000000000000000000000000000..4ed014faa1e6234ad35f3c9f851660fda4104322 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/Normalizer.java @@ -0,0 +1,67 @@ +package org.rrd4j.data; + +import org.rrd4j.core.Util; + +import java.util.Arrays; + +class Normalizer { + private final long[] timestamps; + final int count; + final long step; + + Normalizer(long[] timestamps) { + this.timestamps = timestamps; + this.step = timestamps[1] - timestamps[0]; + this.count = timestamps.length; + } + + double[] normalize(long[] rawTimestamps, double[] rawValues) { + int rawCount = rawTimestamps.length; + long rawStep = rawTimestamps[1] - rawTimestamps[0]; + // check if we have a simple match + if (rawCount == count && rawStep == step && rawTimestamps[0] == timestamps[0]) { + return getCopyOf(rawValues); + } + // reset all normalized values to NaN + double[] values = new double[count]; + Arrays.fill(values, Double.NaN); + double[] weights = new double[count]; + Arrays.fill(weights, Double.NaN); + for (int rawSeg = 0, seg = 0; rawSeg < rawCount && seg < count; rawSeg++) { + double rawValue = rawValues[rawSeg]; + if (!Double.isNaN(rawValue)) { + long rawLeft = rawTimestamps[rawSeg] - rawStep; + while (seg < count && rawLeft >= timestamps[seg]) { + seg++; + } + boolean overlap = true; + for (int fillSeg = seg; overlap && fillSeg < count; fillSeg++) { + long left = timestamps[fillSeg] - step; + long t1 = Math.max(rawLeft, left); + long t2 = Math.min(rawTimestamps[rawSeg], timestamps[fillSeg]); + if (t1 < t2) { + values[fillSeg] = Util.sum(values[fillSeg], (t2 - t1) * rawValues[rawSeg]); + weights[fillSeg] = Util.sum(weights[fillSeg], (double)(t2 - t1)); + } + else { + overlap = false; + } + } + } + } + for (int seg = 0; seg < count; seg++) { + if (!Double.isNaN(weights[seg])) { + values[seg] /= weights[seg]; + } + } + return values; + } + + private static double[] getCopyOf(double[] rawValues) { + int n = rawValues.length; + double[] values = new double[n]; + System.arraycopy(rawValues, 0, values, 0, n); + return values; + } +} + diff --git a/apps/jrobin/java/src/org/rrd4j/data/PDef.java b/apps/jrobin/java/src/org/rrd4j/data/PDef.java new file mode 100644 index 0000000000000000000000000000000000000000..cc215b22055ca298858f8ca7792587d378b334fd --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/PDef.java @@ -0,0 +1,20 @@ +package org.rrd4j.data; + +class PDef extends Source implements NonRrdSource { + private final Plottable plottable; + + PDef(String name, Plottable plottable) { + super(name); + this.plottable = plottable; + } + + /** {@inheritDoc} */ + public void calculate(long tStart, long tEnd, DataProcessor dataProcessor) { + long[] times = getTimestamps(); + double[] vals = new double[times.length]; + for (int i = 0; i < times.length; i++) { + vals[i] = plottable.getValue(times[i]); + } + setValues(vals); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/Plottable.java b/apps/jrobin/java/src/org/rrd4j/data/Plottable.java new file mode 100644 index 0000000000000000000000000000000000000000..f8fb3a9c6cf7d930dbda13a4ce4dc3e86cc9f680 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/Plottable.java @@ -0,0 +1,20 @@ +package org.rrd4j.data; + +/** + * Abstract class 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> + */ +public abstract class Plottable { + /** + * 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) { + return Double.NaN; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/RpnCalculator.java b/apps/jrobin/java/src/org/rrd4j/data/RpnCalculator.java new file mode 100644 index 0000000000000000000000000000000000000000..24946c9c68314e99a5af26c60dc252beedd72186 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/RpnCalculator.java @@ -0,0 +1,837 @@ +package org.rrd4j.data; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.List; +import java.util.TimeZone; + +import org.rrd4j.core.Util; + +import com.tomgibara.crinch.hashing.PerfectStringHash; + +class RpnCalculator { + private enum Token_Symbol { + TKN_VAR("") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(s.token.values[s.slot]); + s.token_rpi = s.rpi; + } + }, + TKN_NUM("") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(s.token.number); + } + }, + + // Arithmetics + TKN_PLUS("+") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.pop() + c.pop()); + } + }, + TKN_ADDNAN("ADDNAN") { + @Override + void do_method(RpnCalculator c, State s) { + double x1 = c.pop(); + double x2 = c.pop(); + c.push(Double.isNaN(x1) ? x2 : (Double.isNaN(x2) ? x1 : x1 + x2)); + } + }, + TKN_MINUS("-") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 - x2); + } + }, + TKN_MULT("*") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.pop() * c.pop()); + } + }, + TKN_DIV("/") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 / x2); + } + }, + TKN_MOD("%") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 % x2); + } + }, + + TKN_SIN("SIN") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.sin(c.pop())); + } + }, + TKN_COS("COS") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.cos(c.pop())); + } + }, + TKN_LOG("LOG") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.log(c.pop())); + } + }, + TKN_EXP("EXP") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.exp(c.pop())); + } + }, + TKN_SQRT("SQRT") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.sqrt(c.pop())); + } + }, + TKN_ATAN("ATAN") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.atan(c.pop())); + } + }, + TKN_ATAN2("ATAN2") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(Math.atan2(x1, x2)); + } + }, + + TKN_FLOOR("FLOOR") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.floor(c.pop())); + } + }, + TKN_CEIL("CEIL") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.ceil(c.pop())); + } + }, + + TKN_DEG2RAD("DEG2RAD") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.toRadians(c.pop())); + } + }, + TKN_RAD2DEG("RAD2DEG") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.toDegrees(c.pop())); + } + }, + TKN_ROUND("ROUND") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.round(c.pop())); + } + }, + TKN_POW("POW") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(Math.pow(x1, x2)); + } + }, + TKN_ABS("ABS") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.abs(c.pop())); + } + }, + TKN_RANDOM("RANDOM") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.random()); + } + }, + TKN_RND("RND") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.floor(c.pop() * Math.random())); + } + }, + + // Boolean operators + TKN_UN("UN") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Double.isNaN(c.pop()) ? 1 : 0); + } + }, + TKN_ISINF("ISINF") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Double.isInfinite(c.pop()) ? 1 : 0); + } + }, + TKN_LT("LT") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 < x2 ? 1 : 0); + } + }, + TKN_LE("LE") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 <= x2 ? 1 : 0); + } + }, + TKN_GT("GT") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 > x2 ? 1 : 0); + } + }, + TKN_GE("GE") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 >= x2 ? 1 : 0); + } + }, + TKN_EQ("EQ") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 == x2 ? 1 : 0); + } + }, + TKN_NE("NE") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 != x2 ? 1 : 0); + } + }, + TKN_IF("IF") { + @Override + void do_method(RpnCalculator c, State s) { + double x3 = c.pop(); + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 != 0 ? x2 : x3); + } + }, + + // Comparing values + TKN_MIN("MIN") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.min(c.pop(), c.pop())); + } + }, + TKN_MAX("MAX") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.max(c.pop(), c.pop())); + } + }, + TKN_MINNAN("MINNAN") { + @Override + void do_method(RpnCalculator c, State s) { + double x1 = c.pop(); + double x2 = c.pop(); + c.push(Double.isNaN(x1) ? x2 : (Double.isNaN(x2) ? x1 : Math.min(x1, x2))); + } + }, + TKN_MAXNAN("MAXNAN") { + @Override + void do_method(RpnCalculator c, State s) { + double x1 = c.pop(); + double x2 = c.pop(); + c.push(Double.isNaN(x1) ? x2 : (Double.isNaN(x2) ? x1 : Math.max(x1, x2))); + } + }, + TKN_LIMIT("LIMIT") { + @Override + void do_method(RpnCalculator c, State s) { + double x3 = c.pop(); + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x1 < x2 || x1 > x3 ? Double.NaN : x1); + } + }, + + // Processing the stack directly + TKN_DUP("DUP") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.peek()); + } + }, + TKN_EXC("EXC") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(x2); + c.push(x1); + } + }, + TKN_POP("POP") { + @Override + void do_method(RpnCalculator c, State s) { + c.pop(); + } + }, + + // Special values + TKN_UNKN("UNKN") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Double.NaN); + } + }, + TKN_PI("PI") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.PI); + } + }, + TKN_E("E") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Math.E); + } + }, + TKN_INF("INF") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Double.POSITIVE_INFINITY); + } + }, + TKN_NEGINF("NEGINF") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Double.NEGATIVE_INFINITY); + } + }, + + // Logical operator + TKN_AND("AND") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push((x1 != 0 && x2 != 0) ? 1 : 0); + } + }, + TKN_OR("OR") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push((x1 != 0 || x2 != 0) ? 1 : 0); + } + }, + TKN_XOR("XOR") { + @Override + void do_method(RpnCalculator c, State s) { + double x2 = c.pop(); + double x1 = c.pop(); + c.push(((x1 != 0 && x2 == 0) || (x1 == 0 && x2 != 0)) ? 1 : 0); + } + }, + + TKN_PREV("PREV") { + @Override + void do_method(RpnCalculator c, State s) { + c.push((s.slot == 0) ? Double.NaN : s.token.values[s.slot - 1]); + } + }, + + //Time and date operator + TKN_STEP("STEP") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.timeStep); + } + }, + TKN_NOW("NOW") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(Util.getTime()); + } + }, + TKN_TIME("TIME") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.timestamps[s.slot]); + } + }, + TKN_LTIME("LTIME") { + @Override + void do_method(RpnCalculator c, State s) { + TimeZone tz = s.getTimeZone(); + c.push((double)(c.timestamps[s.slot] + ((long) tz.getOffset(c.timestamps[s.slot]) / 1000D))); + } + }, + TKN_YEAR("YEAR") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.getCalendarField(c.pop(), Calendar.YEAR)); + } + }, + TKN_MONTH("MONTH") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.getCalendarField(c.pop(), Calendar.MONTH) + 1); + } + }, + TKN_DATE("DATE") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.getCalendarField(c.pop(), Calendar.DAY_OF_MONTH)); + } + }, + TKN_HOUR("HOUR") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.getCalendarField(c.pop(), Calendar.HOUR_OF_DAY)); + } + }, + TKN_MINUTE("MINUTE") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.getCalendarField(c.pop(), Calendar.MINUTE)); + } + }, + TKN_SECOND("SECOND") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.getCalendarField(c.pop(), Calendar.SECOND)); + } + }, + TKN_WEEK("WEEK") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(c.getCalendarField(c.pop(), Calendar.WEEK_OF_YEAR)); + } + }, + TKN_SIGN("SIGN") { + @Override + void do_method(RpnCalculator c, State s) { + double x1 = c.pop(); + c.push(Double.isNaN(x1) ? Double.NaN : x1 > 0 ? +1 : x1 < 0 ? -1 : 0); + } + }, + TKN_SORT("SORT") { + @Override + void do_method(RpnCalculator c, State s) { + int n = (int) c.pop(); + double[] array = new double[n]; + for(int i = 0; i < n; i++) { + array[i] = c.pop(); + } + Arrays.sort(array); + for (int i = 0; i < n; i++) { + c.push(array[i]); + } + } + }, + TKN_REV("REV") { + @Override + void do_method(RpnCalculator c, State s) { + int n = (int) c.pop(); + double[] array = new double[n]; + for(int i = 0; i < n; i++) { + array[i] = c.pop(); + } + for (int i = 0; i < n; i++) { + c.push(array[i]); + } + } + }, + TKN_AVG("AVG"){ + @Override + void do_method(RpnCalculator c, State s) { + int count = 0; + int n = (int) c.pop(); + double sum = 0.0; + while (n > 0) { + double x1 = c.pop(); + n--; + + if (Double.isNaN(x1)) { + continue; + } + sum += x1; + count++; + } + if (count > 0) { + c.push(sum / count); + } else { + c.push(Double.NaN); + } + } + }, + TKN_COUNT("COUNT") { + @Override + void do_method(RpnCalculator c, State s) { + c.push(s.slot + 1.0); + } + }, + TKN_TREND("TREND") { + @Override + void do_method(RpnCalculator c, State s) { + int dur = (int) c.pop(); + c.pop(); + /* + * OK, so to match the output from rrdtool, we have to go *forward* 2 timeperiods. + * So at t[59] we use the average of t[1]..t[61] + * + */ + + if ((s.slot+1) < Math.ceil(dur / c.timeStep)) { + c.push(Double.NaN); + } else { + double[] vals = c.dataProcessor.getValues(c.tokens[s.token_rpi].variable); + boolean ignorenan = s.token.id == TKN_TRENDNAN; + double accum = 0.0; + int count = 0; + + int start = (int) (Math.ceil(dur / c.timeStep)); + int row = 2; + while ((s.slot + row) > vals.length) { + row --; + } + + for(; start > 0; start--) { + double val = vals[s.slot + row - start]; + if (ignorenan || !Double.isNaN(val)) { + accum = Util.sum(accum, val); + ++count; + } + } + c.push((count == 0) ? Double.NaN : (accum / count)); + } + } + }, + TKN_TRENDNAN("TRENDNAN") { + @Override + void do_method(RpnCalculator c, State s) { + TKN_TREND.do_method(c, s); + } + }, + TKN_PREDICT("PREDICT") { + @Override + void do_method(RpnCalculator c, State s) { + c.pop(); // Clear the value of our variable + + /* the local averaging window (similar to trend, but better here, as we get better statistics thru numbers)*/ + int locstepsize = (int) c.pop(); + /* the number of shifts and range-checking*/ + int num_shifts = (int) c.pop(); + double[] multipliers; + + // handle negative shifts special + if (num_shifts < 0) { + multipliers = new double[1]; + multipliers[0] = c.pop(); + } else { + multipliers = new double[num_shifts]; + for(int i = 0; i < num_shifts; i++) { + multipliers[i] = c.pop(); + } + } + + /* the real calculation */ + double val = Double.NaN; + + /* the info on the datasource */ + double[] vals = c.dataProcessor.getValues(c.tokens[s.rpi-1].variable); + + int locstep = (int) Math.ceil((float) locstepsize / (float) c.timeStep); + + /* the sums */ + double sum = 0; + double sum2 = 0; + int count = 0; + + /* now loop for each position */ + int doshifts = Math.abs(num_shifts); + for (int loop = 0; loop < doshifts; loop++) { + /* calculate shift step */ + int shiftstep; + if (num_shifts < 0) { + shiftstep = loop * (int) multipliers[0]; + } else { + shiftstep = (int) multipliers[loop]; + } + if (shiftstep < 0) { + throw new RuntimeException("negative shift step not allowed: " + shiftstep); + } + shiftstep = (int) Math.ceil((float) shiftstep / (float) c.timeStep); + /* loop all local shifts */ + for (int i = 0; i <= locstep; i++) { + int offset = shiftstep + i; + if ((offset >= 0) && (offset < s.slot)) { + /* get the value */ + val = vals[s.slot - offset]; + + /* and handle the non NAN case only*/ + if (!Double.isNaN(val)) { + sum = Util.sum(sum, val); + sum2 = Util.sum(sum2, val * val); + count++; + } + } + } + } + /* do the final calculations */ + val = Double.NaN; + if (s.token.id == TKN_PREDICT) { /* the average */ + if (count > 0) { + val = sum / (double) count; + } + } else { + if (count > 1) { /* the sigma case */ + val = count * sum2 - sum * sum; + if (val < 0) { + val = Double.NaN; + } else { + val = Math.sqrt(val / (count * (count - 1.0))); + } + } + } + c.push(val); + } + + }, + TKN_PREDICTSIGMA("PREDICTSIGMA") { + @Override + void do_method(RpnCalculator c, State s) { + TKN_PREDICT.do_method(c, s); + } + }; + + public final String token_string; + Token_Symbol(String token_string) { + this.token_string = token_string; + } + abstract void do_method(RpnCalculator c, State s); + } + + private static final Token_Symbol[] symbols; + private static final PerfectStringHash perfect; + static + { + List<String> tokenStrings = new ArrayList<String>(Token_Symbol.values().length); + for(Token_Symbol s: Token_Symbol.values()) { + if(! s.token_string.isEmpty()) { + tokenStrings.add(s.token_string); + } + } + + String[] array = tokenStrings.toArray(new String[tokenStrings.size()]); + perfect = new PerfectStringHash(array); + symbols = new Token_Symbol[tokenStrings.size()]; + for(Token_Symbol s: Token_Symbol.values()) { + int hash = perfect.hashAsInt(s.token_string); + if(hash >= 0) { + symbols[hash] = s; + } + } + } + + private final String rpnExpression; + private final String sourceName; + private final DataProcessor dataProcessor; + + private final Token[] tokens; + private final RpnStack stack = new RpnStack(); + private final double[] calculatedValues; + private final long[] timestamps; + private final double timeStep; + private final List<String> sourcesNames; + + RpnCalculator(String rpnExpression, String sourceName, DataProcessor dataProcessor) { + this.rpnExpression = rpnExpression; + this.sourceName = sourceName; + this.dataProcessor = dataProcessor; + this.timestamps = dataProcessor.getTimestamps(); + this.timeStep = (double)(timestamps[1] - timestamps[0]); + this.calculatedValues = new double[timestamps.length]; + this.sourcesNames = Arrays.asList(dataProcessor.getSourceNames()); + String[] tokensString = rpnExpression.split(" *, *"); + tokens = new Token[tokensString.length]; + for (int i = 0; i < tokensString.length; i++) { + tokens[i] = createToken(tokensString[i].trim()); + } + } + + private Token createToken(String parsedText) { + Token token; + int hash = perfect.hashAsInt(parsedText); + if (hash >= 0 ){ + token = new Token(symbols[hash]); + } + else if (parsedText.equals("PREV")) { + token = new Token(Token_Symbol.TKN_PREV, sourceName, calculatedValues); + } + else if (parsedText.startsWith("PREV(") && parsedText.endsWith(")")) { + String variable = parsedText.substring(5, parsedText.length() - 1); + token = new Token(Token_Symbol.TKN_PREV, variable, dataProcessor.getValues(variable)); + } + else if (Util.isDouble(parsedText)) { + token = new Token(Token_Symbol.TKN_NUM, Util.parseDouble(parsedText)); + } + else if (sourcesNames.contains(parsedText)){ + token = new Token(Token_Symbol.TKN_VAR, parsedText, dataProcessor.getValues(parsedText)); + } + else { + throw new IllegalArgumentException("Unexpected RPN token encountered: " + parsedText); + } + return token; + } + + double[] calculateValues() { + State s = new State(); + for (int slot = 0; slot < timestamps.length; slot++) { + resetStack(); + s.rpi = 0; + s.token_rpi = -1; + for (Token token: tokens) { + s.token = token; + s.slot = slot; + token.id.do_method(this, s); + s.rpi++; + } + calculatedValues[slot] = pop(); + // check if stack is empty only on the first try + if (slot == 0 && !isStackEmpty()) { + throw new IllegalArgumentException("Stack not empty at the end of calculation. " + + "Probably bad RPN expression [" + rpnExpression + "]"); + } + } + return calculatedValues; + } + + private double getCalendarField(double timestamp, int field) { + Calendar calendar = Util.getCalendar((long) (timestamp)); + return calendar.get(field); + } + + private void push(final double x) { + stack.push(x); + } + + private double pop() { + return stack.pop(); + } + + private double peek() { + return stack.peek(); + } + + private void resetStack() { + stack.reset(); + } + + private boolean isStackEmpty() { + return stack.isEmpty(); + } + + private static final class RpnStack { + private static final int MAX_STACK_SIZE = 1000; + private double[] stack = new double[MAX_STACK_SIZE]; + private int pos = 0; + + void push(double x) { + if (pos >= MAX_STACK_SIZE) { + throw new IllegalArgumentException("PUSH failed, RPN stack full [" + MAX_STACK_SIZE + "]"); + } + stack[pos++] = x; + } + + double pop() { + if (pos <= 0) { + throw new IllegalArgumentException("POP failed, RPN stack is empty"); + } + return stack[--pos]; + } + + double peek() { + if (pos <= 0) { + throw new IllegalArgumentException("PEEK failed, RPN stack is empty"); + } + return stack[pos - 1]; + } + + void reset() { + pos = 0; + } + + boolean isEmpty() { + return pos <= 0; + } + } + + private final class State { + private int token_rpi; + private int rpi; + Token token; + int slot; + TimeZone getTimeZone() { + return RpnCalculator.this.dataProcessor.getTimeZone(); + } + } + + private static final class Token { + final Token_Symbol id; + final double number; + final String variable; + final double[] values; + Token(Token_Symbol id) { + this.id = id; + this.values = null; + this.variable = ""; + this.number = Double.NaN; + } + Token(Token_Symbol id, String variable, double[] values) { + this.id = id; + this.variable = variable; + this.values = values; + this.number = Double.NaN; + } + Token(Token_Symbol id, double number) { + this.id = id; + this.values = null; + this.variable = ""; + this.number = number; + } + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/Source.java b/apps/jrobin/java/src/org/rrd4j/data/Source.java new file mode 100644 index 0000000000000000000000000000000000000000..6a79c6c5c00d54d80c08eb6be2ab5bbb94374c82 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/Source.java @@ -0,0 +1,59 @@ +package org.rrd4j.data; + +abstract class Source { + private final String name; + + protected double[] values; + protected long[] timestamps; + + Source(String name) { + this.name = name; + } + + String getName() { + return name; + } + + void setValues(double[] values) { + this.values = values; + } + + void setTimestamps(long[] timestamps) { + this.timestamps = timestamps; + } + + double[] getValues() { + return values; + } + + long[] getTimestamps() { + return timestamps; + } + + /** + * @param tStart + * @param tEnd + * @return + * @deprecated This method is deprecated. Uses instance of {@link org.rrd4j.data.Variable}, used with {@link org.rrd4j.data.DataProcessor.addDatasource(String, String, Variable)} + */ + @Deprecated + Aggregates getAggregates(long tStart, long tEnd) { + Aggregator agg = new Aggregator(timestamps, values); + return agg.getAggregates(tStart, tEnd); + } + + /** + * @param tStart + * @param tEnd + * @param percentile + * @return + * @deprecated This method is deprecated. Uses instance of {@link org.rrd4j.data.Variable.PERCENTILE}, used with {@link org.rrd4j.data.DataProcessor.addDatasource(String, String, Variable)} + */ + @Deprecated + double getPercentile(long tStart, long tEnd, double percentile) { + Variable vpercent = new Variable.PERCENTILE((float) percentile); + vpercent.calculate(this, tStart, tEnd); + return vpercent.getValue().value; + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/VDef.java b/apps/jrobin/java/src/org/rrd4j/data/VDef.java new file mode 100644 index 0000000000000000000000000000000000000000..5a5632999922443508f56580f4acf1a6e78ae956 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/VDef.java @@ -0,0 +1,41 @@ +package org.rrd4j.data; + +import java.util.Arrays; + +class VDef extends Source implements NonRrdSource { + private final String defName; + private final Variable var; + + VDef(String name, String defName, Variable aggr) { + super(name); + this.defName = defName; + this.var = aggr; + } + + String getDefName() { + return defName; + } + + /** {@inheritDoc} */ + public void calculate(long tStart, long tEnd, DataProcessor dataProcessor) { + String defName = getDefName(); + Source source = dataProcessor.getSource(defName); + var.calculate(source, tStart, tEnd); + } + + public Variable.Value getValue() { + return var.getValue(); + } + + /* (non-Javadoc) + * @see org.rrd4j.data.Source#getValues() + */ + @Override + double[] getValues() { + int count = getTimestamps().length; + double[] values = new double[count]; + Arrays.fill(values, var.getValue().value); + return values; + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/Variable.java b/apps/jrobin/java/src/org/rrd4j/data/Variable.java new file mode 100644 index 0000000000000000000000000000000000000000..2668032cfc5bd6a919efee5489c3c17931d7525b --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/Variable.java @@ -0,0 +1,506 @@ +package org.rrd4j.data; + +import java.io.Serializable; +import java.util.Comparator; +import java.util.SortedSet; +import java.util.TreeSet; + +import org.rrd4j.core.Util; + +/** + * An abstract class to help extract single value from a set of value (VDEF in rrdtool) + * + * It can be used to add new fancy statistical calculation with rrd values + * + */ +public abstract class Variable { + + /** + * This class store both the value and the time stamp + * It will be used by graph rendering legend + */ + public static final class Value { + public final double value; + public final long timestamp; + Value(long timestamp, double value) { + this.value = value; + this.timestamp = timestamp; + } + }; + + public static final Value INVALIDVALUE = new Value(0, Double.NaN); + + private Value val = null; + + /** + * Used to calculate the needed value from a source, this method call fill. + * @param s + * @param start + * @param end + */ + void calculate(Source s, long start, long end) { + long step = s.timestamps[1] - s.timestamps[0]; + int first = -1; + 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) { + long leftdown = Math.max(s.timestamps[i] - step, start); + long rightdown = Math.min(s.timestamps[i], end); + if(rightdown > leftdown) { + first = i; + } + } + + if(last == -1) { + long leftup = Math.max(s.timestamps[j] - step, start); + long rightup = Math.min(s.timestamps[j], end); + if(rightup > leftup ) { + last = j; + } + } + } + if( first == -1 || last == -1) { + throw new RuntimeException("Invalid range"); + } + 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) { + val = v; + } + else { + if(v.timestamp < end && v.timestamp > start) { + val = v; + } + else { + val = new Value(0, Double.NaN); + } + } + } + else { + long[] timestamps = new long[ last - first + 1]; + System.arraycopy(s.timestamps, first, timestamps, 0, timestamps.length); + double[] values = new double[ last - first + 1]; + System.arraycopy(s.getValues(), first, values, 0, values.length); + val = fill(timestamps, values, start, end); + } + } + + public Value getValue() { + assert val != null : "Used before calculation"; + return val; + } + + /** + * This method is call with the needed values, extracted from the datasource to do the calculation. + * + * Value is to be filled with both the double value and a possible timestamp, when it's used to find + * a specific point + * + * @param timestamps the timestamps for the value + * @param values the actual values + * @param start the start of the period + * @param end the end of the period + * @return a filled Value object + */ + protected abstract Value fill(long timestamps[], double[] values, long start, long end); + + /** + * Find the first valid data point and it's timestamp + * + */ + 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])) { + return new Value(timestamps[i], values[i]); + } + } + return new Value(0, Double.NaN); + } + } + + /** + * Find the first last valid point and it's timestamp + * + */ + 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]) ) { + return new Value(timestamps[i], values[i]); + } + } + return new Value(0, Double.NaN); + } + } + + /** + * The smallest of the data points and it's time stamp (the first one) is stored. + * + */ + public static class MIN extends Variable { + @Override + 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)) { + timestamp = timestamps[i]; + value = values[i]; + } else if( ! Double.isNaN(values[i]) && value > values[i]) { + timestamp = timestamps[i]; + value = values[i]; + } + } + return new Value(timestamp, value); + } + } + + /** + * The biggest of the data points and it's time stamp (the first one) is stored. + * + */ + public static class MAX extends Variable { + @Override + 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)) { + timestamp = timestamps[i]; + value = values[i]; + } else if(!Double.isNaN(values[i]) && value < values[i]) { + timestamp = timestamps[i]; + value = values[i]; + } + } + return new Value(timestamp, value); + } + } + + /** + * Calculate the sum of the data points. + * + */ + public static class TOTAL extends Variable { + @Override + protected Value fill(long[] timestamps, double[] values, long start, long end) { + double value = Double.NaN; + + for(double tempVal: values) { + value = Util.sum(value, tempVal); + } + return new Value(0, value * (timestamps[1] - timestamps[0]) ); + } + } + + /** + * Calculate the average of the data points. + * + */ + public static class AVERAGE extends Variable { + @Override + protected Value fill(long[] timestamps, double[] values, long start, long end) { + double value = 0; + int count = 0; + for (int i = values.length - 1 ; i >= 0 ; i--) { + if ( !Double.isNaN(values[i]) ) { + count++; + value = Double.isNaN(value) ? values[i] : values[i] + value; + } + } + if (! Double.isNaN(value) && count > 0) { + value = value / count; + } + else { + value = Double.NaN; + } + return new Value(0, value); + } + } + + /** + * Calculate the standard deviation for the data point. + * + */ + public static class STDDEV extends Variable { + @Override + protected Value fill(long[] timestamps, double[] values, long start, long end) { + double value = Double.NaN; + int count = 0; + 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)) + continue; + count++; + if(count == 1) { + M = cursVal; + S = 0; + } + else { + double dM = cursVal - M; + M += dM/count; + S += dM * (cursVal - M); + } + } + if(count > 1) { + value = Math.sqrt( S/(count - 1) ); + } + return new Value(0, value); + } + } + + /** + * Store all the informations about a datasource point, for predictive and consistent sorting + * + */ + static final class PercentElem { + long timestamp; + double value; + + PercentElem(int pos, long timestamp, double value) { + this.timestamp = timestamp; + this.value = value; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + PercentElem other = (PercentElem) obj; + if (timestamp != other.timestamp) + return false; + return true; + } + + @Override + public int hashCode() { + return Long.valueOf(timestamp).hashCode(); + } + + @Override + public String toString() { + return String.format("[%d, %f]", timestamp, value); + } + } + + /** + * The sort used by rrdtool for percent, where NaN < -INF < finite values < INF + * + */ + 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)) + return Long.signum(arg0.timestamp - arg1.timestamp); + else if(Double.isNaN(arg0.value)) + return -1; + else if (Double.isNaN(arg1.value)) + return +1; + else { + int compared = Double.compare(arg0.value, arg1.value); + if (compared == 0) { + compared = Long.signum(arg0.timestamp - arg1.timestamp); + } + return compared; + } + } + } + + /** + * Find the point at the n-th percentile. + * + */ + public static class PERCENTILE extends Variable { + private final float percentile; + private final boolean withNaN; + + protected PERCENTILE(float percentile, boolean withNaN) { + this.percentile = percentile; + this.withNaN = withNaN; + } + + public PERCENTILE(double percentile) { + this((float) percentile, true); + } + + public PERCENTILE(float percentile) { + this(percentile, true); + } + + @Override + 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++) { + valuesSet.add(new PercentElem(i, timestamps[i], values[i])); + } + + //If not with nan, just drop all nan (inferior to min value) + if( ! withNaN) { + valuesSet = valuesSet.tailSet(new PercentElem(0, 0, Double.NEGATIVE_INFINITY )); + } + + PercentElem[] element = (PercentElem[]) valuesSet.toArray(new PercentElem[valuesSet.size()]); + int pos = Math.round(percentile * (element.length - 1) / 100); + // if we have anything left... + if (pos >= 0) { + double value = element[pos].value; + long timestamp = element[pos].timestamp; + return new Value(timestamp, value); + } + return new Value(0, Double.NaN); + } + } + + public static class PERCENTILENAN extends PERCENTILE { + + public PERCENTILENAN(float percentile) { + super(percentile, false); + } + + public PERCENTILENAN(double percentile) { + super((float)percentile, false); + } + } + + /** + * Calculate the slop of the least squares line. + * + */ + public static class LSLSLOPE extends Variable { + + @Override + protected Value fill(long[] timestamps, double[] values, long start, long end) { + int cnt = 0; + int lslstep = 0; + double SUMx = 0.0; + double SUMy = 0.0; + double SUMxy = 0.0; + double SUMxx = 0.0; + double lslslope; + + for (int i = 0; i < values.length; i++) { + double value = values[i]; + + if (!Double.isNaN(value)) { + cnt++; + + SUMx += lslstep; + SUMxx += lslstep * lslstep; + SUMy += value; + SUMxy += lslstep * value; + + } + lslstep++; + } + double divisor = (SUMx * SUMx - cnt * SUMxx); + if (divisor != 0) { + /* Bestfit line by linear least squares method */ + lslslope = (SUMx * SUMy - cnt * SUMxy) / divisor; + return new Value(0, lslslope); + } else { + return new Value(0, Double.NaN); + } + } + + } + + /** + * Calculate the y-intercept of the least squares line. + * + */ + public static class LSLINT extends Variable { + + @Override + protected Value fill(long[] timestamps, double[] values, long start, long end) { + int cnt = 0; + int lslstep = 0; + double SUMx = 0.0; + double SUMy = 0.0; + double SUMxy = 0.0; + double SUMxx = 0.0; + double lslslope; + double lslint; + + for(int i = 0; i < values.length; i++) { + double value = values[i]; + + if (!Double.isNaN(value)) { + cnt++; + + SUMx += lslstep; + SUMxx += lslstep * lslstep; + SUMy += value; + SUMxy += lslstep * value; + } + lslstep++; + } + double divisor = (SUMx * SUMx - cnt * SUMxx); + if(cnt > 0 && divisor != 0) { + /* Bestfit line by linear least squares method */ + lslslope = (SUMx * SUMy - cnt * SUMxy) / divisor; + lslint = (SUMy - lslslope * SUMx) / cnt; + return new Value(0, lslint); + } else { + return new Value(0, Double.NaN); + } + } + + } + + /** + * Calculate the correlation coefficient of the least squares line. + * + */ + public static class LSLCORREL extends Variable { + + @Override + protected Value fill(long[] timestamps, double[] values, long start, long end) { + int cnt = 0; + int lslstep = 0; + double SUMx = 0.0; + double SUMy = 0.0; + double SUMxy = 0.0; + double SUMxx = 0.0; + double SUMyy = 0.0; + double lslcorrel; + + for(int i = 0; i < values.length; i++) { + double value = values[i]; + + if (!Double.isNaN(value)) { + cnt++; + + SUMx += lslstep; + SUMxx += lslstep * lslstep; + SUMy += value; + SUMxy += lslstep * value; + SUMyy += value * value; + } + lslstep++; + } + if(cnt > 0) { + /* Bestfit line by linear least squares method */ + lslcorrel = + (SUMxy - (SUMx * SUMy) / cnt) / + Math.sqrt((SUMxx - (SUMx * SUMx) / cnt) * (SUMyy - (SUMy * SUMy) / cnt)); + return new Value(0, lslcorrel); + } + return new Value(0, Double.NaN); + } + + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/data/package-info.java b/apps/jrobin/java/src/org/rrd4j/data/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..37ec9d37ade777ff8a7bfac0a8b19190ea537148 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/data/package-info.java @@ -0,0 +1,4 @@ +/** + * RRD4J data management. + */ +package org.rrd4j.data; diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Area.java b/apps/jrobin/java/src/org/rrd4j/graph/Area.java new file mode 100644 index 0000000000000000000000000000000000000000..c8a169a2f17c877d8b0a2dd8debc480ed9c3c4fb --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Area.java @@ -0,0 +1,9 @@ +package org.rrd4j.graph; + +import java.awt.*; + +class Area extends SourcedPlotElement { + Area(String srcName, Paint color, SourcedPlotElement parent) { + super(srcName, color, parent); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Axis.java b/apps/jrobin/java/src/org/rrd4j/graph/Axis.java new file mode 100644 index 0000000000000000000000000000000000000000..71f506849e8ad0b1020cb4ce59692cfb17d904e6 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Axis.java @@ -0,0 +1,7 @@ +package org.rrd4j.graph; + +public abstract class Axis implements RrdGraphConstants { + + abstract boolean draw(); + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/CDef.java b/apps/jrobin/java/src/org/rrd4j/graph/CDef.java new file mode 100644 index 0000000000000000000000000000000000000000..380d78b9840410af616dae3514af846d474e69f9 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/CDef.java @@ -0,0 +1,16 @@ +package org.rrd4j.graph; + +import org.rrd4j.data.DataProcessor; + +class CDef extends Source { + private final String rpnExpression; + + CDef(String name, String rpnExpression) { + super(name); + this.rpnExpression = rpnExpression; + } + + void requestData(DataProcessor dproc) { + dproc.addDatasource(name, rpnExpression); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/CommentText.java b/apps/jrobin/java/src/org/rrd4j/graph/CommentText.java new file mode 100644 index 0000000000000000000000000000000000000000..ef0c34828a3580d5c14b8448c30936a11daa3b86 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/CommentText.java @@ -0,0 +1,49 @@ +package org.rrd4j.graph; + +import java.util.Locale; + +import org.rrd4j.data.DataProcessor; + +class CommentText implements RrdGraphConstants { + protected final String text; // original text + + String resolvedText; // resolved text + Markers marker; // end-of-text marker + boolean enabled; // hrule and vrule comments can be disabled at runtime + int x, y; // coordinates, evaluated in LegendComposer + + CommentText(String text) { + this.text = text; + } + + void resolveText(Locale l, DataProcessor dproc, ValueScaler valueScaler) { + resolvedText = text; + marker = null; + if (resolvedText != null) { + for (Markers m : Markers.values()) { + String tryMarker = m.marker; + if (resolvedText.endsWith(tryMarker)) { + marker = m; + resolvedText = resolvedText.substring(0, resolvedText.length() - tryMarker.length()); + trimIfGlue(); + break; + } + } + } + enabled = resolvedText != null; + } + + void trimIfGlue() { + if (Markers.GLUE_MARKER == marker) { + resolvedText = resolvedText.replaceFirst("\\s+$", ""); + } + } + + boolean isPrint() { + return false; + } + + boolean isValidGraphElement() { + return !isPrint() && enabled; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ConstantArea.java b/apps/jrobin/java/src/org/rrd4j/graph/ConstantArea.java new file mode 100644 index 0000000000000000000000000000000000000000..87b272ddb33f14aaeffeee7f826de1e4a956cadc --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ConstantArea.java @@ -0,0 +1,29 @@ +package org.rrd4j.graph; + +import java.awt.Paint; +import java.util.Arrays; + +import org.rrd4j.data.DataProcessor; + +public class ConstantArea extends Area { + private final double value; + + ConstantArea(double value, Paint color, SourcedPlotElement parent) { + super(Double.toString(value), color, parent); + this.value = value; + } + + void assignValues(DataProcessor dproc) { + values = new double[dproc.getTimestamps().length]; + Arrays.fill(values, value); + if(parent != null) { + double[] parentValues = parent.getValues(); + for (int i = 0; i < values.length; i++) { + if (! Double.isNaN(parentValues[i])){ + values[i] += parentValues[i]; + } + } + } + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ConstantLine.java b/apps/jrobin/java/src/org/rrd4j/graph/ConstantLine.java new file mode 100644 index 0000000000000000000000000000000000000000..b4749d9da70f9135594af41172b578d1a38ba209 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ConstantLine.java @@ -0,0 +1,30 @@ +package org.rrd4j.graph; + +import java.awt.BasicStroke; +import java.awt.Paint; +import java.util.Arrays; + +import org.rrd4j.data.DataProcessor; + +public class ConstantLine extends Line { + private final double value; + + ConstantLine(double value, Paint color, BasicStroke stroke, SourcedPlotElement parent) { + super(Double.toString(value), color, stroke, parent); + this.value = value; + } + + void assignValues(DataProcessor dproc) { + values = new double[dproc.getTimestamps().length]; + Arrays.fill(values, value); + if(parent != null) { + double[] parentValues = parent.getValues(); + for (int i = 0; i < values.length; i++) { + if (! Double.isNaN(parentValues[i])){ + values[i] += parentValues[i]; + } + } + } + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Def.java b/apps/jrobin/java/src/org/rrd4j/graph/Def.java new file mode 100644 index 0000000000000000000000000000000000000000..c5a2bef5373bca0c9767b8732c4b31042d2a3765 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Def.java @@ -0,0 +1,42 @@ +package org.rrd4j.graph; + +import org.rrd4j.data.DataProcessor; +import org.rrd4j.ConsolFun; +import org.rrd4j.core.RrdBackendFactory; + +class Def extends Source { + private final String rrdPath, 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) { + 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.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); + } + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/DownSampler.java b/apps/jrobin/java/src/org/rrd4j/graph/DownSampler.java new file mode 100644 index 0000000000000000000000000000000000000000..8ab396161dab2d05d103472368bbd62d2d94ddad --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/DownSampler.java @@ -0,0 +1,30 @@ +package org.rrd4j.graph; + +import java.util.Arrays; + +/** + * + * A class that implement a downsampler, used to reduce the number of point to display. + * + * @author Fabrice Bacchella + * + */ +public interface DownSampler { + + public class DataSet { + public final long[] timestamps; + public final double[] values; + public DataSet(long[] timestamps, double[] values) { + this.timestamps = timestamps; + this.values = values; + } + @Override + public String toString() { + return "{\n " + Arrays.toString(timestamps) + ",\n " + Arrays.toString(values) + "}\n"; + } + + } + + public DataSet downsize(long[] timestamps, double[] values); + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ElementsNames.java b/apps/jrobin/java/src/org/rrd4j/graph/ElementsNames.java new file mode 100644 index 0000000000000000000000000000000000000000..a6a2a3cd1958d1d6ca6f16daa5115e9758597a53 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ElementsNames.java @@ -0,0 +1,54 @@ +package org.rrd4j.graph; + +/** + * The elements of the graph. For use in {@link RrdGraphDef#setColor(ElementsNames, java.awt.Paint)} method. + * + * @author Fabrice Bacchella + * + */ +public enum ElementsNames { + /** + * The canvas color + */ + canvas, + /** + * The background color + */ + back, + /** + * The top-left graph shade color + */ + shadea, + /** + * The bottom-right graph shade color + */ + shadeb, + /** + * The minor grid color + */ + grid, + /** + * The major grid color + */ + mgrid, + /** + * The font color + */ + font, + /** + * The frame color + */ + frame, + /** + * The arrow color + */ + arrow, + /** + * The x-axis color + */ + xaxis, + /** + * The y-axis color + */ + yaxis; +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/HRule.java b/apps/jrobin/java/src/org/rrd4j/graph/HRule.java new file mode 100644 index 0000000000000000000000000000000000000000..1fd66c015840bb4a47aab293a00960a8c501a5e5 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/HRule.java @@ -0,0 +1,17 @@ +package org.rrd4j.graph; + +import java.awt.BasicStroke; +import java.awt.Paint; + +class HRule extends Rule { + final double value; + + HRule(double value, Paint color, LegendText legend, BasicStroke stroke) { + super(color, legend, stroke); + this.value = value; + } + + void setLegendVisibility(double minval, double maxval, boolean forceLegend) { + legend.enabled &= (forceLegend || (value >= minval && value <= maxval)); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/HSpan.java b/apps/jrobin/java/src/org/rrd4j/graph/HSpan.java new file mode 100644 index 0000000000000000000000000000000000000000..3166776aa88d6a4b08e102456ba440e4e666dfe2 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/HSpan.java @@ -0,0 +1,25 @@ +package org.rrd4j.graph; + +import java.awt.Paint; + +class HSpan extends Span { + final double start; + final double end; + + HSpan(double start, double end, Paint color, LegendText legend) { + super(color, legend); + this.start = start; + this.end = end; + assert(start < end); + } + + private boolean checkRange(double v, double min, double max) { + return v >= min && v <= max; + } + + void setLegendVisibility(double min, double max, boolean forceLegend) { + legend.enabled = legend.enabled && (forceLegend + || checkRange(start, min, max) + || checkRange(end, min, max)); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ImageParameters.java b/apps/jrobin/java/src/org/rrd4j/graph/ImageParameters.java new file mode 100644 index 0000000000000000000000000000000000000000..5d7135f3c11f23d93f52b66321e0b7e763a7fa56 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ImageParameters.java @@ -0,0 +1,22 @@ +package org.rrd4j.graph; + +class ImageParameters { + long start, end; + double minval, maxval; + int unitsexponent; + double base; + double magfact; + char symbol; + double ygridstep; + int ylabfact; + double decimals; + int quadrant; + double scaledstep; + int xsize; + int ysize; + int xorigin; + int yorigin; + int unitslength; + int xgif, ygif; + String unit; +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ImageWorker.java b/apps/jrobin/java/src/org/rrd4j/graph/ImageWorker.java new file mode 100644 index 0000000000000000000000000000000000000000..f3814a5ff9d079b6af074aedf186855e1f1404aa --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ImageWorker.java @@ -0,0 +1,239 @@ +package org.rrd4j.graph; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.font.LineMetrics; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Paths; + +import javax.imageio.IIOImage; +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.spi.ImageWriterSpi; +import javax.imageio.stream.ImageOutputStream; + +class ImageWorker { + private static final String DUMMY_TEXT = "Dummy"; + + static final int IMG_BUFFER_CAPACITY = 10000; // bytes + + private BufferedImage img; + private Graphics2D g2d; + private int imgWidth, imgHeight; + private AffineTransform initialAffineTransform; + + ImageWorker(int width, int height) { + resize(width, height); + } + + void resize(int width, int height) { + if (g2d != null) { + dispose(); + } + + imgWidth = width; + imgHeight = height; + img = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + + g2d = img.createGraphics(); + initialAffineTransform = g2d.getTransform(); + + setAntiAliasing(false); + setTextAntiAliasing(false); + + g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + } + + void clip(int x, int y, int width, int height) { + g2d.setClip(x, y, width, height); + } + + void transform(int x, int y, double angle) { + g2d.translate(x, y); + g2d.rotate(angle); + } + + void reset() { + g2d.setTransform(initialAffineTransform); + g2d.setClip(0, 0, imgWidth, imgHeight); + } + + void fillRect(int x, int y, int width, int height, Paint paint) { + g2d.setPaint(paint); + g2d.fillRect(x, y, width, height); + } + + void fillPolygon(int[] x, int[] y, Paint paint) { + g2d.setPaint(paint); + g2d.fillPolygon(x, y, x.length); + } + + void fillPolygon(double[] x, double yBottom, double[] yTop, Paint paint) { + g2d.setPaint(paint); + PathIterator path = new PathIterator(yTop); + for (int[] pos = path.getNextPath(); pos != null; pos = path.getNextPath()) { + int start = pos[0], end = pos[1], n = end - start; + int[] xDev = new int[n + 2], yDev = new int[n + 2]; + for (int i = start; i < end; i++) { + xDev[i - start] = (int) x[i]; + yDev[i - start] = (int) yTop[i]; + } + xDev[n] = xDev[n - 1]; + xDev[n + 1] = xDev[0]; + yDev[n] = yDev[n + 1] = (int) yBottom; + g2d.fillPolygon(xDev, yDev, xDev.length); + g2d.drawPolygon(xDev, yDev, xDev.length); + } + } + + void fillPolygon(double[] x, double[] yBottom, double[] yTop, Paint paint) { + g2d.setPaint(paint); + PathIterator path = new PathIterator(yTop); + for (int[] pos = path.getNextPath(); pos != null; pos = path.getNextPath()) { + int start = pos[0], end = pos[1], n = end - start; + int[] xDev = new int[n * 2], yDev = new int[n * 2]; + for (int i = start; i < end; i++) { + int ix1 = i - start, ix2 = n * 2 - 1 - i + start; + xDev[ix1] = xDev[ix2] = (int) x[i]; + yDev[ix1] = (int) yTop[i]; + yDev[ix2] = (int) yBottom[i]; + } + g2d.fillPolygon(xDev, yDev, xDev.length); + } + } + + void drawLine(int x1, int y1, int x2, int y2, Paint paint, Stroke stroke) { + g2d.setStroke(stroke); + g2d.setPaint(paint); + g2d.drawLine(x1, y1, x2, y2); + } + + void drawPolyline(int[] x, int[] y, Paint paint, Stroke stroke) { + g2d.setStroke(stroke); + g2d.setPaint(paint); + g2d.drawPolyline(x, y, x.length); + } + + void drawPolyline(double[] x, double[] y, Paint paint, Stroke stroke) { + g2d.setPaint(paint); + g2d.setStroke(stroke); + PathIterator path = new PathIterator(y); + for (int[] pos = path.getNextPath(); pos != null; pos = path.getNextPath()) { + int start = pos[0], end = pos[1]; + int[] xDev = new int[end - start], yDev = new int[end - start]; + for (int i = start; i < end; i++) { + xDev[i - start] = (int) x[i]; + yDev[i - start] = (int) y[i]; + } + g2d.drawPolyline(xDev, yDev, xDev.length); + } + } + + void drawString(String text, int x, int y, Font font, Paint paint) { + g2d.setFont(font); + g2d.setPaint(paint); + g2d.drawString(text, x, y); + } + + double getFontAscent(Font font) { + LineMetrics lm = font.getLineMetrics(DUMMY_TEXT, g2d.getFontRenderContext()); + return lm.getAscent(); + } + + double getFontHeight(Font font) { + LineMetrics lm = font.getLineMetrics(DUMMY_TEXT, g2d.getFontRenderContext()); + return lm.getAscent() + lm.getDescent(); + } + + double getStringWidth(String text, Font font) { + return font.getStringBounds(text, 0, text.length(), g2d.getFontRenderContext()).getBounds().getWidth(); + } + + void setAntiAliasing(boolean enable) { + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + enable ? RenderingHints.VALUE_ANTIALIAS_ON : RenderingHints.VALUE_ANTIALIAS_OFF); + } + + void setTextAntiAliasing(boolean enable) { + g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, + enable ? RenderingHints.VALUE_TEXT_ANTIALIAS_ON : RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + } + + void dispose() { + g2d.dispose(); + } + + void makeImage(Object stream, ImageWriter writer, ImageWriteParam iwp) throws IOException { + BufferedImage outputImage = img; + + ImageWriterSpi imgProvider = writer.getOriginatingProvider(); + + img.coerceData(false); + + // Some format can't manage 16M colors images + // JPEG don't like transparency + if (! imgProvider.canEncodeImage(outputImage) || "image/jpeg".equals(imgProvider.getMIMETypes()[0].toLowerCase())) { + int w = img.getWidth(); + int h = img.getHeight(); + outputImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); + outputImage.getGraphics().drawImage(img, 0, 0, w, h, null); + if (! imgProvider.canEncodeImage(outputImage)) { + throw new RuntimeException("Invalid image type"); + } + } + + if (! imgProvider.canEncodeImage(outputImage)) { + throw new RuntimeException("Invalid image type"); + } + + try (ImageOutputStream imageStream = ImageIO.createImageOutputStream(stream)) { + writer.setOutput(imageStream); + writer.write(null, new IIOImage(outputImage, null, null), iwp); + imageStream.flush(); + } catch (IOException e) { + writer.abort(); + throw e; + } finally { + writer.dispose(); + } + } + + InputStream saveImage(String path, ImageWriter writer, ImageWriteParam iwp) throws IOException { + makeImage(Paths.get(path).toFile(), writer, iwp); + return new BufferedInputStream(new FileInputStream(path)); + } + + InputStream getImageBytes(ImageWriter writer, ImageWriteParam iwp) throws IOException { + try (ByteArrayOutputStream stream = new ByteArrayOutputStream(IMG_BUFFER_CAPACITY)){ + makeImage(stream, writer, iwp); + return new ByteArrayInputStream(stream.toByteArray()); + } + } + + /** + * <p>loadImage.</p> + * + * @param imageFile a {@link java.lang.String} object. + * @throws java.io.IOException if any. + */ + public void loadImage(String imageFile) throws IOException { + BufferedImage wpImage = ImageIO.read(new File(imageFile)); + TexturePaint paint = new TexturePaint(wpImage, new Rectangle(0, 0, wpImage.getWidth(), wpImage.getHeight())); + g2d.setPaint(paint); + g2d.fillRect(0, 0, wpImage.getWidth(), wpImage.getHeight()); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/LegendComposer.java b/apps/jrobin/java/src/org/rrd4j/graph/LegendComposer.java new file mode 100644 index 0000000000000000000000000000000000000000..f26e1985ee41e081eb7fd9a7f29205453848a6ed --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/LegendComposer.java @@ -0,0 +1,157 @@ +package org.rrd4j.graph; + +import java.util.ArrayList; +import java.util.List; + +class LegendComposer implements RrdGraphConstants { + private final RrdGraphDef gdef; + private final ImageWorker worker; + private int legX, legY; + private final int legWidth; + + private double interLegendSpace; + private double leading; + private double smallLeading; + private double boxSpace; + + LegendComposer(RrdGraph rrdGraph, int legX, int legY, int legWidth) { + this.gdef = rrdGraph.gdef; + this.worker = rrdGraph.worker; + this.legX = legX; + this.legY = legY; + this.legWidth = legWidth; + interLegendSpace = rrdGraph.getInterlegendSpace(); + leading = rrdGraph.getLeading(); + smallLeading = rrdGraph.getSmallLeading(); + boxSpace = rrdGraph.getBoxSpace(); + } + + int placeComments() { + Line line = new Line(); + for (CommentText comment : gdef.comments) { + if (comment.isValidGraphElement()) { + if (!line.canAccommodate(comment)) { + line.layoutAndAdvance(false); + line.clear(); + } + line.add(comment); + } + } + line.layoutAndAdvance(true); + return legY; + } + + class Line { + private Markers lastMarker; + private double width; + private int spaceCount; + private boolean noJustification; + private List<CommentText> comments = new ArrayList<CommentText>(); + + Line() { + clear(); + } + + void clear() { + lastMarker = null; + width = 0; + spaceCount = 0; + noJustification = false; + comments.clear(); + } + + boolean canAccommodate(CommentText comment) { + // always accommodate if empty + if (comments.size() == 0) { + return true; + } + // cannot accommodate if the last marker was \j, \l, \r, \c, \s + if (lastMarker == Markers.ALIGN_LEFT_MARKER || lastMarker == Markers.ALIGN_LEFTNONL_MARKER || lastMarker == Markers.ALIGN_CENTER_MARKER || + lastMarker == Markers.ALIGN_RIGHT_MARKER || lastMarker == Markers.ALIGN_JUSTIFIED_MARKER || + lastMarker == Markers.VERTICAL_SPACING_MARKER) { + return false; + } + // cannot accommodate if line would be too long + double commentWidth = getCommentWidth(comment); + if (lastMarker != Markers.GLUE_MARKER) { + commentWidth += interLegendSpace; + } + return width + commentWidth <= legWidth; + } + + void add(CommentText comment) { + double commentWidth = getCommentWidth(comment); + if (comments.size() > 0 && lastMarker != Markers.GLUE_MARKER) { + commentWidth += interLegendSpace; + spaceCount++; + } + width += commentWidth; + lastMarker = comment.marker; + noJustification |= lastMarker == Markers.NO_JUSTIFICATION_MARKER || lastMarker == null; + comments.add(comment); + } + + void layoutAndAdvance(boolean isLastLine) { + if (comments.size() > 0) { + if (lastMarker == Markers.ALIGN_LEFT_MARKER || lastMarker == Markers.ALIGN_LEFTNONL_MARKER) { + placeComments(legX, interLegendSpace); + } + else if (lastMarker == Markers.ALIGN_RIGHT_MARKER) { + placeComments(legX + legWidth - width, interLegendSpace); + } + else if (lastMarker == Markers.ALIGN_CENTER_MARKER) { + placeComments(legX + (legWidth - width) / 2.0, interLegendSpace); + } + else if (lastMarker == Markers.ALIGN_JUSTIFIED_MARKER) { + // anything to justify? + if (spaceCount > 0) { + placeComments(legX, (legWidth - width) / spaceCount + interLegendSpace); + } + else { + placeComments(legX, interLegendSpace); + } + } + else if (lastMarker == Markers.VERTICAL_SPACING_MARKER) { + placeComments(legX, interLegendSpace); + } + else { + // nothing specified, align with respect to '\J' + if (noJustification || isLastLine) { + placeComments(legX, (legWidth - width) / spaceCount + interLegendSpace); + } + else { + placeComments(legX, interLegendSpace); + } + } + if (!(lastMarker == Markers.ALIGN_LEFTNONL_MARKER)) { + if (lastMarker == Markers.VERTICAL_SPACING_MARKER) { + legY += smallLeading; + } + else { + legY += leading; + } + } + } + } + + private double getCommentWidth(CommentText comment) { + double commentWidth = worker.getStringWidth(comment.resolvedText, gdef.getFont(FONTTAG_LEGEND)); + if (comment instanceof LegendText) { + commentWidth += boxSpace; + } + return commentWidth; + } + + private void placeComments(double xStart, double space) { + double x = xStart; + for (CommentText comment : comments) { + comment.x = (int) x; + comment.y = legY; + x += getCommentWidth(comment); + if (comment.marker != Markers.GLUE_MARKER) { + x += space; + } + } + } + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/LegendText.java b/apps/jrobin/java/src/org/rrd4j/graph/LegendText.java new file mode 100644 index 0000000000000000000000000000000000000000..1f19f6b19b698091f6a4ce3ab566a623cbd98805 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/LegendText.java @@ -0,0 +1,12 @@ +package org.rrd4j.graph; + +import java.awt.*; + +class LegendText extends CommentText { + final Paint legendColor; + + LegendText(Paint legendColor, String text) { + super(text); + this.legendColor = legendColor; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Line.java b/apps/jrobin/java/src/org/rrd4j/graph/Line.java new file mode 100644 index 0000000000000000000000000000000000000000..83bdd9f14015a5a3932a8a9018f70c92676c49c2 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Line.java @@ -0,0 +1,14 @@ +package org.rrd4j.graph; + +import java.awt.BasicStroke; +import java.awt.Paint; + +class Line extends SourcedPlotElement { + final BasicStroke stroke; + + Line(String srcName, Paint color, BasicStroke stroke, SourcedPlotElement parent) { + super(srcName, color, parent); + this.stroke = stroke; + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Mapper.java b/apps/jrobin/java/src/org/rrd4j/graph/Mapper.java new file mode 100644 index 0000000000000000000000000000000000000000..4d168d41937b8037b8293972b4d7e79048d4e04d --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Mapper.java @@ -0,0 +1,66 @@ +package org.rrd4j.graph; + +import org.rrd4j.graph.ImageParameters; +import org.rrd4j.graph.RrdGraphDef; + +class Mapper { + private final RrdGraphDef gdef; + private final ImageParameters im; + private final double pixieX, pixieY; + + Mapper(RrdGraph rrdGraph) { + this.gdef = rrdGraph.gdef; + this.im = rrdGraph.im; + pixieX = (double) im.xsize / (double) (im.end - im.start); + if (!gdef.logarithmic) { + pixieY = (double) im.ysize / (im.maxval - im.minval); + } + else { + pixieY = (double) im.ysize / (ValueAxisLogarithmic.log10(im.maxval) - ValueAxisLogarithmic.log10(im.minval)); + } + } + + Mapper(RrdGraphDef gdef, ImageParameters im) { + this.gdef = gdef; + this.im = im; + pixieX = (double) im.xsize / (double) (im.end - im.start); + if (!gdef.logarithmic) { + pixieY = (double) im.ysize / (im.maxval - im.minval); + } + else { + pixieY = (double) im.ysize / (Math.log10(im.maxval) - Math.log10(im.minval)); + } + } + + int xtr(double mytime) { + return (int) ((double) im.xorigin + pixieX * (mytime - im.start)); + } + + int ytr(double value) { + double yval; + if (!gdef.logarithmic) { + yval = im.yorigin - pixieY * (value - im.minval) + 0.5; + } + else { + if (value < im.minval) { + yval = im.yorigin; + } + else { + yval = im.yorigin - pixieY * (ValueAxisLogarithmic.log10(value) - ValueAxisLogarithmic.log10(im.minval)) + 0.5; + } + } + if (!gdef.rigid) { + return (int) yval; + } + else if ((int) yval > im.yorigin) { + return im.yorigin + 2; + } + else if ((int) yval < im.yorigin - im.ysize) { + return im.yorigin - im.ysize - 2; + } + else { + return (int) yval; + } + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Markers.java b/apps/jrobin/java/src/org/rrd4j/graph/Markers.java new file mode 100644 index 0000000000000000000000000000000000000000..8c014ff4b26f18c9d16da03054443e89cd32053f --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Markers.java @@ -0,0 +1,46 @@ +package org.rrd4j.graph; + +enum Markers { + /** + * Constant to represent left alignment marker + */ + ALIGN_LEFT_MARKER("\\l"), + /** + * Constant to represent left alignment marker, without new line + */ + ALIGN_LEFTNONL_MARKER("\\L"), + /** + * Constant to represent centered alignment marker + */ + ALIGN_CENTER_MARKER("\\c"), + /** + * Constant to represent right alignment marker + */ + ALIGN_RIGHT_MARKER("\\r"), + /** + * Constant to represent justified alignment marker + */ + ALIGN_JUSTIFIED_MARKER("\\j"), + /** + * Constant to represent "glue" marker + */ + GLUE_MARKER("\\g"), + /** + * Constant to represent vertical spacing marker + */ + VERTICAL_SPACING_MARKER("\\s"), + /** + * Constant to represent no justification markers + */ + NO_JUSTIFICATION_MARKER("\\J"); + + final String marker; + Markers(String marker) { + this.marker = marker; + } + + boolean check(String mark) { + return marker.equals(mark); + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/PDef.java b/apps/jrobin/java/src/org/rrd4j/graph/PDef.java new file mode 100644 index 0000000000000000000000000000000000000000..88fe3b0dd8ab8b9bd5cdc858ba4bbeec0c73d408 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/PDef.java @@ -0,0 +1,17 @@ +package org.rrd4j.graph; + +import org.rrd4j.data.DataProcessor; +import org.rrd4j.data.Plottable; + +class PDef extends Source { + private Plottable plottable; + + PDef(String name, Plottable plottable) { + super(name); + this.plottable = plottable; + } + + void requestData(DataProcessor dproc) { + dproc.addDatasource(name, plottable); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/PathIterator.java b/apps/jrobin/java/src/org/rrd4j/graph/PathIterator.java new file mode 100644 index 0000000000000000000000000000000000000000..9b789cf15106b40659a7678aae42bd7ca18263da --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/PathIterator.java @@ -0,0 +1,30 @@ +package org.rrd4j.graph; + +class PathIterator { + private double[] y; + private int pos = 0; + + PathIterator(double[] y) { + this.y = y; + } + + int[] getNextPath() { + while (pos < y.length) { + if (Double.isNaN(y[pos])) { + pos++; + } + else { + int endPos = pos + 1; + while (endPos < y.length && !Double.isNaN(y[endPos])) { + endPos++; + } + int[] result = {pos, endPos}; + pos = endPos; + if (result[1] - result[0] >= 2) { + return result; + } + } + } + return null; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/PlotElement.java b/apps/jrobin/java/src/org/rrd4j/graph/PlotElement.java new file mode 100644 index 0000000000000000000000000000000000000000..173ff1d30133fdbcb5a1067ba788c6d8f5090640 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/PlotElement.java @@ -0,0 +1,11 @@ +package org.rrd4j.graph; + +import java.awt.*; + +class PlotElement { + final Paint color; + + PlotElement(Paint color) { + this.color = color; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/PrintText.java b/apps/jrobin/java/src/org/rrd4j/graph/PrintText.java new file mode 100644 index 0000000000000000000000000000000000000000..f247d68720b27593fdac7b9800d97715b423dcb5 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/PrintText.java @@ -0,0 +1,72 @@ +package org.rrd4j.graph; + +import java.util.Calendar; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.rrd4j.core.Util; +import org.rrd4j.data.DataProcessor; +import org.rrd4j.data.Variable; +import org.rrd4j.data.Variable.Value; + +class PrintText extends CommentText { + static final String UNIT_MARKER = "([^%]?)%(s|S)"; + static final Pattern UNIT_PATTERN = Pattern.compile(UNIT_MARKER); + + private final String srcName; + private final boolean includedInGraph; + private final boolean strftime; + + PrintText(String srcName, String text, boolean includedInGraph, boolean strftime) { + super(text); + this.srcName = srcName; + this.includedInGraph = includedInGraph; + this.strftime = strftime; + } + + boolean isPrint() { + return !includedInGraph; + } + + void resolveText(Locale l, DataProcessor dproc, ValueScaler valueScaler) { + super.resolveText(l, dproc, valueScaler); + Value v = dproc.getVariable(srcName); + if(resolvedText == null) { + return; + } + else if(strftime) { + if(v != Variable.INVALIDVALUE) { + long time = v.timestamp; + try { + Calendar c = new GregorianCalendar(dproc.getTimeZone(), l); + c.setTimeInMillis(time * 1000); + resolvedText = String.format(l, resolvedText, c); + } catch (Exception e) { + throw new RuntimeException("can't format '" + resolvedText + "'", e); + } + } + else { + resolvedText = "-"; + } + } + else { + double value = v.value; + Matcher matcher = UNIT_PATTERN.matcher(resolvedText); + if (matcher.find()) { + // unit specified + ValueScaler.Scaled scaled = valueScaler.scale(value, matcher.group(2).equals("s")); + resolvedText = resolvedText.substring(0, matcher.start()) + + matcher.group(1) + scaled.unit + resolvedText.substring(matcher.end()); + value = scaled.value; + } + try { + resolvedText = Util.sprintf(l, resolvedText, value); + } catch (Exception e) { + throw new RuntimeException("can't format '" + resolvedText + "'", e); + } + } + trimIfGlue(); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/RrdGraph.java b/apps/jrobin/java/src/org/rrd4j/graph/RrdGraph.java new file mode 100644 index 0000000000000000000000000000000000000000..071bfbce93e835b39444125c2717ce5a29cd52dd --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/RrdGraph.java @@ -0,0 +1,781 @@ +package org.rrd4j.graph; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Paint; +import java.awt.Stroke; +import java.io.IOException; + +import javax.imageio.ImageIO; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.spi.ImageWriterSpi; +import javax.swing.ImageIcon; + +import org.rrd4j.core.Util; +import org.rrd4j.data.DataProcessor; +import org.rrd4j.graph.DownSampler.DataSet; + +/** + * Class which actually creates Rrd4j graphs (does the hard work). + */ +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, + 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'}; + + final RrdGraphDef gdef; + final ImageParameters im; + private DataProcessor dproc; + ImageWorker worker; + Mapper mapper; + private final RrdGraphInfo info = new RrdGraphInfo(); + private final String signature; + private final ImageWriter writer; + private final ImageWriteParam param; + + /** + * Creates graph from the corresponding {@link org.rrd4j.graph.RrdGraphDef} object. + * + * @param gdef Graph definition + * @throws java.io.IOException Thrown in case of I/O error + */ + public RrdGraph(RrdGraphDef gdef) throws IOException { + this.gdef = gdef; + signature = gdef.getSignature(); + im = new ImageParameters(); + worker = new ImageWorker(1, 1); // Dummy worker, just to start with something + writer = ImageIO.getImageWritersByFormatName(gdef.imageFormat).next(); + param = getImageParams(); + try { + createGraph(); + } + finally { + worker.dispose(); + worker = null; + dproc = null; + } + } + + /** + * <p>Creates graph from the corresponding {@link org.rrd4j.graph.RrdGraphDef} object.</p> + * <p>The graph will be created using customs {@link javax.imageio.ImageWriter} and {@link javax.imageio.ImageWriteParam} given.</p> + * <p>The ImageWriter type and ImageWriteParam settings have priority other the RrdGraphDef settings. + + * @param gdef Graph definition + * @param writer + * @param param + * @throws IOException Thrown in case of I/O error + * @since 3.5 + */ + public RrdGraph(RrdGraphDef gdef, ImageWriter writer, ImageWriteParam param) throws IOException { + this.gdef = gdef; + signature = gdef.getSignature(); + im = new ImageParameters(); + worker = new ImageWorker(1, 1); // Dummy worker, just to start with something + this.writer = writer; + this.param = param; + try { + createGraph(); + } + finally { + worker.dispose(); + worker = null; + dproc = null; + } + } + + /** + * Returns complete graph information in a single object. + * + * @return Graph information (width, height, filename, image bytes, etc...) + */ + public RrdGraphInfo getRrdGraphInfo() { + return info; + } + + private ImageWriteParam getImageParams() { + ImageWriteParam iwp = writer.getDefaultWriteParam(); + ImageWriterSpi imgProvider = writer.getOriginatingProvider(); + //If lossy compression, use the quality + if (! imgProvider.isFormatLossless()) { + iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); + iwp.setCompressionQuality(gdef.imageQuality); + } + + if (iwp.canWriteProgressive()) { + iwp.setProgressiveMode(gdef.interlaced ? ImageWriteParam.MODE_DEFAULT:ImageWriteParam.MODE_DISABLED); + } + return iwp; + } + + private void createGraph() throws IOException { + boolean lazy = lazyCheck(); + if (!lazy || gdef.printStatementCount() != 0) { + fetchData(); + resolveTextElements(); + if (gdef.shouldPlot() && !lazy) { + calculatePlotValues(); + findMinMaxValues(); + identifySiUnit(); + expandValueRange(); + removeOutOfRangeRules(); + removeOutOfRangeSpans(); + initializeLimits(); + placeLegends(); + createImageWorker(); + drawBackground(); + drawData(); + drawGrid(); + drawAxis(); + drawText(); + drawLegend(); + drawRules(); + drawSpans(); + gator(); + drawOverlay(); + saveImage(); + } + } + collectInfo(); + } + + private void collectInfo() { + info.filename = gdef.filename; + info.width = im.xgif; + info.height = im.ygif; + for (CommentText comment : gdef.comments) { + if (comment instanceof PrintText) { + PrintText pt = (PrintText) comment; + if (pt.isPrint()) { + info.addPrintLine(pt.resolvedText); + } + } + } + if (gdef.imageInfo != null) { + info.imgInfo = Util.sprintf(gdef.locale, gdef.imageInfo, gdef.filename, im.xgif, im.ygif); + } + } + + private void saveImage() throws IOException { + if (! RrdGraphConstants.IN_MEMORY_IMAGE.equals(gdef.filename)) { + info.stream = worker.saveImage(gdef.filename, writer, param); + } + else { + info.stream = worker.getImageBytes(writer, param); + } + } + + private void drawOverlay() throws IOException { + if (gdef.overlayImage != null) { + worker.loadImage(gdef.overlayImage); + } + } + + private void gator() { + if (!gdef.onlyGraph && gdef.showSignature) { + worker.setTextAntiAliasing(gdef.textAntiAliasing); + Font font = gdef.getFont(FONTTAG_WATERMARK); + int x = (int) (im.xgif - 2 - worker.getFontAscent(font)); + int y = 4; + worker.transform(x, y, Math.PI / 2); + worker.drawString(signature, 0, 0, font, Color.LIGHT_GRAY); + worker.reset(); + worker.setTextAntiAliasing(false); + } + } + + private void drawRules() { + worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2); + for (PlotElement pe : gdef.plotElements) { + if (pe instanceof HRule) { + HRule hr = (HRule) pe; + if (hr.value >= im.minval && hr.value <= im.maxval) { + int y = mapper.ytr(hr.value); + worker.drawLine(im.xorigin, y, im.xorigin + im.xsize, y, hr.color, hr.stroke); + } + } + else if (pe instanceof VRule) { + VRule vr = (VRule) pe; + if (vr.timestamp >= im.start && vr.timestamp <= im.end) { + int x = mapper.xtr(vr.timestamp); + worker.drawLine(x, im.yorigin, x, im.yorigin - im.ysize, vr.color, vr.stroke); + } + } + } + worker.reset(); + } + + private void drawSpans() { + worker.clip(im.xorigin + 1, im.yorigin - gdef.height - 1, gdef.width - 1, gdef.height + 2); + for (PlotElement pe : gdef.plotElements) { + if (pe instanceof HSpan) { + HSpan hr = (HSpan) pe; + int ys = mapper.ytr(hr.start); + int ye = mapper.ytr(hr.end); + int height = ys - ye; + worker.fillRect(im.xorigin, ys - height, im.xsize, height, hr.color); + } + else if (pe instanceof VSpan) { + VSpan vr = (VSpan) pe; + int xs = mapper.xtr(vr.start); + int xe = mapper.xtr(vr.end); + worker.fillRect(xs, im.yorigin - im.ysize, xe - xs, im.ysize, vr.color); + } + } + worker.reset(); + } + + private void drawText() { + if (!gdef.onlyGraph) { + worker.setTextAntiAliasing(gdef.textAntiAliasing); + if (gdef.title != null) { + int x = im.xgif / 2 - (int) (worker.getStringWidth(gdef.title, gdef.getFont(FONTTAG_TITLE)) / 2); + int y = PADDING_TOP + (int) worker.getFontAscent(gdef.getFont(FONTTAG_TITLE)); + worker.drawString(gdef.title, x, y, gdef.getFont(FONTTAG_TITLE), gdef.getColor(ElementsNames.font)); + } + if (gdef.verticalLabel != null) { + int x = PADDING_LEFT; + int y = im.yorigin - im.ysize / 2 + (int) worker.getStringWidth(gdef.verticalLabel, gdef.getFont(FONTTAG_UNIT)) / 2; + int ascent = (int) worker.getFontAscent(gdef.getFont(FONTTAG_UNIT)); + worker.transform(x, y, -Math.PI / 2); + worker.drawString(gdef.verticalLabel, 0, ascent, gdef.getFont(FONTTAG_UNIT), gdef.getColor(ElementsNames.font)); + worker.reset(); + } + worker.setTextAntiAliasing(false); + } + } + + private void drawGrid() { + if (!gdef.onlyGraph) { + worker.setTextAntiAliasing(gdef.textAntiAliasing); + Paint shade1 = gdef.getColor(ElementsNames.shadea); + Paint shade2 = gdef.getColor(ElementsNames.shadeb); + Stroke borderStroke = new BasicStroke(1); + worker.drawLine(0, 0, im.xgif - 1, 0, shade1, borderStroke); + worker.drawLine(1, 1, im.xgif - 2, 1, shade1, borderStroke); + worker.drawLine(0, 0, 0, im.ygif - 1, shade1, borderStroke); + worker.drawLine(1, 1, 1, im.ygif - 2, shade1, borderStroke); + worker.drawLine(im.xgif - 1, 0, im.xgif - 1, im.ygif - 1, shade2, borderStroke); + worker.drawLine(0, im.ygif - 1, im.xgif - 1, im.ygif - 1, shade2, borderStroke); + worker.drawLine(im.xgif - 2, 1, im.xgif - 2, im.ygif - 2, shade2, borderStroke); + worker.drawLine(1, im.ygif - 2, im.xgif - 2, im.ygif - 2, shade2, borderStroke); + if (gdef.drawXGrid) { + new TimeAxis(this).draw(); + } + if (gdef.drawYGrid) { + boolean ok; + if (gdef.altYMrtg) { + ok = new ValueAxisMrtg(this).draw(); + } + else if (gdef.logarithmic) { + ok = new ValueAxisLogarithmic(this).draw(); + } + else { + ok = new ValueAxis(this).draw(); + } + if (!ok) { + String msg = "No Data Found"; + worker.drawString(msg, + im.xgif / 2 - (int) worker.getStringWidth(msg, gdef.getFont(FONTTAG_TITLE)) / 2, + (2 * im.yorigin - im.ysize) / 2, + gdef.getFont(FONTTAG_TITLE), gdef.getColor(ElementsNames.font)); + } + } + worker.setTextAntiAliasing(false); + } + } + + private void drawData() { + worker.setAntiAliasing(gdef.antiAliasing); + worker.clip(im.xorigin, im.yorigin - gdef.height - 1, gdef.width, gdef.height + 2); + double areazero = mapper.ytr((im.minval > 0.0) ? im.minval : (im.maxval < 0.0) ? im.maxval : 0.0); + double[] x = gdef.downsampler == null ? xtr(dproc.getTimestamps()) : null; + double[] lastY = null; + // draw line, area and stack + for (PlotElement plotElement : gdef.plotElements) { + if (plotElement instanceof SourcedPlotElement) { + SourcedPlotElement source = (SourcedPlotElement) plotElement; + double[] y; + if (gdef.downsampler != null) { + DataSet set = gdef.downsampler.downsize(dproc.getTimestamps(), source.getValues()); + x = xtr(set.timestamps); + y = ytr(set.values); + } else { + y = ytr(source.getValues()); + } + if (Line.class.isAssignableFrom(source.getClass())) { + worker.drawPolyline(x, y, source.color, ((Line)source).stroke ); + } + else if (Area.class.isAssignableFrom(source.getClass())) { + if(source.parent == null) { + worker.fillPolygon(x, areazero, y, source.color); + } + else { + worker.fillPolygon(x, lastY, y, source.color); + worker.drawPolyline(x, lastY, source.getParentColor(), new BasicStroke(0)); + } + } + else if (source instanceof Stack) { + Stack stack = (Stack) source; + float width = stack.getParentLineWidth(); + if (width >= 0F) { + // line + worker.drawPolyline(x, y, stack.color, new BasicStroke(width)); + } + else { + // area + worker.fillPolygon(x, lastY, y, stack.color); + worker.drawPolyline(x, lastY, stack.getParentColor(), new BasicStroke(0)); + } + } + else { + // should not be here + throw new IllegalStateException("Unknown plot source: " + source.getClass().getName()); + } + lastY = y; + } + } + worker.reset(); + worker.setAntiAliasing(false); + } + + private void drawAxis() { + if (!gdef.onlyGraph) { + Paint gridColor = gdef.getColor(ElementsNames.grid); + Paint xaxisColor = gdef.getColor(ElementsNames.xaxis); + Paint yaxisColor = gdef.getColor(ElementsNames.yaxis); + Paint arrowColor = gdef.getColor(ElementsNames.arrow); + Stroke stroke = new BasicStroke(1); + worker.drawLine(im.xorigin + im.xsize, im.yorigin, im.xorigin + im.xsize, im.yorigin - im.ysize, + gridColor, stroke); + worker.drawLine(im.xorigin, im.yorigin - im.ysize, im.xorigin + im.xsize, im.yorigin - im.ysize, + gridColor, stroke); + worker.drawLine(im.xorigin - 4, im.yorigin, im.xorigin + im.xsize + 4, im.yorigin, + xaxisColor, stroke); + worker.drawLine(im.xorigin, im.yorigin + 4, im.xorigin, im.yorigin - im.ysize - 4, + yaxisColor, stroke); + //Do X axis arrow + double[] Xarrow_x = { + im.xorigin + im.xsize + 4, + im.xorigin + im.xsize + 9, + im.xorigin + im.xsize + 4, + }; + double[] Xarrow_y = { + im.yorigin - 3, + im.yorigin + 0, + im.yorigin + 3, + }; + worker.fillPolygon(Xarrow_x, im.yorigin + 3.0, Xarrow_y, arrowColor); + + //Do y axis arrow + double[] Yarrow_x = { + im.xorigin - 3, + im.xorigin, + im.xorigin + 3, + }; + double[] Yarrow_y = { + im.yorigin - im.ysize - 4, + im.yorigin - im.ysize - 9, + im.yorigin - im.ysize - 4, + }; + worker.fillPolygon(Yarrow_x, im.yorigin - im.ysize - 4.0, Yarrow_y, arrowColor); + } + } + + private void drawBackground() throws IOException { + worker.fillRect(0, 0, im.xgif, im.ygif, gdef.getColor(ElementsNames.back)); + if (gdef.backgroundImage != null) { + worker.loadImage(gdef.backgroundImage); + } + worker.fillRect(im.xorigin, im.yorigin - im.ysize, im.xsize, im.ysize, gdef.getColor(ElementsNames.canvas)); + } + + private void createImageWorker() { + worker.resize(im.xgif, im.ygif); + } + + private void placeLegends() { + if (!gdef.noLegend && !gdef.onlyGraph) { + int border = (int) (getFontCharWidth(FontTag.LEGEND) * PADDING_LEGEND); + LegendComposer lc = new LegendComposer(this, border, im.ygif, im.xgif - 2 * border); + im.ygif = lc.placeComments() + PADDING_BOTTOM; + } + } + + private void initializeLimits() { + im.xsize = gdef.width; + im.ysize = gdef.height; + im.unitslength = gdef.unitsLength; + + if (gdef.onlyGraph) { + im.xorigin = 0; + } + else { + im.xorigin = (int) (PADDING_LEFT + im.unitslength * getFontCharWidth(FontTag.UNIT)); + } + + if (!gdef.onlyGraph && gdef.verticalLabel != null) { + im.xorigin += getFontHeight(FONTTAG_UNIT); + } + + if (gdef.onlyGraph) { + im.yorigin = im.ysize; + } + else { + im.yorigin = PADDING_TOP + im.ysize; + } + + mapper = new Mapper(this); + + if (!gdef.onlyGraph && gdef.title != null) { + im.yorigin += getFontHeight(FONTTAG_TITLE) + PADDING_TITLE; + } + + if (gdef.onlyGraph) { + im.xgif = im.xsize; + im.ygif = im.yorigin; + } + else { + im.xgif = PADDING_RIGHT + im.xsize + im.xorigin; + im.ygif = im.yorigin + (int) (PADDING_PLOT * getFontHeight(FONTTAG_DEFAULT)); + } + } + + private void removeOutOfRangeRules() { + for (PlotElement plotElement : gdef.plotElements) { + if (plotElement instanceof HRule) { + ((HRule) plotElement).setLegendVisibility(im.minval, im.maxval, gdef.forceRulesLegend); + } + else if (plotElement instanceof VRule) { + ((VRule) plotElement).setLegendVisibility(im.start, im.end, gdef.forceRulesLegend); + } + } + } + + private void removeOutOfRangeSpans() { + for (PlotElement plotElement : gdef.plotElements) { + if (plotElement instanceof HSpan) { + ((HSpan) plotElement).setLegendVisibility(im.minval, im.maxval, gdef.forceRulesLegend); + } + else if (plotElement instanceof VSpan) { + ((VSpan) plotElement).setLegendVisibility(im.start, im.end, gdef.forceRulesLegend); + } + } + } + + private void expandValueRange() { + im.ygridstep = (gdef.valueAxisSetting != null) ? gdef.valueAxisSetting.gridStep : Double.NaN; + im.ylabfact = (gdef.valueAxisSetting != null) ? gdef.valueAxisSetting.labelFactor : 0; + if (!gdef.rigid && !gdef.logarithmic) { + double scaled_min, scaled_max, adj; + if (Double.isNaN(im.ygridstep)) { + if (gdef.altYMrtg) { /* mrtg */ + im.decimals = Math.ceil(Math.log10(Math.max(Math.abs(im.maxval), Math.abs(im.minval)))); + im.quadrant = 0; + if (im.minval < 0) { + im.quadrant = 2; + if (im.maxval <= 0) { + im.quadrant = 4; + } + } + switch (im.quadrant) { + case 2: + im.scaledstep = Math.ceil(50 * Math.pow(10, -(im.decimals)) * Math.max(Math.abs(im.maxval), + Math.abs(im.minval))) * Math.pow(10, im.decimals - 2); + scaled_min = -2 * im.scaledstep; + scaled_max = 2 * im.scaledstep; + break; + case 4: + im.scaledstep = Math.ceil(25 * Math.pow(10, + -(im.decimals)) * Math.abs(im.minval)) * Math.pow(10, im.decimals - 2); + scaled_min = -4 * im.scaledstep; + scaled_max = 0; + break; + default: /* quadrant 0 */ + im.scaledstep = Math.ceil(25 * Math.pow(10, -(im.decimals)) * im.maxval) * + Math.pow(10, im.decimals - 2); + scaled_min = 0; + scaled_max = 4 * im.scaledstep; + break; + } + im.minval = scaled_min; + im.maxval = scaled_max; + } + else if (gdef.altAutoscale || (gdef.altAutoscaleMin && gdef.altAutoscaleMax)) { + /* measure the amplitude of the function. Make sure that + graph boundaries are slightly higher then max/min vals + so we can see amplitude on the graph */ + double delt, fact; + + delt = im.maxval - im.minval; + adj = delt * 0.1; + fact = 2.0 * Math.pow(10.0, + Math.floor(Math.log10(Math.max(Math.abs(im.minval), Math.abs(im.maxval)))) - 2); + if (delt < fact) { + adj = (fact - delt) * 0.55; + } + im.minval -= adj; + im.maxval += adj; + } + else if (gdef.altAutoscaleMin) { + /* measure the amplitude of the function. Make sure that + graph boundaries are slightly lower than min vals + so we can see amplitude on the graph */ + adj = (im.maxval - im.minval) * 0.1; + im.minval -= adj; + } + else if (gdef.altAutoscaleMax) { + /* measure the amplitude of the function. Make sure that + graph boundaries are slightly higher than max vals + so we can see amplitude on the graph */ + adj = (im.maxval - im.minval) * 0.1; + im.maxval += adj; + } + else { + scaled_min = im.minval / im.magfact; + scaled_max = im.maxval / im.magfact; + for (int i = 1; SENSIBLE_VALUES[i] > 0; i++) { + if (SENSIBLE_VALUES[i - 1] >= scaled_min && SENSIBLE_VALUES[i] <= scaled_min) { + im.minval = SENSIBLE_VALUES[i] * im.magfact; + } + if (-SENSIBLE_VALUES[i - 1] <= scaled_min && -SENSIBLE_VALUES[i] >= scaled_min) { + im.minval = -SENSIBLE_VALUES[i - 1] * im.magfact; + } + if (SENSIBLE_VALUES[i - 1] >= scaled_max && SENSIBLE_VALUES[i] <= scaled_max) { + im.maxval = SENSIBLE_VALUES[i - 1] * im.magfact; + } + if (-SENSIBLE_VALUES[i - 1] <= scaled_max && -SENSIBLE_VALUES[i] >= scaled_max) { + im.maxval = -SENSIBLE_VALUES[i] * im.magfact; + } + } + } + } + else { + im.minval = (double) im.ylabfact * im.ygridstep * + Math.floor(im.minval / ((double) im.ylabfact * im.ygridstep)); + im.maxval = (double) im.ylabfact * im.ygridstep * + Math.ceil(im.maxval / ((double) im.ylabfact * im.ygridstep)); + } + + } + } + + private void identifySiUnit() { + 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); + } + else { + 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]; + } + else { + im.symbol = '?'; + } + } + } + + private void findMinMaxValues() { + double minval = Double.NaN, maxval = Double.NaN; + for (PlotElement pe : gdef.plotElements) { + if (pe instanceof SourcedPlotElement) { + minval = Util.min(((SourcedPlotElement) pe).getMinValue(), minval); + maxval = Util.max(((SourcedPlotElement) pe).getMaxValue(), maxval); + } + } + if (Double.isNaN(minval)) { + minval = 0D; + } + if (Double.isNaN(maxval)) { + maxval = 1D; + } + im.minval = gdef.minValue; + im.maxval = gdef.maxValue; + /* adjust min and max values */ + if (Double.isNaN(im.minval) || ((!gdef.logarithmic && !gdef.rigid) && im.minval > minval)) { + im.minval = minval; + } + if (Double.isNaN(im.maxval) || (!gdef.rigid && im.maxval < maxval)) { + if (gdef.logarithmic) { + im.maxval = maxval * 1.1; + } + else { + im.maxval = maxval; + } + } + /* make sure min is smaller than max */ + if (im.minval > im.maxval) { + im.minval = 0.99 * im.maxval; + } + /* make sure min and max are not equal */ + if (Math.abs(im.minval - im.maxval) < .0000001) { + im.maxval *= 1.01; + if (!gdef.logarithmic) { + im.minval *= 0.99; + } + /* make sure min and max are not both zero */ + if (im.maxval == 0.0) { + im.maxval = 1.0; + } + } + } + + private void calculatePlotValues() { + for (PlotElement pe : gdef.plotElements) { + if (pe instanceof SourcedPlotElement) { + ((SourcedPlotElement) pe).assignValues(dproc); + } + } + } + + private void resolveTextElements() { + ValueScaler valueScaler = new ValueScaler(gdef.base); + for (CommentText comment : gdef.comments) { + comment.resolveText(gdef.locale, dproc, valueScaler); + } + } + + private void fetchData() throws IOException { + dproc = new DataProcessor(gdef.startTime, gdef.endTime); + dproc.setPoolUsed(gdef.poolUsed); + dproc.setTimeZone(gdef.tz); + if (gdef.step > 0) { + dproc.setStep(gdef.step); + dproc.setFetchRequestResolution(gdef.step); + } + for (Source src : gdef.sources) { + src.requestData(dproc); + } + dproc.processData(); + im.start = gdef.startTime; + im.end = gdef.endTime; + } + + private boolean lazyCheck() { + // redraw if lazy option is not set or file does not exist + if (!gdef.lazy || !Util.fileExists(gdef.filename)) { + return false; // 'false' means 'redraw' + } + // redraw if not enough time has passed + long secPerPixel = (gdef.endTime - gdef.startTime) / gdef.width; + long elapsed = Util.getTimestamp() - Util.getLastModified(gdef.filename); + return elapsed <= secPerPixel; + } + + private void drawLegend() { + if (!gdef.onlyGraph && !gdef.noLegend) { + worker.setTextAntiAliasing(gdef.textAntiAliasing); + int ascent = (int) worker.getFontAscent(gdef.getFont(FONTTAG_LEGEND)); + int box = (int) getBox(), boxSpace = (int) (getBoxSpace()); + for (CommentText c : gdef.comments) { + if (c.isValidGraphElement()) { + int x = c.x, y = c.y + ascent; + if (c instanceof LegendText) { + // draw with BOX + worker.fillRect(x, y - box, box, box, gdef.getColor(ElementsNames.frame)); + worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, gdef.getColor(ElementsNames.canvas)); + worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, gdef.getColor(ElementsNames.back)); + worker.fillRect(x + 1, y - box + 1, box - 2, box - 2, ((LegendText) c).legendColor); + worker.drawString(c.resolvedText, x + boxSpace, y, gdef.getFont(FONTTAG_LEGEND), gdef.getColor(ElementsNames.font)); + } + else { + worker.drawString(c.resolvedText, x, y, gdef.getFont(FONTTAG_LEGEND), gdef.getColor(ElementsNames.font)); + } + } + } + worker.setTextAntiAliasing(false); + } + } + + // helper methods + + double getFontHeight(FontTag fonttag) { + return worker.getFontHeight(gdef.getFont(fonttag)); + } + + double getFontCharWidth(FontTag fonttag) { + return worker.getStringWidth("a", gdef.getFont(fonttag)); + } + + @Deprecated + double getSmallFontHeight() { + return getFontHeight(FONTTAG_LEGEND); + } + + double getTitleFontHeight() { + return getFontHeight(FONTTAG_TITLE); + } + + double getInterlegendSpace() { + return getFontCharWidth(FONTTAG_LEGEND) * LEGEND_INTERSPACING; + } + + double getLeading() { + return getFontHeight(FONTTAG_LEGEND) * LEGEND_LEADING; + } + + double getSmallLeading() { + return getFontHeight(FONTTAG_LEGEND) * LEGEND_LEADING_SMALL; + } + + double getBoxSpace() { + return Math.ceil(getFontHeight(FONTTAG_LEGEND) * LEGEND_BOX_SPACE); + } + + private double getBox() { + return getFontHeight(FONTTAG_LEGEND) * LEGEND_BOX; + } + + private double[] xtr(long[] timestamps) { + double[] timestampsDev = new double[2 * timestamps.length - 1]; + for (int i = 0, j = 0; i < timestamps.length; i += 1, j += 2) { + timestampsDev[j] = mapper.xtr(timestamps[i]); + if (i < timestamps.length - 1) { + timestampsDev[j + 1] = timestampsDev[j]; + } + } + return timestampsDev; + } + + private double[] ytr(double[] values) { + double[] valuesDev = new double[2 * values.length - 1]; + for (int i = 0, j = 0; i < values.length; i += 1, j += 2) { + if (Double.isNaN(values[i])) { + valuesDev[j] = Double.NaN; + } + else { + valuesDev[j] = mapper.ytr(values[i]); + } + if (j > 0) { + valuesDev[j - 1] = valuesDev[j]; + } + } + return valuesDev; + } + + /** + * Renders this graph onto graphing device + * + * @param g Graphics handle + */ + public void render(Graphics g) { + byte[] imageData = getRrdGraphInfo().getBytes(); + ImageIcon image = new ImageIcon(imageData); + image.paintIcon(null, g, 0, 0); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/RrdGraphConstants.java b/apps/jrobin/java/src/org/rrd4j/graph/RrdGraphConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..04d088ddf6da66c5996aad7ad15f06f8a5a2fa10 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/RrdGraphConstants.java @@ -0,0 +1,420 @@ +package org.rrd4j.graph; + +import java.awt.*; +import java.io.IOException; +import java.io.InputStream; +import java.util.Calendar; +import java.util.Locale; + +/** + * Class to represent various constants used for graphing. No methods are specified. + */ +public interface RrdGraphConstants { + /** + * Default graph starting time + */ + String DEFAULT_START = "end-1d"; + /** + * Default graph ending time + */ + String DEFAULT_END = "now"; + + /** + * HH:mm time format + */ + String HH_MM = "HH:mm"; + + /** + * Constant to represent second + */ + int SECOND = Calendar.SECOND; + /** + * Constant to represent minute + */ + int MINUTE = Calendar.MINUTE; + /** + * Constant to represent hour + */ + int HOUR = Calendar.HOUR_OF_DAY; + /** + * Constant to represent day + */ + int DAY = Calendar.DAY_OF_MONTH; + /** + * Constant to represent week + */ + int WEEK = Calendar.WEEK_OF_YEAR; + /** + * Constant to represent month + */ + int MONTH = Calendar.MONTH; + /** + * Constant to represent year + */ + int YEAR = Calendar.YEAR; + + /** + * Constant to represent Monday + */ + int MONDAY = Calendar.MONDAY; + /** + * Constant to represent Tuesday + */ + int TUESDAY = Calendar.TUESDAY; + /** + * Constant to represent Wednesday + */ + int WEDNESDAY = Calendar.WEDNESDAY; + /** + * Constant to represent Thursday + */ + int THURSDAY = Calendar.THURSDAY; + /** + * Constant to represent Friday + */ + int FRIDAY = Calendar.FRIDAY; + /** + * Constant to represent Saturday + */ + int SATURDAY = Calendar.SATURDAY; + /** + * Constant to represent Sunday + */ + int SUNDAY = Calendar.SUNDAY; + + /** + * Index of the canvas color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_CANVAS = 0; + /** + * Index of the background color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_BACK = 1; + /** + * Index of the top-left graph shade color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_SHADEA = 2; + /** + * Index of the bottom-right graph shade color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_SHADEB = 3; + /** + * Index of the minor grid color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_GRID = 4; + /** + * Index of the major grid color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_MGRID = 5; + /** + * Index of the font color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_FONT = 6; + /** + * Index of the frame color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_FRAME = 7; + /** + * Index of the arrow color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_ARROW = 8; + /** + * Index of the x-axis color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_XAXIS = 9; + /** + * Index of the yaxis color. Used in {@link RrdGraphDef#setColor(int, java.awt.Paint)} + */ + @Deprecated + int COLOR_YAXIS = 10; + + /** + * Default first day of the week (obtained from the default locale) + */ + int FIRST_DAY_OF_WEEK = Calendar.getInstance(Locale.getDefault()).getFirstDayOfWeek(); + + /** + * Default graph canvas color + */ + Color DEFAULT_CANVAS_COLOR = Color.WHITE; + /** + * Default graph background color + */ + Color DEFAULT_BACK_COLOR = new Color(245, 245, 245); + /** + * Default top-left graph shade color + */ + Color DEFAULT_SHADEA_COLOR = new Color(200, 200, 200); + /** + * Default bottom-right graph shade color + */ + Color DEFAULT_SHADEB_COLOR = new Color(150, 150, 150); + /** + * Default minor grid color + */ + Color DEFAULT_GRID_COLOR = new Color(171, 171, 171, 95); + /** + * Default major grid color + */ + Color DEFAULT_MGRID_COLOR = new Color(255, 91, 91, 95); + /** + * Default font color + */ + Color DEFAULT_FONT_COLOR = Color.BLACK; + /** + * Default frame color + */ + Color DEFAULT_FRAME_COLOR = Color.BLACK; + /** + * Default arrow color + */ + Color DEFAULT_ARROW_COLOR = new Color(128, 31, 31); + /** + * Default x-axis color + */ + Color DEFAULT_XAXIS_COLOR = Color.BLACK; + /** + * Default x-axis color + */ + Color DEFAULT_YAXIS_COLOR = Color.BLACK; + + /** + * An transparent color + */ + Color BLIND_COLOR = new Color(0, 0, 0, 0); + + /** + * Constant to represent left alignment marker + */ + @Deprecated + String ALIGN_LEFT_MARKER = Markers.ALIGN_LEFT_MARKER.marker; + /** + * Constant to represent left alignment marker, without new line + */ + @Deprecated + String ALIGN_LEFTNONL_MARKER = Markers.ALIGN_LEFTNONL_MARKER.marker; + /** + * Constant to represent centered alignment marker + */ + @Deprecated + String ALIGN_CENTER_MARKER = Markers.ALIGN_CENTER_MARKER.marker; + /** + * Constant to represent right alignment marker + */ + @Deprecated + String ALIGN_RIGHT_MARKER = Markers.ALIGN_RIGHT_MARKER.marker; + /** + * Constant to represent justified alignment marker + */ + @Deprecated + String ALIGN_JUSTIFIED_MARKER = Markers.ALIGN_JUSTIFIED_MARKER.marker; + /** + * Constant to represent "glue" marker + */ + @Deprecated + String GLUE_MARKER = Markers.GLUE_MARKER.marker; + /** + * Constant to represent vertical spacing marker + */ + @Deprecated + String VERTICAL_SPACING_MARKER = Markers.VERTICAL_SPACING_MARKER.marker; + /** + * Constant to represent no justification markers + */ + @Deprecated + String NO_JUSTIFICATION_MARKER = Markers.NO_JUSTIFICATION_MARKER.marker; + + /** + * Constant to represent in-memory image name + */ + String IN_MEMORY_IMAGE = "-"; + + /** + * Default units length + */ + int DEFAULT_UNITS_LENGTH = 9; + /** + * Default graph width + */ + int DEFAULT_WIDTH = 400; + /** + * Default graph height + */ + int DEFAULT_HEIGHT = 100; + /** + * Default image format + */ + String DEFAULT_IMAGE_FORMAT = "gif"; + /** + * Default image quality, used only for jpeg graphs + */ + float DEFAULT_IMAGE_QUALITY = 0.8F; // only for jpegs, not used for png/gif + /** + * Default value base + */ + double DEFAULT_BASE = 1000; + + /** + * Font constructor, to use embedded fonts + */ + static class FontConstructor { + private FontConstructor() {} + + /** + * Return the default RRD4J's default font for the given strength + * @param type {@link java.awt.Font#BOLD} for a bold fond, any other value return plain style. + * @param size the size for the new Font + * @return a new {@link java.awt.Font} instance + */ + 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); + } catch (FontFormatException | IOException e) { + throw new RuntimeException(e); + } + } + } + + /** + * Default graph small font + */ + static final Font DEFAULT_SMALL_FONT = FontConstructor.getFont(Font.PLAIN, 10); + /** + * Default graph large font + */ + static final Font DEFAULT_LARGE_FONT = FontConstructor.getFont(Font.BOLD, 12); + /** + * Font for the Gator + */ + static final Font GATOR_FONT = FontConstructor.getFont(Font.PLAIN, 9); + /** + * Used internally + */ + double LEGEND_LEADING = 1.2; // chars + /** + * Used internally + */ + double LEGEND_LEADING_SMALL = 0.7; // chars + /** + * Used internally + */ + double LEGEND_BOX_SPACE = 1.2; // chars + /** + * Used internally + */ + double LEGEND_BOX = 0.9; // chars + /** + * Used internally + */ + int LEGEND_INTERSPACING = 2; // chars + /** + * Used internally + */ + int PADDING_LEFT = 10; // pix + /** + * Used internally + */ + int PADDING_TOP = 12; // pix + /** + * Used internally + */ + int PADDING_TITLE = 6; // pix + /** + * Used internally + */ + int PADDING_RIGHT = 16; // pix + /** + * Used internally + */ + int PADDING_PLOT = 2; //chars + /** + * Used internally + */ + int PADDING_LEGEND = 2; // chars + /** + * Used internally + */ + int PADDING_BOTTOM = 6; // pix + /** + * Used internally + */ + int PADDING_VLABEL = 7; // pix + + /** + * Stroke used to draw grid + */ + Stroke GRID_STROKE = new BasicStroke(1); + + /** + * Stroke used to draw ticks + */ + Stroke TICK_STROKE = new BasicStroke(1); + + /** + * Allowed font tag names which can be used in {@link org.rrd4j.graph.RrdGraphDef#setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, java.awt.Font)} method + */ + public enum FontTag { + /** + * Index of the default font. Used in {@link org.rrd4j.graph.RrdGraphDef#setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, java.awt.Font)} + */ + DEFAULT, + /** + * Index of the title font. Used in {@link org.rrd4j.graph.RrdGraphDef#setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, java.awt.Font)} + */ + TITLE, + /** + * Index of the axis label font. Used in {@link org.rrd4j.graph.RrdGraphDef#setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, java.awt.Font)} + */ + AXIS, + /** + * Index of the vertical unit label font. Used in {@link org.rrd4j.graph.RrdGraphDef#setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, java.awt.Font)} + */ + UNIT, + /** + * Index of the graph legend font. Used in {@link org.rrd4j.graph.RrdGraphDef#setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, java.awt.Font)} + */ + LEGEND, + /** + * Index of the edge watermark font. Used in {@link org.rrd4j.graph.RrdGraphDef#setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, java.awt.Font)} + */ + WATERMARK; + + public void set(Font f, Font[] fonts) { + fonts[this.ordinal()] = f; + } + + public Font get(Font f, Font[] fonts) { + return fonts[this.ordinal()]; + } + + } + + FontTag FONTTAG_DEFAULT = FontTag.DEFAULT; + + FontTag FONTTAG_TITLE = FontTag.TITLE; + + FontTag FONTTAG_AXIS = FontTag.AXIS; + + FontTag FONTTAG_UNIT = FontTag.AXIS; + + FontTag FONTTAG_LEGEND = FontTag.LEGEND; + + FontTag FONTTAG_WATERMARK = FontTag.WATERMARK; + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/RrdGraphDef.java b/apps/jrobin/java/src/org/rrd4j/graph/RrdGraphDef.java new file mode 100644 index 0000000000000000000000000000000000000000..7e8446e822c09ffae0c839caf0fcdb2aeedac515 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/RrdGraphDef.java @@ -0,0 +1,1668 @@ +package org.rrd4j.graph; + +import java.awt.BasicStroke; +import java.awt.Font; +import java.awt.Paint; +import java.awt.Stroke; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.List; +import java.util.Locale; +import java.util.TimeZone; + +import org.rrd4j.ConsolFun; +import org.rrd4j.core.FetchData; +import org.rrd4j.core.RrdBackendFactory; +import org.rrd4j.core.Util; +import org.rrd4j.data.DataProcessor; +import org.rrd4j.data.Plottable; +import org.rrd4j.data.Variable; + +/** + * <p>Class which should be used to define new Rrd4j graph. Once constructed and populated with data + * object of this class should be passed to the constructor of the {@link org.rrd4j.graph.RrdGraph} class which + * will actually create the graph.</p> + * + * <p>The text printed below the actual graph can be formated by appending + * special escaped characters at the end of a text. When ever such a + * character occurs, all pending text is pushed onto the graph according to + * the character specified.</p> + * + * <p>Valid markers are: \j for justified, \l for left aligned, \r for right + * aligned and \c for centered.</p> + * + * <p>Normally there are two space characters inserted between every two + * items printed into the graph. The space following a string can be + * suppressed by putting a \g at the end of the string. The \g also squashes + * any space inside the string if it is at the very end of the string. + * This can be used in connection with %s to suppress empty unit strings.</p> + * + * <p>A special case is COMMENT:\s this inserts some additional vertical + * space before placing the next row of legends.</p> + * + * <p>When text has to be formated without special instructions from your + * side, RRDTool will automatically justify the text as soon as one string + * goes over the right edge. If you want to prevent the justification + * 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 { + boolean poolUsed = false; // ok + boolean antiAliasing = false; // ok + boolean textAntiAliasing = false; // ok + String filename = RrdGraphConstants.IN_MEMORY_IMAGE; // ok + long startTime, endTime; // ok + TimeAxisSetting timeAxisSetting = null; // ok + TimeLabelFormat timeLabelFormat = null; // ok + ValueAxisSetting valueAxisSetting = null; // ok + boolean altYGrid = false; // ok + boolean noMinorGrid = false; // ok + boolean altYMrtg = false; // ok + boolean altAutoscale = false; // ok + boolean altAutoscaleMin = false; // ok + boolean altAutoscaleMax = false; // ok + int unitsExponent = Integer.MAX_VALUE; // ok + int unitsLength = DEFAULT_UNITS_LENGTH; // ok + String verticalLabel = null; // ok + int width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT; // ok + boolean interlaced = false; // ok + String imageInfo = null; // ok + String imageFormat = DEFAULT_IMAGE_FORMAT; // ok + float imageQuality = DEFAULT_IMAGE_QUALITY; // ok + String backgroundImage = null; // ok + String overlayImage = null; // ok + String unit = null; // ok + boolean lazy = false; // ok + double minValue = Double.NaN; // ok + double maxValue = Double.NaN; // ok + boolean rigid = false; // ok + double base = DEFAULT_BASE; // ok + boolean logarithmic = false; // ok + private final Paint[] colors = new Paint[]{ + // ok + DEFAULT_CANVAS_COLOR, + DEFAULT_BACK_COLOR, + DEFAULT_SHADEA_COLOR, + DEFAULT_SHADEB_COLOR, + DEFAULT_GRID_COLOR, + DEFAULT_MGRID_COLOR, + DEFAULT_FONT_COLOR, + DEFAULT_FRAME_COLOR, + DEFAULT_ARROW_COLOR, + DEFAULT_XAXIS_COLOR, + DEFAULT_YAXIS_COLOR + }; + boolean noLegend = false; // ok + boolean onlyGraph = false; // ok + boolean forceRulesLegend = false; // ok + String title = null; // ok + long step = 0; // ok + Font[] fonts = new Font[] { + DEFAULT_SMALL_FONT, // FONTTAG_DEFAULT + DEFAULT_LARGE_FONT, // FONTTAG_TITLE + DEFAULT_SMALL_FONT, // FONTTAG_AXIS + DEFAULT_SMALL_FONT, // FONTTAG_UNIT + DEFAULT_SMALL_FONT, // FONTTAG_LEGEND + GATOR_FONT // FONTTAG_WATERMARK + }; + boolean drawXGrid = true; // ok + boolean drawYGrid = true; // ok + int firstDayOfWeek = FIRST_DAY_OF_WEEK; // ok + Locale locale = Locale.getDefault(); + TimeZone tz = TimeZone.getDefault(); + String signature = "Generated by RRD4J"; + boolean showSignature = true; + Stroke gridStroke = GRID_STROKE; + Stroke tickStroke = TICK_STROKE; + DownSampler downsampler = null; + + final List<Source> sources = new ArrayList<Source>(); + final List<CommentText> comments = new ArrayList<CommentText>(); + final List<PlotElement> plotElements = new ArrayList<PlotElement>(); + + /** + * Creates RrdGraphDef object and sets default time span (default ending time is 'now', + * default starting time is 'end-1day'. + */ + public RrdGraphDef() { + setTimeSpan(Util.getTimestamps(DEFAULT_START, DEFAULT_END)); + } + + /** + * 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 + */ + public void setStartTime(long time) { + this.startTime = time; + if (time <= 0) { + this.startTime += Util.getTime(); + } + } + + /** + * 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 + */ + public void setEndTime(long time) { + this.endTime = time; + if (time <= 0) { + this.endTime += Util.getTime(); + } + } + + /** + * 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 + */ + public void setTimeSpan(long startTime, long endTime) { + setStartTime(startTime); + setEndTime(endTime); + } + + /** + * Sets starting and ending time for the for the graph. Timestamps in seconds since epoch are + * required. + * + * @param timestamps Array of timestamps. The first array item will be chosen for the starting + * timestamp. The last array item will be chosen for the ending timestamp. + */ + public void setTimeSpan(long[] timestamps) { + setTimeSpan(timestamps[0], timestamps[timestamps.length - 1]); + } + + /** + * Sets RrdDbPool usage policy (defaults to true). If set to true, + * {@link org.rrd4j.core.RrdDbPool RrdDbPool} will be used to + * access individual RRD files. If set to false, RRD files will be accessed directly. + * + * @param poolUsed true, if RrdDbPool class should be used. False otherwise. + */ + public void setPoolUsed(boolean poolUsed) { + this.poolUsed = poolUsed; + } + + /** + * 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, + * .png or .jpg. Rrd4j does not enforce this, however. If the filename is + * set to '-' the image will be created only in memory (no file will be created). + * PNG and GIF formats are recommended but JPEGs should be avoided. + * + * @param filename Path to the image file + */ + public void setFilename(String filename) { + this.filename = filename; + } + + /** + * <p>Configures x-axis grid and labels. The x-axis label is quite complex to configure. + * So if you don't have very special needs, you can rely on the autoconfiguration to + * get this right.</p> + * + * <p>Otherwise, you have to configure three elements making up the x-axis labels + * and grid. The base grid, the major grid and the labels. + * The configuration is based on the idea that you first specify a well + * known amount of time and then say how many times + * it has to pass between each minor/major grid line or label. For the label + * you have to define two additional items: The precision of the label + * in seconds and the format used to generate the text + * of the label.</p> + * + * <p>For example, if you wanted a graph with a base grid every 10 minutes and a major + * one every hour, with labels every hour you would use the following + * x-axis definition.</p> + * + * <pre> + * setTimeAxis(RrdGraphConstants.MINUTE, 10, + * RrdGraphConstants.HOUR, 1, + * RrdGraphConstants.HOUR, 1, + * 0, "%H:%M") + * </pre> + * + * <p>The precision in this example is 0 because the %X format is exact. + * If the label was the name of the day, we would have had a precision + * of 24 hours, because when you say something like 'Monday' you mean + * the whole day and not Monday morning 00:00. Thus the label should + * be positioned at noon. By defining a precision of 24 hours or + * rather 86400 seconds, you make sure that this happens.</p> + * + * @param minorUnit Minor grid unit. Minor grid, major grid and label units + * can be one of the following constants defined in + * {@link org.rrd4j.graph.RrdGraphConstants}: {@link org.rrd4j.graph.RrdGraphConstants#SECOND SECOND}, + * {@link org.rrd4j.graph.RrdGraphConstants#MINUTE MINUTE}, {@link org.rrd4j.graph.RrdGraphConstants#HOUR HOUR}, + * {@link org.rrd4j.graph.RrdGraphConstants#DAY DAY}, {@link org.rrd4j.graph.RrdGraphConstants#WEEK WEEK}, + * {@link org.rrd4j.graph.RrdGraphConstants#MONTH MONTH}, {@link org.rrd4j.graph.RrdGraphConstants#YEAR YEAR}. + * @param minorUnitCount Number of minor grid units between minor grid lines. + * @param majorUnit Major grid unit. + * @param majorUnitCount Number of major grid units between major grid lines. + * @param labelUnit Label unit. + * @param labelUnitCount Number of label units between labels. + * @param labelSpan Label precision + * @param simpleDateFormat Date format (SimpleDateFormat pattern of strftime-like pattern) + */ + public void setTimeAxis(int minorUnit, int minorUnitCount, int majorUnit, int majorUnitCount, + int labelUnit, int labelUnitCount, int labelSpan, String simpleDateFormat) { + timeAxisSetting = new TimeAxisSetting(minorUnit, minorUnitCount, majorUnit, majorUnitCount, + labelUnit, labelUnitCount, labelSpan, new SimpleTimeLabelFormat(simpleDateFormat)); + } + + /** + * It configure the x-axis grid in the same way than {@link #setTimeAxis(int, int, int, int, int, int, int, String)}, but it allows + * to use a {@link org.rrd4j.graph.TimeLabelFormat} to format the date label. + * + * @param minorUnit + * @param minorUnitCount + * @param majorUnit + * @param majorUnitCount + * @param labelUnit + * @param labelUnitCount + * @param labelSpan + * @param format + */ + public void setTimeAxis(int minorUnit, int minorUnitCount, int majorUnit, int majorUnitCount, + int labelUnit, int labelUnitCount, int labelSpan, TimeLabelFormat format) { + timeAxisSetting = new TimeAxisSetting(minorUnit, minorUnitCount, majorUnit, majorUnitCount, + labelUnit, labelUnitCount, labelSpan, format); + } + + /** + * This allows to keep the default major and minor grid unit, but with changing only the label formatting, + * using a {@link org.rrd4j.graph.TimeLabelFormat} + * + * @param format a custom dynamic time label format + */ + public void setTimeLabelFormat(TimeLabelFormat format) { + timeLabelFormat = format; + } + + /** + * Sets vertical axis grid and labels. Makes vertical grid lines appear + * at gridStep interval. Every labelFactor*gridStep, a major grid line is printed, + * along with label showing the value of the grid line. + * + * @param gridStep Minor grid step + * @param labelFactor Specifies how many minor minor grid steps will appear between labels + * (major grid lines) + */ + public void setValueAxis(double gridStep, int labelFactor) { + valueAxisSetting = new ValueAxisSetting(gridStep, labelFactor); + } + + /** + * Places Y grid dynamically based on graph Y range. Algorithm ensures + * that you always have grid, that there are enough but not too many + * grid lines and the grid is metric. That is grid lines are placed + * every 1, 2, 5 or 10 units. + * + * @param altYGrid true, if Y grid should be calculated dynamically (defaults to false) + */ + public void setAltYGrid(boolean altYGrid) { + this.altYGrid = altYGrid; + } + + /** + * Use this method to turn off minor grid lines (printed by default) + * + * @param noMinorGrid true, to turn off, false to turn on (default) + */ + public void setNoMinorGrid(boolean noMinorGrid) { + this.noMinorGrid = noMinorGrid; + } + + /** + * Use this method to request MRTG-like graph (false by default) + * + * @param altYMrtg true, to create MRTG-like graph, false otherwise (default) + */ + public void setAltYMrtg(boolean altYMrtg) { + this.altYMrtg = altYMrtg; + } + + /** + * Computes Y range based on function absolute minimum and maximum + * values. Default algorithm uses predefined set of ranges. This is + * good in many cases but it fails miserably when you need to graph + * something like 260 + 0.001 * sin(x). Default algorithm will use Y + * range from 250 to 300 and on the graph you will see almost straight + * line. With --alt-autoscale Y range will be from slightly less the + * 260 - 0.001 to slightly more then 260 + 0.001 and periodic behavior + * will be seen. + * + * @param altAutoscale true to request alternative autoscaling, false otherwise + * (default). + */ + public void setAltAutoscale(boolean altAutoscale) { + this.altAutoscale = altAutoscale; + } + + /** + * Computes Y range based on function absolute minimum and maximum + * values. Where setAltAutoscale(true) will modify both the absolute maximum AND + * minimum values, this option will only affect the maximum value. The + * minimum value, if not defined elsewhere, will be 0. This + * option can be useful when graphing router traffic when the WAN line + * uses compression, and thus the throughput may be higher than the + * WAN line speed. + * + * @param altAutoscaleMin true to request alternative autoscaling, false + * otherwise (default) + */ + public void setAltAutoscaleMin(boolean altAutoscaleMin) { + this.altAutoscaleMin = altAutoscaleMin; + } + + /** + * Computes Y range based on function absolute minimum and maximum + * values. Where setAltAutoscale(true) will modify both the absolute maximum AND + * minimum values, this option will only affect the maximum value. The + * minimum value, if not defined elsewhere, will be 0. This + * option can be useful when graphing router traffic when the WAN line + * uses compression, and thus the throughput may be higher than the + * WAN line speed. + * + * @param altAutoscaleMax true to request alternative autoscaling, false + * otherwise (default) + */ + public void setAltAutoscaleMax(boolean altAutoscaleMax) { + this.altAutoscaleMax = altAutoscaleMax; + } + + /** + * Sets the 10**unitsExponent scaling of the y-axis values. Normally + * values will be scaled to the appropriate units (k, M, etc.). However + * you may wish to display units always in k (Kilo, 10e3) even if + * the data is in the M (Mega, 10e6) range for instance. Value should + * be an integer which is a multiple of 3 between -18 and 18, inclusive. + * It is the exponent on the units you which to use. For example, + * use 3 to display the y-axis values in k (Kilo, 10e3, thousands), + * use -6 to display the y-axis values in µ (Micro, 10e-6, + * millionths). Use a value of 0 to prevent any scaling of the y-axis + * values. + * + * @param unitsExponent the 10**unitsExponent value for scaling y-axis values. + */ + public void setUnitsExponent(int unitsExponent) { + this.unitsExponent = unitsExponent; + } + + /** + * Sets the character width on the left side of the graph for + * y-axis values. + * + * @param unitsLength Number of characters on the left side of the graphs + * reserved for vertical axis labels. + */ + public void setUnitsLength(int unitsLength) { + this.unitsLength = unitsLength; + } + + /** + * Sets vertical label on the left side of the graph. This is normally used + * to specify the units used. + * + * @param verticalLabel Vertical axis label + */ + public void setVerticalLabel(String verticalLabel) { + this.verticalLabel = verticalLabel; + } + + /** + * Sets width of the drawing area within the graph. This affects the total + * size of the image. + * + * @param width Width of the drawing area. + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * Sets height of the drawing area within the graph. This affects the total + * size of the image. + * + * @param height Height of the drawing area. + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * Creates interlaced or progressive mode image. + * + * @param interlaced true, if GIF image should be interlaced. + */ + public void setInterlaced(boolean interlaced) { + this.interlaced = interlaced; + } + + /** + * <p>Creates additional image information. + * After the image has been created, the graph function uses imageInfo + * format string (printf-like) to create output similar to + * the {@link #print(String, ConsolFun, String)} function. + * The format string is supplied with the following parameters: + * filename, xsize and ysize (in that particular order).</p> + * + * <p>For example, in order to generate an IMG tag + * suitable for including the graph into a web page, the command + * would look like this:</p> + * <pre> + * setImageInfo("<IMG SRC='/img/%s' WIDTH='%d' HEIGHT='%d' ALT='Demo'>"); + * </pre> + * + * @param imageInfo Image info format. Use %s placeholder for filename, %d placeholder for + * image width and height. + */ + public void setImageInfo(String imageInfo) { + this.imageInfo = imageInfo; + } + + /** + * Sets image format. + * + * @param imageFormat Any value as return by {@link javax.imageio.ImageIO#getReaderFormatNames} + */ + public void setImageFormat(String imageFormat) { + this.imageFormat = imageFormat; + } + + /** + * Sets background image - currently, only PNG images can be used as background. + * + * @param backgroundImage Path to background image + */ + public void setBackgroundImage(String backgroundImage) { + this.backgroundImage = backgroundImage; + } + + /** + * Sets overlay image - currently, only PNG images can be used as overlay. Overlay image is + * printed on the top of the image, once it is completely created. + * + * @param overlayImage Path to overlay image + */ + public void setOverlayImage(String overlayImage) { + this.overlayImage = overlayImage; + } + + /** + * Sets unit to be displayed on y axis. It is wise to use only short units on graph, however. + * + * @param unit Unit description + */ + public void setUnit(String unit) { + this.unit = unit; + } + + /** + * Creates graph only if the current graph is out of date or not existent. + * + * @param lazy true, if graph should be 'lazy', false otherwise (default) + */ + public void setLazy(boolean lazy) { + this.lazy = lazy; + } + + /** + * Sets the lower limit of a graph. But rather, this is the + * maximum lower bound of a graph. For example, the value -100 will + * result in a graph that has a lower limit of -100 or less. Use this + * method to expand graphs down. + * + * @param minValue Minimal value displayed on the graph + */ + public void setMinValue(double minValue) { + this.minValue = minValue; + } + + /** + * <p>Defines the value normally located at the upper border of the + * graph. If the graph contains higher values, the upper border will + * move upwards to accommodate these values as well.</p> + * + * <p>If you want to define an upper-limit which will not move in any + * event you have to use {@link #setRigid(boolean)} method as well.</p> + * + * @param maxValue Maximal value displayed on the graph. + */ + public void setMaxValue(double maxValue) { + this.maxValue = maxValue; + } + + /** + * Sets rigid boundaries mode. Normally Rrd4j will automatically expand + * the lower and upper limit if the graph contains a value outside the + * valid range. With the <code>true</code> argument you can disable this behavior. + * + * @param rigid true if upper and lower limits should not be expanded to accommodate + * values outside of the specified range. False otherwise (default). + */ + public void setRigid(boolean rigid) { + this.rigid = rigid; + } + + /** + * Sets default base for magnitude scaling. If you are graphing memory + * (and NOT network traffic) this switch should be set to 1024 so that 1Kb is 1024 byte. + * For traffic measurement, 1 kb/s is 1000 b/s. + * + * @param base Base value (defaults to 1000.0) + */ + public void setBase(double base) { + this.base = base; + } + + /** + * Sets logarithmic y-axis scaling. + * + * @param logarithmic true, for logarithmic scaling, false otherwise (default). + */ + public void setLogarithmic(boolean logarithmic) { + this.logarithmic = logarithmic; + } + + /** + * Overrides the colors for the standard elements of the graph. The + * colorTag must be one of the following constants defined in the {@link org.rrd4j.graph.RrdGraphConstants}: + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_BACK COLOR_BACK}ground, + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_CANVAS COLOR_CANVAS}, + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_XAXIS COLOR_XAXIS}, + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_SHADEA COLOR_SHADEA} left/top border, + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_SHADEB COLOR_SHADEB} right/bottom border, + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_GRID COLOR_GRID}, + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_MGRID COLOR_MGRID} major grid, + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_FONT COLOR_FONT}, + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_FRAME COLOR_FRAME} and axis of the graph or + * {@link org.rrd4j.graph.RrdGraphConstants#COLOR_ARROW COLOR_ARROW}. This + * method can be called multiple times to set several colors. + * + * @param colorTag Color tag, as explained above. + * @param color Any color (paint) you like + * @deprecated Using {@link #setColor(ElementsNames, Paint)} + */ + @Deprecated + public void setColor(int colorTag, Paint color) { + if (colorTag >= 0 && colorTag < colors.length) { + colors[colorTag] = color; + } else { + throw new IllegalArgumentException("Invalid color index specified: " + colorTag); + } + } + + /** + * Overrides the colors for the standard elements of the graph. + * @param colorTag + * @param color + */ + public void setColor(ElementsNames colorTag, Paint color) { + colors[colorTag.ordinal()] = color; + } + + /** + * Overrides the colors for the standard elements of the graph by element name. + * See {@link #setColor(int, java.awt.Paint)} for full explanation. + * + * @param colorName One of the following strings: "BACK", "CANVAS", "SHADEA", "SHADEB", + * "GRID", "MGRID", "FONT", "FRAME", "ARROW", "XAXIS", "YAXIS" + * @param color Any color (paint) you like + * @deprecated Using {@link #setColor(ElementsNames, Paint)} + */ + @Deprecated + public void setColor(String colorName, Paint color) { + setColor(ElementsNames.valueOf(colorName.toLowerCase(Locale.ENGLISH)).ordinal(), color); + } + + /** + * Suppress generation of legend, only render the graph. + * + * @param noLegend true if graph legend should be omitted. False otherwise (default). + */ + public void setNoLegend(boolean noLegend) { + this.noLegend = noLegend; + } + + /** + * Suppresses anything but the graph, works only for height < 64. + * + * @param onlyGraph true if only graph should be created, false otherwise (default). + */ + public void setOnlyGraph(boolean onlyGraph) { + this.onlyGraph = onlyGraph; + } + + /** + * Force the generation of HRULE and VRULE legend even if those HRULE + * or VRULE will not be drawn because out of graph boundaries. + * + * @param forceRulesLegend true if rule legend should be always printed, + * false otherwise (default). + */ + public void setForceRulesLegend(boolean forceRulesLegend) { + this.forceRulesLegend = forceRulesLegend; + } + + /** + * Defines a title to be written into the graph. + * + * @param title Graph title. + */ + public void setTitle(String title) { + this.title = title; + } + + /** + * Suggests which time step should be used by Rrd4j while processing data from RRD files. + * + * @param step Desired time step (don't use this method if you don't know what you're doing). + */ + public void setStep(long step) { + this.step = step; + } + + /** + * This method reset the font set to it's default values. With the flag rrdtool set to true, it's not the old + * default set that is used, but the one taken from rrdtool. So use false to keep compatibility with previous version + * and true for a graph matching rrdtool's + * + * @param rrdtool true to use rrdtool font set + */ + public void setFontSet(boolean rrdtool) { + if(rrdtool) { + // We add a factor to the font size, rrdtool and java don't agree about font size + float rrdtoolfactor = 12f/9; + fonts = new Font[] { + DEFAULT_SMALL_FONT.deriveFont(8.0f * rrdtoolfactor), // FONTTAG_DEFAULT + DEFAULT_SMALL_FONT.deriveFont(9.0f * rrdtoolfactor), // FONTTAG_TITLE + DEFAULT_SMALL_FONT.deriveFont(7.0f * rrdtoolfactor), // FONTTAG_AXIS + DEFAULT_SMALL_FONT.deriveFont(8.0f * rrdtoolfactor), // FONTTAG_UNIT + DEFAULT_SMALL_FONT.deriveFont(8.0f * rrdtoolfactor), // FONTTAG_LEGEND + DEFAULT_SMALL_FONT.deriveFont(5.5f * rrdtoolfactor) // FONTTAG_WATERMARK + }; + } else { + fonts = new Font[] { + DEFAULT_SMALL_FONT, // FONTTAG_DEFAULT + DEFAULT_LARGE_FONT, // FONTTAG_TITLE + DEFAULT_SMALL_FONT, // FONTTAG_AXIS + DEFAULT_SMALL_FONT, // FONTTAG_UNIT + DEFAULT_SMALL_FONT, // FONTTAG_LEGEND + GATOR_FONT // FONTTAG_WATERMARK + }; + } + } + + /** + * Sets default font for graphing. Note that Rrd4j will behave unpredictably if proportional + * font is selected. + * + * @param smallFont Default font for graphing. Use only monospaced fonts. + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public void setSmallFont(final Font smallFont) { + this.setFont(FontTag.DEFAULT, smallFont); + } + + /** + * Sets title font. + * + * @param largeFont Font to be used for graph title. + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public void setLargeFont(final Font largeFont) { + this.setFont(FontTag.TITLE, largeFont); + } + + /** + * Sets font to be used for a specific font tag. The fontTag + * must be one of the following constants defined in the + * {@link RrdGraphConstants}: + * {@link RrdGraphConstants#FONTTAG_DEFAULT FONTTAG_DEFAULT} default font,, + * {@link RrdGraphConstants#FONTTAG_TITLE FONTTAG_TITLE} title, + * {@link RrdGraphConstants#FONTTAG_AXIS FONTTAG_AXIS} grid axis,, + * {@link RrdGraphConstants#FONTTAG_UNIT FONTTAG_UNIT} vertical unit label,, + * {@link RrdGraphConstants#FONTTAG_LEGEND FONTTAG_LEGEND} legend, + * {@link RrdGraphConstants#FONTTAG_WATERMARK FONTTAG_WATERMARK} watermark. + * This method can be called multiple times to set several fonts. + * + * @param fontTag Font tag, as explained above. + * @param font Font to be used for tag + */ + public void setFont(final FontTag fontTag, final Font font) { + this.setFont(fontTag, font, false); + } + + /** + * Sets font. + * + * @param fontTag Font tag, as explained above. + * @param font Font to be used for tag + * @param setAll Boolean to flag whether to set all fonts if fontTag == FONTTAG_DEFAULT + */ + public void setFont(final FontTag fontTag, final Font font, final boolean setAll) { + this.setFont(fontTag, font, setAll, false); + } + + /** + * Sets font. + * + * @param fontTag Font tag, as explained above. + * @param font Font to be used for tag + * @param setAll Boolean to flag whether to set all fonts if fontTag == FONTTAG_DEFAULT + * @param keepSizes Boolean to flag whether to keep original font sizes if setting all fonts. + */ + public void setFont(final FontTag fontTag, final Font font, final boolean setAll, final boolean keepSizes) { + if (fontTag == FontTag.DEFAULT && setAll) { + if (keepSizes) { + this.fonts[FONTTAG_DEFAULT.ordinal()] = font.deriveFont(this.fonts[FONTTAG_DEFAULT.ordinal()].getSize()); + this.fonts[FONTTAG_TITLE.ordinal()] = font.deriveFont(this.fonts[FONTTAG_TITLE.ordinal()].getSize()); + this.fonts[FONTTAG_AXIS.ordinal()] = font.deriveFont(this.fonts[FONTTAG_AXIS.ordinal()].getSize()); + this.fonts[FONTTAG_UNIT.ordinal()] = font.deriveFont(this.fonts[FONTTAG_UNIT.ordinal()].getSize()); + this.fonts[FONTTAG_LEGEND.ordinal()] = font.deriveFont(this.fonts[FONTTAG_LEGEND.ordinal()].getSize()); + this.fonts[FONTTAG_WATERMARK.ordinal()] = font.deriveFont(this.fonts[FONTTAG_WATERMARK.ordinal()].getSize()); + } + else { + this.fonts[FONTTAG_DEFAULT.ordinal()] = font; + this.fonts[FONTTAG_TITLE.ordinal()] = null; + this.fonts[FONTTAG_AXIS.ordinal()] = null; + this.fonts[FONTTAG_UNIT.ordinal()] = null; + this.fonts[FONTTAG_LEGEND.ordinal()] = null; + this.fonts[FONTTAG_WATERMARK.ordinal()] = null; + } + } else { + this.fonts[fontTag.ordinal()] = font; + } + } + + /** + * Sets font. + * + * @param fontTag Font tag as String, as explained in {@link #setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, Font, boolean)}. + * @param font Font to be used for tag + */ + public void setFont(final String fontTag, final Font font) { + this.setFont(FontTag.valueOf(fontTag), font); + } + + /** + * Sets font. + * + * @param fontTag Font tag as String, as explained in {@link #setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, Font, boolean)}. + * @param font Font to be used for tag + * @param setAll Boolean to flag whether to set all fonts if fontTag == FONTTAG_DEFAULT + */ + public void setFont(final String fontTag, final Font font, final boolean setAll) { + this.setFont(FontTag.valueOf(fontTag), font, setAll); + } + + /** + * Sets font. + * + * @param fontTag Font tag as String, as explained in {@link #setFont(org.rrd4j.graph.RrdGraphConstants.FontTag, Font, boolean)}. + * @param font Font to be used for tag + * @param setAll Boolean to flag whether to set all fonts if fontTag == FONTTAG_DEFAULT + * @param keepSizes Boolean to flag whether to keep original font sizes if setting all fonts. + */ + public void setFont(final String fontTag, final Font font, final boolean setAll, final boolean keepSizes) { + this.setFont(FontTag.valueOf(fontTag), font, setAll, keepSizes); + } + + public Font getFont(final FontTag tag) { + return this.fonts[tag.ordinal()] == null ? this.fonts[FONTTAG_DEFAULT.ordinal()] : this.fonts[tag.ordinal()]; + } + + + /** + * 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 rrdPath Path to RRD file + * @param dsName Datasource name in the specified RRD file + * @param consolFun Consolidation function (AVERAGE, MIN, MAX, LAST) + */ + public void datasource(String name, String rrdPath, String dsName, ConsolFun consolFun) { + sources.add(new Def(name, rrdPath, dsName, consolFun)); + } + + /** + * 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 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. + * + * @deprecated Uses {@link #datasource(String, String, String, ConsolFun, RrdBackendFactory)} instead + */ + @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))); + } + + /** + * 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 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. + */ + public void datasource(String name, String rrdPath, String dsName, ConsolFun consolFun, RrdBackendFactory backend) { + sources.add(new Def(name, rrdPath, dsName, consolFun, 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. + */ + public void datasource(String name, String rpnExpression) { + sources.add(new CDef(name, rpnExpression)); + } + + /** + * Creates a new (static) virtual datasource. The value of the datasource is constant. This value is + * evaluated by applying the given consolidation function to another virtual datasource. + * + * @param name Source name + * @param defName Other source name + * @param consolFun Consolidation function to be applied to other datasource. + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public void datasource(String name, String defName, ConsolFun consolFun) { + datasource(name, defName, consolFun.getVariable()); + } + + public void datasource(String name, String defName, Variable var) { + sources.add(new VDef(name, defName, var)); + } + + /** + * Creates a new (plottable) datasource. Datasource values are obtained from the given plottable + * object. + * + * @param name Source name. + * @param plottable Plottable object. + */ + public void datasource(String name, Plottable plottable) { + sources.add(new PDef(name, 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. + */ + public void datasource(String name, FetchData fetchData) { + sources.add(new TDef(name, name, 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. + */ + public void datasource(String name, String dsName, FetchData fetchData) { + sources.add(new TDef(name, dsName, fetchData)); + } + + /** + * Create a new virtual datasource to get the 95th percentile value from another datasource + * + * @param name Source name. + * @param defName Other source name. + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public void percentile(String name, String defName) { + percentile(name, defName, DataProcessor.DEFAULT_PERCENTILE); + } + + /** + * Create a new virtual datasource to get a percentile value from another datasource + * + * @param name Source name. + * @param defName Other source name. + * @param percent The percent value. + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public void percentile(String name, String defName, double percent) { + datasource(name, defName, new Variable.PERCENTILE(percent)); + } + + /** + * <p>Calculates the chosen consolidation function CF over the given datasource + * and creates the result by using the given format string. In + * the format string there should be a '%[l]f', '%[l]g' or '%[l]e' marker in + * the place where the number should be printed.</p> + * + * <p>If an additional '%s' is found AFTER the marker, the value will be + * scaled and an appropriate SI magnitude unit will be printed in + * place of the '%s' marker. The scaling will take the '--base' argument into consideration!</p> + * + * <p>If a '%S' is used instead of a '%s', then instead of calculating + * the appropriate SI magnitude unit for this value, the previously + * calculated SI magnitude unit will be used. This is useful if you + * want all the values in a print statement to have the same SI magnitude unit. + * If there was no previous SI magnitude calculation made, + * then '%S' behaves like a '%s', unless the value is 0, in which case + * it does not remember a SI magnitude unit and a SI magnitude unit + * will only be calculated when the next '%s' is seen or the next '%S' + * for a non-zero value.</p> + * + * <p>Print results are collected in the {@link org.rrd4j.graph.RrdGraphInfo} object which is retrieved + * from the {@link RrdGraph object} once the graph is created.</p> + * + * @param srcName Virtual source name + * @param consolFun Consolidation function to be applied to the source + * @param format Format string (like "average = %10.3f %s") + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public void print(String srcName, ConsolFun consolFun, String format) { + Variable var = consolFun.getVariable(); + String tempName = srcName + "_" + var.hashCode(); + datasource(tempName, srcName, var); + comments.add(new PrintText(tempName, format, false, false)); + } + + /** + * <p>Read the value of a variable (VDEF) and prints the value by using the given format string. In + * the format string there should be a '%[l]f', '%[l]g' or '%[l]e' marker in + * the place where the number should be printed.</p> + * + * <p>If an additional '%s' is found AFTER the marker, the value will be + * scaled and an appropriate SI magnitude unit will be printed in + * place of the '%s' marker. The scaling will take the '--base' argument into consideration!</p> + * + * <p>If a '%S' is used instead of a '%s', then instead of calculating + * the appropriate SI magnitude unit for this value, the previously + * calculated SI magnitude unit will be used. This is useful if you + * want all the values in a print statement to have the same SI magnitude unit. + * If there was no previous SI magnitude calculation made, + * then '%S' behaves like a '%s', unless the value is 0, in which case + * it does not remember a SI magnitude unit and a SI magnitude unit + * will only be calculated when the next '%s' is seen or the next '%S' + * for a non-zero value.</p> + * + * <p>Print results are collected in the {@link org.rrd4j.graph.RrdGraphInfo} object which is retrieved + * from the {@link RrdGraph object} once the graph is created.</p> + * + * @param srcName Virtual source name + * @param format Format string (like "average = %10.3f %s") + */ + public void print(String srcName, String format) { + print(srcName, format, false); + } + + /** + * <p>Read the value of a variable (VDEF) and prints the the value or the time stamp, according to the strftime flag + * by using the given format string. In + * and creates the result by using the given format string. In + * the format string there should be a '%[l]f', '%[l]g' or '%[l]e' marker in + * the place where the number should be printed.</p> + * + * <p>If an additional '%s' is found AFTER the marker, the value will be + * scaled and an appropriate SI magnitude unit will be printed in + * place of the '%s' marker. The scaling will take the '--base' argument into consideration!</p> + * + * <p>If a '%S' is used instead of a '%s', then instead of calculating + * the appropriate SI magnitude unit for this value, the previously + * calculated SI magnitude unit will be used. This is useful if you + * want all the values in a print statement to have the same SI magnitude unit. + * If there was no previous SI magnitude calculation made, + * then '%S' behaves like a '%s', unless the value is 0, in which case + * it does not remember a SI magnitude unit and a SI magnitude unit + * will only be calculated when the next '%s' is seen or the next '%S' + * for a non-zero value.</p> + * + * <p>Print results are collected in the {@link org.rrd4j.graph.RrdGraphInfo} object which is retrieved + * from the {@link RrdGraph object} once the graph is created.</p> + * + * @param srcName Virtual source name + * @param format Format string (like "average = %10.3f %s") + * @param strftime use the timestamp from the variable (true) or the numerical value (false) + */ + public void print(String srcName, String format, boolean strftime) { + comments.add(new PrintText(srcName, format, false, strftime)); + } + + /** + * This method does basically the same thing as {@link #print(String, ConsolFun, String)}, + * but the result is printed on the graph itself, below the chart area. + * + * @param srcName Virtual source name. + * @param consolFun Consolidation function to be applied to the source. + * @param format Format string (like "average = %10.3f %s") + * @deprecated Use {@link Variable} based method instead. + */ + @Deprecated + public void gprint(String srcName, ConsolFun consolFun, String format) { + Variable var = consolFun.getVariable(); + String tempName = srcName + "_" + var.hashCode(); + this.datasource(tempName, srcName, var); + comments.add(new PrintText(tempName, format, true, false)); + } + + /** + * <p>Read the value of a variable (VDEF) and prints the value by using the given format string. In + * the format string there should be a '%[l]f', '%[l]g' or '%[l]e' marker in + * the place where the number should be printed.</p> + * + * <p>If an additional '%s' is found AFTER the marker, the value will be + * scaled and an appropriate SI magnitude unit will be printed in + * place of the '%s' marker. The scaling will take the '--base' argument into consideration!</p> + * + * <p>If a '%S' is used instead of a '%s', then instead of calculating + * the appropriate SI magnitude unit for this value, the previously + * calculated SI magnitude unit will be used. This is useful if you + * want all the values in a print statement to have the same SI magnitude unit. + * If there was no previous SI magnitude calculation made, + * then '%S' behaves like a '%s', unless the value is 0, in which case + * it does not remember a SI magnitude unit and a SI magnitude unit + * will only be calculated when the next '%s' is seen or the next '%S' + * for a non-zero value.</p> + * + * print results are added to the graph as a legend + * + * @param srcName Virtual source name + * @param format Format string (like "average = %10.3f %s") + */ + public void gprint(String srcName, String format) { + gprint(srcName, format, false); + } + + /** + * <p>Read the value of a variable (VDEF) and prints the the value or the time stamp, according to the strftime flag + * by using the given format string. In + * and creates the result by using the given format string. In + * the format string there should be a '%[l]f', '%[l]g' or '%[l]e' marker in + * the place where the number should be printed.</p> + * + * <p>If an additional '%s' is found AFTER the marker, the value will be + * scaled and an appropriate SI magnitude unit will be printed in + * place of the '%s' marker. The scaling will take the '--base' argument into consideration!</p> + * + * <p>If a '%S' is used instead of a '%s', then instead of calculating + * the appropriate SI magnitude unit for this value, the previously + * calculated SI magnitude unit will be used. This is useful if you + * want all the values in a print statement to have the same SI magnitude unit. + * If there was no previous SI magnitude calculation made, + * then '%S' behaves like a '%s', unless the value is 0, in which case + * it does not remember a SI magnitude unit and a SI magnitude unit + * will only be calculated when the next '%s' is seen or the next '%S' + * for a non-zero value.</p> + * + * <p>print results are added to the graph as a legend.</p> + * + * @param srcName Virtual source name + * @param format Format string (like "average = %10.3f %s") + * @param strftime use the timestamp from the variable (true) or the numerical value (false) + */ + public void gprint(String srcName, String format, boolean strftime) { + comments.add(new PrintText(srcName, format, true, strftime)); + } + + /** + * Comment to be printed on the graph. + * + * @param text Comment text + */ + public void comment(String text) { + comments.add(new CommentText(text)); + } + + /** + * Draws a horizontal rule into the graph. + * + * @param value Position of the rule + * @param color Rule color + */ + public void hrule(double value, Paint color) { + hrule(value, color, null, 1.0F); + } + + /** + * Draws a horizontal rule into the graph and optionally adds a legend. + * + * @param value Position of the rule + * @param color Rule color + * @param legend Legend text. If null, legend text will be omitted. + */ + public void hrule(double value, Paint color, String legend) { + hrule(value, color, legend, 1.0F); + } + + /** + * Draws a horizontal rule into the graph and optionally adds a legend. + * + * @param value Position of the rule + * @param color Rule color + * @param legend Legend text. If null, legend text will be omitted. + * @param width Rule width + */ + public void hrule(double value, Paint color, String legend, float width) { + hrule(value, color, legend, new BasicStroke(width)); + } + + /** + * Draws a horizontal rule into the graph and optionally adds a legend. + * + * @param value Position of the rule + * @param color Rule color + * @param legend Legend text. If null, legend text will be omitted. + * @param stroke Rule stroke + */ + public void hrule(double value, Paint color, String legend, BasicStroke stroke) { + LegendText legendText = new LegendText(color, legend); + comments.add(legendText); + plotElements.add(new HRule(value, color, legendText, stroke)); + } + + /** + * Draws a vertical rule into the graph. + * + * @param timestamp Position of the rule (seconds since epoch) + * @param color Rule color + */ + public void vrule(long timestamp, Paint color) { + vrule(timestamp, color, null, 1.0F); + } + + /** + * Draws a vertical rule into the graph and optionally adds a legend + * + * @param timestamp Position of the rule (seconds since epoch) + * @param color Rule color + * @param legend Legend text. Use null to omit the text. + */ + public void vrule(long timestamp, Paint color, String legend) { + vrule(timestamp, color, legend, 1.0F); + } + + /** + * Draws a vertical rule into the graph and optionally adds a legend + * + * @param timestamp Position of the rule (seconds since epoch) + * @param color Rule color + * @param legend Legend text. Use null to omit the text. + * @param width Rule width + */ + public void vrule(long timestamp, Paint color, String legend, float width) { + vrule(timestamp, color, legend, new BasicStroke(width)); + } + + /** + * Draws a vertical rule into the graph and optionally adds a legend + * + * @param timestamp Position of the rule (seconds since epoch) + * @param color Rule color + * @param legend Legend text. Use null to omit the text. + * @param stroke Rule stroke + */ + public void vrule(long timestamp, Paint color, String legend, BasicStroke stroke) { + LegendText legendText = new LegendText(color, legend); + comments.add(legendText); + plotElements.add(new VRule(timestamp, color, legendText, stroke)); + } + + /** + * Draws a horizontal span into the graph. + * + * @param start Starting value of the span + * @param end Ending value of the span + * @param color Rule color + */ + public void hspan(double start, double end, Paint color) { + hspan(start, end, color, null); + } + + /** + * Draws a horizontal span into the graph and optionally adds a legend. + * + * @param start Starting value of the span + * @param end Ending value of the span + * @param color Rule color + * @param legend Legend text. Use null to omit the text. + */ + public void hspan(double start, double end, Paint color, String legend) { + LegendText legendText = new LegendText(color, legend); + comments.add(legendText); + plotElements.add(new HSpan(start, end, color, legendText)); + } + + /** + * Draws a vertical span into the graph. + * + * @param start Start time for the span (seconds since epoch) + * @param end End time for the span (seconds since epoch) + * @param color Rule color + */ + public void vspan(long start, long end, Paint color) { + vspan(start, end, color, null); + } + + /** + * Draws a vertical span into the graph and optionally adds a legend. + * + * @param start Start time for the span (seconds since epoch) + * @param end End time for the span (seconds since epoch) + * @param color Rule color + * @param legend Legend text. Use null to omit the text. + */ + public void vspan(long start, long end, Paint color, String legend) { + LegendText legendText = new LegendText(color, legend); + comments.add(legendText); + plotElements.add(new VSpan(start, end, color, legendText)); + } + + /** + * Plots requested data as a line, using the color specified. Line width is assumed to be + * 1.0F. + * + * @param srcName Virtual source name + * @param color Line color + */ + public void line(String srcName, Paint color) { + line(srcName, color, null, 1F, false); + } + + /** + * Plots requested data as a line, using the color specified. Line width is assumed to be + * 1.0F. + * + * @param srcName Virtual source name + * @param color Line color + * @param legend Legend text + */ + public void line(String srcName, Paint color, String legend) { + line(srcName, color, legend, 1F, false); + } + + + /** + * Plots requested data as a line, using the color and the line width specified. + * + * @param srcName Virtual source name + * @param color Line color + * @param width Line width (default: 1.0F) + */ + public void line(String srcName, Paint color, float width) { + line(srcName, color, null, width, false); + } + + /** + * Plots requested data as a line, using the color and the line width specified. + * + * @param srcName Virtual source name + * @param color Line color + * @param legend Legend text + * @param width Line width (default: 1.0F) + */ + public void line(String srcName, Paint color, String legend, float width) { + line(srcName, color, legend, width, false); + } + + /** + * Plots requested data as a line, using the color and the line width specified. + * + * @param srcName Virtual source name + * @param color Line color. + * @param legend Legend text. + * @param width Line width (default: 1.0F). + * @param stack true if it will be stacked. + */ + public void line(String srcName, Paint color, String legend, float width, boolean stack) { + if (legend != null) { + comments.add(new LegendText(color, legend)); + } + SourcedPlotElement parent = stack ? findParent() : null; + plotElements.add(new Line(srcName, color, new BasicStroke(width), parent)); + } + + /** + * Plots requested data as a line, using the color and the {@link java.awt.BasicStroke} specified. + * + * @param srcName Virtual source name + * @param color Line color. + * @param legend Legend text. + * @param stroke Line stroke to use. + * @param stack true if it will be stacked. + */ + public void line(String srcName, Paint color, String legend, BasicStroke stroke, boolean stack) { + if (legend != null) { + comments.add(new LegendText(color, legend)); + } + SourcedPlotElement parent = stack ? findParent() : null; + plotElements.add(new Line(srcName, color, stroke, parent)); + } + + /** + * Define a line like any other but with constant value, it can be stacked + * @param value Line position. + * @param color Line color. + * @param width Line width (default: 1.0F). + * @param stack true if it will be stacked. + */ + public void line(double value, Paint color, float width, boolean stack) { + SourcedPlotElement parent = stack ? findParent() : null; + plotElements.add(new ConstantLine(value, color, new BasicStroke(width), parent)); + } + + /** + * Define a line like any other but with constant value, it can be stacked + * @param value Line position. + * @param color Line color. + * @param stroke Line stroke to use. + * @param stack true if it will be stacked. + */ + public void line(double value, Paint color, BasicStroke stroke, boolean stack) { + SourcedPlotElement parent = stack ? findParent() : null; + plotElements.add(new ConstantLine(value, color, stroke, parent)); + } + + /** + * Plots requested data in the form of the filled area starting from zero, using + * the color specified. + * + * @param srcName Virtual source name. + * @param color Color of the filled area. + */ + public void area(String srcName, Paint color) { + area(srcName, color, null, false); + } + + /** + * Plots requested data in the form of the filled area starting from zero, using + * the color specified. + * + * @param srcName Virtual source name. + * @param color Color of the filled area. + * @param legend Legend text. + */ + public void area(String srcName, Paint color, String legend) { + area(srcName, color, legend, false); + } + + /** + * Plots requested data in the form of the filled area starting from zero, using + * the color specified. + * + * @param srcName Virtual source name. + * @param color Color of the filled area. + * @param legend Legend text. + * @param stack true if it will be stacked. + */ + public void area(String srcName, Paint color, String legend, boolean stack) { + if (legend != null) { + comments.add(new LegendText(color, legend)); + } + SourcedPlotElement parent = stack ? findParent() : null; + plotElements.add(new Area(srcName, color, parent)); + } + + /** + * Add a area like any other but with a constant value, it can be stacked like any other area + * @param value Area position + * @param color Color of the filled area. + * @param stack true if it will be stacked. + */ + public void area(double value, Paint color, boolean stack) { + SourcedPlotElement parent = stack ? findParent() : null; + plotElements.add(new ConstantArea(value, color, parent)); + } + + /** + * <p>Does the same as {@link #line(String, java.awt.Paint)}, + * but the graph gets stacked on top of the + * previous LINE, AREA or STACK graph. Depending on the type of the + * previous graph, the STACK will be either a LINE or an AREA. This + * obviously implies that the first STACK must be preceded by an AREA + * or LINE.</p> + * + * <p>Note, that when you STACK onto *UNKNOWN* data, Rrd4j will not + * draw any graphics ... *UNKNOWN* is not zero.</p> + * + * @param srcName Virtual source name + * @param color Stacked graph color + * @throws java.lang.IllegalArgumentException Thrown if this STACK has no previously defined AREA, STACK or LINE + * graph bellow it. + */ + public void stack(String srcName, Paint color) { + stack(srcName, color, null); + } + + /** + * <p>Does the same as {@link #line(String, java.awt.Paint, String)}, + * but the graph gets stacked on top of the + * previous LINE, AREA or STACK graph. Depending on the type of the + * previous graph, the STACK will be either a LINE or an AREA. This + * obviously implies that the first STACK must be preceded by an AREA + * or LINE.</p> + * + * Note, that when you STACK onto *UNKNOWN* data, Rrd4j will not + * draw any graphics ... *UNKNOWN* is not zero. + * + * @param srcName Virtual source name + * @param color Stacked graph color + * @param legend Legend text + * @throws java.lang.IllegalArgumentException Thrown if this STACK has no previously defined AREA, STACK or LINE + * graph bellow it. + */ + public void stack(String srcName, Paint color, String legend) { + SourcedPlotElement parent = findParent(); + if (legend != null) { + comments.add(new LegendText(color, legend)); + } + plotElements.add(new Stack(parent, srcName, color)); + } + + private SourcedPlotElement findParent() { + // find parent AREA or LINE + SourcedPlotElement parent = null; + for (int i = plotElements.size() - 1; i >= 0; i--) { + PlotElement plotElement = plotElements.get(i); + if (plotElement instanceof SourcedPlotElement) { + parent = (SourcedPlotElement) plotElement; + break; + } + } + if (parent == null) + throw new IllegalArgumentException("You have to stack graph onto something (line or area)"); + return parent; + } + + /** + * Sets visibility of the X-axis grid. + * + * @param drawXGrid True if X-axis grid should be created (default), false otherwise. + */ + public void setDrawXGrid(boolean drawXGrid) { + this.drawXGrid = drawXGrid; + } + + /** + * Sets visibility of the Y-axis grid. + * + * @param drawYGrid True if Y-axis grid should be created (default), false otherwise. + */ + public void setDrawYGrid(boolean drawYGrid) { + this.drawYGrid = drawYGrid; + } + + /** + * Sets image quality. Relevant only for JPEG images. + * + * @param imageQuality (0F=worst, 1F=best). + */ + public void setImageQuality(float imageQuality) { + this.imageQuality = imageQuality; + } + + /** + * Controls if the chart area of the image should be antialiased or not. + * + * @param antiAliasing use true to turn antialiasing on, false to turn it off (default) + */ + public void setAntiAliasing(boolean antiAliasing) { + this.antiAliasing = antiAliasing; + } + + /** + * Controls if the text should be antialiased or not. + * + * @param textAntiAliasing use true to turn text-antialiasing on, false to turn it off (default) + */ + public void setTextAntiAliasing(boolean textAntiAliasing) { + this.textAntiAliasing = textAntiAliasing; + } + + /** + * Sets the signature string that runs along the right-side of the graph. + * Defaults to "Generated by RRD4J". + * + * @param signature the string to print + */ + public void setSignature(String signature) { + this.signature = signature; + } + + /** + * Gets the signature string that runs along the right-side of the graph. + * + * @return the signature string + */ + public String getSignature() { + return this.signature; + } + + /** + * Shows or hides graph signature (gator) in the top right corner of the graph + * + * @param showSignature true, if signature should be seen (default), false otherwise + */ + public void setShowSignature(boolean showSignature) { + this.showSignature = showSignature; + } + + /** + * Sets first day of the week. + * + * @param firstDayOfWeek One of the following constants: + * {@link org.rrd4j.graph.RrdGraphConstants#MONDAY MONDAY}, + * {@link org.rrd4j.graph.RrdGraphConstants#TUESDAY TUESDAY}, + * {@link org.rrd4j.graph.RrdGraphConstants#WEDNESDAY WEDNESDAY}, + * {@link org.rrd4j.graph.RrdGraphConstants#THURSDAY THURSDAY}, + * {@link org.rrd4j.graph.RrdGraphConstants#FRIDAY FRIDAY}, + * {@link org.rrd4j.graph.RrdGraphConstants#SATURDAY SATURDAY}, + * {@link org.rrd4j.graph.RrdGraphConstants#SUNDAY SUNDAY} + */ + public void setFirstDayOfWeek(int firstDayOfWeek) { + this.firstDayOfWeek = firstDayOfWeek; + } + + /** + * Set the locale used for the legend. + * <p> + * + * It overides the firstDayOfWeek + * + * @param locale the locale to set + */ + public void setLocale(Locale locale) { + this.locale = locale; + this.firstDayOfWeek = Calendar.getInstance(Locale.getDefault()).getFirstDayOfWeek(); + } + + /** + * Set the time zone used for the legend. + * + * @param tz the time zone to set + */ + public void setTimeZone(TimeZone tz) { + this.tz = tz; + } + + /** + * Set the Stroke used to draw grid + * + * @param gridStroke a {@link java.awt.Stroke} object. + */ + public void setGridStroke(Stroke gridStroke) { + this.gridStroke = gridStroke; + } + + /** + * Set the stroke used to draw ticks + * + * @param tickStroke a {@link java.awt.Stroke} object. + */ + public void setTickStroke(Stroke tickStroke) { + this.tickStroke = tickStroke; + } + + /** + * Allows to set a downsampler, used to improved the visual representation of graph. + * <p> + * More details can be found on <a href="http://skemman.is/en/item/view/1946/15343">Sveinn Steinarsson's thesis</a> + * + * @param downsampler The downsampler that will be used + */ + public void setDownsampler(DownSampler downsampler) { + this.downsampler = downsampler; + } + + int printStatementCount() { + int count = 0; + for (CommentText comment : comments) { + if (comment instanceof PrintText) { + if (comment.isPrint()) { + count++; + } + } + } + return count; + } + + boolean shouldPlot() { + if (plotElements.size() > 0) { + return true; + } + for (CommentText comment : comments) { + if (comment.isValidGraphElement()) { + return true; + } + } + return false; + } + + Paint getColor(ElementsNames element) { + return colors[element.ordinal()]; + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/RrdGraphInfo.java b/apps/jrobin/java/src/org/rrd4j/graph/RrdGraphInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..1a3e73ce16b20ba4c705741271b6a3be9c6826a6 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/RrdGraphInfo.java @@ -0,0 +1,127 @@ +package org.rrd4j.graph; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +/** + * Class to represent successfully created Rrd4j graph. Objects of this class are created by method + * {@link org.rrd4j.graph.RrdGraph#getRrdGraphInfo()}. + */ +public class RrdGraphInfo { + String filename; + int width, height; + InputStream stream; + String imgInfo; + private List<String> printLines = new ArrayList<String>(); + + RrdGraphInfo() { + // cannot instantiate this class + } + + void addPrintLine(String printLine) { + printLines.add(printLine); + } + + /** + * Returns filename of the graph + * + * @return filename of the graph. '-' denotes in-memory graph (no file created) + */ + public String getFilename() { + return filename; + } + + /** + * Returns total graph width + * + * @return total graph width + */ + public int getWidth() { + return width; + } + + /** + * Returns total graph height + * + * @return total graph height + */ + public int getHeight() { + return height; + } + + /** + * Returns graph bytes + * + * @return Graph bytes + * @throws IllegalStateException if the images bytes are unavailable or can't be read + */ + public byte[] getBytes() { + try { + byte[] content = new byte[stream.available()]; + int read = stream.read(content); + if (read != content.length) { + throw new IllegalStateException("Unable to read image buffer"); + } + return content; + } catch (IOException e) { + throw new IllegalStateException("Unable to read image bytes", e); + } + } + + /** + * Returns PRINT lines requested by {@link org.rrd4j.graph.RrdGraphDef#print(String, org.rrd4j.ConsolFun, String)} method. + * + * @return An array of formatted PRINT lines + */ + public String[] getPrintLines() { + return printLines.toArray(new String[printLines.size()]); + } + + /** + * Returns image information requested by {@link org.rrd4j.graph.RrdGraphDef#setImageInfo(String)} method + * + * @return Image information + */ + public String getImgInfo() { + return imgInfo; + } + + /** + * Returns the number of bytes in the graph file + * + * @return Length of the graph file + * @throws IllegalStateException if the images bytes are unavailable + */ + public int getByteCount() { + try { + return stream.available(); + } catch (IOException e) { + throw new IllegalStateException("Unable to read image bytes", e); + } + } + + /** + * Dumps complete graph information. Useful for debugging purposes. + * + * @return String containing complete graph information + */ + public String dump() { + StringBuilder b = new StringBuilder(); + b.append("filename = \"").append(getFilename()).append("\"\n"); + b.append("width = ").append(getWidth()).append(", height = ").append(getHeight()).append("\n"); + b.append("byteCount = ").append(getByteCount()).append("\n"); + b.append("imginfo = \"").append(getImgInfo()).append("\"\n"); + String[] plines = getPrintLines(); + if (plines.length == 0) { + b.append("No print lines found\n"); + } + else { + for (int i = 0; i < plines.length; i++) { + b.append("print[").append(i).append("] = \"").append(plines[i]).append("\"\n"); + } + } + return b.toString(); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Rule.java b/apps/jrobin/java/src/org/rrd4j/graph/Rule.java new file mode 100644 index 0000000000000000000000000000000000000000..c794d73cc0402a22e260e3da4cf9e2d945742d4e --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Rule.java @@ -0,0 +1,15 @@ +package org.rrd4j.graph; + +import java.awt.BasicStroke; +import java.awt.Paint; + +class Rule extends PlotElement { + final LegendText legend; + final BasicStroke stroke; + + Rule(Paint color, LegendText legend, BasicStroke stroke) { + super(color); + this.legend = legend; + this.stroke = stroke; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/SimpleTimeLabelFormat.java b/apps/jrobin/java/src/org/rrd4j/graph/SimpleTimeLabelFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..8457a2eed3dfbda3770319a65e2de87fdb8f3003 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/SimpleTimeLabelFormat.java @@ -0,0 +1,43 @@ +package org.rrd4j.graph; + +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Locale; + +/** + * Simple time label using a format similar to {@code strftime}. For more details on the + * supported conversions see the Date/Time Conversions section for {@link java.util.Formatter}. + * Examples: + * + * <ul> + * <li>strftime pattern: {@code %Y-%m-%dT%H:%M:%S}</li> + * <li>simple date format pattern: {@code yyyy'-'MM'-'dd'T'HH':'mm':'ss}</li> + * </ul> + */ +public class SimpleTimeLabelFormat implements TimeLabelFormat { + + private final String format; + + /** + * Create a new instance using a format string that is either an strftime patter or a simple + * date format pattern. + * + * @param format + */ + public SimpleTimeLabelFormat(String format) { + // escape strftime like format string + this.format = format.replaceAll("%([^%])", "%1\\$t$1"); + } + + @Override + public String format(Calendar calendar, Locale locale) { + if (format.contains("%")) { + // strftime like format string + return String.format(locale, format, calendar); + } else { + SimpleDateFormat sdf = new SimpleDateFormat(format); + sdf.setCalendar(calendar); + return sdf.format(calendar.getTime()); + } + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Source.java b/apps/jrobin/java/src/org/rrd4j/graph/Source.java new file mode 100644 index 0000000000000000000000000000000000000000..430ea314cfb593dfa5a7d3098a5d39f35143604a --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Source.java @@ -0,0 +1,13 @@ +package org.rrd4j.graph; + +import org.rrd4j.data.DataProcessor; + +abstract class Source { + final String name; + + Source(String name) { + this.name = name; + } + + abstract void requestData(DataProcessor dproc); +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/SourcedPlotElement.java b/apps/jrobin/java/src/org/rrd4j/graph/SourcedPlotElement.java new file mode 100644 index 0000000000000000000000000000000000000000..bd00c735b9e101cee4eb561b9061202abdb8fbea --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/SourcedPlotElement.java @@ -0,0 +1,67 @@ +package org.rrd4j.graph; + +import org.rrd4j.core.Util; +import org.rrd4j.data.DataProcessor; + +import java.awt.*; + +class SourcedPlotElement extends PlotElement { + final String srcName; + final SourcedPlotElement parent; + double[] values; + + SourcedPlotElement(String srcName, Paint color) { + super(color); + this.srcName = srcName; + this.parent = null; + } + + SourcedPlotElement(String srcName, Paint color, SourcedPlotElement parent) { + super(color); + this.srcName = srcName; + this.parent = parent; + } + + void assignValues(DataProcessor dproc) { + if(parent == null) { + values = dproc.getValues(srcName); + } + else { + values = stackValues(dproc); + } + } + + double[] stackValues(DataProcessor dproc) { + double[] parentValues = parent.getValues(); + double[] procValues = dproc.getValues(srcName); + double[] stacked = new double[procValues.length]; + for (int i = 0; i < stacked.length; i++) { + if (Double.isNaN(parentValues[i])) { + stacked[i] = procValues[i]; + } + else if (Double.isNaN(procValues[i])){ + stacked[i] = parentValues[i]; + } + else { + stacked[i] = parentValues[i] + procValues[i]; + } + } + return stacked; + } + + Paint getParentColor() { + return parent != null ? parent.color : null; + } + + double[] getValues() { + return values; + } + + double getMinValue() { + return Util.min(values); + } + + double getMaxValue() { + return Util.max(values); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Span.java b/apps/jrobin/java/src/org/rrd4j/graph/Span.java new file mode 100644 index 0000000000000000000000000000000000000000..7d7ec1c7d794f69dda8bc20446a87d9e3a00ba12 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Span.java @@ -0,0 +1,12 @@ +package org.rrd4j.graph; + +import java.awt.*; + +class Span extends PlotElement { + final LegendText legend; + + Span(Paint color, LegendText legend) { + super(color); + this.legend = legend; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/Stack.java b/apps/jrobin/java/src/org/rrd4j/graph/Stack.java new file mode 100644 index 0000000000000000000000000000000000000000..9ab42e6df539c913985af743934a27bf9153aeca --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/Stack.java @@ -0,0 +1,46 @@ +package org.rrd4j.graph; + +import org.rrd4j.data.DataProcessor; + +import java.awt.*; + +class Stack extends SourcedPlotElement { + + Stack(SourcedPlotElement parent, String srcName, Paint color) { + super(srcName, color, parent); + } + + void assignValues(DataProcessor dproc) { + double[] parentValues = parent.getValues(); + double[] procValues = dproc.getValues(srcName); + values = new double[procValues.length]; + for (int i = 0; i < values.length; i++) { + if (Double.isNaN(parentValues[i])) { + values[i] = procValues[i]; + } + else if (Double.isNaN(procValues[i])){ + values[i] = parentValues[i]; + } + else { + values[i] = parentValues[i] + procValues[i]; + + } + } + } + + float getParentLineWidth() { + if (parent instanceof Line) { + return ((Line) parent).stroke.getLineWidth(); + } + else if (parent instanceof Area) { + return -1F; + } + else /* if(parent instanceof Stack) */ { + return ((Stack) parent).getParentLineWidth(); + } + } + + Paint getParentColor() { + return parent.color; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/TDef.java b/apps/jrobin/java/src/org/rrd4j/graph/TDef.java new file mode 100644 index 0000000000000000000000000000000000000000..dcddb8694d023b3b00f463723f9e6a6c7d12c4b8 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/TDef.java @@ -0,0 +1,22 @@ +package org.rrd4j.graph; + +import org.rrd4j.core.FetchData; +import org.rrd4j.data.DataProcessor; + +/** @author Mathias Bogaert */ +class TDef extends Source { + private final FetchData fetchData; + private final String dsName; + + TDef(String name, String dsName, FetchData fetchData) { + super(name); + this.dsName = dsName; + this.fetchData = fetchData; + } + + @Override + void requestData(DataProcessor dproc) { + dproc.addDatasource(name, dsName, fetchData); + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/TimeAxis.java b/apps/jrobin/java/src/org/rrd4j/graph/TimeAxis.java new file mode 100644 index 0000000000000000000000000000000000000000..2f6068c5d2dde6294b6fde8a0875b4146061b032 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/TimeAxis.java @@ -0,0 +1,211 @@ +package org.rrd4j.graph; + +import java.awt.Font; +import java.awt.Paint; +import java.util.Calendar; +import java.util.Date; + +class TimeAxis extends Axis { + private static final TimeAxisSetting[] tickSettings = { + new TimeAxisSetting(0, SECOND, 30, MINUTE, 5, MINUTE, 5, 0, HH_MM), + new TimeAxisSetting(2, MINUTE, 1, MINUTE, 5, MINUTE, 5, 0, HH_MM), + new TimeAxisSetting(5, MINUTE, 2, MINUTE, 10, MINUTE, 10, 0, HH_MM), + new TimeAxisSetting(10, MINUTE, 5, MINUTE, 20, MINUTE, 20, 0, HH_MM), + new TimeAxisSetting(30, MINUTE, 10, HOUR, 1, HOUR, 1, 0, HH_MM), + new TimeAxisSetting(60, MINUTE, 30, HOUR, 2, HOUR, 2, 0, HH_MM), + new TimeAxisSetting(180, HOUR, 1, HOUR, 6, HOUR, 6, 0, HH_MM), + new TimeAxisSetting(600, HOUR, 6, DAY, 1, DAY, 1, 24 * 3600, "EEE"), + new TimeAxisSetting(1800, HOUR, 12, DAY, 1, DAY, 2, 24 * 3600, "EEE"), + new TimeAxisSetting(3600, DAY, 1, WEEK, 1, WEEK, 1, 7 * 24 * 3600, "'Week 'w"), + new TimeAxisSetting(3 * 3600L, WEEK, 1, MONTH, 1, WEEK, 2, 7 * 24 * 3600, "'Week 'w"), + new TimeAxisSetting(6 * 3600L, MONTH, 1, MONTH, 1, MONTH, 1, 30 * 24 * 3600, "MMM"), + new TimeAxisSetting(48 * 3600L, MONTH, 1, MONTH, 3, MONTH, 3, 30 * 24 * 3600, "MMM"), + new TimeAxisSetting(10 * 24 * 3600L, YEAR, 1, YEAR, 1, YEAR, 1, 365 * 24 * 3600, "yy"), + new TimeAxisSetting(-1, MONTH, 0, MONTH, 0, MONTH, 0, 0, "") + }; + + private final ImageParameters im; + private final ImageWorker worker; + private final RrdGraphDef gdef; + private final Mapper mapper; + private TimeAxisSetting tickSetting; + + private final double secPerPix; + private final Calendar calendar; + + TimeAxis(RrdGraph rrdGraph) { + this(rrdGraph, rrdGraph.worker); + } + + /** + * Used for test + */ + TimeAxis(RrdGraph rrdGraph, ImageWorker worker) { + this.im = rrdGraph.im; + this.worker = worker; + this.gdef = rrdGraph.gdef; + this.mapper = rrdGraph.mapper; + this.secPerPix = (im.end - im.start) / (double) im.xsize; + this.calendar = Calendar.getInstance(gdef.tz, gdef.locale); + this.calendar.setFirstDayOfWeek(gdef.firstDayOfWeek); + } + + boolean draw() { + chooseTickSettings(); + // early return, avoid exceptions + if (tickSetting == null) { + return false; + } + + drawMinor(); + drawMajor(); + drawLabels(); + + return true; + } + + private void drawMinor() { + if (!gdef.noMinorGrid) { + adjustStartingTime(tickSetting.minorUnit, tickSetting.minorUnitCount); + Paint color = gdef.getColor(ElementsNames.grid); + int y0 = im.yorigin, y1 = y0 - im.ysize; + for (int status = getTimeShift(); status <= 0; status = getTimeShift()) { + if (status == 0) { + long time = calendar.getTime().getTime() / 1000L; + int x = mapper.xtr(time); + worker.drawLine(x, y0 - 1, x, y0 + 1, color, gdef.tickStroke); + worker.drawLine(x, y0, x, y1, color, gdef.gridStroke); + } + findNextTime(tickSetting.minorUnit, tickSetting.minorUnitCount); + } + } + } + + private void drawMajor() { + adjustStartingTime(tickSetting.majorUnit, tickSetting.majorUnitCount); + Paint color = gdef.getColor(ElementsNames.mgrid); + int y0 = im.yorigin, y1 = y0 - im.ysize; + for (int status = getTimeShift(); status <= 0; status = getTimeShift()) { + if (status == 0) { + long time = calendar.getTime().getTime() / 1000L; + int x = mapper.xtr(time); + worker.drawLine(x, y0 - 2, x, y0 + 2, color, gdef.tickStroke); + worker.drawLine(x, y0, x, y1, color, gdef.gridStroke); + } + findNextTime(tickSetting.majorUnit, tickSetting.majorUnitCount); + } + } + + private void drawLabels() { + Font font = gdef.getFont(FONTTAG_AXIS); + Paint color = gdef.getColor(ElementsNames.font); + adjustStartingTime(tickSetting.labelUnit, tickSetting.labelUnitCount); + int y = im.yorigin + (int) worker.getFontHeight(font) + 2; + for (int status = getTimeShift(); status <= 0; status = getTimeShift()) { + String label = tickSetting.format.format(calendar, gdef.locale); + long time = calendar.getTime().getTime() / 1000L; + int x1 = mapper.xtr(time); + int x2 = mapper.xtr(time + tickSetting.labelSpan); + int labelWidth = (int) worker.getStringWidth(label, font); + int x = x1 + (x2 - x1 - labelWidth) / 2; + if (x >= im.xorigin && x + labelWidth <= im.xorigin + im.xsize) { + worker.drawString(label, x, y, font, color); + } + findNextTime(tickSetting.labelUnit, tickSetting.labelUnitCount); + } + } + + private void findNextTime(int timeUnit, int timeUnitCount) { + switch (timeUnit) { + case SECOND: + calendar.add(Calendar.SECOND, timeUnitCount); + break; + case MINUTE: + calendar.add(Calendar.MINUTE, timeUnitCount); + break; + case HOUR: + calendar.add(Calendar.HOUR_OF_DAY, timeUnitCount); + break; + case DAY: + calendar.add(Calendar.DAY_OF_MONTH, timeUnitCount); + break; + case WEEK: + calendar.add(Calendar.DAY_OF_MONTH, 7 * timeUnitCount); + break; + case MONTH: + calendar.add(Calendar.MONTH, timeUnitCount); + break; + case YEAR: + calendar.add(Calendar.YEAR, timeUnitCount); + break; + } + } + + private int getTimeShift() { + long time = calendar.getTime().getTime() / 1000L; + return (time < im.start) ? -1 : (time > im.end) ? +1 : 0; + } + + private void adjustStartingTime(int timeUnit, int timeUnitCount) { + calendar.setTime(new Date(im.start * 1000L)); + switch (timeUnit) { + case SECOND: + calendar.add(Calendar.SECOND, -(calendar.get(Calendar.SECOND) % timeUnitCount)); + break; + case MINUTE: + calendar.set(Calendar.SECOND, 0); + calendar.add(Calendar.MINUTE, -(calendar.get(Calendar.MINUTE) % timeUnitCount)); + break; + case HOUR: + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.add(Calendar.HOUR_OF_DAY, -(calendar.get(Calendar.HOUR_OF_DAY) % timeUnitCount)); + break; + case DAY: + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.HOUR_OF_DAY, 0); + break; + case WEEK: + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.HOUR_OF_DAY, 0); + int diffDays = calendar.get(Calendar.DAY_OF_WEEK) - calendar.getFirstDayOfWeek(); + if (diffDays < 0) { + diffDays += 7; + } + calendar.add(Calendar.DAY_OF_MONTH, -diffDays); + break; + case MONTH: + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.add(Calendar.MONTH, -(calendar.get(Calendar.MONTH) % timeUnitCount)); + break; + case YEAR: + calendar.set(Calendar.SECOND, 0); + calendar.set(Calendar.MINUTE, 0); + calendar.set(Calendar.HOUR_OF_DAY, 0); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.set(Calendar.MONTH, 0); + calendar.add(Calendar.YEAR, -(calendar.get(Calendar.YEAR) % timeUnitCount)); + break; + } + } + + private void chooseTickSettings() { + if (gdef.timeAxisSetting != null) { + tickSetting = new TimeAxisSetting(gdef.timeAxisSetting); + } + else { + for (int i = 0; tickSettings[i].secPerPix >= 0 && secPerPix > tickSettings[i].secPerPix; i++) { + tickSetting = tickSettings[i]; + } + } + if (gdef.timeLabelFormat != null) { + tickSetting = tickSetting.withLabelFormat(gdef.timeLabelFormat); + } + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/TimeAxisSetting.java b/apps/jrobin/java/src/org/rrd4j/graph/TimeAxisSetting.java new file mode 100644 index 0000000000000000000000000000000000000000..0fb1cc3f567349b2f18b588ed0a7d20f8c7b92f2 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/TimeAxisSetting.java @@ -0,0 +1,57 @@ +package org.rrd4j.graph; + +class TimeAxisSetting { + final long secPerPix; + final int minorUnit, minorUnitCount, majorUnit, majorUnitCount; + final int labelUnit, labelUnitCount, labelSpan; + final TimeLabelFormat format; + + TimeAxisSetting(long secPerPix, int minorUnit, int minorUnitCount, int majorUnit, int majorUnitCount, + int labelUnit, int labelUnitCount, int labelSpan, TimeLabelFormat format) { + this.secPerPix = secPerPix; + this.minorUnit = minorUnit; + this.minorUnitCount = minorUnitCount; + this.majorUnit = majorUnit; + this.majorUnitCount = majorUnitCount; + this.labelUnit = labelUnit; + this.labelUnitCount = labelUnitCount; + this.labelSpan = labelSpan; + this.format = format; + } + + TimeAxisSetting(TimeAxisSetting s) { + this.secPerPix = s.secPerPix; + this.minorUnit = s.minorUnit; + this.minorUnitCount = s.minorUnitCount; + this.majorUnit = s.majorUnit; + this.majorUnitCount = s.majorUnitCount; + this.labelUnit = s.labelUnit; + this.labelUnitCount = s.labelUnitCount; + this.labelSpan = s.labelSpan; + this.format = s.format; + } + + TimeAxisSetting(int minorUnit, int minorUnitCount, int majorUnit, int majorUnitCount, + int labelUnit, int labelUnitCount, int labelSpan, TimeLabelFormat format) { + this(0, minorUnit, minorUnitCount, majorUnit, majorUnitCount, + labelUnit, labelUnitCount, labelSpan, format); + } + + TimeAxisSetting(long secPerPix, int minorUnit, int minorUnitCount, int majorUnit, int majorUnitCount, + int labelUnit, int labelUnitCount, int labelSpan, String format) { + this(secPerPix, minorUnit, minorUnitCount, majorUnit, majorUnitCount, + labelUnit, labelUnitCount, labelSpan, new SimpleTimeLabelFormat(format)); + } + + TimeAxisSetting(int minorUnit, int minorUnitCount, int majorUnit, int majorUnitCount, + int labelUnit, int labelUnitCount, int labelSpan, String format) { + this(0, minorUnit, minorUnitCount, majorUnit, majorUnitCount, + labelUnit, labelUnitCount, labelSpan, new SimpleTimeLabelFormat(format)); + } + + TimeAxisSetting withLabelFormat(TimeLabelFormat f) { + return new TimeAxisSetting( + secPerPix, minorUnit, minorUnitCount, majorUnit, majorUnitCount, + labelUnit, labelUnitCount, labelSpan, f); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/TimeLabelFormat.java b/apps/jrobin/java/src/org/rrd4j/graph/TimeLabelFormat.java new file mode 100644 index 0000000000000000000000000000000000000000..4f7a2d33e646eb490d3c242fe79a4624b08182e1 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/TimeLabelFormat.java @@ -0,0 +1,19 @@ +package org.rrd4j.graph; + +import java.util.Calendar; +import java.util.Locale; + +/** + * Simplified version of DateFormat for just defining how to map a timestamp into a label for + * presentation. + */ +public interface TimeLabelFormat { + /** + * Format a timestamp. + * + * @param calendar calendar to use for the formatter + * @param locale locale that will be used with {@code String.format} + * @return formatted string for the timestamp + */ + String format(Calendar calendar, Locale locale); +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/VDef.java b/apps/jrobin/java/src/org/rrd4j/graph/VDef.java new file mode 100644 index 0000000000000000000000000000000000000000..6161020a9e98d5e84b046ae5a6bef1bc8451115e --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/VDef.java @@ -0,0 +1,20 @@ +package org.rrd4j.graph; + +import org.rrd4j.data.DataProcessor; +import org.rrd4j.data.Variable; + +class VDef extends Source { + private final String defName; + private final Variable var; + + VDef(String name, String defName, Variable var) { + super(name); + this.defName = defName; + this.var = var; + } + + void requestData(DataProcessor dproc) { + dproc.addDatasource(name, defName, var); + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/VRule.java b/apps/jrobin/java/src/org/rrd4j/graph/VRule.java new file mode 100644 index 0000000000000000000000000000000000000000..12f1d6f59cd350114d5729f7cc16fea623a32aa6 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/VRule.java @@ -0,0 +1,17 @@ +package org.rrd4j.graph; + +import java.awt.BasicStroke; +import java.awt.Paint; + +class VRule extends Rule { + final long timestamp; + + VRule(long timestamp, Paint color, LegendText legend, BasicStroke stroke) { + super(color, legend, stroke); + this.timestamp = timestamp; + } + + void setLegendVisibility(long minval, long maxval, boolean forceLegend) { + legend.enabled &= (forceLegend || (timestamp >= minval && timestamp <= maxval)); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/VSpan.java b/apps/jrobin/java/src/org/rrd4j/graph/VSpan.java new file mode 100644 index 0000000000000000000000000000000000000000..1e4b6339b2742f292ac4f235624bbfe317767acc --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/VSpan.java @@ -0,0 +1,25 @@ +package org.rrd4j.graph; + +import java.awt.Paint; + +class VSpan extends Span { + final long start; + final long end; + + VSpan(long start, long end, Paint color, LegendText legend) { + super(color, legend); + this.start = start; + this.end = end; + assert(start < end); + } + + private boolean checkRange(long v, long min, long max) { + return v >= min && v <= max; + } + + void setLegendVisibility(long min, long max, boolean forceLegend) { + legend.enabled = legend.enabled && (forceLegend + || checkRange(start, min, max) + || checkRange(end, min, max)); + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ValueAxis.java b/apps/jrobin/java/src/org/rrd4j/graph/ValueAxis.java new file mode 100644 index 0000000000000000000000000000000000000000..d97c3f932d8ac36af36d76853f55b06160c06962 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ValueAxis.java @@ -0,0 +1,249 @@ +package org.rrd4j.graph; + +import java.awt.Font; +import java.awt.Paint; + +import org.rrd4j.core.Util; + +class ValueAxis extends Axis { + private static final YLabel[] ylabels = { + new YLabel(0.1, 1, 2, 5, 10), + new YLabel(0.2, 1, 5, 10, 20), + new YLabel(0.5, 1, 2, 4, 10), + new YLabel(1.0, 1, 2, 5, 10), + new YLabel(2.0, 1, 5, 10, 20), + new YLabel(5.0, 1, 2, 4, 10), + new YLabel(10.0, 1, 2, 5, 10), + new YLabel(20.0, 1, 5, 10, 20), + new YLabel(50.0, 1, 2, 4, 10), + new YLabel(100.0, 1, 2, 5, 10), + new YLabel(200.0, 1, 5, 10, 20), + new YLabel(500.0, 1, 2, 4, 10), + new YLabel(1000.0, 1, 2, 5, 10), + new YLabel(2000.0, 1, 5, 10, 20), + new YLabel(5000.0, 1, 2, 4, 10), + new YLabel(10000.0, 1, 2, 5, 10), + new YLabel(20000.0, 1, 5, 10, 20), + new YLabel(50000.0, 1, 2, 4, 10), + new YLabel(100000.0, 1, 2, 5, 10), + new YLabel(0.0, 0, 0, 0, 0) + }; + + private final ImageParameters im; + private final ImageWorker worker; + private final RrdGraphDef gdef; + private final Mapper mapper; + + ValueAxis(RrdGraph rrdGraph) { + this(rrdGraph, rrdGraph.worker); + } + + ValueAxis(RrdGraph rrdGraph, ImageWorker worker) { + this.im = rrdGraph.im; + this.gdef = rrdGraph.gdef; + this.worker = worker; + this.mapper = rrdGraph.mapper; + } + + boolean draw() { + Font font = gdef.getFont(FONTTAG_AXIS); + Paint gridColor = gdef.getColor(ElementsNames.grid); + Paint mGridColor = gdef.getColor(ElementsNames.mgrid); + Paint fontColor = gdef.getColor(ElementsNames.font); + int labelOffset = (int) (worker.getFontAscent(font) / 2); + int labfact; + double range = im.maxval - im.minval; + double scaledrange = range / im.magfact; + double gridstep; + if (Double.isNaN(scaledrange)) { + return false; + } + String labfmt = null; + if (Double.isNaN(im.ygridstep)) { + if (gdef.altYGrid) { + /* find the value with max number of digits. Get number of digits */ + int decimals = (int) Math.ceil(Math.log10(Math.max(Math.abs(im.maxval), + Math.abs(im.minval)))); + if (decimals <= 0) /* everything is small. make place for zero */ { + decimals = 1; + } + int fractionals = (int) Math.floor(Math.log10(range)); + if (fractionals < 0) /* small amplitude. */ { + labfmt = Util.sprintf(gdef.locale, "%%%d.%df", decimals - fractionals + 1, -fractionals + 1); + } + else { + labfmt = Util.sprintf(gdef.locale, "%%%d.1f", decimals + 1); + } + gridstep = Math.pow(10, fractionals); + if (gridstep == 0) /* range is one -> 0.1 is reasonable scale */ { + gridstep = 0.1; + } + /* should have at least 5 lines but no more then 15 */ + if (range / gridstep < 5) { + gridstep /= 10; + } + if (range / gridstep > 15) { + gridstep *= 10; + } + if (range / gridstep > 5) { + labfact = 1; + if (range / gridstep > 8) { + labfact = 2; + } + } + else { + gridstep /= 5; + labfact = 5; + } + } + else { + //Start looking for a minimum of 3 labels, but settle for 2 or 1 if need be + int minimumLabelCount = 3; + YLabel selectedYLabel = null; + while(selectedYLabel == null) { + selectedYLabel = findYLabel(minimumLabelCount); + minimumLabelCount--; + } + gridstep = selectedYLabel.grid * im.magfact; + labfact = findLabelFactor(selectedYLabel); + } + } + else { + gridstep = im.ygridstep; + labfact = im.ylabfact; + } + int x0 = im.xorigin, x1 = x0 + im.xsize; + int sgrid = (int) (im.minval / gridstep - 1); + int egrid = (int) (im.maxval / gridstep + 1); + double scaledstep = gridstep / im.magfact; + for (int i = sgrid; i <= egrid; i++) { + int y = mapper.ytr(gridstep * i); + if (y >= im.yorigin - im.ysize && y <= im.yorigin) { + if (i % labfact == 0) { + String graph_label; + if (i == 0 || im.symbol == ' ') { + if (scaledstep < 1) { + if (i != 0 && gdef.altYGrid) { + graph_label = Util.sprintf(gdef.locale, labfmt, scaledstep * i); + } + else { + graph_label = Util.sprintf(gdef.locale, "%4.1f", scaledstep * i); + } + } + else { + graph_label = Util.sprintf(gdef.locale, "%4.0f", scaledstep * i); + } + } + else { + if (scaledstep < 1) { + graph_label = Util.sprintf(gdef.locale, "%4.1f %c", scaledstep * i, im.symbol); + } + else { + graph_label = Util.sprintf(gdef.locale, "%4.0f %c", scaledstep * i, im.symbol); + } + } + int length = (int) (worker.getStringWidth(graph_label, font)); + worker.drawString(graph_label, x0 - length - PADDING_VLABEL, y + labelOffset, font, fontColor); + worker.drawLine(x0 - 2, y, x0 + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(x1 - 2, y, x1 + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(x0, y, x1, y, mGridColor, gdef.gridStroke); + } + else if (!(gdef.noMinorGrid)) { + worker.drawLine(x0 - 1, y, x0 + 1, y, gridColor, gdef.tickStroke); + worker.drawLine(x1 - 1, y, x1 + 1, y, gridColor, gdef.tickStroke); + worker.drawLine(x0, y, x1, y, gridColor, gdef.gridStroke); + } + } + } + return true; + } + + /** + * Finds an acceptable YLabel object for the current graph + * If the graph covers positive and negative on the y-axis, then + * desiredMinimumLabelCount is checked as well, to ensure the chosen YLabel definition + * will result in the required number of labels + * + * Returns null if none are acceptable (none the right size or with + * enough labels) + */ + private YLabel findYLabel(int desiredMinimumLabelCount) { + double scaledrange = this.getScaledRange(); + int labelFactor; + //Check each YLabel definition to see if it's acceptable + for (int i = 0; ylabels[i].grid > 0; i++) { + YLabel thisYLabel = ylabels[i]; + //First cut is whether this gridstep would give enough space per gridline + if (this.getPixelsPerGridline(thisYLabel) > 5 ) { + //Yep; now we might have to check the number of labels + if(im.minval < 0.0 && im.maxval > 0.0) { + //The graph covers positive and negative values, so we need the + // desiredMinimumLabelCount number of labels, which is going to + // usually be 3, then maybe 2, then only as a last resort, 1. + // So, we need to find out what the label factor would be + // if we chose this ylab definition + labelFactor = findLabelFactor(thisYLabel); + if(labelFactor == -1) { + //Default to too many to satisfy the label count test, unless we're looking for just 1 + // in which case be sure to satisfy the label count test + labelFactor = desiredMinimumLabelCount==1?1:desiredMinimumLabelCount+1; + } + //Adding one? Think fenceposts (need one more than just dividing length by space between) + int labelCount = ((int)(scaledrange/thisYLabel.grid)/labelFactor)+1; + if(labelCount > desiredMinimumLabelCount) { + return thisYLabel; //Enough pixels, *and* enough labels + } + + } else { + //Only positive or negative on the graph y-axis. No need to + // care about the label count. + return thisYLabel; + } + } + } + + double val = 1; + while(val < scaledrange) { + val = val * 10; + } + return new YLabel(val/10, 1, 2, 5, 10); + } + + /** + * Find the smallest labelFactor acceptable (can fit labels) for the given YLab definition + * Returns the label factor if one is ok, otherwise returns -1 if none are acceptable + */ + private int findLabelFactor(YLabel thisYLabel) { + int pixel = this.getPixelsPerGridline(thisYLabel); + int fontHeight = (int) Math.ceil(worker.getFontHeight(gdef.getFont(FONTTAG_AXIS))); + for (int j = 0; j < 4; j++) { + if (pixel * thisYLabel.labelFacts[j] >= 2 * fontHeight) { + return thisYLabel.labelFacts[j]; + } + } + return -1; + } + + /** + * Finds the number of pixels per gridline that the given YLabel definition will result in + */ + private int getPixelsPerGridline(YLabel thisYLabel) { + double scaledrange = this.getScaledRange(); + return (int) (im.ysize / (scaledrange / thisYLabel.grid)); + } + + private double getScaledRange() { + double range = im.maxval - im.minval; + return range / im.magfact; + } + + static class YLabel { + final double grid; + final int[] labelFacts; + + YLabel(double grid, int lfac1, int lfac2, int lfac3, int lfac4) { + this.grid = grid; + labelFacts = new int[]{lfac1, lfac2, lfac3, lfac4}; + } + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ValueAxisLogarithmic.java b/apps/jrobin/java/src/org/rrd4j/graph/ValueAxisLogarithmic.java new file mode 100644 index 0000000000000000000000000000000000000000..fca83a5ae1f035582e0a5f54ccdf5414a68e198f --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ValueAxisLogarithmic.java @@ -0,0 +1,195 @@ +package org.rrd4j.graph; + +import org.rrd4j.core.Util; + +import java.awt.*; + +class ValueAxisLogarithmic extends Axis { + private static final double[][] yloglab = { + {1e9, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1e3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1e1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {1e1, 1, 2.5, 5, 7.5, 0, 0, 0, 0, 0, 0, 0}, + {1e1, 1, 2, 4, 6, 8, 0, 0, 0, 0, 0, 0}, + {1e1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + }; + + private final ImageParameters im; + private final ImageWorker worker; + private final RrdGraphDef gdef; + private final int fontHeight; + private final Mapper mapper; + + ValueAxisLogarithmic(RrdGraph rrdGraph) { + this(rrdGraph, rrdGraph.worker); + } + + ValueAxisLogarithmic(RrdGraph rrdGraph, ImageWorker worker) { + this.im = rrdGraph.im; + this.gdef = rrdGraph.gdef; + this.worker = worker; + this.fontHeight = (int) Math.ceil(worker.getFontHeight(gdef.getFont(FONTTAG_AXIS))); + this.mapper = rrdGraph.mapper; + } + + boolean draw() { + Font font = gdef.getFont(FONTTAG_AXIS); + Paint gridColor = gdef.getColor(ElementsNames.grid); + Paint mGridColor = gdef.getColor(ElementsNames.mgrid); + Paint fontColor = gdef.getColor(ElementsNames.font); + int labelOffset = (int) (worker.getFontAscent(font) / 2); + + if (im.maxval == im.minval) { + return false; + } + double pixpex = (double) im.ysize / (log10(im.maxval) - log10(im.minval)); + if (Double.isNaN(pixpex)) { + return false; + } + double minstep, pixperstep; + int minoridx = 0, majoridx = 0; + for (int i = 0; yloglab[i][0] > 0; i++) { + minstep = log10(yloglab[i][0]); + for (int ii = 1; yloglab[i][ii + 1] > 0; ii++) { + if (yloglab[i][ii + 2] == 0) { + minstep = log10(yloglab[i][ii + 1]) - log10(yloglab[i][ii]); + break; + } + } + pixperstep = pixpex * minstep; + if (pixperstep > 5) { + minoridx = i; + } + if (pixperstep > 2 * fontHeight) { + majoridx = i; + } + } + + // Draw minor grid for positive values + double positiveMin = (im.minval > 0.0) ? im.minval : 0.0; + int x0 = im.xorigin, x1 = x0 + im.xsize; + if (yloglab[minoridx][0] == 0 || yloglab[majoridx][0] == 0) { + return false; + } + for (double value = Math.pow(10, log10(positiveMin) + - log10(positiveMin) % log10(yloglab[minoridx][0])); + value <= im.maxval; + value *= yloglab[minoridx][0]) { + if (value < positiveMin) continue; + int i = 0; + while (yloglab[minoridx][++i] > 0) { + int y = mapper.ytr(value * yloglab[minoridx][i]); + if (y <= im.yorigin - im.ysize) { + break; + } + worker.drawLine(x0 - 1, y, x0 + 1, y, gridColor, gdef.tickStroke); + worker.drawLine(x1 - 1, y, x1 + 1, y, gridColor, gdef.tickStroke); + worker.drawLine(x0, y, x1, y, gridColor, gdef.gridStroke); + } + } + + // Draw minor grid for negative values + double negativeMin = -1.0 * ((im.maxval < 0.0) ? im.maxval : 0.0); + for (double value = Math.pow(10, log10(negativeMin) + - log10(negativeMin) % log10(yloglab[minoridx][0])); + value <= -1.0 * im.minval; + value *= yloglab[minoridx][0]) { + if (value < negativeMin) continue; + int i = 0; + while (yloglab[minoridx][++i] > 0) { + int y = mapper.ytr(-1.0 * value * yloglab[minoridx][i]); + if (y <= im.yorigin - im.ysize) { + break; + } + worker.drawLine(x0 - 1, y, x0 + 1, y, gridColor, gdef.tickStroke); + worker.drawLine(x1 - 1, y, x1 + 1, y, gridColor, gdef.tickStroke); + worker.drawLine(x0, y, x1, y, gridColor, gdef.gridStroke); + } + } + + // If it has positive and negative, always have a tick mark at 0 + boolean skipFirst = false; + if (im.minval < 0.0 && im.maxval > 0.0) { + skipFirst = true; + int y = mapper.ytr(0.0); + worker.drawLine(x0 - 2, y, x0 + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(x1 - 2, y, x1 + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(x0, y, x1, y, mGridColor, gdef.gridStroke); + String graph_label = Util.sprintf(gdef.locale, "%3.0e", 0.0); + int length = (int) (worker.getStringWidth(graph_label, font)); + worker.drawString(graph_label, x0 - length - PADDING_VLABEL, y + labelOffset, font, fontColor); + } + + // Draw major grid for positive values + int iter = 0; + for (double value = Math.pow(10, log10(positiveMin) + - (log10(positiveMin) % log10(yloglab[majoridx][0]))); + value <= im.maxval; + value *= yloglab[majoridx][0]) { + if (value < positiveMin) { + continue; + } + ++iter; + if (skipFirst && iter == 1) { + continue; + } + int i = 0; + while (yloglab[majoridx][++i] > 0) { + int y = mapper.ytr(value * yloglab[majoridx][i]); + if (y <= im.yorigin - im.ysize) { + break; + } + worker.drawLine(x0 - 2, y, x0 + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(x1 - 2, y, x1 + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(x0, y, x1, y, mGridColor, gdef.gridStroke); + String graph_label = Util.sprintf(gdef.locale, "%3.0e", value * yloglab[majoridx][i]); + int length = (int) (worker.getStringWidth(graph_label, font)); + worker.drawString(graph_label, x0 - length - PADDING_VLABEL, y + labelOffset, font, fontColor); + } + } + + // Draw major grid for negative values + iter = 0; + for (double value = Math.pow(10, log10(negativeMin) + - (log10(negativeMin) % log10(yloglab[majoridx][0]))); + value <= -1.0 * im.minval; + value *= yloglab[majoridx][0]) { + if (value < negativeMin) { + continue; + } + ++iter; + if (skipFirst && iter == 1) { + continue; + } + int i = 0; + while (yloglab[majoridx][++i] > 0) { + int y = mapper.ytr(-1.0 * value * yloglab[majoridx][i]); + if (y <= im.yorigin - im.ysize) { + break; + } + worker.drawLine(x0 - 2, y, x0 + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(x1 - 2, y, x1 + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(x0, y, x1, y, mGridColor, gdef.gridStroke); + String graph_label = Util.sprintf(gdef.locale, "%3.0e", -1.0 * value * yloglab[majoridx][i]); + int length = (int) (worker.getStringWidth(graph_label, font)); + worker.drawString(graph_label, x0 - length - PADDING_VLABEL, y + labelOffset, font, fontColor); + } + } + + return true; + } + + /** + * Compute logarithm for the purposes of y-axis. + */ + static double log10(double v) { + double lv = Math.log10(Math.abs(v)); + if (lv < 0) { + // Don't cross the sign line, round to 0 if that's the case + return 0.0; + } else { + return Math.copySign(lv, v); + } + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ValueAxisMrtg.java b/apps/jrobin/java/src/org/rrd4j/graph/ValueAxisMrtg.java new file mode 100644 index 0000000000000000000000000000000000000000..2da2f397bc93a78cde30dcc811f83dca606aa89f --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ValueAxisMrtg.java @@ -0,0 +1,66 @@ +package org.rrd4j.graph; + +import org.rrd4j.core.Util; + +import java.awt.*; + +class ValueAxisMrtg extends Axis { + + private final ImageParameters im; + private final ImageWorker worker; + private final RrdGraphDef gdef; + + ValueAxisMrtg(RrdGraph rrdGraph) { + this(rrdGraph, rrdGraph.worker); + } + + ValueAxisMrtg(RrdGraph rrdGraph, ImageWorker worker) { + this.im = rrdGraph.im; + this.gdef = rrdGraph.gdef; + this.worker = worker; + im.unit = gdef.unit; + } + + boolean draw() { + Font font = gdef.getFont(FONTTAG_AXIS); + Paint mGridColor = gdef.getColor(ElementsNames.mgrid); + Paint fontColor = gdef.getColor(ElementsNames.font); + int labelOffset = (int) (worker.getFontAscent(font) / 2); + + if (Double.isNaN((im.maxval - im.minval) / im.magfact)) { + return false; + } + + int xLeft = im.xorigin; + int xRight = im.xorigin + im.xsize; + String labfmt; + if (im.scaledstep / im.magfact * Math.max(Math.abs(im.quadrant), Math.abs(4 - im.quadrant)) <= 1.0) { + labfmt = "%5.2f"; + } + else { + labfmt = Util.sprintf(gdef.locale, "%%4.%df", 1 - ((im.scaledstep / im.magfact > 10.0 || Math.ceil(im.scaledstep / im.magfact) == im.scaledstep / im.magfact) ? 1 : 0)); + } + if (im.symbol != ' ' || im.unit != null) { + labfmt += " "; + } + if (im.symbol != ' ') { + labfmt += Character.toString(im.symbol); + } + if (im.unit != null) { + labfmt += im.unit; + } + for (int i = 0; i <= 4; i++) { + int y = im.yorigin - im.ysize * i / 4; + if (y >= im.yorigin - im.ysize && y <= im.yorigin) { + String graph_label = Util.sprintf(gdef.locale, labfmt, im.scaledstep / im.magfact * (i - im.quadrant)); + int length = (int) (worker.getStringWidth(graph_label, font)); + worker.drawString(graph_label, xLeft - length - PADDING_VLABEL, y + labelOffset, font, fontColor); + worker.drawLine(xLeft - 2, y, xLeft + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(xRight - 2, y, xRight + 2, y, mGridColor, gdef.tickStroke); + worker.drawLine(xLeft, y, xRight, y, mGridColor, gdef.gridStroke); + } + } + return true; + } + +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ValueAxisSetting.java b/apps/jrobin/java/src/org/rrd4j/graph/ValueAxisSetting.java new file mode 100644 index 0000000000000000000000000000000000000000..53fdcef9f69babb18db970d7a0aa9046d6d866d7 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ValueAxisSetting.java @@ -0,0 +1,11 @@ +package org.rrd4j.graph; + +class ValueAxisSetting { + final double gridStep; + final int labelFactor; + + ValueAxisSetting(double gridStep, int labelFactor) { + this.gridStep = gridStep; + this.labelFactor = labelFactor; + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/ValueScaler.java b/apps/jrobin/java/src/org/rrd4j/graph/ValueScaler.java new file mode 100644 index 0000000000000000000000000000000000000000..1068365d9d3e50b6b2e03cdada97bf0544b8c108 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/ValueScaler.java @@ -0,0 +1,70 @@ +package org.rrd4j.graph; + +class ValueScaler { + static final String UNIT_UNKNOWN = "?"; + static final String UNIT_SYMBOLS[] = { + "a", "f", "p", "n", "u", "m", " ", "k", "M", "G", "T", "P", "E" + }; + static final int SYMB_CENTER = 6; + + private final double base; + private double magfact = -1; // nothing scaled before, rescale + private String unit; + + ValueScaler(double base) { + this.base = base; + } + + Scaled scale(double value, boolean mustRescale) { + Scaled scaled; + if (mustRescale) { + scaled = rescale(value); + } + else if (magfact >= 0) { + // already scaled, need not rescale + scaled = new Scaled(value / magfact, unit); + } + else { + // scaling not requested, but never scaled before - must rescale anyway + scaled = rescale(value); + // if zero, scale again on the next try + if (scaled.value == 0.0 || Double.isNaN(scaled.value)) { + magfact = -1.0; + } + } + return scaled; + } + + private Scaled rescale(double value) { + int sindex; + if (value == 0.0 || Double.isNaN(value)) { + sindex = 0; + magfact = 1.0; + } + else { + sindex = (int) (Math.floor(Math.log(Math.abs(value)) / Math.log(base))); + magfact = Math.pow(base, sindex); + } + if (sindex <= SYMB_CENTER && sindex >= -SYMB_CENTER) { + unit = UNIT_SYMBOLS[sindex + SYMB_CENTER]; + } + else { + unit = UNIT_UNKNOWN; + } + return new Scaled(value / magfact, unit); + } + + static class Scaled { + double value; + String unit; + + public Scaled(double value, String unit) { + this.value = value; + this.unit = unit; + } + + void dump() { + System.out.println("[" + value + unit + "]"); + } + } +} diff --git a/apps/jrobin/java/src/org/rrd4j/graph/package-info.java b/apps/jrobin/java/src/org/rrd4j/graph/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..3174ae25713c696e4c1313a5ac64a90b7f497ee4 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/graph/package-info.java @@ -0,0 +1,4 @@ +/** + * RRD4J graph capabilities. + */ +package org.rrd4j.graph; diff --git a/apps/jrobin/java/src/org/rrd4j/package-info.java b/apps/jrobin/java/src/org/rrd4j/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..6ed9a528458736059943fc0b08dd36e28ba86577 --- /dev/null +++ b/apps/jrobin/java/src/org/rrd4j/package-info.java @@ -0,0 +1,22 @@ +/** + * RRD4J is a high performance data logging and graphing system for time series data, implementing + * RRDTool's functionality in Java. It follows much of the same logic and uses the same data sources, + * archive types and definitions as RRDTool does. + * <p> + * RRD4J supports all standard operations on Round Robin Database (RRD) files: CREATE, UPDATE, FETCH, + * LAST, DUMP, XPORT and GRAPH. RRD4J's API is made for those who are familiar with RRDTool's concepts + * and logic, but prefer to work with pure java. If you provide the same data to RRDTool and RRD4J, + * you will get very similar results and graphs. + * <p> + * RRD4J does not use native functions and libraries, has no Runtime.exec() calls and does not require + * RRDTool to be present. RRD4J is distributed as a software library (jar files) and comes with full + * java source code (Apache License 2.0). + * <p> + * You will not understand a single thing here if you are not already familiar with RRDTool. Basic + * concepts and terms (such as: datasource, archive, datasource type, consolidation functions, archive steps/rows, + * heartbeat, RRD step, RPN, graph DEFs and CDEFs) are not explained here because they have exactly the same + * meaning in RRD4J and RRDTool. If you are a novice RRDTool/RRD4J user, + * <a href="http://oss.oetiker.ch/rrdtool/tut/rrdtutorial.en.html">this annotated RRDTool tutorial</a> is a + * good place to start. A, <a href="https://github.com/rrd4j/rrd4j/wiki/Tutorial">adapted version</a> for RRD4J is available + */ +package org.rrd4j; diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java index 8e8619a498d8dada3400bf001a9c4af0cbeba42c..9b06a16bba6d1173a406d0cc0fcfb422badaa6de 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryListener.java @@ -13,14 +13,16 @@ import net.i2p.util.Log; import net.i2p.util.SecureFile; import net.i2p.util.SecureFileOutputStream; -import org.jrobin.core.Archive; -import org.jrobin.core.RrdBackendFactory; -import org.jrobin.core.RrdDb; -import org.jrobin.core.RrdDef; -import org.jrobin.core.RrdException; -import org.jrobin.core.RrdMemoryBackendFactory; -import org.jrobin.core.RrdNioBackendFactory; -import org.jrobin.core.Sample; +import org.rrd4j.ConsolFun; +import org.rrd4j.DsType; +import org.rrd4j.core.Archive; +import org.rrd4j.core.RrdBackendFactory; +import org.rrd4j.core.RrdDb; +import org.rrd4j.core.RrdDef; +import org.rrd4j.core.RrdException; +import org.rrd4j.core.RrdMemoryBackendFactory; +import org.rrd4j.core.RrdNioBackendFactory; +import org.rrd4j.core.Sample; /** * Creates and updates the in-memory or on-disk RRD database, @@ -35,7 +37,8 @@ public class SummaryListener implements RateSummaryListener { static final String RRD_DIR = "rrd"; private static final String RRD_PREFIX = "rrd-"; private static final String RRD_SUFFIX = ".jrb"; - static final String CF = "AVERAGE"; + static final ConsolFun CF = ConsolFun.AVERAGE; + static final DsType DS = DsType.GAUGE; private static final double XFF = 0.9d; private static final int STEPS = 1; @@ -88,14 +91,14 @@ public class SummaryListener implements RateSummaryListener { stopListening(); if (path != null) (new File(path)).delete(); - } catch (IOException ioe) { - _log.error("Error adding", ioe); - stopListening(); } catch (RrdException re) { // this can happen after the time slews backwards, so don't make it an error // org.jrobin.core.RrdException: Bad sample timestamp 1264343107. Last update time was 1264343172, at least one second step is required if (_log.shouldLog(Log.WARN)) _log.warn("Error adding", re); + } catch (IOException ioe) { + _log.error("Error adding", ioe); + stopListening(); } } } @@ -149,8 +152,8 @@ public class SummaryListener implements RateSummaryListener { // for info on the heartbeat, xff, steps, etc, see the rrdcreate man page, aka // http://www.jrobin.org/support/man/rrdcreate.html long heartbeat = period*10/1000; - def.addDatasource(_name, "GAUGE", heartbeat, Double.NaN, Double.NaN); - def.addDatasource(_eventName, "GAUGE", heartbeat, 0, Double.NaN); + def.addDatasource(_name, DS, heartbeat, Double.NaN, Double.NaN); + def.addDatasource(_eventName, DS, heartbeat, 0, Double.NaN); if (_isPersistent) { _rows = (int) Math.max(MIN_ROWS, Math.min(MAX_ROWS, THREE_MONTHS / period)); } else { @@ -187,6 +190,7 @@ public class SummaryListener implements RateSummaryListener { "\nContact packager."; _log.log(Log.CRIT, s); System.out.println(s); + StatSummarizer.setDisabled(_context); } catch (Throwable t) { _log.error("Error starting RRD for stat " + baseName, t); } @@ -203,9 +207,7 @@ public class SummaryListener implements RateSummaryListener { _rate.setSummaryListener(null); if (!_isPersistent) { // close() does not release resources for memory backend - try { - ((RrdMemoryBackendFactory)RrdBackendFactory.getFactory(RrdMemoryBackendFactory.NAME)).delete(_db.getPath()); - } catch (RrdException re) {} + ((RrdMemoryBackendFactory)RrdBackendFactory.getFactory("MEMORY")).delete(_db.getPath()); } _db = null; } @@ -254,7 +256,7 @@ public class SummaryListener implements RateSummaryListener { /** @since 0.8.7 */ String getBackendName() { - return _isPersistent ? RrdNioBackendFactory.NAME : RrdMemoryBackendFactory.NAME; + return _isPersistent ? "NIO" : "MEMORY"; } /** @since 0.8.7 */ diff --git a/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java index 02a53e2db666a5aafa1ed97e8d7e189222728b9c..fb25b133470ccbfd2c565f0860da515a21aeb4f2 100644 --- a/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java +++ b/apps/routerconsole/java/src/net/i2p/router/web/SummaryRenderer.java @@ -1,8 +1,10 @@ package net.i2p.router.web; +import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; +import java.awt.Stroke; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.OutputStream; @@ -22,9 +24,11 @@ import static net.i2p.router.web.GraphConstants.*; import net.i2p.util.Log; import net.i2p.util.SystemVersion; -import org.jrobin.core.RrdException; -import org.jrobin.graph.RrdGraph; -import org.jrobin.graph.RrdGraphDef; +import org.rrd4j.ConsolFun; +import org.rrd4j.core.RrdException; +import org.rrd4j.graph.ElementsNames; +import org.rrd4j.graph.RrdGraph; +import org.rrd4j.graph.RrdGraphDef; /** * Generate the RRD graph png images, @@ -46,6 +50,8 @@ class SummaryRenderer { private static final Color AREA_COLOR = new Color(100, 160, 200, 200); private static final Color LINE_COLOR = new Color(0, 30, 110, 255); private static final Color RESTART_BAR_COLOR = new Color(223, 13, 13, 255); + // hide the arrow, full transparent + private static final Color ARROW_COLOR = new Color(0, 0, 0, 0); private static final boolean IS_WIN = SystemVersion.isWindows(); private static final String DEFAULT_FONT_NAME = IS_WIN ? "Lucida Console" : "Monospaced"; @@ -58,6 +64,8 @@ class SummaryRenderer { private static final int SIZE_LEGEND = 10; private static final int SIZE_TITLE = 13; private static final long[] RATES = new long[] { 60*60*1000 }; + // dotted line + private static final Stroke GRID_STROKE = new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER, 1, new float[] {1, 1}, 0); public SummaryRenderer(I2PAppContext ctx, SummaryListener lsnr) { _log = ctx.logManager().getLog(SummaryRenderer.class); @@ -78,35 +86,6 @@ class SummaryRenderer { @Deprecated public static synchronized void render(I2PAppContext ctx, OutputStream out, String filename) throws IOException { throw new UnsupportedOperationException(); -/***** - long end = ctx.clock().now() - 60*1000; - long start = end - 60*1000*SummaryListener.PERIODS; - try { - RrdGraphDefTemplate template = new RrdGraphDefTemplate(filename); - RrdGraphDef def = template.getRrdGraphDef(); - def.setTimeSpan(start/1000, end/1000); // ignore the periods in the template - // FIXME not clear how to get the height and width from the template - int width = DEFAULT_X; - int height = DEFAULT_Y; - def.setWidth(width); - def.setHeight(height); - - RrdGraph graph = new RrdGraph(def); - int totalWidth = graph.getRrdGraphInfo().getWidth(); - int totalHeight = graph.getRrdGraphInfo().getHeight(); - BufferedImage img = new BufferedImage(totalWidth, totalHeight, BufferedImage.TYPE_USHORT_565_RGB); - Graphics gfx = img.getGraphics(); - graph.render(gfx); - ImageOutputStream ios = new MemoryCacheImageOutputStream(out); - ImageIO.write(img, "png", ios); - } catch (RrdException re) { - //_log.error("Error rendering " + filename, re); - throw new IOException("Error plotting: " + re.getLocalizedMessage()); - } catch (IOException ioe) { - //_log.error("Error rendering " + filename, ioe); - throw ioe; - } -*****/ } public void render(OutputStream out) throws IOException { render(out, DEFAULT_X, DEFAULT_Y, @@ -148,13 +127,14 @@ class SummaryRenderer { RrdGraphDef def = new RrdGraphDef(); // Override defaults - def.setColor(RrdGraphDef.COLOR_BACK, BACK_COLOR); - def.setColor(RrdGraphDef.COLOR_SHADEA, SHADEA_COLOR); - def.setColor(RrdGraphDef.COLOR_SHADEB, SHADEB_COLOR); - def.setColor(RrdGraphDef.COLOR_GRID, GRID_COLOR); - def.setColor(RrdGraphDef.COLOR_MGRID, MGRID_COLOR); - def.setColor(RrdGraphDef.COLOR_FONT, FONT_COLOR); - def.setColor(RrdGraphDef.COLOR_FRAME, FRAME_COLOR); + def.setColor(ElementsNames.back, BACK_COLOR); + def.setColor(ElementsNames.shadea, SHADEA_COLOR); + def.setColor(ElementsNames.shadeb, SHADEB_COLOR); + def.setColor(ElementsNames.grid, GRID_COLOR); + def.setColor(ElementsNames.mgrid, MGRID_COLOR); + def.setColor(ElementsNames.font, FONT_COLOR); + def.setColor(ElementsNames.frame, FRAME_COLOR); + def.setColor(ElementsNames.arrow, ARROW_COLOR); // improve text legibility String lang = Messages.getLanguage(_context); @@ -176,6 +156,7 @@ class SummaryRenderer { def.setFont(RrdGraphDef.FONTTAG_DEFAULT, small); // AXIS is unused, we do not set any axis labels def.setFont(RrdGraphDef.FONTTAG_AXIS, small); + // rrd4j sets UNIT = AXIS in RrdGraphConstants, may be bug, maybe not, no use setting them different here def.setFont(RrdGraphDef.FONTTAG_UNIT, small); def.setFont(RrdGraphDef.FONTTAG_LEGEND, legnd); def.setFont(RrdGraphDef.FONTTAG_TITLE, large); @@ -234,8 +215,8 @@ class SummaryRenderer { } if (!hideLegend) { def.gprint(plotName, SummaryListener.CF, " " + _t("Avg") + ": %.2f%s"); - def.gprint(plotName, "MAX", ' ' + _t("Max") + ": %.2f%S"); - def.gprint(plotName, "LAST", ' ' + _t("Now") + ": %.2f%S\\l"); + def.gprint(plotName, ConsolFun.MAX, ' ' + _t("Max") + ": %.2f%S"); + def.gprint(plotName, ConsolFun.LAST, ' ' + _t("Now") + ": %.2f%S\\l"); } String plotName2 = null; if (lsnr2 != null) { @@ -247,8 +228,8 @@ class SummaryRenderer { def.line(plotName2, LINE_COLOR, descr2 + "\\l", 2); if (!hideLegend) { def.gprint(plotName2, SummaryListener.CF, " " + _t("Avg") + ": %.2f%s"); - def.gprint(plotName2, "MAX", ' ' + _t("Max") + ": %.2f%S"); - def.gprint(plotName2, "LAST", ' ' + _t("Now") + ": %.2f%S\\l"); + def.gprint(plotName2, ConsolFun.MAX, ' ' + _t("Max") + ": %.2f%S"); + def.gprint(plotName2, ConsolFun.LAST, ' ' + _t("Now") + ": %.2f%S\\l"); } } if (!hideLegend) { @@ -290,6 +271,8 @@ class SummaryRenderer { } //System.out.println("rendering: path=" + path + " dsNames[0]=" + dsNames[0] + " dsNames[1]=" + dsNames[1] + " lsnr.getName=" + _listener.getName()); def.setAntiAliasing(false); + def.setTextAntiAliasing(true); + def.setGridStroke(GRID_STROKE); //System.out.println("Rendering: \n" + def.exportXmlTemplate()); //System.out.println("*****************\nData: \n" + _listener.getData().dump()); def.setWidth(width); diff --git a/build.xml b/build.xml index 1067069239872fbc2896f6d8810597212b8b0eb2..681040cb9afa9fd798b1733b9a2e536ac3fc8768 100644 --- a/build.xml +++ b/build.xml @@ -842,7 +842,7 @@ <group title="Imagegen Application" packages="com.docuverse.identicon:com.google.zxing:com.google.zxing.*:net.i2p.imagegen" /> <group title="Installer Utilities" packages="net.i2p.installer" /> <group title="Jetty Utilities" packages="net.i2p.jetty:net.i2p.servlet:net.i2p.servlet.*" /> - <group title="JRobin Library" packages="org.jrobin:org.jrobin.*:engine.misc" /> + <group title="RRD4J Library (jrobin.jar)" packages="org.rrd4j:org.rrd4j.*:com.tomgibara.crinch.hashing" /> <group title="SAM Bridge" packages="net.i2p.sam" /> <group title="SAM Demos" packages="net.i2p.sam.client" /> <group title="SusiDNS Application" packages="i2p.susi.dns:net.i2p.addressbook.servlet" /> diff --git a/debian-alt/doc/dependencies.txt b/debian-alt/doc/dependencies.txt index 74c337634c711b46aea83a0986ea46d0eb00e4aa..d78842c966f9f243e0ce0e6bb8cb9dca1f9843f9 100644 --- a/debian-alt/doc/dependencies.txt +++ b/debian-alt/doc/dependencies.txt @@ -123,12 +123,10 @@ the binaries or sources. From https://github.com/PauloMigAlmeida/identicon No package or not widely available. -* jrobin +* rrd4j (jrobin.jar) This is the Java graphing package. - We bundle a large portion of the 1.6.0 source from https://github.com/OpenNMS/jrobin + We bundle most of the source from https://github.com/rrd4j/rrd4j No package or not widely available. - There is an old 1.5.9 Maven jrobin package at http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22org.jrobin%22 - Jrobin is in Gentoo. * libhttpclient-java We only use a few classes from this large package.