0001: /*
0002: * Copyright 2004-2005 OpenSymphony
0003: *
0004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0005: * use this file except in compliance with the License. You may obtain a copy
0006: * of the License at
0007: *
0008: * http://www.apache.org/licenses/LICENSE-2.0
0009: *
0010: * Unless required by applicable law or agreed to in writing, software
0011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0013: * License for the specific language governing permissions and limitations
0014: * under the License.
0015: *
0016: */
0017:
0018: /*
0019: * Previously Copyright (c) 2001-2004 James House
0020: */
0021: package org.quartz.impl;
0022:
0023: import java.beans.BeanInfo;
0024: import java.beans.IntrospectionException;
0025: import java.beans.Introspector;
0026: import java.beans.PropertyDescriptor;
0027: import java.io.BufferedInputStream;
0028: import java.io.File;
0029: import java.io.FileInputStream;
0030: import java.io.IOException;
0031: import java.io.InputStream;
0032: import java.lang.reflect.Method;
0033: import java.security.AccessControlException;
0034: import java.sql.SQLException;
0035: import java.util.Collection;
0036: import java.util.Iterator;
0037: import java.util.Locale;
0038: import java.util.Properties;
0039:
0040: import org.apache.commons.logging.Log;
0041: import org.apache.commons.logging.LogFactory;
0042: import org.quartz.JobListener;
0043: import org.quartz.Scheduler;
0044: import org.quartz.SchedulerConfigException;
0045: import org.quartz.SchedulerException;
0046: import org.quartz.SchedulerFactory;
0047: import org.quartz.TriggerListener;
0048: import org.quartz.core.JobRunShellFactory;
0049: import org.quartz.core.QuartzScheduler;
0050: import org.quartz.core.QuartzSchedulerResources;
0051: import org.quartz.core.SchedulingContext;
0052: import org.quartz.ee.jta.JTAJobRunShellFactory;
0053: import org.quartz.ee.jta.UserTransactionHelper;
0054: import org.quartz.impl.jdbcjobstore.JobStoreSupport;
0055: import org.quartz.impl.jdbcjobstore.Semaphore;
0056: import org.quartz.impl.jdbcjobstore.TablePrefixAware;
0057: import org.quartz.simpl.RAMJobStore;
0058: import org.quartz.simpl.SimpleThreadPool;
0059: import org.quartz.spi.ClassLoadHelper;
0060: import org.quartz.spi.InstanceIdGenerator;
0061: import org.quartz.spi.JobFactory;
0062: import org.quartz.spi.JobStore;
0063: import org.quartz.spi.SchedulerPlugin;
0064: import org.quartz.spi.ThreadPool;
0065: import org.quartz.utils.ConnectionProvider;
0066: import org.quartz.utils.DBConnectionManager;
0067: import org.quartz.utils.JNDIConnectionProvider;
0068: import org.quartz.utils.PoolingConnectionProvider;
0069: import org.quartz.utils.PropertiesParser;
0070:
0071: /**
0072: * <p>
0073: * An implementation of <code>{@link org.quartz.SchedulerFactory}</code> that
0074: * does all of its work of creating a <code>QuartzScheduler</code> instance
0075: * based on the contenents of a <code>Properties</code> file.
0076: * </p>
0077: *
0078: * <p>
0079: * By default a properties file named "quartz.properties" is loaded from the
0080: * 'current working directory'. If that fails, then the "quartz.properties"
0081: * file located (as a resource) in the org/quartz package is loaded. If you
0082: * wish to use a file other than these defaults, you must define the system
0083: * property 'org.quartz.properties' to point to the file you want.
0084: * </p>
0085: *
0086: * <p>
0087: * See the sample properties files that are distributed with Quartz for
0088: * information about the various settings available within the file.
0089: * </p>
0090: *
0091: * <p>
0092: * Alternatively, you can explicitly initialize the factory by calling one of
0093: * the <code>initialize(xx)</code> methods before calling <code>getScheduler()</code>.
0094: * </p>
0095: *
0096: * <p>
0097: * Instances of the specified <code>{@link org.quartz.spi.JobStore}</code>,
0098: * <code>{@link org.quartz.spi.ThreadPool}</code>, classes will be created
0099: * by name, and then any additional properties specified for them in the config
0100: * file will be set on the instance by calling an equivalent 'set' method. For
0101: * example if the properties file contains the property
0102: * 'org.quartz.jobStore.myProp = 10' then after the JobStore class has been
0103: * instantiated, the method 'setMyProp()' will be called on it. Type conversion
0104: * to primitive Java types (int, long, float, double, boolean, and String) are
0105: * performed before calling the property's setter method.
0106: * </p>
0107: *
0108: * @author James House
0109: * @author Anthony Eden
0110: * @author Mohammad Rezaei
0111: */
0112: public class StdSchedulerFactory implements SchedulerFactory {
0113:
0114: /*
0115: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0116: *
0117: * Constants.
0118: *
0119: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0120: */
0121:
0122: public static final String PROPERTIES_FILE = "org.quartz.properties";
0123:
0124: public static final String PROP_SCHED_INSTANCE_NAME = "org.quartz.scheduler.instanceName";
0125:
0126: public static final String PROP_SCHED_INSTANCE_ID = "org.quartz.scheduler.instanceId";
0127:
0128: public static final String PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX = "org.quartz.scheduler.instanceIdGenerator";
0129:
0130: public static final String PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS = PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX
0131: + ".class";
0132:
0133: public static final String PROP_SCHED_THREAD_NAME = "org.quartz.scheduler.threadName";
0134:
0135: public static final String PROP_SCHED_JMX_EXPORT = "org.quartz.scheduler.jmx.export";
0136:
0137: public static final String PROP_SCHED_JMX_PROXY = "org.quartz.scheduler.jmx.proxy";
0138:
0139: public static final String PROP_SCHED_JMX_PROXY_CLASS = "org.quartz.scheduler.jmx.proxy.class";
0140:
0141: public static final String PROP_SCHED_JMX_OBJECT_NAME = "org.quartz.scheduler.jmx.objectName";
0142:
0143: public static final String PROP_SCHED_RMI_EXPORT = "org.quartz.scheduler.rmi.export";
0144:
0145: public static final String PROP_SCHED_RMI_PROXY = "org.quartz.scheduler.rmi.proxy";
0146:
0147: public static final String PROP_SCHED_RMI_HOST = "org.quartz.scheduler.rmi.registryHost";
0148:
0149: public static final String PROP_SCHED_RMI_PORT = "org.quartz.scheduler.rmi.registryPort";
0150:
0151: public static final String PROP_SCHED_RMI_SERVER_PORT = "org.quartz.scheduler.rmi.serverPort";
0152:
0153: public static final String PROP_SCHED_RMI_CREATE_REGISTRY = "org.quartz.scheduler.rmi.createRegistry";
0154:
0155: public static final String PROP_SCHED_RMI_BIND_NAME = "org.quartz.scheduler.rmi.bindName";
0156:
0157: public static final String PROP_SCHED_WRAP_JOB_IN_USER_TX = "org.quartz.scheduler.wrapJobExecutionInUserTransaction";
0158:
0159: public static final String PROP_SCHED_USER_TX_URL = "org.quartz.scheduler.userTransactionURL";
0160:
0161: public static final String PROP_SCHED_IDLE_WAIT_TIME = "org.quartz.scheduler.idleWaitTime";
0162:
0163: public static final String PROP_SCHED_DB_FAILURE_RETRY_INTERVAL = "org.quartz.scheduler.dbFailureRetryInterval";
0164:
0165: public static final String PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON = "org.quartz.scheduler.makeSchedulerThreadDaemon";
0166:
0167: public static final String PROP_SCHED_CLASS_LOAD_HELPER_CLASS = "org.quartz.scheduler.classLoadHelper.class";
0168:
0169: public static final String PROP_SCHED_JOB_FACTORY_CLASS = "org.quartz.scheduler.jobFactory.class";
0170:
0171: public static final String PROP_SCHED_JOB_FACTORY_PREFIX = "org.quartz.scheduler.jobFactory";
0172:
0173: public static final String PROP_SCHED_CONTEXT_PREFIX = "org.quartz.context.key";
0174:
0175: public static final String PROP_THREAD_POOL_PREFIX = "org.quartz.threadPool";
0176:
0177: public static final String PROP_THREAD_POOL_CLASS = "org.quartz.threadPool.class";
0178:
0179: public static final String PROP_JOB_STORE_PREFIX = "org.quartz.jobStore";
0180:
0181: public static final String PROP_JOB_STORE_LOCK_HANDLER_PREFIX = PROP_JOB_STORE_PREFIX
0182: + ".lockHandler";
0183:
0184: public static final String PROP_JOB_STORE_LOCK_HANDLER_CLASS = PROP_JOB_STORE_LOCK_HANDLER_PREFIX
0185: + ".class";
0186:
0187: public static final String PROP_TABLE_PREFIX = "tablePrefix";
0188:
0189: public static final String PROP_JOB_STORE_CLASS = "org.quartz.jobStore.class";
0190:
0191: public static final String PROP_JOB_STORE_USE_PROP = "org.quartz.jobStore.useProperties";
0192:
0193: public static final String PROP_DATASOURCE_PREFIX = "org.quartz.dataSource";
0194:
0195: public static final String PROP_CONNECTION_PROVIDER_CLASS = "connectionProvider.class";
0196:
0197: public static final String PROP_DATASOURCE_DRIVER = "driver";
0198:
0199: public static final String PROP_DATASOURCE_URL = "URL";
0200:
0201: public static final String PROP_DATASOURCE_USER = "user";
0202:
0203: public static final String PROP_DATASOURCE_PASSWORD = "password";
0204:
0205: public static final String PROP_DATASOURCE_MAX_CONNECTIONS = "maxConnections";
0206:
0207: public static final String PROP_DATASOURCE_VALIDATION_QUERY = "validationQuery";
0208:
0209: public static final String PROP_DATASOURCE_JNDI_URL = "jndiURL";
0210:
0211: public static final String PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP = "jndiAlwaysLookup";
0212:
0213: public static final String PROP_DATASOURCE_JNDI_INITIAL = "java.naming.factory.initial";
0214:
0215: public static final String PROP_DATASOURCE_JNDI_PROVDER = "java.naming.provider.url";
0216:
0217: public static final String PROP_DATASOURCE_JNDI_PRINCIPAL = "java.naming.security.principal";
0218:
0219: public static final String PROP_DATASOURCE_JNDI_CREDENTIALS = "java.naming.security.credentials";
0220:
0221: public static final String PROP_PLUGIN_PREFIX = "org.quartz.plugin";
0222:
0223: public static final String PROP_PLUGIN_CLASS = "class";
0224:
0225: public static final String PROP_JOB_LISTENER_PREFIX = "org.quartz.jobListener";
0226:
0227: public static final String PROP_TRIGGER_LISTENER_PREFIX = "org.quartz.triggerListener";
0228:
0229: public static final String PROP_LISTENER_CLASS = "class";
0230:
0231: public static final String DEFAULT_INSTANCE_ID = "NON_CLUSTERED";
0232:
0233: public static final String AUTO_GENERATE_INSTANCE_ID = "AUTO";
0234:
0235: /*
0236: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0237: *
0238: * Data members.
0239: *
0240: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0241: */
0242:
0243: private SchedulerException initException = null;
0244:
0245: private String propSrc = null;
0246:
0247: private PropertiesParser cfg;
0248:
0249: private final Log log = LogFactory.getLog(getClass());
0250:
0251: // private Scheduler scheduler;
0252:
0253: /*
0254: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0255: *
0256: * Constructors.
0257: *
0258: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0259: */
0260:
0261: /**
0262: * Create an uninitialized StdSchedulerFactory.
0263: */
0264: public StdSchedulerFactory() {
0265: }
0266:
0267: /**
0268: * Create a StdSchedulerFactory that has been initialized via
0269: * <code>{@link #initialize(Properties)}</code>.
0270: *
0271: * @see #initialize(Properties)
0272: */
0273: public StdSchedulerFactory(Properties props)
0274: throws SchedulerException {
0275: initialize(props);
0276: }
0277:
0278: /**
0279: * Create a StdSchedulerFactory that has been initialized via
0280: * <code>{@link #initialize(String)}</code>.
0281: *
0282: * @see #initialize(String)
0283: */
0284: public StdSchedulerFactory(String fileName)
0285: throws SchedulerException {
0286: initialize(fileName);
0287: }
0288:
0289: /*
0290: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0291: *
0292: * Interface.
0293: *
0294: * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0295: */
0296:
0297: public Log getLog() {
0298: return log;
0299: }
0300:
0301: /**
0302: * <p>
0303: * Initialize the <code>{@link org.quartz.SchedulerFactory}</code> with
0304: * the contents of a <code>Properties</code> file and overriding System
0305: * properties.
0306: * </p>
0307: *
0308: * <p>
0309: * By default a properties file named "quartz.properties" is loaded from
0310: * the 'current working directory'. If that fails, then the
0311: * "quartz.properties" file located (as a resource) in the org/quartz
0312: * package is loaded. If you wish to use a file other than these defaults,
0313: * you must define the system property 'org.quartz.properties' to point to
0314: * the file you want.
0315: * </p>
0316: *
0317: * <p>
0318: * System properties (environment variables, and -D definitions on the
0319: * command-line when running the JVM) override any properties in the
0320: * loaded file. For this reason, you may want to use a different initialize()
0321: * method if your application security policy prohibits access to
0322: * <code>{@link java.lang.System#getProperties()}</code>.
0323: * </p>
0324: */
0325: public void initialize() throws SchedulerException {
0326: // short-circuit if already initialized
0327: if (cfg != null) {
0328: return;
0329: }
0330: if (initException != null) {
0331: throw initException;
0332: }
0333:
0334: String requestedFile = System.getProperty(PROPERTIES_FILE);
0335: String propFileName = requestedFile != null ? requestedFile
0336: : "quartz.properties";
0337: File propFile = new File(propFileName);
0338:
0339: Properties props = new Properties();
0340:
0341: if (propFile.exists()) {
0342: try {
0343: if (requestedFile != null) {
0344: propSrc = "specified file: '" + requestedFile + "'";
0345: } else {
0346: propSrc = "default file in current working dir: 'quartz.properties'";
0347: }
0348:
0349: props.load(new BufferedInputStream(new FileInputStream(
0350: propFileName)));
0351:
0352: } catch (IOException ioe) {
0353: initException = new SchedulerException(
0354: "Properties file: '" + propFileName
0355: + "' could not be read.", ioe);
0356: throw initException;
0357: }
0358: } else if (requestedFile != null) {
0359: InputStream in = Thread.currentThread()
0360: .getContextClassLoader().getResourceAsStream(
0361: requestedFile);
0362:
0363: if (in == null) {
0364: initException = new SchedulerException(
0365: "Properties file: '" + requestedFile
0366: + "' could not be found.");
0367: throw initException;
0368: }
0369:
0370: propSrc = "specified file: '" + requestedFile
0371: + "' in the class resource path.";
0372:
0373: try {
0374: props.load(new BufferedInputStream(in));
0375: } catch (IOException ioe) {
0376: initException = new SchedulerException(
0377: "Properties file: '" + requestedFile
0378: + "' could not be read.", ioe);
0379: throw initException;
0380: }
0381:
0382: } else {
0383: propSrc = "default resource file in Quartz package: 'quartz.properties'";
0384:
0385: InputStream in = getClass().getClassLoader()
0386: .getResourceAsStream("quartz.properties");
0387:
0388: if (in == null) {
0389: in = getClass().getClassLoader().getResourceAsStream(
0390: "/quartz.properties");
0391: }
0392: if (in == null) {
0393: in = getClass().getClassLoader().getResourceAsStream(
0394: "org/quartz/quartz.properties");
0395: }
0396: if (in == null) {
0397: initException = new SchedulerException(
0398: "Default quartz.properties not found in class path");
0399: throw initException;
0400: }
0401: try {
0402: props.load(in);
0403: } catch (IOException ioe) {
0404: initException = new SchedulerException(
0405: "Resource properties file: 'org/quartz/quartz.properties' "
0406: + "could not be read from the classpath.",
0407: ioe);
0408: throw initException;
0409: }
0410: }
0411:
0412: initialize(overrideWithSysProps(props));
0413: }
0414:
0415: /**
0416: * Add all System properties to the given <code>props</code>. Will override
0417: * any properties that already exist in the given <code>props</code>.
0418: */
0419: private Properties overrideWithSysProps(Properties props) {
0420: Properties sysProps = null;
0421: try {
0422: sysProps = System.getProperties();
0423: } catch (AccessControlException e) {
0424: getLog()
0425: .warn(
0426: "Skipping overriding quartz properties with System properties "
0427: + "during initialization because of an AccessControlException. "
0428: + "This is likely due to not having read/write access for "
0429: + "java.util.PropertyPermission as required by java.lang.System.getProperties(). "
0430: + "To resolve this warning, either add this permission to your policy file or "
0431: + "use a non-default version of initialize().",
0432: e);
0433: }
0434:
0435: if (sysProps != null) {
0436: props.putAll(sysProps);
0437: }
0438:
0439: return props;
0440: }
0441:
0442: /**
0443: * <p>
0444: * Initialize the <code>{@link org.quartz.SchedulerFactory}</code> with
0445: * the contenents of the <code>Properties</code> file with the given
0446: * name.
0447: * </p>
0448: */
0449: public void initialize(String filename) throws SchedulerException {
0450: // short-circuit if already initialized
0451: if (cfg != null) {
0452: return;
0453: }
0454:
0455: if (initException != null) {
0456: throw initException;
0457: }
0458:
0459: InputStream is = null;
0460: Properties props = new Properties();
0461:
0462: is = Thread.currentThread().getContextClassLoader()
0463: .getResourceAsStream(filename);
0464:
0465: try {
0466: if (is != null) {
0467: is = new BufferedInputStream(is);
0468: propSrc = "the specified file : '" + filename
0469: + "' from the class resource path.";
0470: } else {
0471: is = new BufferedInputStream(new FileInputStream(
0472: filename));
0473: propSrc = "the specified file : '" + filename + "'";
0474: }
0475: props.load(is);
0476: } catch (IOException ioe) {
0477: initException = new SchedulerException("Properties file: '"
0478: + filename + "' could not be read.", ioe);
0479: throw initException;
0480: }
0481:
0482: initialize(props);
0483: }
0484:
0485: /**
0486: * <p>
0487: * Initialize the <code>{@link org.quartz.SchedulerFactory}</code> with
0488: * the contenents of the <code>Properties</code> file opened with the
0489: * given <code>InputStream</code>.
0490: * </p>
0491: */
0492: public void initialize(InputStream propertiesStream)
0493: throws SchedulerException {
0494: // short-circuit if already initialized
0495: if (cfg != null) {
0496: return;
0497: }
0498:
0499: if (initException != null) {
0500: throw initException;
0501: }
0502:
0503: Properties props = new Properties();
0504:
0505: if (propertiesStream != null) {
0506: try {
0507: props.load(propertiesStream);
0508: propSrc = "an externally opened InputStream.";
0509: } catch (IOException e) {
0510: initException = new SchedulerException(
0511: "Error loading property data from InputStream",
0512: e);
0513: throw initException;
0514: }
0515: } else {
0516: initException = new SchedulerException(
0517: "Error loading property data from InputStream - InputStream is null.");
0518: throw initException;
0519: }
0520:
0521: initialize(props);
0522: }
0523:
0524: /**
0525: * <p>
0526: * Initialize the <code>{@link org.quartz.SchedulerFactory}</code> with
0527: * the contenents of the given <code>Properties</code> object.
0528: * </p>
0529: */
0530: public void initialize(Properties props) throws SchedulerException {
0531: if (propSrc == null) {
0532: propSrc = "an externally provided properties instance.";
0533: }
0534:
0535: this .cfg = new PropertiesParser(props);
0536: }
0537:
0538: private Scheduler instantiate() throws SchedulerException {
0539: if (cfg == null) {
0540: initialize();
0541: }
0542:
0543: if (initException != null) {
0544: throw initException;
0545: }
0546:
0547: JobStore js = null;
0548: ThreadPool tp = null;
0549: QuartzScheduler qs = null;
0550: SchedulingContext schedCtxt = null;
0551: DBConnectionManager dbMgr = null;
0552: String instanceIdGeneratorClass = null;
0553: Properties tProps = null;
0554: String userTXLocation = null;
0555: boolean wrapJobInTx = false;
0556: boolean autoId = false;
0557: long idleWaitTime = -1;
0558: long dbFailureRetry = -1;
0559: String classLoadHelperClass;
0560: String jobFactoryClass;
0561:
0562: SchedulerRepository schedRep = SchedulerRepository
0563: .getInstance();
0564:
0565: // Get Scheduler Properties
0566: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0567:
0568: String schedName = cfg.getStringProperty(
0569: PROP_SCHED_INSTANCE_NAME, "QuartzScheduler");
0570:
0571: String threadName = cfg.getStringProperty(
0572: PROP_SCHED_THREAD_NAME, schedName
0573: + "_QuartzSchedulerThread");
0574:
0575: String schedInstId = cfg.getStringProperty(
0576: PROP_SCHED_INSTANCE_ID, DEFAULT_INSTANCE_ID);
0577:
0578: if (schedInstId.equals(AUTO_GENERATE_INSTANCE_ID)) {
0579: autoId = true;
0580: instanceIdGeneratorClass = cfg.getStringProperty(
0581: PROP_SCHED_INSTANCE_ID_GENERATOR_CLASS,
0582: "org.quartz.simpl.SimpleInstanceIdGenerator");
0583: }
0584:
0585: userTXLocation = cfg.getStringProperty(PROP_SCHED_USER_TX_URL,
0586: userTXLocation);
0587: if (userTXLocation != null
0588: && userTXLocation.trim().length() == 0) {
0589: userTXLocation = null;
0590: }
0591:
0592: classLoadHelperClass = cfg.getStringProperty(
0593: PROP_SCHED_CLASS_LOAD_HELPER_CLASS,
0594: "org.quartz.simpl.CascadingClassLoadHelper");
0595: wrapJobInTx = cfg.getBooleanProperty(
0596: PROP_SCHED_WRAP_JOB_IN_USER_TX, wrapJobInTx);
0597:
0598: jobFactoryClass = cfg.getStringProperty(
0599: PROP_SCHED_JOB_FACTORY_CLASS, null);
0600:
0601: idleWaitTime = cfg.getLongProperty(PROP_SCHED_IDLE_WAIT_TIME,
0602: idleWaitTime);
0603: dbFailureRetry = cfg.getLongProperty(
0604: PROP_SCHED_DB_FAILURE_RETRY_INTERVAL, dbFailureRetry);
0605:
0606: boolean makeSchedulerThreadDaemon = cfg
0607: .getBooleanProperty(PROP_SCHED_MAKE_SCHEDULER_THREAD_DAEMON);
0608:
0609: boolean jmxExport = cfg
0610: .getBooleanProperty(PROP_SCHED_JMX_EXPORT);
0611: boolean jmxProxy = cfg.getBooleanProperty(PROP_SCHED_JMX_PROXY);
0612: String jmxProxyClass = cfg
0613: .getStringProperty(PROP_SCHED_JMX_PROXY_CLASS);
0614: String jmxObjectName = cfg
0615: .getStringProperty(PROP_SCHED_JMX_OBJECT_NAME);
0616:
0617: boolean rmiExport = cfg.getBooleanProperty(
0618: PROP_SCHED_RMI_EXPORT, false);
0619: boolean rmiProxy = cfg.getBooleanProperty(PROP_SCHED_RMI_PROXY,
0620: false);
0621: String rmiHost = cfg.getStringProperty(PROP_SCHED_RMI_HOST,
0622: "localhost");
0623: int rmiPort = cfg.getIntProperty(PROP_SCHED_RMI_PORT, 1099);
0624: int rmiServerPort = cfg.getIntProperty(
0625: PROP_SCHED_RMI_SERVER_PORT, -1);
0626: String rmiCreateRegistry = cfg.getStringProperty(
0627: PROP_SCHED_RMI_CREATE_REGISTRY,
0628: QuartzSchedulerResources.CREATE_REGISTRY_NEVER);
0629: String rmiBindName = cfg
0630: .getStringProperty(PROP_SCHED_RMI_BIND_NAME);
0631:
0632: if (jmxProxy && rmiProxy) {
0633: throw new SchedulerConfigException(
0634: "Cannot proxy both RMI and JMX.");
0635: }
0636:
0637: Properties schedCtxtProps = cfg.getPropertyGroup(
0638: PROP_SCHED_CONTEXT_PREFIX, true);
0639:
0640: // If Proxying to remote scheduler, short-circuit here...
0641: // ~~~~~~~~~~~~~~~~~~
0642: if (rmiProxy) {
0643:
0644: if (autoId) {
0645: schedInstId = DEFAULT_INSTANCE_ID;
0646: }
0647:
0648: schedCtxt = new SchedulingContext();
0649: schedCtxt.setInstanceId(schedInstId);
0650:
0651: String uid = (rmiBindName == null) ? QuartzSchedulerResources
0652: .getUniqueIdentifier(schedName, schedInstId)
0653: : rmiBindName;
0654:
0655: RemoteScheduler remoteScheduler = new RemoteScheduler(
0656: schedCtxt, uid, rmiHost, rmiPort);
0657:
0658: schedRep.bind(remoteScheduler);
0659:
0660: return remoteScheduler;
0661: }
0662:
0663: // Create class load helper
0664: ClassLoadHelper loadHelper = null;
0665: try {
0666: loadHelper = (ClassLoadHelper) loadClass(
0667: classLoadHelperClass).newInstance();
0668: } catch (Exception e) {
0669: throw new SchedulerConfigException(
0670: "Unable to instantiate class load helper class: "
0671: + e.getMessage(), e);
0672: }
0673: loadHelper.initialize();
0674:
0675: // If Proxying to remote JMX scheduler, short-circuit here...
0676: // ~~~~~~~~~~~~~~~~~~
0677: if (jmxProxy) {
0678: if (autoId) {
0679: schedInstId = DEFAULT_INSTANCE_ID;
0680: }
0681:
0682: if (jmxProxyClass == null) {
0683: throw new SchedulerConfigException(
0684: "No JMX Proxy Scheduler class provided");
0685: }
0686:
0687: RemoteMBeanScheduler jmxScheduler = null;
0688: try {
0689: jmxScheduler = (RemoteMBeanScheduler) loadHelper
0690: .loadClass(jmxProxyClass).newInstance();
0691: } catch (Exception e) {
0692: throw new SchedulerConfigException(
0693: "Unable to instantiate RemoteMBeanScheduler class.",
0694: e);
0695: }
0696:
0697: schedCtxt = new SchedulingContext();
0698: schedCtxt.setInstanceId(schedInstId);
0699:
0700: if (jmxObjectName == null) {
0701: jmxObjectName = QuartzSchedulerResources
0702: .generateJMXObjectName(schedName, schedInstId);
0703: }
0704:
0705: jmxScheduler.setSchedulingContext(schedCtxt);
0706: jmxScheduler.setSchedulerObjectName(jmxObjectName);
0707:
0708: tProps = cfg.getPropertyGroup(PROP_SCHED_JMX_PROXY, true);
0709: try {
0710: setBeanProps(jmxScheduler, tProps);
0711: } catch (Exception e) {
0712: initException = new SchedulerException(
0713: "RemoteMBeanScheduler class '" + jmxProxyClass
0714: + "' props could not be configured.", e);
0715: initException
0716: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0717: throw initException;
0718: }
0719:
0720: jmxScheduler.initialize();
0721:
0722: schedRep.bind(jmxScheduler);
0723:
0724: return jmxScheduler;
0725: }
0726:
0727: JobFactory jobFactory = null;
0728: if (jobFactoryClass != null) {
0729: try {
0730: jobFactory = (JobFactory) loadHelper.loadClass(
0731: jobFactoryClass).newInstance();
0732: } catch (Exception e) {
0733: throw new SchedulerConfigException(
0734: "Unable to instantiate JobFactory class: "
0735: + e.getMessage(), e);
0736: }
0737:
0738: tProps = cfg.getPropertyGroup(
0739: PROP_SCHED_JOB_FACTORY_PREFIX, true);
0740: try {
0741: setBeanProps(jobFactory, tProps);
0742: } catch (Exception e) {
0743: initException = new SchedulerException(
0744: "JobFactory class '" + jobFactoryClass
0745: + "' props could not be configured.", e);
0746: initException
0747: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0748: throw initException;
0749: }
0750: }
0751:
0752: InstanceIdGenerator instanceIdGenerator = null;
0753: if (instanceIdGeneratorClass != null) {
0754: try {
0755: instanceIdGenerator = (InstanceIdGenerator) loadHelper
0756: .loadClass(instanceIdGeneratorClass)
0757: .newInstance();
0758: } catch (Exception e) {
0759: throw new SchedulerConfigException(
0760: "Unable to instantiate InstanceIdGenerator class: "
0761: + e.getMessage(), e);
0762: }
0763:
0764: tProps = cfg.getPropertyGroup(
0765: PROP_SCHED_INSTANCE_ID_GENERATOR_PREFIX, true);
0766: try {
0767: setBeanProps(instanceIdGenerator, tProps);
0768: } catch (Exception e) {
0769: initException = new SchedulerException(
0770: "InstanceIdGenerator class '"
0771: + instanceIdGeneratorClass
0772: + "' props could not be configured.", e);
0773: initException
0774: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0775: throw initException;
0776: }
0777: }
0778:
0779: // Get ThreadPool Properties
0780: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0781:
0782: String tpClass = cfg.getStringProperty(PROP_THREAD_POOL_CLASS,
0783: null);
0784:
0785: if (tpClass == null) {
0786: initException = new SchedulerException(
0787: "ThreadPool class not specified. ",
0788: SchedulerException.ERR_BAD_CONFIGURATION);
0789: throw initException;
0790: }
0791:
0792: try {
0793: tp = (ThreadPool) loadHelper.loadClass(tpClass)
0794: .newInstance();
0795: } catch (Exception e) {
0796: initException = new SchedulerException("ThreadPool class '"
0797: + tpClass + "' could not be instantiated.", e);
0798: initException
0799: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0800: throw initException;
0801: }
0802: tProps = cfg.getPropertyGroup(PROP_THREAD_POOL_PREFIX, true);
0803: try {
0804: setBeanProps(tp, tProps);
0805: } catch (Exception e) {
0806: initException = new SchedulerException("ThreadPool class '"
0807: + tpClass + "' props could not be configured.", e);
0808: initException
0809: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0810: throw initException;
0811: }
0812:
0813: // Get JobStore Properties
0814: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0815:
0816: String jsClass = cfg.getStringProperty(PROP_JOB_STORE_CLASS,
0817: RAMJobStore.class.getName());
0818:
0819: if (jsClass == null) {
0820: initException = new SchedulerException(
0821: "JobStore class not specified. ",
0822: SchedulerException.ERR_BAD_CONFIGURATION);
0823: throw initException;
0824: }
0825:
0826: try {
0827: js = (JobStore) loadHelper.loadClass(jsClass).newInstance();
0828: } catch (Exception e) {
0829: initException = new SchedulerException("JobStore class '"
0830: + jsClass + "' could not be instantiated.", e);
0831: initException
0832: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0833: throw initException;
0834: }
0835: tProps = cfg.getPropertyGroup(PROP_JOB_STORE_PREFIX, true,
0836: new String[] { PROP_JOB_STORE_LOCK_HANDLER_PREFIX });
0837: try {
0838: setBeanProps(js, tProps);
0839: } catch (Exception e) {
0840: initException = new SchedulerException("JobStore class '"
0841: + jsClass + "' props could not be configured.", e);
0842: initException
0843: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0844: throw initException;
0845: }
0846:
0847: if (js instanceof JobStoreSupport) {
0848: ((JobStoreSupport) js).setInstanceId(schedInstId);
0849: ((JobStoreSupport) js).setInstanceName(schedName);
0850:
0851: // Install custom lock handler (Semaphore)
0852: String lockHandlerClass = cfg
0853: .getStringProperty(PROP_JOB_STORE_LOCK_HANDLER_CLASS);
0854: if (lockHandlerClass != null) {
0855: try {
0856: Semaphore lockHandler = (Semaphore) loadHelper
0857: .loadClass(lockHandlerClass).newInstance();
0858:
0859: tProps = cfg.getPropertyGroup(
0860: PROP_JOB_STORE_LOCK_HANDLER_PREFIX, true);
0861:
0862: // If this lock handler requires the table prefix, add it to its properties.
0863: if (lockHandler instanceof TablePrefixAware) {
0864: tProps
0865: .setProperty(PROP_TABLE_PREFIX,
0866: ((JobStoreSupport) js)
0867: .getTablePrefix());
0868: }
0869:
0870: try {
0871: setBeanProps(lockHandler, tProps);
0872: } catch (Exception e) {
0873: initException = new SchedulerException(
0874: "JobStore LockHandler class '"
0875: + lockHandlerClass
0876: + "' props could not be configured.",
0877: e);
0878: initException
0879: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0880: throw initException;
0881: }
0882:
0883: ((JobStoreSupport) js).setLockHandler(lockHandler);
0884: getLog().info(
0885: "Using custom data access locking (synchronization): "
0886: + lockHandlerClass);
0887: } catch (Exception e) {
0888: initException = new SchedulerException(
0889: "JobStore LockHandler class '"
0890: + lockHandlerClass
0891: + "' could not be instantiated.", e);
0892: initException
0893: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0894: throw initException;
0895: }
0896: }
0897: }
0898:
0899: // Set up any DataSources
0900: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0901:
0902: String[] dsNames = cfg
0903: .getPropertyGroups(PROP_DATASOURCE_PREFIX);
0904: for (int i = 0; i < dsNames.length; i++) {
0905: PropertiesParser pp = new PropertiesParser(cfg
0906: .getPropertyGroup(PROP_DATASOURCE_PREFIX + "."
0907: + dsNames[i], true));
0908:
0909: String cpClass = pp.getStringProperty(
0910: PROP_CONNECTION_PROVIDER_CLASS, null);
0911:
0912: // custom connectionProvider...
0913: if (cpClass != null) {
0914: ConnectionProvider cp = null;
0915: try {
0916: cp = (ConnectionProvider) loadHelper.loadClass(
0917: cpClass).newInstance();
0918: } catch (Exception e) {
0919: initException = new SchedulerException(
0920: "ConnectionProvider class '" + cpClass
0921: + "' could not be instantiated.", e);
0922: initException
0923: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0924: throw initException;
0925: }
0926:
0927: try {
0928: // remove the class name, so it isn't attempted to be set
0929: pp.getUnderlyingProperties().remove(
0930: PROP_CONNECTION_PROVIDER_CLASS);
0931:
0932: setBeanProps(cp, pp.getUnderlyingProperties());
0933: } catch (Exception e) {
0934: initException = new SchedulerException(
0935: "ConnectionProvider class '"
0936: + cpClass
0937: + "' props could not be configured.",
0938: e);
0939: initException
0940: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
0941: throw initException;
0942: }
0943:
0944: dbMgr = DBConnectionManager.getInstance();
0945: dbMgr.addConnectionProvider(dsNames[i], cp);
0946: } else {
0947: String dsJndi = pp.getStringProperty(
0948: PROP_DATASOURCE_JNDI_URL, null);
0949:
0950: if (dsJndi != null) {
0951: boolean dsAlwaysLookup = pp
0952: .getBooleanProperty(PROP_DATASOURCE_JNDI_ALWAYS_LOOKUP);
0953: String dsJndiInitial = pp
0954: .getStringProperty(PROP_DATASOURCE_JNDI_INITIAL);
0955: String dsJndiProvider = pp
0956: .getStringProperty(PROP_DATASOURCE_JNDI_PROVDER);
0957: String dsJndiPrincipal = pp
0958: .getStringProperty(PROP_DATASOURCE_JNDI_PRINCIPAL);
0959: String dsJndiCredentials = pp
0960: .getStringProperty(PROP_DATASOURCE_JNDI_CREDENTIALS);
0961: Properties props = null;
0962: if (null != dsJndiInitial || null != dsJndiProvider
0963: || null != dsJndiPrincipal
0964: || null != dsJndiCredentials) {
0965: props = new Properties();
0966: if (dsJndiInitial != null) {
0967: props.put(PROP_DATASOURCE_JNDI_INITIAL,
0968: dsJndiInitial);
0969: }
0970: if (dsJndiProvider != null) {
0971: props.put(PROP_DATASOURCE_JNDI_PROVDER,
0972: dsJndiProvider);
0973: }
0974: if (dsJndiPrincipal != null) {
0975: props.put(PROP_DATASOURCE_JNDI_PRINCIPAL,
0976: dsJndiPrincipal);
0977: }
0978: if (dsJndiCredentials != null) {
0979: props.put(PROP_DATASOURCE_JNDI_CREDENTIALS,
0980: dsJndiCredentials);
0981: }
0982: }
0983: JNDIConnectionProvider cp = new JNDIConnectionProvider(
0984: dsJndi, props, dsAlwaysLookup);
0985: dbMgr = DBConnectionManager.getInstance();
0986: dbMgr.addConnectionProvider(dsNames[i], cp);
0987: } else {
0988: String dsDriver = pp
0989: .getStringProperty(PROP_DATASOURCE_DRIVER);
0990: String dsURL = pp
0991: .getStringProperty(PROP_DATASOURCE_URL);
0992: String dsUser = pp.getStringProperty(
0993: PROP_DATASOURCE_USER, "");
0994: String dsPass = pp.getStringProperty(
0995: PROP_DATASOURCE_PASSWORD, "");
0996: int dsCnt = pp.getIntProperty(
0997: PROP_DATASOURCE_MAX_CONNECTIONS, 10);
0998: String dsValidation = pp
0999: .getStringProperty(PROP_DATASOURCE_VALIDATION_QUERY);
1000:
1001: if (dsDriver == null) {
1002: initException = new SchedulerException(
1003: "Driver not specified for DataSource: "
1004: + dsNames[i]);
1005: throw initException;
1006: }
1007: if (dsURL == null) {
1008: initException = new SchedulerException(
1009: "DB URL not specified for DataSource: "
1010: + dsNames[i]);
1011: throw initException;
1012: }
1013: try {
1014: PoolingConnectionProvider cp = new PoolingConnectionProvider(
1015: dsDriver, dsURL, dsUser, dsPass, dsCnt,
1016: dsValidation);
1017: dbMgr = DBConnectionManager.getInstance();
1018: dbMgr.addConnectionProvider(dsNames[i], cp);
1019: } catch (SQLException sqle) {
1020: initException = new SchedulerException(
1021: "Could not initialize DataSource: "
1022: + dsNames[i], sqle);
1023: throw initException;
1024: }
1025: }
1026:
1027: }
1028:
1029: }
1030:
1031: // Set up any SchedulerPlugins
1032: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1033:
1034: String[] pluginNames = cfg
1035: .getPropertyGroups(PROP_PLUGIN_PREFIX);
1036: SchedulerPlugin[] plugins = new SchedulerPlugin[pluginNames.length];
1037: for (int i = 0; i < pluginNames.length; i++) {
1038: Properties pp = cfg.getPropertyGroup(PROP_PLUGIN_PREFIX
1039: + "." + pluginNames[i], true);
1040:
1041: String plugInClass = pp
1042: .getProperty(PROP_PLUGIN_CLASS, null);
1043:
1044: if (plugInClass == null) {
1045: initException = new SchedulerException(
1046: "SchedulerPlugin class not specified for plugin '"
1047: + pluginNames[i] + "'",
1048: SchedulerException.ERR_BAD_CONFIGURATION);
1049: throw initException;
1050: }
1051: SchedulerPlugin plugin = null;
1052: try {
1053: plugin = (SchedulerPlugin) loadHelper.loadClass(
1054: plugInClass).newInstance();
1055: } catch (Exception e) {
1056: initException = new SchedulerException(
1057: "SchedulerPlugin class '" + plugInClass
1058: + "' could not be instantiated.", e);
1059: initException
1060: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
1061: throw initException;
1062: }
1063: try {
1064: setBeanProps(plugin, pp);
1065: } catch (Exception e) {
1066: initException = new SchedulerException(
1067: "JobStore SchedulerPlugin '" + plugInClass
1068: + "' props could not be configured.", e);
1069: initException
1070: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
1071: throw initException;
1072: }
1073:
1074: plugins[i] = plugin;
1075: }
1076:
1077: // Set up any JobListeners
1078: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1079:
1080: Class[] strArg = new Class[] { String.class };
1081: String[] jobListenerNames = cfg
1082: .getPropertyGroups(PROP_JOB_LISTENER_PREFIX);
1083: JobListener[] jobListeners = new JobListener[jobListenerNames.length];
1084: for (int i = 0; i < jobListenerNames.length; i++) {
1085: Properties lp = cfg.getPropertyGroup(
1086: PROP_JOB_LISTENER_PREFIX + "."
1087: + jobListenerNames[i], true);
1088:
1089: String listenerClass = lp.getProperty(PROP_LISTENER_CLASS,
1090: null);
1091:
1092: if (listenerClass == null) {
1093: initException = new SchedulerException(
1094: "JobListener class not specified for listener '"
1095: + jobListenerNames[i] + "'",
1096: SchedulerException.ERR_BAD_CONFIGURATION);
1097: throw initException;
1098: }
1099: JobListener listener = null;
1100: try {
1101: listener = (JobListener) loadHelper.loadClass(
1102: listenerClass).newInstance();
1103: } catch (Exception e) {
1104: initException = new SchedulerException(
1105: "JobListener class '" + listenerClass
1106: + "' could not be instantiated.", e);
1107: initException
1108: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
1109: throw initException;
1110: }
1111: try {
1112: Method nameSetter = listener.getClass().getMethod(
1113: "setName", strArg);
1114: if (nameSetter != null) {
1115: nameSetter.invoke(listener,
1116: new Object[] { jobListenerNames[i] });
1117: }
1118: setBeanProps(listener, lp);
1119: } catch (Exception e) {
1120: initException = new SchedulerException("JobListener '"
1121: + listenerClass
1122: + "' props could not be configured.", e);
1123: initException
1124: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
1125: throw initException;
1126: }
1127: jobListeners[i] = listener;
1128: }
1129:
1130: // Set up any TriggerListeners
1131: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1132:
1133: String[] triggerListenerNames = cfg
1134: .getPropertyGroups(PROP_TRIGGER_LISTENER_PREFIX);
1135: TriggerListener[] triggerListeners = new TriggerListener[triggerListenerNames.length];
1136: for (int i = 0; i < triggerListenerNames.length; i++) {
1137: Properties lp = cfg.getPropertyGroup(
1138: PROP_TRIGGER_LISTENER_PREFIX + "."
1139: + triggerListenerNames[i], true);
1140:
1141: String listenerClass = lp.getProperty(PROP_LISTENER_CLASS,
1142: null);
1143:
1144: if (listenerClass == null) {
1145: initException = new SchedulerException(
1146: "TriggerListener class not specified for listener '"
1147: + triggerListenerNames[i] + "'",
1148: SchedulerException.ERR_BAD_CONFIGURATION);
1149: throw initException;
1150: }
1151: TriggerListener listener = null;
1152: try {
1153: listener = (TriggerListener) loadHelper.loadClass(
1154: listenerClass).newInstance();
1155: } catch (Exception e) {
1156: initException = new SchedulerException(
1157: "TriggerListener class '" + listenerClass
1158: + "' could not be instantiated.", e);
1159: initException
1160: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
1161: throw initException;
1162: }
1163: try {
1164: Method nameSetter = listener.getClass().getMethod(
1165: "setName", strArg);
1166: if (nameSetter != null) {
1167: nameSetter.invoke(listener,
1168: new Object[] { triggerListenerNames[i] });
1169: }
1170: setBeanProps(listener, lp);
1171: } catch (Exception e) {
1172: initException = new SchedulerException(
1173: "TriggerListener '" + listenerClass
1174: + "' props could not be configured.", e);
1175: initException
1176: .setErrorCode(SchedulerException.ERR_BAD_CONFIGURATION);
1177: throw initException;
1178: }
1179: triggerListeners[i] = listener;
1180: }
1181:
1182: // Fire everything up
1183: // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1184:
1185: JobRunShellFactory jrsf = null; // Create correct run-shell factory...
1186:
1187: UserTransactionHelper.setUserTxLocation(userTXLocation);
1188:
1189: if (wrapJobInTx) {
1190: jrsf = new JTAJobRunShellFactory();
1191: } else {
1192: jrsf = new StdJobRunShellFactory();
1193: }
1194:
1195: if (autoId) {
1196: try {
1197: schedInstId = DEFAULT_INSTANCE_ID;
1198: if (js instanceof JobStoreSupport) {
1199: if (((JobStoreSupport) js).isClustered()) {
1200: schedInstId = instanceIdGenerator
1201: .generateInstanceId();
1202: }
1203: }
1204: } catch (Exception e) {
1205: getLog().error("Couldn't generate instance Id!", e);
1206: throw new IllegalStateException(
1207: "Cannot run without an instance id.");
1208: }
1209: }
1210:
1211: if (js instanceof JobStoreSupport) {
1212: JobStoreSupport jjs = (JobStoreSupport) js;
1213: jjs.setInstanceId(schedInstId);
1214: jjs.setDbRetryInterval(dbFailureRetry);
1215: }
1216:
1217: QuartzSchedulerResources rsrcs = new QuartzSchedulerResources();
1218: rsrcs.setName(schedName);
1219: rsrcs.setThreadName(threadName);
1220: rsrcs.setInstanceId(schedInstId);
1221: rsrcs.setJobRunShellFactory(jrsf);
1222: rsrcs.setMakeSchedulerThreadDaemon(makeSchedulerThreadDaemon);
1223: rsrcs.setJMXExport(jmxExport);
1224: rsrcs.setJMXObjectName(jmxObjectName);
1225:
1226: if (rmiExport) {
1227: rsrcs.setRMIRegistryHost(rmiHost);
1228: rsrcs.setRMIRegistryPort(rmiPort);
1229: rsrcs.setRMIServerPort(rmiServerPort);
1230: rsrcs.setRMICreateRegistryStrategy(rmiCreateRegistry);
1231: rsrcs.setRMIBindName(rmiBindName);
1232: }
1233:
1234: rsrcs.setThreadPool(tp);
1235: if (tp instanceof SimpleThreadPool) {
1236: ((SimpleThreadPool) tp).setThreadNamePrefix(schedName
1237: + "_Worker");
1238: }
1239: tp.initialize();
1240:
1241: rsrcs.setJobStore(js);
1242:
1243: // add plugins
1244: for (int i = 0; i < plugins.length; i++) {
1245: rsrcs.addSchedulerPlugin(plugins[i]);
1246: }
1247:
1248: schedCtxt = new SchedulingContext();
1249: schedCtxt.setInstanceId(rsrcs.getInstanceId());
1250:
1251: qs = new QuartzScheduler(rsrcs, schedCtxt, idleWaitTime,
1252: dbFailureRetry);
1253:
1254: // if(usingJSCMT)
1255: // qs.setSignalOnSchedulingChange(false); // TODO: fixed? (don't need
1256: // this any more?)
1257:
1258: // Create Scheduler ref...
1259: Scheduler scheduler = instantiate(rsrcs, qs);
1260:
1261: // set job factory if specified
1262: if (jobFactory != null) {
1263: qs.setJobFactory(jobFactory);
1264: }
1265:
1266: // Initialize plugins now that we have a Scheduler instance.
1267: for (int i = 0; i < plugins.length; i++) {
1268: plugins[i].initialize(pluginNames[i], scheduler);
1269: }
1270:
1271: // add listeners
1272: for (int i = 0; i < jobListeners.length; i++) {
1273: qs.addGlobalJobListener(jobListeners[i]);
1274: }
1275: for (int i = 0; i < triggerListeners.length; i++) {
1276: qs.addGlobalTriggerListener(triggerListeners[i]);
1277: }
1278:
1279: // set scheduler context data...
1280: Iterator itr = schedCtxtProps.keySet().iterator();
1281: while (itr.hasNext()) {
1282: String key = (String) itr.next();
1283: String val = schedCtxtProps.getProperty(key);
1284:
1285: scheduler.getContext().put(key, val);
1286: }
1287:
1288: // fire up job store, and runshell factory
1289:
1290: js.initialize(loadHelper, qs.getSchedulerSignaler());
1291:
1292: jrsf.initialize(scheduler, schedCtxt);
1293:
1294: getLog().info(
1295: "Quartz scheduler '" + scheduler.getSchedulerName()
1296: + "' initialized from " + propSrc);
1297:
1298: getLog().info("Quartz scheduler version: " + qs.getVersion());
1299:
1300: // prevents the repository from being garbage collected
1301: qs.addNoGCObject(schedRep);
1302: // prevents the db manager from being garbage collected
1303: if (dbMgr != null) {
1304: qs.addNoGCObject(dbMgr);
1305: }
1306:
1307: schedRep.bind(scheduler);
1308:
1309: return scheduler;
1310: }
1311:
1312: protected Scheduler instantiate(QuartzSchedulerResources rsrcs,
1313: QuartzScheduler qs) {
1314: SchedulingContext schedCtxt = new SchedulingContext();
1315: schedCtxt.setInstanceId(rsrcs.getInstanceId());
1316:
1317: Scheduler scheduler = new StdScheduler(qs, schedCtxt);
1318: return scheduler;
1319: }
1320:
1321: private void setBeanProps(Object obj, Properties props)
1322: throws NoSuchMethodException, IllegalAccessException,
1323: java.lang.reflect.InvocationTargetException,
1324: IntrospectionException, SchedulerConfigException {
1325: props.remove("class");
1326:
1327: BeanInfo bi = Introspector.getBeanInfo(obj.getClass());
1328: PropertyDescriptor[] propDescs = bi.getPropertyDescriptors();
1329: PropertiesParser pp = new PropertiesParser(props);
1330:
1331: java.util.Enumeration keys = props.keys();
1332: while (keys.hasMoreElements()) {
1333: String name = (String) keys.nextElement();
1334: String c = name.substring(0, 1).toUpperCase(Locale.US);
1335: String methName = "set" + c + name.substring(1);
1336:
1337: java.lang.reflect.Method setMeth = getSetMethod(methName,
1338: propDescs);
1339:
1340: try {
1341: if (setMeth == null) {
1342: throw new NoSuchMethodException(
1343: "No setter for property '" + name + "'");
1344: }
1345:
1346: Class[] params = setMeth.getParameterTypes();
1347: if (params.length != 1) {
1348: throw new NoSuchMethodException(
1349: "No 1-argument setter for property '"
1350: + name + "'");
1351: }
1352: if (params[0].equals(int.class)) {
1353: setMeth.invoke(obj, new Object[] { new Integer(pp
1354: .getIntProperty(name)) });
1355: } else if (params[0].equals(long.class)) {
1356: setMeth.invoke(obj, new Object[] { new Long(pp
1357: .getLongProperty(name)) });
1358: } else if (params[0].equals(float.class)) {
1359: setMeth.invoke(obj, new Object[] { new Float(pp
1360: .getFloatProperty(name)) });
1361: } else if (params[0].equals(double.class)) {
1362: setMeth.invoke(obj, new Object[] { new Double(pp
1363: .getDoubleProperty(name)) });
1364: } else if (params[0].equals(boolean.class)) {
1365: setMeth.invoke(obj, new Object[] { new Boolean(pp
1366: .getBooleanProperty(name)) });
1367: } else if (params[0].equals(String.class)) {
1368: setMeth.invoke(obj, new Object[] { pp
1369: .getStringProperty(name) });
1370: } else {
1371: throw new NoSuchMethodException(
1372: "No primitive-type setter for property '"
1373: + name + "'");
1374: }
1375: } catch (NumberFormatException nfe) {
1376: throw new SchedulerConfigException(
1377: "Could not parse property '" + name
1378: + "' into correct data type: "
1379: + nfe.toString());
1380: }
1381: }
1382: }
1383:
1384: private java.lang.reflect.Method getSetMethod(String name,
1385: PropertyDescriptor[] props) {
1386: for (int i = 0; i < props.length; i++) {
1387: java.lang.reflect.Method wMeth = props[i].getWriteMethod();
1388:
1389: if (wMeth != null && wMeth.getName().equals(name)) {
1390: return wMeth;
1391: }
1392: }
1393:
1394: return null;
1395: }
1396:
1397: private Class loadClass(String className)
1398: throws ClassNotFoundException {
1399:
1400: try {
1401: return Thread.currentThread().getContextClassLoader()
1402: .loadClass(className);
1403: } catch (ClassNotFoundException e) {
1404: return getClass().getClassLoader().loadClass(className);
1405: }
1406: }
1407:
1408: private String getSchedulerName() {
1409: return cfg.getStringProperty(PROP_SCHED_INSTANCE_NAME,
1410: "QuartzScheduler");
1411: }
1412:
1413: private String getSchedulerInstId() {
1414: return cfg.getStringProperty(PROP_SCHED_INSTANCE_ID,
1415: DEFAULT_INSTANCE_ID);
1416: }
1417:
1418: /**
1419: * <p>
1420: * Returns a handle to the Scheduler produced by this factory.
1421: * </p>
1422: *
1423: * <p>
1424: * If one of the <code>initialize</code> methods has not be previously
1425: * called, then the default (no-arg) <code>initialize()</code> method
1426: * will be called by this method.
1427: * </p>
1428: */
1429: public Scheduler getScheduler() throws SchedulerException {
1430: if (cfg == null) {
1431: initialize();
1432: }
1433:
1434: SchedulerRepository schedRep = SchedulerRepository
1435: .getInstance();
1436:
1437: Scheduler sched = schedRep.lookup(getSchedulerName());
1438:
1439: if (sched != null) {
1440: if (sched.isShutdown()) {
1441: schedRep.remove(getSchedulerName());
1442: } else {
1443: return sched;
1444: }
1445: }
1446:
1447: sched = instantiate();
1448:
1449: return sched;
1450: }
1451:
1452: /**
1453: * <p>
1454: * Returns a handle to the default Scheduler, creating it if it does not
1455: * yet exist.
1456: * </p>
1457: *
1458: * @see #initialize()
1459: */
1460: public static Scheduler getDefaultScheduler()
1461: throws SchedulerException {
1462: StdSchedulerFactory fact = new StdSchedulerFactory();
1463:
1464: return fact.getScheduler();
1465: }
1466:
1467: /**
1468: * <p>
1469: * Returns a handle to the Scheduler with the given name, if it exists (if
1470: * it has already been instantiated).
1471: * </p>
1472: */
1473: public Scheduler getScheduler(String schedName)
1474: throws SchedulerException {
1475: return SchedulerRepository.getInstance().lookup(schedName);
1476: }
1477:
1478: /**
1479: * <p>
1480: * Returns a handle to all known Schedulers (made by any
1481: * StdSchedulerFactory instance.).
1482: * </p>
1483: */
1484: public Collection getAllSchedulers() throws SchedulerException {
1485: return SchedulerRepository.getInstance().lookupAll();
1486: }
1487: }
|