PageRenderTime 115ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/01 - Development/01-inital release/dbones.PlugIn/TinyPlug.cs

#
C# | 312 lines | 183 code | 31 blank | 98 comment | 33 complexity | 5286d2ea0c654e698be73c9bbb73aeac MD5 | raw file
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Reflection;
  5. using System.Text;
  6. namespace dbones.PlugIn
  7. {
  8. /// <summary>
  9. /// small plugin engine, im sure there is a better version
  10. /// somewhere else
  11. /// </summary>
  12. public class TinyPlug : IPlugInObserver
  13. {
  14. ///<summary>
  15. /// create an instance of TinyPlug
  16. ///</summary>
  17. public TinyPlug()
  18. {
  19. //SupportedInterfaces = new List<Type>();
  20. LoadedPlugIns = new Dictionary<Type, List<ActualPlugIn>>();
  21. }
  22. /// <summary>
  23. /// list of all loaded supported interfaces and plugins
  24. /// </summary>
  25. protected Dictionary<Type, List<ActualPlugIn>> LoadedPlugIns { get; private set; }
  26. /// <summary>
  27. /// all the supported interfaces
  28. /// </summary>
  29. /// <returns>a collection of all the supported interfaces</returns>
  30. public virtual IEnumerable<Type> SupportedInterfaces()
  31. {
  32. return LoadedPlugIns.Keys;
  33. }
  34. /// <summary>
  35. /// the plugins for an interface
  36. /// </summary>
  37. /// <param name="supportedInterface">The interface</param>
  38. /// <returns>all the plugins for the interface</returns>
  39. public virtual IEnumerable<ActualPlugIn> PlugInsFor(Type supportedInterface)
  40. {
  41. if (!LoadedPlugIns.ContainsKey(supportedInterface))
  42. {
  43. throw new NotSupportedException("this interface has not been added " + supportedInterface);
  44. }
  45. return LoadedPlugIns[supportedInterface];
  46. }
  47. /// <summary>
  48. /// the plugins for an interface
  49. /// </summary>
  50. /// <typeparam name="T">The interface</typeparam>
  51. /// <returns>all the plugins for the interface</returns>
  52. public virtual IEnumerable<ActualPlugIn> PlugInsFor<T>()
  53. {
  54. return PlugInsFor(typeof(T));
  55. }
  56. /// <summary>
  57. /// add this interface as a plugin
  58. /// </summary>
  59. /// <param name="supportedInterface"></param>
  60. /// <returns></returns>
  61. public virtual TinyPlug AddSupportedInterface(Type supportedInterface)
  62. {
  63. if (!supportedInterface.IsInterface)
  64. {
  65. throw new NotSupportedException("plugin manager only supports interfaces, as the contract");
  66. }
  67. if (!LoadedPlugIns.ContainsKey(supportedInterface))
  68. {
  69. LoadedPlugIns.Add(supportedInterface, new List<ActualPlugIn>());
  70. }
  71. return this;
  72. }
  73. /// <summary>
  74. /// Add a supported interface
  75. /// </summary>
  76. /// <typeparam name="T">the interface</typeparam>
  77. public virtual TinyPlug AddSupportedInterface<T>()
  78. {
  79. return AddSupportedInterface(typeof(T));
  80. }
  81. /// <summary>
  82. /// see if a type has implmented any supported interfaces
  83. /// </summary>
  84. /// <param name="plugIn">plug in type. interface</param>
  85. /// <returns>True if this class can be supported.</returns>
  86. public virtual bool IsSupportedInterface(Type plugIn)
  87. {
  88. foreach (var possiblePlugIn in plugIn.GetInterfaces())
  89. {
  90. if (LoadedPlugIns.ContainsKey(possiblePlugIn))
  91. {
  92. return true;
  93. }
  94. }
  95. return false;
  96. }
  97. /// <summary>
  98. /// see if a type has implmented any supported interfaces
  99. /// </summary>
  100. /// <typeparam name="T">pass in the generic type</typeparam>
  101. /// <returns>true if the class supports a plugin interface</returns>
  102. public virtual bool IsSupportedInterface<T>()
  103. {
  104. return IsSupportedInterface(typeof(T));
  105. }
  106. #region RegisterPlugIn
  107. /// <summary>
  108. /// hook up a plug in to a supported interface
  109. /// </summary>
  110. /// <param name="supportedInterface">the supported interface</param>
  111. /// <param name="actualPlugIn">the plugin to register</param>
  112. public virtual TinyPlug RegisterPlugIn(Type supportedInterface, Type actualPlugIn)
  113. {
  114. if (supportedInterface == null) throw new ArgumentNullException("supportedInterface");
  115. if (actualPlugIn == null) throw new ArgumentNullException("actualPlugIn");
  116. if (!LoadedPlugIns.ContainsKey(supportedInterface))
  117. {
  118. throw new NotSupportedException("this interface has not been added " + supportedInterface);
  119. }
  120. if (!IsSupportedInterface(actualPlugIn))
  121. {
  122. throw new NotSupportedException("The plugin does not implement the interface " + actualPlugIn);
  123. }
  124. var ap = new ActualPlugIn(actualPlugIn);
  125. ap.SupportedInterface = supportedInterface;
  126. ap.Attach(this);
  127. LoadedPlugIns[supportedInterface].Add(ap);
  128. return this;
  129. }
  130. /// <summary>
  131. /// hook up a plug in to a supported interface
  132. /// </summary>
  133. /// <typeparam name="T">the supported interface</typeparam>
  134. /// <typeparam name="AP">the plugin to register</typeparam>
  135. public virtual TinyPlug RegisterPlugIn<T, AP>() where AP : T
  136. {
  137. return RegisterPlugIn(typeof(T), typeof(AP));
  138. }
  139. /// <summary>
  140. /// finds all plugs which support an interface
  141. /// </summary>
  142. /// <typeparam name="T">The interface</typeparam>
  143. /// <param name="assembly">an assembly to search in, will extract the exported classes.</param>
  144. public virtual TinyPlug RegisterPlugIn<T>(Assembly assembly)
  145. {
  146. if (assembly == null) throw new ArgumentNullException("assembly");
  147. IEnumerable<Type> types = assembly.GetExportedTypes().Where(x => x.GetInterfaces().Contains(typeof(T)));
  148. RegisterPlugIn<T>(types);
  149. return this;
  150. }
  151. /// <summary>
  152. /// to to register any types which support the required interface
  153. /// </summary>
  154. /// <typeparam name="T">the interface which you want to register the plugins for</typeparam>
  155. /// <param name="types">a container of possible plugins</param>
  156. public virtual TinyPlug RegisterPlugIn<T>(IEnumerable<Type> types)
  157. {
  158. if (types == null) throw new ArgumentNullException("types");
  159. foreach (var possiblePlugin in types)
  160. {
  161. RegisterPlugIn(typeof(T), possiblePlugin);
  162. }
  163. return this;
  164. }
  165. #endregion
  166. #region RegisterPlugInToAny
  167. /// <summary>
  168. /// hook up a plug in to any supported interfaces (could be very slow)
  169. /// </summary>
  170. /// <param name="actualPlugIn">the plugin to register</param>
  171. public virtual TinyPlug RegisterPlugInToAny(Type actualPlugIn)
  172. {
  173. if (actualPlugIn == null) throw new ArgumentNullException("actualPlugIn");
  174. if (!IsSupportedInterface(actualPlugIn))
  175. {
  176. //not supported
  177. return this;
  178. //throw new NotSupportedException("The plugin does not implement the interface " + actualPlugIn);
  179. }
  180. foreach (var supportedInterface in
  181. actualPlugIn.GetInterfaces()
  182. .Where(x => LoadedPlugIns.Keys.Contains(x)))
  183. {
  184. var ap = new ActualPlugIn(actualPlugIn);
  185. ap.SupportedInterface = supportedInterface;
  186. ap.Attach(this);
  187. LoadedPlugIns[supportedInterface].Add(ap);
  188. }
  189. return this;
  190. }
  191. /// <summary>
  192. /// hook up a plug in to any supported interfaces (could be very slow)
  193. /// </summary>
  194. /// <param name="assembly">an assembly which contains many plugins, looks for the public types</param>
  195. public virtual TinyPlug RegisterPlugInToAny(Assembly assembly)
  196. {
  197. if (assembly == null) throw new ArgumentNullException("assembly");
  198. IEnumerable<Type> types = assembly.GetExportedTypes().Where(x => x.IsClass);
  199. RegisterPlugInToAny(types);
  200. return this;
  201. }
  202. /// <summary>
  203. /// this trys to register any types to any of the supported interfaces
  204. /// </summary>
  205. /// <param name="types">the container of types</param>
  206. public virtual TinyPlug RegisterPlugInToAny(IEnumerable<Type> types)
  207. {
  208. if (types == null) throw new ArgumentNullException("types");
  209. foreach (var possiblePlugIn in types)
  210. {
  211. RegisterPlugInToAny(possiblePlugIn);
  212. }
  213. return this;
  214. }
  215. #endregion
  216. /// <summary>
  217. /// Remove a plugin
  218. /// </summary>
  219. /// <param name="plugIn">To detach/Remove</param>
  220. public virtual TinyPlug UnregisterPlugIn(ActualPlugIn plugIn)
  221. {
  222. if (plugIn == null) throw new ArgumentNullException("plugIn");
  223. LoadedPlugIns[plugIn.SupportedInterface].Remove(plugIn);
  224. plugIn.Detach(this);
  225. return this;
  226. }
  227. /// <summary>
  228. /// Create an instance of the object
  229. /// </summary>
  230. /// <typeparam name="T">The type of plugin, the supported interface</typeparam>
  231. /// <param name="plugIn">The implementation of the plugin</param>
  232. /// <returns>a created instance of this class.</returns>
  233. public T CreateInstance<T>(ActualPlugIn plugIn) where T : class
  234. {
  235. if (plugIn == null) throw new ArgumentNullException("plugIn");
  236. if (!LoadedPlugIns.ContainsKey(typeof(T)))
  237. {
  238. throw new NotSupportedException("Does not support the interface " + typeof(T));
  239. }
  240. return (T)Activator.CreateInstance(plugIn.Class);
  241. }
  242. /// <summary>
  243. /// Create an instance of the object, using the 'Default' ActualPlugIn
  244. /// </summary>
  245. /// <typeparam name="T">The type of plugin, the supported interface</typeparam>
  246. /// <returns>a created instance of this class.</returns>
  247. public T CreateInstance<T>() where T : class
  248. {
  249. Type t = typeof(T);
  250. if (!LoadedPlugIns.ContainsKey(typeof(T)))
  251. {
  252. throw new NotSupportedException("Does not support the interface " + typeof(T));
  253. }
  254. ActualPlugIn plugIn;
  255. plugIn =
  256. LoadedPlugIns[t].Count == 1
  257. ? LoadedPlugIns[t][0]
  258. : LoadedPlugIns[t].Where(x => x.IsDefault).First();
  259. return plugIn == null
  260. ? null
  261. : (T)Activator.CreateInstance(plugIn.Class);
  262. }
  263. /// <summary>
  264. /// used to update the list of plugins, so only one can be the default
  265. /// </summary>
  266. /// <param name="plugIn">the plugin which has a change</param>
  267. public void Update(ActualPlugIn plugIn)
  268. {
  269. if (plugIn == null) throw new ArgumentNullException("plugIn");
  270. //check to see if this should now be the default implementation
  271. if (plugIn.IsDefault)
  272. {
  273. foreach (var other in LoadedPlugIns[plugIn.SupportedInterface]
  274. .Where(x => x != plugIn))
  275. {
  276. other.IsDefault = false;
  277. }
  278. }
  279. }
  280. }
  281. }