1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 
5 namespace System.Activities.DurableInstancing
6 {
7     using System.Collections.Generic;
8     using System.Data;
9     using System.Data.SqlClient;
10     using System.Globalization;
11     using System.Linq;
12     using System.Runtime.DurableInstancing;
13     using System.Transactions;
14     using System.Xml.Linq;
15 
16     class LoadWorkflowAsyncResult : SqlWorkflowInstanceStoreAsyncResult
17     {
18         static readonly string commandText = string.Format(CultureInfo.InvariantCulture, "{0}.[LoadInstance]", SqlWorkflowInstanceStoreConstants.DefaultSchema);
19         Dictionary<Guid, IDictionary<XName, InstanceValue>> associatedInstanceKeys;
20         Dictionary<Guid, IDictionary<XName, InstanceValue>> completedInstanceKeys;
21 
22         Dictionary<XName, InstanceValue> instanceData;
23         Dictionary<XName, InstanceValue> instanceMetadata;
24         IObjectSerializer objectSerializer;
25 
LoadWorkflowAsyncResult( InstancePersistenceContext context, InstancePersistenceCommand command, SqlWorkflowInstanceStore store, SqlWorkflowInstanceStoreLock storeLock, Transaction currentTransaction, TimeSpan timeout, AsyncCallback callback, object state )26         public LoadWorkflowAsyncResult
27             (
28             InstancePersistenceContext context,
29             InstancePersistenceCommand command,
30             SqlWorkflowInstanceStore store,
31             SqlWorkflowInstanceStoreLock storeLock,
32             Transaction currentTransaction,
33             TimeSpan timeout,
34             AsyncCallback callback,
35             object state
36             ) :
37             base(context, command, store, storeLock, currentTransaction, timeout, callback, state)
38         {
39             this.associatedInstanceKeys = new Dictionary<Guid, IDictionary<XName, InstanceValue>>();
40             this.completedInstanceKeys = new Dictionary<Guid, IDictionary<XName, InstanceValue>>();
41             this.objectSerializer = ObjectSerializerFactory.GetDefaultObjectSerializer();
42         }
43 
GenerateLoadSqlCommand( SqlCommand command, LoadType loadType, Guid keyToLoadBy, Guid instanceId, List<CorrelationKey> keysToAssociate )44         protected void GenerateLoadSqlCommand
45             (
46             SqlCommand command,
47             LoadType loadType,
48             Guid keyToLoadBy,
49             Guid instanceId,
50             List<CorrelationKey> keysToAssociate
51             )
52         {
53             long surrogateLockOwnerId = base.StoreLock.SurrogateLockOwnerId;
54             byte[] concatenatedKeyProperties = null;
55             bool singleKeyToAssociate = (keysToAssociate != null && keysToAssociate.Count == 1);
56 
57             if (keysToAssociate != null)
58             {
59                 concatenatedKeyProperties = SerializationUtilities.CreateKeyBinaryBlob(keysToAssociate);
60             }
61 
62             double operationTimeout = this.TimeoutHelper.RemainingTime().TotalMilliseconds;
63 
64             SqlParameterCollection parameters = command.Parameters;
65             parameters.Add(new SqlParameter { ParameterName = "@surrogateLockOwnerId", SqlDbType = SqlDbType.BigInt, Value = surrogateLockOwnerId });
66             parameters.Add(new SqlParameter { ParameterName = "@operationType", SqlDbType = SqlDbType.TinyInt, Value = loadType });
67             parameters.Add(new SqlParameter { ParameterName = "@keyToLoadBy", SqlDbType = SqlDbType.UniqueIdentifier, Value = keyToLoadBy });
68             parameters.Add(new SqlParameter { ParameterName = "@instanceId", SqlDbType = SqlDbType.UniqueIdentifier, Value = instanceId });
69             parameters.Add(new SqlParameter { ParameterName = "@handleInstanceVersion", SqlDbType = SqlDbType.BigInt, Value = base.InstancePersistenceContext.InstanceVersion });
70             parameters.Add(new SqlParameter { ParameterName = "@handleIsBoundToLock", SqlDbType = SqlDbType.Bit, Value = base.InstancePersistenceContext.InstanceView.IsBoundToLock });
71             parameters.Add(new SqlParameter { ParameterName = "@keysToAssociate", SqlDbType = SqlDbType.Xml, Value = singleKeyToAssociate ? DBNull.Value : SerializationUtilities.CreateCorrelationKeyXmlBlob(keysToAssociate) });
72             parameters.Add(new SqlParameter { ParameterName = "@encodingOption", SqlDbType = SqlDbType.TinyInt, Value = base.Store.InstanceEncodingOption });
73             parameters.Add(new SqlParameter { ParameterName = "@concatenatedKeyProperties", SqlDbType = SqlDbType.VarBinary, Value = (object) concatenatedKeyProperties ?? DBNull.Value });
74             parameters.Add(new SqlParameter { ParameterName = "@operationTimeout", SqlDbType = SqlDbType.Int, Value = (operationTimeout < Int32.MaxValue) ? Convert.ToInt32(operationTimeout) : Int32.MaxValue });
75             parameters.Add(new SqlParameter { ParameterName = "@singleKeyId", SqlDbType = SqlDbType.UniqueIdentifier, Value = singleKeyToAssociate ? keysToAssociate[0].KeyId : (object) DBNull.Value });
76         }
77 
GenerateSqlCommand(SqlCommand command)78         protected override void GenerateSqlCommand(SqlCommand command)
79         {
80             LoadWorkflowCommand loadWorkflowCommand = base.InstancePersistenceCommand as LoadWorkflowCommand;
81             LoadType loadType = loadWorkflowCommand.AcceptUninitializedInstance ? LoadType.LoadOrCreateByInstance : LoadType.LoadByInstance;
82             Guid instanceId = base.InstancePersistenceContext.InstanceView.InstanceId;
83 
84             GenerateLoadSqlCommand(command, loadType, Guid.Empty, instanceId, null);
85         }
86 
GetSqlCommandText()87         protected override string GetSqlCommandText()
88         {
89             return LoadWorkflowAsyncResult.commandText;
90         }
91 
GetSqlCommandType()92         protected override CommandType GetSqlCommandType()
93         {
94             return CommandType.StoredProcedure;
95         }
96 
ProcessSqlResult(SqlDataReader reader)97         protected override Exception ProcessSqlResult(SqlDataReader reader)
98         {
99             Exception exception = StoreUtilities.GetNextResultSet(base.InstancePersistenceCommand.Name, reader);
100 
101             if (exception == null)
102             {
103                 Guid instanceId = reader.GetGuid(1);
104                 long surrogateInstanceId = reader.GetInt64(2);
105                 byte[] primitiveProperties = reader.IsDBNull(3) ? null : (byte[])(reader.GetValue(3));
106                 byte[] complexProperties = reader.IsDBNull(4) ? null : (byte[])(reader.GetValue(4));
107                 byte[] metadataProperties = reader.IsDBNull(5) ? null : (byte[])(reader.GetValue(5));
108                 InstanceEncodingOption dataEncodingOption = (InstanceEncodingOption)(reader.GetByte(6));
109                 InstanceEncodingOption metadataEncodingOption = (InstanceEncodingOption)(reader.GetByte(7));
110                 long version = reader.GetInt64(8);
111                 bool isInitialized = reader.GetBoolean(9);
112                 bool createdInstance = reader.GetBoolean(10);
113 
114                 LoadWorkflowCommand loadWorkflowCommand = base.InstancePersistenceCommand as LoadWorkflowCommand;
115                 LoadWorkflowByInstanceKeyCommand loadByKeycommand = base.InstancePersistenceCommand as LoadWorkflowByInstanceKeyCommand;
116 
117                 if (!base.InstancePersistenceContext.InstanceView.IsBoundToInstance)
118                 {
119                     base.InstancePersistenceContext.BindInstance(instanceId);
120                 }
121                 if (!base.InstancePersistenceContext.InstanceView.IsBoundToInstanceOwner)
122                 {
123                     base.InstancePersistenceContext.BindInstanceOwner(base.StoreLock.LockOwnerId, base.StoreLock.LockOwnerId);
124                 }
125                 if (!base.InstancePersistenceContext.InstanceView.IsBoundToLock)
126                 {
127                     InstanceLockTracking instanceLockTracking = (InstanceLockTracking)(base.InstancePersistenceContext.UserContext);
128                     instanceLockTracking.TrackStoreLock(instanceId, version, this.DependentTransaction);
129                     base.InstancePersistenceContext.BindAcquiredLock(version);
130                 }
131 
132                 this.instanceData = SerializationUtilities.DeserializePropertyBag(primitiveProperties, complexProperties, dataEncodingOption);
133                 this.instanceMetadata = SerializationUtilities.DeserializeMetadataPropertyBag(metadataProperties, metadataEncodingOption);
134 
135                 if (!createdInstance)
136                 {
137                     ReadInstanceMetadataChanges(reader, this.instanceMetadata);
138                     ReadKeyData(reader, this.associatedInstanceKeys, this.completedInstanceKeys);
139                 }
140                 else if (loadByKeycommand != null)
141                 {
142                     foreach (KeyValuePair<Guid, IDictionary<XName, InstanceValue>> keyEntry in loadByKeycommand.InstanceKeysToAssociate)
143                     {
144                         this.associatedInstanceKeys.Add(keyEntry.Key, keyEntry.Value);
145                     }
146 
147                     if (!this.associatedInstanceKeys.ContainsKey(loadByKeycommand.LookupInstanceKey))
148                     {
149                         base.InstancePersistenceContext.AssociatedInstanceKey(loadByKeycommand.LookupInstanceKey);
150                         this.associatedInstanceKeys.Add(loadByKeycommand.LookupInstanceKey, new Dictionary<XName, InstanceValue>());
151                     }
152                 }
153 
154                 if (loadByKeycommand != null)
155                 {
156                     foreach (KeyValuePair<Guid, IDictionary<XName, InstanceValue>> keyEntry in loadByKeycommand.InstanceKeysToAssociate)
157                     {
158                         base.InstancePersistenceContext.AssociatedInstanceKey(keyEntry.Key);
159 
160                         if (keyEntry.Value != null)
161                         {
162                             foreach (KeyValuePair<XName, InstanceValue> property in keyEntry.Value)
163                             {
164                                 base.InstancePersistenceContext.WroteInstanceKeyMetadataValue(keyEntry.Key, property.Key, property.Value);
165                             }
166                         }
167                     }
168                 }
169 
170                 base.InstancePersistenceContext.LoadedInstance
171                     (
172                     isInitialized ? InstanceState.Initialized : InstanceState.Uninitialized,
173                     this.instanceData,
174                     this.instanceMetadata,
175                     this.associatedInstanceKeys,
176                     this.completedInstanceKeys
177                     );
178             }
179             else if (exception is InstanceLockLostException)
180             {
181                 base.InstancePersistenceContext.InstanceHandle.Free();
182             }
183 
184             return exception;
185         }
186 
ReadInstanceMetadataChanges(SqlDataReader reader, Dictionary<XName, InstanceValue> instanceMetadata)187         void ReadInstanceMetadataChanges(SqlDataReader reader, Dictionary<XName, InstanceValue> instanceMetadata)
188         {
189             Exception exception = StoreUtilities.GetNextResultSet(base.InstancePersistenceCommand.Name, reader);
190 
191             if (exception == null)
192             {
193                 if (reader.IsDBNull(1))
194                 {
195                     return;
196                 }
197             }
198 
199             do
200             {
201                 InstanceEncodingOption encodingOption = (InstanceEncodingOption) reader.GetByte(1);
202                 byte[] serializedMetadataChanges = (byte[]) reader.GetValue(2);
203 
204                 Dictionary<XName, InstanceValue> metadataChangeSet = SerializationUtilities.DeserializeMetadataPropertyBag(serializedMetadataChanges, encodingOption);
205 
206                 foreach (KeyValuePair<XName, InstanceValue> metadataChange in metadataChangeSet)
207                 {
208                     XName xname = metadataChange.Key;
209                     InstanceValue propertyValue = metadataChange.Value;
210 
211                     if (propertyValue.Value is DeletedMetadataValue)
212                     {
213                         instanceMetadata.Remove(xname);
214                     }
215                     else
216                     {
217                         instanceMetadata[xname] = propertyValue;
218                     }
219                 }
220             }
221             while (reader.Read());
222         }
223 
ReadKeyData(SqlDataReader reader, Dictionary<Guid, IDictionary<XName, InstanceValue>> associatedInstanceKeys, Dictionary<Guid, IDictionary<XName, InstanceValue>> completedInstanceKeys)224         void ReadKeyData(SqlDataReader reader, Dictionary<Guid, IDictionary<XName, InstanceValue>> associatedInstanceKeys,
225             Dictionary<Guid, IDictionary<XName, InstanceValue>> completedInstanceKeys)
226         {
227             Exception exception = StoreUtilities.GetNextResultSet(base.InstancePersistenceCommand.Name, reader);
228 
229             if (exception == null)
230             {
231                 if (reader.IsDBNull(1))
232                 {
233                     return;
234                 }
235 
236                 do
237                 {
238                     Guid key = reader.GetGuid(1);
239                     bool isAssociated = reader.GetBoolean(2);
240                     InstanceEncodingOption encodingOption = (InstanceEncodingOption) reader.GetByte(3);
241                     Dictionary<Guid, IDictionary<XName, InstanceValue>> destination = isAssociated ? associatedInstanceKeys : completedInstanceKeys;
242 
243                     if (!reader.IsDBNull(4))
244                     {
245                         destination[key] = SerializationUtilities.DeserializeKeyMetadata((byte[]) reader.GetValue(4), encodingOption);
246                     }
247                     else
248                     {
249                         destination[key] = new Dictionary<XName, InstanceValue>();
250                     }
251 
252                 }
253                 while (reader.Read());
254             }
255         }
256     }
257 }
258