| 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 &nb
|