fixes #155 replace Quartz 2 integration with Quartz 3 integration

This commit is contained in:
Marko Lahma
2018-10-06 17:34:03 +03:00
parent 7ae40a632c
commit f468abfa83
90 changed files with 2277 additions and 2817 deletions

View File

@@ -65,16 +65,16 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Testing.Microsoft.Te
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Messaging.Ems", "src\Spring\Spring.Messaging.Ems\Spring.Messaging.Ems.csproj", "{900E3839-301E-48B1-BAEB-B6645620ACFF}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Scheduling.Quartz2", "src\Spring\Spring.Scheduling.Quartz2\Spring.Scheduling.Quartz2.csproj", "{E823D54C-CE82-4868-929F-5F95A999F123}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Scheduling.Quartz3", "src\Spring\Spring.Scheduling.Quartz3\Spring.Scheduling.Quartz3.csproj", "{E823D54C-CE82-4868-929F-5F95A999F123}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Scheduling.Quartz2.Tests", "test\Spring\Spring.Scheduling.Quartz2.Tests\Spring.Scheduling.Quartz2.Tests.csproj", "{247787CF-ECE1-4675-8B42-7DF4329A4891}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Scheduling.Quartz3.Integration.Tests", "test\Spring\Spring.Scheduling.Quartz3.Integration.Tests\Spring.Scheduling.Quartz3.Integration.Tests.csproj", "{8CF0F34A-CC93-4D87-AE14-A2DEEF072F26}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Scheduling.Quartz3.Tests", "test\Spring\Spring.Scheduling.Quartz3.Tests\Spring.Scheduling.Quartz3.Tests.csproj", "{247787CF-ECE1-4675-8B42-7DF4329A4891}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Messaging.Ems.Integration.Tests", "test\Spring\Spring.Messaging.Ems.Integration.Tests\Spring.Messaging.Ems.Integration.Tests.csproj", "{FA934E92-C8C2-428A-BE2A-26818F17A787}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Messaging.Nms.Integration.Tests", "test\Spring\Spring.Messaging.Nms.Integration.Tests\Spring.Messaging.Nms.Integration.Tests.csproj", "{E5323AC8-137E-4EF7-BC62-3BD6FC0576CD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Scheduling.Quartz2.Integration.Tests", "test\Spring\Spring.Scheduling.Quartz2.Integration.Tests\Spring.Scheduling.Quartz2.Integration.Tests.csproj", "{8CF0F34A-CC93-4D87-AE14-A2DEEF072F26}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Web.Conversation.NHibernate5", "src\Spring\Spring.Web.Conversation.NHibernate5\Spring.Web.Conversation.NHibernate5.csproj", "{CF375928-B6D5-485C-B04D-2BC41D9DBF1E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spring.Web.Conversation.NHibernate5.Tests", "test\Spring\Spring.Web.Conversation.NHibernate5.Tests\Spring.Web.Conversation.NHibernate5.Tests.csproj", "{C57B05EA-FD1A-40EC-BB60-D2E45AB1A86A}"

View File

@@ -1,4 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/FileHeader/FileHeaderRegionName/@EntryValue">License</s:String>
<s:String x:Key="/Default/CodeStyle/FileHeader/FileHeaderText/@EntryValue">/*&#xD;
* Copyright 2018 the original author or authors.&#xD;
@@ -15,6 +19,7 @@
* See the License for the specific language governing permissions and&#xD;
* limitations under the License.&#xD;
*/</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateInstanceFields/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FCONSTANT/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FFUNCTION/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/JavaScriptNaming/UserRules/=JS_005FBLOCK_005FSCOPE_005FVARIABLE/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" /&gt;</s:String>

View File

@@ -417,6 +417,7 @@ Commandline Examples:
<include name="${spring.basedir}/test/Spring/Spring.Testing.NUnit.Tests/Spring.Testing.NUnit.Tests.csproj" />
<include name="${spring.basedir}/test/Spring/Spring.Data.NHibernate5.Integration.Tests/Spring.Data.NHibernate5.Integration.Tests.csproj" />
<include name="${spring.basedir}/test/Spring/Spring.Data.NHibernate5.Tests/Spring.Data.NHibernate5.Tests.csproj" />
<include name="${spring.basedir}/test/Spring/Spring.Scheduling.Quartz3.Tests/Spring.Scheduling.Quartz3.Tests.csproj" />
</items>
</in>
<do>
@@ -1071,9 +1072,9 @@ Commandline Examples:
<include name="*/*/Spring.Messaging.xml"/>
<include name="*/*/Spring.Messaging.pdb"/>
<include name="*/*/Spring.Scheduling.Quartz2.dll"/>
<include name="*/*/Spring.Scheduling.Quartz2.xml"/>
<include name="*/*/Spring.Scheduling.Quartz2.pdb"/>
<include name="*/*/Spring.Scheduling.Quartz3.dll"/>
<include name="*/*/Spring.Scheduling.Quartz3.xml"/>
<include name="*/*/Spring.Scheduling.Quartz3.pdb"/>
<include name="*/*/Spring.Template.Velocity.dll"/>
<include name="*/*/Spring.Template.Velocity.xml"/>
@@ -1277,7 +1278,7 @@ Commandline Examples:
<include name="src/Spring/Spring.Messaging/**"/>
<include name="src/Spring/Spring.Messaging.Nms/**"/>
<include name="src/Spring/Spring.Messaging.Ems/**"/>
<include name="src/Spring/Spring.Scheduling.Quartz2/**"/>
<include name="src/Spring/Spring.Scheduling.Quartz3/**"/>
<include name="src/Spring/Spring.Template.Velocity/**"/>
<include name="src/Spring/Spring.Testing.NUnit/**"/>
<include name="src/Spring/Spring.Testing.Microsoft/**"/>
@@ -1298,7 +1299,7 @@ Commandline Examples:
<include name="test/Spring/Spring.Messaging.Nms.Tests/**"/>
<include name="test/Spring/Spring.Messaging.Nms.Integration.Tests/**"/>
<include name="test/Spring/Spring.Messaging.Ems.Tests/**"/>
<include name="test/Spring/Spring.Scheduling.Quartz2.Tests/**"/>
<include name="test/Spring/Spring.Scheduling.Quartz3.Tests/**"/>
<include name="test/Spring/Spring.Template.Velocity.Tests/**"/>
<include name="test/Spring/Spring.Testing.NUnit.Tests/**"/>
<include name="test/Spring/Spring.Testing.Microsoft.Tests/**"/>

View File

@@ -10,6 +10,7 @@ Release Notes - Spring.NET - Version 3.0.0
Breaking Changes
* .NET 4.5.2 is the lowest full framework supported
* Tranasaction definitions no longer have EnterpriseServicesInteropOption, it was replaced by TransactionScopeAsyncFlowOption
New Feature Highlights

View File

@@ -1,8 +0,0 @@
<?xml version="1.0" ?>
<project name="Spring.Scheduling.Quartz.Example" default="build" xmlns="http://nant.sf.net/schemas/nant.xsd">
<target name="build">
</target>
</project>

View File

@@ -5,6 +5,14 @@ VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Scheduling.Quartz.Example.2010", "src\Spring.Scheduling.Quartz.Example.csproj", "{0C0D8C65-90DE-4914-9940-4C684C54971B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Scheduling.Quartz3", "..\..\..\src\Spring\Spring.Scheduling.Quartz3\Spring.Scheduling.Quartz3.csproj", "{E397E260-643A-4929-8979-3483BF0C77CB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Core", "..\..\..\src\Spring\Spring.Core\Spring.Core.csproj", "{7BF79668-CD22-461B-BF82-5571E3E1119E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Data", "..\..\..\src\Spring\Spring.Data\Spring.Data.csproj", "{7FBD7BF1-B978-4DBC-BDBC-B8B20865E96D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spring.Aop", "..\..\..\src\Spring\Spring.Aop\Spring.Aop.csproj", "{6905DB1E-B4B7-4B5A-9E6F-72881BB6C98D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -15,6 +23,22 @@ Global
{0C0D8C65-90DE-4914-9940-4C684C54971B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0C0D8C65-90DE-4914-9940-4C684C54971B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0C0D8C65-90DE-4914-9940-4C684C54971B}.Release|Any CPU.Build.0 = Release|Any CPU
{E397E260-643A-4929-8979-3483BF0C77CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E397E260-643A-4929-8979-3483BF0C77CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E397E260-643A-4929-8979-3483BF0C77CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E397E260-643A-4929-8979-3483BF0C77CB}.Release|Any CPU.Build.0 = Release|Any CPU
{7BF79668-CD22-461B-BF82-5571E3E1119E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7BF79668-CD22-461B-BF82-5571E3E1119E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BF79668-CD22-461B-BF82-5571E3E1119E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BF79668-CD22-461B-BF82-5571E3E1119E}.Release|Any CPU.Build.0 = Release|Any CPU
{7FBD7BF1-B978-4DBC-BDBC-B8B20865E96D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7FBD7BF1-B978-4DBC-BDBC-B8B20865E96D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7FBD7BF1-B978-4DBC-BDBC-B8B20865E96D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7FBD7BF1-B978-4DBC-BDBC-B8B20865E96D}.Release|Any CPU.Build.0 = Release|Any CPU
{6905DB1E-B4B7-4B5A-9E6F-72881BB6C98D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6905DB1E-B4B7-4B5A-9E6F-72881BB6C98D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6905DB1E-B4B7-4B5A-9E6F-72881BB6C98D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6905DB1E-B4B7-4B5A-9E6F-72881BB6C98D}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@@ -1,34 +1,31 @@
using System;
using System.Threading.Tasks;
using Quartz;
namespace Spring.Scheduling.Quartz.Example
{
/// <summary>
/// Example job.
/// </summary>
/// <summary>
/// Example job.
/// </summary>
public class ExampleJob : QuartzJobObject
{
private string userName;
/// <summary>
/// Simple property that can be injected.
/// </summary>
/// <summary>
/// Simple property that can be injected.
/// </summary>
public string UserName
{
set { userName = value; }
set => userName = value;
}
/// <summary>
/// Execute.
/// </summary>
/// <param name="context"></param>
protected override void ExecuteInternal(IJobExecutionContext context)
/// <inheritdoc />
protected override Task ExecuteInternal(IJobExecutionContext context)
{
Console.WriteLine("{0}: ExecuteInternal called, user name: {1}, next fire time {2}",
DateTime.Now, userName, context.NextFireTimeUtc.Value.ToLocalTime());
}
Console.WriteLine(
$"{DateTime.Now}: ExecuteInternal called, user name: {userName}, next fire time {context.NextFireTimeUtc?.ToLocalTime()}");
return Task.FromResult(true);
}
}
}
}

View File

@@ -3,19 +3,13 @@
<TargetFramework>net452</TargetFramework>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<Reference Include="Spring.Core">
<HintPath>..\..\..\..\build\$(Configuration)\Spring.Core\$(TargetFramework)\Spring.Core.dll</HintPath>
</Reference>
<Reference Include="Spring.Scheduling.Quartz2">
<HintPath>..\..\..\..\build\$(Configuration)\Spring.Scheduling.Quartz2\$(TargetFramework)\Spring.Scheduling.Quartz2.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Content Include="spring-objects.xml" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Common.Logging" Version="$(CommonLoggingVersion)" />
<PackageReference Include="Quartz" Version="2.6.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Spring\Spring.Scheduling.Quartz3\Spring.Scheduling.Quartz3.csproj" />
</ItemGroup>
</Project>

View File

@@ -2,7 +2,7 @@
<objects xmlns="http://www.springframework.net" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
<object name="exampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz2">
<object name="exampleJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz3">
<property name="JobType" value="Spring.Scheduling.Quartz.Example.ExampleJob, Spring.Scheduling.Quartz.Example" />
<!-- We can inject values throgh JobDataMap -->
<property name="JobDataAsMap">
@@ -17,20 +17,20 @@
<property name="UserName" value="Gabriel" />
</object>
<object id="jobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz2">
<object id="jobDetail" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz3">
<!-- We don't actually need to implement IJob as we can use delegation -->
<property name="TargetObject" ref="adminService" />
<property name="TargetMethod" value="DoAdminWork" />
</object>
<object id="jobDetailNonConcurrent" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz2">
<object id="jobDetailNonConcurrent" type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz3">
<property name="targetObject" ref="adminService" />
<property name="targetMethod" value="DoAdminWork" />
<!-- Automatic IStatefulJob wrapping -->
<property name="concurrent" value="false" />
</object>
<object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz2">
<object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz3">
<!-- see the example of method invoking job above -->
<property name="jobDetail" ref="jobDetail" />
<!-- 5 seconds -->
@@ -40,13 +40,13 @@
</object>
<object id="cronTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz2">
<object id="cronTrigger" type="Spring.Scheduling.Quartz.CronTriggerObject, Spring.Scheduling.Quartz3">
<property name="jobDetail" ref="exampleJob" />
<!-- run every 20 second of minute -->
<property name="cronExpressionString" value="0/20 * * * * ?" />
</object>
<object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz2">
<object type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz3">
<property name="triggers">
<list>
<ref object="cronTrigger" />

View File

@@ -44,7 +44,11 @@
<ItemGroup Condition="'$(SourceLinkEnabled)' != 'false'">
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta-63127-02" PrivateAssets="All"/>
</ItemGroup>
</ItemGroup>
<ItemGroup>
<PackageReference Include="ConfigureAwaitChecker.Analyzer" Version="2.0.0" PrivateAssets="All" />
</ItemGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugType>Full</DebugType>

View File

@@ -16,18 +16,18 @@
* limitations under the License.
*/
#endregion
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
using AopAlliance.Intercept;
using Common.Logging;
using Spring.Core.TypeConversion;
#endregion
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Threading;
using AopAlliance.Intercept;
using Common.Logging;
using Spring.Core.TypeConversion;
using Spring.Expressions;
namespace Spring.Aspects
@@ -40,22 +40,22 @@ namespace Spring.Aspects
/// <remarks>
///
/// </remarks>
/// <author>Mark Pollack</author>
/// <author>Mark Pollack</author>
[Serializable]
public class RetryAdvice : AbstractExceptionHandlerAdvice
{
///<summary>
///The type of the callback that is called for delaying retries.
///</summary>
public delegate void SleepHandler(TimeSpan duration);
private static readonly ILog log;
private static readonly TimeSpanConverter timeSpanConverter;
{
///<summary>
///The type of the callback that is called for delaying retries.
///</summary>
public delegate void SleepHandler(TimeSpan duration);
private static readonly ILog log;
private static readonly TimeSpanConverter timeSpanConverter;
static RetryAdvice()
{
log = LogManager.GetLogger(typeof(RetryAdvice));
timeSpanConverter = new TimeSpanConverter();
{
log = LogManager.GetLogger(typeof(RetryAdvice));
timeSpanConverter = new TimeSpanConverter();
}
#region Fields
@@ -112,19 +112,20 @@ namespace Spring.Aspects
#endregion
/// <summary>
/// Creates a new RetryAdvice instance, using <see cref="Thread.Sleep(TimeSpan)"/> for delaying retries
/// <summary>
/// Creates a new RetryAdvice instance, using <see cref="Thread.Sleep(TimeSpan)"/> for delaying retries
/// </summary>
public RetryAdvice()
:this(new SleepHandler(Thread.Sleep))
{
}
/// <summary>
/// Creates a new RetryAdvice instance, using any arbitrary callback for delaying retries
/// </summary>
public RetryAdvice(SleepHandler sleepHandler)
{
public RetryAdvice()
:this(new SleepHandler(Thread.Sleep))
{
}
/// <summary>
/// Creates a new RetryAdvice instance, using any arbitrary callback for delaying retries
/// </summary>
public RetryAdvice(SleepHandler sleepHandler)
{
this.sleepHandler = sleepHandler;
}
#region IMethodInterceptor implementation
@@ -211,19 +212,19 @@ namespace Spring.Aspects
IExpression expression = Expression.Parse(handler.DelayRateExpression);
object result = expression.GetValue(null, callContextDictionary);
decimal d = decimal.Parse(result.ToString());
decimal d = decimal.Parse(result.ToString());
decimal rounded = decimal.Round(d*1000,0);
TimeSpan duration = TimeSpan.FromMilliseconds(decimal.ToDouble(rounded));
sleepHandler(duration);
}
catch (InvalidCastException e)
{
{
log.Warn("Was not able to cast expression to decimal [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
sleepHandler(new TimeSpan(0,0,1));
}
catch (Exception e)
{
{
log.Warn("Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
log.Warn("Was not able to evaluate rate expression [" + handler.DelayRateExpression + "]. Sleeping for 1 second", e);
sleepHandler(new TimeSpan(0,0,1));
}
}
}
@@ -341,18 +342,18 @@ namespace Spring.Aspects
RegexOptions options = ((RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline) | RegexOptions.IgnoreCase);
Regex reg = new Regex(regexString, options);
return reg.Match(actionExpressionString);
return reg.Match(actionExpressionString);
}
/// <summary>
/// Override in case you need to initialized non-serialized fields on deserialization.
/// </summary>
protected override void OnDeserialization(object sender)
{
base.OnDeserialization(sender);
if (retryExpression != null)
{
this.AfterPropertiesSet();
}
/// <summary>
/// Override in case you need to initialized non-serialized fields on deserialization.
/// </summary>
protected override void OnDeserialization(object sender)
{
base.OnDeserialization(sender);
if (retryExpression != null)
{
this.AfterPropertiesSet();
}
}
}
}

View File

@@ -1,5 +1,3 @@
#region License
/*
* Copyright <20> 2002-2011 the original author or authors.
*
@@ -16,10 +14,6 @@
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.Collections;
using System.Collections.Specialized;
@@ -30,8 +24,6 @@ using Spring.Core.IO;
using Spring.Objects.Factory.Config;
using Spring.Util;
#endregion
namespace Spring.Objects.Factory.Xml
{
/// <summary>
@@ -72,31 +64,38 @@ namespace Spring.Objects.Factory.Xml
/// </summary>
private const string ConfigParsersSectionName = "spring/parsers";
#region Fields
private static IDictionary parsers;
private readonly static IDictionary wellknownNamespaceParserTypeNames;
private static XmlSchemaSet schemas;
#endregion
/// <summary>
/// Creates a new instance of the NamespaceParserRegistry class.
/// </summary>
static NamespaceParserRegistry()
{
wellknownNamespaceParserTypeNames = new CaseInsensitiveHashtable();
wellknownNamespaceParserTypeNames["http://www.springframework.net/tx"] = "Spring.Transaction.Config.TxNamespaceParser, Spring.Data";
wellknownNamespaceParserTypeNames["http://www.springframework.net/aop"] = "Spring.Aop.Config.AopNamespaceParser, Spring.Aop";
wellknownNamespaceParserTypeNames["http://www.springframework.net/context"] = "Spring.Context.Config.ContextNamespaceParser, Spring.Core";
wellknownNamespaceParserTypeNames["http://www.springframework.net/db"] = "Spring.Data.Config.DatabaseNamespaceParser, Spring.Data";
wellknownNamespaceParserTypeNames["http://www.springframework.net/database"] = "Spring.Data.Config.DatabaseNamespaceParser, Spring.Data";
wellknownNamespaceParserTypeNames["http://www.springframework.net/remoting"] = "Spring.Remoting.Config.RemotingNamespaceParser, Spring.Services";
wellknownNamespaceParserTypeNames["http://www.springframework.net/wcf"] = "Spring.ServiceModel.Config.WcfNamespaceParser, Spring.Services";
wellknownNamespaceParserTypeNames["http://www.springframework.net/nms"] = "Spring.Messaging.Nms.Config.NmsNamespaceParser, Spring.Messaging.Nms";
wellknownNamespaceParserTypeNames["http://www.springframework.net/ems"] = "Spring.Messaging.Ems.Config.EmsNamespaceParser, Spring.Messaging.Ems";
wellknownNamespaceParserTypeNames["http://www.springframework.net/validation"] = "Spring.Validation.Config.ValidationNamespaceParser, Spring.Core";
wellknownNamespaceParserTypeNames["http://www.springframework.net/nvelocity"] = "Spring.Template.Velocity.Config.TemplateNamespaceParser, Spring.Template.Velocity";
wellknownNamespaceParserTypeNames["http://www.springframework.net/tx"] =
"Spring.Transaction.Config.TxNamespaceParser, Spring.Data";
wellknownNamespaceParserTypeNames["http://www.springframework.net/aop"] =
"Spring.Aop.Config.AopNamespaceParser, Spring.Aop";
wellknownNamespaceParserTypeNames["http://www.springframework.net/context"] =
"Spring.Context.Config.ContextNamespaceParser, Spring.Core";
wellknownNamespaceParserTypeNames["http://www.springframework.net/db"] =
"Spring.Data.Config.DatabaseNamespaceParser, Spring.Data";
wellknownNamespaceParserTypeNames["http://www.springframework.net/database"] =
"Spring.Data.Config.DatabaseNamespaceParser, Spring.Data";
wellknownNamespaceParserTypeNames["http://www.springframework.net/remoting"] =
"Spring.Remoting.Config.RemotingNamespaceParser, Spring.Services";
wellknownNamespaceParserTypeNames["http://www.springframework.net/wcf"] =
"Spring.ServiceModel.Config.WcfNamespaceParser, Spring.Services";
wellknownNamespaceParserTypeNames["http://www.springframework.net/nms"] =
"Spring.Messaging.Nms.Config.NmsNamespaceParser, Spring.Messaging.Nms";
wellknownNamespaceParserTypeNames["http://www.springframework.net/ems"] =
"Spring.Messaging.Ems.Config.EmsNamespaceParser, Spring.Messaging.Ems";
wellknownNamespaceParserTypeNames["http://www.springframework.net/validation"] =
"Spring.Validation.Config.ValidationNamespaceParser, Spring.Core";
wellknownNamespaceParserTypeNames["http://www.springframework.net/nvelocity"] =
"Spring.Template.Velocity.Config.TemplateNamespaceParser, Spring.Template.Velocity";
Reset();
}
@@ -109,7 +108,7 @@ namespace Spring.Objects.Factory.Xml
{
parsers = new HybridDictionary();
schemas = new XmlSchemaSet();
schemas.XmlResolver = new XmlResourceUrlResolver();
schemas.XmlResolver = new XmlResourceUrlResolver();
RegisterParser(new ObjectsNamespaceParser());
// register custom config parsers
@@ -126,7 +125,7 @@ namespace Spring.Objects.Factory.Xml
if (wellknownNamespaceParserTypeNames.Contains(namespaceUri))
{
string parserTypeName = (string)wellknownNamespaceParserTypeNames[namespaceUri];
string parserTypeName = (string) wellknownNamespaceParserTypeNames[namespaceUri];
// assume, that all Spring.XXX assemblies have same version + public key
// get the ", Version=x.x.x.x, Culture=neutral, PublicKeyToken=65e474d141e25e07" part of Spring.Core and append it
string name = typeof(NamespaceParserRegistry).Assembly.GetName().Name;
@@ -138,6 +137,7 @@ namespace Spring.Objects.Factory.Xml
RegisterParser(parserType);
return true;
}
return false;
}
@@ -151,6 +151,7 @@ namespace Spring.Objects.Factory.Xml
{
return "assembly://" + schemaLocationAssemblyHint.Assembly.FullName + schemaLocation;
}
return schemaLocation;
}
@@ -166,21 +167,22 @@ namespace Spring.Objects.Factory.Xml
/// </returns>
public static INamespaceParser GetParser(string namespaceURI)
{
INamespaceParser parser = (INamespaceParser)parsers[namespaceURI];
INamespaceParser parser = (INamespaceParser) parsers[namespaceURI];
if (parser == null)
{
bool ok = RegisterWellknownNamespaceParserType(namespaceURI);
if (ok)
{
parser = (INamespaceParser)parsers[namespaceURI];
parser = (INamespaceParser) parsers[namespaceURI];
//work-around for SPRNET-1277 where we're inconsistent re: exposing /db or /database as the final namespace element
if (parser == null && namespaceURI == "http://www.springframework.net/db")
{
parser = (INamespaceParser)parsers["http://www.springframework.net/database"];
parser = (INamespaceParser) parsers["http://www.springframework.net/database"];
}
}
}
return parser;
}
@@ -250,7 +252,7 @@ namespace Spring.Objects.Factory.Xml
if ((typeof(INamespaceParser)).IsAssignableFrom(parserType))
{
np = (INamespaceParser)ObjectUtils.InstantiateType(parserType);
np = (INamespaceParser) ObjectUtils.InstantiateType(parserType);
}
// TODO (EE): workaround to enable smooth transition between 1.x and 2.0 style namespace handling
else if (typeof(IObjectDefinitionParser).IsAssignableFrom(parserType))
@@ -264,28 +266,31 @@ namespace Spring.Objects.Factory.Xml
throw new ArgumentNullException(
"Either default or an explicit namespace value must be specified for a configuration parser.");
}
if (StringUtils.IsNullOrEmpty(namespaceUri))
{
namespaceUri = defaults.Namespace;
}
if (StringUtils.IsNullOrEmpty(schemaLocation))
{
schemaLocation = defaults.SchemaLocation;
if (defaults.SchemaLocationAssemblyHint != null)
{
schemaLocation = GetAssemblySchemaLocation(defaults.SchemaLocationAssemblyHint, schemaLocation);
schemaLocation =
GetAssemblySchemaLocation(defaults.SchemaLocationAssemblyHint, schemaLocation);
}
}
}
IObjectDefinitionParser odParser = (IObjectDefinitionParser)ObjectUtils.InstantiateType(parserType);
IObjectDefinitionParser odParser = (IObjectDefinitionParser) ObjectUtils.InstantiateType(parserType);
np = new ObjectDefinitionParserNamespaceParser(odParser);
}
else
{
throw new ArgumentException(
string.Format("The [{0}] Type must implement the INamespaceParser interface.", parserType.Name)
, "parserType");
string.Format("The [{0}] Type must implement the INamespaceParser interface.", parserType.Name)
, "parserType");
}
RegisterParser(np, namespaceUri, schemaLocation);
@@ -345,10 +350,12 @@ namespace Spring.Objects.Factory.Xml
throw new ArgumentNullException(
"Either default or an explicit namespace value must be specified for a configuration parser.");
}
if (StringUtils.IsNullOrEmpty(namespaceUri))
{
namespaceUri = defaults.Namespace;
}
if (StringUtils.IsNullOrEmpty(schemaLocation))
{
schemaLocation = defaults.SchemaLocation;
@@ -364,14 +371,14 @@ namespace Spring.Objects.Factory.Xml
// register parser
lock (parsers.SyncRoot)
lock (schemas)
lock (schemas)
{
parsers[namespaceUri] = parser;
if (StringUtils.HasText(schemaLocation) && !schemas.Contains(namespaceUri))
{
parsers[namespaceUri] = parser;
if (StringUtils.HasText(schemaLocation) && !schemas.Contains(namespaceUri))
{
RegisterSchema(namespaceUri, schemaLocation);
}
RegisterSchema(namespaceUri, schemaLocation);
}
}
}
/// <summary>
@@ -410,13 +417,12 @@ namespace Spring.Objects.Factory.Xml
object[] attrs = parserType.GetCustomAttributes(typeof(NamespaceParserAttribute), true);
if (attrs.Length > 0)
{
return (NamespaceParserAttribute)attrs[0];
return (NamespaceParserAttribute) attrs[0];
}
return null;
}
#region ObjectDefinitionParserNamespaceParser Utility class
/// <summary>
/// Adapts the <see cref="IObjectDefinitionParser"/> interface to <see cref="INamespaceParser"/>.
/// Only for smooth transition between 1.x and 2.0 style namespace handling, will be dropped for 2.0
@@ -440,12 +446,11 @@ namespace Spring.Objects.Factory.Xml
return odParser.ParseElement(element, parserContext);
}
public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition, ParserContext parserContext)
public ObjectDefinitionHolder Decorate(XmlNode node, ObjectDefinitionHolder definition,
ParserContext parserContext)
{
return null;
}
}
#endregion
}
}

View File

@@ -463,7 +463,7 @@ namespace Spring.Data.NHibernate
TransactionScopeOption txScopeOption = CreateTransactionScopeOptions(definition);
TransactionOptions txOptions = CreateTransactionOptions(definition);
txObject.TxScopeAdapter.CreateTransactionScope(txScopeOption, txOptions, definition.EnterpriseServicesInteropOption);
txObject.TxScopeAdapter.CreateTransactionScope(txScopeOption, txOptions, definition.AsyncFlowOption);
}

View File

@@ -2,6 +2,7 @@
<PropertyGroup>
<TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
<Description>Interfaces and classes that provide NHibernate 5 support in Spring.Net</Description>
<RootNamespace>Spring.Data.NHibernate</RootNamespace>
<NoWarn>0618</NoWarn>
</PropertyGroup>
<ItemGroup>

View File

@@ -1,5 +1,3 @@
#region License
/*
* Copyright 2007 the original author or authors.
*
@@ -16,8 +14,6 @@
* limitations under the License.
*/
#endregion
using System;
using System.Transactions;
using Spring.Data.Support;
@@ -54,8 +50,6 @@ namespace Spring.Data.Core
this.txAdapter = txAdapter;
}
#region IInitializingObject Members
/// <summary>
/// No-op initialization
/// </summary>
@@ -64,8 +58,6 @@ namespace Spring.Data.Core
// placeholder for more advanced configurations.
}
#endregion
protected override object DoGetTransaction()
{
PromotableTxScopeTransactionObject txObject = new PromotableTxScopeTransactionObject();
@@ -74,20 +66,21 @@ namespace Spring.Data.Core
{
txObject.TxScopeAdapter = txAdapter;
}
return txObject;
}
protected override bool IsExistingTransaction(object transaction)
{
PromotableTxScopeTransactionObject txObject =
(PromotableTxScopeTransactionObject)transaction;
return txObject.TxScopeAdapter.IsExistingTransaction;
(PromotableTxScopeTransactionObject) transaction;
return txObject.TxScopeAdapter.IsExistingTransaction;
}
protected override void DoBegin(object transaction, Spring.Transaction.ITransactionDefinition definition)
protected override void DoBegin(object transaction, ITransactionDefinition definition)
{
PromotableTxScopeTransactionObject txObject =
(PromotableTxScopeTransactionObject)transaction;
(PromotableTxScopeTransactionObject) transaction;
try
{
DoTxScopeBegin(txObject, definition);
@@ -106,7 +99,7 @@ namespace Spring.Data.Core
PromotableTxScopeTransactionObject txMgrStateObject = (PromotableTxScopeTransactionObject) transaction;
return txMgrStateObject.TxScopeAdapter;
}
protected override void DoResume(object transaction, object suspendedResources)
{
}
@@ -114,7 +107,7 @@ namespace Spring.Data.Core
protected override void DoCommit(DefaultTransactionStatus status)
{
PromotableTxScopeTransactionObject txObject =
(PromotableTxScopeTransactionObject)status.Transaction;
(PromotableTxScopeTransactionObject) status.Transaction;
try
{
txObject.TxScopeAdapter.Complete();
@@ -122,7 +115,8 @@ namespace Spring.Data.Core
}
catch (TransactionAbortedException ex)
{
throw new UnexpectedRollbackException("Transaction unexpectedly rolled back (maybe due to a timeout)", ex);
throw new UnexpectedRollbackException("Transaction unexpectedly rolled back (maybe due to a timeout)",
ex);
}
catch (TransactionInDoubtException ex)
{
@@ -137,54 +131,53 @@ namespace Spring.Data.Core
protected override void DoRollback(DefaultTransactionStatus status)
{
PromotableTxScopeTransactionObject txObject =
(PromotableTxScopeTransactionObject)status.Transaction;
(PromotableTxScopeTransactionObject) status.Transaction;
try
{
txObject.TxScopeAdapter.Dispose();
}
catch (Exception e)
{
throw new Spring.Transaction.TransactionSystemException("Failure on Transaction Scope rollback.", e);
throw new TransactionSystemException("Failure on Transaction Scope rollback.", e);
}
}
protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
{
if (status.Debug)
{
log.Debug("Setting transaction rollback-only");
}
try
{
System.Transactions.Transaction.Current.Rollback();
} catch (Exception ex)
}
catch (Exception ex)
{
throw new TransactionSystemException("Failure on System.Transactions.Transaction.Current.Rollback", ex);
}
}
protected override bool ShouldCommitOnGlobalRollbackOnly
{
get { return true; }
}
protected override bool ShouldCommitOnGlobalRollbackOnly => true;
private void DoTxScopeBegin(PromotableTxScopeTransactionObject txObject,
Spring.Transaction.ITransactionDefinition definition)
private void DoTxScopeBegin(
PromotableTxScopeTransactionObject txObject,
ITransactionDefinition definition)
{
TransactionScopeOption txScopeOption = CreateTransactionScopeOptions(definition);
TransactionScopeOption txScopeOption = CreateTransactionScopeOptions(definition);
TransactionOptions txOptions = CreateTransactionOptions(definition);
txObject.TxScopeAdapter.CreateTransactionScope(txScopeOption, txOptions, definition.EnterpriseServicesInteropOption);
txObject.TxScopeAdapter.CreateTransactionScope(
txScopeOption,
txOptions,
definition.AsyncFlowOption);
}
private static TransactionOptions CreateTransactionOptions(ITransactionDefinition definition)
{
TransactionOptions txOptions = new TransactionOptions();
switch (definition.TransactionIsolationLevel )
switch (definition.TransactionIsolationLevel)
{
case System.Data.IsolationLevel.Chaos:
txOptions.IsolationLevel = IsolationLevel.Chaos;
@@ -210,9 +203,10 @@ namespace Spring.Data.Core
}
if (definition.TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
{
{
txOptions.Timeout = new TimeSpan(0, 0, definition.TransactionTimeout);
}
return txOptions;
}
@@ -233,10 +227,11 @@ namespace Spring.Data.Core
}
else
{
throw new Spring.Transaction.TransactionSystemException("Transaction Propagation Behavior" +
definition.PropagationBehavior +
" not supported by TransactionScope. Use Required or RequiredNew");
throw new TransactionSystemException("Transaction Propagation Behavior" +
definition.PropagationBehavior +
" not supported by TransactionScope. Use Required or RequiredNew");
}
return txScopeOption;
}
@@ -264,22 +259,16 @@ namespace Spring.Data.Core
/// <value>The transaction scope adapter.</value>
public ITransactionScopeAdapter TxScopeAdapter
{
get { return txScopeAdapter; }
set { txScopeAdapter = value; }
get => txScopeAdapter;
set => txScopeAdapter = value;
}
/// <summary>
/// Return whether the transaction is internally marked as rollback-only.
/// </summary>
/// <value></value>
/// <returns>True of the transaction is marked as rollback-only.</returns>
public bool RollbackOnly
{
get {
return txScopeAdapter.RollbackOnly;
}
}
public bool RollbackOnly => txScopeAdapter.RollbackOnly;
}
}
}
}

View File

@@ -31,75 +31,45 @@ namespace Spring.Data.Support
{
private TransactionScope txScope;
/// <summary>
/// Call Complete() on the TransactionScope object created by this instance.
/// </summary>
/// <inheritdoc />
public void Complete()
{
txScope.Complete();
}
/// <summary>
/// Call Disponse() on the TransactionScope object created by this instance.
/// </summary>
/// <inheritdoc />
public void Dispose()
{
txScope.Dispose();
}
/// <inheritdoc />
public bool IsExistingTransaction => System.Transactions.Transaction.Current != null;
/// <summary>
/// Gets a value indicating whether there is a new transaction or an existing transaction.
/// </summary>
/// <value>
/// <c>true</c> if this instance is existing transaction; otherwise, <c>false</c>.
/// </value>
public bool IsExistingTransaction
{
get {
if (System.Transactions.Transaction.Current != null)
{
return true;
}
else
{
return false;
}
}
}
/// <summary>
/// Gets a value indicating whether rollback only has been called (i.e. Rollback() on the
/// Transaction object) and therefore voting that the transaction will be aborted.
/// </summary>
/// <value><c>true</c> if rollback only; otherwise, <c>false</c>.</value>
/// <inheritdoc />
public bool RollbackOnly
{
get
{
if (System.Transactions.Transaction.Current != null &&
System.Transactions.Transaction.Current.TransactionInformation != null &&
System.Transactions.Transaction.Current.TransactionInformation.Status == TransactionStatus.Aborted)
var transaction = System.Transactions.Transaction.Current;
if (transaction != null &&
transaction.TransactionInformation != null &&
transaction.TransactionInformation.Status == TransactionStatus.Aborted)
{
return true;
}
else
{
return false;
}
}
return false;
}
}
/// <summary>
/// Creates the transaction scope.
/// </summary>
/// <param name="txScopeOption">The tx scope option.</param>
/// <param name="txOptions">The tx options.</param>
/// <param name="interopOption">The interop option.</param>
public void CreateTransactionScope(TransactionScopeOption txScopeOption, TransactionOptions txOptions,
EnterpriseServicesInteropOption interopOption)
/// <inheritdoc />
public void CreateTransactionScope(
TransactionScopeOption txScopeOption,
TransactionOptions txOptions,
TransactionScopeAsyncFlowOption asyncFlowOption)
{
txScope = new TransactionScope(txScopeOption, txOptions, interopOption);
txScope = new TransactionScope(txScopeOption, txOptions, asyncFlowOption);
}
}
}
}

View File

@@ -35,21 +35,22 @@ namespace Spring.Data.Support
/// </summary>
/// <param name="txScopeOption">The tx scope option.</param>
/// <param name="txOptions">The tx options.</param>
/// <param name="interopOption">The interop option.</param>
void CreateTransactionScope(TransactionScopeOption txScopeOption, TransactionOptions txOptions, EnterpriseServicesInteropOption interopOption);
/// <param name="asyncFlowOption">The async flow option.</param>
void CreateTransactionScope(
TransactionScopeOption txScopeOption,
TransactionOptions txOptions,
TransactionScopeAsyncFlowOption asyncFlowOption);
/// <summary>
/// Call Complete() on the TransactionScope object created by this instance.
/// </summary>
void Complete();
/// <summary>
/// Call Disponse() on the TransactionScope object created by this instance.
/// Call Dispose() on the TransactionScope object created by this instance.
/// </summary>
void Dispose();
/// <summary>
/// Gets a value indicating whether there is a new transaction or an existing transaction.
/// </summary>
@@ -58,13 +59,11 @@ namespace Spring.Data.Support
/// </value>
bool IsExistingTransaction { get; }
/// <summary>
/// Gets a value indicating whether rollback only has been called (i.e. Rollback() on the
/// Transaction object) and therefore voting that the transaction will be aborted.
/// </summary>
/// <value><c>true</c> if rollback only; otherwise, <c>false</c>.</value>
bool RollbackOnly { get; }
}
}
}
}

View File

@@ -111,9 +111,9 @@ namespace Spring.Transaction
string Name { get; }
/// <summary>
/// Gets the enterprise services interop option.
/// Gets the async flow option.
/// </summary>
/// <value>The enterprise services interop option.</value>
System.Transactions.EnterpriseServicesInteropOption EnterpriseServicesInteropOption { get;}
/// <value>The async flow option.</value>
System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption { get;}
}
}

View File

@@ -89,7 +89,7 @@ namespace Spring.Transaction.Interceptor
rbta.TransactionIsolationLevel = ta.IsolationLevel;
rbta.ReadOnly = ta.ReadOnly;
rbta.TransactionTimeout = ta.Timeout;
rbta.EnterpriseServicesInteropOption = ta.EnterpriseServicesInteropOption;
rbta.AsyncFlowOption = ta.AsyncFlowOption;
Type[] rbf = ta.RollbackFor;

View File

@@ -1,5 +1,3 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
*
@@ -16,83 +14,83 @@
* limitations under the License.
*/
#endregion
using System;
using Spring.Transaction.Support;
namespace Spring.Transaction.Interceptor
{
/// <summary>
/// Transaction attribute approach to rolling back on all exceptions, no other
/// exceptions by default.
/// </summary>
/// <author>Rod Johnson</author>
/// <author>Griffin Caprio (.NET)</author>
public class DefaultTransactionAttribute : DefaultTransactionDefinition, ITransactionAttribute
{
/// <summary>
/// Prefix for rollback-on-exception rules in description strings.
/// </summary>
public static readonly string ROLLBACK_RULE_PREFIX = "-";
/// <summary>
/// Transaction attribute approach to rolling back on all exceptions, no other
/// exceptions by default.
/// </summary>
/// <author>Rod Johnson</author>
/// <author>Griffin Caprio (.NET)</author>
public class DefaultTransactionAttribute : DefaultTransactionDefinition, ITransactionAttribute
{
/// <summary>
/// Prefix for rollback-on-exception rules in description strings.
/// </summary>
public static readonly string ROLLBACK_RULE_PREFIX = "-";
/// <summary>
/// Prefix for commit-on-exception rules in description strings.
/// </summary>
public static readonly string COMMIT_RULE_PREFIX = "+";
/// <summary>
/// Prefix for commit-on-exception rules in description strings.
/// </summary>
public static readonly string COMMIT_RULE_PREFIX = "+";
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Transaction.Interceptor.DefaultTransactionAttribute"/>
/// class.
/// </summary>
public DefaultTransactionAttribute() {}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Transaction.Interceptor.DefaultTransactionAttribute"/>
/// class.
/// </summary>
public DefaultTransactionAttribute()
{
}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Transaction.Interceptor.DefaultTransactionAttribute"/>
/// class, setting the propagation behavior to the supplied value.
/// </summary>
/// <param name="propagationBehavior">
/// The desired transaction propagation behaviour.
/// </param>
public DefaultTransactionAttribute( TransactionPropagation propagationBehavior )
: base (propagationBehavior) {}
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Transaction.Interceptor.DefaultTransactionAttribute"/>
/// class, setting the propagation behavior to the supplied value.
/// </summary>
/// <param name="propagationBehavior">
/// The desired transaction propagation behaviour.
/// </param>
public DefaultTransactionAttribute(TransactionPropagation propagationBehavior)
: base(propagationBehavior)
{
}
#region ITransactionAttribute Members
/// <summary>
/// Decides if rollback is required for the supplied <paramref name="exception"/>.
/// </summary>
/// <remarks>
/// <p>
/// The default behavior is to rollback on any exception.
/// Consistent with <see cref="Spring.Transaction.Support.TransactionTemplate"/>'s behavior.
/// </p>
/// </remarks>
/// <param name="exception">The <see cref="System.Exception"/> to evaluate.</param>
/// <returns>True if the exception causes a rollback, false otherwise.</returns>
public virtual bool RollbackOn(Exception exception)
{
return ( true );
}
#endregion
/// <summary>
/// Decides if rollback is required for the supplied <paramref name="exception"/>.
/// </summary>
/// <remarks>
/// <p>
/// The default behavior is to rollback on any exception.
/// Consistent with <see cref="Spring.Transaction.Support.TransactionTemplate"/>'s behavior.
/// </p>
/// </remarks>
/// <param name="exception">The <see cref="System.Exception"/> to evaluate.</param>
/// <returns>True if the exception causes a rollback, false otherwise.</returns>
public virtual bool RollbackOn(Exception exception)
{
return (true);
}
/// <summary>
/// Return a description of this transaction attribute.
/// </summary>
/// <remarks>
/// <p>
/// The format matches the one used by the
/// <see cref="Spring.Transaction.Interceptor.TransactionAttributeEditor"/>,
/// to be able to feed any result into a <see cref="Spring.Transaction.Interceptor.ITransactionAttribute"/>
/// instance's properties.
/// </p>
/// </remarks>
public override string ToString()
{
string result = DefinitionDescription;
result += "," + ROLLBACK_RULE_PREFIX + "System.Exception";
return result;
}
}
}
/// <summary>
/// Return a description of this transaction attribute.
/// </summary>
/// <remarks>
/// <p>
/// The format matches the one used by the
/// <see cref="Spring.Transaction.Interceptor.TransactionAttributeEditor"/>,
/// to be able to feed any result into a <see cref="Spring.Transaction.Interceptor.ITransactionAttribute"/>
/// instance's properties.
/// </p>
/// </remarks>
public override string ToString()
{
string result = DefinitionDescription;
result += "," + ROLLBACK_RULE_PREFIX + "System.Exception";
return result;
}
}
}

View File

@@ -30,8 +30,8 @@ namespace Spring.Transaction.Interceptor
/// </summary>
public class DelegatingTransactionAttributeWithName : ITransactionAttribute
{
private ITransactionAttribute targetAttribute;
private string joinpointIdentification;
private readonly ITransactionAttribute targetAttribute;
private readonly string joinpointIdentification;
/// <summary>
/// Initializes a new instance of the <see cref="DelegatingTransactionAttributeWithName"/> class.
@@ -61,10 +61,7 @@ namespace Spring.Transaction.Interceptor
/// <see cref="Spring.Transaction.TransactionPropagation"/>.
/// </summary>
/// <value></value>
public TransactionPropagation PropagationBehavior
{
get { return targetAttribute.PropagationBehavior; }
}
public TransactionPropagation PropagationBehavior => targetAttribute.PropagationBehavior;
/// <summary>
/// Return the isolation level of type <see cref="System.Data.IsolationLevel"/>.
@@ -82,75 +79,19 @@ namespace Spring.Transaction.Interceptor
/// <see cref="System.Data.IsolationLevel.Unspecified"/>.
/// </p>
/// </remarks>
public IsolationLevel TransactionIsolationLevel
{
get { return targetAttribute.TransactionIsolationLevel; }
}
public IsolationLevel TransactionIsolationLevel => targetAttribute.TransactionIsolationLevel;
/// <summary>
/// Return the transaction timeout.
/// </summary>
/// <value></value>
/// <remarks>
/// <p>
/// Must return a number of seconds, or -1.
/// Only makes sense in combination with
/// <see cref="Spring.Transaction.TransactionPropagation.Required"/> and
/// <see cref="Spring.Transaction.TransactionPropagation.RequiresNew"/>.
/// Note that a transaction manager that does not support timeouts will
/// throw an exception when given any other timeout than -1.
/// </p>
/// </remarks>
public int TransactionTimeout
{
get { return targetAttribute.TransactionTimeout; }
}
/// <inheritdoc />
public int TransactionTimeout => targetAttribute.TransactionTimeout;
/// <summary>
/// Get whether to optimize as read-only transaction.
/// </summary>
/// <value></value>
/// <remarks>
/// <p>
/// This just serves as hint for the actual transaction subsystem,
/// it will <i>not necessarily</i> cause failure of write accesses.
/// </p>
/// <p>
/// Only makes sense in combination with
/// <see cref="Spring.Transaction.TransactionPropagation.Required"/> and
/// <see cref="Spring.Transaction.TransactionPropagation.RequiresNew"/>.
/// </p>
/// <p>
/// A transaction manager that cannot interpret the read-only hint
/// will <i>not</i> throw an exception when given <c>ReadOnly=true</c>.
/// </p>
/// </remarks>
public bool ReadOnly
{
get { return targetAttribute.ReadOnly; }
}
/// <inheritdoc />
public bool ReadOnly => targetAttribute.ReadOnly;
/// <summary>
/// Return the name of this transaction.
/// </summary>
/// <value></value>
/// <remarks>
/// The exposed name will be the fully
/// qualified type name + "." method name + assembly (by default).
/// </remarks>
public string Name
{
get { return joinpointIdentification; }
}
/// <inheritdoc />
public string Name => joinpointIdentification;
/// <summary>
/// Gets the enterprise services interop option.
/// </summary>
/// <value>The enterprise services interop option.</value>
public EnterpriseServicesInteropOption EnterpriseServicesInteropOption
{
get { return targetAttribute.EnterpriseServicesInteropOption; }
}
/// <inheritdoc />
public TransactionScopeAsyncFlowOption AsyncFlowOption => targetAttribute.AsyncFlowOption;
/// <summary>
/// Return a description of this transaction attribute.

View File

@@ -1,5 +1,3 @@
#region License
/*
* Copyright <20> 2002-2011 the original author or authors.
*
@@ -16,30 +14,23 @@
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.Data;
using Spring.Transaction.Support;
#endregion
namespace Spring.Transaction.Interceptor
{
/// <summary>
/// .NET Attribute for describing transactional behavior of methods in a class.
/// </summary>
/// <remarks>This attribute type is generally directly comparable
/// to Spring's <see cref="RuleBasedTransactionAttribute"/> class and
/// in fact <see cref="AttributesTransactionAttributeSource"/> will
/// <summary>
/// .NET Attribute for describing transactional behavior of methods in a class.
/// </summary>
/// <remarks>This attribute type is generally directly comparable
/// to Spring's <see cref="RuleBasedTransactionAttribute"/> class and
/// in fact <see cref="AttributesTransactionAttributeSource"/> will
/// directly convert the data to a <see cref="RuleBasedTransactionAttribute"/>
/// so that Spring's transaction support code does not have to know about
/// attributes. If no rules are relevant to the exception it will be treaded
/// like DefaultTransactionAttribute, (rolling back on all exceptions).
/// <para>
/// <para>
/// The default property values are TransactionPropagation.Required, IsolationLevel.ReadCommitted,
/// DefaultTransactionDefinition.TIMEOUT_DEFAULT (can be changed, by default is the default
/// value of the underlying transaction subsystem)
@@ -47,32 +38,27 @@ namespace Spring.Transaction.Interceptor
/// types.
/// </para>
/// </remarks>
/// <author>Mark Pollack (.NET)</author>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
Inherited = true)]
/// <author>Mark Pollack (.NET)</author>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
Inherited = true)]
[Serializable]
public class TransactionAttribute : Attribute
{
#region Fields
public class TransactionAttribute : Attribute
{
private TransactionPropagation _transactionPropagation = TransactionPropagation.Required;
private IsolationLevel _isolationLevel = IsolationLevel.ReadCommitted;
private int _timeout = DefaultTransactionDefinition.TIMEOUT_DEFAULT;
private bool _readOnly = false;
private Type[] _rollbackTypes = Type.EmptyTypes;
private Type[] _noRollbackTypes = Type.EmptyTypes;
private System.Transactions.EnterpriseServicesInteropOption _esInteropOption =
System.Transactions.EnterpriseServicesInteropOption.Automatic;
#endregion
private System.Transactions.TransactionScopeAsyncFlowOption _asyncFlowOption = System.Transactions.TransactionScopeAsyncFlowOption.Enabled;
#region Constructor (s)
/// <summary>
/// Initializes a new instance of the <see cref="TransactionAttribute"/> class.
/// <summary>
/// Initializes a new instance of the <see cref="TransactionAttribute"/> class.
/// </summary>
public TransactionAttribute()
{
}
public TransactionAttribute()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TransactionAttribute"/> class.
@@ -89,7 +75,7 @@ namespace Spring.Transaction.Interceptor
/// <param name="transactionPropagation">The transaction propagation.</param>
/// <param name="isolationLevel">The isolation level.</param>
public TransactionAttribute(TransactionPropagation transactionPropagation,
IsolationLevel isolationLevel) : this(transactionPropagation)
IsolationLevel isolationLevel) : this(transactionPropagation)
{
_isolationLevel = isolationLevel;
}
@@ -103,51 +89,41 @@ namespace Spring.Transaction.Interceptor
_isolationLevel = isolationLevel;
}
#endregion
#region Properties
/// <summary>
/// Gets the transaction propagation.
/// </summary>
/// <remarks>Defaults to TransactionPropagation.Required</remarks>
/// <value>The transaction propagation.</value>
public TransactionPropagation TransactionPropagation
{
get { return _transactionPropagation; }
}
public TransactionPropagation TransactionPropagation => _transactionPropagation;
/// <summary>
/// Gets the isolation level.
/// </summary>
/// <remarks>Defaults to IsolationLevel.Unspecified</remarks>
/// <value>The isolation level.</value>
public IsolationLevel IsolationLevel
{
get { return _isolationLevel; }
}
public IsolationLevel IsolationLevel => _isolationLevel;
/// <summary>
/// Gets or sets the timeout.
/// </summary>
/// <remarks>Defaults to the default timeout of the underlying transaction system.</remarks>
/// <value>The timeout.</value>
public int Timeout
{
get { return _timeout; }
set { _timeout = value; }
}
public int Timeout
{
get => _timeout;
set => _timeout = value;
}
/// <summary>
/// Gets or sets a value indicating whether the transaction is readonly.
/// </summary>
/// <remarks>Defaults to false</remarks>
/// <value><c>true</c> if read-only; otherwise, <c>false</c>.</value>
public bool ReadOnly
{
get { return _readOnly; }
set { _readOnly = value; }
}
public bool ReadOnly
{
get => _readOnly;
set => _readOnly = value;
}
/// <summary>
/// Gets or sets the zero or more exception types which
@@ -157,11 +133,11 @@ namespace Spring.Transaction.Interceptor
/// <remarks>This is the preferred way to construct a rollback rule,
/// matching the exception class and subclasses.</remarks>
/// <value>The rollback types.</value>
public Type[] RollbackFor
{
get { return _rollbackTypes; }
set { _rollbackTypes = value; }
}
public Type[] RollbackFor
{
get => _rollbackTypes;
set => _rollbackTypes = value;
}
/// <summary>
/// Gets or sets zero or more exceptions types which
@@ -171,27 +147,20 @@ namespace Spring.Transaction.Interceptor
/// <remarks>This is the preferred way to construct a rollback rule,
/// matching the exception type.</remarks>
/// <value>The no rollback for.</value>
public Type[] NoRollbackFor
{
get { return _noRollbackTypes; }
set { _noRollbackTypes = value; }
}
public Type[] NoRollbackFor
{
get => _noRollbackTypes;
set => _noRollbackTypes = value;
}
/// <summary>
/// Gets or sets the enterprise services interop option.
/// Gets the async flow option.
/// </summary>
/// <value>The enterprise services interop option.</value>
public System.Transactions.EnterpriseServicesInteropOption EnterpriseServicesInteropOption
{
get { return _esInteropOption;}
set { _esInteropOption = value; }
}
#endregion
#region Methods
#endregion
}
}
/// <value>The async flow option.</value>
public System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption
{
get => _asyncFlowOption;
set => _asyncFlowOption = value;
}
}
}

View File

@@ -1,5 +1,3 @@
#region License
/*
* Copyright 2002-2010 the original author or authors.
*
@@ -16,174 +14,170 @@
* limitations under the License.
*/
#endregion
using System;
using System.Data;
using System.Text;
using System.Transactions;
namespace Spring.Transaction.Support
{
/// <summary>
/// Default implementation of the <see cref="Spring.Transaction.ITransactionDefinition"/>
/// interface, offering object-style configuration and sensible default values.
/// </summary>
/// <remarks>
/// <p>
/// Base class for both <see cref="System.SystemException"/> and
/// <see cref="Spring.Transaction.Interceptor.DefaultTransactionAttribute"/>.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <author>Griffin Caprio (.NET)</author>
/// <author>Mark Pollack (.NET)</author>
[Serializable]
public class DefaultTransactionDefinition : ITransactionDefinition
{
/// <summary>
/// Prefix for Propagation settings.
/// </summary>
public static readonly string PROPAGATION_CONSTANT_PREFIX = "PROPAGATION";
/// <summary>
/// Default implementation of the <see cref="Spring.Transaction.ITransactionDefinition"/>
/// interface, offering object-style configuration and sensible default values.
/// </summary>
/// <remarks>
/// <p>
/// Base class for both <see cref="System.SystemException"/> and
/// <see cref="Spring.Transaction.Interceptor.DefaultTransactionAttribute"/>.
/// </p>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <author>Griffin Caprio (.NET)</author>
/// <author>Mark Pollack (.NET)</author>
[Serializable]
public class DefaultTransactionDefinition : ITransactionDefinition
{
/// <summary>
/// Prefix for Propagation settings.
/// </summary>
public static readonly string PROPAGATION_CONSTANT_PREFIX = "PROPAGATION";
/// <summary>
/// Prefix for IsolationLevel settings.
/// </summary>
public static readonly string ISOLATION_CONSTANT_PREFIX = "ISOLATION";
/// <summary>
/// Prefix for IsolationLevel settings.
/// </summary>
public static readonly string ISOLATION_CONSTANT_PREFIX = "ISOLATION";
/// <summary>
/// Prefix for transaction timeout values in description strings.
/// </summary>
public static readonly string TIMEOUT_PREFIX = "timeout_";
/// <summary>
/// Prefix for transaction timeout values in description strings.
/// </summary>
public static readonly string TIMEOUT_PREFIX = "timeout_";
/// <summary>
/// Marker for read-only transactions in description strings.
/// </summary>
public static readonly string READ_ONLY_MARKER = "readOnly";
/// <summary>
/// Marker for read-only transactions in description strings.
/// </summary>
public static readonly string READ_ONLY_MARKER = "readOnly";
/// <summary>
/// The default transaction timeout.
/// </summary>
public const int TIMEOUT_DEFAULT = -1;
/// <summary>
/// The default transaction timeout.
/// </summary>
public const int TIMEOUT_DEFAULT = -1;
//TODO Refactoring to sync with Spring 2.0 for nt/enums for various default values.
private TransactionPropagation _transactionPropagation = TransactionPropagation.Required;
private IsolationLevel _transactionIsolationLevel = IsolationLevel.ReadCommitted;
private int _timeout = DefaultTransactionDefinition.TIMEOUT_DEFAULT;
private bool _readOnly = false;
//TODO Refactoring to sync with Spring 2.0 for nt/enums for various default values.
private TransactionPropagation _transactionPropagation = TransactionPropagation.Required;
private System.Data.IsolationLevel _transactionIsolationLevel = System.Data.IsolationLevel.ReadCommitted;
private int _timeout = TIMEOUT_DEFAULT;
private bool _readOnly = false;
private string _name = null;
private System.Transactions.EnterpriseServicesInteropOption _esInteropOption;
/// <summary>
private System.Transactions.TransactionScopeAsyncFlowOption _asyncFlowOption = TransactionScopeAsyncFlowOption.Enabled;
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition"/> class.
/// </summary>
public DefaultTransactionDefinition() {}
/// </summary>
public DefaultTransactionDefinition()
{
}
/// <summary>
/// <summary>
/// Creates a new instance of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition"/> class
/// with the supplied <see cref="Spring.Transaction.TransactionPropagation"/>
/// behaviour.
/// </summary>
/// <param name="transactionPropagation">
/// The desired <see cref="Spring.Transaction.TransactionPropagation"/> behavior.
/// </param>
public DefaultTransactionDefinition( TransactionPropagation transactionPropagation )
{
_transactionPropagation = transactionPropagation;
}
#region ITransactionDefinition Members
/// </summary>
/// <param name="transactionPropagation">
/// The desired <see cref="Spring.Transaction.TransactionPropagation"/> behavior.
/// </param>
public DefaultTransactionDefinition(TransactionPropagation transactionPropagation)
{
_transactionPropagation = transactionPropagation;
}
// TODO change method name to same as type returned (TransactionPropagation)
/// <summary>
/// Gets / Sets the <see cref="Spring.Transaction.TransactionPropagation">propagation</see>
/// behavior.
/// </summary>
public TransactionPropagation PropagationBehavior
{
get { return _transactionPropagation; }
set { _transactionPropagation = value; }
}
/// <summary>
/// Gets / Sets the <see cref="Spring.Transaction.TransactionPropagation">propagation</see>
/// behavior.
/// </summary>
public TransactionPropagation PropagationBehavior
{
get => _transactionPropagation;
set => _transactionPropagation = value;
}
// TODO change method name to same as type returned (TransactionPropagation)
/// <summary>
/// Return the isolation level of type <see cref="System.Data.IsolationLevel"/>.
/// </summary>
/// <remarks>
/// <p>
/// Only makes sense in combination with
/// <see cref="Spring.Transaction.TransactionPropagation.Required"/> and
/// <see cref="Spring.Transaction.TransactionPropagation.RequiresNew"/>.
/// </p>
/// <p>
/// Note that a transaction manager that does not support custom isolation levels
/// will throw an exception when given any other level than
/// <see cref="System.Data.IsolationLevel.Unspecified"/>.
/// </p>
/// </remarks>
public IsolationLevel TransactionIsolationLevel
{
get { return _transactionIsolationLevel; }
set { _transactionIsolationLevel = value; }
}
/// <summary>
/// Return the isolation level of type <see cref="System.Data.IsolationLevel"/>.
/// </summary>
/// <remarks>
/// <p>
/// Only makes sense in combination with
/// <see cref="Spring.Transaction.TransactionPropagation.Required"/> and
/// <see cref="Spring.Transaction.TransactionPropagation.RequiresNew"/>.
/// </p>
/// <p>
/// Note that a transaction manager that does not support custom isolation levels
/// will throw an exception when given any other level than
/// <see cref="System.Data.IsolationLevel.Unspecified"/>.
/// </p>
/// </remarks>
public System.Data.IsolationLevel TransactionIsolationLevel
{
get => _transactionIsolationLevel;
set => _transactionIsolationLevel = value;
}
/// <summary>
/// Return the transaction timeout.
/// </summary>
/// <remarks>
/// <p>
/// Must return a number of seconds, or -1.
/// Only makes sense in combination with
/// <see cref="Spring.Transaction.TransactionPropagation.Required"/> and
/// <see cref="Spring.Transaction.TransactionPropagation.RequiresNew"/>.
/// Note that a transaction manager that does not support timeouts will
/// throw an exception when given any other timeout than -1.
/// </p>
/// </remarks>
public int TransactionTimeout
{
get { return _timeout; }
set
{
if ( value < DefaultTransactionDefinition.TIMEOUT_DEFAULT )
{
throw new ArgumentException( "Timeout must be a positive integer or DefaultTransactionDefinition.TIMEOUT_DEFAULT" );
}
_timeout = value;
}
}
/// <summary>
/// Get whether to optimize as read-only transaction.
/// </summary>
/// <remarks>
/// <p>
/// This just serves as hint for the actual transaction subsystem,
/// it will <i>not necessarily</i> cause failure of write accesses.
/// </p>
/// <p>
/// Only makes sense in combination with
/// <see cref="Spring.Transaction.TransactionPropagation.Required"/> and
/// <see cref="Spring.Transaction.TransactionPropagation.RequiresNew"/>.
/// </p>
/// <p>
/// A transaction manager that cannot interpret the read-only hint
/// will <i>not</i> throw an exception when given <c>ReadOnly=true</c>.
/// </p>
/// </remarks>
public bool ReadOnly
{
get { return _readOnly; }
set { _readOnly = value; }
}
/// <summary>
/// Return the transaction timeout.
/// </summary>
/// <remarks>
/// <p>
/// Must return a number of seconds, or -1.
/// Only makes sense in combination with
/// <see cref="Spring.Transaction.TransactionPropagation.Required"/> and
/// <see cref="Spring.Transaction.TransactionPropagation.RequiresNew"/>.
/// Note that a transaction manager that does not support timeouts will
/// throw an exception when given any other timeout than -1.
/// </p>
/// </remarks>
public int TransactionTimeout
{
get => _timeout;
set
{
if (value < TIMEOUT_DEFAULT)
{
throw new ArgumentException(
"Timeout must be a positive integer or DefaultTransactionDefinition.TIMEOUT_DEFAULT");
}
_timeout = value;
}
}
/// <summary>
/// Get whether to optimize as read-only transaction.
/// </summary>
/// <remarks>
/// <p>
/// This just serves as hint for the actual transaction subsystem,
/// it will <i>not necessarily</i> cause failure of write accesses.
/// </p>
/// <p>
/// Only makes sense in combination with
/// <see cref="Spring.Transaction.TransactionPropagation.Required"/> and
/// <see cref="Spring.Transaction.TransactionPropagation.RequiresNew"/>.
/// </p>
/// <p>
/// A transaction manager that cannot interpret the read-only hint
/// will <i>not</i> throw an exception when given <c>ReadOnly=true</c>.
/// </p>
/// </remarks>
public bool ReadOnly
{
get => _readOnly;
set => _readOnly = value;
}
/// <summary>
/// Return the name of this transaction. Can be null.
@@ -195,89 +189,86 @@ namespace Spring.Transaction.Support
/// declarative transactions, the exposed name will be the fully
/// qualified type name + "." method name + assembly (by default).
/// </remarks>
public string Name
{
get { return _name; }
set { _name = value;}
}
/// <summary>
/// Gets the enterprise services interop option.
/// </summary>
/// <value>The enterprise services interop option.</value>
public System.Transactions.EnterpriseServicesInteropOption EnterpriseServicesInteropOption
public string Name
{
get { return _esInteropOption; }
set { _esInteropOption = value; }
get => _name;
set => _name = value;
}
#endregion
/// <inheritdoc />
public System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption
{
get => _asyncFlowOption;
set => _asyncFlowOption = value;
}
/// <summary>
/// <summary>
/// An override of the default <see cref="System.Object.Equals(object)"/> method.
/// </summary>
/// <param name="obj">The <see cref="System.Object"/> to compare to.</param>
/// <returns>True if the objects are equal.</returns>
public override bool Equals(object obj)
{
return ( obj is ITransactionDefinition ) && ToString().Equals( obj.ToString() );
}
/// </summary>
/// <param name="obj">The <see cref="System.Object"/> to compare to.</param>
/// <returns>True if the objects are equal.</returns>
public override bool Equals(object obj)
{
return (obj is ITransactionDefinition) && ToString().Equals(obj.ToString());
}
/// <summary>
/// <summary>
/// An override of the default <see cref="System.Object.GetHashCode"/> method that returns the
/// hashcode of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition.DefinitionDescription"/>
/// property.
/// </summary>
/// <returns>
/// The hashcode of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition.DefinitionDescription"/>
/// property.
/// </summary>
/// <returns>
/// The hashcode of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition.DefinitionDescription"/>
/// property.
/// </returns>
public override int GetHashCode()
{
return ToString().GetHashCode();
}
public override int GetHashCode()
{
return ToString().GetHashCode();
}
/// <summary>
/// An override of the default <see cref="System.Object.ToString"/> method that returns a string
/// representation of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition.DefinitionDescription"/>
/// property.
/// </summary>
/// <summary>
/// An override of the default <see cref="System.Object.ToString"/> method that returns a string
/// representation of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition.DefinitionDescription"/>
/// property.
/// </summary>
/// <returns>
/// A string representation of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition.DefinitionDescription"/>
/// property.
/// </returns>
public override string ToString()
{
return DefinitionDescription;
}
public override string ToString()
{
return DefinitionDescription;
}
/// <summary>
/// Returns a <see cref="System.String"/> representation of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition.DefinitionDescription"/>
/// property.
/// </summary>
protected string DefinitionDescription
{
get
{
StringBuilder builder = new StringBuilder();
builder.Append( PROPAGATION_CONSTANT_PREFIX +"_" + PropagationBehavior );
builder.Append( "," );
builder.Append( ISOLATION_CONSTANT_PREFIX + "_" +TransactionIsolationLevel );
if ( TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT )
{
builder.Append( ",timeout_" + _timeout );
}
if ( ReadOnly )
{
builder.Append( ",readOnly" );
}
return builder.ToString();
}
}
}
}
/// <summary>
/// Returns a <see cref="System.String"/> representation of the
/// <see cref="Spring.Transaction.Support.DefaultTransactionDefinition.DefinitionDescription"/>
/// property.
/// </summary>
protected string DefinitionDescription
{
get
{
StringBuilder builder = new StringBuilder();
builder.Append(PROPAGATION_CONSTANT_PREFIX + "_" + PropagationBehavior);
builder.Append(",");
builder.Append(ISOLATION_CONSTANT_PREFIX + "_" + TransactionIsolationLevel);
if (TransactionTimeout != TIMEOUT_DEFAULT)
{
builder.Append(",timeout_" + _timeout);
}
if (ReadOnly)
{
builder.Append(",readOnly");
}
return builder.ToString();
}
}
}
}

View File

@@ -1,121 +0,0 @@
/*
* Copyright 2002-2010 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="IJobDetail"/>
/// and other info relating to the trigger firing can be obtained.</param>
/// <param name="scheduler">The scheduler instance.</param>
/// <returns>the newly instantiated Job</returns>
/// <throws>SchedulerException if there is a problem instantiating the Job.</throws>
public virtual IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try
{
object jobObject = CreateJobInstance(bundle);
return AdaptJob(jobObject);
}
catch (Exception ex)
{
throw new SchedulerException("Job instantiation failed", ex);
}
}
/// <summary>
/// Allows the the job factory to destroy/cleanup the job if needed.
/// </summary>
public virtual void ReturnJob(IJob job)
{
}
/// <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<object>(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;
}
if (jobObject is ThreadStart)
{
return new DelegatingJob((ThreadStart)jobObject);
}
if (jobObject is IThreadRunnable)
{
return new DelegatingJob(((IThreadRunnable)jobObject).Run);
}
string message = string.Format("Unable to execute job class [{0}]: only [IJob] and [ThreadStart] supported.", jobObject.GetType().FullName);
throw new ArgumentException(message);
}
}
}

View File

@@ -1,48 +0,0 @@
/*
* Copyright 2002-2010 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="SchedulerAccessor.Triggers" />
/// <seealso cref="SchedulerAccessor.JobDetails" />
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>
IJobDetail JobDetail { get; }
}
}

View File

@@ -1,41 +0,0 @@
/*
* Copyright 2002-2010 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 Quartz.Spi;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Callback interface to be implemented by Spring-managed
/// Quartz artifacts that need access to the SchedulerContext
/// (without having natural access to it).
/// </summary>
/// <remarks>
/// Currently only supported for custom JobFactory implementations
/// that are passed in via Spring's SchedulerFactoryObject.
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <seealso cref="IJobFactory" />
/// <seealso cref="SchedulerFactoryObject.JobFactory" />
public interface ISchedulerContextAware
{
/// <summary>
/// Set the SchedulerContext of the current Quartz Scheduler.
/// </summary>
/// <seealso cref="IScheduler.Context" />
SchedulerContext SchedulerContext { set; }
}
}

View File

@@ -1,220 +0,0 @@
/*
* Copyright 2002-2010 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 Quartz.Impl;
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="IJobDetail" /> 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="IJobDetail.Key" />
/// <seealso cref="SchedulerConstants.DefaultGroup" />
public class JobDetailObject : JobDetailImpl, IObjectNameAware, IApplicationContextAware, IInitializingObject
{
private Type actualJobType;
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 override Type JobType
{
get { return (actualJobType ?? base.JobType); }
set
{
if (value != null && !typeof (IJob).IsAssignableFrom(value))
{
base.JobType = typeof (DelegatingJob);
actualJobType = value;
}
else
{
base.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
{
if (value == null)
{
throw new ArgumentException("Value cannot be null", "value");
}
foreach (DictionaryEntry entry in value)
{
JobDataMap.Put((string) entry.Key, entry.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>
/// Gets or sets 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.DefaultGroup;
}
if (applicationContextJobDataKey != null)
{
if (applicationContext == null)
{
throw new ArgumentException("JobDetailObject needs to be set up in an IApplicationContext " +
"to be able to handle an 'applicationContextJobDataKey'");
}
JobDataMap.Put(applicationContextJobDataKey, applicationContext);
}
}
}
}

View File

@@ -1,160 +0,0 @@
/*
* Copyright 2002-2010 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 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>
private readonly ILog logger;
private ITaskExecutor taskExecutor;
/// <summary>
/// Initializes a new instance of the <see cref="LocalTaskExecutorThreadPool"/> class.
/// </summary>
public LocalTaskExecutorThreadPool()
{
logger = LogManager.GetLogger(GetType());
}
/// <summary>
/// Logger instance.
/// </summary>
protected ILog Logger
{
get { return logger; }
}
/// <summary>
/// Gets the size of the pool.
/// </summary>
/// <value>The size of the pool.</value>
public virtual int PoolSize
{
get { return - 1; }
}
/// <summary>
/// Inform the <see cref="T:Quartz.Spi.IThreadPool"/> of the Scheduler instance's Id,
/// prior to initialize being invoked.
/// </summary>
public string InstanceId
{
set { }
}
/// <summary>
/// Inform the <see cref="T:Quartz.Spi.IThreadPool"/> of the Scheduler instance's name,
/// prior to initialize being invoked.
/// </summary>
public string InstanceName
{
set { }
}
/// <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(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;
}
}
}

View File

@@ -1,292 +0,0 @@
/*
* Copyright 2002-2010 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 Quartz.Impl;
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,
IObjectFactoryAware,
IFactoryObject,
IObjectNameAware,
IInitializingObject
{
private string name;
private string group;
private bool concurrent = true;
private string[] jobListenerNames;
private string targetObjectName;
private string objectName;
private JobDetailImpl jobDetail;
private IObjectFactory objectFactory;
/// <summary>
/// Initializes a new instance of the <see cref="MethodInvokingJobDetailFactoryObject"/> class.
/// </summary>
public MethodInvokingJobDetailFactoryObject()
{
group = SchedulerConstants.DefaultGroup;
}
/// <summary>
/// Set the name of the job.
/// Default is the object name of this FactoryObject.
/// </summary>
/// <seealso cref="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="Group" />
/// <seealso cref="SchedulerConstants.DefaultGroup" />
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="DisallowConcurrentExecutionAttribute" /> attribute.
/// 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>
/// Gets the job detail.
/// </summary>
/// <value>The job detail.</value>
protected IJobDetail JobDetail
{
get { return jobDetail; }
}
/// <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="SchedulerAccessor.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>
/// Set the name of the target object in the Spring object factory.
/// </summary>
/// <remarks>
/// This is an alternative to specifying TargetObject
/// allowing for non-singleton objects to be invoked. Note that specified
/// "TargetObject" and "TargetType" values will
/// override the corresponding effect of this "TargetObjectName" setting
///(i.e. statically pre-define the object type or even the target object).
/// </remarks>
public string TargetObjectName
{
set { targetObjectName = value; }
}
/// <summary>
/// Sets the object factory.
/// </summary>
/// <value>The object factory.</value>
public IObjectFactory ObjectFactory
{
set { objectFactory = 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 virtual 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
{
if (targetObjectName != null)
{
if (objectFactory == null)
{
throw new InvalidOperationException("ObjectFactory must be set when using 'TargetObjectName'");
}
return objectFactory.GetType(targetObjectName);
}
return typeof(IJobDetail);
}
}
/// <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 ?? objectName;
// Consider the concurrent flag to choose between stateful and stateless job.
Type jobType = (concurrent ? typeof (MethodInvokingJob) : typeof (StatefulMethodInvokingJob));
// Build JobDetail instance.
jobDetail = new JobDetailImpl(jobDetailName, group, jobType);
jobDetail.JobDataMap.Put("methodInvoker", this);
jobDetail.Durable = true;
// job listeners through configuration are no longer supported
if (jobListenerNames != null && jobListenerNames.Length > 0)
{
throw new InvalidOperationException("Non-global IJobListeners not supported on Quartz 2 - " +
"manually register a Matcher against the Quartz ListenerManager instead");
}
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(IJobDetail detail)
{
}
}
}

View File

@@ -1,84 +0,0 @@
/*
* Copyright 2002-2010 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="IJobExecutionContext.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(IJobExecutionContext 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)
{
throw new JobExecutionException(ex);
}
ExecuteInternal(context);
}
/// <summary>
/// Execute the actual job. The job data map will already have been
/// applied as object property values by execute. The contract is
/// exactly the same as for the standard Quartz execute method.
/// </summary>
/// <seealso cref="Execute" />
protected abstract void ExecuteInternal(IJobExecutionContext context);
}
}

View File

@@ -1,127 +0,0 @@
/*
* Copyright 2002-2010 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();
}
}
}
}

View File

@@ -1,11 +0,0 @@
using System;
namespace Spring.Scheduling
{
/// <summary>
/// Summary description for TaskRejectedException.
/// </summary>
public class TaskRejectedException : ApplicationException
{
}
}

View File

@@ -1,5 +1,3 @@
#region License
/*
* Copyright © 2002-2011 the original author or authors.
*
@@ -16,8 +14,6 @@
* limitations under the License.
*/
#endregion
using System.Reflection;
using System.Runtime.InteropServices;

View File

@@ -0,0 +1,129 @@
/*
* Copyright 2002-2010 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 System.Threading.Tasks;
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="IJobDetail"/>
/// and other info relating to the trigger firing can be obtained.</param>
/// <param name="scheduler">The scheduler instance.</param>
/// <returns>the newly instantiated Job</returns>
/// <throws>SchedulerException if there is a problem instantiating the Job.</throws>
public virtual IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
try
{
object jobObject = CreateJobInstance(bundle);
return AdaptJob(jobObject);
}
catch (Exception ex)
{
throw new SchedulerException("Job instantiation failed", ex);
}
}
/// <summary>
/// Allows the the job factory to destroy/cleanup the job if needed.
/// </summary>
public virtual void ReturnJob(IJob job)
{
}
/// <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<object>(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 job)
{
return job;
}
if (jobObject is ThreadStart start)
{
return new DelegatingJob(start);
}
if (jobObject is IThreadRunnable threadRunnable)
{
return new DelegatingJob(() => threadRunnable.Run().ConfigureAwait(false).GetAwaiter().GetResult());
}
if (jobObject is Func<Task> func)
{
return new DelegatingJob(() => func().ConfigureAwait(false).GetAwaiter().GetResult());
}
string message =
$"Unable to execute job class [{jobObject.GetType().FullName}]: only [IJob] and [ThreadStart] supported.";
throw new ArgumentException(message);
}
}
}

View File

@@ -17,7 +17,6 @@
using System;
using System.Collections;
using System.Reflection;
using Quartz;
using Quartz.Impl.Triggers;
using Spring.Objects.Factory;
@@ -25,69 +24,73 @@ using Spring.Util;
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>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <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>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <seealso cref="ITrigger.Key" />
/// <seealso cref="ITrigger.StartTimeUtc" />
/// <seealso cref="ITrigger.JobKey" />
/// <seealso cref="JobDetail" />
/// <seealso cref="SchedulerAccessor.Triggers" />
/// <seealso cref="SchedulerAccessor.JobDetails" />
public class CronTriggerObject : CronTriggerImpl, IJobDetailAwareTrigger, IObjectNameAware, IInitializingObject
{
private readonly Constants constants = new Constants(typeof(MisfireInstruction.CronTrigger), typeof(MisfireInstruction));
/// <seealso cref="SchedulerAccessor.Triggers" />
/// <seealso cref="SchedulerAccessor.JobDetails" />
public class CronTriggerObject : CronTriggerImpl, IJobDetailAwareTrigger, IObjectNameAware, IInitializingObject
{
private readonly Constants constants = new Constants(
typeof(MisfireInstruction.CronTrigger),
typeof(MisfireInstruction)
);
private IJobDetail jobDetail;
private string objectName;
private TimeSpan startDelay;
private string objectName;
private TimeSpan startDelay;
/// <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
{
foreach (DictionaryEntry entry in value)
{
JobDataMap.Put((string) entry.Key, entry.Value);
}
}
}
/// <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
{
foreach (DictionaryEntry entry in value)
{
JobDataMap.Put((string) entry.Key, entry.Value);
}
}
}
/// <summary>
/// Set the misfire instruction via the name of the corresponding
/// constant in the CronTrigger class.
/// <summary>
/// Set the misfire instruction via the name of the corresponding
/// constant in the CronTrigger class.
/// Default is <see cref="MisfireInstruction.SmartPolicy" />.
/// </summary>
/// </summary>
/// <seealso cref="MisfireInstruction.CronTrigger.FireOnceNow" />
/// <seealso cref="MisfireInstruction.CronTrigger.DoNothing" />
/// <seealso cref="MisfireInstruction.SmartPolicy" />
public virtual string MisfireInstructionName
{
set { MisfireInstruction = constants.AsNumber(value); }
}
public virtual string MisfireInstructionName
{
set => MisfireInstruction = constants.AsNumber(value);
}
/// <summary>
/// Set the name of the object in the object factory that created this object.
@@ -101,25 +104,25 @@ namespace Spring.Scheduling.Quartz
/// method or a custom init-method.
/// </p>
/// </remarks>
public virtual string ObjectName
{
set { objectName = value; }
}
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="ITrigger.JobKey" />
public virtual IJobDetail JobDetail
{
get { return jobDetail; }
set { jobDetail = 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="ITrigger.JobKey" />
public virtual IJobDetail JobDetail
{
get => jobDetail;
set => jobDetail = value;
}
/// <summary>
/// Set the start delay as <see cref="TimeSpan" />.
@@ -136,17 +139,17 @@ namespace Spring.Scheduling.Quartz
/// </para>
/// </remarks>
/// <value>the start delay, as <see cref="TimeSpan" /> object.</value>
public TimeSpan StartDelay
public TimeSpan StartDelay
{
set
{
AssertUtils.State(value >= TimeSpan.Zero, "Start delay cannot be negative.");
startDelay = value;
}
get { return startDelay; }
{
AssertUtils.State(value >= TimeSpan.Zero, "Start delay cannot be negative.");
startDelay = value;
}
get => startDelay;
}
/// <summary>
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// after it has injected all of an object's dependencies.
/// </summary>
@@ -172,31 +175,35 @@ namespace Spring.Scheduling.Quartz
/// In the event of misconfiguration (such as the failure to set a
/// required property) or if initialization fails.
/// </exception>
public virtual void AfterPropertiesSet()
{
public virtual void AfterPropertiesSet()
{
if (StartTimeUtc == DateTimeOffset.MinValue)
{
StartTimeUtc = DateTimeOffset.UtcNow;
}
if (StartDelay > TimeSpan.Zero)
{
StartTimeUtc = DateTime.UtcNow.Add(startDelay);
}
if (Name == null)
{
Name = objectName;
}
if (Group == null)
{
if (Name == null)
{
Name = objectName;
}
if (Group == null)
{
Group = SchedulerConstants.DefaultGroup;
}
if (jobDetail != null)
{
JobName = jobDetail.Key.Name;
JobGroup = jobDetail.Key.Group;
}
}
}
}
if (jobDetail != null)
{
JobName = jobDetail.Key.Name;
JobGroup = jobDetail.Key.Group;
}
}
}
/// <summary>
/// Helper class to map constant names to their values.
@@ -222,7 +229,7 @@ namespace Spring.Scheduling.Quartz
}
// not found
throw new Exception(string.Format("Unknown field '{0}'", field));
throw new Exception($"Unknown field '{field}'");
}
}
}

View File

@@ -13,59 +13,50 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Threading;
using System.Threading.Tasks;
using Quartz;
using Spring.Util;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Simple Quartz IJob adapter that delegates to a
/// <summary>
/// Simple Quartz IJob adapter that delegates to a
/// given <see cref="ThreadStart" /> instance.
/// </summary>
/// <remarks>
/// Typically used in combination with property injection on the
/// Runnable instance, receiving parameters from the Quartz JobDataMap
/// that way instead of via the JobExecutionContext.
/// Typically used in combination with property injection on the
/// Runnable instance, receiving parameters from the Quartz JobDataMap
/// that way instead of via the JobExecutionContext.
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <author>Marko Lahma (.NET)</author>
/// <seealso cref="SpringObjectJobFactory" />
/// <seealso cref="IJob.Execute(IJobExecutionContext)" />
public class DelegatingJob : IJob
{
/// <author>Juergen Hoeller</author>
/// <author>Marko Lahma (.NET)</author>
/// <seealso cref="SpringObjectJobFactory" />
/// <seealso cref="IJob.Execute(IJobExecutionContext)" />
public class DelegatingJob : IJob
{
private readonly ThreadStart delegateInstance;
/// <summary>
/// Return the wrapped Runnable implementation.
/// <summary>
/// Create a new DelegatingJob.
/// </summary>
/// <value>The delegate.</value>
public virtual ThreadStart Delegate
{
get { return delegateInstance; }
}
/// <summary>
/// Create a new DelegatingJob.
/// </summary>
/// <param name="delegateInstance">
/// The Runnable implementation to delegate to.
/// </param>
/// <param name="delegateInstance">
/// The Runnable implementation to delegate to.
/// </param>
public DelegatingJob(ThreadStart delegateInstance)
{
{
AssertUtils.ArgumentNotNull(delegateInstance, "delegateInstance", "Delegate must not be null");
this.delegateInstance = delegateInstance;
}
this.delegateInstance = delegateInstance;
}
/// <summary>
/// <summary>
/// Delegates execution to the underlying ThreadStart.
/// </summary>
public virtual void Execute(IJobExecutionContext context)
{
/// </summary>
public virtual Task Execute(IJobExecutionContext context)
{
delegateInstance.Invoke();
}
}
return Task.FromResult(true);
}
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 2002-2010 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="SchedulerAccessor.Triggers" />
/// <seealso cref="SchedulerAccessor.JobDetails" />
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>
IJobDetail JobDetail { get; }
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 2002-2010 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 Quartz.Spi;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Callback interface to be implemented by Spring-managed
/// Quartz artifacts that need access to the SchedulerContext
/// (without having natural access to it).
/// </summary>
/// <remarks>
/// Currently only supported for custom JobFactory implementations
/// that are passed in via Spring's SchedulerFactoryObject.
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <seealso cref="IJobFactory" />
/// <seealso cref="SchedulerFactoryObject.JobFactory" />
public interface ISchedulerContextAware
{
/// <summary>
/// Set the SchedulerContext of the current Quartz Scheduler.
/// </summary>
/// <seealso cref="IScheduler.Context" />
SchedulerContext SchedulerContext { set; }
}
}

View File

@@ -18,14 +18,14 @@ using System.Threading;
namespace Spring.Scheduling
{
/// <summary>
///
/// </summary>
public interface ITaskExecutor
{
/// <summary>
/// Executes this instance.
/// </summary>
void Execute(ThreadStart runnable);
}
}
/// <summary>
///
/// </summary>
public interface ITaskExecutor
{
/// <summary>
/// Executes this instance.
/// </summary>
void Execute(ThreadStart runnable);
}
}

View File

@@ -0,0 +1,33 @@
#region License
// /*
// * Copyright 2018 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.
// */
#endregion
using System.Threading.Tasks;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Adapter interface as Quartz no longer has this interface.
/// </summary>
public interface IThreadRunnable
{
/// <summary>
/// Runs thread runnable.
/// </summary>
Task Run();
}
}

View File

@@ -0,0 +1,224 @@
/*
* Copyright 2002-2010 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 Quartz.Impl;
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="IJobDetail" /> 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="IJobDetail.Key" />
/// <seealso cref="SchedulerConstants.DefaultGroup" />
public class JobDetailObject : JobDetailImpl, IObjectNameAware, IApplicationContextAware, IInitializingObject
{
private Type actualJobType;
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 override Type JobType
{
get => actualJobType ?? base.JobType;
set
{
if (value != null && !typeof(IJob).IsAssignableFrom(value))
{
base.JobType = typeof(DelegatingJob);
actualJobType = value;
}
else
{
base.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
{
if (value == null)
{
throw new ArgumentException("Value cannot be null", "value");
}
foreach (DictionaryEntry entry in value)
{
JobDataMap.Put((string) entry.Key, entry.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>
/// Gets or sets 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 => 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.DefaultGroup;
}
if (applicationContextJobDataKey != null)
{
if (applicationContext == null)
{
throw new ArgumentException("JobDetailObject needs to be set up in an IApplicationContext " +
"to be able to handle an 'applicationContextJobDataKey'");
}
JobDataMap.Put(applicationContextJobDataKey, applicationContext);
}
}
}
}

View File

@@ -15,7 +15,6 @@
*/
using System;
using Spring.Objects.Support;
namespace Spring.Scheduling.Quartz
@@ -35,12 +34,9 @@ namespace Spring.Scheduling.Quartz
/// <param name="methodInvoker">the MethodInvoker used for reflective invocation</param>
/// <param name="cause">the root cause (as thrown from the target method)</param>
public JobMethodInvocationFailedException(MethodInvoker methodInvoker, Exception cause) :
base("Invocation of method '" + methodInvoker.TargetMethod +
"' on target class [" + methodInvoker.TargetType + "] failed", cause)
base("Invocation of method '" + methodInvoker.TargetMethod +
"' on target class [" + methodInvoker.TargetType + "] failed", cause)
{
}
}
}
}

View File

@@ -14,10 +14,10 @@
* limitations under the License.
*/
using System.Data.Common;
using Quartz;
using Quartz.Impl.AdoJobStore;
using Quartz.Util;
using Spring.Data.Support;
namespace Spring.Scheduling.Quartz
@@ -48,7 +48,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="DBConnectionManager.AddConnectionProvider" />
/// <seealso cref="SchedulerFactoryObject.DbProvider" />
/// </summary>
public const string TX_DATA_SOURCE_PREFIX = "springTxDataSource.";
public const string TxDataSourcePrefix = "springTxDataSource.";
private Data.Common.IDbProvider dbProvider;
@@ -58,12 +58,12 @@ namespace Spring.Scheduling.Quartz
/// <value>The name of the instance.</value>
public override string InstanceName
{
get { return base.InstanceName; }
get => base.InstanceName;
set
{
// use to catch property setting
base.InstanceName = value;
DataSource = TX_DATA_SOURCE_PREFIX + InstanceName;
DataSource = TxDataSourcePrefix + InstanceName;
// Register transactional ConnectionProvider for Quartz.
// Absolutely needs thread-bound DataSource to initialize.
dbProvider = SchedulerFactoryObject.ConfigTimeDbProvider;
@@ -72,10 +72,10 @@ namespace Spring.Scheduling.Quartz
throw new SchedulerConfigException(
"No db provider found for configuration - " +
"'DbProvider' property must be set on SchedulerFactoryObject");
}
DBConnectionManager.Instance.AddConnectionProvider(
TX_DATA_SOURCE_PREFIX + InstanceName, new SpringDbProviderAdapter(dbProvider));
}
DBConnectionManager.Instance.AddConnectionProvider(
TxDataSourcePrefix + InstanceName, new SpringDbProviderAdapter(dbProvider));
}
}
@@ -86,7 +86,7 @@ namespace Spring.Scheduling.Quartz
protected override ConnectionAndTransactionHolder GetNonManagedTXConnection()
{
ConnectionTxPair pair = ConnectionUtils.DoGetConnection(dbProvider);
return new ConnectionAndTransactionHolder(pair.Connection, pair.Transaction);
return new ConnectionAndTransactionHolder((DbConnection) pair.Connection, (DbTransaction) pair.Transaction);
}
/// <summary>
@@ -99,4 +99,4 @@ namespace Spring.Scheduling.Quartz
ConnectionUtils.DisposeConnection(connectionAndTransactionHolder.Connection, dbProvider);
}
}
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 2002-2010 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.Tasks;
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
{
private ITaskExecutor taskExecutor;
/// <summary>
/// Initializes a new instance of the <see cref="LocalTaskExecutorThreadPool"/> class.
/// </summary>
public LocalTaskExecutorThreadPool()
{
Logger = LogManager.GetLogger(GetType());
}
/// <summary>
/// Logger instance.
/// </summary>
protected ILog Logger { get; }
/// <inheritdoc />
public virtual int PoolSize => -1;
/// <inheritdoc />
public string InstanceId
{
set { }
}
/// <inheritdoc />
public string InstanceName
{
set { }
}
/// <inheritdoc />
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");
}
}
/// <inheritdoc />
public virtual void Shutdown(bool waitForJobsToComplete)
{
}
/// <inheritdoc />
public virtual bool RunInThread(Func<Task> runnable)
{
if (runnable == null)
{
return false;
}
try
{
taskExecutor.Execute(() => runnable().ConfigureAwait(false).GetAwaiter().GetResult());
return true;
}
catch (TaskRejectedException ex)
{
Logger.Error("Task has been rejected by TaskExecutor", ex);
return false;
}
}
/// <inheritdoc />
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;
}
}
}

View File

@@ -16,11 +16,9 @@
using System;
using System.Reflection;
using System.Threading.Tasks;
using Common.Logging;
using Quartz;
using Spring.Objects.Support;
namespace Spring.Scheduling.Quartz
@@ -42,28 +40,23 @@ namespace Spring.Scheduling.Quartz
{
set
{
if (value == null)
{
throw new ArgumentException("Method invoker cannot be null", "value");
}
methodInvoker = value;
methodInvoker = value ?? throw new ArgumentException("Method invoker cannot be null", nameof(value));
errorMessage =
string.Format("Could not invoke method '{0}' on target object [{1}]", methodInvoker.TargetMethod,
methodInvoker.TargetObject);
$"Could not invoke method '{methodInvoker.TargetMethod}' on target object [{methodInvoker.TargetObject}]";
}
}
/// <summary>
/// Invoke the method via the MethodInvoker.
/// </summary>
/// <param name="context"></param>
protected override void ExecuteInternal(IJobExecutionContext context)
protected override Task ExecuteInternal(IJobExecutionContext context)
{
if (methodInvoker == null)
{
throw new JobExecutionException("Could not execute job when method invoker is null");
}
try
{
context.Result = methodInvoker.Invoke();
@@ -76,15 +69,17 @@ namespace Spring.Scheduling.Quartz
// -> JobExecutionException, to be logged at info level by Quartz
throw ex.GetBaseException();
}
// -> "unhandled exception", to be logged at error level by Quartz
throw new JobMethodInvocationFailedException(methodInvoker, ex.GetBaseException());
}
catch (Exception ex)
{
// -> "unhandled exception", to be logged at error level by Quartz
throw new JobMethodInvocationFailedException(methodInvoker, ex.GetBaseException());
throw new JobMethodInvocationFailedException(methodInvoker, ex.GetBaseException());
}
return Task.FromResult(true);
}
}
}
}

View File

@@ -0,0 +1,284 @@
/*
* Copyright 2002-2010 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 Quartz.Impl;
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,
IObjectFactoryAware,
IFactoryObject,
IObjectNameAware,
IInitializingObject
{
private string name;
private string group;
private bool concurrent = true;
private string[] jobListenerNames;
private string targetObjectName;
private string objectName;
private JobDetailImpl jobDetail;
private IObjectFactory objectFactory;
/// <summary>
/// Initializes a new instance of the <see cref="MethodInvokingJobDetailFactoryObject"/> class.
/// </summary>
public MethodInvokingJobDetailFactoryObject()
{
group = SchedulerConstants.DefaultGroup;
}
/// <summary>
/// Set the name of the job.
/// Default is the object name of this FactoryObject.
/// </summary>
/// <seealso cref="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="Group" />
/// <seealso cref="SchedulerConstants.DefaultGroup" />
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="DisallowConcurrentExecutionAttribute" /> attribute.
/// 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>
/// Gets the job detail.
/// </summary>
/// <value>The job detail.</value>
protected IJobDetail JobDetail => jobDetail;
/// <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="SchedulerAccessor.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>
/// Set the name of the target object in the Spring object factory.
/// </summary>
/// <remarks>
/// This is an alternative to specifying TargetObject
/// allowing for non-singleton objects to be invoked. Note that specified
/// "TargetObject" and "TargetType" values will
/// override the corresponding effect of this "TargetObjectName" setting
///(i.e. statically pre-define the object type or even the target object).
/// </remarks>
public string TargetObjectName
{
set => targetObjectName = value;
}
/// <summary>
/// Sets the object factory.
/// </summary>
/// <value>The object factory.</value>
public IObjectFactory ObjectFactory
{
set => objectFactory = 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 virtual 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
{
if (targetObjectName != null)
{
if (objectFactory == null)
{
throw new InvalidOperationException("ObjectFactory must be set when using 'TargetObjectName'");
}
return objectFactory.GetType(targetObjectName);
}
return typeof(IJobDetail);
}
}
/// <summary>
/// Is the object managed by this factory a singleton or a prototype?
/// </summary>
/// <value></value>
public virtual bool IsSingleton => 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 ?? objectName;
// Consider the concurrent flag to choose between stateful and stateless job.
Type jobType = (concurrent ? typeof(MethodInvokingJob) : typeof(StatefulMethodInvokingJob));
// Build JobDetail instance.
jobDetail = new JobDetailImpl(jobDetailName, group, jobType);
jobDetail.JobDataMap.Put("methodInvoker", this);
jobDetail.Durable = true;
// job listeners through configuration are no longer supported
if (jobListenerNames != null && jobListenerNames.Length > 0)
{
throw new InvalidOperationException("Non-global IJobListeners not supported on Quartz 2 - " +
"manually register a Matcher against the Quartz ListenerManager instead");
}
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(IJobDetail detail)
{
}
}
}

View File

@@ -13,13 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Reflection;
using System.Threading.Tasks;
using Common.Logging;
using Quartz;
using Spring.Objects.Factory;
using Spring.Objects.Support;
@@ -34,19 +32,6 @@ namespace Spring.Scheduling.Quartz
/// 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" />
@@ -69,19 +54,14 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// Logger instance.
/// </summary>
protected ILog Logger
{
get { return logger; }
}
protected ILog Logger => logger;
/// <summary>
/// Gets the invocation failure message.
/// </summary>
/// <value>The invocation failure message.</value>
protected virtual string InvocationFailureMessage
{
get { return string.Format("Invocation of method '{0}' on target object [{1}] failed", TargetMethod, TargetObject); }
}
protected virtual string InvocationFailureMessage =>
$"Invocation of method '{TargetMethod}' on target object [{TargetObject}] failed";
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
@@ -118,7 +98,7 @@ namespace Spring.Scheduling.Quartz
/// 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()
public virtual Task Run()
{
try
{
@@ -134,6 +114,8 @@ namespace Spring.Scheduling.Quartz
logger.Error(InvocationFailureMessage, ex);
// Do not throw exception, else the main loop of the Timer will stop!
}
return Task.FromResult(true);
}
}
}

View File

@@ -0,0 +1,86 @@
/*
* Copyright 2002-2010 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.Tasks;
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="IJobExecutionContext.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 Task Execute(IJobExecutionContext 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)
{
throw new JobExecutionException(ex);
}
return ExecuteInternal(context);
}
/// <summary>
/// Execute the actual job. The job data map will already have been
/// applied as object property values by execute. The contract is
/// exactly the same as for the standard Quartz execute method.
/// </summary>
/// <seealso cref="Execute" />
protected abstract Task ExecuteInternal(IJobExecutionContext context);
}
}

View File

@@ -14,16 +14,14 @@
* limitations under the License.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using Common.Logging;
using Quartz;
using Quartz.Simpl;
using Quartz.Xml;
using Spring.Collections;
using Spring.Context;
using Spring.Core.IO;
@@ -48,6 +46,7 @@ namespace Spring.Scheduling.Quartz
/// Logger instance.
/// </summary>
private readonly ILog logger;
private bool overwriteExistingJobs;
private string[] jobSchedulingDataLocations;
@@ -63,6 +62,7 @@ namespace Spring.Scheduling.Quartz
private ITriggerListener[] triggerListeners;
private IPlatformTransactionManager transactionManager;
/// <summary>
/// Resource loader instance for sub-classes
/// </summary>
@@ -83,10 +83,9 @@ namespace Spring.Scheduling.Quartz
/// </summary>
public virtual bool OverwriteExistingJobs
{
set { overwriteExistingJobs = value; }
set => overwriteExistingJobs = value;
}
/// <summary>
/// Set the locations of Quartz job definition XML files that follow the
/// "job_scheduling_data_1_5" XSD. Can be specified to automatically
@@ -96,7 +95,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="XMLSchedulingDataProcessor" />
public virtual string[] JobSchedulingDataLocations
{
set { jobSchedulingDataLocations = value; }
set => jobSchedulingDataLocations = value;
}
/// <summary>
@@ -108,7 +107,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="XMLSchedulingDataProcessor" />
public virtual string JobSchedulingDataLocation
{
set { jobSchedulingDataLocations = new string[] {value}; }
set => jobSchedulingDataLocations = new string[] {value};
}
/// <summary>
@@ -125,12 +124,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="ITrigger.JobKey" />
public virtual IJobDetail[] JobDetails
{
set
{
// Use modifiable ArrayList here, to allow for further adding of
// JobDetail objects during autodetection of JobDetailAwareTriggers.
jobDetails = new List<IJobDetail>(value);
}
set => jobDetails = new List<IJobDetail>(value);
}
/// <summary>
@@ -142,7 +136,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="ITrigger.CalendarName" />
public virtual IDictionary Calendars
{
set { calendars = value; }
set => calendars = value;
}
/// <summary>
@@ -162,7 +156,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="SimpleTriggerObject" />
public virtual ITrigger[] Triggers
{
set { triggers = new ArrayList(value); }
set => triggers = new ArrayList(value);
}
/// <summary>
@@ -170,7 +164,7 @@ namespace Spring.Scheduling.Quartz
/// </summary>
public virtual ISchedulerListener[] SchedulerListeners
{
set { schedulerListeners = value; }
set => schedulerListeners = value;
}
/// <summary>
@@ -179,7 +173,7 @@ namespace Spring.Scheduling.Quartz
/// </summary>
public virtual IJobListener[] GlobalJobListeners
{
set { globalJobListeners = value; }
set => globalJobListeners = value;
}
/// <summary>
@@ -190,20 +184,18 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="IJobListener.Name" />
public virtual IJobListener[] JobListeners
{
set { jobListeners = value; }
set => jobListeners = value;
}
/// <summary>
/// Specify global Quartz TriggerListeners to be registered with the Scheduler.
/// Such TriggerListeners will apply to all Triggers in the Scheduler.
/// </summary>
public virtual ITriggerListener[] GlobalTriggerListeners
{
set { globalTriggerListeners = value; }
set => globalTriggerListeners = value;
}
/// <summary>
/// Specify named Quartz TriggerListeners to be registered with the Scheduler.
/// Such TriggerListeners will only apply to Triggers that explicitly activate
@@ -212,10 +204,9 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="ITriggerListener.Name" />
public virtual ITriggerListener[] TriggerListeners
{
set { triggerListeners = value; }
set => triggerListeners = value;
}
/// <summary>
/// Set the transaction manager to be used for registering jobs and triggers
/// that are defined by this SchedulerFactoryObject. Default is none; setting
@@ -223,7 +214,7 @@ namespace Spring.Scheduling.Quartz
/// </summary>
public virtual IPlatformTransactionManager TransactionManager
{
set { transactionManager = value; }
set => transactionManager = value;
}
/// <summary>
@@ -250,30 +241,28 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// Logger instance.
/// </summary>
protected ILog Logger
{
get { return logger; }
}
protected ILog Logger => logger;
/// <summary>
/// Register jobs and triggers (within a transaction, if possible).
/// </summary>
protected virtual void RegisterJobsAndTriggers()
protected virtual async Task RegisterJobsAndTriggers()
{
ITransactionStatus transactionStatus = null;
if (transactionManager != null)
{
transactionStatus = transactionManager.GetTransaction(new DefaultTransactionDefinition());
}
try
{
if (jobSchedulingDataLocations != null)
{
XMLSchedulingDataProcessor dataProcessor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper());
var dataProcessor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper());
dataProcessor.OverWriteExistingData = overwriteExistingJobs;
foreach (string location in jobSchedulingDataLocations)
{
dataProcessor.ProcessFileAndScheduleJobs(location, GetScheduler());
await dataProcessor.ProcessFileAndScheduleJobs(location, GetScheduler()).ConfigureAwait(false);
}
}
@@ -282,7 +271,7 @@ namespace Spring.Scheduling.Quartz
{
foreach (IJobDetail jobDetail in jobDetails)
{
AddJobToScheduler(jobDetail);
await AddJobToScheduler(jobDetail).ConfigureAwait(false);
}
}
else
@@ -298,7 +287,7 @@ namespace Spring.Scheduling.Quartz
{
string calendarName = (string) entry.Key;
ICalendar calendar = (ICalendar) entry.Value;
GetScheduler().AddCalendar(calendarName, calendar, true, true);
await GetScheduler().AddCalendar(calendarName, calendar, true, true).ConfigureAwait(false);
}
}
@@ -307,11 +296,10 @@ namespace Spring.Scheduling.Quartz
{
foreach (ITrigger trigger in triggers)
{
AddTriggerToScheduler(trigger);
await AddTriggerToScheduler(trigger).ConfigureAwait(false);
}
}
}
catch (Exception ex)
{
if (transactionStatus != null)
@@ -326,10 +314,12 @@ namespace Spring.Scheduling.Quartz
throw;
}
}
if (ex is SchedulerException)
{
throw;
}
throw new SchedulerException("Registration of jobs and triggers failed: " + ex.Message);
}
@@ -345,17 +335,16 @@ namespace Spring.Scheduling.Quartz
/// </summary>
/// <param name="jobDetail">the job to add</param>
/// <returns><code>true</code> if the job was actually added, <code>false</code> if it already existed before</returns>
private bool AddJobToScheduler(IJobDetail jobDetail)
private async Task<bool> AddJobToScheduler(IJobDetail jobDetail)
{
if (overwriteExistingJobs || GetScheduler().GetJobDetail(jobDetail.Key) == null)
if (overwriteExistingJobs
|| await GetScheduler().GetJobDetail(jobDetail.Key).ConfigureAwait(false) == null)
{
GetScheduler().AddJob(jobDetail, true, true);
await GetScheduler().AddJob(jobDetail, true, true).ConfigureAwait(false);
return true;
}
else
{
return false;
}
return false;
}
/// <summary>
@@ -364,45 +353,48 @@ namespace Spring.Scheduling.Quartz
/// </summary>
/// <param name="trigger">the trigger to add</param>
/// <returns><code>true</code> if the trigger was actually added, <code>false</code> if it already existed before</returns>
private bool AddTriggerToScheduler(ITrigger trigger)
private async Task<bool> AddTriggerToScheduler(ITrigger trigger)
{
bool triggerExists = (GetScheduler().GetTrigger(trigger.Key) != null);
if (!triggerExists || this.overwriteExistingJobs)
bool triggerExists = await GetScheduler().GetTrigger(trigger.Key).ConfigureAwait(false) != null;
if (!triggerExists || overwriteExistingJobs)
{
// Check if the Trigger is aware of an associated JobDetail.
if (trigger is IJobDetailAwareTrigger)
if (trigger is IJobDetailAwareTrigger awareTrigger)
{
IJobDetail jobDetail = ((IJobDetailAwareTrigger) trigger).JobDetail;
IJobDetail jobDetail = awareTrigger.JobDetail;
// Automatically register the JobDetail too.
if (!jobDetails.Contains(jobDetail) && AddJobToScheduler(jobDetail))
if (!jobDetails.Contains(jobDetail)
&& await AddJobToScheduler(jobDetail).ConfigureAwait(false))
{
jobDetails.Add(jobDetail);
}
}
if (!triggerExists)
{
try
{
GetScheduler().ScheduleJob(trigger);
await GetScheduler().ScheduleJob(trigger).ConfigureAwait(false);
}
catch (ObjectAlreadyExistsException ex)
{
if (logger.IsDebugEnabled)
{
logger.Debug(
"Unexpectedly found existing trigger, assumably due to cluster race condition: " +
ex.Message + " - can safely be ignored");
$"Unexpectedly found existing trigger, assumably due to cluster race condition: {ex.Message} - can safely be ignored");
}
if (overwriteExistingJobs)
{
GetScheduler().RescheduleJob(trigger.Key, trigger);
await GetScheduler().RescheduleJob(trigger.Key, trigger).ConfigureAwait(false);
}
}
}
else
{
GetScheduler().RescheduleJob(trigger.Key, trigger);
await GetScheduler().RescheduleJob(trigger.Key, trigger).ConfigureAwait(false);
}
return true;
}
else
@@ -411,7 +403,6 @@ namespace Spring.Scheduling.Quartz
}
}
/// <summary>
/// Register all specified listeners with the Scheduler.
/// </summary>
@@ -424,6 +415,7 @@ namespace Spring.Scheduling.Quartz
GetScheduler().ListenerManager.AddSchedulerListener(schedulerListeners[i]);
}
}
if (globalJobListeners != null)
{
foreach (IJobListener jobListener in globalJobListeners)
@@ -431,11 +423,13 @@ namespace Spring.Scheduling.Quartz
GetScheduler().ListenerManager.AddJobListener(jobListener);
}
}
if (jobListeners != null && jobListeners.Length > 0)
{
throw new InvalidOperationException("Non-global JobListeners not supported on Quartz 2 - " +
"manually register a Matcher against the Quartz ListenerManager instead");
throw new InvalidOperationException("Non-global JobListeners not supported on Quartz 2 - " +
"manually register a Matcher against the Quartz ListenerManager instead");
}
if (globalTriggerListeners != null)
{
foreach (ITriggerListener triggerListener in globalTriggerListeners)
@@ -443,10 +437,11 @@ namespace Spring.Scheduling.Quartz
GetScheduler().ListenerManager.AddTriggerListener(triggerListener);
}
}
if (triggerListeners != null && triggerListeners.Length > 0)
{
throw new InvalidOperationException("Non-global TriggerListeners not supported on Quartz 2 - " +
"manually register a Matcher against the Quartz ListenerManager instead");
"manually register a Matcher against the Quartz ListenerManager instead");
}
}

View File

@@ -15,10 +15,8 @@
*/
using System;
using System.Collections.Generic;
using Quartz;
using Quartz.Impl;
using Spring.Objects.Factory;
namespace Spring.Scheduling.Quartz
@@ -50,7 +48,7 @@ namespace Spring.Scheduling.Quartz
/// </remarks>
public string SchedulerName
{
set { schedulerName = value; }
set => schedulerName = value;
}
/// <summary>
@@ -58,7 +56,7 @@ namespace Spring.Scheduling.Quartz
/// </summary>
protected IScheduler Scheduler
{
set { scheduler = value; }
set => scheduler = value;
}
/// <summary>
@@ -75,10 +73,9 @@ namespace Spring.Scheduling.Quartz
/// </summary>
public IObjectFactory ObjectFactory
{
set { objectFactory = value; }
set => objectFactory = value;
}
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// after it has injected all of an object's dependencies.
@@ -118,8 +115,9 @@ namespace Spring.Scheduling.Quartz
throw new InvalidOperationException("No Scheduler specified");
}
}
RegisterListeners();
RegisterJobsAndTriggers();
RegisterJobsAndTriggers().ConfigureAwait(false).GetAwaiter().GetResult();
}
/// <summary>
@@ -129,26 +127,27 @@ namespace Spring.Scheduling.Quartz
/// <returns></returns>
protected virtual IScheduler FindScheduler(string schedulerName)
{
if (objectFactory is IListableObjectFactory)
if (objectFactory is IListableObjectFactory lbf)
{
IListableObjectFactory lbf = (IListableObjectFactory) objectFactory;
IEnumerable<string> objectNames = lbf.GetObjectNamesForType(typeof(IScheduler));
var objectNames = lbf.GetObjectNamesForType(typeof(IScheduler));
foreach (string objectName in objectNames)
{
IScheduler schedulerObject = (IScheduler)lbf.GetObject(objectName);
IScheduler schedulerObject = (IScheduler) lbf.GetObject(objectName);
if (schedulerName.Equals(schedulerObject.SchedulerName))
{
return schedulerObject;
}
}
}
IScheduler schedulerInRepo = SchedulerRepository.Instance.Lookup(schedulerName);
IScheduler schedulerInRepo = SchedulerRepository.Instance.Lookup(schedulerName)
.ConfigureAwait(false).GetAwaiter().GetResult();
if (schedulerInRepo == null)
{
throw new InvalidOperationException("No Scheduler named '" + schedulerName + "' found");
}
return schedulerInRepo;
}
}
}

View File

@@ -19,13 +19,12 @@ using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Quartz;
using Quartz.Impl;
using Quartz.Simpl;
using Quartz.Spi;
using Quartz.Util;
using Spring.Context;
using Spring.Context.Events;
using Spring.Core.IO;
@@ -81,18 +80,16 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// Default thread count to be set to thread pool.
/// </summary>
public const int DEFAULT_THREAD_COUNT = 10;
public const int DefaultThreadCount = 10;
/// <summary>
/// Property name for thread count in thread pool.
/// </summary>
public const string PROP_THREAD_COUNT = "quartz.threadPool.threadCount";
public const string PropThreadCount = "quartz.threadPool.threadCount";
[ThreadStatic]
private static IDbProvider configTimeDbProvider;
[ThreadStatic] private static IDbProvider configTimeDbProvider;
[ThreadStatic]
private static ITaskExecutor configTimeTaskExecutor;
[ThreadStatic] private static ITaskExecutor configTimeTaskExecutor;
/// <summary>
/// Return the IDbProvider for the currently configured Quartz Scheduler,
@@ -105,10 +102,7 @@ namespace Spring.Scheduling.Quartz
/// </remarks>
/// <seealso cref="DbProvider" />
/// <seealso cref="LocalDataSourceJobStore" />
public static IDbProvider ConfigTimeDbProvider
{
get { return configTimeDbProvider; }
}
public static IDbProvider ConfigTimeDbProvider => configTimeDbProvider;
/// <summary>
/// Return the TaskExecutor for the currently configured Quartz Scheduler,
@@ -119,10 +113,7 @@ namespace Spring.Scheduling.Quartz
/// Scheduler, and reset immediately afterwards. It is thus only available
/// during configuration.
/// </remarks>
public static ITaskExecutor ConfigTimeTaskExecutor
{
get { return configTimeTaskExecutor; }
}
public static ITaskExecutor ConfigTimeTaskExecutor => configTimeTaskExecutor;
private IApplicationContext applicationContext;
private string applicationContextSchedulerContextKey;
@@ -146,7 +137,7 @@ namespace Spring.Scheduling.Quartz
/// </summary>
public SchedulerFactoryObject()
{
schedulerFactoryType = typeof (StdSchedulerFactory);
schedulerFactoryType = typeof(StdSchedulerFactory);
}
/// <summary>
@@ -165,10 +156,11 @@ namespace Spring.Scheduling.Quartz
{
set
{
if (value == null || !typeof (ISchedulerFactory).IsAssignableFrom(value))
if (value == null || !typeof(ISchedulerFactory).IsAssignableFrom(value))
{
throw new ArgumentException("schedulerFactoryType must implement [Quartz.ISchedulerFactory]");
}
schedulerFactoryType = value;
}
}
@@ -182,7 +174,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="ISchedulerFactory.GetScheduler()"/>
public virtual string SchedulerName
{
set { schedulerName = value; }
set => schedulerName = value;
}
/// <summary>
@@ -196,7 +188,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="QuartzProperties" />
public virtual IResource ConfigLocation
{
set { configLocation = value; }
set => configLocation = value;
}
/// <summary>
@@ -209,7 +201,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="ConfigLocation" />
public virtual IDictionary QuartzProperties
{
set { quartzProperties = value; }
set => quartzProperties = value;
}
/// <summary>
@@ -225,7 +217,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="LocalTaskExecutorThreadPool"/>
public virtual ITaskExecutor TaskExecutor
{
set { taskExecutor = value; }
set => taskExecutor = value;
}
/// <summary>
@@ -244,7 +236,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="JobDetailObject.JobDataAsMap" />
public virtual IDictionary SchedulerContextAsMap
{
set { schedulerContextMap = value; }
set => schedulerContextMap = value;
}
/// <summary>
@@ -275,7 +267,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="JobDetailObject.ApplicationContextJobDataKey"/>
public virtual string ApplicationContextSchedulerContextKey
{
set { applicationContextSchedulerContextKey = value; }
set => applicationContextSchedulerContextKey = value;
}
/// <summary>
@@ -317,7 +309,7 @@ namespace Spring.Scheduling.Quartz
/// </remarks>
public virtual bool ExposeSchedulerInRepository
{
set { exposeSchedulerInRepository = value; }
set => exposeSchedulerInRepository = value;
}
/// <summary>
@@ -326,7 +318,7 @@ namespace Spring.Scheduling.Quartz
/// </summary>
public virtual bool AutoStartup
{
set { autoStartup = value; }
set => autoStartup = value;
}
/// <summary>
@@ -340,7 +332,7 @@ namespace Spring.Scheduling.Quartz
/// </remarks>
public virtual TimeSpan StartupDelay
{
set { startupDelay = value; }
set => startupDelay = value;
}
/// <summary>
@@ -353,7 +345,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="IScheduler.Shutdown(bool)"/>
public virtual bool WaitForJobsToCompleteOnShutdown
{
set { waitForJobsToCompleteOnShutdown = value; }
set => waitForJobsToCompleteOnShutdown = value;
}
/// <summary>
@@ -377,7 +369,7 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="LocalDataSourceJobStore" />
public IDbProvider DbProvider
{
set { dbProvider = value; }
set => dbProvider = value;
}
/// <summary>
@@ -422,12 +414,11 @@ namespace Spring.Scheduling.Quartz
return false;
}
}
return false;
}
}
#region IApplicationContextAware Members
/// <summary>
/// Sets the <see cref="Spring.Context.IApplicationContext"/> that this
/// object runs in.
@@ -457,13 +448,9 @@ namespace Spring.Scheduling.Quartz
/// <exception cref="Spring.Objects.Factory.ObjectInitializationException"/>
public virtual IApplicationContext ApplicationContext
{
set { applicationContext = value; }
set => applicationContext = value;
}
#endregion
#region IDisposable Members
/// <summary>
/// Shut down the Quartz scheduler on object factory Shutdown,
/// stopping all scheduled jobs.
@@ -471,11 +458,9 @@ namespace Spring.Scheduling.Quartz
public virtual void Dispose()
{
Logger.Info("Shutting down Quartz Scheduler");
scheduler.Shutdown(waitForJobsToCompleteOnShutdown);
scheduler.Shutdown(waitForJobsToCompleteOnShutdown).ConfigureAwait(false).GetAwaiter().GetResult();
}
#endregion
/// <summary>
/// Template method that determines the Scheduler to operate on.
/// To be implemented by subclasses.
@@ -486,8 +471,6 @@ namespace Spring.Scheduling.Quartz
return scheduler;
}
#region IFactoryObject Members
/// <summary>
/// Return an instance (possibly shared or independent) of the object
/// managed by this factory.
@@ -515,28 +498,18 @@ namespace Spring.Scheduling.Quartz
/// <see langword="null"/> if not known in advance.
/// </summary>
/// <value></value>
public virtual Type ObjectType
{
get { return (scheduler != null) ? scheduler.GetType() : typeof (IScheduler); }
}
public virtual Type ObjectType => (scheduler != null) ? scheduler.GetType() : typeof(IScheduler);
/// <summary>
/// Is the object managed by this factory a singleton or a prototype?
/// </summary>
/// <value></value>
public virtual bool IsSingleton
{
get { return true; }
}
#endregion
public virtual bool IsSingleton => true;
//---------------------------------------------------------------------
// Implementation of IInitializingObject interface
//---------------------------------------------------------------------
#region IInitializingObject Members
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
/// after it has injected all of an object's dependencies.
@@ -575,6 +548,7 @@ namespace Spring.Scheduling.Quartz
// Make given TaskExecutor available for SchedulerFactory configuration.
configTimeTaskExecutor = taskExecutor;
}
if (dbProvider != null)
{
// Make given db provider available for SchedulerFactory configuration.
@@ -600,6 +574,7 @@ namespace Spring.Scheduling.Quartz
{
((ISchedulerContextAware) jobFactory).SchedulerContext = scheduler.Context;
}
scheduler.JobFactory = jobFactory;
}
}
@@ -609,6 +584,7 @@ namespace Spring.Scheduling.Quartz
{
configTimeTaskExecutor = null;
}
if (dbProvider != null)
{
configTimeDbProvider = null;
@@ -616,11 +592,9 @@ namespace Spring.Scheduling.Quartz
}
RegisterListeners();
RegisterJobsAndTriggers();
RegisterJobsAndTriggers().ConfigureAwait(false).GetAwaiter().GetResult();
}
#endregion
/// <summary>
/// Load and/or apply Quartz properties to the given SchedulerFactory.
/// </summary>
@@ -632,11 +606,14 @@ namespace Spring.Scheduling.Quartz
if (configLocation != null || quartzProperties != null || schedulerName != null ||
taskExecutor != null || dbProvider != null)
{
throw new ArgumentException("StdSchedulerFactory required for applying Quartz properties: " + schedulerFactory);
throw new ArgumentException("StdSchedulerFactory required for applying Quartz properties: " +
schedulerFactory);
}
// Otherwise assume that no initialization is necessary...
return;
}
NameValueCollection mergedProps = new NameValueCollection();
// Set necessary default properties here, as Quartz will not apply
@@ -644,12 +621,13 @@ namespace Spring.Scheduling.Quartz
if (taskExecutor != null)
{
mergedProps[StdSchedulerFactory.PropertyThreadPoolType] =
typeof (LocalTaskExecutorThreadPool).AssemblyQualifiedName;
typeof(LocalTaskExecutorThreadPool).AssemblyQualifiedName;
}
else
{
mergedProps.Set(StdSchedulerFactory.PropertyThreadPoolType, typeof (SimpleThreadPool).AssemblyQualifiedName);
mergedProps[PROP_THREAD_COUNT] = Convert.ToString(DEFAULT_THREAD_COUNT);
mergedProps.Set(StdSchedulerFactory.PropertyThreadPoolType,
typeof(DefaultThreadPool).AssemblyQualifiedName);
mergedProps[PropThreadCount] = Convert.ToString(DefaultThreadCount);
}
if (configLocation != null)
@@ -658,6 +636,7 @@ namespace Spring.Scheduling.Quartz
{
Logger.Info("Loading Quartz config from [" + configLocation + "]");
}
using (StreamReader sr = new StreamReader(configLocation.InputStream))
{
string line;
@@ -680,7 +659,8 @@ namespace Spring.Scheduling.Quartz
if (dbProvider != null)
{
mergedProps[StdSchedulerFactory.PropertyJobStoreType] = typeof (LocalDataSourceJobStore).AssemblyQualifiedName;
mergedProps[StdSchedulerFactory.PropertyJobStoreType] =
typeof(LocalDataSourceJobStore).AssemblyQualifiedName;
}
// Make sure to set the scheduler name as configured in the Spring configuration.
@@ -724,21 +704,25 @@ namespace Spring.Scheduling.Quartz
SchedulerRepository repository = SchedulerRepository.Instance;
lock (repository)
{
IScheduler existingScheduler = (schedulerName != null ? repository.Lookup(schedulerName) : null);
IScheduler newScheduler = schedulerFactory.GetScheduler();
IScheduler existingScheduler = schedulerName != null
? repository.Lookup(schedulerName).ConfigureAwait(false).GetAwaiter().GetResult()
: null;
IScheduler newScheduler =
schedulerFactory.GetScheduler().ConfigureAwait(false).GetAwaiter().GetResult();
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));
$"Active Scheduler of name '{schedulerName}' already registered in Quartz SchedulerRepository. Cannot create a new Spring-managed Scheduler of the same name!");
}
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;
}
}
@@ -752,7 +736,8 @@ namespace Spring.Scheduling.Quartz
// Put specified objects into Scheduler context.
if (schedulerContextMap != null)
{
var dictionary = schedulerContextMap.Cast<DictionaryEntry>().ToDictionary(entry => entry.Key.ToString(), entry => entry.Value);
var dictionary = schedulerContextMap.Cast<DictionaryEntry>()
.ToDictionary(entry => entry.Key.ToString(), entry => entry.Value);
scheduler.Context.PutAll(dictionary);
}
@@ -764,6 +749,7 @@ namespace Spring.Scheduling.Quartz
throw new SystemException("SchedulerFactoryObject needs to be set up in an IApplicationContext " +
"to be able to handle an 'applicationContextSchedulerContextKey'");
}
scheduler.Context.Put(applicationContextSchedulerContextKey, applicationContext);
}
}
@@ -773,21 +759,23 @@ namespace Spring.Scheduling.Quartz
/// </summary>
/// <param name="sched">the Scheduler to start</param>
/// <param name="startDelay">the time span to wait before starting
/// the Scheduler asynchronously</param>
protected virtual void StartScheduler(IScheduler sched, TimeSpan startDelay)
/// the Scheduler asynchronously</param>
protected virtual async Task StartScheduler(IScheduler sched, TimeSpan startDelay)
{
if (startDelay.TotalSeconds <= 0)
{
Logger.Info("Starting Quartz Scheduler now");
sched.Start();
await sched.Start().ConfigureAwait(false);
}
else
{
if (Logger.IsInfoEnabled)
{
Logger.InfoFormat("Will start Quartz Scheduler [{0}] in {1} seconds", sched.SchedulerName, startDelay);
Logger.InfoFormat("Will start Quartz Scheduler [{0}] in {1} seconds", sched.SchedulerName,
startDelay);
}
sched.StartDelayed(startDelay);
await sched.StartDelayed(startDelay).ConfigureAwait(false);
}
}
@@ -798,13 +786,13 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// Starts this instance.
/// </summary>
public virtual void Start()
public virtual async Task Start()
{
if (scheduler != null)
{
try
{
scheduler.Start();
await scheduler.Start().ConfigureAwait(false);
}
catch (SchedulerException ex)
{
@@ -816,13 +804,13 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// Stops this instance.
/// </summary>
public virtual void Stop()
public virtual async Task Stop()
{
if (scheduler != null)
{
try
{
scheduler.Standby();
await scheduler.Standby().ConfigureAwait(false);
}
catch (SchedulerException ex)
{
@@ -841,7 +829,7 @@ namespace Spring.Scheduling.Quartz
{
try
{
StartScheduler(scheduler, startupDelay);
StartScheduler(scheduler, startupDelay).ConfigureAwait(false).GetAwaiter().GetResult();
}
catch (SchedulerException ex)
{

View File

@@ -2,26 +2,26 @@ using System;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Generic scheduling exception.
/// </summary>
public class SchedulingException : Exception
{
/// <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)
{
}
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)
{
}
}
public SchedulingException(string message, Exception ex) : base(message, ex)
{
}
}
}

View File

@@ -13,50 +13,51 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections;
using Quartz;
using Quartz.Impl.Triggers;
using Spring.Objects.Factory;
using Spring.Util;
namespace Spring.Scheduling.Quartz
{
/// <summary>
/// Convenience subclass of Quartz's <see cref="ISimpleTrigger" />
/// class, making properties based usage easier.
/// </summary>
/// <remarks>
/// <p>
/// SimpleTrigger itself is already a PONO 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>
/// <summary>
/// Convenience subclass of Quartz's <see cref="ISimpleTrigger" />
/// class, making properties based usage easier.
/// </summary>
/// <remarks>
/// <p>
/// SimpleTrigger itself is already a PONO 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>
/// </remarks>
/// <author>Juergen Hoeller</author>
/// <seealso cref="ITrigger.Key" />
/// <author>Juergen Hoeller</author>
/// <seealso cref="ITrigger.Key" />
/// <seealso cref="ITrigger.StartTimeUtc" />
/// <seealso cref="ITrigger.JobKey" />
/// <seealso cref="SimpleTriggerObject.JobDetail" />
/// <seealso cref="SchedulerAccessor.Triggers" />
/// <seealso cref="SchedulerAccessor.JobDetails" />
/// <seealso cref="CronTriggerObject" />
public class SimpleTriggerObject : SimpleTriggerImpl, IJobDetailAwareTrigger, IObjectNameAware, IInitializingObject
{
private TimeSpan startDelay = TimeSpan.Zero;
private IJobDetail jobDetail;
private string objectName;
private readonly Constants constants = new Constants(typeof(MisfireInstruction.SimpleTrigger), typeof(MisfireInstruction));
/// <seealso cref="SchedulerAccessor.Triggers" />
/// <seealso cref="SchedulerAccessor.JobDetails" />
/// <seealso cref="CronTriggerObject" />
public class SimpleTriggerObject : SimpleTriggerImpl, IJobDetailAwareTrigger, IObjectNameAware, IInitializingObject
{
private TimeSpan startDelay = TimeSpan.Zero;
private IJobDetail jobDetail;
private string objectName;
private readonly Constants constants =
new Constants(typeof(MisfireInstruction.SimpleTrigger), typeof(MisfireInstruction));
/// <summary>
/// Initializes a new instance of the <see cref="SimpleTriggerObject"/> class.
@@ -66,62 +67,62 @@ namespace Spring.Scheduling.Quartz
RepeatCount = RepeatIndefinitely;
}
/// <summary>
/// Register objects in the JobDataMap via a given Map.
/// <p>
/// These objects will be available to this Trigger only,
/// in contrast to objects in the JobDetail's data map.
/// </p>
/// </summary>
/// <seealso cref="JobDetailObject.JobDataAsMap" />
public virtual IDictionary JobDataAsMap
{
set
{
foreach (DictionaryEntry entry in value)
{
/// <summary>
/// Register objects in the JobDataMap via a given Map.
/// <p>
/// These objects will be available to this Trigger only,
/// in contrast to objects in the JobDetail's data map.
/// </p>
/// </summary>
/// <seealso cref="JobDetailObject.JobDataAsMap" />
public virtual IDictionary JobDataAsMap
{
set
{
foreach (DictionaryEntry entry in value)
{
JobDataMap.Put((string) entry.Key, entry.Value);
}
}
}
}
}
}
/// <summary>
/// Set the misfire instruction via the name of the corresponding
/// constant in the SimpleTrigger class.
/// <summary>
/// Set the misfire instruction via the name of the corresponding
/// constant in the SimpleTrigger class.
/// Default is <see cref="MisfireInstruction.SmartPolicy" />.
/// </summary>
/// </summary>
/// <seealso cref="MisfireInstruction.SimpleTrigger.FireNow" />
/// <seealso cref="MisfireInstruction.SimpleTrigger.RescheduleNextWithExistingCount" />
/// <seealso cref="MisfireInstruction.SimpleTrigger.RescheduleNextWithRemainingCount" />
/// <seealso cref="MisfireInstruction.SimpleTrigger.RescheduleNowWithExistingRepeatCount" />
/// <seealso cref="MisfireInstruction.SimpleTrigger.RescheduleNowWithRemainingRepeatCount" />
/// <seealso cref="MisfireInstruction.SmartPolicy" />
public virtual string MisfireInstructionName
{
set { MisfireInstruction = constants.AsNumber(value); }
}
public virtual string MisfireInstructionName
{
set => MisfireInstruction = constants.AsNumber(value);
}
/// <summary>
/// Set the delay before starting the job for the first time.
/// The given time span will be added to the current
/// time to calculate the start time. Default is <see cref="TimeSpan.Zero" />.
/// </summary>
/// <remarks>
/// This delay will just be applied if no custom start time was
/// specified. However, in typical usage within a Spring context,
/// the start time will be the container startup time anyway.
/// Specifying a relative delay is appropriate in that case.
/// </remarks>
/// <seealso cref="ITrigger.StartTimeUtc" />
public virtual TimeSpan StartDelay
{
/// <summary>
/// Set the delay before starting the job for the first time.
/// The given time span will be added to the current
/// time to calculate the start time. Default is <see cref="TimeSpan.Zero" />.
/// </summary>
/// <remarks>
/// This delay will just be applied if no custom start time was
/// specified. However, in typical usage within a Spring context,
/// the start time will be the container startup time anyway.
/// Specifying a relative delay is appropriate in that case.
/// </remarks>
/// <seealso cref="ITrigger.StartTimeUtc" />
public virtual TimeSpan StartDelay
{
set
{
AssertUtils.State(value >= TimeSpan.Zero, "Start delay cannot be negative.");
startDelay = value;
}
get { return startDelay; }
}
get => startDelay;
}
/// <summary>
/// Set the name of the object in the object factory that created this object.
@@ -135,25 +136,24 @@ namespace Spring.Scheduling.Quartz
/// 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.
/// <p>
/// 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.
/// </p>
/// </summary>
public virtual IJobDetail JobDetail
{
get { return jobDetail; }
set { jobDetail = value; }
}
public virtual string ObjectName
{
set => objectName = value;
}
/// <summary>
/// Set the JobDetail that this trigger should be associated with.
/// <p>
/// 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.
/// </p>
/// </summary>
public virtual IJobDetail JobDetail
{
get => jobDetail;
set => jobDetail = value;
}
/// <summary>
/// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
@@ -181,30 +181,33 @@ namespace Spring.Scheduling.Quartz
/// In the event of misconfiguration (such as the failure to set a
/// required property) or if initialization fails.
/// </exception>
public virtual void AfterPropertiesSet()
{
public virtual void AfterPropertiesSet()
{
if (StartTimeUtc == DateTimeOffset.MinValue)
{
StartTimeUtc = DateTimeOffset.UtcNow;
}
if (StartDelay > TimeSpan.Zero)
{
StartTimeUtc = DateTime.UtcNow.Add(startDelay);
}
if (Name == null)
{
Name = objectName;
}
if (Group == null)
{
if (Name == null)
{
Name = objectName;
}
if (Group == null)
{
Group = SchedulerConstants.DefaultGroup;
}
if (jobDetail != null)
{
JobName = jobDetail.Key.Name;
JobGroup = jobDetail.Key.Group;
}
}
}
}
if (jobDetail != null)
{
JobName = jobDetail.Key.Name;
JobGroup = jobDetail.Key.Group;
}
}
}
}

View File

@@ -1,4 +1,4 @@
/*
/*
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,10 @@
using System;
using System.Data;
using System.Data.Common;
using System.Reflection;
using Quartz.Impl.AdoJobStore.Common;
using IDbMetadata=Spring.Data.Common.IDbMetadata;
using IDbMetadata = Spring.Data.Common.IDbMetadata;
namespace Spring.Scheduling.Quartz
{
@@ -48,16 +47,15 @@ namespace Spring.Scheduling.Quartz
/// </summary>
public void Initialize()
{
}
/// <summary>
/// Creates the command.
/// </summary>
/// <returns></returns>
public IDbCommand CreateCommand()
public DbCommand CreateCommand()
{
return dbProvider.CreateCommand();
return (DbCommand) dbProvider.CreateCommand();
}
/// <summary>
@@ -73,9 +71,9 @@ namespace Spring.Scheduling.Quartz
/// Creates the connection.
/// </summary>
/// <returns></returns>
public IDbConnection CreateConnection()
public DbConnection CreateConnection()
{
return dbProvider.CreateConnection();
return (DbConnection) dbProvider.CreateConnection();
}
/// <summary>
@@ -101,18 +99,15 @@ namespace Spring.Scheduling.Quartz
/// <value>The connection string.</value>
public string ConnectionString
{
get { return dbProvider.ConnectionString; }
set { dbProvider.ConnectionString = value; }
get => dbProvider.ConnectionString;
set => dbProvider.ConnectionString = value;
}
/// <summary>
/// Gets the metadata.
/// </summary>
/// <value>The metadata.</value>
public DbMetadata Metadata
{
get { return metadata; }
}
public DbMetadata Metadata => metadata;
}
/// <summary>
@@ -149,7 +144,6 @@ namespace Spring.Scheduling.Quartz
// use standard binary type
dbTypeBinary = DbType.Binary;
}
}
/// <summary>
@@ -158,8 +152,8 @@ namespace Spring.Scheduling.Quartz
/// <value>The name of the product.</value>
public override string ProductName
{
get { return metadata.ProductName; }
set { throw new NotSupportedException(); }
get => metadata.ProductName;
set => throw new NotSupportedException();
}
/// <summary>
@@ -168,8 +162,8 @@ namespace Spring.Scheduling.Quartz
/// <value>The type of the connection.</value>
public override Type ConnectionType
{
get { return metadata.ConnectionType; }
set { throw new NotSupportedException(); }
get => metadata.ConnectionType;
set => throw new NotSupportedException();
}
/// <summary>
@@ -178,8 +172,8 @@ namespace Spring.Scheduling.Quartz
/// <value>The type of the command.</value>
public override Type CommandType
{
get { return metadata.CommandType; }
set { throw new NotSupportedException(); }
get => metadata.CommandType;
set => throw new NotSupportedException();
}
/// <summary>
@@ -188,28 +182,8 @@ namespace Spring.Scheduling.Quartz
/// <value>The type of the parameter.</value>
public override Type ParameterType
{
get { return metadata.ParameterType; }
set { throw new NotSupportedException(); }
}
/// <summary>
/// Gets or sets the type of the command builder.
/// </summary>
/// <value>The type of the command builder.</value>
public override Type CommandBuilderType
{
get { return metadata.CommandBuilderType; }
set { throw new NotSupportedException(); }
}
/// <summary>
/// Gets or sets the command builder derive parameters method.
/// </summary>
/// <value>The command builder derive parameters method.</value>
public override MethodInfo CommandBuilderDeriveParametersMethod
{
get { return metadata.CommandBuilderDeriveParametersMethod; }
set { throw new NotSupportedException(); }
get => metadata.ParameterType;
set => throw new NotSupportedException();
}
/// <summary>
@@ -218,8 +192,8 @@ namespace Spring.Scheduling.Quartz
/// <value>The parameter name prefix.</value>
public override string ParameterNamePrefix
{
get { return metadata.ParameterNamePrefix; }
set { throw new NotSupportedException(); }
get => metadata.ParameterNamePrefix;
set => throw new NotSupportedException();
}
/// <summary>
@@ -228,8 +202,8 @@ namespace Spring.Scheduling.Quartz
/// <value>The type of the exception.</value>
public override Type ExceptionType
{
get { return metadata.ExceptionType; }
set { throw new NotSupportedException(); }
get => metadata.ExceptionType;
set => throw new NotSupportedException();
}
/// <summary>
@@ -238,8 +212,8 @@ namespace Spring.Scheduling.Quartz
/// <value><c>true</c> if [bind by name]; otherwise, <c>false</c>.</value>
public override bool BindByName
{
get { return metadata.BindByName; }
set { throw new NotSupportedException(); }
get => metadata.BindByName;
set => throw new NotSupportedException();
}
/// <summary>
@@ -248,8 +222,8 @@ namespace Spring.Scheduling.Quartz
/// <value>The type of the parameter db.</value>
public override Type ParameterDbType
{
get { return metadata.ParameterDbType; }
set { throw new NotSupportedException(); }
get => metadata.ParameterDbType;
set => throw new NotSupportedException();
}
/// <summary>
@@ -258,8 +232,8 @@ namespace Spring.Scheduling.Quartz
/// <value>The parameter db type property.</value>
public override PropertyInfo ParameterDbTypeProperty
{
get { return metadata.ParameterDbTypeProperty; }
set { throw new NotSupportedException(); }
get => metadata.ParameterDbTypeProperty;
set => throw new NotSupportedException();
}
/// <summary>
@@ -268,18 +242,15 @@ namespace Spring.Scheduling.Quartz
/// <value>The parameter is nullable property.</value>
public override PropertyInfo ParameterIsNullableProperty
{
get { return metadata.ParameterIsNullableProperty; }
set { throw new NotSupportedException(); }
get => metadata.ParameterIsNullableProperty;
set => throw new NotSupportedException();
}
/// <summary>
/// Gets the type of the db binary.
/// </summary>
/// <value>The type of the db binary.</value>
public override Enum DbBinaryType
{
get { return dbTypeBinary; }
}
public override Enum DbBinaryType => dbTypeBinary;
/// <summary>
/// Gets or sets a value indicating whether [use parameter name prefix in parameter collection].
@@ -289,9 +260,8 @@ namespace Spring.Scheduling.Quartz
/// </value>
public override bool UseParameterNamePrefixInParameterCollection
{
get { return metadata.UseParameterNamePrefixInParameterCollection; }
set { throw new NotSupportedException(); }
get => metadata.UseParameterNamePrefixInParameterCollection;
set => throw new NotSupportedException();
}
}
}

View File

@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using Quartz;
using Quartz.Spi;
using Spring.Objects;
@@ -50,7 +51,7 @@ namespace Spring.Scheduling.Quartz
/// </remarks>
public virtual string[] IgnoredUnknownProperties
{
set { ignoredUnknownProperties = value; }
set => ignoredUnknownProperties = value;
}
/// <summary>
@@ -60,10 +61,9 @@ namespace Spring.Scheduling.Quartz
/// <seealso cref="IScheduler.Context"/>
public virtual SchedulerContext SchedulerContext
{
set { schedulerContext = value; }
set => schedulerContext = value;
}
/// <summary>
/// Create the job instance, populating it with property values taken
/// from the scheduler context, job data map and trigger data map.
@@ -78,6 +78,7 @@ namespace Spring.Scheduling.Quartz
{
pvs.AddAll(schedulerContext);
}
pvs.AddAll(bundle.JobDetail.JobDataMap);
pvs.AddAll(bundle.Trigger.JobDataMap);
if (ignoredUnknownProperties != null)
@@ -90,6 +91,7 @@ namespace Spring.Scheduling.Quartz
pvs.Remove(propName);
}
}
ow.SetPropertyValues(pvs);
}
else
@@ -97,6 +99,7 @@ namespace Spring.Scheduling.Quartz
ow.SetPropertyValues(pvs, true);
}
}
return ow.WrappedInstance;
}

View File

@@ -30,4 +30,4 @@ namespace Spring.Scheduling.Quartz
// No implementation, just an addition of the tag interface StatefulJob
// in order to allow stateful method invoking jobs.
}
}
}

View File

@@ -0,0 +1,11 @@
using System;
namespace Spring.Scheduling
{
/// <summary>
/// Summary description for TaskRejectedException.
/// </summary>
public class TaskRejectedException : ApplicationException
{
}
}

View File

@@ -1,14 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net452</TargetFramework>
<Description>Spring.NET Integration with the Quartz Scheduling Library 2.x</Description>
<TargetFrameworks>netstandard2.0;$(TargetFullFrameworkVersion)</TargetFrameworks>
<Description>Spring.NET Integration with the Quartz Scheduling Library 3.x</Description>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Spring.Core\Spring.Core.csproj" />
<ProjectReference Include="..\Spring.Data\Spring.Data.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Quartz" Version="2.6.2" />
<PackageReference Include="Quartz" Version="3.0.7" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\GenCommonAssemblyInfo.cs">

View File

@@ -63,7 +63,7 @@ namespace Spring.Data.Core
TransactionOptions txOptions = new TransactionOptions();
txOptions.IsolationLevel = IsolationLevel.ReadCommitted;
txAdapter.CreateTransactionScope(TransactionScopeOption.Required, txOptions, EnterpriseServicesInteropOption.None);
txAdapter.CreateTransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled);
txAdapter.Complete();
txAdapter.Dispose();
}
@@ -103,7 +103,7 @@ namespace Spring.Data.Core
}
Assert.IsTrue(!TransactionSynchronizationManager.SynchronizationActive, "Synchronizations not active");
A.CallTo(() => txAdapter.CreateTransactionScope(TransactionScopeOption.Required, txOptions, EnterpriseServicesInteropOption.None)).MustHaveHappenedOnceExactly();
A.CallTo(() => txAdapter.CreateTransactionScope(TransactionScopeOption.Required, txOptions, TransactionScopeAsyncFlowOption.Enabled)).MustHaveHappenedOnceExactly();
A.CallTo(() => txAdapter.Dispose()).MustHaveHappenedOnceExactly();
}
@@ -151,7 +151,7 @@ namespace Spring.Data.Core
return null;
});
A.CallTo(() => txAdapter.CreateTransactionScope(TransactionScopeOption.RequiresNew, txOptions, EnterpriseServicesInteropOption.None)).MustHaveHappenedTwiceExactly();
A.CallTo(() => txAdapter.CreateTransactionScope(TransactionScopeOption.RequiresNew, txOptions, TransactionScopeAsyncFlowOption.Enabled)).MustHaveHappenedTwiceExactly();
A.CallTo(() => txAdapter.Dispose()).MustHaveHappenedTwiceExactly();
A.CallTo(() => txAdapter.Complete()).MustHaveHappenedOnceExactly();
}

View File

@@ -1,5 +1,3 @@
#region License
/*
* Copyright <20> 2002-2011 the original author or authors.
*
@@ -16,47 +14,31 @@
* limitations under the License.
*/
#endregion
#region Imports
using System;
using System.Transactions;
using Common.Logging;
using Spring.Objects;
using Spring.Transaction;
using Spring.Transaction.Interceptor;
using Spring.Transaction.Support;
using IsolationLevel=System.Data.IsolationLevel;
#endregion
using IsolationLevel = System.Data.IsolationLevel;
namespace Spring.Data
{
/// <summary>
/// Group together multiple ITestObjectDao operations.
/// </summary>
/// <author>Mark Pollack (.NET)</author>
public class TestObjectMgr : ITestObjectMgr
{
#region Fields
/// <summary>
/// Group together multiple ITestObjectDao operations.
/// </summary>
/// <author>Mark Pollack (.NET)</author>
public class TestObjectMgr : ITestObjectMgr
{
private static readonly ILog LOG = LogManager.GetLogger(typeof(TestObjectMgr));
#endregion
#region Constructor (s)
/// <summary>
/// Initializes a new instance of the <see cref="TestObjectMgr"/> class.
/// <summary>
/// Initializes a new instance of the <see cref="TestObjectMgr"/> class.
/// </summary>
public TestObjectMgr()
{
}
#endregion
#region Methods
public TestObjectMgr()
{
}
[Transaction()]
public void SaveTwoTestObjects(TestObject to1, TestObject to2)
@@ -65,14 +47,12 @@ namespace Spring.Data
}
[Transaction(TransactionPropagation.Required, IsolationLevel.Unspecified, Timeout = 50,
RollbackFor = new Type[]{typeof(ArgumentNullException)},
ReadOnly = false,
EnterpriseServicesInteropOption = System.Transactions.EnterpriseServicesInteropOption.Automatic,
NoRollbackFor = new Type[] { typeof(ArithmeticException), typeof(NotSupportedException) })]
public void DeleteTwoTestObjects(string name1, string name2)
RollbackFor = new Type[] {typeof(ArgumentNullException)},
ReadOnly = false,
AsyncFlowOption = TransactionScopeAsyncFlowOption.Enabled,
NoRollbackFor = new Type[] {typeof(ArithmeticException), typeof(NotSupportedException)})]
public void DeleteTwoTestObjects(string name1, string name2)
{
}
#endregion
}
}
}
}

View File

@@ -5,49 +5,17 @@ namespace Spring.Transaction
{
public class MockTxnDefinition : ITransactionDefinition
{
private int _transactionTimeout = DefaultTransactionDefinition.TIMEOUT_DEFAULT;
private TransactionPropagation _transactionPropagation = TransactionPropagation.NotSupported;
private bool _readOnly = false;
private string _name = null;
private System.Transactions.EnterpriseServicesInteropOption _esInteropOption;
public bool ReadOnly { get; set; }
#region ITransactionDefinition Members
public int TransactionTimeout { get; set; } = DefaultTransactionDefinition.TIMEOUT_DEFAULT;
public bool ReadOnly
{
get { return _readOnly; }
set { _readOnly = value; }
}
public IsolationLevel TransactionIsolationLevel => IsolationLevel.Unspecified;
public int TransactionTimeout
{
get { return _transactionTimeout; }
set { _transactionTimeout = value; }
}
public TransactionPropagation PropagationBehavior { get; set; } = TransactionPropagation.NotSupported;
public IsolationLevel TransactionIsolationLevel
{
get { return IsolationLevel.Unspecified; }
}
public string Name { get; } = null;
public TransactionPropagation PropagationBehavior
{
get { return _transactionPropagation; }
set { _transactionPropagation = value; }
}
public string Name
{
get { return _name; }
}
public System.Transactions.EnterpriseServicesInteropOption EnterpriseServicesInteropOption
{
get { return _esInteropOption; }
set { _esInteropOption = value; }
}
#endregion
public System.Transactions.TransactionScopeAsyncFlowOption AsyncFlowOption { get; set; }
}
public class MockTxnPlatformMgrAbstract : AbstractPlatformTransactionManager
@@ -68,32 +36,18 @@ namespace Spring.Transaction
_isExistingTransaction = true;
}
public object Transaction
{
get { return _transaction; }
}
public object Transaction => _transaction;
public bool Savepoints
{
set { _useSavepointForNestedTransaction = value; }
set => _useSavepointForNestedTransaction = value;
}
public int DoBeginCallCount
{
get { return _doBeginCalls; }
}
public int DoBeginCallCount => _doBeginCalls;
public int DoGetTransactionCallCount
{
get { return _doGetTxnCalls; }
}
public int DoGetTransactionCallCount => _doGetTxnCalls;
public int IsExistingTransactionCallCount
{
get { return _isExistingTxnCalls; }
}
#region AbstractPlatformTransactionManager Impls
public int IsExistingTransactionCallCount => _isExistingTxnCalls;
protected override void DoResume(object transaction, object suspendedResources)
{
@@ -144,7 +98,5 @@ namespace Spring.Transaction
{
return _useSavepointForNestedTransaction;
}
#endregion
}
}

View File

@@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
xmlns:aop="http://www.springframework.net/aop"
xmlns:db="http://www.springframework.net/database"
xmlns:tx="http://www.springframework.net/tx">
<!-- Property placeholder configurer for database settings -->
<object type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
<property name="ConfigSections" value="appSettings"/>
</object>
<!-- DB -->
<db:provider id="dbProvider" provider="SqlServer-2.0" connectionString="${ConnectionString}"/>
<object id="transactionManager" type="Spring.Data.Core.TxScopeTransactionManager, Spring.Data">
</object>
<!-- And actual Quartz -->
<object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz2">
<property name="AutoStartup" value="true" />
<property name="StartupDelay" value="5s" />
<property name="QuartzProperties">
<dictionary>
<entry key="quartz.threadPool.threadCount" value="10"/>
<entry key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz"/>
<entry key="quartz.threadPool.threadPriority" value="Normal"/>
<entry key="quartz.jobStore.misfireThreshold" value="60000"/>
<entry key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz"/>
<entry key="quartz.jobStore.useProperties" value="false"/>
<entry key="quartz.jobStore.tablePrefix" value="QRTZ_"/>
<entry key="quartz.jobStore.lockHandler.type" value="Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz"/>
</dictionary>
</property>
<property name="triggers">
<list>
<ref object="simpleTrigger" />
</list>
</property>
<property name="DbProvider" ref="dbProvider" />
<property name="TransactionManager" ref="transactionManager" />
</object>
<object id="testJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz2">
<property name="JobType" value="Spring.Scheduling.Quartz.Integration.Tests.TestJob, Spring.Scheduling.Quartz2.Integration.Tests" />
</object>
<object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz2">
<!-- see the example of method invoking job above -->
<property name="jobDetail" ref="testJob" />
<!-- 2 seconds -->
<property name="startDelay" value="2s" />
<!-- repeat every 3 seconds -->
<property name="repeatInterval" value="3s" />
</object>
</objects>

View File

@@ -1,7 +1,7 @@
#region License
/*
* Copyright © 2002-2007 the original author or authors.
* Copyright <EFBFBD> 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.
@@ -21,32 +21,32 @@
#region Imports
using System.Threading;
using NUnit.Framework;
using Spring.Context;
using Spring.Context.Support;
#endregion
namespace Spring.Scheduling.Quartz.Integration.Tests
{
[TestFixture]
public class LocalDataSourceJobStoreTest
public class LocalDataSourceJobStoreTest
{
private IApplicationContext ctx;
[SetUp]
public void SetUp()
{
ctx = new XmlApplicationContext("assembly://Spring.Scheduling.Quartz2.Integration.Tests/Spring.Scheduling.Quartz/LocalDataSourceJobStoreTest.xml");
ctx = new XmlApplicationContext(
"assembly://Spring.Scheduling.Quartz3.Integration.Tests/Spring.Scheduling.Quartz/LocalDataSourceJobStoreTest.xml");
}
[Test]
[Ignore("Appveyor problems")]
[Explicit("Appveyor problems")]
public void TestLocalDataSourceJobStore()
{
// sleep 20 seconds
Thread.Sleep(20000);
}
}
}

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<objects xmlns="http://www.springframework.net"
xmlns:aop="http://www.springframework.net/aop"
xmlns:db="http://www.springframework.net/database"
xmlns:tx="http://www.springframework.net/tx">
<!-- Property placeholder configurer for database settings -->
<object type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
<property name="ConfigSections" value="appSettings" />
</object>
<!-- DB -->
<db:provider id="dbProvider" provider="SqlServer-2.0" connectionString="${ConnectionString}" />
<object id="transactionManager" type="Spring.Data.Core.TxScopeTransactionManager, Spring.Data">
</object>
<!-- And actual Quartz -->
<object id="quartzSchedulerFactory" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz3">
<property name="AutoStartup" value="true" />
<property name="StartupDelay" value="5s" />
<property name="QuartzProperties">
<dictionary>
<entry key="quartz.serializer.type" value="binary" />
<entry key="quartz.threadPool.threadCount" value="10" />
<entry key="quartz.threadPool.type" value="Quartz.Simpl.SimpleThreadPool, Quartz" />
<entry key="quartz.threadPool.threadPriority" value="Normal" />
<entry key="quartz.jobStore.misfireThreshold" value="60000" />
<entry key="quartz.jobStore.driverDelegateType" value="Quartz.Impl.AdoJobStore.StdAdoDelegate, Quartz" />
<entry key="quartz.jobStore.useProperties" value="false" />
<entry key="quartz.jobStore.tablePrefix" value="QRTZ_" />
<entry key="quartz.jobStore.lockHandler.type" value="Quartz.Impl.AdoJobStore.UpdateLockRowSemaphore, Quartz" />
</dictionary>
</property>
<property name="triggers">
<list>
<ref object="simpleTrigger" />
</list>
</property>
<property name="DbProvider" ref="dbProvider" />
<property name="TransactionManager" ref="transactionManager" />
</object>
<object id="testJob" type="Spring.Scheduling.Quartz.JobDetailObject, Spring.Scheduling.Quartz3">
<property name="JobType"
value="Spring.Scheduling.Quartz.Integration.Tests.TestJob, Spring.Scheduling.Quartz3.Integration.Tests" />
</object>
<object id="simpleTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz3">
<!-- see the example of method invoking job above -->
<property name="jobDetail" ref="testJob" />
<!-- 2 seconds -->
<property name="startDelay" value="2s" />
<!-- repeat every 3 seconds -->
<property name="repeatInterval" value="3s" />
</object>
</objects>

View File

@@ -1,14 +1,15 @@
using System;
using System.Threading.Tasks;
using Quartz;
namespace Spring.Scheduling.Quartz.Integration.Tests
{
public class TestJob : IJob
{
public void Execute(IJobExecutionContext context)
public Task Execute(IJobExecutionContext context)
{
Console.WriteLine("Executing Execute!");
return Task.FromResult(true);
}
public void DoIt()

View File

@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net452</TargetFramework>
<TargetFrameworks>netcoreapp2.1;$(TargetFullFrameworkVersion)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Spring\Spring.Core\Spring.Core.csproj" />
<ProjectReference Include="..\..\..\src\Spring\Spring.Data\Spring.Data.csproj" />
<ProjectReference Include="..\..\..\src\Spring\Spring.Scheduling.Quartz2\Spring.Scheduling.Quartz2.csproj" />
<ProjectReference Include="..\..\..\src\Spring\Spring.Scheduling.Quartz3\Spring.Scheduling.Quartz3.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FakeItEasy" Version="$(FakeItEasyVersion)" />

View File

@@ -19,7 +19,6 @@ using System;
using NUnit.Framework;
using Quartz;
using Quartz.Job;
using Quartz.Spi;
namespace Spring.Scheduling.Quartz

View File

@@ -22,8 +22,6 @@ using NUnit.Framework;
using Quartz;
using Quartz.Impl;
using Quartz.Job;
namespace Spring.Scheduling.Quartz
{

View File

@@ -20,7 +20,6 @@ using System.Collections;
using NUnit.Framework;
using Quartz;
using Quartz.Job;
using Spring.Context.Support;

View File

@@ -24,7 +24,6 @@ using NUnit.Framework;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Triggers;
using Quartz.Job;
using Quartz.Spi;
using Spring.Objects.Support;
@@ -151,7 +150,15 @@ namespace Spring.Scheduling.Quartz
{
IJobDetail jd = new JobDetailImpl("jobName", "jobGroup", typeof(NoOpJob));
IOperableTrigger trigger = new SimpleTriggerImpl("triggerName", "triggerGroup");
TriggerFiredBundle retValue = new TriggerFiredBundle(jd, trigger, null, false, null, null, null, null);
TriggerFiredBundle retValue = new TriggerFiredBundle(
jd,
trigger,
null,
false,
DateTimeOffset.UtcNow,
null,
null,
null);
return retValue;
}

View File

@@ -17,7 +17,7 @@
using System;
using System.Collections;
using System.Threading;
using System.Threading.Tasks;
using FakeItEasy;
using NUnit.Framework;
@@ -46,18 +46,18 @@ namespace Spring.Scheduling.Quartz
/// Executes parametrized test.
/// </summary>
[Test]
public void TestSchedulerFactoryObject()
public async Task TestSchedulerFactoryObject()
{
DoTestSchedulerFactoryObject(false, false);
await DoTestSchedulerFactoryObject(false, false);
}
/// <summary>
/// Executes parametrized test.
/// </summary>
[Test]
public void TestSchedulerFactoryObjectWithExplicitJobDetail()
public async Task TestSchedulerFactoryObjectWithExplicitJobDetail()
{
DoTestSchedulerFactoryObject(true, false);
await DoTestSchedulerFactoryObject(true, false);
}
/// <summary>
@@ -65,12 +65,12 @@ namespace Spring.Scheduling.Quartz
/// </summary>
[Test]
[Ignore("Requires change to MethodInvoker for overriding target object and type")]
public void TestSchedulerFactoryObjectWithPrototypeJob()
public async Task TestSchedulerFactoryObjectWithPrototypeJob()
{
DoTestSchedulerFactoryObject(false, true);
await DoTestSchedulerFactoryObject(false, true);
}
private void DoTestSchedulerFactoryObject(bool explicitJobDetail, bool prototypeJob)
private async Task DoTestSchedulerFactoryObject(bool explicitJobDetail, bool prototypeJob)
{
TestObject tb = new TestObject("tb", 99);
JobDetailObject jobDetail0 = new JobDetailObject();
@@ -116,8 +116,8 @@ namespace Spring.Scheduling.Quartz
IScheduler scheduler = A.Fake<IScheduler>();
A.CallTo(() => scheduler.Context).Returns(new SchedulerContext());
A.CallTo(() => scheduler.GetTrigger(A<TriggerKey>._)).Returns(null);
A.CallTo(() => scheduler.GetJobDetail(A<JobKey>._)).Returns(null);
A.CallTo(() => scheduler.GetTrigger(A<TriggerKey>._, A<CancellationToken>._)).Returns(Task.FromResult<ITrigger>(null));
A.CallTo(() => scheduler.GetJobDetail(A<JobKey>._, A<CancellationToken>._)).Returns(Task.FromResult<IJobDetail>(null));
SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
schedulerFactoryObject.JobFactory = null;
@@ -132,42 +132,42 @@ namespace Spring.Scheduling.Quartz
try
{
schedulerFactoryObject.AfterPropertiesSet();
schedulerFactoryObject.Start();
await schedulerFactoryObject.Start();
}
finally
{
schedulerFactoryObject.Dispose();
}
A.CallTo(() => scheduler.ScheduleJob(trigger0)).MustHaveHappened();
A.CallTo(() => scheduler.ScheduleJob(trigger1)).MustHaveHappened();
A.CallTo(() => scheduler.ScheduleJob(trigger0, A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.ScheduleJob(trigger1, A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true)).MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true)).MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.Start()).MustHaveHappened();
A.CallTo(() => scheduler.Shutdown(false)).MustHaveHappened();
A.CallTo(() => scheduler.Start(A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.Shutdown(false, A<CancellationToken>._)).MustHaveHappened();
}
/// <summary>
/// Executes parametrized test.
/// </summary>
[Test]
public void TestSchedulerFactoryObjectWithExistingJobs()
public async Task TestSchedulerFactoryObjectWithExistingJobs()
{
DoTestSchedulerFactoryObjectWithExistingJobs(false);
await DoTestSchedulerFactoryObjectWithExistingJobs(false);
}
/// <summary>
/// Executes parametrized test.
/// </summary>
[Test]
public void TestSchedulerFactoryObjectWithOverwriteExistingJobs()
public async Task TestSchedulerFactoryObjectWithOverwriteExistingJobs()
{
DoTestSchedulerFactoryObjectWithExistingJobs(true);
await DoTestSchedulerFactoryObjectWithExistingJobs(true);
}
private void DoTestSchedulerFactoryObjectWithExistingJobs(bool overwrite)
private async Task DoTestSchedulerFactoryObjectWithExistingJobs(bool overwrite)
{
TestObject tb = new TestObject("tb", 99);
JobDetailObject jobDetail0 = new JobDetailObject();
@@ -202,13 +202,13 @@ namespace Spring.Scheduling.Quartz
IScheduler scheduler = A.Fake<IScheduler>();
A.CallTo(() => scheduler.Context).Returns(new SchedulerContext());
A.CallTo(() => scheduler.GetJobDetail(A<JobKey>._)).Returns(null);
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup))).Returns(null);
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup))).Returns(new SimpleTriggerImpl());
A.CallTo(() => scheduler.GetJobDetail(A<JobKey>._, A<CancellationToken>._)).Returns(Task.FromResult<IJobDetail>(null));
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), A<CancellationToken>._)).Returns(Task.FromResult<ITrigger>(null));
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), A<CancellationToken>._)).Returns(Task.FromResult<ITrigger>(new SimpleTriggerImpl()));
if (overwrite)
{
A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), trigger1)).Returns(DateTime.UtcNow);
A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), trigger1, A<CancellationToken>._)).Returns(DateTime.UtcNow);
}
SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
@@ -224,38 +224,38 @@ namespace Spring.Scheduling.Quartz
try
{
schedulerFactoryObject.AfterPropertiesSet();
schedulerFactoryObject.Start();
await schedulerFactoryObject.Start();
}
finally
{
schedulerFactoryObject.Dispose();
}
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true)).MustHaveHappened();
A.CallTo(() => scheduler.ScheduleJob(trigger0)).MustHaveHappened();
A.CallTo(() => scheduler.Start()).MustHaveHappened();
A.CallTo(() => scheduler.Shutdown(false)).MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.ScheduleJob(trigger0, A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.Start(A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.Shutdown(false, A<CancellationToken>._)).MustHaveHappened();
}
/// <summary>
/// Executes parametrized test.
/// </summary>
[Test]
public void TestSchedulerFactoryObjectWithExistingJobsAndRaceCondition()
public async Task TestSchedulerFactoryObjectWithExistingJobsAndRaceCondition()
{
DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(false);
await DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(false);
}
/// <summary>
/// Executes parametrized test.
/// </summary>
[Test]
public void TestSchedulerFactoryObjectWithOverwriteExistingJobsAndRaceCondition()
public async Task TestSchedulerFactoryObjectWithOverwriteExistingJobsAndRaceCondition()
{
DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(true);
await DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(true);
}
private void DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(bool overwrite)
private async Task DoTestSchedulerFactoryObjectWithExistingJobsAndRaceCondition(bool overwrite)
{
TestObject tb = new TestObject("tb", 99);
JobDetailObject jobDetail0 = new JobDetailObject();
@@ -290,24 +290,24 @@ namespace Spring.Scheduling.Quartz
IScheduler scheduler = A.Fake<IScheduler>();
A.CallTo(() => scheduler.Context).Returns(new SchedulerContext());
A.CallTo(() => scheduler.GetJobDetail(A<JobKey>._)).Returns(null);
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup))).Returns(null);
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup))).Returns(new SimpleTriggerImpl());
A.CallTo(() => scheduler.GetJobDetail(A<JobKey>._, A<CancellationToken>._)).Returns(Task.FromResult<IJobDetail>(null));
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), A<CancellationToken>._)).Returns(Task.FromResult<ITrigger>(null));
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), A<CancellationToken>._)).Returns(Task.FromResult<ITrigger>(new SimpleTriggerImpl()));
if (overwrite)
{
scheduler.AddJob(jobDetail1, true);
A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), trigger1)).Returns(DateTime.UtcNow);
await scheduler.AddJob(jobDetail1, true);
A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), trigger1, A<CancellationToken>._)).Returns(DateTime.UtcNow);
}
A.CallTo(() => scheduler.ScheduleJob(trigger0)).Throws(new ObjectAlreadyExistsException(""));
A.CallTo(() => scheduler.ScheduleJob(trigger0, A<CancellationToken>._)).Throws(new ObjectAlreadyExistsException(""));
if (overwrite)
{
A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), trigger0)).Returns(DateTime.UtcNow);
A.CallTo(() => scheduler.RescheduleJob(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), trigger0, A<CancellationToken>._)).Returns(DateTime.UtcNow);
}
scheduler.Start();
scheduler.Shutdown(false);
await scheduler.Start();
await scheduler.Shutdown(false);
SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
@@ -323,14 +323,14 @@ namespace Spring.Scheduling.Quartz
try
{
schedulerFactoryObject.AfterPropertiesSet();
schedulerFactoryObject.Start();
await schedulerFactoryObject.Start();
}
finally
{
schedulerFactoryObject.Dispose();
}
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true)).MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A<CancellationToken>._)).MustHaveHappened();
}
@@ -417,7 +417,7 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// </summary>
[Test]
public void TestSchedulerFactoryObjectWithPlainQuartzObjects()
public async Task TestSchedulerFactoryObjectWithPlainQuartzObjects()
{
IJobFactory jobFactory = new AdaptableJobFactory();
@@ -456,8 +456,8 @@ namespace Spring.Scheduling.Quartz
trigger1.RepeatInterval = TimeSpan.FromMilliseconds(20);
IScheduler scheduler = A.Fake<IScheduler>();
A.CallTo(() => scheduler.GetTrigger(A<TriggerKey>._)).Returns(null);
A.CallTo(() => scheduler.GetJobDetail(A<JobKey>._)).Returns(null);
A.CallTo(() => scheduler.GetTrigger(A<TriggerKey>._, A<CancellationToken>._)).Returns(Task.FromResult<ITrigger>(null));
A.CallTo(() => scheduler.GetJobDetail(A<JobKey>._, A<CancellationToken>._)).Returns(Task.FromResult<IJobDetail>(null));
SchedulerFactoryObject schedulerFactoryObject = new TestSchedulerFactoryObject(scheduler);
@@ -467,7 +467,7 @@ namespace Spring.Scheduling.Quartz
try
{
schedulerFactoryObject.AfterPropertiesSet();
schedulerFactoryObject.Start();
await schedulerFactoryObject.Start();
}
finally
{
@@ -479,18 +479,18 @@ namespace Spring.Scheduling.Quartz
.WhenArgumentsMatch(x => x.Get<IJobFactory>(0) == jobFactory)
.MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true)).MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail1, true, true)).MustHaveHappened();
A.CallTo(() => scheduler.GetJobDetail(new JobKey("myJob0", SchedulerConstants.DefaultGroup))).MustHaveHappened();
A.CallTo(() => scheduler.GetJobDetail(new JobKey("myJob1", SchedulerConstants.DefaultGroup))).MustHaveHappened();
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup))).MustHaveHappened();
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup))).MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail0, true, true, A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.AddJob(jobDetail1, true, true, A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.GetJobDetail(new JobKey("myJob0", SchedulerConstants.DefaultGroup), A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.GetJobDetail(new JobKey("myJob1", SchedulerConstants.DefaultGroup), A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger0", SchedulerConstants.DefaultGroup), A<CancellationToken>._)).MustHaveHappened();
A.CallTo(() => scheduler.GetTrigger(new TriggerKey("myTrigger1", SchedulerConstants.DefaultGroup), A<CancellationToken>._)).MustHaveHappened();
}
/// <summary>
/// </summary>
[Test]
public void TestSchedulerFactoryObjectWithApplicationContext()
public async Task TestSchedulerFactoryObjectWithApplicationContext()
{
TestObject tb = new TestObject("tb", 99);
StaticApplicationContext ac = new StaticApplicationContext();
@@ -509,7 +509,7 @@ namespace Spring.Scheduling.Quartz
try
{
schedulerFactoryObject.AfterPropertiesSet();
schedulerFactoryObject.Start();
await schedulerFactoryObject.Start();
IScheduler returnedScheduler = (IScheduler) schedulerFactoryObject.GetObject();
Assert.AreEqual(tb, returnedScheduler.Context["testObject"]);
Assert.AreEqual(ac, returnedScheduler.Context["appCtx"]);
@@ -545,7 +545,7 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// </summary>
[Test]
public void TestSchedulerWithTaskExecutor()
public async Task TestSchedulerWithTaskExecutor()
{
CountingTaskExecutor taskExecutor = new CountingTaskExecutor();
DummyJob.count = 0;
@@ -567,7 +567,7 @@ namespace Spring.Scheduling.Quartz
factoryObject.Triggers = new ITrigger[] {trigger};
factoryObject.JobDetails = new IJobDetail[] {jobDetail};
factoryObject.AfterPropertiesSet();
factoryObject.Start();
await factoryObject.Start();
Thread.Sleep(500);
Assert.IsTrue(DummyJob.count > 0);
@@ -579,7 +579,7 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// </summary>
[Test]
public void TestSchedulerWithRunnable()
public async Task TestSchedulerWithRunnable()
{
DummyRunnable.count = 0;
@@ -599,7 +599,7 @@ namespace Spring.Scheduling.Quartz
factoryObject.Triggers = new ITrigger[] {trigger};
factoryObject.JobDetails = new IJobDetail[] {jobDetail};
factoryObject.AfterPropertiesSet();
factoryObject.Start();
await factoryObject.Start();
DummyRunnable.runEvent.WaitOne(500);
Assert.IsTrue(DummyRunnable.count > 0);
@@ -610,7 +610,7 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// </summary>
[Test]
public void TestSchedulerWithQuartzJobObject()
public async Task TestSchedulerWithQuartzJobObject()
{
DummyJob.param = 0;
DummyJob.count = 0;
@@ -632,7 +632,7 @@ namespace Spring.Scheduling.Quartz
factoryObject.Triggers = new ITrigger[] {trigger};
factoryObject.JobDetails = new IJobDetail[] {jobDetail};
factoryObject.AfterPropertiesSet();
factoryObject.Start();
await factoryObject.Start();
Thread.Sleep(500);
Assert.AreEqual(10, DummyJobObject.param);
@@ -644,7 +644,7 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// </summary>
[Test]
public void TestSchedulerWithSpringObjectJobFactory()
public async Task TestSchedulerWithSpringObjectJobFactory()
{
DummyJob.param = 0;
DummyJob.count = 0;
@@ -668,7 +668,7 @@ namespace Spring.Scheduling.Quartz
factoryObject.Triggers = new ITrigger[] {trigger};
factoryObject.JobDetails = new IJobDetail[] {jobDetail};
factoryObject.AfterPropertiesSet();
factoryObject.Start();
await factoryObject.Start();
Thread.Sleep(500);
Assert.AreEqual(10, DummyJob.param);
@@ -717,7 +717,7 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// </summary>
[Test]
public void TestSchedulerWithSpringObjectJobFactoryAndRunnable()
public async Task TestSchedulerWithSpringObjectJobFactoryAndRunnable()
{
DummyRunnable.param = 0;
DummyRunnable.count = 0;
@@ -740,7 +740,7 @@ namespace Spring.Scheduling.Quartz
factoryObject.Triggers = new ITrigger[] {trigger};
factoryObject.JobDetails = new IJobDetail[] {jobDetail};
factoryObject.AfterPropertiesSet();
factoryObject.Start();
await factoryObject.Start();
Thread.Sleep(500);
Assert.AreEqual(10, DummyRunnable.param);
@@ -752,7 +752,7 @@ namespace Spring.Scheduling.Quartz
///<summary>
///</summary>
[Test]
public void TestSchedulerWithSpringObjectJobFactoryAndQuartzJobObject()
public async Task TestSchedulerWithSpringObjectJobFactoryAndQuartzJobObject()
{
DummyJobObject.param = 0;
DummyJobObject.count = 0;
@@ -775,7 +775,7 @@ namespace Spring.Scheduling.Quartz
factoryObject.Triggers = new ITrigger[] {trigger};
factoryObject.JobDetails = new IJobDetail[] {jobDetail};
factoryObject.AfterPropertiesSet();
factoryObject.Start();
await factoryObject.Start();
Thread.Sleep(500);
Assert.AreEqual(10, DummyJobObject.param);
@@ -788,7 +788,7 @@ namespace Spring.Scheduling.Quartz
///
/// </summary>
[Test]
public void TestSchedulerWithSpringObjectJobFactoryAndJobSchedulingData()
public async Task TestSchedulerWithSpringObjectJobFactoryAndJobSchedulingData()
{
DummyJob.param = 0;
DummyJob.count = 0;
@@ -798,7 +798,7 @@ namespace Spring.Scheduling.Quartz
factoryObject.JobSchedulingDataLocation = "job-scheduling-data.xml";
// TODO bean.ResourceLoader = (new FileSystemResourceLoader());
factoryObject.AfterPropertiesSet();
factoryObject.Start();
await factoryObject.Start();
Thread.Sleep(500);
Assert.AreEqual(10, DummyJob.param);
@@ -924,145 +924,14 @@ namespace Spring.Scheduling.Quartz
/// Tests how scheduler is exposed to application context.
/// </summary>
[Test]
public void TestSchedulerRepositoryExposure()
public async Task TestSchedulerRepositoryExposure()
{
XmlApplicationContext ctx = new XmlApplicationContext("schedulerRepositoryExposure.xml");
Assert.AreSame(SchedulerRepository.Instance.Lookup("myScheduler"), ctx.GetObject("scheduler"));
var expected = await SchedulerRepository.Instance.Lookup("myScheduler");
Assert.AreSame(expected, ctx.GetObject("scheduler"));
ctx.Dispose();
}
private class TestSchedulerListener : ISchedulerListener
{
public void JobScheduled(ITrigger trigger)
{
}
public void JobUnscheduled(TriggerKey triggerKey)
{
}
public void TriggerFinalized(ITrigger trigger)
{
}
public void TriggerPaused(TriggerKey triggerKey)
{
}
public void TriggersPaused(string triggerGroup)
{
}
public void TriggerResumed(TriggerKey triggerKey)
{
}
public void TriggersResumed(string triggerGroup)
{
}
public void JobAdded(IJobDetail jobDetail)
{
}
public void JobDeleted(JobKey jobKey)
{
}
public void JobPaused(JobKey jobKey)
{
}
public void JobsPaused(string jobGroup)
{
}
public void JobResumed(JobKey jobKey)
{
}
public void JobsResumed(string jobGroup)
{
}
public void SchedulerError(string msg, SchedulerException cause)
{
}
public void SchedulerInStandbyMode()
{
}
public void SchedulerStarted()
{
}
public void SchedulerStarting()
{
}
public void SchedulerShutdown()
{
}
public void SchedulerShuttingdown()
{
}
public void SchedulingDataCleared()
{
}
}
private class TestJobListener : IJobListener
{
public string Name
{
get { return null; }
}
public void JobToBeExecuted(IJobExecutionContext context)
{
}
public void JobExecutionVetoed(IJobExecutionContext context)
{
}
public void JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException)
{
}
}
private class TestTriggerListener : ITriggerListener
{
public string Name
{
get { return null; }
}
public void TriggerFired(ITrigger trigger, IJobExecutionContext context)
{
}
public bool VetoJobExecution(ITrigger trigger, IJobExecutionContext context)
{
return false;
}
public void TriggerMisfired(ITrigger trigger)
{
}
public void TriggerComplete(ITrigger trigger, IJobExecutionContext context,
SchedulerInstruction triggerInstructionCode)
{
}
}
/// <summary>
/// Simple task executor that tracks invocation count.
/// </summary>
@@ -1107,9 +976,10 @@ namespace Spring.Scheduling.Quartz
/// applied as object property values by execute. The contract is
/// exactly the same as for the standard Quartz execute method.
/// </summary>
protected override void ExecuteInternal(IJobExecutionContext jobExecutionContext)
protected override Task ExecuteInternal(IJobExecutionContext jobExecutionContext)
{
count++;
return Task.FromResult(true);
}
}
@@ -1125,10 +995,11 @@ namespace Spring.Scheduling.Quartz
/// <summary>
/// Runs thread runnable.
/// </summary>
public void Run()
public Task Run()
{
count++;
runEvent.Set();
return Task.FromResult(true);
}
}
}
@@ -1158,9 +1029,10 @@ namespace Spring.Scheduling.Quartz
/// Executes this job instance.
///</summary>
///<param name="jobExecutionContext"></param>
public void Execute(IJobExecutionContext jobExecutionContext)
public Task Execute(IJobExecutionContext jobExecutionContext)
{
count++;
return Task.FromResult(true);
}
}

View File

@@ -21,7 +21,8 @@ using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using FakeItEasy;
using NUnit.Framework;
@@ -87,7 +88,7 @@ namespace Spring.Scheduling.Quartz
factory.AutoStartup = false;
factory.AfterPropertiesSet();
A.CallTo(() => TestSchedulerFactory.MockScheduler.Start()).MustNotHaveHappened();
A.CallTo(() => TestSchedulerFactory.MockScheduler.Start(A<CancellationToken>._)).MustNotHaveHappened();
}
/// <summary>
@@ -106,7 +107,7 @@ namespace Spring.Scheduling.Quartz
factory.AfterPropertiesSet();
A.CallTo(() => TestSchedulerFactory.MockScheduler.AddCalendar(calendarName, cal, true, true)).MustHaveHappened();
A.CallTo(() => TestSchedulerFactory.MockScheduler.AddCalendar(calendarName, cal, true, true, A<CancellationToken>._)).MustHaveHappened();
}
/// <summary>
@@ -122,7 +123,7 @@ namespace Spring.Scheduling.Quartz
SimpleTriggerImpl trigger = new SimpleTriggerImpl(TRIGGER_NAME, TRIGGER_GROUP);
factory.Triggers = new ITrigger[] { trigger };
A.CallTo(() => TestSchedulerFactory.MockScheduler.GetTrigger(new TriggerKey(TRIGGER_NAME, TRIGGER_GROUP))).Returns(trigger);
A.CallTo(() => TestSchedulerFactory.MockScheduler.GetTrigger(new TriggerKey(TRIGGER_NAME, TRIGGER_GROUP), A<CancellationToken>._)).Returns(trigger);
factory.AfterPropertiesSet();
}
@@ -134,7 +135,7 @@ namespace Spring.Scheduling.Quartz
public void TestAfterPropertiesSet_Trigger_TriggerDoesntExist()
{
InitForAfterPropertiesSetTest();
A.CallTo(() => TestSchedulerFactory.MockScheduler.GetTrigger(A<TriggerKey>._)).Returns(null);
A.CallTo(() => TestSchedulerFactory.MockScheduler.GetTrigger(A<TriggerKey>._, A<CancellationToken>._)).Returns(Task.FromResult<ITrigger>(null));
const string TRIGGER_NAME = "trigName";
const string TRIGGER_GROUP = "trigGroup";
@@ -143,7 +144,7 @@ namespace Spring.Scheduling.Quartz
factory.AfterPropertiesSet();
A.CallTo(() => TestSchedulerFactory.MockScheduler.ScheduleJob(trigger)).MustHaveHappened();
A.CallTo(() => TestSchedulerFactory.MockScheduler.ScheduleJob(trigger, A<CancellationToken>._)).MustHaveHappened();
}
@@ -159,38 +160,38 @@ namespace Spring.Scheduling.Quartz
/// Tests AfterPropertiesSet behavior.
/// </summary>
[Test]
public void TestStart()
public async Task TestStart()
{
factory.SchedulerFactoryType = typeof(TestSchedulerFactory);
factory.AutoStartup = false;
factory.AfterPropertiesSet();
factory.Start();
await factory.Start();
A.CallTo(TestSchedulerFactory.MockScheduler)
.Where(x => x.Method.Name.Equals("set_JobFactory"))
.WhenArgumentsMatch(x => x.Get<IJobFactory>(0) != null)
.MustHaveHappened();
A.CallTo(() => TestSchedulerFactory.MockScheduler.Start()).MustHaveHappened();
A.CallTo(() => TestSchedulerFactory.MockScheduler.Start(A<CancellationToken>._)).MustHaveHappened();
}
/// <summary>
/// Tests AfterPropertiesSet behavior.
/// </summary>
[Test]
public void TestStop()
public async Task TestStop()
{
factory.SchedulerFactoryType = typeof(TestSchedulerFactory);
factory.AutoStartup = false;
factory.AfterPropertiesSet();
factory.Stop();
await factory.Stop();
A.CallTo(TestSchedulerFactory.MockScheduler)
.Where(x => x.Method.Name.Equals("set_JobFactory"))
.WhenArgumentsMatch(x => x.Get<IJobFactory>(0) != null)
.MustHaveHappened();
A.CallTo(() => TestSchedulerFactory.MockScheduler.Standby()).MustHaveHappened();
A.CallTo(() => TestSchedulerFactory.MockScheduler.Standby(A<CancellationToken>._)).MustHaveHappened();
}
/// <summary>
@@ -284,34 +285,23 @@ ConnectionStringKey+ " = " + ConnectionStringValue + Environment.NewLine +
/// <summary>
/// The mocked scheduler.
/// </summary>
public static IScheduler MockScheduler
public static IScheduler MockScheduler => mockScheduler;
/// <inheritdoc />
public Task<IScheduler> GetScheduler(CancellationToken _)
{
get { return mockScheduler; }
return Task.FromResult(mockScheduler);
}
///<summary>
///</summary>
///<returns></returns>
public IScheduler GetScheduler()
/// <inheritdoc />
public Task<IScheduler> GetScheduler(string schedName, CancellationToken _)
{
return mockScheduler;
return Task.FromResult(mockScheduler);
}
///<summary>
///</summary>
///<param name="schedName"></param>
///<returns></returns>
public IScheduler GetScheduler(string schedName)
{
return mockScheduler;
}
///<summary>
///</summary>
public ICollection<IScheduler> AllSchedulers
{
get { return new List<IScheduler>(); }
}
/// <inheritdoc />
public Task<IReadOnlyList<IScheduler>> GetAllSchedulers(CancellationToken _)
=> Task.FromResult<IReadOnlyList<IScheduler>>(new List<IScheduler>());
public static void Initialize()
{
@@ -326,21 +316,15 @@ ConnectionStringKey+ " = " + ConnectionStringValue + Environment.NewLine +
{
private NameValueCollection properties;
///<summary>
/// Initializes the factory.
///</summary>
///<param name="props"></param>
/// <inheritdoc />
public override void Initialize(NameValueCollection props)
{
this.properties = props;
properties = props;
}
/// <summary>
/// Return propeties given to this factory at initialization time.
/// </summary>
public NameValueCollection Properties
{
get { return properties; }
}
public NameValueCollection Properties => properties;
}
}

View File

@@ -21,7 +21,6 @@ using System.Collections.Generic;
using NUnit.Framework;
using Quartz.Impl;
using Quartz.Job;
namespace Spring.Scheduling.Quartz
{

View File

@@ -15,12 +15,11 @@
*/
using System.Collections.Generic;
using System.Threading.Tasks;
using NUnit.Framework;
using Quartz;
using Quartz.Impl.Triggers;
using Quartz.Job;
using Quartz.Spi;
namespace Spring.Scheduling.Quartz
@@ -95,31 +94,28 @@ namespace Spring.Scheduling.Quartz
}
}
public class NoOpJob : IJob
{
public Task Execute(IJobExecutionContext context)
{
return Task.FromResult(true);
}
}
/// <summary>
/// Test job object that has injectable properties
/// </summary>
public class InjectableJob : NoOpJob
{
private int number;
private string foo;
/// <summary>
/// Simple int property.
/// </summary>
public int Number
{
get { return number; }
set { number = value; }
}
public int Number { get; set; }
/// <summary>
/// Simple string property.
/// </summary>
public string Foo
{
get { return foo; }
set { foo = value; }
}
public string Foo { get; set; }
}
}

View File

@@ -49,7 +49,7 @@ namespace Spring.Scheduling.Quartz
public static TriggerFiredBundle CreateMinimalFiredBundleWithTypedJobDetail(Type jobType, IOperableTrigger trigger)
{
IJobDetail jd = new JobDetailImpl("jobName", "jobGroup", jobType);
TriggerFiredBundle bundle = new TriggerFiredBundle(jd, trigger, null, false, null, null, null, null);
TriggerFiredBundle bundle = new TriggerFiredBundle(jd, trigger, null, false, DateTimeOffset.UtcNow, null, null, null);
return bundle;
}
}

View File

@@ -1,10 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net452</TargetFramework>
<TargetFrameworks>netcoreapp2.1;$(TargetFullFrameworkVersion)</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Spring\Spring.Core\Spring.Core.csproj" />
<ProjectReference Include="..\..\..\src\Spring\Spring.Scheduling.Quartz2\Spring.Scheduling.Quartz2.csproj" />
<ProjectReference Include="..\..\..\src\Spring\Spring.Scheduling.Quartz3\Spring.Scheduling.Quartz3.csproj" />
<ProjectReference Include="..\Spring.Core.Tests\Spring.Core.Tests.csproj" />
</ItemGroup>
<ItemGroup>

View File

@@ -13,7 +13,7 @@
<job>
<name>myJob</name>
<group>myGroup</group>
<job-type>Spring.Scheduling.Quartz.DummyJob, Spring.Scheduling.Quartz2.Tests</job-type>
<job-type>Spring.Scheduling.Quartz.DummyJob, Spring.Scheduling.Quartz3.Tests</job-type>
<durable>true</durable>
<recover>false</recover>
<job-data-map>

View File

@@ -4,7 +4,7 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
<object id="scheduler" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz2">
<object id="scheduler" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz3">
<property name="Triggers">
<list>
<ref local="exportTrigger"/>
@@ -14,9 +14,9 @@
</property>
</object>
<object id="exportTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz2">
<object id="exportTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz3">
<property name="JobDetail">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz2">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz3">
<property name="TargetObject" ref="exportService"/>
<property name="TargetMethod" value="DoExport"/>
</object>
@@ -26,9 +26,9 @@
<property name="RepeatCount" value="1"/>
</object>
<object id="importTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz2">
<object id="importTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz3">
<property name="JobDetail">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz2">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz3">
<property name="TargetObject" ref="importService"/>
<property name="TargetMethod" value="DoImport"/>
@@ -38,8 +38,8 @@
<property name="RepeatCount" value="1"/>
</object>
<object id="exportService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz2.Tests"/>
<object id="exportService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz3.Tests"/>
<object id="importService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz2.Tests"/>
<object id="importService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz3.Tests"/>
</objects>

View File

@@ -5,11 +5,11 @@
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
<object id="scheduler1" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz2">
<object id="scheduler1" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz3">
<property name="SchedulerName" value="quartz1"/>
</object>
<object id="scheduler2" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz2">
<object id="scheduler2" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz3">
<property name="SchedulerName" value="quartz2"/>
</object>

View File

@@ -5,9 +5,9 @@
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
<object id="scheduler" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz2"/>
<object id="scheduler" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz3"/>
<object type="Spring.Scheduling.Quartz.SchedulerAccessorObject, Spring.Scheduling.Quartz2">
<object type="Spring.Scheduling.Quartz.SchedulerAccessorObject, Spring.Scheduling.Quartz3">
<property name="Scheduler" ref="scheduler"/>
<property name="Triggers">
<list>
@@ -18,9 +18,9 @@
</property>
</object>
<object id="exportTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz2">
<object id="exportTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz3">
<property name="JobDetail">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz2">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz3">
<property name="TargetObject" ref="exportService"/>
<property name="TargetMethod" value="DoExport"/>
</object>
@@ -29,10 +29,10 @@
<property name="RepeatCount" value="1"/>
</object>
<object id="importTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz2">
<object id="importTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz3">
<property name="jobDetail">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz2">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz3">
<property name="TargetObject" ref="importService"/>
<property name="TargetMethod" value="DoImport"/>
</object>
@@ -41,8 +41,8 @@
<property name="RepeatCount" value="1"/>
</object>
<object id="exportService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz2.Tests"/>
<object id="exportService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz3.Tests"/>
<object id="importService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz2.Tests"/>
<object id="importService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz3.Tests"/>
</objects>

View File

@@ -5,12 +5,12 @@
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
<object id="scheduler" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz2">
<object id="scheduler" type="Spring.Scheduling.Quartz.SchedulerFactoryObject, Spring.Scheduling.Quartz3">
<property name="schedulerName" value="myScheduler"/>
<property name="exposeSchedulerInRepository" value="true"/>
</object>
<object type="Spring.Scheduling.Quartz.SchedulerAccessorObject, Spring.Scheduling.Quartz2">
<object type="Spring.Scheduling.Quartz.SchedulerAccessorObject, Spring.Scheduling.Quartz3">
<property name="schedulerName" value="myScheduler"/>
<property name="triggers">
@@ -21,10 +21,10 @@
</property>
</object>
<object id="exportTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz2">
<object id="exportTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz3">
<property name="JobDetail">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz2">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz3">
<property name="TargetObject" ref="exportService"/>
<property name="TargetMethod" value="DoExport"/>
</object>
@@ -33,9 +33,9 @@
<property name="RepeatCount" value="1"/>
</object>
<object id="importTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz2">
<object id="importTrigger" type="Spring.Scheduling.Quartz.SimpleTriggerObject, Spring.Scheduling.Quartz3">
<property name="jobDetail">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz2">
<object type="Spring.Scheduling.Quartz.MethodInvokingJobDetailFactoryObject, Spring.Scheduling.Quartz3">
<property name="TargetObject" ref="importService"/>
<property name="TargetMethod" value="DoImport"/>
</object>
@@ -45,8 +45,8 @@
<property name="RepeatCount" value="1"/>
</object>
<object id="exportService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz2.Tests"/>
<object id="exportService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz3.Tests"/>
<object id="importService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz2.Tests"/>
<object id="importService" type="Spring.Scheduling.Quartz.QuartzTestObject, Spring.Scheduling.Quartz3.Tests"/>
</objects>