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;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |