1 /* 2 * This file is part of the OpenNMS(R) Application. 3 * 4 * OpenNMS(R) is Copyright (C) 2002-2015 The OpenNMS Group, Inc. All rights reserved. 5 * OpenNMS(R) is a derivative work, containing both original code, included code and modified 6 * code that was published under the GNU General Public License. Copyrights for modified 7 * and included code are below. 8 * 9 * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. 10 * 11 * Modifications: 12 * 13 * 2007 May 21: Better logging around loading of the shared library, format 14 * code, and eliminate m_loaded member. - dj@opennms.org 15 * 2003 Jan 31: Cleaned up some unused imports. 16 * 17 * Orignal code base Copyright (C) 1999-2001 Oculan Corp. All rights reserved. 18 * 19 * This program is free software; you can redistribute it and/or modify 20 * it under the terms of the GNU General Public License as published by 21 * the Free Software Foundation; either version 2 of the License, or 22 * (at your option) any later version. 23 * 24 * This program is distributed in the hope that it will be useful, 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 27 * GNU General Public License for more details. 28 * 29 * You should have received a copy of the GNU General Public License 30 * along with this program; if not, write to the Free Software 31 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 32 * 33 * For more information contact: 34 * OpenNMS Licensing <license@opennms.org> 35 * http://www.opennms.org/ 36 * http://www.opennms.com/ 37 */ 38 package org.opennms.netmgt.rrd.rrdtool; 39 40 import java.io.File; 41 import java.util.LinkedHashSet; 42 import java.util.Set; 43 44 /** 45 * This is a singleton class which provides an interface through which RRD 46 * (Round Robin Database) functions (rrd_create(), rrd_update(), and others) can 47 * be accessed from Java code. 48 * 49 * <pre> 50 * The native method 'launch()' takes a single argument which is a 51 * RRD command string of similar format to what RRDtool takes. Please 52 * note the following examples: 53 * 54 * "create test.rrd --start N DS:ifOctetsIn:COUNTER:600:U:U \ 55 * RRA:AVERAGE:0.5:1:24" 56 * 57 * "update test.rrd --template:ifOctetsIn N:123456789" 58 * 59 * Refer to www.rrdtool.org for additional examples and information on 60 * the format of rrdtool command strings. 61 * 62 * Currently only 'create', 'update', and 'fetch' commands are supported. 63 * </pre> 64 * 65 * @author <A HREF="mailto:mike@opennms.org">Mike </A> 66 * @author <A HREF="http://www.opennms.org/">OpenNMS </A> 67 * 68 * @version 1.1.1.1 69 * 70 */ 71 public final class Interface { 72 private static final String LIBRARY_NAME = "jrrd"; 73 private static final String PROPERTY_NAME = "opennms.library.jrrd"; 74 75 /** 76 * The singleton instance of the interface 77 */ 78 private static Interface s_singleton = null; 79 80 /** 81 * Native method implemented in C which provides an interface to the 82 * lower-level RRD functions 83 * 84 * WARNING: The RRD C api (rrd_update(), rrd_create(), etc...) relies on 85 * getopt() & therefore is not thread safe. This method is therefore 86 * synchronized in order to prevent more than one thread access at a time. 87 * 88 * @param cmd 89 * RRDtool style command string to be executed. Currently 90 * supported RRD commands are: 'create' - calls rrd_create() 91 * 'update' - calls rrd_update() 'fetch' - calls rrd_fetch() 92 * 93 * @return array of Java String objects 94 * 95 * In the case of rrd_fetch() the returned String array has the following 96 * characteristics: 97 * 98 * String[0] = error text if command failed or NULL if successful String[1] = 99 * for 'fetch' cmd: data source names String[2..n] = for 'fetch' cmd: 100 * retrieved data rows for each interval between start and end parms 101 */ launch(String cmd)102 public static synchronized native String[] launch(String cmd); 103 104 /** 105 * Load the jrrd library and create the singleton instance of the interface. 106 * 107 * @throws SecurityException 108 * if we don't have permission to load the library 109 * @throws UnsatisfiedLinkError 110 * if the library doesn't exist 111 */ init()112 public static synchronized void init() throws SecurityException, UnsatisfiedLinkError { 113 if (isLoaded()) { 114 // init already called - return 115 // to reload, reload() will need to be called 116 return; 117 } 118 119 setInstance(new Interface()); 120 } 121 isLoaded()122 private static boolean isLoaded() { 123 return s_singleton != null; 124 } 125 126 /** 127 * Reload the jrrd library and create the singleton instance of the 128 * interface. 129 * 130 * @throws SecurityException 131 * if we don't have permission to load the library 132 * @throws UnsatisfiedLinkError 133 * if the library doesn't exist 134 */ reload()135 public static synchronized void reload() throws SecurityException, UnsatisfiedLinkError { 136 setInstance(null); 137 138 init(); 139 } 140 141 /** 142 * Constructor. Responsible for loading the jrrd shared/dynamic link library 143 * which contains the implementation of the 'launch()' native method. 144 * 145 * @throws SecurityException 146 * if we don't have permission to load the library 147 * @throws UnsatisfiedLinkError 148 * if the library doesn't exist 149 */ Interface()150 private Interface() throws SecurityException, UnsatisfiedLinkError { 151 String jniPath = System.getProperty(PROPERTY_NAME); 152 try { 153 debug("System property '" + PROPERTY_NAME + "' set to '" + System.getProperty(PROPERTY_NAME) + ". Attempting to load " + LIBRARY_NAME + " library from this location."); 154 System.load(jniPath); 155 } catch (final Throwable t) { 156 debug("System property '" + PROPERTY_NAME + "' not set. Attempting to find library."); 157 System.loadLibrary(LIBRARY_NAME); 158 } 159 info("Successfully loaded " + LIBRARY_NAME + " library."); 160 } 161 loadLibrary()162 private static void loadLibrary() { 163 final Set<String> searchPaths = new LinkedHashSet<String>(); 164 165 if (System.getProperty("java.library.path") != null) { 166 for (final String entry : System.getProperty("java.library.path").split(File.pathSeparator)) { 167 searchPaths.add(entry); 168 } 169 } 170 171 for (final String entry : new String[] { 172 "/usr/lib64/jni", 173 "/usr/lib64", 174 "/usr/local/lib64", 175 "/usr/lib/jni", 176 "/usr/lib", 177 "/usr/local/lib" 178 }) { 179 searchPaths.add(entry); 180 } 181 182 for (final String path : searchPaths) { 183 for (final String prefix : new String[] { "", "lib" }) { 184 for (final String suffix : new String[] { ".jnilib", ".dylib", ".so" }) { 185 final File f = new File(path + File.separator + prefix + LIBRARY_NAME + suffix); 186 if (f.exists()) { 187 try { 188 System.load(f.getCanonicalPath()); 189 return; 190 } catch (final Throwable t) { 191 // failed, keep looping and hope for a match 192 } 193 } 194 } 195 } 196 } 197 debug("Unable to locate '" + LIBRARY_NAME + "' in common paths. Attempting System.loadLibrary() as a last resort."); 198 System.loadLibrary(LIBRARY_NAME); 199 } 200 201 /** 202 * Return the singleton instance of this class. 203 * 204 * @return The current instance. 205 * 206 * @throws java.lang.IllegalStateException 207 * Thrown if the interface has not yet been initialized. 208 */ getInstance()209 public static synchronized Interface getInstance() { 210 assertState(isLoaded(), "The RRD JNI interface has not been initialized"); 211 212 return s_singleton; 213 } 214 setInstance(Interface instance)215 public static synchronized void setInstance(Interface instance) { 216 s_singleton = instance; 217 } 218 debug(String msg)219 public static void debug(String msg) { 220 System.err.println("[DEBUG] "+msg); 221 } 222 info(String msg)223 public static void info(String msg) { 224 System.err.println("[INFO] "+msg); 225 } 226 assertState(boolean check, String msg)227 public static void assertState(boolean check, String msg) { 228 if (!check) { 229 throw new IllegalStateException(msg); 230 } 231 } 232 233 /** 234 * Debug purposes only 235 */ main(String[] argv)236 public static void main(String[] argv) { 237 try { 238 // initialize the interface 239 Interface.reload(); 240 241 // build create command 242 // Build RRD create command prefix 243 String filename = argv[0]; 244 System.out.println("filename=" + filename); 245 String cmd = "create \"" + filename + "\" --start N" + " --step 900 DS:test:COUNTER:900:0:100 RRA:MIN:0.5:1:1000"; 246 247 // issue rrd command 248 System.out.println("issuing RRD cmd: " + cmd); 249 Interface.launch(cmd); 250 System.out.println("command completed."); 251 } catch (Throwable t) { 252 System.err.println("unexpected error, reason: " + t); 253 t.printStackTrace(); 254 } 255 } 256 } 257