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 }