e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
364 lines
13 KiB
C#
364 lines
13 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.Activities
|
|
{
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Runtime.Serialization;
|
|
using System.Activities.Runtime;
|
|
using System.Runtime;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
|
|
[DataContract]
|
|
public class ExclusiveHandle : Handle
|
|
{
|
|
ReadOnlyCollection<BookmarkScopeHandle> readOnlyBookmarkScopeCollection;
|
|
|
|
List<BookmarkScopeHandle> bookmarkScopes;
|
|
|
|
ActivityInstance owningInstance;
|
|
|
|
ActivityExecutor executor;
|
|
|
|
ExclusiveHandleBookmarkList importantBookmarks;
|
|
|
|
ExclusiveHandleBookmarkList unimportantBookmarks;
|
|
|
|
bool bookmarkScopesListIsDefault;
|
|
|
|
public ExclusiveHandle()
|
|
{
|
|
this.CanBeRemovedWithExecutingChildren = true;
|
|
}
|
|
|
|
public ReadOnlyCollection<BookmarkScopeHandle> RegisteredBookmarkScopes
|
|
{
|
|
get
|
|
{
|
|
if (this.bookmarkScopes == null)
|
|
{
|
|
return new ReadOnlyCollection<BookmarkScopeHandle>(new List<BookmarkScopeHandle>());
|
|
}
|
|
|
|
if (this.readOnlyBookmarkScopeCollection == null)
|
|
{
|
|
this.readOnlyBookmarkScopeCollection = new ReadOnlyCollection<BookmarkScopeHandle>(this.bookmarkScopes);
|
|
}
|
|
return this.readOnlyBookmarkScopeCollection;
|
|
}
|
|
}
|
|
|
|
[DataMember(EmitDefaultValue = false, Name = "bookmarkScopes")]
|
|
internal List<BookmarkScopeHandle> SerializedBookmarkScopes
|
|
{
|
|
get { return this.bookmarkScopes; }
|
|
set { this.bookmarkScopes = value; }
|
|
}
|
|
|
|
[DataMember(Name = "owningInstance")]
|
|
internal ActivityInstance SerializedOwningInstance
|
|
{
|
|
get { return this.owningInstance; }
|
|
set { this.owningInstance = value; }
|
|
}
|
|
|
|
[DataMember(EmitDefaultValue = false, Name = "executor")]
|
|
internal ActivityExecutor SerializedExecutor
|
|
{
|
|
get { return this.executor; }
|
|
set { this.executor = value; }
|
|
}
|
|
|
|
[DataMember(EmitDefaultValue = false, Name = "importantBookmarks")]
|
|
internal ExclusiveHandleBookmarkList SerializedImportantBookmarks
|
|
{
|
|
get { return this.importantBookmarks; }
|
|
set { this.importantBookmarks = value; }
|
|
}
|
|
|
|
[DataMember(EmitDefaultValue = false, Name = "unimportantBookmarks")]
|
|
internal ExclusiveHandleBookmarkList SerializedUnimportantBookmarks
|
|
{
|
|
get { return this.unimportantBookmarks; }
|
|
set { this.unimportantBookmarks = value; }
|
|
}
|
|
|
|
[DataMember(EmitDefaultValue = false, Name = "bookmarkScopesListIsDefault")]
|
|
internal bool SerializedBookmarkScopesListIsDefault
|
|
{
|
|
get { return this.bookmarkScopesListIsDefault; }
|
|
set { this.bookmarkScopesListIsDefault = value; }
|
|
}
|
|
|
|
|
|
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.ConsiderPassingBaseTypesAsParameters,
|
|
Justification = "We are restricting the activities that can call this API.")]
|
|
public void RegisterBookmarkScope(NativeActivityContext context, BookmarkScopeHandle bookmarkScopeHandle)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("context");
|
|
}
|
|
|
|
context.ThrowIfDisposed();
|
|
|
|
if (bookmarkScopeHandle == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("bookmarkScopeHandle");
|
|
}
|
|
|
|
if ((this.ImportantBookmarks != null && this.ImportantBookmarks.Count != 0) || (this.UnimportantBookmarks != null && this.UnimportantBookmarks.Count != 0))
|
|
{
|
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ExclusiveHandleRegisterBookmarkScopeFailed));
|
|
}
|
|
|
|
if (this.bookmarkScopesListIsDefault)
|
|
{
|
|
this.bookmarkScopesListIsDefault = false;
|
|
this.bookmarkScopes.Clear();
|
|
}
|
|
|
|
this.bookmarkScopes.Add(bookmarkScopeHandle);
|
|
this.readOnlyBookmarkScopeCollection = null;
|
|
}
|
|
|
|
[SuppressMessage(FxCop.Category.Design, FxCop.Rule.ConsiderPassingBaseTypesAsParameters,
|
|
Justification = "We are restricting the activities that can call this API.")]
|
|
public void Reinitialize(NativeActivityContext context)
|
|
{
|
|
if (context == null)
|
|
{
|
|
throw FxTrace.Exception.ArgumentNull("context");
|
|
}
|
|
|
|
context.ThrowIfDisposed();
|
|
|
|
if ((this.ImportantBookmarks != null && this.ImportantBookmarks.Count != 0) || (this.UnimportantBookmarks != null && this.UnimportantBookmarks.Count != 0))
|
|
{
|
|
throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ExclusiveHandleReinitializeFailed));
|
|
}
|
|
this.bookmarkScopes.Clear();
|
|
this.readOnlyBookmarkScopeCollection = null;
|
|
this.PerformDefaultRegistration();
|
|
}
|
|
|
|
protected override void OnInitialize(HandleInitializationContext context)
|
|
{
|
|
this.owningInstance = context.OwningActivityInstance;
|
|
this.executor = context.Executor;
|
|
PerformDefaultRegistration();
|
|
}
|
|
|
|
internal ExclusiveHandleBookmarkList ImportantBookmarks
|
|
{
|
|
get
|
|
{
|
|
return this.importantBookmarks;
|
|
}
|
|
set
|
|
{
|
|
this.importantBookmarks = value;
|
|
}
|
|
}
|
|
|
|
internal ExclusiveHandleBookmarkList UnimportantBookmarks
|
|
{
|
|
get
|
|
{
|
|
return this.unimportantBookmarks;
|
|
}
|
|
set
|
|
{
|
|
this.unimportantBookmarks = value;
|
|
}
|
|
}
|
|
|
|
internal void AddToImportantBookmarks(Bookmark bookmark)
|
|
{
|
|
if (this.ImportantBookmarks == null)
|
|
{
|
|
this.ImportantBookmarks = new ExclusiveHandleBookmarkList();
|
|
}
|
|
|
|
Fx.Assert(!this.ImportantBookmarks.Contains(bookmark), "We shouldnt be here. We attempted to add the same bookmark");
|
|
this.ImportantBookmarks.Add(bookmark);
|
|
|
|
if (bookmark.ExclusiveHandles == null)
|
|
{
|
|
bookmark.ExclusiveHandles = new ExclusiveHandleList();
|
|
}
|
|
|
|
Fx.Assert(!bookmark.ExclusiveHandles.Contains(this), "We shouldnt be here. We attempted to add the bookmark to this exclusive handle already");
|
|
bookmark.ExclusiveHandles.Add(this);
|
|
}
|
|
|
|
internal void AddToUnimportantBookmarks(Bookmark bookmark)
|
|
{
|
|
if (this.UnimportantBookmarks == null)
|
|
{
|
|
this.UnimportantBookmarks = new ExclusiveHandleBookmarkList();
|
|
}
|
|
|
|
Fx.Assert(!this.UnimportantBookmarks.Contains(bookmark), "We shouldnt be here. We attempted to add the same bookmark");
|
|
this.UnimportantBookmarks.Add(bookmark);
|
|
|
|
if (bookmark.ExclusiveHandles == null)
|
|
{
|
|
bookmark.ExclusiveHandles = new ExclusiveHandleList();
|
|
}
|
|
|
|
Fx.Assert(!bookmark.ExclusiveHandles.Contains(this), "We shouldnt be here. We attempted to add the bookmark to this exclusive handle already");
|
|
bookmark.ExclusiveHandles.Add(this);
|
|
}
|
|
|
|
internal void RemoveBookmark(Bookmark bookmark)
|
|
{
|
|
Fx.Assert((this.ImportantBookmarks != null && this.ImportantBookmarks.Contains(bookmark)) ||
|
|
(this.UnimportantBookmarks != null && this.UnimportantBookmarks.Contains(bookmark)), "Internal error");
|
|
|
|
if (this.ImportantBookmarks != null)
|
|
{
|
|
if (this.ImportantBookmarks.Contains(bookmark))
|
|
{
|
|
this.ImportantBookmarks.Remove(bookmark);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (this.UnimportantBookmarks != null)
|
|
{
|
|
if (this.UnimportantBookmarks.Contains(bookmark))
|
|
{
|
|
this.UnimportantBookmarks.Remove(bookmark);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PerformDefaultRegistration()
|
|
{
|
|
if (this.bookmarkScopes == null)
|
|
{
|
|
this.bookmarkScopes = new List<BookmarkScopeHandle>();
|
|
}
|
|
|
|
//First register the default subinstance
|
|
this.bookmarkScopes.Add(BookmarkScopeHandle.Default);
|
|
|
|
// Note that we are starting the LocationEnvironment traversal from the current environment's Parent. We don't
|
|
// want to include any BookmarkScopeHandles that are at the same scope level as the ExclusiveHandle. The ExclusiveHandle
|
|
// should only be dependent on BookmarkScopeHandles that are higher in the scope tree.
|
|
LocationEnvironment current = this.owningInstance.Environment;
|
|
if (current != null)
|
|
{
|
|
for (current = current.Parent; current != null; current = current.Parent)
|
|
{
|
|
//don't bother continuing if at this level there are no handles
|
|
if (!current.HasHandles)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Look at the contained handles for the environment.
|
|
List<Handle> handles = current.Handles;
|
|
if (handles != null)
|
|
{
|
|
int count = handles.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
BookmarkScopeHandle scopeHandle = handles[i] as BookmarkScopeHandle;
|
|
if (scopeHandle != null)
|
|
{
|
|
this.bookmarkScopes.Add(scopeHandle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Also need to look in the Executor for handles that may have been created without an environment.
|
|
List<Handle> executorHandles = this.executor.Handles;
|
|
if (executorHandles != null)
|
|
{
|
|
int count = executorHandles.Count;
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
BookmarkScopeHandle scopeHandle = executorHandles[i] as BookmarkScopeHandle;
|
|
if (scopeHandle != null)
|
|
{
|
|
this.bookmarkScopes.Add(scopeHandle);
|
|
}
|
|
}
|
|
}
|
|
|
|
this.bookmarkScopesListIsDefault = true;
|
|
}
|
|
|
|
// Exclusive handle needs to track bookmarks such that it can tell the difference between two bookmarks in
|
|
// different bookmark scopes with the same name. Since we always deal in terms of the internal bookmark
|
|
// reference that we have, we can do an object.ReferenceEquals comparison to determine distinct bookmarks
|
|
// without having to add some sort of "containing scope" property to Bookmark.
|
|
[DataContract]
|
|
internal class ExclusiveHandleBookmarkList
|
|
{
|
|
List<Bookmark> bookmarks;
|
|
|
|
public ExclusiveHandleBookmarkList()
|
|
: base()
|
|
{
|
|
this.bookmarks = new List<Bookmark>();
|
|
}
|
|
|
|
public int Count
|
|
{
|
|
get { return this.bookmarks.Count; }
|
|
}
|
|
|
|
[DataMember(Name = "bookmarks")]
|
|
internal List<Bookmark> SerializedBookmarks
|
|
{
|
|
get { return this.bookmarks; }
|
|
set { this.bookmarks = value; }
|
|
}
|
|
|
|
public void Add(Bookmark bookmark)
|
|
{
|
|
Fx.Assert(bookmark != null, "A valid bookmark is expected.");
|
|
this.bookmarks.Add(bookmark);
|
|
}
|
|
|
|
public void Remove(Bookmark bookmark)
|
|
{
|
|
Fx.Assert(bookmark != null, "A valid bookmark is expected.");
|
|
|
|
for (int i = 0; i < this.bookmarks.Count; i++)
|
|
{
|
|
if (object.ReferenceEquals(this.bookmarks[i], bookmark))
|
|
{
|
|
this.bookmarks.RemoveAt(i);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool Contains(Bookmark bookmark)
|
|
{
|
|
Fx.Assert(bookmark != null, "A valid bookmark is expected.");
|
|
|
|
for (int i = 0; i < this.bookmarks.Count; i++)
|
|
{
|
|
if (object.ReferenceEquals(this.bookmarks[i], bookmark))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|