diff --git a/packaging/nuget/NServiceBus.MongoDB.nuspec b/packaging/nuget/NServiceBus.MongoDB.nuspec index b7152e0..ef9fd60 100644 --- a/packaging/nuget/NServiceBus.MongoDB.nuspec +++ b/packaging/nuget/NServiceBus.MongoDB.nuspec @@ -3,7 +3,7 @@ NServiceBus.MongoDB NServiceBus MongoDB - 5.2.4 + 5.2.5 Carlos Sandoval SharkByte Software https://github.com/sbmako/NServiceBus.MongoDB/blob/master/LICENSE diff --git a/src/.nuget/NuGet.exe b/src/.nuget/NuGet.exe index c41a0d0..6bb79fe 100644 Binary files a/src/.nuget/NuGet.exe and b/src/.nuget/NuGet.exe differ diff --git a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_a_existing_saga_instance_exists.cs b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_a_existing_saga_instance_exists.cs index 975300c..3821fed 100644 --- a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_a_existing_saga_instance_exists.cs +++ b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_a_existing_saga_instance_exists.cs @@ -83,6 +83,8 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion public virtual Guid SomeId { get; set; } public int DocumentVersion { get; set; } + + public int ETag { get; set; } } } diff --git a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_receiving_that_completes_the_saga.cs b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_receiving_that_completes_the_saga.cs index 591510e..e4f2514 100644 --- a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_receiving_that_completes_the_saga.cs +++ b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_receiving_that_completes_the_saga.cs @@ -148,6 +148,7 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion public virtual Guid SomeId { get; set; } public int DocumentVersion { get; set; } + public int ETag { get; set; } } } diff --git a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_saga_has_a_non_empty_constructor.cs b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_saga_has_a_non_empty_constructor.cs index 0e906a6..7092ddc 100644 --- a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_saga_has_a_non_empty_constructor.cs +++ b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_saga_has_a_non_empty_constructor.cs @@ -81,6 +81,7 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion public virtual Guid SomeId { get; set; } public int DocumentVersion { get; set; } + public int ETag { get; set; } } } diff --git a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_saga_is_mapped_to_complex_expression.cs b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_saga_is_mapped_to_complex_expression.cs index b50c86a..871f02c 100644 --- a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_saga_is_mapped_to_complex_expression.cs +++ b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_saga_is_mapped_to_complex_expression.cs @@ -70,6 +70,7 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion public virtual string KeyValue { get; set; } public int DocumentVersion { get; set; } + public int ETag { get; set; } } } diff --git a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_using_a_received_message_for_timeout.cs b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_using_a_received_message_for_timeout.cs index 0070b1e..c138231 100644 --- a/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_using_a_received_message_for_timeout.cs +++ b/src/NServiceBus.MongoDB.Acceptance.Tests/App_Packages/NSB.AcceptanceTests.5.2.5/Sagas/When_using_a_received_message_for_timeout.cs @@ -71,6 +71,7 @@ public class TestSagaData : IContainSagaData, IHaveDocumentVersion public virtual Guid SomeId { get; set; } public int DocumentVersion { get; set; } + public int ETag { get; set; } } } diff --git a/src/NServiceBus.MongoDB.Tests/Issues/Issue_16.cs b/src/NServiceBus.MongoDB.Tests/Issues/Issue_16.cs index 9a3a367..e5e3dfe 100644 --- a/src/NServiceBus.MongoDB.Tests/Issues/Issue_16.cs +++ b/src/NServiceBus.MongoDB.Tests/Issues/Issue_16.cs @@ -75,5 +75,6 @@ public sealed class DeviceCommandSagaState : IContainSagaData, IHaveDocumentVers //IHaveDocumentVersion properties public int DocumentVersion { get; set; } + public int ETag { get; set; } } } diff --git a/src/NServiceBus.MongoDB.Tests/SagaPersister/MongoSagaPersisterTests.cs b/src/NServiceBus.MongoDB.Tests/SagaPersister/MongoSagaPersisterTests.cs index 4a7abca..3f70311 100644 --- a/src/NServiceBus.MongoDB.Tests/SagaPersister/MongoSagaPersisterTests.cs +++ b/src/NServiceBus.MongoDB.Tests/SagaPersister/MongoSagaPersisterTests.cs @@ -238,6 +238,40 @@ public void UpdatingSagaWithoutDocumentVersion( sut.Invoking(s => s.Update(sagaData)).ShouldThrow(); } + [Theory, IntegrationTest] + [AutoDatabase] + public void UpdatingSagaWithNoChangesShouldNotUpdateVersion( + MongoSagaPersister sut, + MongoDatabaseFactory factory, + SagaWithoutUniqueProperties sagaData) + { + sut.Save(sagaData); + var saga1 = factory.RetrieveSagaData(sagaData); + + sut.Update(saga1); + + var saga2 = factory.RetrieveSagaData(sagaData); + saga2.DocumentVersion.Should().Be(saga1.DocumentVersion); + } + + [Theory, IntegrationTest] + [AutoDatabase] + public void UpdatingSagaWithChangesShouldUpdateVersion( + MongoSagaPersister sut, + MongoDatabaseFactory factory, + SagaWithoutUniqueProperties sagaData) + { + sut.Save(sagaData); + var saga1 = factory.RetrieveSagaData(sagaData); + + saga1.UniqueProperty = "NewValue"; + sut.Update(saga1); + + var saga2 = factory.RetrieveSagaData(sagaData); + saga2.DocumentVersion.Should().Be(saga1.DocumentVersion + 1); + saga2.UniqueProperty.Should().Be(saga1.UniqueProperty); + } + [Theory, IntegrationTest] [AutoDatabase] public void CompletingSagaShouldRemoveDocument( diff --git a/src/NServiceBus.MongoDB/ContainMongoSagaData.cs b/src/NServiceBus.MongoDB/ContainMongoSagaData.cs index 68de4db..37fd436 100644 --- a/src/NServiceBus.MongoDB/ContainMongoSagaData.cs +++ b/src/NServiceBus.MongoDB/ContainMongoSagaData.cs @@ -39,5 +39,10 @@ public abstract class ContainMongoSagaData : ContainSagaData, IHaveDocumentVersi /// Gets or sets the document version. /// public int DocumentVersion { get; set; } + + /// + /// Gets or sets the e tag. + /// + public int ETag { get; set; } } } diff --git a/src/NServiceBus.MongoDB/Extensions/DocumentVersionExtensions.cs b/src/NServiceBus.MongoDB/Extensions/DocumentVersionExtensions.cs index 63752be..3143538 100644 --- a/src/NServiceBus.MongoDB/Extensions/DocumentVersionExtensions.cs +++ b/src/NServiceBus.MongoDB/Extensions/DocumentVersionExtensions.cs @@ -1,105 +1,114 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// The MIT License (MIT) -// -// Copyright (c) 2015 SharkByte Software -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// -// Defines the DocumentVersionExtensions type. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace NServiceBus.MongoDB.Extensions -{ - using System; - using System.Diagnostics.Contracts; - using System.Linq; - using global::MongoDB.Bson; - using global::MongoDB.Driver; - using global::MongoDB.Driver.Builders; - - using NServiceBus.MongoDB.Internals; - using NServiceBus.MongoDB.SubscriptionPersister; - using NServiceBus.Saga; - - internal static class DocumentVersionExtensions - { - public static IMongoQuery MongoUpdateQuery(this IContainSagaData saga) - { - Contract.Requires(saga != null); - Contract.Ensures(Contract.Result() != null); - - var versionedDocument = saga as IHaveDocumentVersion; - - if (versionedDocument == null) - { - throw new InvalidOperationException( - string.Format("Saga type {0} does not implement IHaveDocumentVersion", saga.GetType().Name)); - } - - return - Query.And( - Query.EQ("_id", saga.Id), - Query.EQ(MongoPersistenceConstants.VersionPropertyName, versionedDocument.DocumentVersion)) - .AssumedNotNull(); - } - - public static IMongoUpdate MongoUpdate(this T saga) where T : IContainSagaData - { - Contract.Requires(saga != null); - Contract.Ensures(Contract.Result() != null); - - var classMap = saga.ToBsonDocument(); - - var versionedDocument = saga as IHaveDocumentVersion; - if (versionedDocument == null) - { - return Update.Replace(saga).AssumedNotNull(); - } - - classMap.Remove("_id"); - classMap.Remove(MongoPersistenceConstants.VersionPropertyName); - var updateBuilder = Update.Inc(MongoPersistenceConstants.VersionPropertyName, 1); - - classMap.ToList().ForEach(f => updateBuilder.Set(f.Name, f.Value)); - - return updateBuilder.AssumedNotNull(); - } - - public static IMongoQuery MongoUpdateQuery(this Subscription subscription) - { - Contract.Requires(subscription != null); - Contract.Ensures(Contract.Result() != null); - - return - Query.And( - Query.EQ(s => s.Id, subscription.Id), - Query.EQ(s => s.DocumentVersion, subscription.DocumentVersion)).AssumedNotNull(); - } - - public static IMongoUpdate MongoUpdate(this Subscription subscription) - { - Contract.Requires(subscription != null); - Contract.Ensures(Contract.Result() != null); - - return Update.Replace(subscription).AssumedNotNull(); - } - } -} +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2015 SharkByte Software +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// Defines the DocumentVersionExtensions type. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace NServiceBus.MongoDB.Extensions +{ + using System; + using System.Diagnostics.Contracts; + using System.Linq; + using global::MongoDB.Bson; + using global::MongoDB.Driver; + using global::MongoDB.Driver.Builders; + + using NServiceBus.MongoDB.Internals; + using NServiceBus.MongoDB.SubscriptionPersister; + using NServiceBus.Saga; + + internal static class DocumentVersionExtensions + { + public static IMongoQuery MongoUpdateQuery(this IContainSagaData saga) + { + Contract.Requires(saga != null); + Contract.Ensures(Contract.Result() != null); + + var versionedDocument = saga as IHaveDocumentVersion; + + if (versionedDocument == null) + { + throw new InvalidOperationException( + string.Format("Saga type {0} does not implement IHaveDocumentVersion", saga.GetType().Name)); + } + + return + Query.And( + Query.EQ("_id", saga.Id), + Query.EQ(MongoPersistenceConstants.VersionPropertyName, versionedDocument.DocumentVersion)) + .AssumedNotNull(); + } + + public static IMongoUpdate MongoUpdate(this T saga) where T : IContainSagaData + { + Contract.Requires(saga != null); + Contract.Ensures(Contract.Result() != null); + + var classMap = saga.ToBsonDocument(); + + var versionedDocument = saga as IHaveDocumentVersion; + if (versionedDocument == null) + { + return Update.Replace(saga).AssumedNotNull(); + } + + classMap.Remove("_id"); + classMap.Remove(MongoPersistenceConstants.VersionPropertyName); + var updateBuilder = Update.Inc(MongoPersistenceConstants.VersionPropertyName, 1); + + classMap.ToList().ForEach(f => updateBuilder.Set(f.Name, f.Value)); + + return updateBuilder.AssumedNotNull(); + } + + public static IMongoQuery MongoUpdateQuery(this Subscription subscription) + { + Contract.Requires(subscription != null); + Contract.Ensures(Contract.Result() != null); + + return Query.EQ(s => s.Id, subscription.Id).AssumedNotNull(); + } + + public static IMongoUpdate MongoUpdate(this Subscription subscription) + { + Contract.Requires(subscription != null); + Contract.Ensures(Contract.Result() != null); + + return Update.Replace(subscription).AssumedNotNull(); + } + + public static int ComputeETag(this T sagaData) where T : IContainSagaData + { + Contract.Requires(sagaData != null); + + var bsonDocument = sagaData.ToBsonDocument(); + + bsonDocument.Remove(MongoPersistenceConstants.VersionPropertyName); + bsonDocument.Remove(MongoPersistenceConstants.ETagPropertyName); + + return bsonDocument.GetHashCode(); + } + } +} diff --git a/src/NServiceBus.MongoDB/IHaveDocumentVersion.cs b/src/NServiceBus.MongoDB/IHaveDocumentVersion.cs index 184b1f1..79cf78a 100644 --- a/src/NServiceBus.MongoDB/IHaveDocumentVersion.cs +++ b/src/NServiceBus.MongoDB/IHaveDocumentVersion.cs @@ -37,5 +37,10 @@ public interface IHaveDocumentVersion /// Gets or sets the document version. /// int DocumentVersion { get; set; } + + /// + /// Gets or sets the e tag. + /// + int ETag { get; set; } } } diff --git a/src/NServiceBus.MongoDB/Internals/MongoPersistenceConstants.cs b/src/NServiceBus.MongoDB/Internals/MongoPersistenceConstants.cs index 04235fd..d918d12 100644 --- a/src/NServiceBus.MongoDB/Internals/MongoPersistenceConstants.cs +++ b/src/NServiceBus.MongoDB/Internals/MongoPersistenceConstants.cs @@ -36,6 +36,8 @@ internal static class MongoPersistenceConstants public const string VersionPropertyName = "DocumentVersion"; + public const string ETagPropertyName = "ETag"; + public const string OwningTimeoutManagerAndTimeName = "OwningTimeoutManagerAndTime"; public const string OwningTimeoutManagerAndSagaIdAndTimeName = "OwningTimeoutManagerAndSagaIdAndTime"; diff --git a/src/NServiceBus.MongoDB/NServiceBus.MongoDB.csproj b/src/NServiceBus.MongoDB/NServiceBus.MongoDB.csproj index b577161..88ff364 100644 --- a/src/NServiceBus.MongoDB/NServiceBus.MongoDB.csproj +++ b/src/NServiceBus.MongoDB/NServiceBus.MongoDB.csproj @@ -123,7 +123,7 @@ true bin\DebugContracts\ CODE_ANALYSIS;DEBUG;TRACE - true + false full false prompt diff --git a/src/NServiceBus.MongoDB/SagaPersister/MongoSagaPersister.cs b/src/NServiceBus.MongoDB/SagaPersister/MongoSagaPersister.cs index 578515c..11dc408 100644 --- a/src/NServiceBus.MongoDB/SagaPersister/MongoSagaPersister.cs +++ b/src/NServiceBus.MongoDB/SagaPersister/MongoSagaPersister.cs @@ -68,12 +68,17 @@ public void Save(IContainSagaData saga) { var sagaTypeName = saga.GetType().Name; - if (!(saga is IHaveDocumentVersion)) + var sagaDataWithVersion = saga as IHaveDocumentVersion; + + if (sagaDataWithVersion == null) { throw new InvalidOperationException( string.Format("Saga type {0} does not implement IHaveDocumentVersion", sagaTypeName)); } + sagaDataWithVersion.DocumentVersion = 0; + sagaDataWithVersion.ETag = saga.ComputeETag(); + var uniqueProperty = UniqueAttribute.GetUniqueProperty(saga); if (uniqueProperty.HasValue) { @@ -96,6 +101,14 @@ public void Save(IContainSagaData saga) /// The saga entity to updated. public void Update(IContainSagaData saga) { + var newETag = saga.AssumedNotNull().ComputeETag(); + + var versionedDocument = (IHaveDocumentVersion)saga; + if (versionedDocument.ETag == newETag) + { + return; + } + var collection = this.mongoDatabase.GetCollection(saga.GetType().Name); var query = saga.MongoUpdateQuery(); diff --git a/src/NServiceBus.MongoDB/SubscriptionPersister/Subscription.cs b/src/NServiceBus.MongoDB/SubscriptionPersister/Subscription.cs index 5b646c4..ecff33f 100644 --- a/src/NServiceBus.MongoDB/SubscriptionPersister/Subscription.cs +++ b/src/NServiceBus.MongoDB/SubscriptionPersister/Subscription.cs @@ -1,117 +1,117 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// The MIT License (MIT) -// -// Copyright (c) 2015 SharkByte Software -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -// -// -// The subscription. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace NServiceBus.MongoDB.SubscriptionPersister -{ - using System; - using System.Collections.Generic; - using System.Diagnostics.Contracts; - using System.Linq; - - using NServiceBus.MongoDB.Internals; - using NServiceBus.Unicast.Subscriptions; - - internal sealed class Subscription : IHaveDocumentVersion - { - /// - /// Initializes a new instance of the class. - /// - public Subscription() - { - this.Id = string.Empty; - this.DocumentVersion = 0; - this.MessageType = new MessageType(typeof(object)); - this.Clients = new List
(); - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The message type. - /// - /// - /// The clients. - /// - public Subscription(MessageType messageType, IEnumerable
clients) - { - Contract.Requires(messageType != null, "messageType != null"); - Contract.Requires(clients != null, "clients != null"); - - this.Id = FormatId(messageType); - this.MessageType = messageType; - this.Clients = clients.ToList(); - } - - /// - /// Gets or sets the id. - /// - public string Id { get; set; } - - /// - /// Gets or sets the document version. - /// - public int DocumentVersion { get; set; } - - /// - /// Gets or sets the message type. - /// - public MessageType MessageType { get; set; } - - /// - /// Gets or sets the clients. - /// - public List
Clients { get; set; } - - /// - /// The format id. - /// - /// - /// The message type. - /// - /// - /// The . - /// - public static string FormatId(MessageType messageType) - { - Contract.Requires(messageType != null, "messageType != null"); - Contract.Ensures(Contract.Result() != null); - - var id = DeterministicGuid.Create(messageType.TypeName, "/", messageType.Version.Major); - return string.Format("Subscriptions/{0}", id); - } - - [ContractInvariantMethod] - private void ObjectInvariants() - { - Contract.Invariant(this.Id != null); - Contract.Invariant(this.MessageType != null); - Contract.Invariant(this.Clients != null); - } - } -} +// -------------------------------------------------------------------------------------------------------------------- +// +// The MIT License (MIT) +// +// Copyright (c) 2015 SharkByte Software +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +// +// The subscription. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace NServiceBus.MongoDB.SubscriptionPersister +{ + using System; + using System.Collections.Generic; + using System.Diagnostics.Contracts; + using System.Linq; + + using NServiceBus.MongoDB.Internals; + using NServiceBus.Unicast.Subscriptions; + + internal sealed class Subscription + { + /// + /// Initializes a new instance of the class. + /// + public Subscription() + { + this.Id = string.Empty; + this.DocumentVersion = 0; + this.MessageType = new MessageType(typeof(object)); + this.Clients = new List
(); + } + + /// + /// Initializes a new instance of the class. + /// + /// + /// The message type. + /// + /// + /// The clients. + /// + public Subscription(MessageType messageType, IEnumerable
clients) + { + Contract.Requires(messageType != null, "messageType != null"); + Contract.Requires(clients != null, "clients != null"); + + this.Id = FormatId(messageType); + this.MessageType = messageType; + this.Clients = clients.ToList(); + } + + /// + /// Gets or sets the id. + /// + public string Id { get; set; } + + /// + /// Gets or sets the document version. + /// + public int DocumentVersion { get; set; } + + /// + /// Gets or sets the message type. + /// + public MessageType MessageType { get; set; } + + /// + /// Gets or sets the clients. + /// + public List
Clients { get; set; } + + /// + /// The format id. + /// + /// + /// The message type. + /// + /// + /// The . + /// + public static string FormatId(MessageType messageType) + { + Contract.Requires(messageType != null, "messageType != null"); + Contract.Ensures(Contract.Result() != null); + + var id = DeterministicGuid.Create(messageType.TypeName, "/", messageType.Version.Major); + return string.Format("Subscriptions/{0}", id); + } + + [ContractInvariantMethod] + private void ObjectInvariants() + { + Contract.Invariant(this.Id != null); + Contract.Invariant(this.MessageType != null); + Contract.Invariant(this.Clients != null); + } + } +}