001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.monitoring.snapshot;
018
019 import java.sql.Connection;
020 import java.sql.DriverManager;
021 import java.sql.ResultSet;
022 import java.sql.Statement;
023 import java.text.SimpleDateFormat;
024 import java.util.ArrayList;
025 import java.util.Calendar;
026 import java.util.Date;
027 import java.util.HashMap;
028 import java.util.Iterator;
029 import java.util.TreeMap;
030
031 import javax.sql.DataSource;
032
033 import org.apache.commons.logging.Log;
034 import org.apache.commons.logging.LogFactory;
035
036 public class SnapshotDBHelper {
037 private static Log log = LogFactory.getLog(SnapshotDBHelper.class);
038 // field attributes for the Statistics table in the DB
039 private static final String SNAPSHOT_TIME = "snapshot_time";
040 private static final String MBEANNAME = "mbeanName";
041 private static final String STATSVALUELIST = "statsValueList";
042 private static final String STATSNAMELIST = "statsNameList";
043 // Connection object used for DB interaction
044 private static Connection conn = null;
045 // Data Sources
046 private static DataSource activeDS = null;
047 private static DataSource archiveDS = null;
048
049 public SnapshotDBHelper() {
050
051 }
052
053 public SnapshotDBHelper(DataSource activeDS, DataSource archiveDS) {
054 SnapshotDBHelper.activeDS = activeDS;
055 SnapshotDBHelper.archiveDS = archiveDS;
056 }
057
058 /**
059 * @return A map: mbeanName --> ArrayList of statistic attributes for that mbean
060 */
061 public HashMap<String, ArrayList<String>> getAllSnapshotStatAttributes() {
062 openActiveConnection();
063 HashMap<String, ArrayList<String>> retval = new HashMap<String, ArrayList<String>>();
064 try {
065 Statement stmt = conn.createStatement();
066 String query = "SELECT DISTINCT mbeanName, statsNameList FROM MBeans";
067 ResultSet rs = stmt.executeQuery(query);
068 // add each mbean/statsValue combination to retval
069 while(rs.next()) {
070 String mbeanName = rs.getString(MBEANNAME);
071 String statsNameStr = rs.getString(STATSNAMELIST);
072 String[] statsNameList = statsNameStr.split(",");
073 ArrayList<String> mbeanAttributeList = new ArrayList<String>();
074 // copy from String[] to ArrayList<String>
075 for(int i = 0; i < statsNameList.length; i++) {
076 mbeanAttributeList.add(statsNameList[i]);
077 }
078 retval.put(mbeanName, mbeanAttributeList);
079 }
080 } catch(Exception e) {
081 log.error(e.getMessage(), e);
082 } finally {
083 closeConnection();
084 }
085 return retval;
086 }
087
088 /**
089 *
090 * @return The number of snapshots present in the active database
091 */
092 public Long getSnapshotCount() {
093 long retval = 0;
094 try {
095 openActiveConnection();
096 Statement stmt = conn.createStatement();
097 String query = "SELECT COUNT(DISTINCT snapshot_time) FROM Statistics";
098 ResultSet rs = stmt.executeQuery(query);
099 rs.next();
100 retval = rs.getLong(1);
101 } catch(Exception e) {
102 log.error(e.getMessage(), e);
103 } finally {
104 closeConnection();
105 }
106 return new Long(retval);
107 }
108
109 /**
110 * @param numberOfSnapshots - the number of latest snapshots to look at
111 * @return A hashmap which maps an mbean --> a hashmap with an attribute name and its value . All values will be the max.
112 */
113 public HashMap<String, HashMap<String, Long>> fetchMaxSnapshotData(Integer numberOfSnapshots) {
114 return fetchMaxOrMinSnapshotData(numberOfSnapshots, true);
115 }
116 /**
117 * @param numberOfSnapshots - the number of latest snapshots to look at
118 * @return A hashmap which maps an mbean --> a hashmap with an attribute name and its value . All values will be the min.
119 */
120 public HashMap<String, HashMap<String, Long>> fetchMinSnapshotData(Integer numberOfSnapshots) {
121 return fetchMaxOrMinSnapshotData(numberOfSnapshots, false);
122 }
123
124 /**
125 * @param numberOfSnapshots - the number of latest snapshots to look at.
126 * @param isMax - true if the result should be all maximum values. otherwise, false.
127 * @return A hashmap which maps an mbean --> a hashmap with an attribute name and its value . All values will be the min
128 * or max, depending on the isMax parameter.
129 */
130 private HashMap<String, HashMap<String, Long>> fetchMaxOrMinSnapshotData(Integer numberOfSnapshots, boolean isMax) {
131 openActiveConnection();
132 ResultSet snapshotTimeTable = fetchSnapshotTimesFromDB();
133 HashMap<String, HashMap<String, Long>> stats = new HashMap<String, HashMap<String, Long>>();
134 try {
135 // for each snapshot in the table
136 while(snapshotTimeTable.next()) {
137 Long snapshotTime = snapshotTimeTable.getLong(SNAPSHOT_TIME);
138 // retrieve the snapshot information by time
139 ResultSet snapshotData = fetchSnapshotDataFromDB(snapshotTime);
140 // for each statistic, perform a relaxation
141 while(snapshotData.next()) {
142 String mbean = snapshotData.getString(MBEANNAME);
143 // get map associated with mbean
144 HashMap<String, Long> mbeanMap = stats.get(mbean);
145 if(mbeanMap == null) {
146 mbeanMap = new HashMap<String, Long>();
147 }
148 String[] statsNameList = snapshotData.getString(STATSNAMELIST).split(",");
149 String[] statsValueList = snapshotData.getString(STATSVALUELIST).split(",");
150 assert(statsNameList.length == statsValueList.length);
151 // for each statname/statsvalue combo in an mbean
152 for(int i = 0 ; i < statsNameList.length; i++) {
153 String statsName = statsNameList[i];
154 Long maxStatsValue = mbeanMap.get(statsName);
155 // give maxStatsValue some value if there isn't one
156 if(maxStatsValue == null) {
157 if(isMax) {
158 maxStatsValue = new Long(0);
159 } else {
160 maxStatsValue = Long.MAX_VALUE;
161 }
162 }
163 // relax
164 if(isMax) {
165 maxStatsValue = new Long(Math.max(Long.parseLong(statsValueList[i]), maxStatsValue.longValue()));
166 } else {
167 maxStatsValue = new Long(Math.min(Long.parseLong(statsValueList[i]), maxStatsValue.longValue()));
168 }
169 // save name/value back into mbeanMap
170 mbeanMap.put(statsName, maxStatsValue);
171 }
172 // save mbeanMap back into stats
173 stats.put(mbean, mbeanMap);
174 }
175
176 // compute the remaining snapshots left to look at
177 numberOfSnapshots--;
178 // discontinue once we have looked at numberOfSnapshots snapshots
179 if(numberOfSnapshots == 0) {
180 break;
181 }
182 }
183 } catch(Exception e) {
184 log.error(e.getMessage(), e);
185 } finally {
186 closeConnection();
187 }
188 return stats;
189 }
190
191 /**
192 * @param ds
193 * @param aggregateStats
194 * @return Returns a boolean if the snapshot statistics were successfully added
195 * to the DB.
196 */
197 public boolean addSnapshotToDB(HashMap<String, HashMap<String, Long>> aggregateStats) {
198 boolean success = true;
199 // get the current time from 1970
200 String currTime = "";
201 currTime += (new Date()).getTime();
202 try {
203 // for each mbean
204 for(Iterator itt = aggregateStats.keySet().iterator(); itt.hasNext(); ) {
205 String mbean = (String)itt.next();
206 // prepare the statsNameList and statsValueList beforehand
207 String statsNameList = "", statsValueList = "";
208 for(Iterator<String> it = aggregateStats.get(mbean).keySet().iterator(); it.hasNext(); ) {
209 String statsName = it.next();
210 Long statsValue = aggregateStats.get(mbean).get(statsName);
211 if(statsNameList.length() == 0 || statsValueList.length() == 0) {
212 // do not add a comma because this is the first occurrence
213 statsValueList += statsValue.toString();
214 statsNameList += statsName;
215 } else {
216 // add a comma
217 statsValueList += "," + statsValue.toString();
218 statsNameList += "," + statsName;
219 }
220 }
221
222 // start talking to DB
223 openActiveConnection();
224 Statement stmt = conn.createStatement();
225 HashMap stats = aggregateStats.get(mbean);
226 //--------Ensure MBeans are in place
227 int mbeanId = getMBeanId(mbean);
228 if(mbeanId != -1) {
229 // mbean already exists in the db
230 } else {
231 // doesn't exist in the db so add it
232 // add mbean record to the db
233 stmt.executeUpdate("INSERT INTO MBeans (mbeanName, statsNameList) VALUES ("+ surroundWithQuotes(mbean) + "," + surroundWithQuotes(statsNameList) + ")");
234 mbeanId = getMBeanId(mbean);
235 }
236
237 // insert the statistics into Statistics table
238 stmt.executeUpdate( prepareInsertSnapshotStatement(currTime, statsValueList, mbeanId) );
239 closeConnection();
240 }
241 } catch(Exception e){
242 log.error(e.getMessage(), e);
243 success = false;
244 } finally {
245 closeConnection();
246 }
247
248 // go through the archiving process
249 try {
250 int retentionDays = Integer.parseInt(SnapshotConfigXMLBuilder.getAttributeValue("retention"));
251 long retentionMillis = (long)(retentionDays) * 86400000; // convert from days to milliseconds
252 archiveSnapshots( Long.parseLong(currTime) - retentionMillis );
253 } catch(Exception e) {
254 log.warn("Cannot archive snapshots because attribute 'retention' is not present in snapshot-config.xml.");
255 }
256 return success;
257 }
258
259 /**
260 * Moves records from the ActiveDB to the ArchiveDB. The records that are moved
261 * are those whose snapshot_times exceed the retention period
262 * @param cutOffTime - in milliseconds
263 */
264 private void archiveSnapshots(long cutOffTime) {
265 // for each successful update of Snapshots/Statistics table
266 // increment or decrement these counters to ensure that nothing is being
267 // lost in between. If these counters are non-zero, some records have been
268 // lost.
269 int snapshotsOver = 0;
270 int statisticsOver = 0;
271 try {
272 openActiveConnection();
273 ResultSet overDueSnapshotTimes = getOverDueSnapshotTimes(cutOffTime);
274 ArrayList<Long> overdueTimes = new ArrayList<Long>();
275 // save overdue times into an array list for later usage
276 while(overDueSnapshotTimes.next()) {
277 overdueTimes.add(overDueSnapshotTimes.getLong(SNAPSHOT_TIME));
278 }
279 closeConnection();
280 // for each overdue snapshot time
281 // -transfer all records associated with that snaphot_time to ArchiveDB
282 for(int i = 0; i < overdueTimes.size(); i++) {
283 long snapshotTime = overdueTimes.get(i);
284 openActiveConnection();
285 ResultSet rsSnapshotData = fetchSnapshotDataFromDB(new Long(snapshotTime));
286 HashMap<String, HashMap<String, Long>> snapshotData = new HashMap<String,HashMap<String, Long>>();
287 while(rsSnapshotData.next()) {
288 // extract values from sql table
289 String mbeanName = rsSnapshotData.getString(MBEANNAME);
290 String statsNameList = rsSnapshotData.getString(STATSNAMELIST);
291 String statsValueList = rsSnapshotData.getString(STATSVALUELIST);
292 Long snapshot_time = rsSnapshotData.getLong(SNAPSHOT_TIME);
293 // get a connection to the archive db too
294 Connection archiveConn = archiveDS.getConnection();
295 Statement archiveStmt = archiveConn.createStatement();
296 //--------Ensure MBeans are in place
297 int mbeanId = getMBeanIdFromArchive(mbeanName);
298 if(mbeanId != -1) {
299 // mbean already exists in the db
300 } else {
301 // doesn't exist in the db so add it
302 // add mbean record to the db
303 archiveStmt.executeUpdate("INSERT INTO MBeans (mbeanName, statsNameList) VALUES ("+ surroundWithQuotes(mbeanName) + ", " + surroundWithQuotes(statsNameList) + ")");
304 mbeanId = getMBeanIdFromArchive(mbeanName);
305 }
306 // ensure Statistics table has record of mbeanId, snapshotId, statsValue, statsName
307 String updateStr = prepareInsertSnapshotStatement(snapshot_time + "", statsValueList, mbeanId);
308 statisticsOver += archiveStmt.executeUpdate( updateStr );
309 // close connection to archiveDB
310 archiveConn.close();
311 }
312 closeConnection();
313 }
314 // for each snapshot time, remove all instances that is associated with in
315 // in the active DB
316 for(int i = 0; i < overdueTimes.size(); i++) {
317 long snapshotTime = overdueTimes.get(i);
318 openActiveConnection();
319 Statement stmt = conn.createStatement();
320 // remove from Statistics table
321 String statisticsUpdate = "DELETE FROM Statistics WHERE snapshot_time=" + snapshotTime;
322 statisticsOver -= stmt.executeUpdate(statisticsUpdate);
323 closeConnection();
324 }
325 } catch(Exception e) {
326 log.error(e.getMessage(), e);
327 } finally {
328 closeConnection();
329 }
330
331 // ensure that the transferring was good
332 if(snapshotsOver != 0) {
333 log.warn("Transferred snapshots was completed, but some things were lost.");
334 }
335 if(statisticsOver != 0) {
336 log.warn("Transferred statistics was completed, but some things were lost.");
337 }
338 }
339
340 /**
341 * @param cutOffTime
342 * @return An SQL table contain a column of all the times that did not make the cutOffTime.
343 */
344 private ResultSet getOverDueSnapshotTimes(long cutOffTime) {
345 try {
346 Statement stmt = conn.createStatement();
347 String query = "SELECT DISTINCT snapshot_time FROM Statistics WHERE snapshot_time < " + cutOffTime;
348 return stmt.executeQuery(query);
349 } catch(Exception e) {
350 log.error(e.getMessage(), e);
351 }
352 return null;
353 }
354
355 /**
356 * @param mbean
357 * @return The mbean id of the mbean from table ArchiveDB.MBean. Returns -1 if record does not exist.
358 */
359 private int getMBeanIdFromArchive(String mbean) throws Exception {
360 int retval = -1;
361 Connection archiveConn = archiveDS.getConnection();
362 Statement stmt = archiveConn.createStatement();
363 ResultSet rs = stmt.executeQuery("SELECT id FROM MBeans WHERE mbeanName=" + surroundWithQuotes(mbean));
364 if(rs.next()) {
365 retval = rs.getInt("id");
366 }
367 stmt.close();
368 archiveConn.close();
369 return retval;
370 }
371
372 /**
373 * @param mbean
374 * @return The mbean id of the mbean from table ActiveDB.MBean. Returns -1 if record does not exist.
375 */
376 private int getMBeanId(String mbean) throws Exception {
377 int retval = -1;
378 Connection conn = activeDS.getConnection();
379 Statement stmt = conn.createStatement();
380 ResultSet rs = stmt.executeQuery("SELECT id FROM MBeans WHERE mbeanName=" + surroundWithQuotes(mbean));
381 if(rs.next()) {
382 retval = rs.getInt("id");
383 }
384 stmt.close();
385 conn.close();
386 return retval;
387 }
388
389 /**
390 * @param snapshot_time
391 * @param statsValueList
392 * @param mbeanId
393 * @return Returns an SQL insert statement for one statistic given the correct information.
394 */
395 public String prepareInsertSnapshotStatement(String snapshot_time, String statsValueList, int mbeanId) {
396 String retval = "INSERT INTO Statistics (snapshot_time, statsValueList, mbeanId) VALUES (";
397 retval += snapshot_time;
398 retval += ",";
399 retval += surroundWithQuotes(statsValueList);
400 retval += ",";
401 retval += mbeanId;
402 retval += ")";
403 return retval;
404 }
405
406 /**
407 * @param s
408 * @return A String with ' at the beginning and end
409 */
410 private String surroundWithQuotes(String s) {
411 return "'" + s.trim() + "'";
412 }
413
414 /**
415 * Fetches the data stored from the snapshot thread and returns
416 * it in a ArrayList with each element being a HashMap of the attribute
417 * mapping to the statistic. Grabs 'numberOfSnapshots' snapshots. Grabs
418 * one snapshot per 'everyNthsnapshot'
419 *
420 * @param numberOfSnapshot
421 * @param everyNthSnapshot
422 * @return ArrayList
423 */
424 public ArrayList<HashMap<String, HashMap<String, Object>>> fetchData(Integer numberOfSnapshot,
425 Integer everyNthSnapshot) {
426 ArrayList<HashMap<String, HashMap<String, Object>>> stats = new ArrayList<HashMap<String, HashMap<String, Object>>>();
427 openActiveConnection();
428 // get all records in the database grouped and ordered by time
429 ResultSet table = fetchSnapshotTimesFromDB();
430 // iterate through the table and finds the times (which uniquely IDs a snapshot)
431 // that are wanted and queries the rest of the DB using the time as the condition
432 // (i.e. the ones that are in the c*n-th snapshot where c <= numberOfSnapshot
433 // and n == everyNthSnapshot)
434 int nthSnapshot = 0;
435 try {
436 while(table.next()) {
437 Long snapshotTime = table.getLong(SNAPSHOT_TIME);
438 // grab 0*nth, 1*nth, 2*nth snapshot up to min(numberOfSnapshot*everyNthSnapshot, size of the table)
439 if(nthSnapshot % everyNthSnapshot == 0) {
440 HashMap<String, HashMap<String, Object>> snapshotData = packageSnapshotData(snapshotTime);
441 stats.add( 0, snapshotData );
442 numberOfSnapshot--;
443 }
444 nthSnapshot++;
445 // no more snapshots needs to be looked at, we have successfully acquired our goal
446 if(numberOfSnapshot == 0) {
447 break;
448 }
449 }
450 } catch(Exception e) {
451 log.error(e.getMessage(), e);
452 } finally {
453 closeConnection();
454 }
455 return stats;
456 }
457
458 /**
459 * @param snapshotTime
460 * @return A hashmap in the form <String1, HashMap> where String1 is the mbean name
461 * and HashMap is a map containing a <String2, Object> where String2 is an attribute name
462 * and Object is the value. Additionally, if String is "times" then it maps to a HashMap
463 * containing snapshot_time and snapshot_date information.
464 */
465 private HashMap<String, HashMap<String, Object>> packageSnapshotData(Long snapshotTime) {
466 HashMap<String, HashMap<String, Object>> snapshotPkg = new HashMap<String, HashMap<String, Object>>();
467 openActiveConnection();
468 ResultSet snapshotData = fetchSnapshotDataFromDB(snapshotTime);
469 try {
470 // for each record save it somewhere in the snapshotPkg
471 while(snapshotData.next()) {
472 String currMBean = snapshotData.getString(MBEANNAME);
473 // get the information for the mbean defined by currMBean
474 HashMap<String, Object> mbeanInfo = snapshotPkg.get(currMBean);
475 if(mbeanInfo == null) {
476 mbeanInfo = new HashMap<String, Object>();
477 }
478 // get statistics from resultset
479 String statsValueStr = snapshotData.getString(STATSVALUELIST);
480 String statsNameStr = snapshotData.getString(STATSNAMELIST);
481 String[] statsValueList = statsValueStr.split(",");
482 String[] statsNameList = statsNameStr.split(",");
483 assert(statsValueList.length == statsNameList.length);
484 // for each statsValue/statsName, save it
485 for(int i = 0 ; i < statsValueList.length; i++) {
486 long statValue = Long.parseLong(statsValueList[i]);
487 mbeanInfo.put(statsNameList[i], new Long(statValue));
488 }
489 // save the hashmap into the snapshotpkg
490 snapshotPkg.put(currMBean, mbeanInfo);
491 }
492 } catch(Exception e) {
493 log.error(e.getMessage(), e);
494 } finally {
495 closeConnection();
496 }
497 // add the time and date
498 HashMap<String, Object> timeMap = new HashMap<String, Object>();
499 timeMap.put(SNAPSHOT_TIME, snapshotTime);
500 snapshotPkg.put("times", timeMap);
501
502 return snapshotPkg;
503 }
504
505 /**
506 * @param snapshotTime
507 * @return Returns a ResultSet with all statistic information that matches the snapshot_time.
508 */
509 private ResultSet fetchSnapshotDataFromDB(Long snapshotTime) {
510 String query = "SELECT S.statsValueList AS statsValueList, M.statsNameList AS statsNameList, S.snapshot_time AS snapshot_time, M.mbeanName AS mbeanName FROM Statistics S, MBeans M WHERE S.snapshot_time=" + snapshotTime;
511 query += " AND S.mbeanId=M.id";
512 ResultSet retval = null;
513 try {
514 if(conn.isClosed()) {
515 openActiveConnection();
516 }
517 Statement stmt = conn.createStatement();
518 retval = stmt.executeQuery(query);
519 } catch(Exception e) {
520 log.error(e.getMessage(), e);
521 }
522 return retval;
523 }
524
525 /**
526 * @return Returns a ResultSet with one column (snapshot_time) sorted in descending order
527 */
528 private ResultSet fetchSnapshotTimesFromDB() {
529 String query = "SELECT DISTINCT snapshot_time FROM Statistics ORDER BY snapshot_time DESC";
530 ResultSet retval = null;
531 try {
532 if(conn.isClosed()) {
533 openActiveConnection();
534 }
535 Statement stmt = conn.createStatement();
536 retval = stmt.executeQuery(query);
537 } catch(Exception e) {
538 log.error(e.getMessage(), e);
539 }
540 return retval;
541 }
542
543 /**
544 * Opens the global connection to activeDB
545 */
546 private void openActiveConnection() {
547 try {
548 conn = activeDS.getConnection();
549 } catch(Exception e) {
550 log.error(e.getMessage(), e);
551 }
552 }
553
554 /**
555 * Opens the global connection to archiveDB
556 */
557 private void openArchiveConnection() {
558 try {
559 conn = archiveDS.getConnection();
560 } catch(Exception e) {
561 log.error(e.getMessage(), e);
562 }
563 }
564
565 /**
566 * Closes the global connection to a DB
567 */
568 private void closeConnection() {
569 if(conn != null) {
570 try {
571 conn.close();
572 } catch(Exception e) {
573 log.error(e.getMessage(), e);
574 }
575 }
576 }
577
578 /**
579 * @param mbeanName
580 * @param statsName
581 * @param numberOfSnapshots
582 * @param everyNthSnapshot
583 * @return HashMap which maps from a snapshot_time --> value of the mbean.statsName at that time
584 */
585 public TreeMap<Long, Long> getSpecificStatistics( String mbeanName,
586 String statsName,
587 int numberOfSnapshots,
588 int everyNthSnapshot,
589 boolean showArchived) {
590 openActiveConnection();
591 TreeMap<Long, Long> stats = new TreeMap<Long, Long>();
592 int nthSnapshot = 0;
593 // attempt to get as many snapshots from the active db as possible
594 try {
595 Statement stmt = conn.createStatement();
596 int mbeanId = getMBeanId(mbeanName);
597 if(mbeanId == -1) {
598 log.error(mbeanName + " does not exist in the database.");
599 } else {
600 String query = "SELECT DISTINCT snapshot_time, statsValueList, statsNameList FROM Statistics, MBeans M WHERE mbeanId=" + mbeanId + " AND mbeanId=M.id ORDER BY snapshot_time DESC";
601 ResultSet rs = stmt.executeQuery(query);
602 // iterate through the table paying attention to those at everyNthSnapshot-th position
603 while(rs.next()) {
604 // every nth snapshot I save the information into my returning hashmap
605 if(nthSnapshot % everyNthSnapshot == 0) {
606 String[] statsValueList = rs.getString(STATSVALUELIST).split(",");
607 String[] statsNameList = rs.getString(STATSNAMELIST).split(",");
608 assert(statsValueList.length == statsNameList.length);
609 Long statsValue = null;
610 for(int i = 0 ; i < statsNameList.length; i++) {
611 if(statsNameList[i].equals(statsName)) {
612 long value = Long.parseLong(statsValueList[i]);
613 statsValue = new Long(value);
614 }
615 }
616 // exit function after error
617 if(statsValue == null) {
618 log.warn("Statistics name '" + statsName + "' does not exist");
619 return stats;
620 } else {
621 stats.put(rs.getLong(SNAPSHOT_TIME), statsValue);
622 numberOfSnapshots--;
623 }
624 }
625 // update counter
626 nthSnapshot++;
627 // enough data, end this thing
628 if(numberOfSnapshots == 0) {
629 break;
630 }
631 }
632 }
633 } catch(Exception e) {
634 log.error(e.getMessage(), e);
635 } finally {
636 closeConnection();
637 }
638
639 nthSnapshot = 0;
640
641 // attempt to get the remaining snapshots requested from the archive DB
642 // iff the showArchive flag is set
643 if(showArchived && numberOfSnapshots != 0) {
644 try {
645 openArchiveConnection(); // connection to the Archive DB
646 Statement stmt = conn.createStatement();
647 int mbeanId = getMBeanId(mbeanName);
648 if(mbeanId == -1) {
649 log.error(mbeanName + " does not exist in the database.");
650 } else {
651 String query = "SELECT DISTINCT snapshot_time, statsValueList, statsNameList FROM Statistics, MBeans M WHERE mbeanId=" + mbeanId + " AND mbeanId=M.id ORDER BY snapshot_time DESC";
652 ResultSet rs = stmt.executeQuery(query);
653 // iterate through the table paying attention to those at everyNthSnapshot-th position
654 while(rs.next()) {
655 // every nth snapshot I save the information into my returning hashmap
656 if(nthSnapshot % everyNthSnapshot == 0) {
657 String[] statsValueList = rs.getString(STATSVALUELIST).split(",");
658 String[] statsNameList = rs.getString(STATSNAMELIST).split(",");
659 assert(statsValueList.length == statsNameList.length);
660 Long statsValue = null;
661 for(int i = 0 ; i < statsNameList.length; i++) {
662 if(statsNameList[i].equals(statsName)) {
663 long value = Long.parseLong(statsValueList[i]);
664 statsValue = new Long(value);
665 }
666 }
667 // exit function after error
668 if(statsValue == null) {
669 log.warn("Statistics name '" + statsName + "' does not exist");
670 return stats;
671 } else {
672 stats.put(rs.getLong(SNAPSHOT_TIME), statsValue);
673 numberOfSnapshots--;
674 }
675 }
676 // update counter
677 nthSnapshot++;
678 // enough data, end this thing
679 if(numberOfSnapshots == 0) {
680 break;
681 }
682 }
683 }
684 } catch(Exception e) {
685 log.error(e.getMessage(), e);
686 } finally {
687 closeConnection();
688 }
689 }
690 return stats;
691 }
692
693 /**
694 * Sets the necessary data sources for this helper to talk to the db
695 * @param activeDS
696 * @param archiveDS
697 */
698 public void setDataSources(DataSource active, DataSource archive) {
699 activeDS = active;
700 archiveDS = archive;
701 }
702 }