Line data Source code
1 : #region Copyright
2 : // // -----------------------------------------------------------------------
3 : // // <copyright company="Chinchilla Software Limited">
4 : // // Copyright Chinchilla Software Limited. All rights reserved.
5 : // // </copyright>
6 : // // -----------------------------------------------------------------------
7 : #endregion
8 :
9 : using System;
10 : using cdmdotnet.Logging;
11 : using Cqrs.Configuration;
12 : using Cqrs.Domain;
13 : using Cqrs.Events;
14 :
15 : namespace Cqrs.Snapshots
16 : {
17 : /// <summary>
18 : /// Stores the most recent <see cref="Snapshot">snapshots</see> for replay and <see cref="IAggregateRoot{TAuthenticationToken}"/> rehydration on a <see cref="SnapshotAggregateRoot{TAuthenticationToken,TSnapshot}"/>.
19 : /// </summary>
20 : public abstract class SnapshotStore
21 : : ISnapshotStore
22 1 : {
23 : /// <summary>
24 : /// Instantiate a new instance of the <see cref="SnapshotStore"/> class.
25 : /// </summary>
26 1 : protected SnapshotStore(IConfigurationManager configurationManager, ISnapshotDeserialiser eventDeserialiser, ISnapshotBuilder snapshotBuilder, ILogger logger, ICorrelationIdHelper correlationIdHelper)
27 : {
28 : ConfigurationManager = configurationManager;
29 : EventDeserialiser = eventDeserialiser;
30 : SnapshotBuilder = snapshotBuilder;
31 : Logger = logger;
32 : CorrelationIdHelper = correlationIdHelper;
33 : }
34 :
35 : /// <summary>
36 : /// The pattern used to generate the stream name.
37 : /// </summary>
38 : protected const string CqrsSnapshotStoreStreamNamePattern = "{0}/{1}";
39 :
40 : /// <summary>
41 : /// Gets or sets the <see cref="IConfigurationManager"/>
42 : /// </summary>
43 : protected IConfigurationManager ConfigurationManager { get; private set; }
44 :
45 : /// <summary>
46 : /// The <see cref="ISnapshotDeserialiser"/> used to deserialise snapshots.
47 : /// </summary>
48 : protected ISnapshotDeserialiser EventDeserialiser { get; private set; }
49 :
50 : /// <summary>
51 : /// The <see cref="ISnapshotBuilder"/> used to build snapshots.
52 : /// </summary>
53 : protected ISnapshotBuilder SnapshotBuilder { get; private set; }
54 :
55 : /// <summary>
56 : /// The <see cref="ILogger"/> to use.
57 : /// </summary>
58 : protected ILogger Logger { get; private set; }
59 :
60 : /// <summary>
61 : /// The <see cref="ICorrelationIdHelper"/> to use.
62 : /// </summary>
63 : protected ICorrelationIdHelper CorrelationIdHelper { get; private set; }
64 :
65 : #region Implementation of ISnapshotStore
66 :
67 : /// <summary>
68 : /// Get the latest <see cref="Snapshot"/> from storage.
69 : /// </summary>
70 : /// <typeparam name="TAggregateRoot">The <see cref="Type"/> of <see cref="IAggregateRoot{TAuthenticationToken}"/> to find a snapshot for.</typeparam>
71 : /// <param name="id">The identifier of the <see cref="IAggregateRoot{TAuthenticationToken}"/> to get the most recent <see cref="Snapshot"/> of.</param>
72 : /// <returns>The most recent <see cref="Snapshot"/> of</returns>
73 1 : public virtual Snapshot Get<TAggregateRoot>(Guid id)
74 : {
75 : Type aggregateRootType = typeof (TAggregateRoot);
76 : return Get(aggregateRootType, id);
77 : }
78 :
79 : /// <summary>
80 : /// Get the latest <see cref="Snapshot"/> from storage.
81 : /// </summary>
82 : /// <param name="aggregateRootType">The <see cref="Type"/> of <see cref="IAggregateRoot{TAuthenticationToken}"/> to find a snapshot for.</param>
83 : /// <param name="id">The identifier of the <see cref="IAggregateRoot{TAuthenticationToken}"/> to get the most recent <see cref="Snapshot"/> of.</param>
84 : /// <returns>The most recent <see cref="Snapshot"/> of</returns>
85 1 : public Snapshot Get(Type aggregateRootType, Guid id)
86 : {
87 : while (aggregateRootType != null && !aggregateRootType.IsGenericType && aggregateRootType.GetGenericArguments().Length != 2)
88 : aggregateRootType = aggregateRootType.BaseType;
89 : if (aggregateRootType == null)
90 : return null;
91 :
92 : aggregateRootType = aggregateRootType.GetGenericArguments()[1];
93 : if (aggregateRootType.BaseType != typeof(Snapshot))
94 : return null;
95 :
96 : string streamName = string.Format(CqrsSnapshotStoreStreamNamePattern, aggregateRootType.FullName, id);
97 :
98 : return Get(aggregateRootType, streamName);
99 : }
100 :
101 : /// <summary>
102 : /// Get the latest <see cref="Snapshot"/> from storage.
103 : /// </summary>
104 : /// <returns>The most recent <see cref="Snapshot"/> of</returns>
105 1 : protected abstract Snapshot Get(Type aggregateRootType, string streamName);
106 :
107 : /// <summary>
108 : /// Saves the provided <paramref name="snapshot"/> into storage.
109 : /// </summary>
110 : /// <param name="snapshot">the <see cref="Snapshot"/> to save and store.</param>
111 1 : public abstract void Save(Snapshot snapshot);
112 :
113 : #endregion
114 :
115 : /// <summary>
116 : /// Generate a unique stream name based on the provided <paramref name="aggregateRootType"/> and the <paramref name="aggregateId"/>.
117 : /// </summary>
118 : /// <param name="aggregateRootType">The <see cref="Type"/> of the <see cref="IAggregateRoot{TAuthenticationToken}"/>.</param>
119 : /// <param name="aggregateId">The ID of the <see cref="IAggregateRoot{TAuthenticationToken}"/>.</param>
120 1 : protected virtual string GenerateStreamName(Type aggregateRootType, Guid aggregateId)
121 : {
122 : return string.Format(CqrsSnapshotStoreStreamNamePattern, aggregateRootType.FullName, aggregateId);
123 : }
124 :
125 : /// <summary>
126 : /// Builds the <see cref="EventData"/> from the <paramref name="snapshot"/>.
127 : /// </summary>
128 1 : protected virtual EventData BuildEventData(Snapshot snapshot)
129 : {
130 : Logger.LogDebug("Building the snapshot event data", "SnapshotStore\\BuildEventData");
131 : try
132 : {
133 : DateTime start = DateTime.Now;
134 : EventData eventData = SnapshotBuilder.CreateFrameworkEvent(snapshot);
135 : string streamName = GenerateStreamName(snapshot.GetType(), snapshot.Id);
136 : eventData.AggregateId = streamName;
137 : eventData.AggregateRsn = snapshot.Id;
138 : eventData.Version = snapshot.Version;
139 : eventData.CorrelationId = CorrelationIdHelper.GetCorrelationId();
140 : DateTime end = DateTime.Now;
141 : Logger.LogDebug(string.Format("Building the snapshot event data took {0}.", end - start), "SnapshotStore\\BuildEventData");
142 : return eventData;
143 : }
144 : catch (Exception exception)
145 : {
146 : Logger.LogError("There was an issue building the snapshot event data.", exception: exception);
147 : throw;
148 : }
149 : finally
150 : {
151 : Logger.LogDebug("Building the snapshot event data... Done", "SnapshotStore\\BuildEventData");
152 : }
153 : }
154 : }
155 : }
|