Bump corefx
[mono-project.git] / mcs / class / referencesource / System.Workflow.Runtime / WorkflowStateRollbackService.cs
blobe3a39d23419c54a6148410de8c8a43cac8feaff7
1 using System;
2 using System.Collections.Generic;
3 using System.Collections;
4 using System.Diagnostics;
5 using System.Reflection;
6 using System.Text;
7 using System.IO;
8 using System.IO.Compression;
9 using System.Transactions;
10 using System.Workflow.ComponentModel;
12 namespace System.Workflow.Runtime
14 internal sealed class WorkflowStateRollbackService
16 WorkflowExecutor workflowExecutor;
18 // cache the revert back data
19 MemoryStream clonedInstanceStateStream;
20 Activity workflowDefinition = null;
21 bool isInstanceStateRevertRequested = false;
23 // revert back notification info
24 string activityQualifiedName;
25 int activityContextId;
26 EventArgs callbackData;
27 EventHandler<EventArgs> callbackHandler;
28 bool suspendOnRevert;
29 string suspendOnRevertInfo;
31 Hashtable completedContextActivities = new Hashtable();
33 public WorkflowStateRollbackService(WorkflowExecutor workflowExecutor)
35 this.workflowExecutor = workflowExecutor;
38 internal bool IsInstanceStateRevertRequested
40 get { return this.isInstanceStateRevertRequested; }
43 internal void CheckpointInstanceState()
45 Debug.Assert(this.workflowExecutor.InstanceId != null, "instance id null at checkpoint time");
47 // serialize the instance state
48 this.clonedInstanceStateStream = new MemoryStream(10240);
49 this.workflowExecutor.RootActivity.Save(this.clonedInstanceStateStream);
50 this.workflowDefinition = this.workflowExecutor.WorkflowDefinition;
51 this.completedContextActivities = (Hashtable)this.workflowExecutor.CompletedContextActivities.Clone();
52 this.clonedInstanceStateStream.Position = 0;
55 internal void RequestRevertToCheckpointState(Activity currentActivity, EventHandler<EventArgs> callbackHandler, EventArgs callbackData, bool suspendOnRevert, string suspendInfo)
57 if (this.clonedInstanceStateStream == null)
58 throw new InvalidOperationException(ExecutionStringManager.InvalidRevertRequest);
60 // cache the after revert information
61 this.activityContextId = ContextActivityUtils.ContextId(ContextActivityUtils.ContextActivity(currentActivity));
62 this.activityQualifiedName = currentActivity.QualifiedName;
63 this.callbackData = callbackData;
64 this.callbackHandler = callbackHandler;
65 this.suspendOnRevert = suspendOnRevert;
66 this.suspendOnRevertInfo = suspendInfo;
68 // ask scheduler to stop
69 this.isInstanceStateRevertRequested = true;
70 this.workflowExecutor.Scheduler.CanRun = false;
73 internal void DisposeCheckpointState()
75 this.clonedInstanceStateStream = null;
78 internal void RevertToCheckpointState()
80 Debug.Assert(this.clonedInstanceStateStream != null, "cloned instance-state stream null at restore time");
82 // deserialize only on first access
83 Activity clonedRootActivity = null;
84 this.clonedInstanceStateStream.Position = 0;
85 using (RuntimeEnvironment runtimeEnv = new RuntimeEnvironment(this.workflowExecutor.WorkflowRuntime))
87 clonedRootActivity = Activity.Load(this.clonedInstanceStateStream, (Activity)this.workflowDefinition);
89 Debug.Assert(clonedRootActivity != null);
91 // Set the trackingListenerBroker before initializing the executor so the tracking
92 // runtime gets a reference to the correct object
93 clonedRootActivity.SetValue(WorkflowExecutor.TrackingListenerBrokerProperty, workflowExecutor.RootActivity.GetValue(WorkflowExecutor.TrackingListenerBrokerProperty));
95 // create the new workflowExecutor
96 WorkflowExecutor newWorkflowExecutor = new WorkflowExecutor(Guid.Empty); // use a dummy guid while swapping executors
97 newWorkflowExecutor.Initialize(clonedRootActivity, this.workflowExecutor.WorkflowRuntime, this.workflowExecutor);
99 // enqueue the activity notifier
100 Activity activityContext = newWorkflowExecutor.GetContextActivityForId(this.activityContextId);
101 Activity activity = activityContext.GetActivityByName(this.activityQualifiedName);
102 using (new ServiceEnvironment(activity))
104 using (newWorkflowExecutor.SetCurrentActivity(activity))
106 using (ActivityExecutionContext executionContext = new ActivityExecutionContext(activity))
107 executionContext.Invoke<EventArgs>(this.callbackHandler, this.callbackData);
111 // Push the batch item ordering id to the new instance
112 newWorkflowExecutor.BatchCollection.WorkItemOrderId = this.workflowExecutor.BatchCollection.WorkItemOrderId;
113 // replace pending batch items
114 foreach (KeyValuePair<object, WorkBatch> batch in this.workflowExecutor.BatchCollection)
116 batch.Value.SetWorkBatchCollection(newWorkflowExecutor.BatchCollection);
117 Activity oldActivity = batch.Key as Activity;
118 // no need to add the transient state batch
119 if (oldActivity != null)
121 Activity newactivity = activityContext.GetActivityByName(oldActivity.QualifiedName);
122 newWorkflowExecutor.BatchCollection.Add(newactivity, batch.Value);
125 this.workflowExecutor.BatchCollection.Clear();
127 Debug.Assert(this.completedContextActivities != null);
128 newWorkflowExecutor.CompletedContextActivities = this.completedContextActivities;
130 // replace with the WorkflowRuntime
131 Debug.Assert(this.workflowExecutor.IsInstanceValid);
132 this.workflowExecutor.WorkflowRuntime.ReplaceWorkflowExecutor(this.workflowExecutor.InstanceId, this.workflowExecutor, newWorkflowExecutor);
134 // now resume or suspend the scheduler as needed
135 if (!this.suspendOnRevert)
137 // get the new one going
138 newWorkflowExecutor.Scheduler.Resume();
140 else
142 // this call will be old scheduler's thread
143 newWorkflowExecutor.SuspendOnIdle(this.suspendOnRevertInfo);
145 DisposeCheckpointState();