1 17 18 21 package org.quartz.impl; 22 23 import java.beans.BeanInfo ; 24 import java.beans.IntrospectionException ; 25 import java.beans.Introspector ; 26 import java.beans.PropertyDescriptor ; 27 import java.io.BufferedInputStream ; 28 import java.io.File ; 29 import java.io.FileInputStream ; 30 import java.io.IOException ; 31 import java.io.InputStream ; 32 import java.lang.reflect.Method ; 33 import java.security.AccessControlException ; 34 import java.sql.SQLException ; 35 import java.util.Collection ; 36 import java.util.Iterator ; 37 import java.util.Locale ; 38 import java.util.Properties ; 39 40 import org.apache.commons.logging.Log; 41 import org.apache.commons.logging.LogFactory; 42 import org.quartz.JobListener; 43 import org.quartz.Scheduler; 44 import org.quartz.SchedulerConfigException; 45 import org.quartz.SchedulerException; 46 import org.quartz.SchedulerFactory; 47 import org.quartz.TriggerListener; 48 import org.quartz.core.JobRunShellFactory; 49 import org.quartz.core.QuartzScheduler; 50 import org.quartz.core.QuartzSchedulerResources; 51 import org.quartz.core.SchedulingContext; 52 import org.quartz.ee.jta.JTAJobRunShellFactory; 53 import org.quartz.ee.jta.UserTransactionHelper; 54 import org.quartz.impl.jdbcjobstore.JobStoreSupport; 55 import org.quartz.impl.jdbcjobstore.Semaphore; 56 import org.quartz.impl.jdbcjobstore.TablePrefixAware; 57 import org.quartz.simpl.RAMJobStore; 58 import org.quartz.simpl.SimpleThreadPool; 59 import org.quartz.spi.ClassLoadHelper; 60 import org.quartz.spi.InstanceIdGenerator; 61 import org.quartz.spi.JobFactory; 62 import org.quartz.spi.JobStore; 63 import org.quartz.spi.SchedulerPlugin; 64 import org.quartz.spi.ThreadPool; 65 import org.quartz.utils.ConnectionProvider; 66 import org.quartz.utils.DBConnectionManager; 67 import org.quartz.utils.JNDIConnectionProvider; 68 import org.quartz.utils.PoolingConnectionProvider; 69 import org.quartz.utils.PropertiesParser; 70 71 112 public class StdSchedulerFactory implements SchedulerFactory { 113 114 121 122 public static final String PROPERTIES_FILE = "org.quartz.properties"; 123 124 public static final String PROP_SCHED_INSTANCE_NAME = "org.quartz.scheduler.instanceName"; 125 126 public static final String PROP_SCHED_INSTANCE_ID = "org.quartz.scheduler.instanceId"; 127 128 public static final String PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX = "org.quartz.scheduler.instanceIdGenerator"; 129 130 public static final String PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS = 131 PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX + ".class"; 132 133 public static final String PROP_SCHED_THREAD_NAME = "org.quartz.scheduler.threadName"; 134 135 public static final String PROP_SCHED_JMX_EXPORT = "org.quartz.scheduler.jmx.export"; 136 137 public static final String PROP_SCHED_JMX_PROXY = "org.quartz.scheduler.jmx.proxy"; 138 139 public static final String PROP_SCHED_JMX_PROXY_CLASS = "org.quartz.scheduler.jmx.proxy.class"; 140 141 public static final String PROP_SCHED_JMX_OBJECT_NAME = "org.quartz.scheduler.jmx.objectName"; 142 143 public static final String PROP_SCHED_RMI_EXPORT = "org.quartz.scheduler.rmi.export"; 144 145 public static final String PROP_SCHED_RMI_PROXY = "org.quartz.scheduler.rmi.proxy"; 146 147 public static final String PROP_SCHED_RMI_HOST = "org.quartz.scheduler.rmi.registryHost"; 148 149 public static final String PROP_SCHED_RMI_PORT = "org.quartz.scheduler.rmi.registryPort"; 150 151 public static final String PROP_SCHED_RMI_SERVER_PORT = "org.quartz.scheduler.rmi.serverPort"; 152 153 public static final String PROP_SCHED_RMI_CREATE_REGISTRY = "org.quartz.scheduler.rmi.createRegistry"; 154 155 public static final String PROP_SCHED_RMI_BIND_NAME = "org.quartz.scheduler.rmi.bindName"; 156 157 public static final String PROP_SCHED_WRAP_JOB_IN_USER_TX = "org.quartz.scheduler.wrapJobExecutionInUserTransaction"; 158 159 public static final String PROP_SCHED_USER_TX_URL = "org.quartz.scheduler.userTransactionURL"; 160 161 public static final String PROP_SCHED_IDLE_WAIT_TIME = "org.quartz.scheduler.idleWaitTime"; 162 163 public static final String PROP_SCHED_DB_FAILURE_RETRY_INTERVAL = "org.quartz.scheduler.dbFailureRetryInterval"; 164 165 public static final String PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON = "org.quartz.scheduler.makeSchedulerThreadDaemon"; 166 167 public static final String PROP_SCHED_CLASS_LOAD_HELPER_CLASS = "org.quartz.scheduler.classLoadHelper.class"; 168 169 public static final String PROP_SCHED_JOB_FACTORY_CLASS = "org.quartz.scheduler.jobFactory.class"; 170 171 public static final String PROP_SCHED_JOB_FACTORY_PREFIX = "org.quartz.scheduler.jobFactory"; 172 173 public static final String PROP_SCHED_CONTEXT_PREFIX = "org.quartz.context.key"; 174 175 public static final String PROP_THREAD_POOL_PREFIX = "org.quartz.threadPool"; 176 177 public static final String PROP_THREAD_POOL_CLASS = "org.quartz.threadPool.class"; 178 179 public static final String PROP_JOB_STORE_PREFIX = "org.quartz.jobStore"; 180 181 public static final String PROP_JOB_STORE_LOCK_HANDLER_PREFIX = PROP_JOB_STORE_PREFIX + ".lockHandler"; 182 183 public static final String PROP_JOB_STORE_LOCK_HANDLER_CLASS = PROP_JOB_STORE_LOCK_HANDLER_PREFIX + ".class"; 184 185 public static final String PROP_TABLE_PREFIX = "tablePrefix"; 186 187 public static final String PROP_JOB_STORE_CLASS = "org.quartz.jobStore.class"; 188 189 public static final String PROP_JOB_STORE_USE_PROP = "org.quartz.jobStore.useProperties"; 190 191 public static final String PROP_DATASOURCE_PREFIX = "org.quartz.dataSource"; 192 193 public static final String PROP_CONNECTION_PROVIDER_CLASS = "connectionProvider.class"; 194 195 public static final String PROP_DATASOURCE_DRIVER = "driver"; 196 197 public static final String PROP_DATASOURCE_URL = "URL"; 198 199 public static final String PROP_DATASOURCE_USER = "user"; 200 201 public static final String PROP_DATASOURCE_PASSWORD = "password"; 202 203 public static final String PROP_DATASOURCE_MAX_CONNECTIONS = "maxConnections"; 204 205 public static final String PROP_DATASOURCE_VALIDATION_QUERY = "validationQuery"; 206 207 public static final String PROP_DATASOURCE_JNDI_URL = "jndiURL"; 208 209 public static final String PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP = "jndiAlwaysLookup"; 210 211 public static final String PROP_DATASOURCE_JNDI_INITIAL = "java.naming.factory.initial"; 212 213 public static final String PROP_DATASOURCE_JNDI_PROVDER = "java.naming.provider.url"; 214 215 public static final String PROP_DATASOURCE_JNDI_PRINCIPAL = "java.naming.security.principal"; 216 217 public static final String PROP_DATASOURCE_JNDI_CREDENTIALS = "java.naming.security.credentials"; 218 219 public static final String PROP_PLUGIN_PREFIX = "org.quartz.plugin"; 220 221 public static final String PROP_PLUGIN_CLASS = "class"; 222 223 public static final String PROP_JOB_LISTENER_PREFIX = "org.quartz.jobListener"; 224 225 public static final String PROP_TRIGGER_LISTENER_PREFIX = "org.quartz.triggerListener"; 226 227 public static final String PROP_LISTENER_CLASS = "class"; 228 229 public static final String DEFAULT_INSTANCE_ID = "NON_CLUSTERED"; 230 231 public static final String AUTO_GENERATE_INSTANCE_ID = "AUTO"; 232 233 240 241 private SchedulerException initException = null; 242 243 private String propSrc = null; 244 245 private PropertiesParser cfg; 246 247 private final Log log = LogFactory.getLog(getClass()); 248 249 251 258 259 262 public StdSchedulerFactory() { 263 } 264 265 271 public StdSchedulerFactory(Properties props) throws SchedulerException { 272 initialize(props); 273 } 274 275 281 public StdSchedulerFactory(String fileName) throws SchedulerException { 282 initialize(fileName); 283 } 284 285 292 293 public Log getLog() { 294 return log; 295 } 296 297 321 public void initialize() throws SchedulerException { 322 if (cfg != null) { 324 return; 325 } 326 if (initException != null) { 327 throw initException; 328 } 329 330 String requestedFile = System.getProperty(PROPERTIES_FILE); 331 String propFileName = requestedFile != null ? requestedFile 332 : "quartz.properties"; 333 File propFile = new File (propFileName); 334 335 Properties props = new Properties (); 336 337 if (propFile.exists()) { 338 try { 339 if (requestedFile != null) { 340 propSrc = "specified file: '" + requestedFile + "'"; 341 } else { 342 propSrc = "default file in current working dir: 'quartz.properties'"; 343 } 344 345 props.load(new BufferedInputStream (new FileInputStream ( 346 propFileName))); 347 348 } catch (IOException ioe) { 349 initException = new SchedulerException("Properties file: '" 350 + propFileName + "' could not be read.", ioe); 351 throw initException; 352 } 353 } else if (requestedFile != null) { 354 InputStream in = 355 Thread.currentThread().getContextClassLoader().getResourceAsStream(requestedFile); 356 357 if(in == null) { 358 initException = new SchedulerException("Properties file: '" 359 + requestedFile + "' could not be found."); 360 throw initException; 361 } 362 363 propSrc = "specified file: '" + requestedFile + "' in the class resource path."; 364 365 try { 366 props.load(new BufferedInputStream (in)); 367 } catch (IOException ioe) { 368 initException = new SchedulerException("Properties file: '" 369 + requestedFile + "' could not be read.", ioe); 370 throw initException; 371 } 372 373 } else { 374 propSrc = "default resource file in Quartz package: 'quartz.properties'"; 375 376 InputStream in = getClass().getClassLoader().getResourceAsStream( 377 "quartz.properties"); 378 379 if (in == null) { 380 in = getClass().getClassLoader().getResourceAsStream( 381 "/quartz.properties"); 382 } 383 if (in == null) { 384 in = getClass().getClassLoader().getResourceAsStream( 385 "org/quartz/quartz.properties"); 386 } 387 if (in == null) { 388 initException = new SchedulerException( 389 "Default quartz.properties not found in class path"); 390 throw initException; 391 } 392 try { 393 props.load(in); 394 } catch (IOException ioe) { 395 initException = new SchedulerException( 396 "Resource properties file: 'org/quartz/quartz.properties' " 397 + "could not be read from the classpath.", ioe); 398 throw initException; 399 } 400 } 401 402 initialize(overrideWithSysProps(props)); 403 } 404 405 409 private Properties overrideWithSysProps(Properties props) { 410 Properties sysProps = null; 411 try { 412 sysProps = System.getProperties(); 413 } catch (AccessControlException e) { 414 getLog().warn( 415 "Skipping overriding quartz properties with System properties " + 416 "during initialization because of an AccessControlException. " + 417 "This is likely due to not having read/write access for " + 418 "java.util.PropertyPermission as required by java.lang.System.getProperties(). " + 419 "To resolve this warning, either add this permission to your policy file or " + 420 "use a non-default version of initialize().", 421 e); 422 } 423 424 if (sysProps != null) { 425 props.putAll(sysProps); 426 } 427 428 return props; 429 } 430 431 438 public void initialize(String filename) throws SchedulerException { 439 if (cfg != null) { 441 return; 442 } 443 444 if (initException != null) { 445 throw initException; 446 } 447 448 InputStream is = null; 449 Properties props = new Properties (); 450 451 is = Thread.currentThread().getContextClassLoader().getResourceAsStream(filename); 452 453 try { 454 if(is != null) { 455 is = new BufferedInputStream (is); 456 propSrc = "the specified file : '" + filename + "' from the class resource path."; 457 } else { 458 is = new BufferedInputStream (new FileInputStream (filename)); 459 propSrc = "the specified file : '" + filename + "'"; 460 } 461 props.load(is); 462 } catch (IOException ioe) { 463 initException = new SchedulerException("Properties file: '" 464 + filename + "' could not be read.", ioe); 465 throw initException; 466 } 467 468 initialize(props); 469 } 470 471 478 public void initialize(InputStream propertiesStream) 479 throws SchedulerException { 480 if (cfg != null) { 482 return; 483 } 484 485 if (initException != null) { 486 throw initException; 487 } 488 489 Properties props = new Properties (); 490 491 if (propertiesStream != null) { 492 try { 493 props.load(propertiesStream); 494 propSrc = "an externally opened InputStream."; 495 } catch (IOException e) { 496 initException = new SchedulerException( 497 "Error loading property data from InputStream", e); 498 throw initException; 499 } 500 } else { 501 initException = new SchedulerException( 502 "Error loading property data from InputStream - InputStream is null."); 503 throw initException; 504 } 505 506 initialize(props); 507 } 508 509 515 public void initialize(Properties props) throws SchedulerException { 516 if (propSrc == null) { 517 propSrc = "an externally provided properties instance."; 518 } 519 520 this.cfg = new PropertiesParser(props); 521 } 522 523 private Scheduler instantiate() throws SchedulerException { 524 if (cfg == null) { 525 initialize(); 526 } 527 528 if (initException != null) { 529 throw initException; 530 } 531 532 JobStore js = null; 533 ThreadPool tp = null; 534 QuartzScheduler qs = null; 535 SchedulingContext schedCtxt = null; 536 DBConnectionManager dbMgr = null; 537 String instanceIdGeneratorClass = null; 538 Properties tProps = null; 539 String userTXLocation = null; 540 boolean wrapJobInTx = false; 541 boolean autoId = false; 542 long idleWaitTime = -1; 543 long dbFailureRetry = -1; 544 String classLoadHelperClass; 545 String jobFactoryClass; 546 547 SchedulerRepository schedRep = SchedulerRepository.getInstance(); 548 549 552 String schedName = cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME, 553 "QuartzScheduler"); 554 555 String threadName = cfg.getStringProperty(PROP_SCHED_THREAD_NAME, 556 schedName + "_QuartzSchedulerThread"); 557 558 String schedInstId = cfg.getStringProperty(PROP_SCHED_INSTANCE_ID, 559 DEFAULT_INSTANCE_ID); 560 561 if (schedInstId.equals(AUTO_GENERATE_INSTANCE_ID)) { 562 autoId = true; 563 instanceIdGeneratorClass = cfg.getStringProperty( 564 PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS, 565 "org.quartz.simpl.SimpleInstanceIdGenerator"); 566 } 567 568 userTXLocation = cfg.getStringProperty(PROP_SCHED_USER_TX_URL, 569 userTXLocation); 570 if (userTXLocation != null && userTXLocation.trim().length() == 0) { 571 userTXLocation = null; 572 } 573 574 classLoadHelperClass = cfg.getStringProperty( 575 PROP_SCHED_CLASS_LOAD_HELPER_CLASS, 576 "org.quartz.simpl.CascadingClassLoadHelper"); 577 wrapJobInTx = cfg.getBooleanProperty(PROP_SCHED_WRAP_JOB_IN_USER_TX, 578 wrapJobInTx); 579 580 jobFactoryClass = cfg.getStringProperty( 581 PROP_SCHED_JOB_FACTORY_CLASS, null); 582 583 idleWaitTime = cfg.getLongProperty(PROP_SCHED_IDLE_WAIT_TIME, 584 idleWaitTime); 585 dbFailureRetry = cfg.getLongProperty( 586 PROP_SCHED_DB_FAILURE_RETRY_INTERVAL, dbFailureRetry); 587 588 boolean makeSchedulerThreadDaemon = 589 cfg.getBooleanProperty(PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON); 590 591 boolean jmxExport = cfg.getBooleanProperty(PROP_SCHED_JMX_EXPORT); 592 boolean jmxProxy = cfg.getBooleanProperty(PROP_SCHED_JMX_PROXY); 593 String jmxProxyClass = cfg.getStringProperty(PROP_SCHED_JMX_PROXY_CLASS); 594 String jmxObjectName = cfg.getStringProperty(PROP_SCHED_JMX_OBJECT_NAME); 595 596 boolean rmiExport = cfg.getBooleanProperty(PROP_SCHED_RMI_EXPORT, false); 597 boolean rmiProxy = cfg.getBooleanProperty(PROP_SCHED_RMI_PROXY, false); 598 String rmiHost = cfg.getStringProperty(PROP_SCHED_RMI_HOST, "localhost"); 599 int rmiPort = cfg.getIntProperty(PROP_SCHED_RMI_PORT, 1099); 600 int rmiServerPort = cfg.getIntProperty(PROP_SCHED_RMI_SERVER_PORT, -1); 601 String rmiCreateRegistry = cfg.getStringProperty( 602 PROP_SCHED_RMI_CREATE_REGISTRY, 603 QuartzSchedulerResources.CREATE_REGISTRY_NEVER); 604 String rmiBindName = cfg.getStringProperty(PROP_SCHED_RMI_BIND_NAME); 605 606 if (jmxProxy && rmiProxy) { 607 throw new SchedulerConfigException("Cannot proxy both RMI and JMX."); 608 } 609 610 Properties schedCtxtProps = cfg.getPropertyGroup(PROP_SCHED_CONTEXT_PREFIX, true); 611 612 if (rmiProxy) { 615 616 if (autoId) { 617 schedInstId = DEFAULT_INSTANCE_ID; 618 } 619 620 schedCtxt = new SchedulingContext(); 621 schedCtxt.setInstanceId(schedInstId); 622 623 String uid = (rmiBindName == null) ? QuartzSchedulerResources.getUniqueIdentifier( 624 schedName, schedInstId) : rmiBindName; 625 626 RemoteScheduler remoteScheduler = new RemoteScheduler(schedCtxt, 627 uid, rmiHost, rmiPort); 628 629 schedRep.bind(remoteScheduler); 630 631 return remoteScheduler; 632 } 633 634 635 ClassLoadHelper loadHelper = null; 637 try { 638 loadHelper = (ClassLoadHelper) loadClass(classLoadHelperClass) 639 .newInstance(); 640 } catch (Exception e) { 641 throw new SchedulerConfigException( 642 "Unable to instantiate class load helper class: " 643 + e.getMessage(), e); 644 } 645 loadHelper.initialize(); 646 647 if (jmxProxy) { 650 if (autoId) { 651 schedInstId = DEFAULT_INSTANCE_ID; 652 } 653 654 if (jmxProxyClass == null) { 655 throw new SchedulerConfigException("No JMX Proxy Scheduler class provided"); 656 } 657 658 RemoteMBeanScheduler jmxScheduler = null; 659 try { 660 jmxScheduler = (RemoteMBeanScheduler)loadHelper.loadClass(jmxProxyClass) 661 .newInstance(); 662 } catch (Exception e) { 663 throw new SchedulerConfigException( 664 "Unable to instantiate RemoteMBeanScheduler class.", e); 665 } 666 667 schedCtxt = new SchedulingContext(); 668 schedCtxt.setInstanceId(schedInstId); 669 670 if (jmxObjectName == null) { 671 jmxObjectName = QuartzSchedulerResources.generateJMXObjectName(schedName, schedInstId); 672 } 673 674 jmxScheduler.setSchedulingContext(schedCtxt); 675 jmxScheduler.setSchedulerObjectName(jmxObjectName); 676 677 tProps = cfg.getPropertyGroup(PROP_SCHED_JMX_PROXY, true); 678 try { 679 setBeanProps(jmxScheduler, tProps); 680 } catch (Exception e) { 681 initException = new SchedulerException("RemoteMBeanScheduler class '" 682 + jmxProxyClass + "' props could not be configured.", e); 683 initException.setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 684 throw initException; 685 } 686 687 jmxScheduler.initialize(); 688 689 schedRep.bind(jmxScheduler); 690 691 return jmxScheduler; 692 } 693 694 JobFactory jobFactory = null; 695 if(jobFactoryClass != null) { 696 try { 697 jobFactory = (JobFactory) loadHelper.loadClass(jobFactoryClass) 698 .newInstance(); 699 } catch (Exception e) { 700 throw new SchedulerConfigException( 701 "Unable to instantiate JobFactory class: " 702 + e.getMessage(), e); 703 } 704 705 tProps = cfg.getPropertyGroup(PROP_SCHED_JOB_FACTORY_PREFIX, true); 706 try { 707 setBeanProps(jobFactory, tProps); 708 } catch (Exception e) { 709 initException = new SchedulerException("JobFactory class '" 710 + jobFactoryClass + "' props could not be configured.", e); 711 initException 712 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 713 throw initException; 714 } 715 } 716 717 InstanceIdGenerator instanceIdGenerator = null; 718 if(instanceIdGeneratorClass != null) { 719 try { 720 instanceIdGenerator = (InstanceIdGenerator) loadHelper.loadClass(instanceIdGeneratorClass) 721 .newInstance(); 722 } catch (Exception e) { 723 throw new SchedulerConfigException( 724 "Unable to instantiate InstanceIdGenerator class: " 725 + e.getMessage(), e); 726 } 727 728 tProps = cfg.getPropertyGroup(PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX, true); 729 try { 730 setBeanProps(instanceIdGenerator, tProps); 731 } catch (Exception e) { 732 initException = new SchedulerException("InstanceIdGenerator class '" 733 + instanceIdGeneratorClass + "' props could not be configured.", e); 734 initException 735 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 736 throw initException; 737 } 738 } 739 740 743 String tpClass = cfg.getStringProperty(PROP_THREAD_POOL_CLASS, null); 744 745 if (tpClass == null) { 746 initException = new SchedulerException( 747 "ThreadPool class not specified. ", 748 SchedulerException.ERR_BAD_CONFIGURATION); 749 throw initException; 750 } 751 752 try { 753 tp = (ThreadPool) loadHelper.loadClass(tpClass).newInstance(); 754 } catch (Exception e) { 755 initException = new SchedulerException("ThreadPool class '" 756 + tpClass + "' could not be instantiated.", e); 757 initException 758 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 759 throw initException; 760 } 761 tProps = cfg.getPropertyGroup(PROP_THREAD_POOL_PREFIX, true); 762 try { 763 setBeanProps(tp, tProps); 764 } catch (Exception e) { 765 initException = new SchedulerException("ThreadPool class '" 766 + tpClass + "' props could not be configured.", e); 767 initException 768 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 769 throw initException; 770 } 771 772 775 String jsClass = cfg.getStringProperty(PROP_JOB_STORE_CLASS, 776 RAMJobStore.class.getName()); 777 778 if (jsClass == null) { 779 initException = new SchedulerException( 780 "JobStore class not specified. ", 781 SchedulerException.ERR_BAD_CONFIGURATION); 782 throw initException; 783 } 784 785 try { 786 js = (JobStore) loadHelper.loadClass(jsClass).newInstance(); 787 } catch (Exception e) { 788 initException = new SchedulerException("JobStore class '" + jsClass 789 + "' could not be instantiated.", e); 790 initException 791 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 792 throw initException; 793 } 794 tProps = cfg.getPropertyGroup(PROP_JOB_STORE_PREFIX, true, new String [] {PROP_JOB_STORE_LOCK_HANDLER_PREFIX}); 795 try { 796 setBeanProps(js, tProps); 797 } catch (Exception e) { 798 initException = new SchedulerException("JobStore class '" + jsClass 799 + "' props could not be configured.", e); 800 initException 801 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 802 throw initException; 803 } 804 805 if (js instanceof JobStoreSupport) { 806 ((JobStoreSupport)js).setInstanceId(schedInstId); 807 ((JobStoreSupport)js).setInstanceName(schedName); 808 809 String lockHandlerClass = cfg.getStringProperty(PROP_JOB_STORE_LOCK_HANDLER_CLASS); 811 if (lockHandlerClass != null) { 812 try { 813 Semaphore lockHandler = (Semaphore)loadHelper.loadClass(lockHandlerClass).newInstance(); 814 815 tProps = cfg.getPropertyGroup(PROP_JOB_STORE_LOCK_HANDLER_PREFIX, true); 816 817 if (lockHandler instanceof TablePrefixAware) { 819 tProps.setProperty( 820 PROP_TABLE_PREFIX, ((JobStoreSupport)js).getTablePrefix()); 821 } 822 823 try { 824 setBeanProps(lockHandler, tProps); 825 } catch (Exception e) { 826 initException = new SchedulerException("JobStore LockHandler class '" + lockHandlerClass 827 + "' props could not be configured.", e); 828 initException.setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 829 throw initException; 830 } 831 832 ((JobStoreSupport)js).setLockHandler(lockHandler); 833 getLog().info("Using custom data access locking (synchronization): " + lockHandlerClass); 834 } catch (Exception e) { 835 initException = new SchedulerException("JobStore LockHandler class '" + lockHandlerClass 836 + "' could not be instantiated.", e); 837 initException.setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 838 throw initException; 839 } 840 } 841 } 842 843 846 String [] dsNames = cfg.getPropertyGroups(PROP_DATASOURCE_PREFIX); 847 for (int i = 0; i < dsNames.length; i++) { 848 PropertiesParser pp = new PropertiesParser(cfg.getPropertyGroup( 849 PROP_DATASOURCE_PREFIX + "." + dsNames[i], true)); 850 851 String cpClass = pp.getStringProperty(PROP_CONNECTION_PROVIDER_CLASS, null); 852 853 if(cpClass != null) { 855 ConnectionProvider cp = null; 856 try { 857 cp = (ConnectionProvider) loadHelper.loadClass(cpClass).newInstance(); 858 } catch (Exception e) { 859 initException = new SchedulerException("ConnectionProvider class '" + cpClass 860 + "' could not be instantiated.", e); 861 initException 862 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 863 throw initException; 864 } 865 866 try { 867 pp.getUnderlyingProperties().remove( 869 PROP_CONNECTION_PROVIDER_CLASS); 870 871 setBeanProps(cp, pp.getUnderlyingProperties()); 872 } catch (Exception e) { 873 initException = new SchedulerException("ConnectionProvider class '" + cpClass 874 + "' props could not be configured.", e); 875 initException 876 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 877 throw initException; 878 } 879 880 dbMgr = DBConnectionManager.getInstance(); 881 dbMgr.addConnectionProvider(dsNames[i], cp); 882 } else { 883 String dsJndi = pp.getStringProperty(PROP_DATASOURCE_JNDI_URL, null); 884 885 if (dsJndi != null) { 886 boolean dsAlwaysLookup = pp.getBooleanProperty( 887 PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP); 888 String dsJndiInitial = pp.getStringProperty( 889 PROP_DATASOURCE_JNDI_INITIAL); 890 String dsJndiProvider = pp.getStringProperty( 891 PROP_DATASOURCE_JNDI_PROVDER); 892 String dsJndiPrincipal = pp.getStringProperty( 893 PROP_DATASOURCE_JNDI_PRINCIPAL); 894 String dsJndiCredentials = pp.getStringProperty( 895 PROP_DATASOURCE_JNDI_CREDENTIALS); 896 Properties props = null; 897 if (null != dsJndiInitial || null != dsJndiProvider 898 || null != dsJndiPrincipal || null != dsJndiCredentials) { 899 props = new Properties (); 900 if (dsJndiInitial != null) { 901 props.put(PROP_DATASOURCE_JNDI_INITIAL, 902 dsJndiInitial); 903 } 904 if (dsJndiProvider != null) { 905 props.put(PROP_DATASOURCE_JNDI_PROVDER, 906 dsJndiProvider); 907 } 908 if (dsJndiPrincipal != null) { 909 props.put(PROP_DATASOURCE_JNDI_PRINCIPAL, 910 dsJndiPrincipal); 911 } 912 if (dsJndiCredentials != null) { 913 props.put(PROP_DATASOURCE_JNDI_CREDENTIALS, 914 dsJndiCredentials); 915 } 916 } 917 JNDIConnectionProvider cp = new JNDIConnectionProvider(dsJndi, 918 props, dsAlwaysLookup); 919 dbMgr = DBConnectionManager.getInstance(); 920 dbMgr.addConnectionProvider(dsNames[i], cp); 921 } else { 922 String dsDriver = pp.getStringProperty(PROP_DATASOURCE_DRIVER); 923 String dsURL = pp.getStringProperty(PROP_DATASOURCE_URL); 924 String dsUser = pp.getStringProperty(PROP_DATASOURCE_USER, ""); 925 String dsPass = pp.getStringProperty(PROP_DATASOURCE_PASSWORD, ""); 926 int dsCnt = pp.getIntProperty(PROP_DATASOURCE_MAX_CONNECTIONS, 10); 927 String dsValidation = pp.getStringProperty(PROP_DATASOURCE_VALIDATION_QUERY); 928 929 if (dsDriver == null) { 930 initException = new SchedulerException( 931 "Driver not specified for DataSource: " 932 + dsNames[i]); 933 throw initException; 934 } 935 if (dsURL == null) { 936 initException = new SchedulerException( 937 "DB URL not specified for DataSource: " 938 + dsNames[i]); 939 throw initException; 940 } 941 try { 942 PoolingConnectionProvider cp = new PoolingConnectionProvider( 943 dsDriver, dsURL, dsUser, dsPass, dsCnt, 944 dsValidation); 945 dbMgr = DBConnectionManager.getInstance(); 946 dbMgr.addConnectionProvider(dsNames[i], cp); 947 } catch (SQLException sqle) { 948 initException = new SchedulerException( 949 "Could not initialize DataSource: " + dsNames[i], 950 sqle); 951 throw initException; 952 } 953 } 954 955 } 956 957 } 958 959 962 String [] pluginNames = cfg.getPropertyGroups(PROP_PLUGIN_PREFIX); 963 SchedulerPlugin[] plugins = new SchedulerPlugin[pluginNames.length]; 964 for (int i = 0; i < pluginNames.length; i++) { 965 Properties pp = cfg.getPropertyGroup(PROP_PLUGIN_PREFIX + "." 966 + pluginNames[i], true); 967 968 String plugInClass = pp.getProperty(PROP_PLUGIN_CLASS, null); 969 970 if (plugInClass == null) { 971 initException = new SchedulerException( 972 "SchedulerPlugin class not specified for plugin '" 973 + pluginNames[i] + "'", 974 SchedulerException.ERR_BAD_CONFIGURATION); 975 throw initException; 976 } 977 SchedulerPlugin plugin = null; 978 try { 979 plugin = (SchedulerPlugin) 980 loadHelper.loadClass(plugInClass).newInstance(); 981 } catch (Exception e) { 982 initException = new SchedulerException( 983 "SchedulerPlugin class '" + plugInClass 984 + "' could not be instantiated.", e); 985 initException 986 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 987 throw initException; 988 } 989 try { 990 setBeanProps(plugin, pp); 991 } catch (Exception e) { 992 initException = new SchedulerException( 993 "JobStore SchedulerPlugin '" + plugInClass 994 + "' props could not be configured.", e); 995 initException 996 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 997 throw initException; 998 } 999 1000 plugins[i] = plugin; 1001 } 1002 1003 1006 Class [] strArg = new Class [] { String .class }; 1007 String [] jobListenerNames = cfg.getPropertyGroups(PROP_JOB_LISTENER_PREFIX); 1008 JobListener[] jobListeners = new JobListener[jobListenerNames.length]; 1009 for (int i = 0; i < jobListenerNames.length; i++) { 1010 Properties lp = cfg.getPropertyGroup(PROP_JOB_LISTENER_PREFIX + "." 1011 + jobListenerNames[i], true); 1012 1013 String listenerClass = lp.getProperty(PROP_LISTENER_CLASS, null); 1014 1015 if (listenerClass == null) { 1016 initException = new SchedulerException( 1017 "JobListener class not specified for listener '" 1018 + jobListenerNames[i] + "'", 1019 SchedulerException.ERR_BAD_CONFIGURATION); 1020 throw initException; 1021 } 1022 JobListener listener = null; 1023 try { 1024 listener = (JobListener) 1025 loadHelper.loadClass(listenerClass).newInstance(); 1026 } catch (Exception e) { 1027 initException = new SchedulerException( 1028 "JobListener class '" + listenerClass 1029 + "' could not be instantiated.", e); 1030 initException 1031 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 1032 throw initException; 1033 } 1034 try { 1035 Method nameSetter = listener.getClass().getMethod("setName", strArg); 1036 if(nameSetter != null) { 1037 nameSetter.invoke(listener, new Object [] {jobListenerNames[i] } ); 1038 } 1039 setBeanProps(listener, lp); 1040 } catch (Exception e) { 1041 initException = new SchedulerException( 1042 "JobListener '" + listenerClass 1043 + "' props could not be configured.", e); 1044 initException 1045 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 1046 throw initException; 1047 } 1048 jobListeners[i] = listener; 1049 } 1050 1051 1054 String [] triggerListenerNames = cfg.getPropertyGroups(PROP_TRIGGER_LISTENER_PREFIX); 1055 TriggerListener[] triggerListeners = new TriggerListener[triggerListenerNames.length]; 1056 for (int i = 0; i < triggerListenerNames.length; i++) { 1057 Properties lp = cfg.getPropertyGroup(PROP_TRIGGER_LISTENER_PREFIX + "." 1058 + triggerListenerNames[i], true); 1059 1060 String listenerClass = lp.getProperty(PROP_LISTENER_CLASS, null); 1061 1062 if (listenerClass == null) { 1063 initException = new SchedulerException( 1064 "TriggerListener class not specified for listener '" 1065 + triggerListenerNames[i] + "'", 1066 SchedulerException.ERR_BAD_CONFIGURATION); 1067 throw initException; 1068 } 1069 TriggerListener listener = null; 1070 try { 1071 listener = (TriggerListener) 1072 loadHelper.loadClass(listenerClass).newInstance(); 1073 } catch (Exception e) { 1074 initException = new SchedulerException( 1075 "TriggerListener class '" + listenerClass 1076 + "' could not be instantiated.", e); 1077 initException 1078 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 1079 throw initException; 1080 } 1081 try { 1082 Method nameSetter = listener.getClass().getMethod("setName", strArg); 1083 if(nameSetter != null) { 1084 nameSetter.invoke(listener, new Object [] {triggerListenerNames[i] } ); 1085 } 1086 setBeanProps(listener, lp); 1087 } catch (Exception e) { 1088 initException = new SchedulerException( 1089 "TriggerListener '" + listenerClass 1090 + "' props could not be configured.", e); 1091 initException 1092 .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION); 1093 throw initException; 1094 } 1095 triggerListeners[i] = listener; 1096 } 1097 1098 1099 1102 JobRunShellFactory jrsf = null; 1104 UserTransactionHelper.setUserTxLocation(userTXLocation); 1105 1106 if (wrapJobInTx) { 1107 jrsf = new JTAJobRunShellFactory(); 1108 } else { 1109 jrsf = new StdJobRunShellFactory(); 1110 } 1111 1112 if (autoId) { 1113 try { 1114 schedInstId = DEFAULT_INSTANCE_ID; 1115 if (js instanceof JobStoreSupport) { 1116 if(((JobStoreSupport)js).isClustered()) { 1117 schedInstId = instanceIdGenerator.generateInstanceId(); 1118 } 1119 } 1120 } catch (Exception e) { 1121 getLog().error("Couldn't generate instance Id!", e); 1122 throw new IllegalStateException ( 1123 "Cannot run without an instance id."); 1124 } 1125 } 1126 1127 if (js instanceof JobStoreSupport) { 1128 JobStoreSupport jjs = (JobStoreSupport)js; 1129 jjs.setInstanceId(schedInstId); 1130 jjs.setDbRetryInterval(dbFailureRetry); 1131 } 1132 1133 QuartzSchedulerResources rsrcs = new QuartzSchedulerResources(); 1134 rsrcs.setName(schedName); 1135 rsrcs.setThreadName(threadName); 1136 rsrcs.setInstanceId(schedInstId); 1137 rsrcs.setJobRunShellFactory(jrsf); 1138 rsrcs.setMakeSchedulerThreadDaemon(makeSchedulerThreadDaemon); 1139 rsrcs.setJMXExport(jmxExport); 1140 rsrcs.setJMXObjectName(jmxObjectName); 1141 1142 if (rmiExport) { 1143 rsrcs.setRMIRegistryHost(rmiHost); 1144 rsrcs.setRMIRegistryPort(rmiPort); 1145 rsrcs.setRMIServerPort(rmiServerPort); 1146 rsrcs.setRMICreateRegistryStrategy(rmiCreateRegistry); 1147 rsrcs.setRMIBindName(rmiBindName); 1148 } 1149 1150 rsrcs.setThreadPool(tp); 1151 if(tp instanceof SimpleThreadPool) { 1152 ((SimpleThreadPool)tp).setThreadNamePrefix(schedName + "_Worker"); 1153 } 1154 tp.initialize(); 1155 1156 rsrcs.setJobStore(js); 1157 1158 for (int i = 0; i < plugins.length; i++) { 1160 rsrcs.addSchedulerPlugin(plugins[i]); 1161 } 1162 1163 schedCtxt = new SchedulingContext(); 1164 schedCtxt.setInstanceId(rsrcs.getInstanceId()); 1165 1166 qs = new QuartzScheduler(rsrcs, schedCtxt, idleWaitTime, dbFailureRetry); 1167 1168 1172 Scheduler scheduler = instantiate(rsrcs, qs); 1174 1175 if(jobFactory != null) { 1177 qs.setJobFactory(jobFactory); 1178 } 1179 1180 for (int i = 0; i < plugins.length; i++) { 1182 plugins[i].initialize(pluginNames[i], scheduler); 1183 } 1184 1185 for (int i = 0; i < jobListeners.length; i++) { 1187 qs.addGlobalJobListener(jobListeners[i]); 1188 } 1189 for (int i = 0; i < triggerListeners.length; i++) { 1190 qs.addGlobalTriggerListener(triggerListeners[i]); 1191 } 1192 1193 Iterator itr = schedCtxtProps.keySet().iterator(); 1195 while(itr.hasNext()) { 1196 String key = (String ) itr.next(); 1197 String val = schedCtxtProps.getProperty(key); 1198 1199 scheduler.getContext().put(key, val); 1200 } 1201 1202 1204 js.initialize(loadHelper, qs.getSchedulerSignaler()); 1205 1206 jrsf.initialize(scheduler, schedCtxt); 1207 1208 getLog().info( 1209 "Quartz scheduler '" + scheduler.getSchedulerName() 1210 + "' initialized from " + propSrc); 1211 1212 getLog().info("Quartz scheduler version: " + qs.getVersion()); 1213 1214 qs.addNoGCObject(schedRep); 1216 if (dbMgr != null) { 1218 qs.addNoGCObject(dbMgr); 1219 } 1220 1221 schedRep.bind(scheduler); 1222 1223 return scheduler; 1224 } 1225 1226 protected Scheduler instantiate(QuartzSchedulerResources rsrcs, QuartzScheduler qs) { 1227 SchedulingContext schedCtxt = new SchedulingContext(); 1228 schedCtxt.setInstanceId(rsrcs.getInstanceId()); 1229 1230 Scheduler scheduler = new StdScheduler(qs, schedCtxt); 1231 return scheduler; 1232 } 1233 1234 1235 private void setBeanProps(Object obj, Properties props) 1236 throws NoSuchMethodException , IllegalAccessException , 1237 java.lang.reflect.InvocationTargetException , 1238 IntrospectionException , SchedulerConfigException { 1239 props.remove("class"); 1240 1241 BeanInfo bi = Introspector.getBeanInfo(obj.getClass()); 1242 PropertyDescriptor [] propDescs = bi.getPropertyDescriptors(); 1243 PropertiesParser pp = new PropertiesParser(props); 1244 1245 java.util.Enumeration keys = props.keys(); 1246 while (keys.hasMoreElements()) { 1247 String name = (String ) keys.nextElement(); 1248 String c = name.substring(0, 1).toUpperCase(Locale.US); 1249 String methName = "set" + c + name.substring(1); 1250 1251 java.lang.reflect.Method setMeth = getSetMethod(methName, propDescs); 1252 1253 try { 1254 if (setMeth == null) { 1255 throw new NoSuchMethodException ( 1256 "No setter for property '" + name + "'"); 1257 } 1258 1259 Class [] params = setMeth.getParameterTypes(); 1260 if (params.length != 1) { 1261 throw new NoSuchMethodException ( 1262 "No 1-argument setter for property '" + name + "'"); 1263 } 1264 if (params[0].equals(int.class)) { 1265 setMeth.invoke(obj, new Object []{new Integer (pp 1266 .getIntProperty(name))}); 1267 } else if (params[0].equals(long.class)) { 1268 setMeth.invoke(obj, new Object []{new Long (pp 1269 .getLongProperty(name))}); 1270 } else if (params[0].equals(float.class)) { 1271 setMeth.invoke(obj, new Object []{new Float (pp 1272 .getFloatProperty(name))}); 1273 } else if (params[0].equals(double.class)) { 1274 setMeth.invoke(obj, new Object []{new Double (pp 1275 .getDoubleProperty(name))}); 1276 } else if (params[0].equals(boolean.class)) { 1277 setMeth.invoke(obj, new Object []{new Boolean (pp 1278 .getBooleanProperty(name))}); 1279 } else if (params[0].equals(String .class)) { 1280 setMeth.invoke(obj, 1281 new Object []{pp.getStringProperty(name)}); 1282 } else { 1283 throw new NoSuchMethodException ( 1284 "No primitive-type setter for property '" + name 1285 + "'"); 1286 } 1287 } catch (NumberFormatException nfe) { 1288 throw new SchedulerConfigException("Could not parse property '" 1289 + name + "' into correct data type: " + nfe.toString()); 1290 } 1291 } 1292 } 1293 1294 private java.lang.reflect.Method getSetMethod(String name, 1295 PropertyDescriptor [] props) { 1296 for (int i = 0; i < props.length; i++) { 1297 java.lang.reflect.Method wMeth = props[i].getWriteMethod(); 1298 1299 if (wMeth != null && wMeth.getName().equals(name)) { 1300 return wMeth; 1301 } 1302 } 1303 1304 return null; 1305 } 1306 1307 private Class loadClass(String className) throws ClassNotFoundException { 1308 1309 try { 1310 return Thread.currentThread().getContextClassLoader().loadClass( 1311 className); 1312 } catch (ClassNotFoundException e) { 1313 return getClass().getClassLoader().loadClass(className); 1314 } 1315 } 1316 1317 private String getSchedulerName() { 1318 return cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME, 1319 "QuartzScheduler"); 1320 } 1321 1322 private String getSchedulerInstId() { 1323 return cfg.getStringProperty(PROP_SCHED_INSTANCE_ID, 1324 DEFAULT_INSTANCE_ID); 1325 } 1326 1327 1338 public Scheduler getScheduler() throws SchedulerException { 1339 if (cfg == null) { 1340 initialize(); 1341 } 1342 1343 SchedulerRepository schedRep = SchedulerRepository.getInstance(); 1344 1345 Scheduler sched = schedRep.lookup(getSchedulerName()); 1346 1347 if (sched != null) { 1348 if (sched.isShutdown()) { 1349 schedRep.remove(getSchedulerName()); 1350 } else { 1351 return sched; 1352 } 1353 } 1354 1355 sched = instantiate(); 1356 1357 return sched; 1358 } 1359 1360 1368 public static Scheduler getDefaultScheduler() throws SchedulerException { 1369 StdSchedulerFactory fact = new StdSchedulerFactory(); 1370 1371 return fact.getScheduler(); 1372 } 1373 1374 1380 public Scheduler getScheduler(String schedName) throws SchedulerException { 1381 return SchedulerRepository.getInstance().lookup(schedName); 1382 } 1383 1384 1390 public Collection getAllSchedulers() throws SchedulerException { 1391 return SchedulerRepository.getInstance().lookupAll(); 1392 } 1393} 1394 | Popular Tags |