/// Default thread count to be set to thread pool.
@@ -126,45 +121,28 @@ namespace Spring.Scheduling.Quartz
get { return configTimeTaskExecutor; }
}
-
- ///
- /// Logger for this instance and its sub-class instances.
- ///
- protected ILog logger;
-
private IApplicationContext applicationContext;
private string applicationContextSchedulerContextKey;
private bool autoStartup = true;
- private IDictionary calendars;
private IResource configLocation;
- private IJobListener[] globalJobListeners;
- private ITriggerListener[] globalTriggerListeners;
- private ArrayList jobDetails;
private IJobFactory jobFactory;
private bool jobFactorySet;
- private IJobListener[] jobListeners;
- private string[] jobSchedulingDataLocations;
- private bool overwriteExistingJobs;
private IDictionary quartzProperties;
private IScheduler scheduler;
private IDictionary schedulerContextMap;
private Type schedulerFactoryType;
- private ISchedulerListener[] schedulerListeners;
private string schedulerName;
private TimeSpan startupDelay = TimeSpan.Zero;
private ITaskExecutor taskExecutor;
- private ITriggerListener[] triggerListeners;
- private ArrayList triggers;
+ private bool exposeSchedulerInRepository;
private bool waitForJobsToCompleteOnShutdown;
private IDbProvider dbProvider;
- private IPlatformTransactionManager transactionManager;
///
/// Initializes a new instance of the class.
///
public SchedulerFactoryObject()
{
- logger = LogManager.GetLogger(GetType());
schedulerFactoryType = typeof (StdSchedulerFactory);
}
@@ -325,149 +303,16 @@ namespace Spring.Scheduling.Quartz
}
}
- ///
- /// Set whether any jobs defined on this SchedulerFactoryObject should overwrite
- /// existing job definitions. Default is "false", to not overwrite already
- /// registered jobs that have been read in from a persistent job store.
- ///
- public virtual bool OverwriteExistingJobs
+ /// Set whether to expose the Spring-managed {@link Scheduler} instance in the
+ /// Quartz {@link SchedulerRepository}. Default is "false", since the Spring-managed
+ /// Scheduler is usually exclusively intended for access within the Spring context.
+ /// Switch this flag to "true" in order to expose the Scheduler globally.
+ /// This is not recommended unless you have an existing Spring application that
+ /// relies on this behavior. Note that such global exposure was the accidental
+ /// default in earlier Spring versions; this has been fixed as of Spring 2.5.6.
+ public virtual bool ExposeSchedulerInRepository
{
- set { overwriteExistingJobs = value; }
- }
-
- ///
- /// Set the location of a Quartz job definition XML file that follows the
- /// "job_scheduling_data" XSD. Can be specified to automatically
- /// register jobs that are defined in such a file, possibly in addition
- /// to jobs defined directly on this SchedulerFactoryObject.
- ///
- ///
- ///
- public virtual string JobSchedulingDataLocation
- {
- set { jobSchedulingDataLocations = new string[] {value}; }
- }
-
- ///
- /// Set the locations of Quartz job definition XML files that follow the
- /// "job_scheduling_data" XSD. Can be specified to automatically
- /// register jobs that are defined in such files, possibly in addition
- /// to jobs defined directly on this SchedulerFactoryObject.
- ///
- /// The job scheduling data locations.
- ///
- ///
- public virtual string[] JobSchedulingDataLocations
- {
- set { jobSchedulingDataLocations = value; }
- }
-
- ///
- /// Register a list of JobDetail objects with the Scheduler that
- /// this FactoryObject creates, to be referenced by Triggers.
- /// This is not necessary when a Trigger determines the JobDetail
- /// itself: In this case, the JobDetail will be implicitly registered
- /// in combination with the Trigger.
- ///
- ///
- ///
- ///
- ///
- ///
- public virtual JobDetail[] JobDetails
- {
- set
- {
- // Use modifiable ArrayList here, to allow for further adding of
- // JobDetail objects during autodetection of JobDetailAwareTriggers.
- jobDetails = new ArrayList(value);
- }
- }
-
- ///
- /// Register a list of Quartz ICalendar objects with the Scheduler
- /// that this FactoryObject creates, to be referenced by Triggers.
- ///
- /// The calendars.
- ///
- ///
- public virtual IDictionary Calendars
- {
- set { calendars = value; }
- }
-
- ///
- /// Register a list of Trigger objects with the Scheduler that
- /// this FactoryObject creates.
- ///
- /// If the Trigger determines the corresponding JobDetail itself,
- /// the job will be automatically registered with the Scheduler.
- /// Else, the respective JobDetail needs to be registered via the
- /// "jobDetails" property of this FactoryObject.
- ///
- ///
- ///
- ///
- ///
- ///
- public virtual Trigger[] Triggers
- {
- set { triggers = new ArrayList(value); }
- }
-
- ///
- /// Specify Quartz SchedulerListeners to be registered with the Scheduler.
- ///
- public virtual ISchedulerListener[] SchedulerListeners
- {
- set { schedulerListeners = value; }
- }
-
- ///
- /// Specify global Quartz JobListeners to be registered with the Scheduler.
- /// Such JobListeners will apply to all Jobs in the Scheduler.
- ///
- public virtual IJobListener[] GlobalJobListeners
- {
- set { globalJobListeners = value; }
- }
-
- ///
- /// Specify named Quartz JobListeners to be registered with the Scheduler.
- /// Such JobListeners will only apply to Jobs that explicitly activate
- /// them via their name.
- ///
- /// The job listeners.
- ///
- ///
- ///
- public virtual IJobListener[] JobListeners
- {
- set { jobListeners = value; }
- }
-
- ///
- /// Specify global Quartz TriggerListeners to be registered with the Scheduler.
- /// Such TriggerListeners will apply to all Triggers in the Scheduler.
- ///
- /// The global trigger listeners.
- public virtual ITriggerListener[] GlobalTriggerListeners
- {
- set { globalTriggerListeners = value; }
- }
-
- ///
- /// Specify named Quartz TriggerListeners to be registered with the Scheduler.
- /// Such TriggerListeners will only apply to Triggers that explicitly activate
- /// them via their name.
- ///
- ///
- ///
- ///
- ///
- public virtual ITriggerListener[] TriggerListeners
- {
- set { triggerListeners = value; }
+ set { exposeSchedulerInRepository = value; }
}
///
@@ -524,7 +369,6 @@ namespace Spring.Scheduling.Quartz
///
///
///
- ///
///
public IDbProvider DbProvider
{
@@ -532,15 +376,27 @@ namespace Spring.Scheduling.Quartz
}
///
- /// Set the transaction manager to be used for registering jobs and triggers
- /// that are defined by this SchedulerFactoryObject. Default is none; setting
- /// this only makes sense when specifying a DataSource for the Scheduler.
+ /// Set the name of the object in the object factory that created this object.
///
- ///
- public IPlatformTransactionManager TransactionManager
- {
- set { transactionManager = value; }
- }
+ /// The name of the object in the factory.
+ ///
+ ///
+ /// Invoked after population of normal object properties but before an init
+ /// callback like 's
+ ///
+ /// method or a custom init-method.
+ ///
+ ///
+ public string ObjectName
+ {
+ set
+ {
+ if (schedulerName == null)
+ {
+ schedulerName = value;
+ }
+ }
+ }
///
/// Gets a value indicating whether this is running.
@@ -615,6 +471,16 @@ namespace Spring.Scheduling.Quartz
#endregion
+ ///
+ /// Template method that determines the Scheduler to operate on.
+ /// To be implemented by subclasses.
+ ///
+ ///
+ protected override IScheduler GetScheduler()
+ {
+ return scheduler;
+ }
+
#region IFactoryObject Members
///
@@ -633,7 +499,7 @@ namespace Spring.Scheduling.Quartz
/// probably fatal) exception.
///
///
- public object GetObject()
+ public virtual object GetObject()
{
return scheduler;
}
@@ -720,7 +586,7 @@ namespace Spring.Scheduling.Quartz
if (!jobFactorySet && !(scheduler is RemoteScheduler))
{
// Use AdaptableJobFactory as default for a local Scheduler, unless when
- // explicitly given a null value through the "jobFactory" bean property.
+ // explicitly given a null value through the "jobFactory" object property.
jobFactory = new AdaptableJobFactory();
}
@@ -763,70 +629,72 @@ namespace Spring.Scheduling.Quartz
/// the SchedulerFactory to Initialize
private void InitSchedulerFactory(ISchedulerFactory schedulerFactory)
{
- if (configLocation != null || quartzProperties != null || schedulerName != null ||
- taskExecutor != null || dbProvider != null)
+ if (!(schedulerFactory is StdSchedulerFactory))
{
- if (!(schedulerFactory is StdSchedulerFactory))
+ if (configLocation != null || quartzProperties != null || schedulerName != null ||
+ taskExecutor != null || dbProvider != null)
{
- throw new ArgumentException("StdSchedulerFactory required for applying Quartz properties");
+
+ throw new ArgumentException("StdSchedulerFactory required for applying Quartz properties: " + schedulerFactory);
}
-
- NameValueCollection mergedProps = new NameValueCollection();
-
- // Set necessary default properties here, as Quartz will not apply
- // its default configuration when explicitly given properties.
- if (taskExecutor != null)
- {
- mergedProps[StdSchedulerFactory.PropertyThreadPoolType] =
- typeof (LocalTaskExecutorThreadPool).AssemblyQualifiedName;
- }
- else
- {
- mergedProps.Set(StdSchedulerFactory.PropertyThreadPoolType, typeof(SimpleThreadPool).Name);
- mergedProps[PROP_THREAD_COUNT] = Convert.ToString(DEFAULT_THREAD_COUNT);
- }
-
- if (configLocation != null)
- {
- if (logger.IsInfoEnabled)
- {
- logger.Info("Loading Quartz config from [" + configLocation + "]");
- }
- using (StreamReader sr = new StreamReader(configLocation.InputStream))
- {
- string line;
- while ((line = sr.ReadLine()) != null)
- {
- string[] lineItems = line.Split(new char[] { '=' }, 2);
- if (lineItems.Length == 2)
- {
- mergedProps[lineItems[0].Trim()] = lineItems[1].Trim();
- }
- }
- }
-
- }
-
- if (quartzProperties != null)
- {
- // if given quartz properties, merge to them to configuration
- MergePropertiesIntoMap(quartzProperties, mergedProps);
- }
-
- if (dbProvider != null)
- {
- mergedProps.Add(StdSchedulerFactory.PropertyJobStoreType, typeof(LocalDataSourceJobStore).AssemblyQualifiedName);
- }
-
-
- // Make sure to set the scheduler name as configured in the Spring configuration.
- if (schedulerName != null)
- {
- mergedProps.Add(StdSchedulerFactory.PropertySchedulerInstanceName, schedulerName);
- }
-
- ((StdSchedulerFactory) schedulerFactory).Initialize(mergedProps);
+ // Otherwise assume that no initialization is necessary...
+ return;
}
+ NameValueCollection mergedProps = new NameValueCollection();
+
+ // Set necessary default properties here, as Quartz will not apply
+ // its default configuration when explicitly given properties.
+ if (taskExecutor != null)
+ {
+ mergedProps[StdSchedulerFactory.PropertyThreadPoolType] =
+ typeof (LocalTaskExecutorThreadPool).AssemblyQualifiedName;
+ }
+ else
+ {
+ mergedProps.Set(StdSchedulerFactory.PropertyThreadPoolType, typeof(SimpleThreadPool).AssemblyQualifiedName);
+ mergedProps[PROP_THREAD_COUNT] = Convert.ToString(DEFAULT_THREAD_COUNT);
+ }
+
+ if (configLocation != null)
+ {
+ if (logger.IsInfoEnabled)
+ {
+ logger.Info("Loading Quartz config from [" + configLocation + "]");
+ }
+ using (StreamReader sr = new StreamReader(configLocation.InputStream))
+ {
+ string line;
+ while ((line = sr.ReadLine()) != null)
+ {
+ string[] lineItems = line.Split(new char[] { '=' }, 2);
+ if (lineItems.Length == 2)
+ {
+ mergedProps[lineItems[0].Trim()] = lineItems[1].Trim();
+ }
+ }
+ }
+
+ }
+
+ if (quartzProperties != null)
+ {
+ // if given quartz properties, merge to them to configuration
+ MergePropertiesIntoMap(quartzProperties, mergedProps);
+ }
+
+ if (dbProvider != null)
+ {
+ mergedProps.Add(StdSchedulerFactory.PropertyJobStoreType, typeof(LocalDataSourceJobStore).AssemblyQualifiedName);
+ }
+
+
+ // Make sure to set the scheduler name as configured in the Spring configuration.
+ if (schedulerName != null)
+ {
+ mergedProps.Add(StdSchedulerFactory.PropertySchedulerInstanceName, schedulerName);
+ }
+
+ ((StdSchedulerFactory) schedulerFactory).Initialize(mergedProps);
}
///
@@ -859,10 +727,24 @@ namespace Spring.Scheduling.Quartz
///
protected virtual IScheduler CreateScheduler(ISchedulerFactory schedulerFactory, string schedName)
{
- // StdSchedulerFactory's default "getScheduler" implementation
- // uses the scheduler name specified in the Quartz properties,
- // which we have set before (in "InitSchedulerFactory").
- return schedulerFactory.GetScheduler();
+ SchedulerRepository repository = SchedulerRepository.Instance;
+ lock (repository)
+ {
+ IScheduler existingScheduler = (schedulerName != null ? repository.Lookup(schedulerName) : null);
+ IScheduler newScheduler = schedulerFactory.GetScheduler();
+ if (newScheduler == existingScheduler) {
+ throw new InvalidOperationException(
+ string.Format(
+ "Active Scheduler of name '{0}' already registered in Quartz SchedulerRepository. Cannot create a new Spring-managed Scheduler of the same name!",
+ schedulerName));
+ }
+ if (!exposeSchedulerInRepository) {
+ // Need to explicitly remove it if not intended for exposure,
+ // since Quartz shares the Scheduler instance by default!
+ SchedulerRepository.Instance.Remove(newScheduler.SchedulerName);
+ }
+ return newScheduler;
+ }
}
///
@@ -890,212 +772,6 @@ namespace Spring.Scheduling.Quartz
}
- ///
- /// Register all specified listeners with the Scheduler.
- ///
- private void RegisterListeners()
- {
- if (schedulerListeners != null)
- {
- for (int i = 0; i < schedulerListeners.Length; i++)
- {
- scheduler.AddSchedulerListener(schedulerListeners[i]);
- }
- }
- if (globalJobListeners != null)
- {
- for (int i = 0; i < globalJobListeners.Length; i++)
- {
- scheduler.AddGlobalJobListener(globalJobListeners[i]);
- }
- }
- if (jobListeners != null)
- {
- for (int i = 0; i < jobListeners.Length; i++)
- {
- scheduler.AddJobListener(jobListeners[i]);
- }
- }
- if (globalTriggerListeners != null)
- {
- for (int i = 0; i < globalTriggerListeners.Length; i++)
- {
- scheduler.AddGlobalTriggerListener(globalTriggerListeners[i]);
- }
- }
- if (triggerListeners != null)
- {
- for (int i = 0; i < triggerListeners.Length; i++)
- {
- scheduler.AddTriggerListener(triggerListeners[i]);
- }
- }
- }
-
- ///
- /// Register jobs and triggers (within a transaction, if possible).
- ///
- private void RegisterJobsAndTriggers()
- {
- ITransactionStatus transactionStatus = null;
- if (transactionManager != null) {
- transactionStatus = transactionManager.GetTransaction(new DefaultTransactionDefinition());
- }
-
- try
- {
- if (jobSchedulingDataLocations != null)
- {
- ResourceJobSchedulingDataProcessor dataProcessor = new ResourceJobSchedulingDataProcessor();
- if (applicationContext != null)
- {
- dataProcessor.ResourceLoader = applicationContext;
- }
- for (int i = 0; i < jobSchedulingDataLocations.Length; i++)
- {
- dataProcessor.ProcessFileAndScheduleJobs(jobSchedulingDataLocations[i], scheduler,
- overwriteExistingJobs);
- }
- }
-
- // Register JobDetails.
- if (jobDetails != null)
- {
- foreach (JobDetail jobDetail in jobDetails)
- {
- AddJobToScheduler(jobDetail);
- }
- }
- else
- {
- // Create empty list for easier checks when registering triggers.
- jobDetails = new ArrayList();
- }
-
- // Register Calendars.
- if (calendars != null)
- {
- foreach (DictionaryEntry entry in calendars)
- {
- string calendarName = (string) entry.Key;
- ICalendar calendar = (ICalendar) entry.Value;
- scheduler.AddCalendar(calendarName, calendar, true, true);
- }
- }
-
- // Register Triggers.
- if (triggers != null)
- {
- foreach (Trigger trigger in triggers)
- {
- AddTriggerToScheduler(trigger);
- }
- }
- }
- catch (Exception ex)
- {
- if (transactionStatus != null)
- {
- try
- {
- transactionManager.Rollback(transactionStatus);
- }
- catch (TransactionException)
- {
- logger.Error("Job registration exception overridden by rollback exception", ex);
- throw;
- }
- }
-
- if (ex is SchedulerException)
- {
- throw;
- }
- throw new SchedulerException("Registration of jobs and triggers failed: " + ex.Message, ex);
- }
-
- if (transactionStatus != null)
- {
- transactionManager.Commit(transactionStatus);
- }
- }
-
- ///
- /// Add the given job to the Scheduler, if it doesn't already exist.
- /// Overwrites the job in any case if "overwriteExistingJobs" is set.
- ///
- /// the job to add
- ///
- /// true if the job was actually added,
- /// false if it already existed before
- ///
- ///
- private bool AddJobToScheduler(JobDetail jobDetail)
- {
- if (overwriteExistingJobs || scheduler.GetJobDetail(jobDetail.Name, jobDetail.Group) == null)
- {
- scheduler.AddJob(jobDetail, true);
- return true;
- }
- return false;
- }
-
- ///
- /// Add the given trigger to the Scheduler, if it doesn't already exist.
- /// Overwrites the trigger in any case if "overwriteExistingJobs" is set.
- ///
- /// the trigger to add
- ///
- /// true if the trigger was actually added,
- /// false if it already existed before
- ///
- ///
- private bool AddTriggerToScheduler(Trigger trigger)
- {
- bool triggerExists = (scheduler.GetTrigger(trigger.Name, trigger.Group) != null);
- if (!triggerExists || overwriteExistingJobs)
- {
- // Check if the Trigger is aware of an associated JobDetail.
- if (trigger is IJobDetailAwareTrigger)
- {
- JobDetail jobDetail = ((IJobDetailAwareTrigger) trigger).JobDetail;
- // Automatically register the JobDetail too.
- if (!jobDetails.Contains(jobDetail) && AddJobToScheduler(jobDetail))
- {
- jobDetails.Add(jobDetail);
- }
- }
- if (!triggerExists)
- {
- try
- {
- scheduler.ScheduleJob(trigger);
- }
- catch (ObjectAlreadyExistsException ex)
- {
- if (logger.IsDebugEnabled)
- {
- logger.Debug(
- string.Format(
- "Unexpectedly found existing trigger, assumably due to cluster race condition: {0} - can safely be ignored",
- ex.Message));
- }
- if (overwriteExistingJobs)
- {
- scheduler.RescheduleJob(trigger.Name, trigger.Group, trigger);
- }
- }
- }
- else
- {
- scheduler.RescheduleJob(trigger.Name, trigger.Group, trigger);
- }
- return true;
- }
- return false;
- }
-
-
///
/// Start the Quartz Scheduler, respecting the "startDelay" setting.
///
diff --git a/src/Spring/Spring.Scheduling.Quartz/Spring.Scheduling.Quartz.2005.csproj b/src/Spring/Spring.Scheduling.Quartz/Spring.Scheduling.Quartz.2005.csproj
index 94219426..876d3780 100644
--- a/src/Spring/Spring.Scheduling.Quartz/Spring.Scheduling.Quartz.2005.csproj
+++ b/src/Spring/Spring.Scheduling.Quartz/Spring.Scheduling.Quartz.2005.csproj
@@ -62,6 +62,8 @@
+
+
diff --git a/src/Spring/Spring.Scheduling.Quartz/Spring.Scheduling.Quartz.2008.csproj b/src/Spring/Spring.Scheduling.Quartz/Spring.Scheduling.Quartz.2008.csproj
index f8e70671..37e7f168 100644
--- a/src/Spring/Spring.Scheduling.Quartz/Spring.Scheduling.Quartz.2008.csproj
+++ b/src/Spring/Spring.Scheduling.Quartz/Spring.Scheduling.Quartz.2008.csproj
@@ -2,7 +2,7 @@
Debug
AnyCPU
- 9.0.21022
+ 9.0.30729
2.0
{E823D54C-CE82-4868-929F-5F95A999F61E}
Library
@@ -58,6 +58,8 @@
+
+
diff --git a/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/QuartzSupportTests.cs b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/QuartzSupportTests.cs
new file mode 100644
index 00000000..fb39a729
--- /dev/null
+++ b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/QuartzSupportTests.cs
@@ -0,0 +1,1153 @@
+/*
+ * Copyright 2002-2008 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections;
+using System.Threading;
+
+using NUnit.Framework;
+
+using Quartz;
+using Quartz.Impl;
+using Quartz.Spi;
+
+using Rhino.Mocks;
+
+using Spring.Context.Support;
+using Spring.Objects;
+using Spring.Objects.Factory.Support;
+
+namespace Spring.Scheduling.Quartz
+{
+ ///
+ ///
+ /// Juergen Hoeller
+ /// Alef Arendsen
+ /// Rob Harrop
+ /// Marko Lahma (.NET)
+ [TestFixture]
+ public class QuartzSupportTests
+ {
+ private MockRepository mockery;
+
+ [SetUp]
+ public void SetUp()
+ {
+ mockery = new MockRepository();
+ }
+
+ [Test]
+ public void TestSchedulerFactoryObject()
+ {
+ DoTestSchedulerFactoryObject(false, false);
+ }
+
+ [Test]
+ public void TestSchedulerFactoryObjectWithExplicitJobDetail()
+ {
+ DoTestSchedulerFactoryObject(true, false);
+ }
+
+ [Test]
+ [Ignore("Requires change to MethodInvoker for overriding target object and type")]
+ public void TestSchedulerFactoryObjectWithPrototypeJob()
+ {
+ DoTestSchedulerFactoryObject(false, true);
+ }
+
+ private void DoTestSchedulerFactoryObject(bool explicitJobDetail, bool prototypeJob)
+ {
+ TestObject tb = new TestObject("tb", 99);
+ JobDetailObject jobDetail0 = new JobDetailObject();
+ jobDetail0.JobType = typeof (IJob);
+ jobDetail0.ObjectName = ("myJob0");
+ IDictionary jobData = new Hashtable();
+ jobData.Add("testObject", tb);
+ jobDetail0.JobDataAsMap = (jobData);
+ jobDetail0.AfterPropertiesSet();
+ Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject"));
+
+ CronTriggerObject trigger0 = new CronTriggerObject();
+ trigger0.ObjectName = ("myTrigger0");
+ trigger0.JobDetail = (jobDetail0);
+ trigger0.CronExpressionString = ("0/1 * * * * ?");
+ trigger0.AfterPropertiesSet();
+
+ TestMethodInvokingTask task1 = new TestMethodInvokingTask();
+ MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject();
+ mijdfb.ObjectName = ("myJob1");
+ if (prototypeJob)
+ {
+ StaticListableObjectFactory objectFactory = new StaticListableObjectFactory();
+ objectFactory.AddObject("task", task1);
+ mijdfb.TargetObjectName = ("task");
+ mijdfb.ObjectFactory = objectFactory;
+ }
+ else
+ {
+ mijdfb.TargetObject = (task1);
+ }
+ mijdfb.TargetMethod = ("doSomething");
+ mijdfb.AfterPropertiesSet();
+ JobDetail jobDetail1 = (JobDetail) mijdfb.GetObject();
+
+ SimpleTriggerObject trigger1 = new SimpleTriggerObject();
+ trigger1.ObjectName = ("myTrigger1");
+ trigger1.JobDetail = (jobDetail1);
+ trigger1.StartDelay = TimeSpan.FromMilliseconds(0);
+ trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20);
+ trigger1.AfterPropertiesSet();
+
+ IScheduler scheduler = (IScheduler) mockery.CreateMock(typeof (IScheduler));
+
+ Expect.Call(scheduler.Context).Return(new SchedulerContext());
+ Expect.Call(scheduler.GetJobDetail("myJob0", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(scheduler.GetJobDetail("myJob1", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(scheduler.GetTrigger("myTrigger0", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(scheduler.GetTrigger("myTrigger1", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(delegate { scheduler.AddJob(jobDetail0, true); }).IgnoreArguments();
+ Expect.Call(scheduler.ScheduleJob(trigger0)).Return(DateTime.UtcNow);
+ Expect.Call(delegate { scheduler.AddJob(jobDetail1, true); }).IgnoreArguments();
+ Expect.Call(scheduler.ScheduleJob(trigger1)).Return(DateTime.UtcNow);
+ Expect.Call(delegate { scheduler.Start(); });
+ Expect.Call(delegate { scheduler.Shutdown(false); });
+
+ mockery.ReplayAll();
+
+ SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
+ schedulerFactoryObject.JobFactory = (null);
+ IDictionary schedulerContext = new Hashtable();
+ schedulerContext.Add("otherTestObject", tb);
+ schedulerFactoryObject.SchedulerContextAsMap = (schedulerContext);
+ if (explicitJobDetail)
+ {
+ schedulerFactoryObject.JobDetails = (new JobDetail[] {jobDetail0});
+ }
+ schedulerFactoryObject.Triggers = (new Trigger[] {trigger0, trigger1});
+ try
+ {
+ schedulerFactoryObject.AfterPropertiesSet();
+ }
+ finally
+ {
+ schedulerFactoryObject.Dispose();
+ }
+
+ mockery.VerifyAll();
+ }
+
+ [Test]
+ public void TestSchedulerFactoryObjectWithExistingJobs()
+ {
+ DoTestSchedulerFactoryObjectWithExistingJobs(false);
+ }
+
+ [Test]
+ public void TestSchedulerFactoryObjectWithOverwriteExistingJobs()
+ {
+ DoTestSchedulerFactoryObjectWithExistingJobs(true);
+ }
+
+ private void DoTestSchedulerFactoryObjectWithExistingJobs(bool overwrite)
+ {
+ TestObject tb = new TestObject("tb", 99);
+ JobDetailObject jobDetail0 = new JobDetailObject();
+ jobDetail0.JobType = typeof (IJob);
+ jobDetail0.ObjectName = ("myJob0");
+ IDictionary jobData = new Hashtable();
+ jobData.Add("testObject", tb);
+ jobDetail0.JobDataAsMap = (jobData);
+ jobDetail0.AfterPropertiesSet();
+ Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject"));
+
+ CronTriggerObject trigger0 = new CronTriggerObject();
+ trigger0.ObjectName = ("myTrigger0");
+ trigger0.JobDetail = (jobDetail0);
+ trigger0.CronExpressionString = ("0/1 * * * * ?");
+ trigger0.AfterPropertiesSet();
+
+ TestMethodInvokingTask task1 = new TestMethodInvokingTask();
+ MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject();
+ mijdfb.ObjectName = ("myJob1");
+ mijdfb.TargetObject = (task1);
+ mijdfb.TargetMethod = ("doSomething");
+ mijdfb.AfterPropertiesSet();
+ JobDetail jobDetail1 = (JobDetail) mijdfb.GetObject();
+
+ SimpleTriggerObject trigger1 = new SimpleTriggerObject();
+ trigger1.ObjectName = ("myTrigger1");
+ trigger1.JobDetail = (jobDetail1);
+ trigger1.StartDelay = TimeSpan.FromMilliseconds(0);
+ trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20);
+ trigger1.AfterPropertiesSet();
+
+ IScheduler scheduler = (IScheduler) mockery.CreateMock(typeof (IScheduler));
+ Expect.Call(scheduler.Context).Return(new SchedulerContext());
+ Expect.Call(scheduler.GetTrigger("myTrigger0", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(scheduler.GetTrigger("myTrigger1", SchedulerConstants.DefaultGroup)).Return(new SimpleTrigger());
+ if (overwrite)
+ {
+ Expect.Call(delegate { scheduler.AddJob(jobDetail1, true); }).IgnoreArguments();
+ Expect.Call(scheduler.RescheduleJob("myTrigger1", SchedulerConstants.DefaultGroup, trigger1)).Return(
+ DateTime.UtcNow);
+ }
+ else
+ {
+ Expect.Call(scheduler.GetJobDetail("myJob0", SchedulerConstants.DefaultGroup)).Return(null);
+ }
+ Expect.Call(delegate { scheduler.AddJob(jobDetail0, true); }).IgnoreArguments();
+ Expect.Call(scheduler.ScheduleJob(trigger0)).Return(DateTime.UtcNow);
+ ;
+ Expect.Call(delegate { scheduler.Start(); });
+ Expect.Call(delegate { scheduler.Shutdown(false); });
+
+ mockery.ReplayAll();
+
+ SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
+ schedulerFactoryObject.JobFactory = (null);
+ IDictionary schedulerContext = new Hashtable();
+ schedulerContext.Add("otherTestObject", tb);
+ schedulerFactoryObject.SchedulerContextAsMap = (schedulerContext);
+ schedulerFactoryObject.Triggers = (new Trigger[] {trigger0, trigger1});
+ if (overwrite)
+ {
+ schedulerFactoryObject.OverwriteExistingJobs = (true);
+ }
+ try
+ {
+ schedulerFactoryObject.AfterPropertiesSet();
+ }
+ finally
+ {
+ schedulerFactoryObject.Dispose();
+ }
+
+ mockery.VerifyAll();
+ }
+
+ [Test]
+ public void TestSchedulerFactoryObjectWithExistingJobsAndRaceCondition()
+ {
+ DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(false);
+ }
+
+ [Test]
+ public void TestSchedulerFactoryObjectWithOverwriteExistingJobsAndRaceCondition()
+ {
+ DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(true);
+ }
+
+ private void DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(bool overwrite)
+ {
+ TestObject tb = new TestObject("tb", 99);
+ JobDetailObject jobDetail0 = new JobDetailObject();
+ jobDetail0.JobType = typeof (IJob);
+ jobDetail0.ObjectName = ("myJob0");
+ IDictionary jobData = new Hashtable();
+ jobData.Add("testObject", tb);
+ jobDetail0.JobDataAsMap = (jobData);
+ jobDetail0.AfterPropertiesSet();
+ Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject"));
+
+ CronTriggerObject trigger0 = new CronTriggerObject();
+ trigger0.ObjectName = ("myTrigger0");
+ trigger0.JobDetail = (jobDetail0);
+ trigger0.CronExpressionString = ("0/1 * * * * ?");
+ trigger0.AfterPropertiesSet();
+
+ TestMethodInvokingTask task1 = new TestMethodInvokingTask();
+ MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject();
+ mijdfb.ObjectName = ("myJob1");
+ mijdfb.TargetObject = (task1);
+ mijdfb.TargetMethod = ("doSomething");
+ mijdfb.AfterPropertiesSet();
+ JobDetail jobDetail1 = (JobDetail) mijdfb.GetObject();
+
+ SimpleTriggerObject trigger1 = new SimpleTriggerObject();
+ trigger1.ObjectName = ("myTrigger1");
+ trigger1.JobDetail = (jobDetail1);
+ trigger1.StartDelay = TimeSpan.FromMilliseconds(0);
+ trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20);
+ trigger1.AfterPropertiesSet();
+
+ IScheduler scheduler = (IScheduler) mockery.CreateMock(typeof (IScheduler));
+ Expect.Call(scheduler.Context).Return(new SchedulerContext());
+ Expect.Call(scheduler.GetTrigger("myTrigger0", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(scheduler.GetTrigger("myTrigger1", SchedulerConstants.DefaultGroup)).Return(new SimpleTrigger());
+ if (overwrite)
+ {
+ Expect.Call(delegate { scheduler.AddJob(jobDetail1, true); }).IgnoreArguments();
+ Expect.Call(scheduler.RescheduleJob("myTrigger1", SchedulerConstants.DefaultGroup, trigger1)).Return(
+ DateTime.UtcNow);
+ }
+ else
+ {
+ Expect.Call(scheduler.GetJobDetail("myJob0", SchedulerConstants.DefaultGroup)).Return(null);
+ }
+ Expect.Call(delegate { scheduler.AddJob(jobDetail0, true); }).IgnoreArguments();
+ Expect.Call(scheduler.ScheduleJob(trigger0)).Throw(new ObjectAlreadyExistsException(""));
+ if (overwrite)
+ {
+ Expect.Call(scheduler.RescheduleJob("myTrigger0", SchedulerConstants.DefaultGroup, trigger0)).Return(
+ DateTime.UtcNow);
+ }
+
+ Expect.Call(delegate { scheduler.Start(); });
+ Expect.Call(delegate { scheduler.Shutdown(false); });
+
+ mockery.ReplayAll();
+
+ SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
+
+ schedulerFactoryObject.JobFactory = (null);
+ IDictionary schedulerContext = new Hashtable();
+ schedulerContext.Add("otherTestObject", tb);
+ schedulerFactoryObject.SchedulerContextAsMap = (schedulerContext);
+ schedulerFactoryObject.Triggers = (new Trigger[] {trigger0, trigger1});
+ if (overwrite)
+ {
+ schedulerFactoryObject.OverwriteExistingJobs = (true);
+ }
+ try
+ {
+ schedulerFactoryObject.AfterPropertiesSet();
+ }
+ finally
+ {
+ schedulerFactoryObject.Dispose();
+ }
+
+ mockery.VerifyAll();
+ }
+
+ [Test]
+ public void TestSchedulerFactoryObjectWithListeners()
+ {
+ IJobFactory jobFactory = new AdaptableJobFactory();
+
+ IScheduler scheduler = (IScheduler) mockery.CreateMock(typeof (IScheduler));
+
+ ISchedulerListener schedulerListener = new TestSchedulerListener();
+ IJobListener globalJobListener = new TestJobListener();
+ IJobListener jobListener = new TestJobListener();
+ ITriggerListener globalTriggerListener = new TestTriggerListener();
+ ITriggerListener triggerListener = new TestTriggerListener();
+
+ Expect.Call(scheduler.JobFactory = (jobFactory));
+ Expect.Call(delegate { scheduler.AddSchedulerListener(schedulerListener); });
+ Expect.Call(delegate { scheduler.AddGlobalJobListener(globalJobListener); });
+ Expect.Call(delegate { scheduler.AddJobListener(jobListener); });
+ Expect.Call(delegate { scheduler.AddGlobalTriggerListener(globalTriggerListener); });
+ Expect.Call(delegate { scheduler.AddTriggerListener(triggerListener); });
+ Expect.Call(delegate { scheduler.Start(); });
+ Expect.Call(delegate { scheduler.Shutdown(false); });
+
+ mockery.ReplayAll();
+
+ SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
+
+ schedulerFactoryObject.JobFactory = (jobFactory);
+ schedulerFactoryObject.SchedulerListeners = (new ISchedulerListener[] {schedulerListener});
+ schedulerFactoryObject.GlobalJobListeners = (new IJobListener[] {globalJobListener});
+ schedulerFactoryObject.JobListeners = (new IJobListener[] {jobListener});
+ schedulerFactoryObject.GlobalTriggerListeners = (new ITriggerListener[] {globalTriggerListener});
+ schedulerFactoryObject.TriggerListeners = (new ITriggerListener[] {triggerListener});
+ try
+ {
+ schedulerFactoryObject.AfterPropertiesSet();
+ }
+ finally
+ {
+ schedulerFactoryObject.Dispose();
+ }
+
+ mockery.VerifyAll();
+ }
+
+ /*public void TestMethodInvocationWithConcurrency() {
+ methodInvokingConcurrency(true);
+ }*/
+
+ // We can't test both since Quartz somehow seems to keep things in memory
+ // enable both and one of them will fail (order doesn't matter).
+ /*public void TestMethodInvocationWithoutConcurrency() {
+ methodInvokingConcurrency(false);
+ }*/
+
+ private void methodInvokingConcurrency(bool concurrent)
+ {
+ // Test the concurrency flag.
+ // Method invoking job with two triggers.
+ // If the concurrent flag is false, the triggers are NOT allowed
+ // to interfere with each other.
+
+ TestMethodInvokingTask task1 = new TestMethodInvokingTask();
+ MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject();
+ // set the concurrency flag!
+ mijdfb.Concurrent = (concurrent);
+ mijdfb.ObjectName = ("myJob1");
+ mijdfb.TargetObject = (task1);
+ mijdfb.TargetMethod = ("doWait");
+ mijdfb.AfterPropertiesSet();
+ JobDetail jobDetail1 = (JobDetail) mijdfb.GetObject();
+
+ SimpleTriggerObject trigger0 = new SimpleTriggerObject();
+ trigger0.ObjectName = ("myTrigger1");
+ trigger0.JobDetail = (jobDetail1);
+ trigger0.StartDelay = TimeSpan.FromMilliseconds(0);
+ trigger0.RepeatInterval = TimeSpan.FromMilliseconds(1);
+ trigger0.RepeatCount = (1);
+ trigger0.AfterPropertiesSet();
+
+ SimpleTriggerObject trigger1 = new SimpleTriggerObject();
+ trigger1.ObjectName = ("myTrigger1");
+ trigger1.JobDetail = (jobDetail1);
+ trigger1.StartDelay = TimeSpan.FromMilliseconds(1000L);
+ trigger1.RepeatInterval = TimeSpan.FromMilliseconds(1);
+ trigger1.RepeatCount = (1);
+ trigger1.AfterPropertiesSet();
+
+ SchedulerFactoryObject schedulerFactoryObject = new SchedulerFactoryObject();
+ schedulerFactoryObject.JobDetails = (new JobDetail[] {jobDetail1});
+ schedulerFactoryObject.Triggers = (new Trigger[] {trigger1, trigger0});
+ schedulerFactoryObject.AfterPropertiesSet();
+
+ // ok scheduler is set up... let's wait for like 4 seconds
+ try
+ {
+ Thread.Sleep(4000);
+ }
+ catch (ThreadInterruptedException ex)
+ {
+ // fall through
+ }
+
+ if (concurrent)
+ {
+ Assert.AreEqual(2, task1.counter);
+ task1.Stop();
+ // we're done, both jobs have ran, let's call it a day
+ return;
+ }
+ else
+ {
+ Assert.AreEqual(1, task1.counter);
+ task1.Stop();
+ // we need to check whether or not the test succeed with non-concurrent jobs
+ }
+
+ try
+ {
+ Thread.Sleep(4000);
+ }
+ catch (ThreadInterruptedException ex)
+ {
+ // fall through
+ }
+
+ task1.Stop();
+ Assert.AreEqual(2, task1.counter);
+
+ // Although we're destroying the scheduler, it does seem to keep things in memory:
+ // When executing both tests (concurrent and non-concurrent), the second test always
+ // fails.
+ schedulerFactoryObject.Dispose();
+ }
+
+ [Test]
+ public void TestSchedulerFactoryObjectWithPlainQuartzObjects()
+ {
+ IJobFactory jobFactory = new AdaptableJobFactory();
+
+ TestObject tb = new TestObject("tb", 99);
+ JobDetail jobDetail0 = new JobDetail();
+ jobDetail0.JobType = typeof (IJob);
+ jobDetail0.Name = ("myJob0");
+ jobDetail0.Group = (SchedulerConstants.DefaultGroup);
+ jobDetail0.JobDataMap.Add("testObject", tb);
+ Assert.AreEqual(tb, jobDetail0.JobDataMap.Get("testObject"));
+
+ CronTrigger trigger0 = new CronTrigger();
+ trigger0.Name = ("myTrigger0");
+ trigger0.Group = SchedulerConstants.DefaultGroup;
+ trigger0.JobName = "myJob0";
+ trigger0.JobGroup = SchedulerConstants.DefaultGroup;
+ trigger0.StartTimeUtc = (DateTime.UtcNow);
+ trigger0.CronExpressionString = ("0/1 * * * * ?");
+
+ TestMethodInvokingTask task1 = new TestMethodInvokingTask();
+ MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject();
+ mijdfb.Name = ("myJob1");
+ mijdfb.Group = (SchedulerConstants.DefaultGroup);
+ mijdfb.TargetObject = (task1);
+ mijdfb.TargetMethod = ("doSomething");
+ mijdfb.AfterPropertiesSet();
+ JobDetail jobDetail1 = (JobDetail) mijdfb.GetObject();
+
+ SimpleTrigger trigger1 = new SimpleTrigger();
+ trigger1.Name = "myTrigger1";
+ trigger1.Group = SchedulerConstants.DefaultGroup;
+ trigger1.JobName = "myJob1";
+ trigger1.JobGroup = SchedulerConstants.DefaultGroup;
+ trigger1.StartTimeUtc = (DateTime.UtcNow);
+ trigger1.RepeatCount = (SimpleTrigger.RepeatIndefinitely);
+ trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20);
+
+ IScheduler scheduler = (IScheduler) mockery.CreateMock(typeof (IScheduler));
+ Expect.Call(scheduler.JobFactory = (jobFactory));
+ Expect.Call(scheduler.GetJobDetail("myJob0", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(scheduler.GetJobDetail("myJob1", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(scheduler.GetTrigger("myTrigger0", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(scheduler.GetTrigger("myTrigger1", SchedulerConstants.DefaultGroup)).Return(null);
+ Expect.Call(delegate { scheduler.AddJob(jobDetail0, true); }).IgnoreArguments();
+ Expect.Call(delegate { scheduler.AddJob(jobDetail1, true); }).IgnoreArguments();
+ Expect.Call(scheduler.ScheduleJob(trigger0)).Return(DateTime.UtcNow);
+ Expect.Call(scheduler.ScheduleJob(trigger1)).Return(DateTime.UtcNow);
+ Expect.Call(delegate { scheduler.Start(); });
+ Expect.Call(delegate { scheduler.Shutdown(false); });
+
+ mockery.ReplayAll();
+
+ SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
+
+ schedulerFactoryObject.JobFactory = (jobFactory);
+ schedulerFactoryObject.JobDetails = (new JobDetail[] {jobDetail0, jobDetail1});
+ schedulerFactoryObject.Triggers = (new Trigger[] {trigger0, trigger1});
+ try
+ {
+ schedulerFactoryObject.AfterPropertiesSet();
+ }
+ finally
+ {
+ schedulerFactoryObject.Dispose();
+ }
+
+ mockery.VerifyAll();
+ }
+
+ [Test]
+ public void TestSchedulerFactoryObjectWithApplicationContext()
+ {
+ TestObject tb = new TestObject("tb", 99);
+ StaticApplicationContext ac = new StaticApplicationContext();
+
+ IScheduler scheduler = (IScheduler) mockery.CreateMock(typeof (IScheduler));
+ SchedulerContext schedulerContext = new SchedulerContext();
+ Expect.Call(scheduler.Context).Return(schedulerContext).Repeat.Times(4);
+ Expect.Call(delegate { scheduler.Start(); });
+ Expect.Call(delegate { scheduler.Shutdown(false); });
+
+ mockery.ReplayAll();
+
+ SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
+ schedulerFactoryObject.JobFactory = (null);
+ IDictionary schedulerContextMap = new Hashtable();
+ schedulerContextMap.Add("testObject", tb);
+ schedulerFactoryObject.SchedulerContextAsMap = (schedulerContextMap);
+ schedulerFactoryObject.ApplicationContext = (ac);
+ schedulerFactoryObject.ApplicationContextSchedulerContextKey = ("appCtx");
+ try
+ {
+ schedulerFactoryObject.AfterPropertiesSet();
+ IScheduler returnedScheduler = (IScheduler) schedulerFactoryObject.GetObject();
+ Assert.AreEqual(tb, returnedScheduler.Context["testObject"]);
+ Assert.AreEqual(ac, returnedScheduler.Context["appCtx"]);
+ }
+ finally
+ {
+ schedulerFactoryObject.Dispose();
+ }
+
+ mockery.VerifyAll();
+ }
+
+ [Test]
+ public void TestJobDetailObjectWithApplicationContext()
+ {
+ TestObject tb = new TestObject("tb", 99);
+ StaticApplicationContext ac = new StaticApplicationContext();
+
+ JobDetailObject jobDetail = new JobDetailObject();
+ jobDetail.JobType = typeof (IJob);
+ jobDetail.ObjectName = ("myJob0");
+ IDictionary jobData = new Hashtable();
+ jobData.Add("testObject", tb);
+ jobDetail.JobDataAsMap = (jobData);
+ jobDetail.ApplicationContext = (ac);
+ jobDetail.ApplicationContextJobDataKey = ("appCtx");
+ jobDetail.AfterPropertiesSet();
+
+ Assert.AreEqual(tb, jobDetail.JobDataMap.Get("testObject"));
+ Assert.AreEqual(ac, jobDetail.JobDataMap.Get("appCtx"));
+ }
+
+ [Test]
+ public void TestMethodInvokingJobDetailFactoryObjectWithListenerNames()
+ {
+ TestMethodInvokingTask task = new TestMethodInvokingTask();
+ MethodInvokingJobDetailFactoryObject mijdfb = new MethodInvokingJobDetailFactoryObject();
+ String[] names = new String[] {"test1", "test2"};
+ mijdfb.Name = ("myJob1");
+ mijdfb.Group = (SchedulerConstants.DefaultGroup);
+ mijdfb.TargetObject = (task);
+ mijdfb.TargetMethod = ("doSomething");
+ mijdfb.JobListenerNames = (names);
+ mijdfb.AfterPropertiesSet();
+ JobDetail jobDetail = (JobDetail) mijdfb.GetObject();
+ ArrayList result = new ArrayList(jobDetail.JobListenerNames);
+ Assert.AreEqual(names, result);
+ }
+
+ [Test]
+ public void TestJobDetailObjectWithListenerNames()
+ {
+ JobDetailObject jobDetail = new JobDetailObject();
+ String[] names = new String[] {"test1", "test2"};
+ jobDetail.JobListenerNames = (names);
+ ArrayList result = new ArrayList(jobDetail.JobListenerNames);
+ Assert.AreEqual(names, result);
+ }
+
+ [Test]
+ public void TestCronTriggerObjectWithListenerNames()
+ {
+ CronTriggerObject trigger = new CronTriggerObject();
+ String[] names = new String[] {"test1", "test2"};
+ trigger.TriggerListenerNames = (names);
+ ArrayList result = new ArrayList(trigger.TriggerListenerNames);
+ Assert.AreEqual(names, result);
+ }
+
+ [Test]
+ public void TestSimpleTriggerObjectWithListenerNames()
+ {
+ SimpleTriggerObject trigger = new SimpleTriggerObject();
+ String[] names = new String[] {"test1", "test2"};
+ trigger.TriggerListenerNames = (names);
+ ArrayList result = new ArrayList(trigger.TriggerListenerNames);
+ Assert.AreEqual(names, result);
+ }
+
+ [Test]
+ public void TestSchedulerWithTaskExecutor()
+ {
+ CountingTaskExecutor taskExecutor = new CountingTaskExecutor();
+ DummyJob.count = 0;
+
+ JobDetail jobDetail = new JobDetail();
+ jobDetail.JobType = typeof (DummyJob);
+ ;
+ jobDetail.Name = ("myJob");
+
+ SimpleTriggerObject trigger = new SimpleTriggerObject();
+ trigger.Name = ("myTrigger");
+ trigger.JobDetail = (jobDetail);
+ trigger.StartDelay = TimeSpan.FromMilliseconds(1);
+ trigger.RepeatInterval = TimeSpan.FromMilliseconds(500);
+ trigger.RepeatCount = (1);
+ trigger.AfterPropertiesSet();
+
+ SchedulerFactoryObject bean = new SchedulerFactoryObject();
+ bean.TaskExecutor = (taskExecutor);
+ bean.Triggers = (new Trigger[] {trigger});
+ bean.JobDetails = (new JobDetail[] {jobDetail});
+ bean.AfterPropertiesSet();
+
+ Thread.Sleep(500);
+ Assert.IsTrue(DummyJob.count > 0);
+ Assert.AreEqual(DummyJob.count, taskExecutor.count);
+
+ bean.Dispose();
+ }
+
+ [Test]
+ public void TestSchedulerWithRunnable()
+ {
+ DummyRunnable.count = 0;
+
+ JobDetail jobDetail = new JobDetailObject();
+ jobDetail.JobType = typeof (DummyRunnable);
+ jobDetail.Name = ("myJob");
+
+ SimpleTriggerObject trigger = new SimpleTriggerObject();
+ trigger.Name = ("myTrigger");
+ trigger.JobDetail = (jobDetail);
+ trigger.StartDelay = TimeSpan.FromMilliseconds(1);
+ trigger.RepeatInterval = TimeSpan.FromMilliseconds(500);
+ trigger.RepeatCount = (1);
+ trigger.AfterPropertiesSet();
+
+ SchedulerFactoryObject bean = new SchedulerFactoryObject();
+ bean.Triggers = (new Trigger[] {trigger});
+ bean.JobDetails = (new JobDetail[] {jobDetail});
+ bean.AfterPropertiesSet();
+
+ Thread.Sleep(500);
+ Assert.IsTrue(DummyRunnable.count > 0);
+
+ bean.Dispose();
+ }
+
+ [Test]
+ public void TestSchedulerWithQuartzJobObject()
+ {
+ DummyJob.param = 0;
+ DummyJob.count = 0;
+
+ JobDetail jobDetail = new JobDetail();
+ jobDetail.JobType = (typeof (DummyJobObject));
+ jobDetail.Name = ("myJob");
+ jobDetail.JobDataMap.Put("param", "10");
+
+ SimpleTriggerObject trigger = new SimpleTriggerObject();
+ trigger.Name = ("myTrigger");
+ trigger.JobDetail = (jobDetail);
+ trigger.StartDelay = TimeSpan.FromMilliseconds(1);
+ trigger.RepeatInterval = TimeSpan.FromMilliseconds(500);
+ trigger.RepeatCount = (1);
+ trigger.AfterPropertiesSet();
+
+ SchedulerFactoryObject sfo = new SchedulerFactoryObject();
+ sfo.Triggers = (new Trigger[] {trigger});
+ sfo.JobDetails = (new JobDetail[] {jobDetail});
+ sfo.AfterPropertiesSet();
+
+ Thread.Sleep(500);
+ Assert.AreEqual(10, DummyJobObject.param);
+ Assert.IsTrue(DummyJobObject.count > 0);
+
+ sfo.Dispose();
+ }
+
+ [Test]
+ public void TestSchedulerWithSpringObjectJobFactory()
+ {
+ DummyJob.param = 0;
+ DummyJob.count = 0;
+
+ JobDetail jobDetail = new JobDetail();
+ jobDetail.JobType = typeof(DummyJob);
+ jobDetail.Name = ("myJob");
+ jobDetail.JobDataMap.Add("param", "10");
+ jobDetail.JobDataMap.Add("ignoredParam", "10");
+
+ SimpleTriggerObject trigger = new SimpleTriggerObject();
+ trigger.Name = ("myTrigger");
+ trigger.JobDetail = (jobDetail);
+ trigger.StartDelay = TimeSpan.FromMilliseconds(1);
+ trigger.RepeatInterval = TimeSpan.FromMilliseconds(500);
+ trigger.RepeatCount = (1);
+ trigger.AfterPropertiesSet();
+
+ SchedulerFactoryObject bean = new SchedulerFactoryObject();
+ bean.JobFactory = (new SpringObjectJobFactory());
+ bean.Triggers = (new Trigger[] {trigger});
+ bean.JobDetails = (new JobDetail[] {jobDetail});
+ bean.AfterPropertiesSet();
+
+ Thread.Sleep(500);
+ Assert.AreEqual(10, DummyJob.param);
+ Assert.IsTrue(DummyJob.count > 0);
+
+ bean.Dispose();
+ }
+
+ [Test]
+ public void TestSchedulerWithSpringObjectJobFactoryAndParamMismatchNotIgnored()
+ {
+ DummyJob.param = 0;
+ DummyJob.count = 0;
+
+ JobDetail jobDetail = new JobDetail();
+ jobDetail.JobType = typeof(DummyJob);
+ jobDetail.Name = ("myJob");
+ jobDetail.JobDataMap.Add("para", "10");
+ jobDetail.JobDataMap.Add("ignoredParam", "10");
+
+ SimpleTriggerObject trigger = new SimpleTriggerObject();
+ trigger.Name = ("myTrigger");
+ trigger.JobDetail = (jobDetail);
+ trigger.StartDelay = TimeSpan.FromMilliseconds(1);
+ trigger.RepeatInterval = TimeSpan.FromMilliseconds(500);
+ trigger.RepeatCount = (1);
+ trigger.AfterPropertiesSet();
+
+ SchedulerFactoryObject bean = new SchedulerFactoryObject();
+ SpringObjectJobFactory jobFactory = new SpringObjectJobFactory();
+ jobFactory.IgnoredUnknownProperties = (new String[] {"ignoredParam"});
+ bean.JobFactory = (jobFactory);
+ bean.Triggers = (new Trigger[] {trigger});
+ bean.JobDetails = (new JobDetail[] {jobDetail});
+ bean.AfterPropertiesSet();
+
+ Thread.Sleep(500);
+ Assert.AreEqual(0, DummyJob.param);
+ Assert.IsTrue(DummyJob.count == 0);
+
+ bean.Dispose();
+ }
+
+ [Test]
+ public void TestSchedulerWithSpringObjectJobFactoryAndRunnable()
+ {
+ DummyRunnable.param = 0;
+ DummyRunnable.count = 0;
+
+ JobDetail jobDetail = new JobDetailObject();
+ jobDetail.JobType = typeof (DummyRunnable);
+ jobDetail.Name = ("myJob");
+ jobDetail.JobDataMap.Add("param", "10");
+
+ SimpleTriggerObject trigger = new SimpleTriggerObject();
+ trigger.Name = ("myTrigger");
+ trigger.JobDetail = (jobDetail);
+ trigger.StartDelay = TimeSpan.FromMilliseconds(1);
+ trigger.RepeatInterval = TimeSpan.FromMilliseconds(500);
+ trigger.RepeatCount = (1);
+ trigger.AfterPropertiesSet();
+
+ SchedulerFactoryObject bean = new SchedulerFactoryObject();
+ bean.JobFactory = (new SpringObjectJobFactory());
+ bean.Triggers = (new Trigger[] {trigger});
+ bean.JobDetails = (new JobDetail[] {jobDetail});
+ bean.AfterPropertiesSet();
+
+ Thread.Sleep(500);
+ Assert.AreEqual(10, DummyRunnable.param);
+ Assert.IsTrue(DummyRunnable.count > 0);
+
+ bean.Dispose();
+ }
+
+ [Test]
+ public void TestSchedulerWithSpringObjectJobFactoryAndQuartzJobObject()
+ {
+ DummyJobObject.param = 0;
+ DummyJobObject.count = 0;
+
+ JobDetail jobDetail = new JobDetail();
+ jobDetail.JobType = typeof (DummyJobObject);
+ jobDetail.Name = ("myJob");
+ jobDetail.JobDataMap.Add("param", "10");
+
+ SimpleTriggerObject trigger = new SimpleTriggerObject();
+ trigger.Name = ("myTrigger");
+ trigger.JobDetail = (jobDetail);
+ trigger.StartDelay = TimeSpan.FromMilliseconds(1);
+ trigger.RepeatInterval = TimeSpan.FromMilliseconds(500);
+ trigger.RepeatCount = (1);
+ trigger.AfterPropertiesSet();
+
+ SchedulerFactoryObject bean = new SchedulerFactoryObject();
+ bean.JobFactory = (new SpringObjectJobFactory());
+ bean.Triggers = (new Trigger[] {trigger});
+ bean.JobDetails = (new JobDetail[] {jobDetail});
+ bean.AfterPropertiesSet();
+
+ Thread.Sleep(500);
+ Assert.AreEqual(10, DummyJobObject.param);
+ Assert.IsTrue(DummyJobObject.count > 0);
+
+ bean.Dispose();
+ }
+
+ [Test]
+ public void TestSchedulerWithSpringObjectJobFactoryAndJobSchedulingData()
+ {
+ DummyJob.param = 0;
+ DummyJob.count = 0;
+
+ SchedulerFactoryObject bean = new SchedulerFactoryObject();
+ bean.JobFactory = (new SpringObjectJobFactory());
+ bean.JobSchedulingDataLocation = ("job-scheduling-data.xml");
+ // TODO bean.ResourceLoader = (new FileSystemResourceLoader());
+ bean.AfterPropertiesSet();
+
+ Thread.Sleep(500);
+ Assert.AreEqual(10, DummyJob.param);
+ Assert.IsTrue(DummyJob.count > 0);
+
+ bean.Dispose();
+ }
+
+
+ ///
+ /// Tests the creation of multiple schedulers (SPR-772)
+ ///
+ [Test]
+ public void TestMultipleSchedulers()
+ {
+ XmlApplicationContext ctx = new XmlApplicationContext("multipleSchedulers.xml");
+ try
+ {
+ IScheduler scheduler1 = (IScheduler) ctx.GetObject("scheduler1");
+ IScheduler scheduler2 = (IScheduler) ctx.GetObject("scheduler2");
+ Assert.AreNotSame(scheduler1, scheduler2);
+ Assert.AreEqual("quartz1", scheduler1.SchedulerName);
+ Assert.AreEqual("quartz2", scheduler2.SchedulerName);
+
+ XmlApplicationContext ctx2 = new XmlApplicationContext("multipleSchedulers.xml");
+ try
+ {
+ IScheduler scheduler1a = (IScheduler) ctx2.GetObject("scheduler1");
+ IScheduler scheduler2a = (IScheduler) ctx2.GetObject("scheduler2");
+ Assert.AreNotSame(scheduler1a, scheduler2a);
+ Assert.AreNotSame(scheduler1a, scheduler1);
+ Assert.AreNotSame(scheduler2a, scheduler2);
+ Assert.AreEqual("quartz1", scheduler1a.SchedulerName);
+ Assert.AreEqual("quartz2", scheduler2a.SchedulerName);
+ }
+ finally
+ {
+ ctx2.Dispose();
+ }
+ }
+ finally
+ {
+ ctx.Dispose();
+ }
+ }
+
+ [Test]
+ public void TestWithTwoAnonymousMethodInvokingJobDetailFactoryObjects()
+ {
+ XmlApplicationContext ctx = new XmlApplicationContext("multipleAnonymousMethodInvokingJobDetailFB.xml");
+ Thread.Sleep(3000);
+ try
+ {
+ QuartzTestObject exportService = (QuartzTestObject) ctx.GetObject("exportService");
+ QuartzTestObject importService = (QuartzTestObject) ctx.GetObject("importService");
+
+ Assert.AreEqual(0, exportService.ImportCount, "doImport called exportService");
+ Assert.AreEqual(2, exportService.ExportCount, "doExport not called on exportService");
+ Assert.AreEqual(2, importService.ImportCount, "doImport not called on importService");
+ Assert.AreEqual(0, importService.ExportCount, "doExport called on importService");
+ }
+ finally
+ {
+ ctx.Dispose();
+ }
+ }
+
+ [Test]
+ public void TestSchedulerAccessorObject()
+ {
+ XmlApplicationContext ctx = new XmlApplicationContext("schedulerAccessorObject.xml");
+ Thread.Sleep(3000);
+ try
+ {
+ QuartzTestObject exportService = (QuartzTestObject) ctx.GetObject("exportService");
+ QuartzTestObject importService = (QuartzTestObject) ctx.GetObject("importService");
+
+ Assert.AreEqual(0, exportService.ImportCount, "doImport called exportService");
+ Assert.AreEqual(2, exportService.ExportCount, "doExport not called on exportService");
+ Assert.AreEqual(2, importService.ImportCount, "doImport not called on importService");
+ Assert.AreEqual(0, importService.ExportCount, "doExport called on importService");
+ }
+ finally
+ {
+ ctx.Dispose();
+ }
+ }
+
+ [Test]
+ public void TestSchedulerRepositoryExposure()
+ {
+ XmlApplicationContext ctx = new XmlApplicationContext("schedulerRepositoryExposure.xml");
+ Assert.AreSame(SchedulerRepository.Instance.Lookup("myScheduler"), ctx.GetObject("scheduler"));
+ ctx.Dispose();
+ }
+
+
+ private class TestSchedulerListener : ISchedulerListener
+ {
+ public void JobScheduled(Trigger trigger)
+ {
+ }
+
+ public void JobUnscheduled(String triggerName, String triggerGroup)
+ {
+ }
+
+ public void TriggerFinalized(Trigger trigger)
+ {
+ }
+
+ public void TriggersPaused(String triggerName, String triggerGroup)
+ {
+ }
+
+ public void TriggersResumed(String triggerName, String triggerGroup)
+ {
+ }
+
+ public void JobsPaused(String jobName, String jobGroup)
+ {
+ }
+
+ public void JobsResumed(String jobName, String jobGroup)
+ {
+ }
+
+ public void SchedulerError(String msg, SchedulerException cause)
+ {
+ }
+
+ public void SchedulerShutdown()
+ {
+ }
+ }
+
+
+ private class TestJobListener : IJobListener
+ {
+ public string Name
+ {
+ get { return null; }
+ }
+
+ public void JobToBeExecuted(JobExecutionContext context)
+ {
+ }
+
+ public void JobExecutionVetoed(JobExecutionContext context)
+ {
+ }
+
+ public void JobWasExecuted(JobExecutionContext context, JobExecutionException jobException)
+ {
+ }
+ }
+
+
+ private class TestTriggerListener : ITriggerListener
+ {
+ public string Name
+ {
+ get { return null; }
+ }
+
+ public void TriggerFired(Trigger trigger, JobExecutionContext context)
+ {
+ }
+
+ public bool VetoJobExecution(Trigger trigger, JobExecutionContext context)
+ {
+ return false;
+ }
+
+ public void TriggerMisfired(Trigger trigger)
+ {
+ }
+
+ public void TriggerComplete(Trigger trigger, JobExecutionContext context,
+ SchedulerInstruction triggerInstructionCode)
+ {
+ }
+ }
+
+
+ public class CountingTaskExecutor : ITaskExecutor
+ {
+ internal int count;
+
+ public void Execute(ThreadStart task)
+ {
+ count++;
+ task.Invoke();
+ }
+ }
+
+
+ public class DummyJobObject : QuartzJobObject
+ {
+ internal static int param;
+ internal static int count;
+
+ public void SetParam(int value)
+ {
+ if (param > 0)
+ {
+ throw new NotSupportedException("Param already set");
+ }
+ param = value;
+ }
+
+ protected override void ExecuteInternal(JobExecutionContext jobExecutionContext)
+ {
+ count++;
+ }
+ }
+
+
+ public class DummyRunnable : IThreadRunnable
+ {
+ internal static int param;
+
+ internal static int count;
+
+ public void SetParam(int value)
+ {
+ if (param > 0)
+ {
+ throw new NotSupportedException("Param already set");
+ }
+ param = value;
+ }
+
+ public void Run()
+ {
+ count++;
+ }
+ }
+ }
+
+ public class DummyJob : IJob
+ {
+ internal static int param;
+
+ internal static int count;
+
+ public void SetParam(int value)
+ {
+ if (param > 0)
+ {
+ throw new NotSupportedException("Param already set");
+ }
+ param = value;
+ }
+
+ public void Execute(JobExecutionContext jobExecutionContext)
+ {
+ count++;
+ }
+ }
+
+ public class TestSchedulerFactoryObject : SchedulerFactoryObject
+ {
+ private readonly IScheduler sched;
+
+ public TestSchedulerFactoryObject(IScheduler sched)
+ {
+ this.sched = sched;
+ }
+
+ protected override IScheduler CreateScheduler(ISchedulerFactory schedulerFactory, String schedulerName)
+ {
+ return sched;
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/QuartzTestObject.cs b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/QuartzTestObject.cs
new file mode 100644
index 00000000..5c6161ad
--- /dev/null
+++ b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/QuartzTestObject.cs
@@ -0,0 +1,31 @@
+namespace Spring.Scheduling.Quartz
+{
+ ///
+ ///
+ /// Rob Harrop
+ public class QuartzTestObject
+ {
+ private int exportCount;
+ private int importCount;
+
+ public void DoImport()
+ {
+ ++importCount;
+ }
+
+ public void DoExport()
+ {
+ ++exportCount;
+ }
+
+ public int ImportCount
+ {
+ get { return importCount; }
+ }
+
+ public int ExportCount
+ {
+ get { return exportCount; }
+ }
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/SchedulerFactoryObjectTest.cs b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/SchedulerFactoryObjectTest.cs
index 8775c8ee..327b3e97 100644
--- a/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/SchedulerFactoryObjectTest.cs
+++ b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/SchedulerFactoryObjectTest.cs
@@ -50,6 +50,11 @@ namespace Spring.Scheduling.Quartz
{
factory = new SchedulerFactoryObject();
TestSchedulerFactory.Mockery.BackToRecordAll();
+
+ Expect
+ .Call(TestSchedulerFactory.MockScheduler.SchedulerName)
+ .Return("scheduler")
+ .Repeat.Any();
}
[Test]
diff --git a/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/TestMethodInvokingTask.cs b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/TestMethodInvokingTask.cs
new file mode 100644
index 00000000..c41551c0
--- /dev/null
+++ b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/TestMethodInvokingTask.cs
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2002-2005 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System.Threading;
+
+namespace Spring.Scheduling.Quartz
+{
+
+ ///
+ ///
+ /// Juergen Hoeller
+ public class TestMethodInvokingTask
+ {
+ public int counter;
+ private readonly object lockObject = new object();
+
+ public void DoSomething()
+ {
+ counter++;
+ }
+
+ public void DoWait()
+ {
+ counter++;
+ // wait until stop is called
+ lock (lockObject)
+ {
+ try
+ {
+ Monitor.Wait(lockObject);
+ }
+ catch (ThreadInterruptedException)
+ {
+ // fall through
+ }
+ }
+ }
+
+ public void Stop()
+ {
+ lock (lockObject)
+ {
+ Monitor.Pulse(lockObject);
+ }
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/TriggerObjectTest.cs b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/TriggerObjectTest.cs
index 1c47ae28..873e9e2d 100644
--- a/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/TriggerObjectTest.cs
+++ b/test/Spring/Spring.Scheduling.Quartz.Tests/Scheduling/Quartz/TriggerObjectTest.cs
@@ -20,6 +20,8 @@ using NUnit.Framework;
using Quartz;
+using Spring.Objects.Factory;
+
namespace Spring.Scheduling.Quartz
{
///
@@ -40,6 +42,8 @@ namespace Spring.Scheduling.Quartz
[Test]
public virtual void TestAfterPropertiesSet_Defaults()
{
+ ((IInitializingObject) trigger).AfterPropertiesSet();
+
Assert.AreEqual(TRIGGER_NAME, trigger.Name, "trigger name mismatch");
Assert.AreEqual(SchedulerConstants.DefaultGroup, trigger.Group, "trigger group name mismatch");
AssertDateTimesEqualityWithAllowedDelta(DateTime.UtcNow, trigger.StartTimeUtc, 1000);
@@ -50,6 +54,8 @@ namespace Spring.Scheduling.Quartz
[Test]
public virtual void TestAfterPropertiesSet_ValuesGiven()
{
+ ((IInitializingObject)trigger).AfterPropertiesSet();
+
const string NAME = "newName";
const string GROUP = "newGroup";
DateTime START_TIME = new DateTime(10000000);
@@ -65,6 +71,8 @@ namespace Spring.Scheduling.Quartz
[Test]
public virtual void TestAfterPropertiesSet_JobDetailGiven()
{
+ ((IInitializingObject)trigger).AfterPropertiesSet();
+
const string jobName = "jobName";
const string jobGroup = "jobGroup";
Assert.AreEqual(jobName, trigger.JobName, "trigger job name was not from job detail");
@@ -74,7 +82,9 @@ namespace Spring.Scheduling.Quartz
[Test]
public virtual void TestTriggerListenerNames_Valis()
{
- string[] LISTENER_NAMES = new string[] {"Foo", "Bar", "Baz"};
+ ((IInitializingObject)trigger).AfterPropertiesSet();
+
+ string[] LISTENER_NAMES = new string[] { "Foo", "Bar", "Baz" };
trigger.TriggerListenerNames = LISTENER_NAMES;
CollectionAssert.AreEqual(LISTENER_NAMES, trigger.TriggerListenerNames, "Trigger listeners were not equal");
}
diff --git a/test/Spring/Spring.Scheduling.Quartz.Tests/Spring.Scheduling.Quartz.Tests.2005.csproj b/test/Spring/Spring.Scheduling.Quartz.Tests/Spring.Scheduling.Quartz.Tests.2005.csproj
index c20f1273..34a3e208 100644
--- a/test/Spring/Spring.Scheduling.Quartz.Tests/Spring.Scheduling.Quartz.Tests.2005.csproj
+++ b/test/Spring/Spring.Scheduling.Quartz.Tests/Spring.Scheduling.Quartz.Tests.2005.csproj
@@ -58,11 +58,18 @@
{E823D54C-CE82-4868-929F-5F95A999F61E}
Spring.Scheduling.Quartz.2005
+
+ {44B16BAA-6DF8-447C-9D7F-3AD3D854D904}
+ Spring.Core.Tests.2005
+
+
+
+
@@ -76,6 +83,23 @@
PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+
+ PreserveNewest
+
+