1 21 22 package uk.org.primrose.pool.jmx; 23 import com.sun.jdmk.comm.*; 24 import javax.management.*; 25 import javax.management.loading.*; 26 import javax.management.remote.*; 27 import javax.management.monitor.*; 28 import java.util.*; 29 import java.io.*; 30 import java.sql.ResultSet ; 31 import java.sql.SQLException ; 32 import java.lang.reflect.*; 33 import javax.naming.Context ; 34 import javax.naming.InitialContext ; 35 import uk.org.primrose.pool.datasource.PoolDataSource; 36 import uk.org.primrose.pool.jmx.html.*; 37 import javax.management.openmbean.*; 38 39 public class PoolController extends NotificationBroadcasterSupport implements PoolControllerMBean { private static MBeanServer _server; 41 protected static HtmlAdaptorServer _html; 42 private static MBeanInfo _MBeanInfo; 43 private static PoolController controller; 44 public static final String CONTROLLER_OBJECT_NAME = "PoolController Domain:name=PoolController"; 45 public static final String POOL_QUEUE_OBJECT_NAME = "Pool Domain"; 46 private ArrayList _mbeans = new ArrayList(); 47 private ArrayList _queues = new ArrayList(); 48 private ArrayList pools = new ArrayList(); 49 PoolControllerListener listener = null; 50 private Context ctx = null; 51 private String [] email = null; 52 private String poolConfigFile = ""; 53 private String adminWebManagementPort = "-1"; 54 private boolean emailNotifications = true; 55 private String adminUser = "admin"; 56 private String adminPassword = "admin"; 57 private int emailMaxWarningNumber = 10; 58 private long emailNotificationPeriod = 30000; 59 private String emailSMTPServer = ""; 60 private String adminEmailCrisisAddress = ""; 61 private AllPoolsOverview allPoolOverviewBean = null; 62 private String poolControllerLogFile = null; 63 private ObjectMonitor lastModifiedMonitor = null; 64 65 67 69 public String createNewPoolQueue(String poolName, Integer base, Integer overflow, String plog, 70 Integer idleTime, Boolean messageLogging, Boolean sizeLogging, 71 String driverClass, String driverURL, String user, String password, 72 String killActiveConnectionsOverAge, String cycleConnections, Boolean queueConnectionRequests, 73 Boolean runPooledMode, Boolean connectionAutoCommit, String connectionTransactionIsolation, String checkSQL) { 74 Properties props = new Properties(); 75 props.setProperty("poolName", poolName); 76 props.setProperty("base", base+""); 77 props.setProperty("overflow", overflow +""); 78 props.setProperty("plog", plog); 79 props.setProperty("idleTime", idleTime +""); 80 props.setProperty("messageLogging", messageLogging +""); 81 props.setProperty("sizeLogging", sizeLogging +""); 82 props.setProperty("driverClass", driverClass); 83 props.setProperty("driverURL", driverURL); 84 props.setProperty("user", user); 85 props.setProperty("password", password); 86 props.setProperty("killActiveConnectionsOverAge", killActiveConnectionsOverAge); 87 props.setProperty("cycleConnections", cycleConnections); 88 props.setProperty("queueConnectionRequests", queueConnectionRequests +""); 89 props.setProperty("runPooledMode", runPooledMode +""); 90 props.setProperty("connectionAutoCommit", connectionAutoCommit +""); 91 props.setProperty("connectionTransactionIsolation", connectionTransactionIsolation); 92 props.setProperty("checkSQL", checkSQL); 93 94 return createNewPoolQueue(props); 95 } 96 97 98 public String createNewPoolQueue(Properties props) { 99 100 114 116 Object tmpProp = null; 117 tmpProp = props.getProperty("poolName"); 119 String poolName = (tmpProp == null ? "noPoolNameSet" : (String )tmpProp); 120 ControllerLogger.log("[PoolController] Creating new pool - " +poolName); 122 123 124 tmpProp = props.getProperty("password"); 131 String password = (tmpProp == null ? "" : (String )tmpProp); 132 133 tmpProp = props.getProperty("encryptionKeyFile"); 134 String encryptionKeyFile = (tmpProp == null ? "" : (String )tmpProp); 135 136 if (this.getPoolConfigFile() != null || encryptionKeyFile != null) { 137 File f; 138 if (this.getPoolConfigFile() != null) { 139 File pcf = new File(this.getPoolConfigFile()); 140 String parentFileName = pcf.getParentFile().toString(); 141 if (parentFileName == null) { 142 parentFileName = "."; 143 } 144 f = new File(parentFileName +File.separator +"pool.keys"); 145 } else { 146 f = new File(encryptionKeyFile); 147 } 148 if (f.exists()) { 149 try { 150 ControllerLogger.log("[PoolController] Decrypting '" +password +"' using file " +f); 151 password = new PoolCryptoTool().getDecryptedString(password, f.toString()); 152 props.setProperty("password", password); 153 } catch (Exception e) { 154 e.printStackTrace(System.err); 155 ControllerLogger.log("[PoolController] ERROR : Cannot load pool because decryption of the password failed. See stderr for full stack trace. Tryed to load file : " +f); 156 return null; 157 } 158 159 } else { 160 ControllerLogger.log("[PoolController] INFO : Not using password encryption for db's because cannot find file : " +f.toString()); 161 } 162 } 163 164 try { 165 ObjectName objName = null; 166 MBeanServer mbs = null; 167 168 mbs = MBeanUtil.getMBeanServer(_server); 170 171 180 184 Queue _queue = new Queue(); 185 186 _queue.startNewPool(props); 188 189 objName = new ObjectName(POOL_QUEUE_OBJECT_NAME + ":name=Queue,pool=" +poolName); 191 MBeanUtil.registerMBean(_server, _queue, objName); 192 193 _mbeans.add(objName); 195 _queues.add(_queue); 196 197 PoolDataSource pds = new PoolDataSource(); 199 pds.setPoolName(poolName); 200 201 MBeanUtil.bind("q_" +poolName, _queue); 204 MBeanUtil.bind(poolName, pds); 205 ControllerLogger.log("[PoolController] DataSource " +pds +" bound to javax.naming.Context " +poolName); 206 207 AttributeChangeNotification acn = new AttributeChangeNotification(this, 209 0, 210 System.currentTimeMillis(), 211 ("[PoolController] Creating new pool - " +poolName), 213 "[PoolController] createNewPoolQueue", 214 "", 215 null, 216 null); 217 sendNotification(acn); 218 219 225 ObjectMonitor omonitor = new ObjectMonitor(); 227 omonitor.setName(poolName); 228 omonitor.setObservedObject(_queue); 229 omonitor.setObservedMethod("getWaitingThreads", null); 230 omonitor.setCheckValue("5"); 231 omonitor.setIncrementThreshold(true); 232 omonitor.setObservedMethodNotificationType(ObjectMonitor.THRESHOLD); 233 omonitor.setRefreshInterval(5000); 234 ObjectName monObjName = new ObjectName("Pool Monitor:name=ObjectMonitor([" +poolName +"] waiting threads)"); 235 236 MBeanUtil.registerMBean(_server, omonitor, monObjName); 237 _server.addNotificationListener(monObjName, listener, null, null); 238 omonitor.start(); 239 _queue.registerNewObjectMonitor(omonitor); 240 _mbeans.add(monObjName); 241 242 tmpProp = props.getProperty("idleTime"); 244 String idleTime = (tmpProp == null ? "-1" : (String )tmpProp); 245 246 if (!(idleTime.equals("-1"))) { 247 ObjectMonitor omonitor2 = new ObjectMonitor(); 248 omonitor2.setName(poolName); 249 omonitor2.setObservedObject(_queue); 250 omonitor2.setObservedMethod("checkIdleConnections", null); 251 omonitor2.setCheckValue("5"); 252 omonitor2.setIncrementThreshold(false); 253 omonitor2.setObservedMethodNotificationType(ObjectMonitor.THRESHOLD); 254 omonitor2.setRefreshInterval(10000); 255 monObjName = new ObjectName("Pool Monitor:name=ObjectMonitor([" +poolName +"] idle connections)"); 256 MBeanUtil.registerMBean(_server, omonitor2, monObjName); 257 _server.addNotificationListener(monObjName, listener, null, null); 258 omonitor2.start(); 259 _queue.registerNewObjectMonitor(omonitor2); 260 _mbeans.add(monObjName); 261 } 262 263 tmpProp = props.getProperty("log"); 267 String plog = (tmpProp == null ? null : (String )tmpProp); 268 269 if (plog != null) { 270 if (plog.indexOf("${") != -1) { 271 ObjectMonitor omonitor3 = new ObjectMonitor(); 273 omonitor3.setName(poolName); 274 omonitor3.setObservedObject(_queue); 275 omonitor3.setObservedMethod("setUpLog", null); 276 omonitor3.setCheckValue("0"); 277 omonitor3.setIncrementThreshold(true); 278 omonitor3.setObservedMethodNotificationType(ObjectMonitor.DIFFERING); 279 omonitor3.setRefreshInterval(60000); 280 monObjName = new ObjectName("Pool Monitor:name=ObjectMonitor([" +poolName +"] pool log cycling)"); 281 MBeanUtil.registerMBean(_server, omonitor3, monObjName); 282 _server.addNotificationListener(monObjName, listener, null, null); 283 omonitor3.start(); 284 _queue.registerNewObjectMonitor(omonitor3); 285 _mbeans.add(monObjName); 286 } 287 } 288 289 tmpProp = props.getProperty("killActiveConnectionsOverAge"); 293 String killActiveConnectionsOverAge = (tmpProp == null ? "-1" : (String )tmpProp); 294 295 if (!(killActiveConnectionsOverAge.equals("-1"))) { 296 ObjectMonitor omonitor4 = new ObjectMonitor(); 297 omonitor4.setName(poolName); 298 omonitor4.setObservedObject(_queue); 299 omonitor4.setObservedMethod("checkActiveConnectionTimes", null); 300 omonitor4.setCheckValue("5"); 301 omonitor4.setIncrementThreshold(false); 302 omonitor4.setObservedMethodNotificationType(ObjectMonitor.THRESHOLD); 303 omonitor4.setRefreshInterval(5000); 304 monObjName = new ObjectName("Pool Monitor:name=ObjectMonitor([" +poolName +"] active connections kill daemon)"); 305 MBeanUtil.registerMBean(_server, omonitor4, monObjName); 306 _server.addNotificationListener(monObjName, listener, null, null); 307 omonitor4.start(); 308 _queue.registerNewObjectMonitor(omonitor4); 309 _mbeans.add(monObjName); 310 } 311 312 313 allPoolOverviewBean.addPoolData(_queue); 314 315 } catch (Exception e) { 316 e.printStackTrace(); 317 ControllerLogger.log(e.toString()); 318 return "ERROR"; 319 } 320 321 322 return poolName +" successfully started."; 323 324 } 325 326 329 public ArrayList getQueues() { 330 return this._queues; 331 } 332 333 337 public Queue getQueue(String queueName) { 338 Queue queue = null; 339 try { 340 MBeanServer mbs = MBeanUtil.getMBeanServer(_server); 341 ObjectName name = new ObjectName(POOL_QUEUE_OBJECT_NAME + ":name=Queue,pool=" +queueName); 342 QueryExp query = null; 343 Iterator results = (mbs.queryMBeans(name, query)).iterator(); 344 345 while (results.hasNext()) { 346 ObjectName on = ((ObjectInstance)results.next()).getObjectName(); 347 ControllerLogger.log("[PoolController] Locked to : " +on.toString()); 348 for (int i = 0; i < _queues.size(); i++) { 349 queue = (Queue)_queues.get(i); 350 if (queue.getName().equals(queueName)) { 351 ControllerLogger.log("[PoolController] Queue found : " +queue +" " +queue.getName()); 352 return queue; 353 } 354 } 355 356 } 357 } catch (Exception e) { 358 e.printStackTrace(System.err); 359 } 360 361 return null; 362 } 363 364 367 public void startAllPoolQueues() { 368 ObjectName on = null; 369 Queue queue = null; 370 String q = ""; 371 try { 372 MBeanServer mbs = MBeanUtil.getMBeanServer(_server); 373 ObjectName name = new ObjectName(POOL_QUEUE_OBJECT_NAME + ":*"); 374 QueryExp query = null; 375 Iterator results = (mbs.queryMBeans(name, query)).iterator(); 376 while (results.hasNext()) { 377 on = ((ObjectInstance)results.next()).getObjectName(); 378 ControllerLogger.log("[PoolController] Locked to : " +on.toString()); 379 for (int i = 0; i < _queues.size(); i++) { 380 queue = (Queue)_queues.get(i); 381 if (on.toString().indexOf(queue.getName()) != -1) { 382 queue.startPool(); 383 q += (on +" " +queue +"\n"); 384 } 385 } 386 387 } 388 AttributeChangeNotification acn = new AttributeChangeNotification(this, 389 0, 390 System.currentTimeMillis(), 391 q, 392 "[PoolController] startAllPoolQueues", 393 "", 394 null, 395 null); 396 sendNotification(acn); 397 } catch (Exception e) { 398 ControllerLogger.log("[PoolController] : ERROR: " + "Error stoppping pool queue MBean " +on +" " +queue +" !"); 399 e.printStackTrace(); 400 } 401 } 402 403 406 public void stopAllPoolQueues() { 407 ObjectName on = null; 408 Queue queue = null; 409 String q = ""; 410 if (lastModifiedMonitor != null) lastModifiedMonitor.stop(); 411 try { 412 MBeanServer mbs = MBeanUtil.getMBeanServer(_server); 413 ObjectName name = new ObjectName(POOL_QUEUE_OBJECT_NAME + ":*"); 414 QueryExp query = null; 415 Iterator results = (mbs.queryMBeans(name, query)).iterator(); 416 while (results.hasNext()) { 417 on = ((ObjectInstance)results.next()).getObjectName(); 418 ControllerLogger.log("[PoolController] Locked to : " +on.toString()); 419 for (int i = 0; i < _queues.size(); i++) { 420 queue = (Queue)_queues.get(i); 421 if (on.toString().indexOf(queue.getName()) != -1) { 422 queue.stopPool(); 423 q += (on +" " +queue +"\n"); 424 } 425 } 426 427 } 428 AttributeChangeNotification acn = new AttributeChangeNotification(this, 429 0, 430 System.currentTimeMillis(), 431 q, 432 "[PoolController] stopAllPoolQueues", 433 "", 434 null, 435 null); 436 sendNotification(acn); 437 } catch (Exception e) { 438 ControllerLogger.log("[PoolController] : ERROR: " + "Error stoppping pool queue MBean " +on +" " +queue +" !"); 439 e.printStackTrace(); 440 } 441 } 442 443 446 public void reset() { 447 stopAllPoolQueues(); 448 try { Thread.sleep(1000); } catch (Exception e) {} 449 startAllPoolQueues(); 450 451 } 452 453 456 public static boolean restartSinglePool(String poolName) { 457 ControllerLogger.log("[PoolController] Got request to restart single pool queue : " +poolName); 458 Queue queue = controller.getQueue(poolName); 459 if (queue == null) { 460 ControllerLogger.log("[PoolController] Cannot locate pool queue under name : " +poolName); 461 return false; 462 } 463 464 String n = queue.getName(); 465 ControllerLogger.log("[PoolController] Stopping pool : " +n); 466 queue.stopPool(); 467 try { Thread.sleep(1000); } catch (Exception e) {} 468 ControllerLogger.log("[PoolController] Starting pool : " +n); 469 queue.startPool(); 470 471 AttributeChangeNotification acn = new AttributeChangeNotification(controller, 472 0, 473 System.currentTimeMillis(), 474 "restartSinglePool(" +poolName +")", 475 "[PoolController] restarted pool : " +poolName, 476 "", 477 null, 478 null); 479 controller.sendNotification(acn); 480 return true; 481 } 482 483 487 public static boolean startSinglePool(String poolName) { 488 ControllerLogger.log("[PoolController] Got request to start single pool queue : " +poolName); 489 Queue queue = controller.getQueue(poolName); 490 if (queue == null) { 491 ControllerLogger.log("[PoolController] Cannot locate pool queue under name : " +poolName); 492 return false; 493 } 494 495 String n = queue.getName(); 496 ControllerLogger.log("[PoolController] Starting pool : " +n); 497 queue.startPool(); 498 499 AttributeChangeNotification acn = new AttributeChangeNotification(controller, 500 0, 501 System.currentTimeMillis(), 502 "startSinglePool(" +poolName +")", 503 "[PoolController] Started pool : " +poolName, 504 "", 505 null, 506 null); 507 controller.sendNotification(acn); 508 return true; 509 } 510 511 515 public static boolean stopSinglePool(String poolName) { 516 ControllerLogger.log("[PoolController] Got request to stop single pool queue : " +poolName); 517 Queue queue = controller.getQueue(poolName); 518 if (queue == null) { 519 ControllerLogger.log("[PoolController] Cannot locate pool queue under name : " +poolName); 520 return false; 521 } 522 523 String n = queue.getName(); 524 ControllerLogger.log("[PoolController] Stopping pool : " +n); 525 queue.stopPool(); 526 527 AttributeChangeNotification acn = new AttributeChangeNotification(controller, 528 0, 529 System.currentTimeMillis(), 530 "stopSinglePool(" +poolName +")", 531 "[PoolController] stopped pool : " +poolName, 532 "", 533 null, 534 null); 535 controller.sendNotification(acn); 536 return true; 537 } 538 539 public static void restartAllPools() { 540 controller.reset(); 541 } 542 543 546 public Boolean refreshPoolConfigFile() { 547 548 ArrayList oldPools = new ArrayList(); 550 for (int i = 0; i < pools.size(); i++) { 551 oldPools.add(pools.get(i)); 552 } 553 554 555 try { 557 loadPoolsFromConfigFile(false); 558 } catch (IOException ioe) { 559 ioe.printStackTrace(System.err); 560 return new Boolean ("false"); 561 } 562 563 if (oldPools.size() == pools.size()) { 564 for (int i = 0; i < pools.size(); i++) { 566 Properties pool = (Properties)pools.get(i); 567 for (int j = 0; j < pools.size(); j++) { 568 Properties oldPool = (Properties)oldPools.get(j); 569 if (pool.getProperty("poolName").equals(oldPool.getProperty("poolName"))) { 570 Set s = pool.entrySet(); 571 Set s1 = oldPool.entrySet(); 572 if (!s.equals(s1)) { 573 Queue q = getQueue(pool.getProperty("poolName")); 575 ControllerLogger.log("[PoolController] Restarting " +pool.getProperty("poolName")); 576 577 boolean queueConnectionRequests = true; 578 if (pool.getProperty("queueConnectionRequests") != null) { 579 queueConnectionRequests = new Boolean (pool.getProperty("queueConnectionRequests")).booleanValue(); 580 } 581 582 boolean runPooledMode = true; 583 if (pool.getProperty("runPooledMode") != null) { 584 runPooledMode = new Boolean (pool.getProperty("runPooledMode")).booleanValue(); 585 } 586 587 boolean connectionAutoCommit = true; 588 if (pool.getProperty("connectionAutoCommit") != null) { 589 connectionAutoCommit = new Boolean (pool.getProperty("connectionAutoCommit")).booleanValue(); 590 } 591 592 593 q.stopPool(); 594 q.restartPool( 595 pool.getProperty("poolName"), 596 new Integer (pool.getProperty("base")).intValue(), 597 new Integer (pool.getProperty("overflow")).intValue(), 598 pool.getProperty("log"), 599 new Integer (pool.getProperty("idleTime")), 600 new Boolean (pool.getProperty("messageLogging")), 601 new Boolean (pool.getProperty("sizeLogging")), 602 pool.getProperty("driverClass"), 603 pool.getProperty("driverURL"), 604 pool.getProperty("user"), 605 pool.getProperty("password"), 606 pool.getProperty("killActiveConnectionsOverAge"), 607 pool.getProperty("cycleConnections"), 608 queueConnectionRequests, 609 runPooledMode, 610 connectionAutoCommit, 611 pool.getProperty("connectionTransactionIsolation"), 612 pool.getProperty("checkSQL") 613 ); 614 break; 615 } 616 } 617 } 618 619 620 } 621 } else if (oldPools.size() < pools.size()) { 623 for (int i = 0; i < pools.size(); i++) { 624 Properties pool = (Properties)pools.get(i); 625 Queue q = getQueue(pool.getProperty("poolName")); 626 if (q == null) { 627 Boolean queueConnectionRequests = new Boolean ("true"); 628 if (pool.getProperty("queueConnectionRequests") != null) { 629 queueConnectionRequests = new Boolean (pool.getProperty("queueConnectionRequests")); 630 } 631 632 Boolean runPooledMode = new Boolean ("true"); 633 if (pool.getProperty("runPooledMode") != null) { 634 runPooledMode = new Boolean (pool.getProperty("runPooledMode")); 635 } 636 637 638 this.createNewPoolQueue(pool); 639 } 640 } 641 } else { 643 for (int i = 0; i < oldPools.size(); i++) { 644 Properties oldPool = (Properties)oldPools.get(i); 645 String s = oldPool.getProperty("poolName"); 646 for (int j = 0; j < pools.size(); j++) { 647 Properties pool = (Properties)pools.get(j); 648 if (s.equals(pool.getProperty("poolName"))) { 649 break; 650 } 651 if(j == pools.size()-1) { 652 Queue q = getQueue(s); 655 q.stopPool(); 656 MBeanUtil.unRegisterSingle(_server, _mbeans, s); 657 try { 658 ctx = new InitialContext (); 659 ctx.unbind("q_" +s); 660 ctx.unbind(s); 661 } catch (javax.naming.NamingException ne) { 662 ne.printStackTrace(System.err); 663 } 664 } 665 666 } 667 } 668 } 669 670 return new Boolean ("true"); 671 } 672 673 public void loadPoolsFromConfigFile(String poolConfigFile, boolean actuallyLoad) throws IOException { 674 setPoolConfigFile(poolConfigFile); 675 loadPoolsFromConfigFile(actuallyLoad); 676 } 677 678 public void loadPoolsFromConfigFile(Properties pool) throws IOException { 679 if (pool.getProperty("poolName") == null) { 680 CharArrayWriter caw = new CharArrayWriter(); 681 for (Enumeration e = pool.propertyNames() ; e.hasMoreElements() ;) { 682 String key = (String )e.nextElement(); 683 caw.write(key +"=" +pool.getProperty(key) +"\n"); 684 } 685 686 BufferedReader br = new BufferedReader(new StringReader(caw.toString())); 687 setAdminDetails(br); 688 } else { 689 this.createNewPoolQueue(pool); 690 } 691 } 692 693 public void loadPoolsFromConfigFile(boolean actuallyLoad) throws IOException { 694 BufferedReader br = new BufferedReader(new FileReader(this.getPoolConfigFile())); 695 loadPoolsFromConfigFile(br, actuallyLoad); 696 } 697 698 public void loadPoolsFromConfigFile(BufferedReader br, boolean actuallyLoad) throws IOException { 699 String line = ""; 700 Properties pool = null; 701 if (pools != null) pools.clear(); 702 while ((line = br.readLine()) != null) { 703 if (!line.trim().startsWith("#") && !line.trim().equals("")) { 704 StringTokenizer st = new StringTokenizer(line, "="); 705 int cnt = st.countTokens(); 706 String key = st.nextToken(); 707 String value = ""; 708 while (st.hasMoreTokens()) { 709 value += (st.nextToken() +"="); 710 } 711 712 if (value.length() != 0) { 713 value = value.substring(0, value.length() -1); 714 } 715 716 if (key.startsWith("admin")) { 718 continue; 719 } 720 721 if (key.equals("poolName")) { 722 if (pool != null) { 723 pools.add(pool); 724 if (actuallyLoad) createNewPoolQueue(pool); 725 } 726 pool = new Properties(); 727 } 728 729 pool.setProperty(key, value); 730 } 731 } 732 733 br.close(); 734 735 pools.add(pool); 736 737 if (actuallyLoad) createNewPoolQueue(pool); 738 739 740 } 741 742 743 751 public static void main (String [] args) { 752 PoolController pc = new PoolController(); 753 pc.init(args); 754 } 755 756 757 public PoolController() { 758 super(); 759 760 PoolShutdownHook hook = new PoolShutdownHook(this); 762 Runtime.getRuntime().addShutdownHook(hook); 763 764 } 765 766 private void printInitMessage() { 767 ControllerLogger.log(""); 768 ControllerLogger.log("---------------------------------"); 769 ControllerLogger.log("[Primrose] initialising at " +new java.util.Date () +" ..."); 770 ControllerLogger.log("\tPrimrose version 2.7.3"); 772 } 773 774 private void createPoolControllerLog(String logFile) { 775 if (logFile == null) { 776 logFile = "./PoolController.log"; 777 System.out.println("WARNING ! Primrose init : as of version 2.6.1, the PoolController.log location " + 778 "is specified in the poolConfig.properties file, eg : " + 779 "\n\tadminPoolControllerLogFile=/var/log/PoolController.log " + 780 "\nThis has not been added, so am writing to the CWD (.) !"); 781 } 782 783 try { 787 File f = new File(logFile); 788 if (!f.exists()) { 789 f.createNewFile(); 790 } 791 792 if (f.canWrite()) { 793 ControllerLogger.setLogWriter(new PrintWriter(new FileOutputStream(f, true), true)); 794 } else { 795 System.err.println("[PoolController] Error initializing Primrose : Cannot write to log file : " +f.toString()); 796 } 797 798 } catch (Exception e) { 799 e.printStackTrace(System.err); 800 } 801 802 } 803 804 807 public void init(String [] args) { 808 controller = this; 809 810 _server = MBeanUtil.getMBeanServer(_server); 811 try { 812 813 if (this.getPoolControllerLogFile() == null) { 816 System.out.println("\n\n-------------------------------------------\n" + 817 "[PoolController] WARNING !!!\n\tYou have not loaded a config with admin settings yet.\n" + 818 "\tAs of v2.6.1, this is not recommended, you must load a config file that contains \n"+ 819 "\tthe PoolController log file location), eg :\n" + 820 "\t\t\tadminPoolControllerLogFile=/var/log/PoolController.log\n" + 821 "\tThis should be added in the \"admin\" section, not the pool instance section.\n" + 822 "\tIf you want to run the admin controller in silent mode (ie no logging), then set value to 'none'\n" + 823 "\tFor now, we'll continue loading, but with a default log (./PoolController.log) ... \n\tplease change this in the future !" + 824 "\n\n-------------------------------------------\n\n\n"); 825 826 setPoolControllerLogFile("./PoolController.log"); 827 } 828 829 ObjectName objName = null; 830 setDescription(); 832 833 objName = new ObjectName(PoolController.CONTROLLER_OBJECT_NAME); 834 ControllerLogger.log("\tOBJECT NAME = " + objName); 835 _server.registerMBean(controller, objName); 836 controller._mbeans.add(objName); 837 838 int port = Integer.parseInt(getAdminWebManagementPort()); 839 842 if (port != -1) { 843 848 String adminPasswd = this.getAdminPassword(); 849 String encryptionKeyFile = null; 850 if (args.length > 0) { 851 encryptionKeyFile = args[0]; 852 } 853 if (this.getPoolConfigFile() != null || encryptionKeyFile != null) { 854 File f = null; 855 856 if (this.getPoolConfigFile() != null) { 857 File pcf = new File(this.getPoolConfigFile()); 858 String parentFileName = pcf.getParentFile().toString(); 859 if (parentFileName == null) { 860 parentFileName = "."; 861 } 862 f = new File(parentFileName +File.separator +"pool.keys"); 863 } else { 864 f = new File(encryptionKeyFile); 865 } 866 867 868 if (f.exists()) { 869 if (adminPasswd.indexOf("__EQUALS__") != -1) { 870 try { 871 ControllerLogger.log("[PoolController] Decrypting admin password '" +adminPasswd +"' from : " +f); 872 adminPasswd = new PoolCryptoTool().getDecryptedString(adminPasswd, f.toString()); 873 this.adminPassword = adminPasswd; 874 } catch (Exception e) { 875 e.printStackTrace(System.err); 876 ControllerLogger.log("[PoolController] ERROR : Cannot load PoolController because decryption of the password failed. See stderr for full stack trace"); 877 return; 878 } 879 } 880 881 } else { 882 ControllerLogger.log("[PoolController] INFO : Not using password encryption for web management tool because cannot find file : " +f.toString()); 883 } 884 } 885 886 _html = MBeanUtil.createHTMLAdapter(_html, _server, _mbeans, this.getAdminUser(), adminPasswd, Integer.parseInt(getAdminWebManagementPort())); 887 888 if (getAdminUser().equals("none") && adminPasswd.equals("none")) { 889 ControllerLogger.log("[PoolController] Created web management tool on port(" +getAdminWebManagementPort() +"), with NO authentication (user and password are set to \"none\" in the poolConfig.properties file !"); 890 } else { 891 ControllerLogger.log("[PoolController] Created web management tool on port(" +getAdminWebManagementPort() +"), user(" +getAdminUser() +"), password(" +getAdminPassword() +")"); 892 } 893 } 894 895 899 904 listener = new PoolControllerListener(); 906 ControllerLogger.log("[PoolController] Add notification listener to " +objName +"..."); 907 _server.addNotificationListener(objName, listener, null, null); 908 909 if (this.getPoolConfigFile() != null) { 911 File f = new File(this.getPoolConfigFile()); 912 lastModifiedMonitor = new ObjectMonitor(); 913 lastModifiedMonitor.setObservedObject(f); 914 lastModifiedMonitor.setObservedMethod("lastModified", null); 915 lastModifiedMonitor.setObservedMethodNotificationType(ObjectMonitor.DIFFERING); 916 lastModifiedMonitor.setCheckValue(f.lastModified() +""); 917 lastModifiedMonitor.setRefreshInterval(2000); 918 ObjectName monObjName = new ObjectName("Pool Monitor:name=ObjectMonitor(config file deployer)"); 920 _server.registerMBean(lastModifiedMonitor, monObjName); 921 _server.addNotificationListener(monObjName, listener, null, null); 922 _mbeans.add(monObjName); 924 } 925 926 MBeanUtil.bind("pool", controller); 927 928 try { 929 } catch (Exception e) { 938 e.printStackTrace(); 939 } 940 941 allPoolOverviewBean = new AllPoolsOverview(); 944 ObjectName monObjName = new ObjectName("Overview of All Pools:name=AllPoolsOverview"); 945 _server.registerMBean(allPoolOverviewBean, monObjName); 946 _mbeans.add(monObjName); 947 948 950 } catch (Exception e) { 951 e.printStackTrace(System.err); 952 ControllerLogger.log("[PoolController] initialisation : ERROR: " + "Could not register the Controller MBean ... " +e); 953 954 return; 955 } 956 957 } 958 959 962 963 public void destroy() { 964 try { 965 ctx = new InitialContext (); 966 for (int i = 0; i < _queues.size(); i++) { 967 String n = ((Queue)_queues.get(i)).getName(); 968 969 if (ctx != null) { 970 971 try { ctx.unbind(n); } catch (Exception e) {} 972 try { ctx.unbind("q_" +n); } catch (Exception e) {} 973 } 974 ControllerLogger.log("[PoolController] Unbinding " +n +"..."); 975 ControllerLogger.log("[PoolController] Unbinding q_" +n +"..."); 976 977 } 978 ControllerLogger.log("[PoolController] Stopping all pool queues ..."); 979 controller.stopAllPoolQueues(); 980 ControllerLogger.log("[PoolController] Stopping HTML monitor thread..."); 981 if (_html != null) _html.stop(); 982 983 ControllerLogger.log("[PoolController] Unregistering mbeans ..."); 984 MBeanUtil.unRegisterAll(_server, _mbeans); 985 986 _mbeans.removeAll(_mbeans); 987 pools.removeAll(pools); 988 _queues.removeAll(_queues); 989 990 ControllerLogger.log("[PoolController] Shut down."); 991 992 } catch (Exception e) { 993 e.printStackTrace(System.err); 994 } 995 996 997 998 } 999 1000 1002 1004 public void setPoolControllerLogFile(String poolControllerLogFile) { 1005 this.poolControllerLogFile = poolControllerLogFile; 1006 ControllerLogger.closeLogWriter(); 1007 if (poolControllerLogFile.equals("none")) { 1008 ControllerLogger.setLogWriter(null); 1011 } else { 1012 createPoolControllerLog(poolControllerLogFile); 1014 printInitMessage(); 1015 } 1016 1017 } 1018 1019 public String getPoolControllerLogFile() { 1020 return poolControllerLogFile; 1021 } 1022 1023 public void setPoolConfigFile(String poolConfigFile) { 1024 this.poolConfigFile = poolConfigFile; 1025 } 1026 1027 public String getPoolConfigFile() { 1028 return poolConfigFile; 1029 } 1030 1031 public String [] getEmail() { 1032 return email; 1033 } 1034 1035 public void setEmail(String [] email) { 1036 this.email = email; 1037 } 1038 1039 public void setAdminWebManagementPort(String adminWebManagementPort) { 1040 this.adminWebManagementPort = adminWebManagementPort; 1041 } 1042 1043 public String getAdminWebManagementPort() { 1044 return adminWebManagementPort; 1045 } 1046 1047 public boolean getEmailNotifications() { 1048 return emailNotifications; 1049 } 1050 1051 public void setEmailNotifications(boolean emailNotifications) { 1052 this.emailNotifications = emailNotifications; 1053 1054 } 1055 1056 public long getEmailNotificationPeriod() { 1057 return emailNotificationPeriod; 1058 } 1059 1060 public void setEmailNotificationPeriod(long emailNotificationPeriod) { 1061 this.emailNotificationPeriod = emailNotificationPeriod; 1062 } 1063 1064 public int getEmailMaxWarningNumber() { 1065 return emailMaxWarningNumber; 1066 } 1067 1068 public void setEmailMaxWarningNumber(int emailMaxWarningNumber) { 1069 this.emailMaxWarningNumber = emailMaxWarningNumber; 1070 } 1071 1072 public String getEmailSMTPServer() { 1073 return emailSMTPServer; 1074 } 1075 1076 public void setEmailSMTPServer(String emailSMTPServer) { 1077 this.emailSMTPServer = emailSMTPServer; 1078 } 1079 1080 public String getAdminUser() { 1081 return adminUser; 1082 } 1083 1084 public void setAdminUser(String adminUser) { 1085 this.adminUser = adminUser; 1086 } 1087 1088 public String getAdminPassword() { 1089 return adminPassword; 1090 } 1091 1092 public void setAdminPassword(String adminPassword) { 1093 this.adminPassword = adminPassword; 1094 } 1095 1096 public String getEmailCrisisAddress() { 1097 return adminEmailCrisisAddress; 1098 } 1099 1100 public void setEmailCrisisAddress(String adminEmailCrisisAddress) { 1101 this.adminEmailCrisisAddress = adminEmailCrisisAddress; 1102 } 1103 1104 1105 1107 1109 public void setAdminDetails(String fileName) throws IOException { 1110 1111 BufferedReader br = new BufferedReader(new FileReader(fileName)); 1112 setAdminDetails(br); 1113 } 1114 1115 public void setAdminDetails(BufferedReader br) throws IOException { 1116 boolean havePoolControllerLogFileFlag = false; 1119 String line = ""; 1120 while ((line = br.readLine()) != null) { 1121 1122 if (!line.trim().startsWith("#") && !line.trim().equals("")) { 1123 StringTokenizer st = new StringTokenizer(line, "="); 1124 int cnt = st.countTokens(); 1125 String key = st.nextToken(); 1126 String value = ""; 1127 if (cnt >= 2) value = st.nextToken(); 1128 1129 if (key.startsWith("admin")) { 1130 if (key.equals("adminUser")) { 1131 this.setAdminUser(value); 1132 } else if (key.equals("adminPassword")) { 1133 this.setAdminPassword(value); 1134 } else if (key.equals("adminWebManagementPort")) { 1135 this.setAdminWebManagementPort(value); 1136 } else if (key.equals("adminEmailAddresses")) { 1137 1138 StringTokenizer st1 = new StringTokenizer(value, ", "); 1139 email = new String [st1.countTokens()]; 1140 int i = 0; 1141 while (st1.hasMoreTokens()) { 1142 email[i++] = st1.nextToken(); 1143 } 1144 this.setEmail(email); 1145 } else if (key.equals("adminEmailNotifcations") || key.equals("adminEmailNotifications")) { 1146 this.setEmailNotifications(new Boolean (value).booleanValue()); 1147 } else if (key.equals("adminEmailSMTPServer")) { 1148 this.setEmailSMTPServer(value); 1149 } else if (key.equals("adminEmailNotificationPeriod")) { 1150 if (value.length() != 0) 1151 this.setEmailNotificationPeriod(Long.parseLong(value)); 1152 } else if (key.equals("adminEmailMaxWarningNumber")) { 1153 if (value.length() != 0) 1154 this.setEmailMaxWarningNumber(Integer.parseInt(value)); 1155 } else if (key.equals("adminEmailCrisisAddress")) { 1156 this.setEmailCrisisAddress(value); 1157 } else if (key.equals("adminPoolControllerLogFile")) { 1158 this.setPoolControllerLogFile(value); 1159 1160 havePoolControllerLogFileFlag = true; 1161 } else { 1162 ControllerLogger.log("[PoolController] unrecognised admin setting - ignoring line :" +line); 1163 } 1164 } 1165 } 1166 } 1167 1168 if (!havePoolControllerLogFileFlag) { 1170 this.setPoolControllerLogFile(null); 1171 } 1172 1173 br.close(); 1174 } 1175 1176 1180 private void callSetMethod(Attribute att) { 1181 Class targetClass = this.getClass(); 1182 Method[] publicMethods = targetClass.getMethods(); 1183 for (int j = 0; j < publicMethods.length; j++) { 1184 String fieldName = publicMethods[j].getName(); 1185 Class typeClass = publicMethods[j].getReturnType(); 1186 String fieldType = typeClass.getName(); 1187 1189 if (("set" +att.getName()).equalsIgnoreCase(fieldName)) { 1190 try { 1191 publicMethods[j].invoke(this, new Object []{att.getValue()}); 1192 } catch (IllegalAccessException iae) { 1193 iae.printStackTrace(System.err); 1194 } catch (InvocationTargetException ite) { 1195 ite.printStackTrace(System.err); 1196 } 1197 1198 } 1199 } 1200 } 1201 1202 1206 private Object callGetMethod(String attributeName) { 1207 Class targetClass = this.getClass(); 1209 Method[] publicMethods = targetClass.getMethods(); 1210 for (int j = 0; j < publicMethods.length; j++) { 1211 String fieldName = publicMethods[j].getName(); 1212 Class typeClass = publicMethods[j].getReturnType(); 1213 String fieldType = typeClass.getName(); 1214 1216 if (("get" +attributeName).equalsIgnoreCase(fieldName)) { 1217 try { 1218 return publicMethods[j].invoke(this, null); 1220 } catch (IllegalAccessException iae) { 1221 iae.printStackTrace(System.err); 1222 } catch (InvocationTargetException ite) { 1223 ite.printStackTrace(System.err); 1224 } 1225 1226 } 1227 } 1228 return null; 1229 } 1230 1231 1235 public void setDescription() { 1236 OpenMBeanOperationInfo[] operationInfo = new OpenMBeanOperationInfo[5]; 1237 1238 operationInfo[0] = new OpenMBeanOperationInfoSupport( 1239 "stopAllPoolQueues", "Stop all queues, close all connections(and kill active connections). Contexts are NOT unbound.", new OpenMBeanParameterInfo[]{}, SimpleType.VOID, MBeanOperationInfo.ACTION ); 1246 operationInfo[1] = new OpenMBeanOperationInfoSupport( 1247 "reset", "This will stop all the pool queues, and then restart. In effect, cycles all live connections. \nSee stopAllPoolQueues() and startAllPoolQueues() description.", new OpenMBeanParameterInfo[]{}, 1251 SimpleType.VOID, MBeanOperationInfo.ACTION ); 1254 OpenMBeanParameterInfo[] signature = new OpenMBeanParameterInfo[13]; 1255 signature[0] = new OpenMBeanParameterInfoSupport( 1256 "poolName", "The JNDI pool name.", SimpleType.STRING 1259 ); 1260 signature[1] = new OpenMBeanParameterInfoSupport( 1261 "base", "The number of base connections allowed.", SimpleType.INTEGER 1264 ); 1265 signature[2] = new OpenMBeanParameterInfoSupport( 1266 "overflow", "The number of overflow connections allowed.", SimpleType.INTEGER 1269 ); 1270 signature[3] = new OpenMBeanParameterInfoSupport( 1271 "log", "Pool Queue's log file.", SimpleType.STRING 1274 ); 1275 1276 signature[4] = new OpenMBeanParameterInfoSupport( 1277 "idleTime", "The idle time for the (non-active) connections to timeout and be dumped.", SimpleType.INTEGER 1280 ); 1281 signature[5] = new OpenMBeanParameterInfoSupport( 1282 "messageLogging", "Turn on/off pool message logging.", SimpleType.BOOLEAN 1285 ); 1286 signature[6] = new OpenMBeanParameterInfoSupport( 1287 "sizeLogging", "Turn on/off pool size logging", SimpleType.BOOLEAN 1290 ); 1291 signature[7] = new OpenMBeanParameterInfoSupport( 1292 "driverClass", "Database driver class.", SimpleType.STRING 1295 ); 1296 signature[8] = new OpenMBeanParameterInfoSupport( 1297 "driverURL", "Database connection URL.", SimpleType.STRING 1300 ); 1301 1302 signature[9] = new OpenMBeanParameterInfoSupport( 1303 "user", "Database schema user.", SimpleType.STRING 1306 ); 1307 signature[10] = new OpenMBeanParameterInfoSupport( 1308 "password", "Database schema password.", SimpleType.STRING 1311 ); 1312 1313 signature[11] = new OpenMBeanParameterInfoSupport( 1314 "killActiveConnectionsOverAge", "Kill Active Connections Over Age (milliseconds).", SimpleType.STRING 1317 ); 1318 1319 signature[12] = new OpenMBeanParameterInfoSupport( 1320 "cycleConnections", "After n number of SQL transactions for a connection, cycle it", SimpleType.STRING 1323 ); 1324 1325 operationInfo[2] = new OpenMBeanOperationInfoSupport( 1326 "createNewPoolQueue", "Start a new pool.", signature, SimpleType.STRING, MBeanOperationInfo.ACTION ); 1332 1333 operationInfo[3] = new OpenMBeanOperationInfoSupport( 1334 "refreshPoolConfigFile", "Refresh the pool config file data (ie reload pools if data changed).", new OpenMBeanParameterInfo[]{}, 1338 SimpleType.BOOLEAN, MBeanOperationInfo.ACTION ); 1341 1342 operationInfo[4] = new OpenMBeanOperationInfoSupport( 1343 "startAllPoolQueues", "Start all queues, usually used after a stopAllPoolQueues() operation.", new OpenMBeanParameterInfo[]{}, 1347 SimpleType.VOID, MBeanOperationInfo.ACTION ); 1350 1351 OpenMBeanAttributeInfo[] attributeInfo = new OpenMBeanAttributeInfo[10]; 1352 try { 1353 attributeInfo[0] = new OpenMBeanAttributeInfoSupport( 1354 "email", 1355 "Email notification addresses for pool events.", 1356 new ArrayType(1, SimpleType.STRING), 1357 true, 1358 true, 1359 false 1360 ); 1361 1362 attributeInfo[1] = new OpenMBeanAttributeInfoSupport( 1363 "poolConfigFile", 1364 "The configuration file for the pool.", 1365 SimpleType.STRING, 1366 true, 1367 true, false 1369 ); 1370 1371 attributeInfo[2] = new OpenMBeanAttributeInfoSupport( 1372 "emailNotifications", 1373 "Whether or not email notifications for pool events should be enabled (events are the pools starting or stopping, and pool crisis information).", 1374 SimpleType.BOOLEAN, 1375 true, 1376 true, 1377 false 1378 ); 1379 1380 attributeInfo[3] = new OpenMBeanAttributeInfoSupport( 1381 "adminWebManagementPort", 1382 "The port that this tool can be accessed from (set in the poolConfig.properties file).", 1383 SimpleType.STRING, 1384 true, 1385 false, 1386 false 1387 ); 1388 1389 attributeInfo[4] = new OpenMBeanAttributeInfoSupport( 1390 "adminUser", 1391 "The user name for the admin user (set in the poolConfig.properties file).", 1392 SimpleType.STRING, 1393 true, 1394 false, 1395 false 1396 ); 1397 1398 attributeInfo[5] = new OpenMBeanAttributeInfoSupport( 1399 "adminPassword", 1400 "The password for the admin user (set in the poolConfig.properties file).", 1401 SimpleType.STRING, 1402 true, 1403 false, 1404 false 1405 ); 1406 1407 attributeInfo[6] = new OpenMBeanAttributeInfoSupport( 1408 "emailSMTPServer", 1409 "The SMTP server to use to send email warnings (if email notification is 'true').", 1410 SimpleType.STRING, 1411 true, 1412 false, 1413 false 1414 ); 1415 1416 attributeInfo[7] = new OpenMBeanAttributeInfoSupport( 1417 "emailNotificationPeriod", 1418 "If there are problems with the pool, and until the problem is fixed, how often should the pool mail you about the problem.", 1419 SimpleType.LONG, 1420 true, 1421 true, 1422 false 1423 ); 1424 1425 attributeInfo[8] = new OpenMBeanAttributeInfoSupport( 1426 "emailMaxWarningNumber", 1427 "If there are problems with the pool, and until the problem is fixed, what is the maximum number of email warnings to send ?.", 1428 SimpleType.INTEGER, 1429 true, 1430 true, 1431 false 1432 ); 1433 attributeInfo[9] = new OpenMBeanAttributeInfoSupport( 1434 "adminEmailCrisisAddress", 1435 "Crisis email address. If email notificatiosn are on, and the max number of emails to thte normal address have been sent, this email address will be used to send a final crisis alert.", 1436 SimpleType.STRING, 1437 true, 1438 true, 1439 false 1440 ); 1441 1442 1443 } catch (OpenDataException ode) { 1444 ode.printStackTrace(System.err); 1445 } 1446 1447 _MBeanInfo = new OpenMBeanInfoSupport( 1448 this.getClass().getName(), "PoolController.<br>This class contols the starting and stopping of pools.<br>Think before you use !", attributeInfo, new OpenMBeanConstructorInfo[]{}, 1453 operationInfo, new MBeanNotificationInfo[]{} 1456 ); 1457 } 1458 1459 1461 1463 public MBeanInfo getMBeanInfo () { 1464 return (_MBeanInfo); 1466 } 1467 1468 1469 1480 public Object getAttribute (String attributeName) throws AttributeNotFoundException, MBeanException, ReflectionException { 1481 return callGetMethod(attributeName); 1483 } 1484 1485 1496 public void setAttribute (Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { 1497 callSetMethod(attribute); 1499 1500 } 1501 1509 public AttributeList getAttributes (String [] attributeNames) { 1510 AttributeList resultList = new AttributeList(); 1512 for (int aa = 0; aa < attributeNames.length; aa++) { 1513 try { 1514 Object value = getAttribute((String )attributeNames[aa]); 1515 resultList.add(new Attribute(attributeNames[aa], value)); 1516 } catch (Exception e) { 1517 e.printStackTrace(); 1518 } 1519 } 1520 return resultList; 1521 } 1522 1533 public AttributeList setAttributes (AttributeList attributes) { 1534 for (int i = 0; i < attributes.size(); i++) { 1536 Attribute att = (Attribute)attributes.get(i); 1537 callSetMethod(att); 1538 1539 } 1540 return attributes; 1541 } 1542 1543 1559 public Object invoke (String operationName, Object params[], String signature[]) throws MBeanException, ReflectionException { 1560 Object ret = Void.TYPE; 1561 try { 1567 Class [] sign = null; 1568 if (params != null) { 1569 sign = new Class [signature.length]; 1570 for (int aa = 0; aa < signature.length; aa++) { 1571 try { 1572 sign[aa] = MBeanUtil.getClassFromString(signature[aa]); 1573 } catch (ClassNotFoundException e) { 1574 throw new RuntimeOperationsException(new IllegalArgumentException ( 1575 "PoolController.invoke(): ERROR: " + "Bad argument \'" 1576 + sign[aa] + " found when attempting to invoke operation \'" 1577 + operationName + "\'!")); 1578 } 1579 } 1580 } 1581 1582 Method theMethod = this.getClass().getMethod(operationName, sign); 1583 ret = theMethod.invoke(this, params); 1584 1585 } catch (NoSuchMethodException e) { 1586 throw new ReflectionException(e, e.getClass().getName()); 1587 } catch (IllegalAccessException e) { 1588 throw new ReflectionException(e, e.getClass().getName()); 1589 } catch (InvocationTargetException e) { 1590 throw new ReflectionException(e, e.getClass().getName()); 1591 } 1592 return ret; 1593 } 1594 1595} 1596 | Popular Tags |