/// <summary>
        /// Creates a new <see cref="IJob"/> instance from the given scheduled job configuration.
        /// If the created object extends from <see cref="ScheduledJob"/>, its <see cref="ScheduledJob.Metadata"/>
        /// collection will be filled with any metadata defined in the configuration.
        /// </summary>
        /// <param name="element">The configuration to create the job from.</param>
        /// <returns>The created job.</returns>
        /// <exception cref="ConfigurationErrorsException">The configuration does not identify a valid type or the type identified does not implement <see cref="IJob"/>.</exception>
        public static IJob CreateFromConfiguration(JobScheduledJobElement element)
        {
            IJob job = null;
            Type concreteType = Type.GetType(element.JobType, false);

            if (concreteType != null && typeof(IJob).IsAssignableFrom(concreteType))
            {
                try
                {
                    job = (IJob)Activator.CreateInstance(concreteType);
                    ScheduledJob sj = job as ScheduledJob;

                    if (sj != null)
                    {
                        sj.Metadata.FillWith(element.Metadata);
                    }
                }
                catch (ArgumentException)
                {
                }
                catch (NotSupportedException)
                {
                }
                catch (TargetInvocationException)
                {
                }
                catch (MethodAccessException)
                {
                }
                catch (MemberAccessException)
                {
                }
                catch (TypeLoadException)
                {
                }
            }

            if (job == null)
            {
                throw new ConfigurationErrorsException(String.Format(CultureInfo.InvariantCulture, "The type \"{0}\" could not be instantiated into an object implementing the BlueCollar.IJob interface.", element.JobType), element.ElementInformation.Source, element.ElementInformation.LineNumber);
            }

            return job;
        }
        /// <summary>
        /// Creates a new scheduled job record for storing in the <see cref="IJobStore"/>.
        /// </summary>
        /// <param name="scheduleElement">The configured schedule element to create the record for.</param>
        /// <param name="jobElement">The configured job element to create the record for.</param>
        /// <param name="now">The queue and start date to create the record for.</param>
        /// <returns>A new scheduled job record.</returns>
        public static JobRecord CreateRecord(JobScheduleElement scheduleElement, JobScheduledJobElement jobElement, DateTime now)
        {
            if (scheduleElement == null)
            {
                throw new ArgumentNullException("scheduleElement", "scheduleElement cannot be null.");
            }

            if (String.IsNullOrEmpty(scheduleElement.Name))
            {
                throw new ArgumentException("scheduleElement cannot have an empty Name.", "scheduleElement");
            }

            if (jobElement == null)
            {
                throw new ArgumentNullException("jobElement", "jobElement cannot be null.");
            }

            if (String.IsNullOrEmpty(jobElement.JobType))
            {
                throw new ArgumentException("jobElement cannot have an empty JobType.", "jobElement");
            }

            if (now.Kind != DateTimeKind.Utc)
            {
                throw new ArgumentException("now must be in UTC.", "now");
            }

            return new JobRecord()
            {
                Name = scheduleElement.Name,
                JobType = jobElement.JobType,
                QueueDate = now,
                ScheduleName = scheduleElement.Name,
                StartDate = now,
                Status = JobStatus.Started
            };
        }
        public void JobRunnerExecuteScheduledJobs()
        {
            JobScheduleElement sched1 = new JobScheduleElement()
            {
                Name = "___TEST_SCHED_1___" + Guid.NewGuid().ToString(),
                RepeatHours = 24,
                StartOn = DateTime.UtcNow.AddYears(-1).AddMilliseconds(Heartbeat)
            };

            JobScheduleElement sched2 = new JobScheduleElement()
            {
                Name = "___TEST_SCHED_2___" + Guid.NewGuid().ToString(),
                RepeatHours = .5,
                StartOn = DateTime.UtcNow.AddDays(-1).AddMilliseconds(Heartbeat)
            };

            JobScheduleElement sched3 = new JobScheduleElement()
            {
                Name = "___TEST_SCHED_3___" + Guid.NewGuid().ToString(),
                RepeatHours = .5,
                StartOn = DateTime.UtcNow.AddDays(1).AddMilliseconds(Heartbeat)
            };

            JobScheduledJobElement job1 = new JobScheduledJobElement()
            {
                JobType = JobRecord.JobTypeString(typeof(TestIdJob))
            };

            JobScheduledJobElement job2 = new JobScheduledJobElement()
            {
                JobType = JobRecord.JobTypeString(typeof(TestScheduledJob))
            };

            sched1.ScheduledJobs.Add(job1);
            sched1.ScheduledJobs.Add(job2);
            sched2.ScheduledJobs.Add(job2);
            sched3.ScheduledJobs.Add(job1);

            jobRunner.SetSchedules(new JobScheduleElement[] { sched1, sched2, sched3 });
            Thread.Sleep(Heartbeat * 2);

            Assert.AreEqual(2, jobStore.GetJobCount(null, null, sched1.Name));
            Assert.AreEqual(1, jobStore.GetJobCount(null, null, sched2.Name));
            Assert.AreEqual(0, jobStore.GetJobCount(null, null, sched3.Name));
        }