Added container accessor to Castle.Core
[castle.git] / Tools / Castle.DynamicProxy2 / Castle.DynamicProxy / ModuleScope.cs
blob90f1536747da9ba390feb1043d9869f90c3dc6a4
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 namespace Castle.DynamicProxy
17 using System;
18 using System.Collections;
19 using System.IO;
20 using System.Reflection;
21 using System.Reflection.Emit;
22 using System.Resources;
23 using System.Threading;
24 using Castle.DynamicProxy.Generators;
26 /// <summary>
27 /// Summary description for ModuleScope.
28 /// </summary>
29 public class ModuleScope
31 /// <summary>
32 /// The default file name used when the assembly is saved using <see cref="DEFAULT_FILE_NAME"/>.
33 /// </summary>
34 public static readonly String DEFAULT_FILE_NAME = "CastleDynProxy2.dll";
36 /// <summary>
37 /// The default assembly (simple) name used for the assemblies generated by a <see cref="ModuleScope"/> instance.
38 /// </summary>
39 public static readonly String DEFAULT_ASSEMBLY_NAME = "DynamicProxyGenAssembly2";
41 // Avoid leaks caused by non disposal of generated types.
42 private ModuleBuilder moduleBuilderWithStrongName = null;
43 private ModuleBuilder moduleBuilder = null;
45 // The names to use for the generated assemblies and the paths (including the names) of their manifest modules
46 private string strongAssemblyName;
47 private string weakAssemblyName;
48 private string strongModulePath;
49 private string weakModulePath;
51 // Keeps track of generated types
52 private Hashtable typeCache = Hashtable.Synchronized(new Hashtable());
54 // Users of ModuleScope should use this lock when accessing the cache
55 private ReaderWriterLock readerWriterLock = new ReaderWriterLock ();
57 // Used to lock the module builder creation
58 private object _lockobj = new object();
60 // Specified whether the generated assemblies are intended to be saved
61 private bool savePhysicalAssembly;
63 /// <summary>
64 /// Initializes a new instance of the <see cref="ModuleScope"/> class; assemblies created by this instance will not be saved.
65 /// </summary>
66 public ModuleScope() : this (false)
70 /// <summary>
71 /// Initializes a new instance of the <see cref="ModuleScope"/> class, allowing to specify whether the assemblies generated by this instance
72 /// should be saved.
73 /// </summary>
74 /// <param name="savePhysicalAssembly">If set to <c>true</c> saves the generated module.</param>
75 public ModuleScope (bool savePhysicalAssembly)
76 : this (savePhysicalAssembly, DEFAULT_ASSEMBLY_NAME, DEFAULT_FILE_NAME, DEFAULT_ASSEMBLY_NAME, DEFAULT_FILE_NAME)
80 /// <summary>
81 /// Initializes a new instance of the <see cref="ModuleScope"/> class, allowing to specify whether the assemblies generated by this instance
82 /// should be saved and what simple names are to be assigned to them.
83 /// </summary>
84 /// <param name="savePhysicalAssembly">If set to <c>true</c> saves the generated module.</param>
85 /// <param name="strongAssemblyName">The simple name of the strong-named assembly generated by this <see cref="ModuleScope"/>.</param>
86 /// <param name="strongModulePath">The path and file name of the manifest module of the strong-named assembly generated by this <see cref="ModuleScope"/>.</param>
87 /// <param name="weakAssemblyName">The simple name of the weak-named assembly generated by this <see cref="ModuleScope"/>.</param>
88 /// <param name="weakModulePath">The path and file name of the manifest module of the weak-named assembly generated by this <see cref="ModuleScope"/>.</param>
89 public ModuleScope (bool savePhysicalAssembly, string strongAssemblyName, string strongModulePath, string weakAssemblyName, string weakModulePath)
91 this.savePhysicalAssembly = savePhysicalAssembly;
92 this.strongAssemblyName = strongAssemblyName;
93 this.strongModulePath = strongModulePath;
94 this.weakAssemblyName = weakAssemblyName;
95 this.weakModulePath = weakModulePath;
98 /// <summary>
99 /// Users of this <see cref="ModuleScope"/> should use this lock when accessing the cache.
100 /// </summary>
101 public ReaderWriterLock RWLock
103 get { return readerWriterLock; }
106 /// <summary>
107 /// Returns a type from this scope's type cache, or null if the key cannot be found.
108 /// </summary>
109 /// <param name="key">The key to be looked up in the cache.</param>
110 /// <returns>The type from this scope's type cache matching the key, or null if the key cannot be found</returns>
111 public Type GetFromCache (CacheKey key)
113 // no lock needed, typeCache is synchronized
114 return (Type) typeCache[key];
117 /// <summary>
118 /// Registers a type in this scope's type cache.
119 /// </summary>
120 /// <param name="key">The key to be associated with the type.</param>
121 /// <param name="type">The type to be stored in the cache.</param>
122 public void RegisterInCache (CacheKey key, Type type)
124 // no lock needed, typeCache is synchronized
125 typeCache[key] = type;
128 /// <summary>
129 /// Gets the key pair used to sign the strong-named assembly generated by this <see cref="ModuleScope"/>.
130 /// </summary>
131 /// <returns></returns>
132 public static byte[] GetKeyPair ()
134 byte[] keyPair;
136 using (Stream stream = Assembly.GetExecutingAssembly ().GetManifestResourceStream ("Castle.DynamicProxy.DynProxy.snk"))
138 if (stream == null)
139 throw new MissingManifestResourceException (
140 "Should have a Castle.DynamicProxy.DynProxy.snk as an embedded resource, so Dynamic Proxy could sign generated assembly");
142 int length = (int) stream.Length;
143 keyPair = new byte[length];
144 stream.Read (keyPair, 0, length);
147 return keyPair;
150 /// <summary>
151 /// Gets the strong-named module generated by this scope, or <see langword="null"/> if none has yet been generated.
152 /// </summary>
153 /// <value>The strong-named module generated by this scope, or <see langword="null"/> if none has yet been generated.</value>
154 public ModuleBuilder StrongNamedModule
158 lock (_lockobj)
160 return moduleBuilderWithStrongName;
165 /// <summary>
166 /// Gets the file name of the strongly named module generated by this scope.
167 /// </summary>
168 /// <value>The file name of the strongly named module generated by this scope.</value>
169 public string StrongNamedModuleName
173 return Path.GetFileName (strongModulePath);
177 /// <summary>
178 /// Gets the directory where the strongly named module generated by this scope will be saved, or <see langword="null"/> if the current directory
179 /// is used.
180 /// </summary>
181 /// <value>The directory where the strongly named module generated by this scope will be saved when <see cref="SaveAssembly()"/> is called
182 /// (if this scope was created to save modules).</value>
183 public string StrongNamedModuleDirectory
187 string directory = Path.GetDirectoryName (strongModulePath);
188 if (directory == "")
189 return null;
190 else
191 return directory;
195 /// <summary>
196 /// Gets the weak-named module generated by this scope, or <see langword="null"/> if none has yet been generated.
197 /// </summary>
198 /// <value>The weak-named module generated by this scope, or <see langword="null"/> if none has yet been generated.</value>
199 public ModuleBuilder WeakNamedModule
203 lock (_lockobj)
205 return moduleBuilder;
210 /// <summary>
211 /// Gets the file name of the weakly named module generated by this scope.
212 /// </summary>
213 /// <value>The file name of the weakly named module generated by this scope.</value>
214 public string WeakNamedModuleName
218 return Path.GetFileName (weakModulePath);
222 /// <summary>
223 /// Gets the directory where the weakly named module generated by this scope will be saved, or <see langword="null"/> if the current directory
224 /// is used.
225 /// </summary>
226 /// <value>The directory where the weakly named module generated by this scope will be saved when <see cref="SaveAssembly()"/> is called
227 /// (if this scope was created to save modules).</value>
228 public string WeakNamedModuleDirectory
232 string directory = Path.GetDirectoryName (weakModulePath);
233 if (directory == "")
234 return null;
235 else
236 return directory;
240 /// <summary>
241 /// Gets the specified module generated by this scope, creating a new one if none has yet been generated.
242 /// </summary>
243 /// <param name="isStrongNamed">If set to true, a strong-named module is returned; otherwise, a weak-named module is returned.</param>
244 /// <returns>A strong-named or weak-named module generated by this scope, as specified by the <paramref name="isStrongNamed"/> parameter.</returns>
245 public ModuleBuilder ObtainDynamicModule (bool isStrongNamed)
247 lock (_lockobj)
249 if (isStrongNamed)
250 return ObtainDynamicModuleWithStrongName ();
251 else
252 return ObtainDynamicModuleWithWeakName ();
256 /// <summary>
257 /// Gets the strong-named module generated by this scope, creating a new one if none has yet been generated.
258 /// </summary>
259 /// <returns>A strong-named module generated by this scope.</returns>
260 public ModuleBuilder ObtainDynamicModuleWithStrongName()
262 lock (_lockobj)
264 if (moduleBuilderWithStrongName == null)
266 moduleBuilderWithStrongName = CreateModule (true);
268 return moduleBuilderWithStrongName;
272 /// <summary>
273 /// Gets the weak-named module generated by this scope, creating a new one if none has yet been generated.
274 /// </summary>
275 /// <returns>A weak-named module generated by this scope.</returns>
276 public ModuleBuilder ObtainDynamicModuleWithWeakName ()
278 lock (_lockobj)
280 if (moduleBuilder == null)
282 moduleBuilder = CreateModule (false);
284 return moduleBuilder;
288 private ModuleBuilder CreateModule(bool signStrongName)
290 AssemblyName assemblyName = GetAssemblyName(signStrongName);
292 string moduleName = signStrongName ? StrongNamedModuleName : WeakNamedModuleName;
293 string moduleDirectory = signStrongName ? StrongNamedModuleDirectory : WeakNamedModuleDirectory;
295 if (savePhysicalAssembly)
297 AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
298 assemblyName, AssemblyBuilderAccess.RunAndSave, moduleDirectory);
300 return assemblyBuilder.DefineDynamicModule(moduleName, moduleName, true);
302 else
304 AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
305 assemblyName,
306 AssemblyBuilderAccess.Run);
308 return assemblyBuilder.DefineDynamicModule(moduleName, true);
312 private AssemblyName GetAssemblyName (bool signStrongName)
314 AssemblyName assemblyName = new AssemblyName();
315 assemblyName.Name = signStrongName ? strongAssemblyName : weakAssemblyName;
317 if (signStrongName)
319 byte[] keyPairStream = GetKeyPair();
321 if (keyPairStream != null)
323 assemblyName.KeyPair = new StrongNameKeyPair(keyPairStream);
326 return assemblyName;
329 /// <summary>
330 /// Saves the generated assembly with the name and directory information given when this <see cref="ModuleScope"/> instance was created (or with
331 /// the <see cref="DEFAULT_FILE_NAME"/> and current directory if none was given).
332 /// </summary>
333 /// <remarks>
334 /// <para>
335 /// This method stores the generated assembly in the directory passed as part of the module information specified when this instance was
336 /// constructed (if any, else the current directory is used). If both a strong-named and a weak-named assembly
337 /// have been generated, it will throw an exception; in this case, use the <see cref="SaveAssembly (bool)"/> overload.
338 /// </para>
339 /// <para>
340 /// If this <see cref="ModuleScope"/> was created without indicating that the assembly should be saved, this method does nothing.
341 /// </para></remarks>
342 /// <exception cref="InvalidOperationException">Both a strong-named and a weak-named assembly have been generated or no assembly has been
343 /// generated.</exception>
344 public void SaveAssembly ()
346 if (!savePhysicalAssembly)
347 return;
349 if (StrongNamedModule != null && WeakNamedModule != null)
350 throw new InvalidOperationException ("Both a strong-named and a weak-named assembly have been generated.");
351 else if (StrongNamedModule != null)
352 SaveAssembly (true);
353 else if (WeakNamedModule != null)
354 SaveAssembly (false);
355 else
356 throw new InvalidOperationException ("No assembly has been generated.");
359 /// <summary>
360 /// Saves the specified generated assembly with the name and directory information given when this <see cref="ModuleScope"/> instance was created
361 /// (or with the <see cref="DEFAULT_FILE_NAME"/> and current directory if none was given).
362 /// </summary>
363 /// <param name="strongNamed">True if the generated assembly with a strong name should be saved (see <see cref="StrongNamedModule"/>);
364 /// false if the generated assembly without a strong name should be saved (see <see cref="WeakNamedModule"/>.</param>
365 /// <remarks>
366 /// <para>
367 /// This method stores the specified generated assembly in the directory passed as part of the module information specified when this instance was
368 /// constructed (if any, else the current directory is used).
369 /// </para>
370 /// <para>
371 /// If this <see cref="ModuleScope"/> was created without indicating that the assembly should be saved, this method does nothing.
372 /// </para>
373 /// </remarks>
374 /// <exception cref="InvalidOperationException">No assembly has been generated that matches the <paramref name="strongNamed"/> parameter.
375 /// </exception>
376 public void SaveAssembly (bool strongNamed)
378 if (!savePhysicalAssembly)
379 return;
381 AssemblyBuilder assemblyBuilder;
382 string assemblyFileName;
383 string assemblyFilePath;
385 if (strongNamed)
387 if (StrongNamedModule == null)
388 throw new InvalidOperationException ("No strong-named assembly has been generated.");
389 else
391 assemblyBuilder = (AssemblyBuilder) StrongNamedModule.Assembly;
392 assemblyFileName = StrongNamedModuleName;
393 assemblyFilePath = StrongNamedModule.FullyQualifiedName;
396 else
398 if (WeakNamedModule == null)
399 throw new InvalidOperationException ("No weak-named assembly has been generated.");
400 else
402 assemblyBuilder = (AssemblyBuilder) WeakNamedModule.Assembly;
403 assemblyFileName = WeakNamedModuleName;
404 assemblyFilePath = WeakNamedModule.FullyQualifiedName;
408 if (File.Exists (assemblyFilePath))
410 File.Delete (assemblyFilePath);
413 assemblyBuilder.Save (assemblyFileName);