KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jrobin > core > FetchData


1 /* ============================================================
2  * JRobin : Pure java implementation of RRDTool's functionality
3  * ============================================================
4  *
5  * Project Info: http://www.jrobin.org
6  * Project Lead: Sasa Markovic (saxon@jrobin.org);
7  *
8  * (C) Copyright 2003, by Sasa Markovic.
9  *
10  * Developers: Sasa Markovic (saxon@jrobin.org)
11  * Arne Vandamme (cobralord@jrobin.org)
12  *
13  * This library is free software; you can redistribute it and/or modify it under the terms
14  * of the GNU Lesser General Public License as published by the Free Software Foundation;
15  * either version 2.1 of the License, or (at your option) any later version.
16  *
17  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
18  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  * See the GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License along with this
22  * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */

25
26 package org.jrobin.core;
27
28 import java.io.IOException JavaDoc;
29 import java.io.OutputStream JavaDoc;
30 import java.io.FileOutputStream JavaDoc;
31 import java.io.ByteArrayOutputStream JavaDoc;
32 import java.text.DecimalFormat JavaDoc;
33
34 /**
35  * Class used to represent data fetched from the RRD.
36  * Object of this class is created when the method
37  * {@link org.jrobin.core.FetchRequest#fetchData() fetchData()} is
38  * called on a {@link org.jrobin.core.FetchRequest FetchRequest} object.<p>
39  *
40  * Data returned from the RRD is, simply, just one big table filled with
41  * timestamps and corresponding datasource values.
42  * Use {@link #getRowCount() getRowCount()} method to count the number
43  * of returned timestamps (table rows).<p>
44  *
45  * The first table column is filled with timestamps. Time intervals
46  * between consecutive timestamps are guaranteed to be equal. Use
47  * {@link #getTimestamps() getTimestamps()} method to get an array of
48  * timestamps returned.<p>
49  *
50  * Remaining columns are filled with datasource values for the whole timestamp range,
51  * on a column-per-datasource basis. Use {@link #getColumnCount() getColumnCount()} to find
52  * the number of datasources and {@link #getValues(int) getValues(i)} method to obtain
53  * all values for the i-th datasource. Returned datasource values correspond to
54  * the values returned with {@link #getTimestamps() getTimestamps()} method.<p>
55  */

56 public class FetchData implements RrdDataSet {
57     private FetchRequest request;
58     private Archive matchingArchive;
59     private String JavaDoc[] dsNames;
60     private long[] timestamps;
61     private double[][] values;
62
63     FetchData(Archive matchingArchive, FetchRequest request) throws IOException JavaDoc {
64         this.matchingArchive = matchingArchive;
65         this.dsNames = request.getFilter();
66         if(this.dsNames == null) {
67             this.dsNames = matchingArchive.getParentDb().getDsNames();
68         }
69         this.request = request;
70     }
71
72     void setTimestamps(long[] timestamps) {
73         this.timestamps = timestamps;
74     }
75
76     void setValues(double[][] values) {
77         this.values = values;
78     }
79
80     /**
81      * Returns the number of rows fetched from the corresponding RRD.
82      * Each row represents datasource values for the specific timestamp.
83      * @return Number of rows.
84      */

85     public int getRowCount() {
86         return timestamps.length;
87     }
88
89     /**
90      * Returns the number of columns fetched from the corresponding RRD.
91      * This number is always equal to the number of datasources defined
92      * in the RRD. Each column represents values of a single datasource.
93      * @return Number of columns (datasources).
94      */

95     public int getColumnCount() {
96         return dsNames.length;
97     }
98
99     /**
100      * Returns the number of rows fetched from the corresponding RRD.
101      * Each row represents datasource values for the specific timestamp.
102      * @param rowIndex Row index.
103      * @return FetchPoint object which represents datasource values for the
104      * specific timestamp.
105      */

106     public FetchPoint getRow(int rowIndex) {
107         int numCols = getColumnCount();
108         FetchPoint point = new FetchPoint(timestamps[rowIndex], getColumnCount());
109         for(int dsIndex = 0; dsIndex < numCols; dsIndex++) {
110             point.setValue(dsIndex, values[dsIndex][rowIndex]);
111         }
112         return point;
113     }
114
115     /**
116      * Returns an array of timestamps covering the whole range specified in the
117      * {@link FetchRequest FetchReguest} object.
118      * @return Array of equidistant timestamps.
119      */

120     public long[] getTimestamps() {
121         return timestamps;
122     }
123
124     /**
125      * Returns the step with which this data was fetched.
126      * @return Step as long.
127      */

128     public long getStep() {
129         return timestamps[1] - timestamps[0];
130     }
131
132     /**
133      * Returns all archived values for a single datasource.
134      * Returned values correspond to timestamps
135      * returned with {@link #getTimestamps() getTimestamps()} method.
136      * @param dsIndex Datasource index.
137      * @return Array of single datasource values.
138      */

139     public double[] getValues(int dsIndex) {
140         return values[dsIndex];
141     }
142
143     /**
144      * Returns all archived values for all datasources.
145      * Returned values correspond to timestamps
146      * returned with {@link #getTimestamps() getTimestamps()} method.
147      * @return Two-dimensional aray of all datasource values.
148      */

149     public double[][] getValues() {
150         return values;
151     }
152     
153     /**
154      * Returns all archived values for a single datasource.
155      * Returned values correspond to timestamps
156      * returned with {@link #getTimestamps() getTimestamps()} method.
157      * @param dsName Datasource name.
158      * @return Array of single datasource values.
159      * @throws RrdException Thrown if no matching datasource name is found.
160      */

161     public double[] getValues(String JavaDoc dsName) throws RrdException {
162         for(int dsIndex = 0; dsIndex < getColumnCount(); dsIndex++) {
163             if(dsName.equals(dsNames[dsIndex])) {
164                 return getValues(dsIndex);
165             }
166         }
167         throw new RrdException("Datasource [" + dsName + "] not found");
168     }
169
170     /**
171      * Returns {@link FetchRequest FetchRequest} object used to create this FetchData object.
172      * @return Fetch request object.
173      */

174     public FetchRequest getRequest() {
175         return request;
176     }
177
178     /**
179      * Returns the first timestamp in this FetchData object.
180      * @return The smallest timestamp.
181      */

182     public long getFirstTimestamp() {
183         return timestamps[0];
184     }
185
186     /**
187      * Returns the last timestamp in this FecthData object.
188      * @return The biggest timestamp.
189      */

190     public long getLastTimestamp() {
191         return timestamps[timestamps.length - 1];
192     }
193
194     /**
195      * Returns Archive object which is determined to be the best match for the
196      * timestamps specified in the fetch request. All datasource values are obtained
197      * from round robin archives belonging to this archive.
198      * @return Matching archive.
199      */

200     public Archive getMatchingArchive() {
201         return matchingArchive;
202     }
203
204     /**
205      * Returns array of datasource names found in the corresponding RRD. If the request
206      * was filtered (data was fetched only for selected datasources), only datasources selected
207      * for fetching are returned.
208      * @return Array of datasource names.
209      */

210     public String JavaDoc[] getDsNames() {
211         return dsNames;
212     }
213     
214     /**
215      * Retrieve the table index number of a datasource by name. Names are case sensitive.
216      * @param dsName Name of the datasource for which to find the index.
217      * @return Index number of the datasources in the value table.
218      */

219     public int getDsIndex(String JavaDoc dsName) {
220         // Let's assume the table of dsNames is always small, so it is not necessary to use a hashmap for lookups
221
for (int i = 0; i < dsNames.length; i++)
222             if ( dsNames[i].equals(dsName) )
223                 return i;
224         
225         return -1; // Datasource not found !
226
}
227
228     /**
229      * Dumps the content of the whole FetchData object to stdout. Useful for debugging.
230      */

231     public void dump() {
232         for(int i = 0; i < getRowCount(); i++) {
233             System.out.println(getRow(i).dump());
234         }
235     }
236
237     /**
238      * Returns string representing fetched data in a RRDTool-like form.
239      * @return Fetched data as a string in a rrdfetch-like output form.
240      */

241     public String JavaDoc toString() {
242         final DecimalFormat JavaDoc df = new DecimalFormat JavaDoc("+0.0000000000E00");
243         // print header row
244
StringBuffer JavaDoc buff = new StringBuffer JavaDoc();
245         buff.append(padWithBlanks("", 10));
246         buff.append(" ");
247         for(int i = 0; i < dsNames.length; i++) {
248             buff.append(padWithBlanks(dsNames[i], 18));
249         }
250         buff.append("\n \n");
251         for(int i = 0; i < timestamps.length; i++) {
252             buff.append(padWithBlanks("" + timestamps[i], 10));
253             buff.append(":");
254             for(int j = 0; j < dsNames.length; j++) {
255                 double value = values[j][i];
256                 String JavaDoc valueStr = Double.isNaN(value)? "nan": df.format(value);
257                 buff.append(padWithBlanks(valueStr, 18));
258             }
259             buff.append("\n");
260         }
261         return buff.toString();
262     }
263
264     private static String JavaDoc padWithBlanks(String JavaDoc input, int width) {
265         StringBuffer JavaDoc buff = new StringBuffer JavaDoc("");
266         int diff = width - input.length();
267         while(diff-- > 0) {
268             buff.append(' ');
269         }
270         buff.append(input);
271         return buff.toString();
272     }
273
274     /**
275      * Returns aggregated value from the fetched data for a single datasource.
276      * @param dsName Datasource name
277      * @param consolFun Consolidation function to be applied to fetched datasource values.
278      * Valid consolidation functions are MIN, MAX, LAST and AVERAGE
279      * @return MIN, MAX, LAST or AVERAGE value calculated from the fetched data
280      * for the given datasource name
281      * @throws RrdException Thrown if the given datasource name cannot be found in fetched data.
282      */

283     public double getAggregate(String JavaDoc dsName, String JavaDoc consolFun) throws RrdException {
284         return getAggregate(dsName, consolFun, null);
285     }
286
287     /**
288      * Returns aggregated value from the fetched data for a single datasource.
289      * Before applying aggrregation functions, specified RPN expression is applied to fetched
290      * data. For example, if you have a gauge datasource named 'foots' but you wont to
291      * find the maximum fetched value in meters use something like:</p>
292      * <code>getAggregate("foots", "MAX", "value,0.3048,*");</code>
293      * Note that 'value' in the RPN expression is a reserved word and stands for the
294      * original value (value fetched from RRD)</p>
295      * @param dsName Datasource name
296      * @param consolFun Consolidation function to be applied to fetched datasource values.
297      * Valid consolidation functions are MIN, MAX, LAST and AVERAGE
298      * @return MIN, MAX, LAST or AVERAGE value calculated from the fetched data
299      * for the given datasource name
300      * @throws RrdException Thrown if the given datasource name cannot be found in fetched data.
301      */

302     public double getAggregate(String JavaDoc dsName, String JavaDoc consolFun, String JavaDoc rpnExpression)
303         throws RrdException {
304         if(consolFun.equals("MAX")) {
305             return getMax(dsName, rpnExpression);
306         }
307         else if(consolFun.equals("MIN")) {
308             return getMin(dsName, rpnExpression);
309         }
310         else if(consolFun.equals("LAST")) {
311             return getLast(dsName, rpnExpression);
312         }
313         else if(consolFun.equals("AVERAGE")) {
314             return getAverage(dsName, rpnExpression);
315         }
316         else {
317             throw new RrdException("Unsupported consolidation function [" + consolFun + "]");
318         }
319     }
320
321     private double getMax(String JavaDoc dsName, String JavaDoc rpnExpression) throws RrdException {
322         RpnCalculator rpnCalculator = null;
323         if(rpnExpression != null) {
324             rpnCalculator = new RpnCalculator(rpnExpression);
325         }
326         double vals[] = getValues(dsName), max = Double.NaN;
327         for(int i = 0; i < vals.length - 1; i++) {
328             double value = vals[i + 1];
329             if(rpnCalculator != null) {
330                 rpnCalculator.setValue(value);
331                 value = rpnCalculator.calculate();
332             }
333             max = Util.max(max, value);
334         }
335         return max;
336     }
337
338     private double getMin(String JavaDoc dsName, String JavaDoc rpnExpression) throws RrdException {
339         RpnCalculator rpnCalculator = null;
340         if(rpnExpression != null) {
341             rpnCalculator = new RpnCalculator(rpnExpression);
342         }
343         double vals[] = getValues(dsName), min = Double.NaN;
344         for(int i = 0; i < vals.length - 1; i++) {
345             double value = vals[i + 1];
346             if(rpnCalculator != null) {
347                 rpnCalculator.setValue(value);
348                 value = rpnCalculator.calculate();
349             }
350             min = Util.min(min, value);
351         }
352         return min;
353     }
354
355     private double getLast(String JavaDoc dsName, String JavaDoc rpnExpression) throws RrdException {
356         RpnCalculator rpnCalculator = null;
357         if(rpnExpression != null) {
358             rpnCalculator = new RpnCalculator(rpnExpression);
359         }
360         double vals[] = getValues(dsName);
361         double value = vals[vals.length - 1];
362         if(rpnCalculator != null) {
363             rpnCalculator.setValue(value);
364             value = rpnCalculator.calculate();
365         }
366         return value;
367     }
368
369     private double getAverage(String JavaDoc dsName, String JavaDoc rpnExpression) throws RrdException {
370         RpnCalculator rpnCalculator = null;
371         if(rpnExpression != null) {
372             rpnCalculator = new RpnCalculator(rpnExpression);
373         }
374         double vals[] = getValues(dsName);
375         double totalVal = 0;
376         long totalSecs = 0;
377         for(int i = 0; i < vals.length - 1; i++) {
378             long t1 = Math.max(request.getFetchStart(), timestamps[i]);
379             long t2 = Math.min(request.getFetchEnd(), timestamps[i + 1]);
380             double value = vals[i + 1];
381             if(rpnCalculator != null) {
382                 rpnCalculator.setValue(value);
383                 value = rpnCalculator.calculate();
384             }
385             if(!Double.isNaN(value)) {
386                 totalSecs += (t2 - t1);
387                 totalVal += (t2 - t1) * value;
388             }
389         }
390         return totalSecs > 0? totalVal / totalSecs: Double.NaN;
391     }
392
393     /**
394      * Dumps fetch data to output stream in XML format.
395      * @param outputStream Output stream to dump fetch data to
396      * @throws IOException Thrown in case of I/O error
397      */

398     public void exportXml(OutputStream JavaDoc outputStream) throws IOException JavaDoc {
399         XmlWriter writer = new XmlWriter(outputStream);
400         writer.startTag("fetch_data");
401         writer.startTag("request");
402         writer.writeTag("file", request.getParentDb().getPath());
403         writer.writeComment(Util.getDate(request.getFetchStart()));
404         writer.writeTag("start", request.getFetchStart());
405         writer.writeComment(Util.getDate(request.getFetchEnd()));
406         writer.writeTag("end", request.getFetchEnd());
407         writer.writeTag("resolution", request.getResolution());
408         writer.writeTag("cf", request.getConsolFun());
409         writer.closeTag(); // request
410
writer.startTag("datasources");
411         for(int i = 0; i < dsNames.length; i++) {
412             writer.writeTag("name", dsNames[i]);
413         }
414         writer.closeTag(); // datasources
415
writer.startTag("data");
416         for(int i = 0; i < timestamps.length; i++) {
417             writer.startTag("row");
418             writer.writeComment(Util.getDate(timestamps[i]));
419             writer.writeTag("timestamp", timestamps[i]);
420             writer.startTag("values");
421             for(int j = 0; j < dsNames.length; j++) {
422                 writer.writeTag("v", values[j][i]);
423             }
424             writer.closeTag(); // values
425
writer.closeTag(); // row
426
}
427         writer.closeTag(); // data
428
writer.closeTag(); // fetch_data
429
writer.flush();
430     }
431
432     /**
433      * Dumps fetch data to file in XML format.
434      * @param filepath Path to destination file
435      * @throws IOException Thrown in case of I/O error
436      */

437     public void exportXml(String JavaDoc filepath) throws IOException JavaDoc {
438         OutputStream JavaDoc outputStream = null;
439         try {
440             outputStream = new FileOutputStream JavaDoc(filepath);
441             exportXml(outputStream);
442         }
443         finally {
444             if(outputStream != null) {
445                 outputStream.close();
446             }
447         }
448     }
449
450     /**
451      * Dumps fetch data in XML format.
452      * @return String containing XML formatted fetch data
453      * @throws IOException Thrown in case of I/O error
454      */

455     public String JavaDoc exportXml() throws IOException JavaDoc {
456         ByteArrayOutputStream JavaDoc outputStream = new ByteArrayOutputStream JavaDoc();
457         exportXml(outputStream);
458         return outputStream.toString();
459     }
460 }
461
Popular Tags