Update of /cvsroot/springnet/Spring.Net.Integration/projects/Spring.Scheduling.Quartz/src/Spring/Spring.Scheduling.Quartz/Scheduling/Quartz
In directory sc8-pr-cvs8.sourceforge.net:/tmp/cvs-serv24084/src/Spring/Spring.Scheduling.Quartz/Scheduling/Quartz
Added Files:
AdaptableJobFactory.cs CronTriggerObject.cs DelegatingJob.cs
IJobDetailAwareTrigger.cs ISchedulerContextAware.cs
ISchedulingTaskExecutor.cs ITaskExecutor.cs JobDetailObject.cs
LocalTaskExecutorThreadPool.cs MethodInvokingJob.cs
MethodInvokingJobDetailFactoryBean.cs
MethodInvokingJobDetailFactoryObject.cs
MethodInvokingRunnable.cs QuartzJobObject.cs
ResourceJobSchedulingDataProcessor.cs
SchedulerFactoryObject.cs SchedulingException.cs
SimpleThreadPoolTaskExecutor.cs SimpleTriggerObject.cs
SpringObjectJobFactory.cs StatefulMethodInvokingJob.cs
TaskRejectedException.cs
Log Message:
add initial quartrz integration support from Marko Lahma
--- NEW FILE: MethodInvokingRunnable.cs ---
/*
* Copyright 2002-2006 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.Reflection;
using Common.Logging;
using Quartz;
using Spring.Objects.Factory;
using Spring.Objects.Support;
namespace Spring.Scheduling.Quartz.scheduling.support
{
/// <summary>
/// Adapter that implements the Runnable interface as a configurable
/// method invocation based on Spring's MethodInvoker.
/// </summary>
/// <remarks>
/// <p>
/// Derives from ArgumentConvertingMethodInvoker, inheriting common
/// configuration properties from MethodInvoker.
/// </p>
///
/// <p>
/// Useful to generically encapsulate a method invocation as timer task for
/// <code>java.util.Timer</code>, in combination with a DelegatingTimerTask adapter.
/// Can also be used with JDK 1.5's <code>java.util.concurrent.Executor</code>
/// abstraction, which works with plain Runnables.
/// </p>
/// <p>
/// Extended by Spring's MethodInvokingTimerTaskFactoryObject adapter
/// for <code>TimerTask</code>. Note that you can populate a
/// ScheduledTimerTask object with a plain MethodInvokingRunnable instance
/// as well, which will automatically get wrapped with a DelegatingTimerTask.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <seealso cref="MethodInvoker" />
/// <seealso cref="ArgumentConvertingMethodInvoker" />
public class MethodInvokingRunnable : ArgumentConvertingMethodInvoker, IInitializingObject, IThreadRunnable
{
protected ILog logger;
/// <summary>
/// Initializes a new instance of the <see cref="MethodInvokingRunnable"/> class.
/// </summary>
public MethodInvokingRunnable()
{
logger = LogManager.GetLogger(GetType());
}
protected virtual string InvocationFailureMessage
{
get { return string.Format("Invocation of method '{0}' on target object [{1}] failed", TargetMethod, TargetObject); }
}
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// after it has injected all of an object's dependencies.
/// </summary>
/// <remarks>
/// <p>
/// This method allows the object instance to perform the kind of
/// initialization only possible when all of it's dependencies have
/// been injected (set), and to throw an appropriate exception in the
/// event of misconfiguration.
/// </p>
/// <p>
/// Please do consult the class level documentation for the
/// <see cref="Spring.Objects.Factory.IObjectFactory"/> interface for a
/// description of exactly <i>when</i> this method is invoked. In
/// particular, it is worth noting that the
/// <see cref="Spring.Objects.Factory.IObjectFactoryAware"/>
/// and <see cref="Spring.Context.IApplicationContextAware"/>
/// callbacks will have been invoked <i>prior</i> to this method being
/// called.
/// </p>
/// </remarks>
/// <exception cref="System.Exception">
/// In the event of misconfiguration (such as the failure to set a
/// required property) or if initialization fails.
/// </exception>
public virtual void AfterPropertiesSet()
{
Prepare();
}
/// <summary>
/// This method has to be implemented in order that starting of the thread causes the object's
/// run method to be called in that separately executing thread.
/// </summary>
public virtual void Run()
{
try
{
Invoke();
}
catch (TargetInvocationException ex)
{
logger.Error(InvocationFailureMessage, ex);
// Do not throw exception, else the main loop of the Timer will stop!
}
catch (Exception ex)
{
logger.Error(InvocationFailureMessage, ex);
// Do not throw exception, else the main loop of the Timer will stop!
}
}
}
}
--- NEW FILE: LocalTaskExecutorThreadPool.cs ---
/*
* Copyright 2002-2006 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;
using Common.Logging;
using Quartz;
using Quartz.Spi;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Quartz ThreadPool adapter that delegates to a Spring-managed
/// TaskExecutor instance, specified on SchedulerFactoryObject.
/// </summary>
/// <author>Juergen Hoeller</author>
/// <seealso cref="SchedulerFactoryObject.TaskExecutor" />
public class LocalTaskExecutorThreadPool : IThreadPool
{
/// <summary>
/// Logger available to subclasses.
/// </summary>
protected ILog logger;
private ITaskExecutor taskExecutor;
/// <summary>
/// Initializes a new instance of the <see cref="LocalTaskExecutorThreadPool"/> class.
/// </summary>
public LocalTaskExecutorThreadPool()
{
logger = LogManager.GetLogger(GetType());
}
/// <summary>
/// Gets the size of the pool.
/// </summary>
/// <value>The size of the pool.</value>
public virtual int PoolSize
{
get { return - 1; }
}
/// <summary>
/// Called by the QuartzScheduler before the <see cref="T:System.Threading.ThreadPool"/> is
/// used, in order to give the it a chance to Initialize.
/// </summary>
public virtual void Initialize()
{
// Absolutely needs thread-bound TaskExecutor to Initialize.
taskExecutor = SchedulerFactoryObject.ConfigTimeTaskExecutor;
if (taskExecutor == null)
{
throw new SchedulerConfigException("No local TaskExecutor found for configuration - " +
"'taskExecutor' property must be set on SchedulerFactoryObject");
}
}
/// <summary>
/// Called by the QuartzScheduler to inform the <see cref="T:System.Threading.ThreadPool"/>
/// that it should free up all of it's resources because the scheduler is
/// shutting down.
/// </summary>
/// <param name="waitForJobsToComplete"></param>
public virtual void Shutdown(bool waitForJobsToComplete)
{
}
/// <summary>
/// Execute the given <see cref="T:Quartz.IThreadRunnable"/> in the next
/// available <see cref="T:System.Threading.Thread"/>.
/// </summary>
/// <param name="runnable"></param>
/// <returns></returns>
/// <remarks>
/// The implementation of this interface should not throw exceptions unless
/// there is a serious problem (i.e. a serious misconfiguration). If there
/// are no available threads, rather it should either queue the Runnable, or
/// block until a thread is available, depending on the desired strategy.
/// </remarks>
public virtual bool RunInThread(IThreadRunnable runnable)
{
if (runnable == null)
{
return false;
}
try
{
taskExecutor.Execute(new ThreadStart(runnable.Run));
return true;
}
catch (TaskRejectedException ex)
{
logger.Error("Task has been rejected by TaskExecutor", ex);
return false;
}
}
/// <summary>
/// Determines the number of threads that are currently available in in
/// the pool. Useful for determining the number of times
/// <see cref="M:Quartz.Spi.IThreadPool.RunInThread(Quartz.IThreadRunnable)"/> can be called before returning
/// false.
/// </summary>
/// <returns>
/// the number of currently available threads
/// </returns>
/// <remarks>
/// The implementation of this method should block until there is at
/// least one available thread.
/// </remarks>
public virtual int BlockForAvailableThreads()
{
// The present implementation always returns 1, making Quartz (1.6)
// always schedule any tasks that it feels like scheduling.
// This could be made smarter for specific TaskExecutors,
// for example calling <code>getMaximumPoolSize() - getActiveCount()</code>
// on a <code>java.util.concurrent.ThreadPoolExecutor</code>.
return 1;
}
}
}
--- NEW FILE: MethodInvokingJobDetailFactoryBean.cs ---
/*
* Copyright 2002-2006 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.Reflection;
using Common.Logging;
using Quartz;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Config;
using Spring.Objects.Support;
using Spring.Util;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// FactoryBean that exposes a JobDetail object that delegates job execution
/// to a specified (static or non-static) method. Avoids the need to implement
/// a one-line Quartz Job that just invokes an existing service method.
///
/// <p>
/// Derived from MethodInvoker to share common properties and behavior
/// with MethodInvokingFactoryBean.
/// </p>
///
/// <p>
/// Supports both concurrently running jobs and non-currently running
/// ones through the "concurrent" property. Jobs created by this
/// MethodInvokingJobDetailFactoryBean are by default volatile and durable
/// (according to Quartz terminology).
/// </p>
/// <p><b>NOTE: JobDetails created via this FactoryBean are <i>not</i>
/// serializable and thus not suitable for persistent job stores.</b>
/// You need to implement your own Quartz Job as a thin wrapper for each case
/// where you want a persistent job to delegate to a specific service method.
/// </p>
/// </summary>
/// <author>Juergen Hoeller</author>
/// <author>Alef Arendsen</author>
/// <seealso cref="#TargetObject" />
/// <seealso cref="#TargetMethod" />
/// <seealso cref="#Concurrent" />
/// <seealso cref="MethodInvokingFactoryObject">
public class MethodInvokingJobDetailFactoryBean : ArgumentConvertingMethodInvoker, IFactoryObject, IObjectNameAware,
IInitializingObject
{
private string name;
private string group;
private bool concurrent = true;
private string[] jobListenerNames;
private string objectName;
private JobDetail jobDetail;
public MethodInvokingJobDetailFactoryBean()
{
group = Scheduler.DEFAULT_GROUP;
}
/// <summary>
/// Set the name of the job.
/// Default is the bean name of this FactoryObject.
/// </summary>
/// <seealso cref="JobDetail.Name" />
public virtual string Name
{
set { name = value; }
}
/// <summary>
/// Set the group of the job.
/// Default is the default group of the Scheduler.
/// </summary>
/// <seealso cref="JobDetail.Group" />
/// <seealso cref="Scheduler_Fields.DEFAULT_GROUP" />
public virtual string Group
{
set { group = value; }
}
/// <summary>
/// Specify whether or not multiple jobs should be run in a concurrent
/// fashion. The behavior when one does not want concurrent jobs to be
/// executed is realized through adding the {@link StatefulJob} interface.
/// More information on stateful versus stateless jobs can be found
/// <a href="http://www.opensymphony.com/quartz/tutorial.html#jobsMore">here</a>.
/// <p>
/// The default setting is to run jobs concurrently.
/// </p>
/// </summary>
public virtual bool Concurrent
{
set { concurrent = value; }
}
/// <summary>
/// Set a list of JobListener names for this job, referring to
/// non-global JobListeners registered with the Scheduler.
/// <p>A JobListener name always refers to the name returned
/// by the JobListener implementation.
/// </summary>
/// <seealso cref="SchedulerFactoryObject.JobListeners" />
/// <seealso cref="IJobListener.Name" />
public virtual string[] JobListenerNames
{
set { jobListenerNames = value; }
}
public virtual string ObjectName
{
set { objectName = value; }
}
public virtual object GetObject()
{
return jobDetail;
}
public virtual Type ObjectType
{
get { return typeof (JobDetail); }
}
public virtual bool IsSingleton
{
get { return true; }
}
public virtual void AfterPropertiesSet()
{
Prepare();
// Use specific name if given, else fall back to object name.
string jobDetailName = (name != null ? name : objectName);
// Consider the concurrent flag to choose between stateful and stateless job.
Type jobClass = (concurrent ? typeof (MethodInvokingJob) : typeof (StatefulMethodInvokingJob));
// Build JobDetail instance.
jobDetail = new JobDetail(jobDetailName, group, jobClass);
jobDetail.JobDataMap.Put("methodInvoker", this);
jobDetail.Volatility = true;
jobDetail.Durability = true;
// Register job listener names.
if (jobListenerNames != null)
{
for (int i = 0; i < jobListenerNames.Length; i++)
{
jobDetail.AddJobListener(jobListenerNames[i]);
}
}
PostProcessJobDetail(jobDetail);
}
/// <summary>
/// Callback for post-processing the JobDetail to be exposed by this FactoryObject.
/// <p>
/// The default implementation is empty. Can be overridden in subclasses.
/// </p>
/// </summary>
/// <param name="jobDetail">the JobDetail prepared by this FactoryObject</param>
protected internal virtual void PostProcessJobDetail(JobDetail jobDetail)
{
}
/// <summary> Quartz Job implementation that invokes a specified method.
/// Automatically applied by MethodInvokingJobDetailFactoryBean.
/// </summary>
public class MethodInvokingJob : QuartzJobObject
{
private static readonly ILog logger = LogManager.GetLogger(typeof (MethodInvokingJob));
private MethodInvoker methodInvoker;
private string errorMessage;
/// <summary>
/// Set the MethodInvoker to use.
/// </summary>
public virtual MethodInvoker MethodInvoker
{
set
{
methodInvoker = value;
errorMessage =
string.Format("Could not invoke method '{0}' on target object [{1}]", methodInvoker.TargetMethod,
methodInvoker.TargetObject);
}
}
/// <summary> Invoke the method via the MethodInvoker.</summary>
protected override void ExecuteInternal(JobExecutionContext context)
{
try
{
methodInvoker.Invoke();
}
catch (TargetInvocationException ex)
{
logger.Warn(errorMessage, ex.GetBaseException());
if (ex.GetBaseException() is JobExecutionException)
{
throw ex.GetBaseException();
}
if (MethodInvokingJobDetailFactoryBean.oldJobExecutionExceptionConstructor !=
null)
{
Exception jobEx = (ex.GetBaseException() is Exception) ? (Exception) ex.GetBaseException() : ex;
throw (JobExecutionException)
ObjectUtils.InstantiateType(
Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryBean.
oldJobExecutionExceptionConstructor, new Object[] {errorMessage, jobEx, false});
}
else
{
throw new JobExecutionException(errorMessage, ex.GetBaseException());
}
}
catch (Exception ex)
{
logger.Warn(errorMessage, ex);
if (Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryBean.oldJobExecutionExceptionConstructor !=
null)
{
throw (JobExecutionException)
ObjectUtils.InstantiateType(
Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryBean.
oldJobExecutionExceptionConstructor, new object[] {errorMessage, ex, false});
}
else
{
throw new JobExecutionException(errorMessage, ex);
}
}
}
}
/// <summary>
/// Extension of the MethodInvokingJob, implementing the StatefulJob interface.
/// Quartz checks whether or not jobs are stateful and if so,
/// won't let jobs interfere with each other.
/// </summary>
public class StatefulMethodInvokingJob : MethodInvokingJob, IStatefulJob
{
// No implementation, just an addition of the tag interface StatefulJob
// in order to allow stateful method invoking jobs.
}
static MethodInvokingJobDetailFactoryBean()
{
oldJobExecutionExceptionConstructor =
ObjectUtils.getConstructorIfAvailable(typeof (JobExecutionException),
new Type[] {typeof (String), typeof (Exception), typeof (bool)});
}
}
}
--- NEW FILE: ResourceJobSchedulingDataProcessor.cs ---
/*
* 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.IO;
using Quartz.Xml;
using Spring.Context;
using Spring.Core.IO;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Subclass of Quartz' JobSchedulingDataProcessor that considers
/// given filenames as Spring resource locations.
/// </summary>
/// <author>Juergen Hoeller</author>
/// <seealso cref="IResourceLoader" />
public class ResourceJobSchedulingDataProcessor : JobSchedulingDataProcessor, IResourceLoaderAware
{
private IResourceLoader resourceLoader;
/// <summary>
/// Initializes a new instance of the <see cref="ResourceJobSchedulingDataProcessor"/> class.
/// </summary>
public ResourceJobSchedulingDataProcessor()
{
resourceLoader = new ConfigurableResourceLoader();
}
/// <summary>
/// Gets and sets the <see cref="Spring.Core.IO.IResourceLoader"/>
/// that this object runs in.
/// </summary>
/// <value></value>
/// <remarks>
/// Invoked <b>after</b> population of normal objects properties but
/// before an init callback such as
/// <see cref="Spring.Objects.Factory.IInitializingObject"/>'s
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet()"/>
/// or a custom init-method. Invoked <b>before</b> setting
/// <see cref="Spring.Context.IApplicationContextAware"/>'s
/// <see cref="Spring.Context.IApplicationContextAware.ApplicationContext"/>
/// property.
/// </remarks>
public virtual IResourceLoader ResourceLoader
{
set { resourceLoader = (value != null ? value : new ConfigurableResourceLoader()); }
get { return resourceLoader; }
}
protected override Stream GetInputStream(string fileName)
{
try
{
return resourceLoader.GetResource(fileName).InputStream;
}
catch (IOException ex)
{
throw new SchedulingException("Could not load job scheduling data XML file", ex);
}
}
}
}
--- NEW FILE: MethodInvokingJobDetailFactoryObject.cs ---
/*
* Copyright 2002-2006 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 Quartz;
using Spring.Objects.Factory;
using Spring.Objects.Factory.Config;
using Spring.Objects.Support;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// IFactoryObject that exposes a JobDetail object that delegates job execution
/// to a specified (static or non-static) method. Avoids the need to implement
/// a one-line Quartz Job that just invokes an existing service method.
/// </summary>
/// <remarks>
/// <p>
/// Derived from ArgumentConverting MethodInvoker to share common properties and behavior
/// with MethodInvokingFactoryObject.
/// </p>
/// <p>
/// Supports both concurrently running jobs and non-currently running
/// ones through the "concurrent" property. Jobs created by this
/// MethodInvokingJobDetailFactoryObject are by default volatile and durable
/// (according to Quartz terminology).
/// </p>
/// <p><b>NOTE: JobDetails created via this FactoryObject are <i>not</i>
/// serializable and thus not suitable for persistent job stores.</b>
/// You need to implement your own Quartz Job as a thin wrapper for each case
/// where you want a persistent job to delegate to a specific service method.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <author>Alef Arendsen</author>
/// <seealso cref="Concurrent" />
/// <seealso cref="MethodInvokingFactoryObject" />
public class MethodInvokingJobDetailFactoryObject : ArgumentConvertingMethodInvoker, IFactoryObject, IObjectNameAware,
IInitializingObject
{
private string name;
private string group;
private bool concurrent = true;
private string[] jobListenerNames;
private string objectName;
private JobDetail jobDetail;
/// <summary>
/// Initializes a new instance of the <see cref="MethodInvokingJobDetailFactoryObject"/> class.
/// </summary>
public MethodInvokingJobDetailFactoryObject()
{
group = SchedulerConstants.DEFAULT_GROUP;
}
/// <summary>
/// Set the name of the job.
/// Default is the object name of this FactoryObject.
/// </summary>
/// <seealso cref="JobDetail.Name" />
public virtual string Name
{
set { name = value; }
}
/// <summary>
/// Set the group of the job.
/// Default is the default group of the Scheduler.
/// </summary>
/// <seealso cref="JobDetail.Group" />
/// <seealso cref="SchedulerConstants.DEFAULT_GROUP" />
public virtual string Group
{
set { group = value; }
}
/// <summary>
/// Specify whether or not multiple jobs should be run in a concurrent
/// fashion. The behavior when one does not want concurrent jobs to be
/// executed is realized through adding the <see cref="IStatefulJob" /> interface.
/// More information on stateful versus stateless jobs can be found
/// <a href="http://www.opensymphony.com/quartz/tutorial.html#jobsMore">here</a>.
/// <p>
/// The default setting is to run jobs concurrently.
/// </p>
/// </summary>
public virtual bool Concurrent
{
set { concurrent = value; }
}
/// <summary>
/// Set a list of JobListener names for this job, referring to
/// non-global JobListeners registered with the Scheduler.
/// </summary>
/// <remarks>
/// A JobListener name always refers to the name returned
/// by the JobListener implementation.
/// </remarks>
/// <seealso cref="SchedulerFactoryObject.JobListeners" />
/// <seealso cref="IJobListener.Name" />
public virtual string[] JobListenerNames
{
set { jobListenerNames = value; }
}
/// <summary>
/// Set the name of the object in the object factory that created this object.
/// </summary>
/// <value>The name of the object in the factory.</value>
/// <remarks>
/// Invoked after population of normal object properties but before an init
/// callback like <see cref="Spring.Objects.Factory.IInitializingObject"/>'s
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
/// method or a custom init-method.
/// </remarks>
public virtual string ObjectName
{
set { objectName = value; }
}
/// <summary>
/// Return an instance (possibly shared or independent) of the object
/// managed by this factory.
/// </summary>
/// <returns>
/// An instance (possibly shared or independent) of the object managed by
/// this factory.
/// </returns>
/// <remarks>
/// <note type="caution">
/// If this method is being called in the context of an enclosing IoC container and
/// returns <see langword="null"/>, the IoC container will consider this factory
/// object as not being fully initialized and throw a corresponding (and most
/// probably fatal) exception.
/// </note>
/// </remarks>
public object GetObject()
{
return jobDetail;
}
/// <summary>
/// Return the <see cref="System.Type"/> of object that this
/// <see cref="Spring.Objects.Factory.IFactoryObject"/> creates, or
/// <see langword="null"/> if not known in advance.
/// </summary>
/// <value></value>
public virtual Type ObjectType
{
get { return typeof (JobDetail); }
}
/// <summary>
/// Is the object managed by this factory a singleton or a prototype?
/// </summary>
/// <value></value>
public virtual bool IsSingleton
{
get { return true; }
}
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// after it has injected all of an object's dependencies.
/// </summary>
/// <remarks>
/// <p>
/// This method allows the object instance to perform the kind of
/// initialization only possible when all of it's dependencies have
/// been injected (set), and to throw an appropriate exception in the
/// event of misconfiguration.
/// </p>
/// <p>
/// Please do consult the class level documentation for the
/// <see cref="Spring.Objects.Factory.IObjectFactory"/> interface for a
/// description of exactly <i>when</i> this method is invoked. In
/// particular, it is worth noting that the
/// <see cref="Spring.Objects.Factory.IObjectFactoryAware"/>
/// and <see cref="Spring.Context.IApplicationContextAware"/>
/// callbacks will have been invoked <i>prior</i> to this method being
/// called.
/// </p>
/// </remarks>
/// <exception cref="System.Exception">
/// In the event of misconfiguration (such as the failure to set a
/// required property) or if initialization fails.
/// </exception>
public virtual void AfterPropertiesSet()
{
Prepare();
// Use specific name if given, else fall back to object name.
string jobDetailName = (name != null ? name : objectName);
// Consider the concurrent flag to choose between stateful and stateless job.
Type jobClass = (concurrent ? typeof (MethodInvokingJob) : typeof (StatefulMethodInvokingJob));
// Build JobDetail instance.
jobDetail = new JobDetail(jobDetailName, group, jobClass);
jobDetail.JobDataMap.Put("methodInvoker", this);
jobDetail.Volatility = true;
jobDetail.Durability = true;
// Register job listener names.
if (jobListenerNames != null)
{
for (int i = 0; i < jobListenerNames.Length; i++)
{
jobDetail.AddJobListener(jobListenerNames[i]);
}
}
PostProcessJobDetail(jobDetail);
}
/// <summary>
/// Callback for post-processing the JobDetail to be exposed by this FactoryObject.
/// <p>
/// The default implementation is empty. Can be overridden in subclasses.
/// </p>
/// </summary>
/// <param name="detail">the JobDetail prepared by this FactoryObject</param>
protected virtual void PostProcessJobDetail(JobDetail detail)
{
}
}
}
--- NEW FILE: TaskRejectedException.cs ---
using System;
namespace Spring.Scheduling
{
/// <summary>
/// Summary description for TaskRejectedException.
/// </summary>
public class TaskRejectedException : ApplicationException
{
}
}
--- NEW FILE: JobDetailObject.cs ---
/*
* Copyright 2002-2006 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 Quartz;
using Spring.Context;
using Spring.Objects.Factory;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Convenience subclass of Quartz' JobDetail class that eases properties based
/// usage.
/// </summary>
/// <remarks>
/// <see cref="JobDetail" /> itself is already a object but lacks
/// sensible defaults. This class uses the Spring object name as job name,
/// and the Quartz default group ("DEFAULT") as job group if not specified.
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <seealso cref="JobDetail.Name" />
/// <seealso cref="JobDetail.Group" />
/// <seealso cref="SchedulerConstants.DEFAULT_GROUP" />
public class JobDetailObject : JobDetail, IObjectNameAware, IApplicationContextAware, IInitializingObject
{
private Type actualJobClass;
private string objectName;
private IApplicationContext applicationContext;
private string applicationContextJobDataKey;
/// <summary>
/// Overridden to support any job class, to allow a custom JobFactory
/// to adapt the given job class to the Quartz Job interface.
/// </summary>
/// <seealso cref="SchedulerFactoryObject.JobFactory" />
public virtual Type JobClass
{
get { return (actualJobClass != null ? actualJobClass : JobType); }
set
{
if (value != null && !typeof (IJob).IsAssignableFrom(value))
{
JobType = typeof (DelegatingJob);
actualJobClass = value;
}
else
{
JobType = value;
}
}
}
/// <summary>
/// Register objects in the JobDataMap via a given Map.
/// </summary>
/// <remarks>
/// These objects will be available to this Job only,
/// in contrast to objects in the SchedulerContext.
/// <p>
/// Note: When using persistent Jobs whose JobDetail will be kept in the
/// database, do not put Spring-managed objects or an ApplicationContext
/// reference into the JobDataMap but rather into the SchedulerContext.
/// </p>
/// </remarks>
/// <seealso cref="SchedulerFactoryObject.SchedulerContextAsMap" />
public virtual IDictionary JobDataAsMap
{
set { JobDataMap.PutAll(value); }
}
/// <summary>
/// Set a list of JobListener names for this job, referring to
/// non-global JobListeners registered with the Scheduler.
/// </summary>
/// <remarks>
/// A JobListener name always refers to the name returned
/// by the JobListener implementation.
/// </remarks>
/// <seealso cref="SchedulerFactoryObject.JobListeners" />
/// <seealso cref="IJobListener.Name" />
public virtual string[] JobListenerNamesAsSetProperty
{
set
{
for (int i = 0; i < value.Length; i++)
{
AddJobListener(value[i]);
}
}
}
/// <summary>
/// Set the name of the object in the object factory that created this object.
/// </summary>
/// <value>The name of the object in the factory.</value>
/// <remarks>
/// Invoked after population of normal object properties but before an init
/// callback like <see cref="Spring.Objects.Factory.IInitializingObject"/>'s
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
/// method or a custom init-method.
/// </remarks>
public virtual string ObjectName
{
set { objectName = value; }
}
/// <summary>
/// Set the <see cref="Spring.Context.IApplicationContext"/> that this
/// object runs in.
/// </summary>
/// <value></value>
/// <remarks>
/// <p>
/// Normally this call will be used to initialize the object.
/// </p>
/// <p>
/// Invoked after population of normal object properties but before an
/// init callback such as
/// <see cref="Spring.Objects.Factory.IInitializingObject"/>'s
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
/// or a custom init-method. Invoked after the setting of any
/// <see cref="Spring.Context.IResourceLoaderAware"/>'s
/// <see cref="Spring.Context.IResourceLoaderAware.ResourceLoader"/>
/// property.
/// </p>
/// </remarks>
/// <exception cref="Spring.Context.ApplicationContextException">
/// In the case of application context initialization errors.
/// </exception>
/// <exception cref="Spring.Objects.ObjectsException">
/// If thrown by any application context methods.
/// </exception>
/// <exception cref="Spring.Objects.Factory.ObjectInitializationException"/>
public virtual IApplicationContext ApplicationContext
{
set { applicationContext = value; }
get { return applicationContext; }
}
/// <summary>
/// Set the key of an IApplicationContext reference to expose in the JobDataMap,
/// for example "applicationContext". Default is none.
/// Only applicable when running in a Spring ApplicationContext.
/// </summary>
/// <remarks>
/// <p>
/// In case of a QuartzJobObject, the reference will be applied to the Job
/// instance as object property. An "applicationContext" attribute will correspond
/// to a "setApplicationContext" method in that scenario.
/// </p>
/// <p>
/// Note that ObjectFactory callback interfaces like IApplicationContextAware
/// are not automatically applied to Quartz Job instances, because Quartz
/// itself is responsible for the lifecycle of its Jobs.
/// </p>
/// <p>
/// <b>Note: When using persistent job stores where JobDetail contents will
/// be kept in the database, do not put an IApplicationContext reference into
/// the JobDataMap but rather into the SchedulerContext.</b>
/// </p>
/// </remarks>
/// <seealso cref="SchedulerFactoryObject.ApplicationContextSchedulerContextKey" />
/// <seealso cref="IApplicationContext" />
public virtual string ApplicationContextJobDataKey
{
set { applicationContextJobDataKey = value; }
}
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// after it has injected all of an object's dependencies.
/// </summary>
/// <remarks>
/// <p>
/// This method allows the object instance to perform the kind of
/// initialization only possible when all of it's dependencies have
/// been injected (set), and to throw an appropriate exception in the
/// event of misconfiguration.
/// </p>
/// <p>
/// Please do consult the class level documentation for the
/// <see cref="Spring.Objects.Factory.IObjectFactory"/> interface for a
/// description of exactly <i>when</i> this method is invoked. In
/// particular, it is worth noting that the
/// <see cref="Spring.Objects.Factory.IObjectFactoryAware"/>
/// and <see cref="Spring.Context.IApplicationContextAware"/>
/// callbacks will have been invoked <i>prior</i> to this method being
/// called.
/// </p>
/// </remarks>
/// <exception cref="System.Exception">
/// In the event of misconfiguration (such as the failure to set a
/// required property) or if initialization fails.
/// </exception>
public virtual void AfterPropertiesSet()
{
if (Name == null)
{
Name = objectName;
}
if (Group == null)
{
Group = SchedulerConstants.DEFAULT_GROUP;
}
if (applicationContextJobDataKey != null)
{
if (applicationContext == null)
{
throw new SystemException("JobDetailObject needs to be set up in an IApplicationContext " +
"to be able to handle an 'applicationContextJobDataKey'");
}
JobDataMap.Put(applicationContextJobDataKey, applicationContext);
}
}
}
}
--- NEW FILE: SchedulingException.cs ---
using System;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Generic scheduling exception.
/// </summary>
public class SchedulingException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="SchedulingException"/> class.
/// </summary>
/// <param name="message">The message.</param>
public SchedulingException(string message) : base(message)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="SchedulingException"/> class.
/// </summary>
/// <param name="message">The message.</param>
/// <param name="ex">The original exception.</param>
public SchedulingException(string message, Exception ex) : base(message, ex)
{
}
}
}
--- NEW FILE: SimpleThreadPoolTaskExecutor.cs ---
/*
* Copyright 2002-2006 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.Threading;
using Quartz;
using Quartz.Simpl;
using Spring.Objects.Factory;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Subclass of Quartz's SimpleThreadPool that implements Spring's
/// TaskExecutor interface and listens to Spring lifecycle callbacks.
/// </summary>
/// <author>Juergen Hoeller</author>
/// <seealso cref="SimpleThreadPool" />
/// <seealso cref="ITaskExecutor" />
/// <seealso cref="SchedulerFactoryObject.TaskExecutor" />
public class SimpleThreadPoolTaskExecutor : SimpleThreadPool, ISchedulingTaskExecutor, IInitializingObject, IDisposable
{
private bool waitForJobsToCompleteOnShutdown = false;
/// <summary>
/// Set whether to wait for running jobs to complete on Shutdown.
/// Default is "false".
/// </summary>
/// <value>
/// <c>true</c> if [wait for jobs to complete on shutdown]; otherwise, <c>false</c>.
/// </value>
/// <seealso cref="SimpleThreadPool.Shutdown(bool)"/>
public virtual bool WaitForJobsToCompleteOnShutdown
{
set { waitForJobsToCompleteOnShutdown = value; }
}
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// after it has injected all of an object's dependencies.
/// </summary>
/// <remarks>
/// <p>
/// This method allows the object instance to perform the kind of
/// initialization only possible when all of it's dependencies have
/// been injected (set), and to throw an appropriate exception in the
/// event of misconfiguration.
/// </p>
/// <p>
/// Please do consult the class level documentation for the
/// <see cref="Spring.Objects.Factory.IObjectFactory"/> interface for a
/// description of exactly <i>when</i> this method is invoked. In
/// particular, it is worth noting that the
/// <see cref="Spring.Objects.Factory.IObjectFactoryAware"/>
/// and <see cref="Spring.Context.IApplicationContextAware"/>
/// callbacks will have been invoked <i>prior</i> to this method being
/// called.
/// </p>
/// </remarks>
/// <exception cref="System.Exception">
/// In the event of misconfiguration (such as the failure to set a
/// required property) or if initialization fails.
/// </exception>
public virtual void AfterPropertiesSet()
{
Initialize();
}
/// <summary>
/// Executes the specified task.
/// </summary>
/// <param name="task">The task.</param>
public virtual void Execute(ThreadStart task)
{
if (task == null)
{
throw new ArgumentException("Runnable must not be null", "task");
}
if (!RunInThread(new ThreadRunnableDelegate(task)))
{
throw new SchedulingException("Quartz SimpleThreadPool already shut down");
}
}
/// <summary> This task executor prefers short-lived work units.</summary>
public virtual bool PrefersShortLivedTasks
{
get { return true; }
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public virtual void Dispose()
{
Shutdown(waitForJobsToCompleteOnShutdown);
}
internal class ThreadRunnableDelegate : IThreadRunnable
{
private ThreadStart ts;
public ThreadRunnableDelegate(ThreadStart ts)
{
this.ts = ts;
}
public void Run()
{
ts.Invoke();
}
}
}
}
--- NEW FILE: IJobDetailAwareTrigger.cs ---
/*
* 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 Quartz;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Interface to be implemented by Quartz Triggers that are aware
/// of the JobDetail object that they are associated with.
/// </summary>
/// <remarks>
/// <p>
/// SchedulerFactoryObject will auto-detect Triggers that implement this
/// interface and register them for the respective JobDetail accordingly.
/// </p>
///
/// <p>
/// The alternative is to configure a Trigger for a Job name and group:
/// This involves the need to register the JobDetail object separately
/// with SchedulerFactoryObject.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <seealso cref="SchedulerFactoryObject.Triggers" />
/// <seealso cref="SchedulerFactoryObject.JobDetails" />
/// <seealso cref="Trigger.JobName" />
/// <seealso cref="Trigger.JobGroup" />
public interface IJobDetailAwareTrigger
{
/// <summary>
/// Return the JobDetail that this Trigger is associated with.
/// </summary>
/// <returns>The associated JobDetail, or <code>null</code> if none</returns>
JobDetail JobDetail { get; }
}
}
--- NEW FILE: AdaptableJobFactory.cs ---
/*
* Copyright 2002-2006 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.Threading;
using Quartz;
using Quartz.Spi;
using Quartz.Util;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// JobFactory implementation that supports <see cref="ThreadStart" />
/// objects as well as standard Quartz <see cref="IJob" /> instances.
/// </summary>
/// <author>Juergen Hoeller</author>
/// <author>Marko Lahma (.NET)</author>
/// <seealso cref="DelegatingJob" />
/// <seealso cref="AdaptJob(object)" />
public class AdaptableJobFactory : IJobFactory
{
/// <summary>
/// Called by the scheduler at the time of the trigger firing, in order to
/// produce a <see cref="IJob"/> instance on which to call Execute.
/// </summary>
/// <remarks>
/// It should be extremely rare for this method to throw an exception -
/// basically only the the case where there is no way at all to instantiate
/// and prepare the Job for execution. When the exception is thrown, the
/// Scheduler will move all triggers associated with the Job into the
/// <see cref="TriggerState.Error"/> state, which will require human
/// intervention (e.g. an application restart after fixing whatever
/// configuration problem led to the issue wih instantiating the Job.
/// </remarks>
/// <param name="bundle">The TriggerFiredBundle from which the <see cref="JobDetail"/>
/// and other info relating to the trigger firing can be obtained.</param>
/// <returns>the newly instantiated Job</returns>
/// <throws>SchedulerException if there is a problem instantiating the Job.</throws>
public virtual IJob NewJob(TriggerFiredBundle bundle)
{
try
{
object jobObject = CreateJobInstance(bundle);
return AdaptJob(jobObject);
}
catch (Exception ex)
{
throw new SchedulerException("Job instantiation failed", ex);
}
}
/// <summary>
/// Create an instance of the specified job class.
/// <p>
/// Can be overridden to post-process the job instance.
/// </p>
/// </summary>
/// <param name="bundle">
/// The TriggerFiredBundle from which the JobDetail
/// and other info relating to the trigger firing can be obtained.
/// </param>
/// <returns>The job instance.</returns>
protected virtual object CreateJobInstance(TriggerFiredBundle bundle)
{
return ObjectUtils.InstantiateType(bundle.JobDetail.JobType);
}
/// <summary>
/// Adapt the given job object to the Quartz Job interface.
/// </summary>
/// <remarks>
/// The default implementation supports straight Quartz Jobs
/// as well as Runnables, which get wrapped in a DelegatingJob.
/// </remarks>
/// <param name="jobObject">
/// The original instance of the specified job class.
/// </param>
/// <returns>The adapted Quartz Job instance.</returns>
/// <seealso cref="DelegatingJob" />
protected virtual IJob AdaptJob(object jobObject)
{
if (jobObject is IJob)
{
return (IJob) jobObject;
}
else if (jobObject is ThreadStart)
{
return new DelegatingJob((ThreadStart)jobObject);
}
else
{
throw new ArgumentException(
string.Format("Unable to execute job class [{0}]: only [IJob] and [ThreadStart] supported.",
jobObject.GetType().FullName));
}
}
}
}
--- NEW FILE: CronTriggerObject.cs ---
/*
* Copyright 2002-2007 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.Reflection;
using Quartz;
using Spring.Objects.Factory;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Convenience subclass of Quartz's CronTrigger type, making property based
/// usage easier.
/// </summary>
/// <remarks>
/// <p>
/// CronTrigger itself is already property based but lacks sensible defaults.
/// This class uses the Spring object name as job name, the Quartz default group
/// ("DEFAULT") as job group, the current time as start time, and indefinite
/// repetition, if not specified.
/// </p>
/// <p>
/// This class will also register the trigger with the job name and group of
/// a given <see cref="JobDetail" />. This allows <see cref="SchedulerFactoryObject" />
/// to automatically register a trigger for the corresponding JobDetail,
/// instead of registering the JobDetail separately.
/// </p>
/// <p><b>NOTE:</b> This convenience subclass does not work with trigger
/// persistence in Quartz, due Quartz's trigger handling.
/// You shouldn't use this class if you rely on trigger persistence based on this class
/// You can always use the standard Quartz <see cref="CronTrigger" /> class instead.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <seealso cref="Trigger.Name" />
/// <seealso cref="Trigger.Group" />
/// <seealso cref="Trigger.StartTime" />
/// <seealso cref="Trigger.JobName" />
/// <seealso cref="Trigger.JobGroup" />
/// <seealso cref="JobDetail" />
/// <seealso cref="SchedulerFactoryObject.Triggers" />
/// <seealso cref="SchedulerFactoryObject.JobDetails" />
public class CronTriggerObject : CronTrigger, IJobDetailAwareTrigger, IObjectNameAware, IInitializingObject
{
private JobDetail jobDetail;
private string objectName;
private readonly Constants constants = new Constants(typeof(CronTrigger));
/// <summary>
/// Register objects in the JobDataMap via a given Map.
/// </summary>
/// <remarks>
/// These objects will be available to this Trigger only,
/// in contrast to objects in the JobDetail's data map.
/// </remarks>
/// <seealso cref="JobDetailObject.JobDataAsMap" />
public virtual IDictionary JobDataAsMap
{
set { JobDataMap.PutAll(value); }
}
/// <summary>
/// Set the misfire instruction via the name of the corresponding
/// constant in the CronTrigger class.
/// Default is <code>MISFIRE_INSTRUCTION_SMART_POLICY</code>.
/// </summary>
/// <seealso cref="CronTrigger.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW" />
/// <seealso cref="CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING" />
/// <seealso cref="Trigger.MISFIRE_INSTRUCTION_SMART_POLICY" />
public virtual string MisfireInstructionName
{
set
{
MisfireInstruction = constants.AsNumber(value);
}
}
/// <summary>
/// Set the name of the object in the object factory that created this object.
/// </summary>
/// <value>The name of the object in the factory.</value>
/// <remarks>
/// <p>
/// Invoked after population of normal object properties but before an init
/// callback like <see cref="Spring.Objects.Factory.IInitializingObject"/>'s
/// <see cref="Spring.Objects.Factory.IInitializingObject.AfterPropertiesSet"/>
/// method or a custom init-method.
/// </p>
/// </remarks>
public virtual string ObjectName
{
set { objectName = value; }
}
/// <summary>
/// Set the JobDetail that this trigger should be associated with.
/// </summary>
/// <remarks>
/// This is typically used with a object reference if the JobDetail
/// is a Spring-managed object. Alternatively, the trigger can also
/// be associated with a job by name and group.
/// </remarks>
/// <seealso cref="Trigger.JobName" />
/// <seealso cref="Trigger.JobGroup" />
public virtual JobDetail JobDetail
{
get { return jobDetail; }
set { jobDetail = value; }
}
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// after it has injected all of an object's dependencies.
/// </summary>
/// <remarks>
/// <p>
/// This method allows the object instance to perform the kind of
/// initialization only possible when all of it's dependencies have
/// been injected (set), and to throw an appropriate exception in the
/// event of misconfiguration.
/// </p>
/// <p>
/// Please do consult the class level documentation for the
/// <see cref="Spring.Objects.Factory.IObjectFactory"/> interface for a
/// description of exactly <i>when</i> this method is invoked. In
/// particular, it is worth noting that the
/// <see cref="Spring.Objects.Factory.IObjectFactoryAware"/>
/// and <see cref="Spring.Context.IApplicationContextAware"/>
/// callbacks will have been invoked <i>prior</i> to this method being
/// called.
/// </p>
/// </remarks>
/// <exception cref="System.Exception">
/// In the event of misconfiguration (such as the failure to set a
/// required property) or if initialization fails.
/// </exception>
public virtual void AfterPropertiesSet()
{
if (Name == null)
{
Name = objectName;
}
if (Group == null)
{
Group = SchedulerConstants.DEFAULT_GROUP;
}
if (StartTime == DateTime.MinValue)
{
StartTime = DateTime.Now;
}
if (TimeZone == null)
{
TimeZone = TimeZone.CurrentTimeZone;
}
if (jobDetail != null)
{
JobName = jobDetail.Name;
JobGroup = jobDetail.Group;
}
}
}
/// <summary>
/// Helper class to map constant names to their values.
/// </summary>
internal class Constants
{
private readonly Type type;
public Constants(Type reflectedType)
{
type = reflectedType;
}
public int AsNumber(string field)
{
FieldInfo fi = type.GetField(field, BindingFlags.Static);
if (fi != null)
{
return Convert.ToInt32(fi.GetValue(null));
}
else
{
throw new Exception(string.Format("Unknown field '{0}'", field));
}
}
}
}
--- NEW FILE: SchedulerFactoryObject.cs ---
/*
* Copyright 2002-2006 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.Collections.Specialized;
[...1035 lines suppressed...]
if (Enclosing_Instance.logger.IsInfoEnabled)
{
Enclosing_Instance.logger.Info("Starting Quartz Scheduler now, after delay of " +
Enclosing_Instance.startupDelay +
" seconds");
}
try
{
Enclosing_Instance.scheduler.Start();
}
catch (SchedulerException ex)
{
throw new SchedulingException("Could not start Quartz Scheduler after delay", ex);
}
}
}
#endregion
}
}
--- NEW FILE: QuartzJobObject.cs ---
/*
* Copyright 2002-2006 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 Quartz;
using Spring.Objects;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Simple implementation of the Quartz Job interface, applying the
/// passed-in JobDataMap and also the SchedulerContext as object property
/// values. This is appropriate because a new Job instance will be created
/// for each execution. JobDataMap entries will override SchedulerContext
/// entries with the same keys.
/// </summary>
/// <remarks>
/// <p>
/// For example, let's assume that the JobDataMap contains a key
/// "myParam" with value "5": The Job implementation can then expose
/// a object property "myParam" of type int to receive such a value,
/// i.e. a method "setMyParam(int)". This will also work for complex
/// types like business objects etc.
/// </p>
///
/// <p>
/// Note: The QuartzJobObject class itself only implements the standard
/// Quartz IJob interface. Let your subclass explicitly implement the
/// Quartz IStatefulJob interface to mark your concrete job object as stateful.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <seealso cref="JobExecutionContext.MergedJobDataMap" />
/// <seealso cref="IScheduler.Context" />
/// <seealso cref="JobDetailObject.JobDataAsMap" />
/// <seealso cref="CronTriggerObject.JobDataAsMap" />
/// <seealso cref="SchedulerFactoryObject.SchedulerContextAsMap" />
/// <seealso cref="SpringObjectJobFactory" />
/// <seealso cref="SchedulerFactoryObject.JobFactory" />
public abstract class QuartzJobObject : IJob
{
/// <summary>
/// This implementation applies the passed-in job data map as object property
/// values, and delegates to <code>ExecuteInternal</code> afterwards.
/// </summary>
/// <seealso cref="ExecuteInternal" />
public void Execute(JobExecutionContext context)
{
try
{
ObjectWrapper bw = new ObjectWrapper(this);
MutablePropertyValues pvs = new MutablePropertyValues();
pvs.AddAll(context.Scheduler.Context);
pvs.AddAll(context.MergedJobDataMap);
bw.SetPropertyValues(pvs, true);
}
catch (SchedulerException ex)
...
[truncated message content] |