Example #1
0
	    /// <summary>
		/// Creates a scheduler using the specified thread pool and job store and
		/// binds it to RMI.
		/// </summary>
		/// <param name="schedulerName">The name for the scheduler.</param>
		/// <param name="schedulerInstanceId">The instance ID for the scheduler.</param>
		/// <param name="threadPool">The thread pool for executing jobs</param>
		/// <param name="jobStore">The type of job store</param>
		/// <param name="schedulerPluginMap"></param>
		/// <param name="idleWaitTime">The idle wait time. You can specify TimeSpan.Zero for
		/// the default value, which is currently 30000 ms.</param>
		/// <param name="dbFailureRetryInterval">The db failure retry interval.</param>
		public virtual void CreateScheduler(string schedulerName, string schedulerInstanceId, IThreadPool threadPool,
                                            IJobStore jobStore, IDictionary schedulerPluginMap, TimeSpan idleWaitTime,
		                                    TimeSpan dbFailureRetryInterval)
		{
			// Currently only one run-shell factory is available...
			IJobRunShellFactory jrsf = new StdJobRunShellFactory();

			// Fire everything up
			// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
			SchedulingContext schedCtxt = new SchedulingContext();
			schedCtxt.InstanceId = schedulerInstanceId;

			SchedulerSchedulerResources qrs = new SchedulerSchedulerResources();

			qrs.Name = schedulerName;
			qrs.InstanceId = schedulerInstanceId;
			qrs.JobRunShellFactory = jrsf;
			qrs.ThreadPool = threadPool;
			qrs.JobStore = jobStore;


            // add plugins
            if (schedulerPluginMap != null)
            {
                foreach (ISchedulerPlugin plugin in schedulerPluginMap.Values)
                {
                    qrs.AddSchedulerPlugin(plugin);
                }
            }

			SchedulerScheduler qs = new SchedulerScheduler(qrs, schedCtxt, idleWaitTime, dbFailureRetryInterval);

			ITypeLoadHelper cch = new CascadingClassLoadHelper();
			cch.Initialize();

			jobStore.Initialize(cch, qs.SchedulerSignaler);

			IScheduler scheduler = new StdScheduler(qs, schedCtxt);

            // Initialize plugins now that we have a Scheduler instance.
            if (schedulerPluginMap != null)
            {
                foreach (DictionaryEntry pluginEntry in schedulerPluginMap)
                {
                    ((ISchedulerPlugin)pluginEntry.Value).Initialize(
                            (string) pluginEntry.Key, scheduler);
                }
            }

			jrsf.Initialize(scheduler, schedCtxt);

			Log.Info(string.Format(CultureInfo.InvariantCulture, "Scheduler scheduler '{0}", scheduler.SchedulerName));

			Log.Info(string.Format(CultureInfo.InvariantCulture, "Scheduler scheduler version: {0}", qs.Version));

			SchedulerRepository schedRep = SchedulerRepository.Instance;

			qs.AddNoGCObject(schedRep); // prevents the repository from being
			// garbage collected

			schedRep.Bind(scheduler);
		}
Example #2
0
        /// <summary>
        /// Create a <see cref="SchedulerScheduler" /> with the given configuration
        /// properties.
        /// </summary>
        /// <seealso cref="SchedulerSchedulerResources" />
        public SchedulerScheduler(SchedulerSchedulerResources resources, SchedulingContext ctxt, TimeSpan idleWaitTime, TimeSpan dbRetryInterval)
        {
            Log = LogManager.GetLogger(GetType());
            this.resources = resources;
            try
            {
                Bind();
            }
            catch (Exception re)
            {
                throw new SchedulerException("Unable to bind scheduler to remoting context.", re);
            }

            schedThread = new SchedulerSchedulerThread(this, resources, ctxt);
            if (idleWaitTime > TimeSpan.Zero)
            {
                schedThread.IdleWaitTime = idleWaitTime;
            }
            if (dbRetryInterval > TimeSpan.Zero)
            {
                schedThread.DbFailureRetryInterval = dbRetryInterval;
            }

            jobMgr = new ExecutingJobsManager();
            AddGlobalJobListener(jobMgr);
            errLogger = new ErrorLogger();
            AddSchedulerListener(errLogger);

            signaler = new SchedulerSignalerImpl(this, this.schedThread);

            Log.Info(string.Format(CultureInfo.InvariantCulture, "Scheduler Scheduler v.{0} created.", Version));
        }
Example #3
0
        /// <summary>
        /// The main processing loop of the <see cref="SchedulerSchedulerThread" />.
        /// </summary>
        public override void Run()
        {
            bool lastAcquireFailed = false;

            while (!halted)
            {
                try
                {
                    // check if we're supposed to pause...
                    lock (sigLock)
                    {
                        while (paused && !halted)
                        {
                            try
                            {
                                // wait until togglePause(false) is called...
                                Monitor.Wait(sigLock, 1000);
                            }
                            catch (ThreadInterruptedException)
                            {
                            }
                        }

                        if (halted)
                        {
                            break;
                        }
                    }

                    int availTreadCount = qsRsrcs.ThreadPool.BlockForAvailableThreads();
                    if (availTreadCount > 0) // will always be true, due to semantics of blockForAvailableThreads...
                    {
                        Trigger trigger = null;

                        DateTime now = DateTime.UtcNow;

                        ClearSignaledSchedulingChange();
                        try
                        {
                            trigger = qsRsrcs.JobStore.AcquireNextTrigger(ctxt, now.Add(idleWaitTime));
                            lastAcquireFailed = false;
                        }
                        catch (JobPersistenceException jpe)
                        {
                            if (!lastAcquireFailed)
                            {
                                qs.NotifySchedulerListenersError(
                                    "An error occured while scanning for the next trigger to fire.",
                                    jpe);
                            }
                            lastAcquireFailed = true;
                        }
                        catch (Exception e)
                        {
                            if (!lastAcquireFailed)
                            {
                                Log.Error("SchedulerSchedulerThreadLoop: RuntimeException "
                                          + e.Message, e);
                            }
                            lastAcquireFailed = true;
                        }

                        if (trigger != null)
                        {
                            now = DateTime.UtcNow;
                            DateTime triggerTime = trigger.GetNextFireTimeUtc().Value;
                            TimeSpan timeUntilTrigger =  triggerTime - now;

                            while (timeUntilTrigger > TimeSpan.Zero) 
                            {
                                lock (sigLock)
                                {
                                    try
                                    {
                                        // we could have blocked a long while
                                        // on 'synchronize', so we must recompute
                                        now = DateTime.UtcNow;
                                        timeUntilTrigger = triggerTime - now;
                                        if (timeUntilTrigger.TotalMilliseconds >= 1)
                                        {
                                            Monitor.Wait(sigLock, timeUntilTrigger);
                                        }
                                    }
                                    catch (ThreadInterruptedException)
                                    {
                                    }
                                }
                                if (IsScheduleChanged())
                                {
                                    if (IsCandidateNewTimeEarlierWithinReason(triggerTime))
                                    {
                                        // above call does a clearSignaledSchedulingChange()
                                        try
                                        {
                                            qsRsrcs.JobStore.ReleaseAcquiredTrigger(ctxt, trigger);
                                        }
                                        catch (JobPersistenceException jpe)
                                        {
                                            qs.NotifySchedulerListenersError(
                                                "An error occured while releasing trigger '"
                                                + trigger.FullName + "'",
                                                jpe);
                                            // db connection must have failed... keep
                                            // retrying until it's up...
                                            ReleaseTriggerRetryLoop(trigger);
                                        }
                                        catch (Exception e)
                                        {
                                            Log.Error(
                                                "releaseTriggerRetryLoop: RuntimeException "
                                                + e.Message, e);
                                            // db connection must have failed... keep
                                            // retrying until it's up...
                                            ReleaseTriggerRetryLoop(trigger);
                                        }
                                        trigger = null;
                                        break;
                                    }
                                    
                                }
                                now = DateTime.UtcNow;
                                timeUntilTrigger = triggerTime - now;
                            }

                            if (trigger == null)
                            {
                                continue;
                            }
                                              
                            // set trigger to 'executing'
                            TriggerFiredBundle bndle = null;

                            bool goAhead = true;
                            lock (sigLock) 
                            {
                        	    goAhead = !halted;
                            }
                            if(goAhead) 
                            {
                                try
                                {
                                    bndle = qsRsrcs.JobStore.TriggerFired(ctxt,
                                                                          trigger);
                                }
                                catch (SchedulerException se)
                                {
                                    qs.NotifySchedulerListenersError(
                                        string.Format(CultureInfo.InvariantCulture,
                                                      "An error occured while firing trigger '{0}'",
                                                      trigger.FullName), se);
                                }
                                catch (Exception e)
                                {
                                    Log.Error(
                                        string.Format(CultureInfo.InvariantCulture,
                                                      "RuntimeException while firing trigger {0}", trigger.FullName),
                                        e);
                                    // db connection must have failed... keep
                                    // retrying until it's up...
                                    ReleaseTriggerRetryLoop(trigger);
                                }
                            }
                            
                            // it's possible to get 'null' if the trigger was paused,
                            // blocked, or other similar occurrences that prevent it being
                            // fired at this time...  or if the scheduler was shutdown (halted)
                            if (bndle == null)
                            {
                                try
                                {
                                    qsRsrcs.JobStore.ReleaseAcquiredTrigger(ctxt,
                                                                            trigger);
                                }
                                catch (SchedulerException se)
                                {
                                    qs.NotifySchedulerListenersError(
                                        string.Format(CultureInfo.InvariantCulture, "An error occured while releasing trigger '{0}'",
                                                      trigger.FullName), se);
                                    // db connection must have failed... keep retrying
                                    // until it's up...
                                    ReleaseTriggerRetryLoop(trigger);
                                }
                                continue;
                            }

                            // TODO: improvements:
                            //
                            // 2- make sure we can get a job runshell before firing trigger, or
                            //   don't let that throw an exception (right now it never does,
                            //   but the signature says it can).
                            // 3- acquire more triggers at a time (based on num threads available?)


                            JobRunShell shell;
                            try
                            {
                                shell = qsRsrcs.JobRunShellFactory.BorrowJobRunShell();
                                shell.Initialize(qs, bndle);
                            }
                            catch (SchedulerException)
                            {
                                try
                                {
                                    qsRsrcs.JobStore.TriggeredJobComplete(ctxt,
                                                                          trigger, bndle.JobDetail,
                                                                          SchedulerInstruction.
                                                                              SetAllJobTriggersError);
                                }
                                catch (SchedulerException se2)
                                {
                                    qs.NotifySchedulerListenersError(
                                        string.Format(
                                            CultureInfo.InvariantCulture,
                                            "An error occured while placing job's triggers in error state '{0}'",
                                            trigger.FullName), se2);
                                    // db connection must have failed... keep retrying
                                    // until it's up...
                                    ErrorTriggerRetryLoop(bndle);
                                }
                                continue;
                            }

                            if (qsRsrcs.ThreadPool.RunInThread(shell) == false)
                            {
                                try
                                {
                                    // this case should never happen, as it is indicative of the
                                    // scheduler being shutdown or a bug in the thread pool or
                                    // a thread pool being used concurrently - which the docs
                                    // say not to do...
                                    Log.Error("ThreadPool.runInThread() return false!");
                                    qsRsrcs.JobStore.TriggeredJobComplete(ctxt,
                                                                          trigger, bndle.JobDetail,
                                                                          SchedulerInstruction.
                                                                              SetAllJobTriggersError);
                                }
                                catch (SchedulerException se2)
                                {
                                    qs.NotifySchedulerListenersError(
                                        string.Format(CultureInfo.InvariantCulture,
                                            "An error occured while placing job's triggers in error state '{0}'",
                                            trigger.FullName), se2);
                                    // db connection must have failed... keep retrying
                                    // until it's up...
                                    ReleaseTriggerRetryLoop(trigger);
                                }
                            }

                            continue;
                        }
                    }
                    else
                    {
                        // if(availTreadCount > 0)
                        continue; // should never happen, if threadPool.blockForAvailableThreads() follows contract
                    }

                    DateTime utcNow = DateTime.UtcNow;
                    DateTime waitTime = utcNow.Add(GetRandomizedIdleWaitTime());
                    TimeSpan timeUntilContinue = waitTime - utcNow;
                    lock (sigLock) 
                    {
                	    try 
                        {
						    Monitor.Wait(sigLock, timeUntilContinue);
					    } 
                        catch (ThreadInterruptedException) 
                        {
					    }
                    }
                }
                catch (Exception re)
                {
                    if (Log != null)
                    {
                        Log.Error("Runtime error occured in main trigger firing loop.", re);
                    }
                }
            } // loop...

            // drop references to scheduler stuff to aid garbage collection...
            qs = null;
            qsRsrcs = null;
        }
Example #4
0
        /// <summary>
        /// Construct a new <see cref="SchedulerSchedulerThread" /> for the given
        /// <see cref="SchedulerScheduler" /> as a <see cref="Thread" /> with the given
        /// attributes.
        /// </summary>
        internal SchedulerSchedulerThread(SchedulerScheduler qs, SchedulerSchedulerResources qsRsrcs, SchedulingContext ctxt,
                                       bool setDaemon, int threadPrio) : base(qsRsrcs.ThreadName)
        {
            log = LogManager.GetLogger(GetType());
            //ThreadGroup generatedAux = qs.SchedulerThreadGroup;
            this.qs = qs;
            this.qsRsrcs = qsRsrcs;
            this.ctxt = ctxt;
            IsBackground = setDaemon;
            Priority = (ThreadPriority) threadPrio;

            // start the underlying thread, but put this object into the 'paused'
            // state
            // so processing doesn't start yet...
            paused = true;
            halted = false;
            Start();
        }
Example #5
0
 /// <summary>
 /// Construct a new <see cref="SchedulerSchedulerThread" /> for the given
 /// <see cref="SchedulerScheduler" /> as a non-daemon <see cref="Thread" />
 /// with normal priority.
 /// </summary>
 internal SchedulerSchedulerThread(SchedulerScheduler qs, SchedulerSchedulerResources qsRsrcs, SchedulingContext ctxt)
     : this(qs, qsRsrcs, ctxt, qsRsrcs.MakeSchedulerThreadDaemon, (int) ThreadPriority.Normal)
 {
 }
Example #6
0
        protected internal virtual IScheduler Instantiate(SchedulerSchedulerResources rsrcs, SchedulerScheduler qs)
        {
            SchedulingContext schedCtxt = new SchedulingContext();
            schedCtxt.InstanceId = rsrcs.InstanceId;

            IScheduler sched = new StdScheduler(qs, schedCtxt);
            return sched;
        }
Example #7
0
        /// <summary>  </summary>
        private IScheduler Instantiate()
        {
            if (cfg == null)
            {
                Initialize();
            }

            if (initException != null)
            {
                throw initException;
            }

            ISchedulerExporter exporter = null;
            IJobStore js;
            IThreadPool tp;
            SchedulerScheduler qs;
            SchedulingContext schedCtxt;
            DBConnectionManager dbMgr = null;
            string instanceIdGeneratorType = null;
            NameValueCollection tProps;
            bool autoId = false;
            TimeSpan idleWaitTime = TimeSpan.Zero;
            TimeSpan dbFailureRetry = TimeSpan.Zero;
            string typeLoadHelperType;
            string jobFactoryType;

            SchedulerRepository schedRep = SchedulerRepository.Instance;

            // Get Scheduler Properties
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            string schedName = cfg.GetStringProperty(PropertySchedulerInstanceName, "SchedulerScheduler");
            string threadName =
                cfg.GetStringProperty(PropertySchedulerThreadName, string.Format(CultureInfo.InvariantCulture, "{0}_SchedulerSchedulerThread", schedName));
            string schedInstId = cfg.GetStringProperty(PropertySchedulerInstanceId, DefaultInstanceId);

            if (schedInstId.Equals(AutoGenerateInstanceId))
            {
                autoId = true;
                instanceIdGeneratorType =
                    cfg.GetStringProperty(PropertySchedulerInstanceIdGeneratorType,
                                          "Scheduler.Simpl.SimpleInstanceIdGenerator, Scheduler");
            }


            typeLoadHelperType =
                cfg.GetStringProperty(PropertySchedulerTypeLoadHelperType,
                                      "Scheduler.Simpl.CascadingClassLoadHelper, Scheduler");
            jobFactoryType = cfg.GetStringProperty(PropertySchedulerJobFactoryType, null);

            idleWaitTime = cfg.GetTimeSpanProperty(PropertySchedulerIdleWaitTime, idleWaitTime);
            dbFailureRetry = cfg.GetTimeSpanProperty(PropertySchedulerDbFailureRetryInterval, dbFailureRetry);
            bool makeSchedulerThreadDaemon = cfg.GetBooleanProperty(PropertySchedulerMakeSchedulerThreadDaemon);

            NameValueCollection schedCtxtProps = cfg.GetPropertyGroup(PropertySchedulerContextPrefix, true);

            bool proxyScheduler = cfg.GetBooleanProperty(PropertySchedulerProxy, false);
            // If Proxying to remote scheduler, short-circuit here...
            // ~~~~~~~~~~~~~~~~~~
            if (proxyScheduler)
            {
                if (autoId)
                {
                    schedInstId = DefaultInstanceId;
                }

                schedCtxt = new SchedulingContext();
                schedCtxt.InstanceId = schedInstId;

                string uid = SchedulerSchedulerResources.GetUniqueIdentifier(schedName, schedInstId);

                RemoteScheduler remoteScheduler = new RemoteScheduler(schedCtxt, uid);
                string remoteSchedulerAddress = cfg.GetStringProperty(PropertySchedulerProxyAddress);
                remoteScheduler.RemoteSchedulerAddress = remoteSchedulerAddress;
                schedRep.Bind(remoteScheduler);

                return remoteScheduler;
            }

            // Create type load helper
            ITypeLoadHelper loadHelper;
            try
            {
                loadHelper = (ITypeLoadHelper)ObjectUtils.InstantiateType(LoadType(typeLoadHelperType));
            }
            catch (Exception e)
            {
                throw new SchedulerConfigException(
                    string.Format(CultureInfo.InvariantCulture, "Unable to instantiate type load helper: {0}", e.Message), e);
            }
            loadHelper.Initialize();

            IJobFactory jobFactory = null;
            if (jobFactoryType != null)
            {
                try
                {
                    jobFactory = (IJobFactory) ObjectUtils.InstantiateType(loadHelper.LoadType(jobFactoryType));
                }
                catch (Exception e)
                {
                    throw new SchedulerConfigException(
                        string.Format(CultureInfo.InvariantCulture, "Unable to Instantiate JobFactory: {0}", e.Message), e);
                }

                tProps = cfg.GetPropertyGroup(PropertySchedulerJobFactoryPrefix, true);
                try
                {
                    ObjectUtils.SetObjectProperties(jobFactory, tProps);
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "JobFactory of type '{0}' props could not be configured.", jobFactoryType), e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }
            }

            IInstanceIdGenerator instanceIdGenerator = null;
            if (instanceIdGeneratorType != null)
            {
                try
                {
                    instanceIdGenerator =
                        (IInstanceIdGenerator)
                        ObjectUtils.InstantiateType(loadHelper.LoadType(instanceIdGeneratorType));
                }
                catch (Exception e)
                {
                    throw new SchedulerConfigException(
                        string.Format(CultureInfo.InvariantCulture, "Unable to Instantiate InstanceIdGenerator: {0}", e.Message), e);
                }
                tProps = cfg.GetPropertyGroup(PropertySchedulerInstanceIdGeneratorPrefix, true);
                try
                {
                    ObjectUtils.SetObjectProperties(instanceIdGenerator, tProps);
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "InstanceIdGenerator of type '{0}' props could not be configured.",
                                          instanceIdGeneratorType), e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }
            }

            // Get ThreadPool Properties
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            string tpType = cfg.GetStringProperty(PropertyThreadPoolType, typeof(SimpleThreadPool).AssemblyQualifiedName);

            if (tpType == null)
            {
                initException =
                    new SchedulerException("ThreadPool type not specified. ", SchedulerException.ErrorBadConfiguration);
                throw initException;
            }

            try
            {
                tp = (IThreadPool) ObjectUtils.InstantiateType(loadHelper.LoadType(tpType));
            }
            catch (Exception e)
            {
                initException =
                    new SchedulerException(string.Format(CultureInfo.InvariantCulture, "ThreadPool type '{0}' could not be instantiated.", tpType),
                                           e);
                initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                throw initException;
            }
            tProps = cfg.GetPropertyGroup(PropertyThreadPoolPrefix, true);
            try
            {
                ObjectUtils.SetObjectProperties(tp, tProps);
            }
            catch (Exception e)
            {
                initException =
                    new SchedulerException(
                        string.Format(CultureInfo.InvariantCulture, "ThreadPool type '{0}' props could not be configured.", tpType), e);
                initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                throw initException;
            }

                        // Set up any DataSources
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            string[] dsNames = cfg.GetPropertyGroups(PropertyDataSourcePrefix);
            for (int i = 0; i < dsNames.Length; i++)
            {
                PropertiesParser pp =
                    new PropertiesParser(
                        cfg.GetPropertyGroup(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", PropertyDataSourcePrefix, dsNames[i]), true));

                string cpType = pp.GetStringProperty(PropertyDbProviderType, null);

                // custom connectionProvider...
                if (cpType != null)
                {
                    IDbProvider cp;
                    try
                    {
                        cp = (IDbProvider) ObjectUtils.InstantiateType(loadHelper.LoadType(cpType));
                    }
                    catch (Exception e)
                    {
                        initException =
                            new SchedulerException(
                                string.Format(CultureInfo.InvariantCulture, "ConnectionProvider of type '{0}' could not be instantiated.", cpType), e);
                        initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                        throw initException;
                    }

                    try
                    {
                        // remove the type name, so it isn't attempted to be set
                        pp.UnderlyingProperties.Remove(PropertyDbProviderType);

                        ObjectUtils.SetObjectProperties(cp, pp.UnderlyingProperties);
                    }
                    catch (Exception e)
                    {
                        initException =
                            new SchedulerException(
                                string.Format(CultureInfo.InvariantCulture, "ConnectionProvider type '{0}' props could not be configured.", cpType),
                                e);
                        initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                        throw initException;
                    }

                    dbMgr = DBConnectionManager.Instance;
                    dbMgr.AddConnectionProvider(dsNames[i], cp);
                }
                else
                {
                    string dsProvider = pp.GetStringProperty(PropertyDataSourceProvider, null);
                    string dsConnectionString = pp.GetStringProperty(PropertyDataSourceConnectionString, null);
                    string dsConnectionStringName = pp.GetStringProperty(PropertyDataSourceConnectionStringName, null);

                    if (dsConnectionString == null && dsConnectionStringName != null && dsConnectionStringName.Length > 0)
                    {
#if NET_20
                        ConnectionStringSettings connectionStringSettings = ConfigurationManager.ConnectionStrings[dsConnectionStringName];
                        if (connectionStringSettings == null)
                        {
                            initException =
                                new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Named connection string '{0}' not found for DataSource: {1}", dsConnectionStringName,  dsNames[i]));
                            throw initException;
                        }
                        dsConnectionString = connectionStringSettings.ConnectionString;
#endif
                    }

                    if (dsProvider == null)
                    {
                        initException =
                            new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Provider not specified for DataSource: {0}", dsNames[i]));
                        throw initException;
                    }
                    if (dsConnectionString == null)
                    {
                        initException =
                            new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Connection string not specified for DataSource: {0}", dsNames[i]));
                        throw initException;
                    }
                    try
                    {
                        DbProvider dbp = new DbProvider(dsProvider, dsConnectionString);
						
                        dbMgr = DBConnectionManager.Instance;
                        dbMgr.AddConnectionProvider(dsNames[i], dbp);
                    }
                    catch (Exception exception)
                    {
                        initException =
                            new SchedulerException(string.Format(CultureInfo.InvariantCulture, "Could not Initialize DataSource: {0}", dsNames[i]),
                                                   exception);
                        throw initException;
                    }
                }
            }

            // Get JobStore Properties
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            string jsType = cfg.GetStringProperty(PropertyJobStoreType, typeof (RAMJobStore).FullName);

            if (jsType == null)
            {
                initException =
                    new SchedulerException("JobStore type not specified. ", SchedulerException.ErrorBadConfiguration);
                throw initException;
            }

            try
            {
                js = (IJobStore) ObjectUtils.InstantiateType(loadHelper.LoadType(jsType));
            }
            catch (Exception e)
            {
                initException =
                    new SchedulerException(string.Format(CultureInfo.InvariantCulture, "JobStore of type '{0}' could not be instantiated.", jsType), e);
                initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                throw initException;
            }
            
            tProps =
                cfg.GetPropertyGroup(PropertyJobStorePrefix, true, new string[] {PropertyJobStoreLockHandlerPrefix});
            
            try
            {
                ObjectUtils.SetObjectProperties(js, tProps);
            }
            catch (Exception e)
            {
                initException =
                    new SchedulerException(
                        string.Format(CultureInfo.InvariantCulture, "JobStore type '{0}' props could not be configured.", jsType), e);
                initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                throw initException;
            }


            if (js is JobStoreSupport)
            {
                ((JobStoreSupport) js).InstanceId = schedInstId;
                ((JobStoreSupport) js).InstanceName = schedName;

                // Install custom lock handler (Semaphore)
                string lockHandlerTypeName = cfg.GetStringProperty(PropertyJobStoreLockHandlerType);
                if (lockHandlerTypeName != null)
                {
                    try
                    {
                        Type lockHandlerType = loadHelper.LoadType(lockHandlerTypeName);
                        ISemaphore lockHandler;
                        ConstructorInfo cWithDbProvider =
                            lockHandlerType.GetConstructor(new Type[] {typeof (DbProvider)});

                        if (cWithDbProvider != null)
                        {
                            // takes db provider
                            IDbProvider dbProvider = DBConnectionManager.Instance.GetDbProvider(((JobStoreSupport) js).DataSource);
                            lockHandler = (ISemaphore) cWithDbProvider.Invoke(new object[] { dbProvider });
                        }
                        else
                        {
                            lockHandler = (ISemaphore)ObjectUtils.InstantiateType(lockHandlerType);
                        }

                        tProps = cfg.GetPropertyGroup(PropertyJobStoreLockHandlerPrefix, true);

                        // If this lock handler requires the table prefix, add it to its properties.
                        if (lockHandler is ITablePrefixAware)
                        {
                            tProps[PropertyTablePrefix] = ((JobStoreSupport) js).TablePrefix;
                        }

                        try
                        {
                            ObjectUtils.SetObjectProperties(lockHandler, tProps);
                        }
                        catch (Exception e)
                        {
                            initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "JobStore LockHandler type '{0}' props could not be configured.", lockHandlerTypeName), e);
                            initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                            throw initException;
                        }

                        ((JobStoreSupport) js).LockHandler = lockHandler;
                        Log.Info("Using custom data access locking (synchronization): " + lockHandlerType);
                    }
                    catch (Exception e)
                    {
                        initException = new SchedulerException(string.Format(CultureInfo.InvariantCulture, "JobStore LockHandler type '{0}' could not be instantiated.", lockHandlerTypeName), e);
                        initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                        throw initException;
                    }
                }
            }

            // Set up any SchedulerPlugins
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            string[] pluginNames = cfg.GetPropertyGroups(PropertyPluginPrefix);
            ISchedulerPlugin[] plugins = new ISchedulerPlugin[pluginNames.Length];
            for (int i = 0; i < pluginNames.Length; i++)
            {
                NameValueCollection pp =
                    cfg.GetPropertyGroup(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", PropertyPluginPrefix, pluginNames[i]), true);

                string plugInType = pp[PropertyPluginType] == null ? null : pp[PropertyPluginType];

                if (plugInType == null)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "SchedulerPlugin type not specified for plugin '{0}'", pluginNames[i]),
                            SchedulerException.ErrorBadConfiguration);
                    throw initException;
                }
                ISchedulerPlugin plugin;
                try
                {
                    plugin = (ISchedulerPlugin) ObjectUtils.InstantiateType(LoadType(plugInType));
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "SchedulerPlugin of type '{0}' could not be instantiated.", plugInType), e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }
                try
                {
                    ObjectUtils.SetObjectProperties(plugin, pp);
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "JobStore SchedulerPlugin '{0}' props could not be configured.", plugInType),
                            e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }
                plugins[i] = plugin;
            }

            // Set up any JobListeners
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            Type[] strArg = new Type[] {typeof (string)};
            string[] jobListenerNames = cfg.GetPropertyGroups(PropertyJobListenerPrefix);
            IJobListener[] jobListeners = new IJobListener[jobListenerNames.Length];
            for (int i = 0; i < jobListenerNames.Length; i++)
            {
                NameValueCollection lp =
                    cfg.GetPropertyGroup(string.Format(CultureInfo.InvariantCulture, "{0}.{1}", PropertyJobListenerPrefix, jobListenerNames[i]), true);

                string listenerType = lp[PropertyListenerType] == null ? null : lp[PropertyListenerType];

                if (listenerType == null)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "JobListener type not specified for listener '{0}'", jobListenerNames[i]),
                            SchedulerException.ErrorBadConfiguration);
                    throw initException;
                }
                IJobListener listener;
                try
                {
                    listener = (IJobListener) ObjectUtils.InstantiateType(loadHelper.LoadType(listenerType));
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "JobListener of type '{0}' could not be instantiated.", listenerType), e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }
                try
                {
                    MethodInfo nameSetter =
                        listener.GetType().GetMethod("setName", (strArg == null) ? new Type[0] : strArg);
                    if (nameSetter != null)
                    {
                        nameSetter.Invoke(listener, new object[] {jobListenerNames[i]});
                    }
                    ObjectUtils.SetObjectProperties(listener, lp);
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "JobListener '{0}' props could not be configured.", listenerType), e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }
                jobListeners[i] = listener;
            }

            // Set up any TriggerListeners
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            string[] triggerListenerNames = cfg.GetPropertyGroups(PropertyTriggerListenerPrefix);
            ITriggerListener[] triggerListeners = new ITriggerListener[triggerListenerNames.Length];
            for (int i = 0; i < triggerListenerNames.Length; i++)
            {
                NameValueCollection lp =
                    cfg.GetPropertyGroup(
                        string.Format(CultureInfo.InvariantCulture, "{0}.{1}", PropertyTriggerListenerPrefix, triggerListenerNames[i]), true);

                string listenerType = lp[PropertyListenerType] == null ? null : lp[PropertyListenerType];

                if (listenerType == null)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "TriggerListener type not specified for listener '{0}'",
                                          triggerListenerNames[i]),
                            SchedulerException.ErrorBadConfiguration);
                    throw initException;
                }
                ITriggerListener listener;
                try
                {
                    listener = (ITriggerListener) ObjectUtils.InstantiateType(loadHelper.LoadType(listenerType));
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "TriggerListener of type '{0}' could not be instantiated.", listenerType), e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }
                try
                {
                    MethodInfo nameSetter =
                        listener.GetType().GetMethod("setName", (strArg == null) ? new Type[0] : strArg);
                    if (nameSetter != null)
                    {
                        nameSetter.Invoke(listener, (new object[] {triggerListenerNames[i]}));
                    }
                    ObjectUtils.SetObjectProperties(listener, lp);
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "TriggerListener '{0}' props could not be configured.", listenerType), e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }
                triggerListeners[i] = listener;
            }

            // Get exporter
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            string exporterType = cfg.GetStringProperty(PropertySchedulerExporterType, null);

            if (exporterType != null)
            {
                try
                {
                    exporter = (ISchedulerExporter)ObjectUtils.InstantiateType(loadHelper.LoadType(exporterType));
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "Scheduler exporter of type '{0}' could not be instantiated.", exporterType), e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }

                tProps = cfg.GetPropertyGroup(PropertySchedulerExporterPrefix, true);

                try
                {
                    ObjectUtils.SetObjectProperties(exporter, tProps);
                }
                catch (Exception e)
                {
                    initException =
                        new SchedulerException(
                            string.Format(CultureInfo.InvariantCulture, "Scheduler exporter type '{0}' props could not be configured.", exporterType), e);
                    initException.ErrorCode = SchedulerException.ErrorBadConfiguration;
                    throw initException;
                }
            }

            // Fire everything up
            // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

            IJobRunShellFactory jrsf = new StdJobRunShellFactory();
            
            if (autoId)
            {
                try
                {
                    schedInstId = DefaultInstanceId;
                    
                    if (js is JobStoreSupport)
					{
						if (((JobStoreSupport) js).Clustered)
						{
							schedInstId = instanceIdGenerator.GenerateInstanceId();
						}
					}
                   
                }
                catch (Exception e)
                {
                    Log.Error("Couldn't generate instance Id!", e);
                    throw new SystemException("Cannot run without an instance id.");
                }
            }

            
			if (js is JobStoreSupport)
			{
				JobStoreSupport jjs = (JobStoreSupport) js;
				jjs.InstanceId = schedInstId;
                jjs.DbRetryInterval = dbFailureRetry;
			}

            SchedulerSchedulerResources rsrcs = new SchedulerSchedulerResources();
            rsrcs.Name = schedName;
            rsrcs.ThreadName = threadName;
            rsrcs.InstanceId = schedInstId;
            rsrcs.JobRunShellFactory = jrsf;
            rsrcs.MakeSchedulerThreadDaemon = makeSchedulerThreadDaemon;
            rsrcs.ThreadPool = tp;
            rsrcs.SchedulerExporter = exporter;

            if (tp is SimpleThreadPool)
            {
                ((SimpleThreadPool) tp).ThreadNamePrefix = schedName + "_Worker";
            }
            tp.Initialize();

            rsrcs.JobStore = js;

            // add plugins
            for (int i = 0; i < plugins.Length; i++)
            {
                rsrcs.AddSchedulerPlugin(plugins[i]);
            }

            schedCtxt = new SchedulingContext();
            schedCtxt.InstanceId = rsrcs.InstanceId;

            qs = new SchedulerScheduler(rsrcs, schedCtxt, idleWaitTime, dbFailureRetry);

            // Create Scheduler ref...
            IScheduler sched = Instantiate(rsrcs, qs);

            // set job factory if specified
            if (jobFactory != null)
            {
                qs.JobFactory = jobFactory;
            }

            // Initialize plugins now that we have a Scheduler instance.
            for (int i = 0; i < plugins.Length; i++)
            {
                plugins[i].Initialize(pluginNames[i], sched);
            }

            // add listeners
            for (int i = 0; i < jobListeners.Length; i++)
            {
                qs.AddGlobalJobListener(jobListeners[i]);
            }
            for (int i = 0; i < triggerListeners.Length; i++)
            {
                qs.AddGlobalTriggerListener(triggerListeners[i]);
            }

            // set scheduler context data...
            IEnumerator itr = new HashSet(schedCtxtProps).GetEnumerator();
            while (itr.MoveNext())
            {
                string key = (String) itr.Current;
                string val = schedCtxtProps.Get(key);

                sched.Context.Put(key, val);
            }

            // fire up job store, and runshell factory

            js.Initialize(loadHelper, qs.SchedulerSignaler);

            jrsf.Initialize(sched, schedCtxt);

            Log.Info(string.Format(CultureInfo.InvariantCulture, "Scheduler scheduler '{0}' initialized", sched.SchedulerName));

            Log.Info(string.Format(CultureInfo.InvariantCulture, "Scheduler scheduler version: {0}", qs.Version));

            // prevents the repository from being garbage collected
            qs.AddNoGCObject(schedRep);
            // prevents the db manager from being garbage collected
            if (dbMgr != null)
            {
                qs.AddNoGCObject(dbMgr);
            }

            schedRep.Bind(sched);

            return sched;
        }