You've already forked linux-packaging-mono
							
							
		
			
	
	
		
			386 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
		
		
			
		
	
	
			386 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
|   | //---------------------------------------------------------------- | ||
|  | // Copyright (c) Microsoft Corporation.  All rights reserved. | ||
|  | //---------------------------------------------------------------- | ||
|  | 
 | ||
|  | namespace System.Activities.Statements | ||
|  | { | ||
|  |     using System.Activities; | ||
|  |     using System.Activities.Tracking; | ||
|  |     using System.Collections.Generic; | ||
|  |     using System.Collections.ObjectModel; | ||
|  |     using System.Diagnostics; | ||
|  |     using System.Reflection; | ||
|  |     using System.Runtime.Serialization; | ||
|  |     using System.Transactions; | ||
|  |     using System.Workflow.Runtime; | ||
|  |     using System.Workflow.Runtime.Tracking; | ||
|  |     using System.Runtime; | ||
|  |     using System.Globalization; | ||
|  | 
 | ||
|  |     class InteropEnvironment : IDisposable, IServiceProvider | ||
|  |     { | ||
|  |         static readonly ReadOnlyCollection<IComparable> emptyList = new ReadOnlyCollection<IComparable>(new IComparable[] { }); | ||
|  | 
 | ||
|  |         static MethodInfo getServiceMethod = typeof(NativeActivityContext).GetMethod("GetExtension"); | ||
|  | 
 | ||
|  |         NativeActivityContext nativeActivityContext; | ||
|  | 
 | ||
|  |         BookmarkCallback bookmarkCallback; | ||
|  | 
 | ||
|  |         bool disposed; | ||
|  |         bool completed; | ||
|  |         bool canceled; | ||
|  | 
 | ||
|  |         InteropExecutor executor; | ||
|  |         IEnumerable<IComparable> initialBookmarks; | ||
|  |         Exception uncaughtException; | ||
|  |         Transaction transaction; | ||
|  | 
 | ||
|  |         public InteropEnvironment(InteropExecutor interopExecutor, NativeActivityContext nativeActivityContext, | ||
|  |             BookmarkCallback bookmarkCallback, Interop activity, Transaction transaction) | ||
|  |         { | ||
|  |             //setup environment; | ||
|  |             this.executor = interopExecutor; | ||
|  |             this.nativeActivityContext = nativeActivityContext; | ||
|  |             this.Activity = activity; | ||
|  |             this.executor.ServiceProvider = this; | ||
|  |             this.bookmarkCallback = bookmarkCallback; | ||
|  |             this.transaction = transaction; | ||
|  |             OnEnter(); | ||
|  |         } | ||
|  | 
 | ||
|  |         public Interop Activity { get; set; } | ||
|  | 
 | ||
|  |         void IDisposable.Dispose() | ||
|  |         { | ||
|  |             if (!this.disposed) | ||
|  |             { | ||
|  |                 OnExit(); | ||
|  |                 this.disposed = true; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Execute(System.Workflow.ComponentModel.Activity definition, NativeActivityContext context) | ||
|  |         { | ||
|  |             Debug.Assert(!disposed, "Cannot access disposed object"); | ||
|  |             try | ||
|  |             { | ||
|  |                 this.executor.Initialize(definition, this.Activity.GetInputArgumentValues(context), this.Activity.HasNameCollision); | ||
|  |                 ProcessExecutionStatus(this.executor.Execute()); | ||
|  |             } | ||
|  |             catch (Exception e) | ||
|  |             { | ||
|  |                 this.uncaughtException = e; | ||
|  |                 throw; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Cancel() | ||
|  |         { | ||
|  |             Debug.Assert(!disposed, "Cannot access disposed object"); | ||
|  |             try | ||
|  |             { | ||
|  |                 ProcessExecutionStatus(this.executor.Cancel()); | ||
|  |                 this.canceled = true; | ||
|  |             } | ||
|  |             catch (Exception e) | ||
|  |             { | ||
|  |                 this.uncaughtException = e; | ||
|  |                 throw; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public void EnqueueEvent(IComparable queueName, object item) | ||
|  |         { | ||
|  |             Debug.Assert(!disposed, "Cannot access disposed object"); | ||
|  |             try | ||
|  |             { | ||
|  |                 ProcessExecutionStatus(this.executor.EnqueueEvent(queueName, item)); | ||
|  |             } | ||
|  |             catch (Exception e) | ||
|  |             { | ||
|  |                 this.uncaughtException = e; | ||
|  |                 throw; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         public void TrackActivityStatusChange(System.Workflow.ComponentModel.Activity activity, int eventCounter) | ||
|  |         { | ||
|  |             this.nativeActivityContext.Track( | ||
|  |                 new InteropTrackingRecord(this.Activity.DisplayName, | ||
|  |                     new ActivityTrackingRecord( | ||
|  |                         activity.GetType(), | ||
|  |                         activity.QualifiedName, | ||
|  |                         activity.ContextGuid, | ||
|  |                         activity.Parent == null ? Guid.Empty : activity.Parent.ContextGuid, | ||
|  |                         activity.ExecutionStatus, | ||
|  |                         DateTime.UtcNow, | ||
|  |                         eventCounter, | ||
|  |                         null | ||
|  |                     ) | ||
|  |                 ) | ||
|  |             ); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void TrackData(System.Workflow.ComponentModel.Activity activity, int eventCounter, string key, object data) | ||
|  |         { | ||
|  |             this.nativeActivityContext.Track( | ||
|  |                 new InteropTrackingRecord(this.Activity.DisplayName, | ||
|  |                     new UserTrackingRecord( | ||
|  |                         activity.GetType(), | ||
|  |                         activity.QualifiedName, | ||
|  |                         activity.ContextGuid, | ||
|  |                         activity.Parent == null ? Guid.Empty : activity.Parent.ContextGuid, | ||
|  |                         DateTime.UtcNow, | ||
|  |                         eventCounter, | ||
|  |                         key, | ||
|  |                         data | ||
|  |                     ) | ||
|  |                 ) | ||
|  |             ); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Resume() | ||
|  |         { | ||
|  |             Debug.Assert(!disposed, "Cannot access disposed object"); | ||
|  |             try | ||
|  |             { | ||
|  |                 ProcessExecutionStatus(this.executor.Resume()); | ||
|  |             } | ||
|  |             catch (Exception e) | ||
|  |             { | ||
|  |                 this.uncaughtException = e; | ||
|  |                 throw; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         // | ||
|  |         object IServiceProvider.GetService(Type serviceType) | ||
|  |         { | ||
|  |             Debug.Assert(!disposed, "Cannot access disposed object"); | ||
|  |             MethodInfo genericMethodInfo = getServiceMethod.MakeGenericMethod(serviceType); | ||
|  |             return genericMethodInfo.Invoke(this.nativeActivityContext, null); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void Persist() | ||
|  |         { | ||
|  |             this.Activity.Persist(this.nativeActivityContext); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void CreateTransaction(TransactionOptions transactionOptions) | ||
|  |         { | ||
|  |             this.Activity.CreateTransaction(this.nativeActivityContext, transactionOptions); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void CommitTransaction() | ||
|  |         { | ||
|  |             this.Activity.CommitTransaction(this.nativeActivityContext); | ||
|  |         } | ||
|  | 
 | ||
|  |         public void AddResourceManager(VolatileResourceManager resourceManager) | ||
|  |         { | ||
|  |             this.Activity.AddResourceManager(this.nativeActivityContext, resourceManager); | ||
|  |         } | ||
|  | 
 | ||
|  |         //Called everytime on enter of interopenvironment. | ||
|  |         void OnEnter() | ||
|  |         { | ||
|  |             //Capture Current state of Queues in InteropEnvironment. | ||
|  |             this.initialBookmarks = this.executor.Queues; | ||
|  | 
 | ||
|  |             // This method sets up the ambient transaction for the current thread. | ||
|  |             // Since the runtime can execute us on different threads,  | ||
|  |             // we have to set up the transaction scope everytime we enter the interop environment and clear it when we leave the environment. | ||
|  |             this.executor.SetAmbientTransactionAndServiceEnvironment(this.transaction); | ||
|  |         } | ||
|  | 
 | ||
|  |         //Called everytime we leave InteropEnvironment. | ||
|  |         void OnExit() | ||
|  |         { | ||
|  |             if (this.uncaughtException != null) | ||
|  |             { | ||
|  |                 if (WorkflowExecutor.IsIrrecoverableException(this.uncaughtException)) | ||
|  |                 { | ||
|  |                     return; | ||
|  |                 } | ||
|  |             } | ||
|  | 
 | ||
|  |             // This method clears the ambient transaction for the current thread. | ||
|  |             // Since the runtime can execute us on different threads,  | ||
|  |             // we have to set up the transaction scope everytime we enter the interop environment and clear it when we leave the environment. | ||
|  |             this.executor.ClearAmbientTransactionAndServiceEnvironment(); | ||
|  | 
 | ||
|  |             //Capture Current state of Queues in InteropEnvironment. | ||
|  |             IEnumerable<IComparable> currentBookmarks = this.executor.Queues; | ||
|  | 
 | ||
|  |             //Set outparameters when completed or faulted. | ||
|  |             if (this.completed || this.uncaughtException != null) | ||
|  |             { | ||
|  |                 this.Activity.OnClose(this.nativeActivityContext, this.uncaughtException); | ||
|  | 
 | ||
|  |                 this.Activity.SetOutputArgumentValues( | ||
|  |                     this.executor.Outputs, this.nativeActivityContext); | ||
|  | 
 | ||
|  |                 this.nativeActivityContext.RemoveAllBookmarks(); | ||
|  |                 this.executor.BookmarkQueueMap.Clear(); | ||
|  | 
 | ||
|  |                 if (this.canceled) | ||
|  |                 { | ||
|  |                     this.nativeActivityContext.MarkCanceled(); | ||
|  |                 } | ||
|  |             } | ||
|  |             else | ||
|  |             { | ||
|  |                 //Find Differentials | ||
|  |                 IList<IComparable> deletedBookmarks = new List<IComparable>(); | ||
|  |                 foreach (IComparable value in this.initialBookmarks) | ||
|  |                 { | ||
|  |                     deletedBookmarks.Add(value); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 IList<IComparable> newBookmarks = null; | ||
|  |                 foreach (IComparable value in currentBookmarks) | ||
|  |                 { | ||
|  |                     if (!deletedBookmarks.Remove(value)) | ||
|  |                     { | ||
|  |                         if (newBookmarks == null) | ||
|  |                         { | ||
|  |                             newBookmarks = new List<IComparable>(); | ||
|  |                         } | ||
|  |                         newBookmarks.Add(value); | ||
|  |                     } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (newBookmarks != null) | ||
|  |                 { | ||
|  |                     // Create new Queues as Bookmark. | ||
|  |                     foreach (IComparable bookmark in newBookmarks) | ||
|  |                     { | ||
|  |                         // | ||
|  |                         Bookmark v2Bookmark = this.nativeActivityContext.CreateBookmark(bookmark.ToString(), | ||
|  |                             this.bookmarkCallback, BookmarkOptions.MultipleResume); | ||
|  |                         this.executor.BookmarkQueueMap.Add(v2Bookmark, bookmark); | ||
|  |                     } | ||
|  |                 } | ||
|  | 
 | ||
|  |                 // Delete removed queues.     | ||
|  |                 foreach (IComparable bookmark in deletedBookmarks) | ||
|  |                 { | ||
|  |                     this.nativeActivityContext.RemoveBookmark(bookmark.ToString()); | ||
|  |                     List<Bookmark> bookmarksToRemove = new List<Bookmark>(); | ||
|  |                     foreach (KeyValuePair<Bookmark, IComparable> entry in this.executor.BookmarkQueueMap) | ||
|  |                     { | ||
|  |                         if (entry.Value == bookmark) | ||
|  |                         { | ||
|  |                             bookmarksToRemove.Add(entry.Key); | ||
|  |                         } | ||
|  |                     } | ||
|  | 
 | ||
|  |                     foreach (Bookmark bookmarkToRemove in bookmarksToRemove) | ||
|  |                     { | ||
|  |                         this.executor.BookmarkQueueMap.Remove(bookmarkToRemove); | ||
|  |                     } | ||
|  |                 } | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         void ProcessExecutionStatus(System.Workflow.ComponentModel.ActivityExecutionStatus executionStatus) | ||
|  |         { | ||
|  |             this.completed = (executionStatus == System.Workflow.ComponentModel.ActivityExecutionStatus.Closed); | ||
|  |         } | ||
|  | 
 | ||
|  |         public static class ParameterHelper | ||
|  |         { | ||
|  |             static readonly Type activityType = typeof(System.Workflow.ComponentModel.Activity); | ||
|  |             static readonly Type compositeActivityType = typeof(System.Workflow.ComponentModel.CompositeActivity); | ||
|  |             static readonly Type dependencyObjectType = typeof(System.Workflow.ComponentModel.DependencyObject); | ||
|  |             static readonly Type activityConditionType = typeof(System.Workflow.ComponentModel.ActivityCondition); | ||
|  |             // Interop Property Names | ||
|  |             internal const string interopPropertyActivityType = "ActivityType"; | ||
|  |             internal const string interopPropertyActivityProperties = "ActivityProperties"; | ||
|  |             internal const string interopPropertyActivityMetaProperties = "ActivityMetaProperties"; | ||
|  |             // Allowed Meta-Properties | ||
|  |             internal const string activityNameMetaProperty = "Name"; | ||
|  | 
 | ||
|  | 
 | ||
|  |             //Check property names for any Property/PropertyOut pairs that would conflict with our naming scheme  | ||
|  |             public static bool HasPropertyNameCollision(IList<PropertyInfo> properties) | ||
|  |             { | ||
|  |                 bool hasNameCollision = false; | ||
|  |                 HashSet<string> propertyNames = new HashSet<string>(); | ||
|  |                 foreach (PropertyInfo propertyInfo in properties) | ||
|  |                 { | ||
|  |                     propertyNames.Add(propertyInfo.Name); | ||
|  |                 } | ||
|  | 
 | ||
|  |                 if (propertyNames.Contains(interopPropertyActivityType) || | ||
|  |                     propertyNames.Contains(interopPropertyActivityProperties) || | ||
|  |                     propertyNames.Contains(interopPropertyActivityMetaProperties)) | ||
|  |                 { | ||
|  |                     hasNameCollision = true; | ||
|  |                 } | ||
|  |                 else | ||
|  |                 { | ||
|  |                     foreach (PropertyInfo propertyInfo in properties) | ||
|  |                     { | ||
|  |                         if (propertyNames.Contains(propertyInfo.Name + Interop.OutArgumentSuffix)) | ||
|  |                         { | ||
|  |                             hasNameCollision = true; | ||
|  |                             break; | ||
|  |                         } | ||
|  |                     } | ||
|  |                 } | ||
|  |                 return hasNameCollision; | ||
|  |             } | ||
|  | 
 | ||
|  |             public static bool IsBindable(PropertyInfo propertyInfo) | ||
|  |             { | ||
|  |                 bool isMetaProperty; | ||
|  |                 if (!IsBindableOrMetaProperty(propertyInfo, out isMetaProperty)) | ||
|  |                 { | ||
|  |                     return false; | ||
|  |                 } | ||
|  |                 return !isMetaProperty; | ||
|  |             } | ||
|  | 
 | ||
|  |             public static bool IsBindableOrMetaProperty(PropertyInfo propertyInfo, out bool isMetaProperty) | ||
|  |             { | ||
|  |                 isMetaProperty = false; | ||
|  | 
 | ||
|  |                 // Validate the declaring type: CompositeActivity and DependencyObject | ||
|  |                 if (propertyInfo.DeclaringType.Equals(compositeActivityType) || | ||
|  |                     propertyInfo.DeclaringType.Equals(dependencyObjectType)) | ||
|  |                 { | ||
|  |                     return false; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 // Validate the declaring type: Activity | ||
|  |                 // We allow certain meta-properties on System.Workflow.ComponentModel.Activity to be visible | ||
|  |                 if (propertyInfo.DeclaringType.Equals(activityType) && | ||
|  |                     !String.Equals(propertyInfo.Name, activityNameMetaProperty, StringComparison.Ordinal)) | ||
|  |                 { | ||
|  |                     return false; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 //Validate the data type | ||
|  |                 if (activityConditionType.IsAssignableFrom(propertyInfo.PropertyType)) | ||
|  |                 { | ||
|  |                     return false; | ||
|  |                 } | ||
|  | 
 | ||
|  |                 //Validate whether there is DP(Meta) backup | ||
|  |                 string dependencyPropertyName = propertyInfo.Name; | ||
|  | 
 | ||
|  |                 System.Workflow.ComponentModel.DependencyProperty dependencyProperty = System.Workflow.ComponentModel.DependencyProperty.FromName(dependencyPropertyName, | ||
|  |                     propertyInfo.DeclaringType); | ||
|  | 
 | ||
|  |                 if (dependencyProperty != null && dependencyProperty.DefaultMetadata.IsMetaProperty) | ||
|  |                 { | ||
|  |                     isMetaProperty = true; | ||
|  |                 } | ||
|  |                 return true; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |