Line data Source code
1 : #region Copyright
2 : // // -----------------------------------------------------------------------
3 : // // <copyright company="cdmdotnet Limited">
4 : // // Copyright cdmdotnet Limited. All rights reserved.
5 : // // </copyright>
6 : // // -----------------------------------------------------------------------
7 : #endregion
8 :
9 : using System;
10 : using System.Collections.Generic;
11 : using System.Linq;
12 : using cdmdotnet.Logging;
13 : using Cqrs.Domain.Exceptions;
14 : using Cqrs.Domain.Factories;
15 : using Cqrs.Events;
16 :
17 : namespace Cqrs.Domain
18 : {
19 : public class SagaRepository<TAuthenticationToken> : ISagaRepository<TAuthenticationToken>
20 0 : {
21 : protected IEventStore<TAuthenticationToken> EventStore { get; private set; }
22 :
23 : protected IEventPublisher<TAuthenticationToken> Publisher { get; private set; }
24 :
25 : protected IAggregateFactory SagaFactory { get; private set; }
26 :
27 : protected ICorrelationIdHelper CorrelationIdHelper { get; private set; }
28 :
29 0 : public SagaRepository(IAggregateFactory sagaFactory, IEventStore<TAuthenticationToken> eventStore, IEventPublisher<TAuthenticationToken> publisher, ICorrelationIdHelper correlationIdHelper)
30 : {
31 : EventStore = eventStore;
32 : Publisher = publisher;
33 : CorrelationIdHelper = correlationIdHelper;
34 : SagaFactory = sagaFactory;
35 : }
36 :
37 0 : public virtual void Save<TSaga>(TSaga saga, int? expectedVersion = null)
38 : where TSaga : ISaga<TAuthenticationToken>
39 : {
40 : IList<ISagaEvent<TAuthenticationToken>> uncommittedChanges = saga.GetUncommittedChanges().ToList();
41 : if (!uncommittedChanges.Any())
42 : return;
43 :
44 : if (expectedVersion != null)
45 : {
46 : IEnumerable<IEvent<TAuthenticationToken>> eventStoreResults = EventStore.Get(saga.GetType(), saga.Id, false, expectedVersion.Value);
47 : if (eventStoreResults.Any())
48 : throw new ConcurrencyException(saga.Id);
49 : }
50 :
51 : var eventsToPublish = new List<ISagaEvent<TAuthenticationToken>>();
52 :
53 : int i = 0;
54 : foreach (ISagaEvent<TAuthenticationToken> @event in uncommittedChanges)
55 : {
56 : if (@event.Id == Guid.Empty)
57 : @event.Id = saga.Id;
58 : if (@event.Id == Guid.Empty)
59 : throw new AggregateOrEventMissingIdException(saga.GetType(), @event.GetType());
60 :
61 : i++;
62 :
63 : @event.Version = saga.Version + i;
64 : @event.TimeStamp = DateTimeOffset.UtcNow;
65 : @event.CorrelationId = CorrelationIdHelper.GetCorrelationId();
66 : EventStore.Save(saga.GetType(), @event);
67 : eventsToPublish.Add(@event);
68 : }
69 :
70 : saga.MarkChangesAsCommitted();
71 : foreach (ISagaEvent<TAuthenticationToken> @event in eventsToPublish)
72 : PublishEvent(@event);
73 : }
74 :
75 0 : protected virtual void PublishEvent(ISagaEvent<TAuthenticationToken> @event)
76 : {
77 : Publisher.Publish(@event);
78 : }
79 :
80 0 : public virtual TSaga Get<TSaga>(Guid sagaId, IList<ISagaEvent<TAuthenticationToken>> events = null)
81 : where TSaga : ISaga<TAuthenticationToken>
82 : {
83 : return LoadSaga<TSaga>(sagaId, events);
84 : }
85 :
86 0 : protected virtual TSaga CreateSaga<TSaga>(Guid id)
87 : where TSaga : ISaga<TAuthenticationToken>
88 : {
89 : var saga = SagaFactory.Create<TSaga>(id);
90 :
91 : return saga;
92 : }
93 :
94 0 : protected virtual TSaga LoadSaga<TSaga>(Guid id, IList<ISagaEvent<TAuthenticationToken>> events = null)
95 : where TSaga : ISaga<TAuthenticationToken>
96 : {
97 : var saga = SagaFactory.Create<TSaga>(id);
98 :
99 : LoadSagaHistory(saga, events);
100 : return saga;
101 : }
102 :
103 0 : public virtual void LoadSagaHistory<TSaga>(TSaga saga, IList<ISagaEvent<TAuthenticationToken>> events = null, bool throwExceptionOnNoEvents = true)
104 : where TSaga : ISaga<TAuthenticationToken>
105 : {
106 : IList<ISagaEvent<TAuthenticationToken>> theseEvents = events ?? EventStore.Get<TSaga>(saga.Id).Cast<ISagaEvent<TAuthenticationToken>>().ToList();
107 : if (!theseEvents.Any())
108 : {
109 : if (throwExceptionOnNoEvents)
110 : throw new SagaNotFoundException<TSaga, TAuthenticationToken>(saga.Id);
111 : return;
112 : }
113 :
114 : var duplicatedEvents =
115 : theseEvents.GroupBy(x => x.Version)
116 : .Select(x => new { Version = x.Key, Total = x.Count() })
117 : .FirstOrDefault(x => x.Total > 1);
118 : if (duplicatedEvents != null)
119 : throw new DuplicateSagaEventException<TSaga, TAuthenticationToken>(saga.Id, duplicatedEvents.Version);
120 :
121 : saga.LoadFromHistory(theseEvents);
122 : }
123 : }
124 : }
|