Implement MachineKey.Protect and MachineKey.Unprotect
[mono.git] / mcs / class / System.ComponentModel.Composition / src / ComponentModel / System / ComponentModel / Composition / Hosting / ImportEngine.PartManager.cs
1 // -----------------------------------------------------------------------\r
2 // Copyright (c) Microsoft Corporation.  All rights reserved.\r
3 // -----------------------------------------------------------------------\r
4 using System;\r
5 using System.Collections.Generic;\r
6 using System.ComponentModel.Composition.Primitives;\r
7 using System.Diagnostics;\r
8 using System.Linq;\r
9 using System.Runtime.CompilerServices;\r
10 using Microsoft.Internal;\r
11 using Microsoft.Internal.Collections;\r
12 \r
13 namespace System.ComponentModel.Composition.Hosting\r
14 {\r
15     public partial class ImportEngine\r
16     {\r
17         /// <summary>\r
18         ///     Used by the <see cref="ImportEngine"/> to manage the composition of a given part.\r
19         ///     It stores things like the list of disposable exports used to satisfy the imports as\r
20         ///     well as the caching of the exports discovered during previewing of a part.\r
21         /// </summary>\r
22         private class PartManager\r
23         {\r
24             private Dictionary<ImportDefinition, List<IDisposable>> _importedDisposableExports;\r
25             private Dictionary<ImportDefinition, Export[]> _importCache;\r
26             private string[] _importedContractNames;\r
27             private ComposablePart _part;\r
28             private ImportState _state = ImportState.NoImportsSatisfied;\r
29             private readonly ImportEngine _importEngine;\r
30 \r
31             public PartManager(ImportEngine importEngine, ComposablePart part)\r
32             {\r
33                 this._importEngine = importEngine;\r
34                 this._part = part;\r
35             }\r
36 \r
37             public ComposablePart Part\r
38             {\r
39                 get\r
40                 {\r
41                     return this._part;\r
42                 }\r
43             }\r
44 \r
45             public ImportState State\r
46             {\r
47                 get\r
48                 {\r
49                     using (this._importEngine._lock.LockStateForRead())\r
50                     {\r
51                         return this._state;\r
52                     }\r
53                 }\r
54                 set\r
55                 {\r
56                     using (this._importEngine._lock.LockStateForWrite())\r
57                     {\r
58                         this._state = value;\r
59                     }\r
60                 }\r
61             }\r
62 \r
63             public bool TrackingImports { get; set; }\r
64 \r
65             public IEnumerable<string> GetImportedContractNames()\r
66             {\r
67                 if (this.Part == null)\r
68                 {\r
69                     return Enumerable.Empty<string>();\r
70                 }\r
71 \r
72                 if (this._importedContractNames == null)\r
73                 {\r
74                     this._importedContractNames = this.Part.ImportDefinitions.Select(import => import.ContractName ?? ImportDefinition.EmptyContractName).Distinct().ToArray();\r
75                 }\r
76                 return this._importedContractNames;\r
77             }\r
78 \r
79             public CompositionResult TrySetImport(ImportDefinition import, IEnumerable<Export> exports)\r
80             {\r
81                 try\r
82                 {\r
83                     this.Part.SetImport(import, exports);\r
84                     UpdateDisposableDependencies(import, exports);\r
85                     return CompositionResult.SucceededResult;\r
86                 }\r
87                 catch (CompositionException ex)\r
88                 {   // Pulling on one of the exports failed\r
89 \r
90                     return new CompositionResult(\r
91                         ErrorBuilder.CreatePartCannotSetImport(Part, import, ex));\r
92                 }\r
93                 catch (ComposablePartException ex)\r
94                 {   // Type mismatch between export and import\r
95 \r
96                     return new CompositionResult(\r
97                         ErrorBuilder.CreatePartCannotSetImport(Part, import, ex));\r
98                 }\r
99             }\r
100 \r
101             public void SetSavedImport(ImportDefinition import, Export[] exports, AtomicComposition atomicComposition)\r
102             {\r
103                 if (atomicComposition != null)\r
104                 {\r
105                     var savedExports = this.GetSavedImport(import);\r
106 \r
107                     // Add a revert action to revert the stored exports\r
108                     // in the case that this atomicComposition gets rolled back.\r
109                     atomicComposition.AddRevertAction(() =>\r
110                         this.SetSavedImport(import, savedExports, null));\r
111                 }\r
112 \r
113                 if (this._importCache == null)\r
114                 {\r
115                     this._importCache = new Dictionary<ImportDefinition, Export[]>();\r
116                 }\r
117 \r
118                 this._importCache[import] = exports;\r
119             }\r
120 \r
121             public Export[] GetSavedImport(ImportDefinition import)\r
122             {\r
123                 Export[] exports = null;\r
124                 if (this._importCache != null)\r
125                 {\r
126                     // We don't care about the return value we just want the exports\r
127                     // and if it isn't present we just return the initialized null value\r
128                     this._importCache.TryGetValue(import, out exports);\r
129                 }\r
130                 return exports;\r
131             }\r
132 \r
133             public void ClearSavedImports()\r
134             {\r
135                 this._importCache = null;\r
136             }\r
137 \r
138             public CompositionResult TryOnComposed()\r
139             {\r
140                 try\r
141                 {\r
142                     this.Part.Activate();\r
143                     return CompositionResult.SucceededResult;\r
144                 }\r
145                 catch (ComposablePartException ex)\r
146                 {   // Type failed to be constructed, imports could not be set, etc\r
147                     return new CompositionResult(\r
148                         ErrorBuilder.CreatePartCannotActivate(this.Part, ex));\r
149                 }\r
150             }\r
151 \r
152             public void UpdateDisposableDependencies(ImportDefinition import, IEnumerable<Export> exports)\r
153             {\r
154                 // Determine if there are any new disposable exports, optimizing for the most\r
155                 // likely case, which is that there aren't any\r
156                 List<IDisposable> disposableExports = null;\r
157                 foreach (var disposableExport in exports.OfType<IDisposable>())\r
158                 {\r
159                     if (disposableExports == null)\r
160                     {\r
161                         disposableExports = new List<IDisposable>();\r
162                     }\r
163                     disposableExports.Add(disposableExport);\r
164                 }\r
165 \r
166                 // Dispose any existing references previously set on this import\r
167                 List<IDisposable> oldDisposableExports = null;\r
168                 if (this._importedDisposableExports != null &&\r
169                     this._importedDisposableExports.TryGetValue(import, out oldDisposableExports))\r
170                 {\r
171                     oldDisposableExports.ForEach(disposable => disposable.Dispose());\r
172 \r
173                     // If there aren't any replacements, get rid of the old storage\r
174                     if (disposableExports == null)\r
175                     {\r
176                         this._importedDisposableExports.Remove(import);\r
177                         if (!this._importedDisposableExports.FastAny())\r
178                         {\r
179                             this._importedDisposableExports = null;\r
180                         }\r
181 \r
182                         return;\r
183                     }\r
184                 }\r
185 \r
186                 // Record the new collection\r
187                 if (disposableExports != null)\r
188                 {\r
189                     if (this._importedDisposableExports == null)\r
190                     {\r
191                         this._importedDisposableExports = new Dictionary<ImportDefinition, List<IDisposable>>();\r
192                     }\r
193                     this._importedDisposableExports[import] = disposableExports;\r
194                 }\r
195             }\r
196 \r
197             public void DisposeAllDependencies()\r
198             {\r
199                 if (this._importedDisposableExports != null)\r
200                 {\r
201                     IEnumerable<IDisposable> dependencies = this._importedDisposableExports.Values\r
202                         .SelectMany(exports => exports);\r
203 \r
204                     this._importedDisposableExports = null;\r
205 \r
206                     dependencies.ForEach(disposableExport => disposableExport.Dispose());\r
207                 }\r
208             }\r
209         }\r
210     }\r
211 }\r