PageRenderTime 27ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/pServiceBus/Src/PServiceBus.RabbitMQ/Provider.cs

#
C# | 291 lines | 246 code | 45 blank | 0 comment | 40 complexity | b30cb5faf8c86394d7df888847980201 MD5 | raw file
Possible License(s): LGPL-2.1, MIT, Apache-2.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using RabbitMQ.Client;
  6. using System.Text.RegularExpressions;
  7. using RabbitMQ.Client.Exceptions;
  8. using System.Runtime.Serialization.Formatters.Binary;
  9. using System.IO;
  10. using PServiceBus.Core.Runtime;
  11. using PServiceBus.Core.Runtime.Extensions;
  12. using PServiceBus.Core.Logger;
  13. using PServiceBus.Core.Interface;
  14. using System.Collections;
  15. using System.Collections.Concurrent;
  16. namespace PServiceBus.RabbitMQ {
  17. public sealed class Provider<TObject> : IHaveEndpoint, IObjectProvider<TObject> where TObject : class {
  18. private object _lockObject = new object();
  19. private static ConcurrentDictionary<string, IConnection> _connections = new ConcurrentDictionary<string, IConnection>();
  20. private static ConcurrentDictionary<string, IModel> _models = new ConcurrentDictionary<string, IModel>();
  21. private static ConcurrentDictionary<string, ProviderFactory> _factories = new ConcurrentDictionary<string, ProviderFactory>();
  22. private static ConcurrentDictionary<string, object> _providers = new ConcurrentDictionary<string, object>();
  23. public static Provider<TObject> GetProvider(string endpoint, bool appendTypeNameToEndpoint = false, string endpointAlias = null) {
  24. return _providers.GetOrAdd(endpoint, key =>
  25. new Provider<TObject> { Endpoint = endpoint, IDFunc = x => Guid.NewGuid(),
  26. EndpointAlias = endpointAlias, AppendTypeNameToEndpoint = appendTypeNameToEndpoint }) as Provider<TObject>;
  27. }
  28. private void Query(Action<IModel, string, string> action) {
  29. lock (_lockObject) {
  30. var factory = ConnectionProviderFactory;
  31. CreateQueue(Model, factory.ExchangeName, factory.Queue);
  32. action(Model, factory.ExchangeName, factory.Queue);
  33. }
  34. }
  35. internal class ProviderFactory {
  36. public ConnectionFactory ConnectionFactory { get; set; }
  37. public string ExchangeName { get; set; }
  38. public string Queue { get; set; }
  39. }
  40. private IConnection GetConnection(string endpoint, bool appendTypeNameToEndpoint, string endpointAlias = null) {
  41. string key = String.Concat(endpoint, endpointAlias ?? string.Empty);
  42. var connection = _connections.GetOrAdd(key, k => {
  43. return GetConnectionFactory(Endpoint, AppendTypeNameToEndpoint, EndpointAlias).ConnectionFactory.CreateConnection();
  44. });
  45. if (connection == null || !connection.IsOpen)
  46. connection = _connections.AddOrUpdate(key, k => GetConnectionFactory(Endpoint, AppendTypeNameToEndpoint, EndpointAlias).ConnectionFactory.CreateConnection(),
  47. (k, c) => GetConnectionFactory(Endpoint, AppendTypeNameToEndpoint, EndpointAlias).ConnectionFactory.CreateConnection());
  48. return connection;
  49. }
  50. private IModel GetModel(string endpoint, bool appendTypeNameToEndpoint, string endpointAlias = null) {
  51. string key = String.Concat(endpoint, endpointAlias ?? string.Empty);
  52. var model = _models.GetOrAdd(key, k => GetConnection(endpoint, appendTypeNameToEndpoint, endpointAlias).CreateModel());
  53. if(model == null || !model.IsOpen)
  54. model = _models.AddOrUpdate(key, k => GetConnection(endpoint, appendTypeNameToEndpoint, endpointAlias).CreateModel(),
  55. (k, c) => GetConnection(endpoint, appendTypeNameToEndpoint, endpointAlias).CreateModel());
  56. return model;
  57. }
  58. private IConnection Connection {
  59. get { return GetConnection(Endpoint, AppendTypeNameToEndpoint, EndpointAlias); }
  60. }
  61. private IModel Model {
  62. get { return GetModel(Endpoint, AppendTypeNameToEndpoint, EndpointAlias); }
  63. }
  64. private ProviderFactory GetConnectionFactory(string endpoint, bool appendTypeNameToEndpoint, string endpointAlias = null) {
  65. var key = String.Concat(endpoint, endpointAlias ?? string.Empty);
  66. return _factories.GetOrAdd(key, k =>
  67. {
  68. var path = AppendTypeNameToEndpoint ? typeof(TObject).FullName.Replace(".", "_") : string.Empty;
  69. path += (EndpointAlias ?? string.Empty);
  70. endpoint += (endpoint.EndsWith("/") ? string.Empty : "/") + path;
  71. var uri = EndpointUri.Parse(endpoint);
  72. var queue = uri.Path;
  73. var exchangeName = "ex" + queue;
  74. var factory = new ConnectionFactory() { HostName = uri.Host, UserName = uri.Username, Password = uri.Password, Port = uri.Port };
  75. return new ProviderFactory() { ConnectionFactory = factory, ExchangeName = exchangeName, Queue = queue };
  76. });
  77. }
  78. private ProviderFactory ConnectionProviderFactory {
  79. get {
  80. return GetConnectionFactory(Endpoint, AppendTypeNameToEndpoint, EndpointAlias);
  81. }
  82. }
  83. public void Clear() {
  84. Query((ch, exchangeName, queue) => ch.QueuePurge(Endpoint));
  85. }
  86. private bool _queueCreated = false;
  87. private bool CreateQueue(IModel ch, string exchangeName, string queue) {
  88. var success = true;
  89. if (_queueCreated) return success;
  90. try {
  91. ch.ExchangeDeclare(exchangeName, ExchangeType.Fanout, true);
  92. ch.QueueDeclare(queue, true, false, false, null);
  93. ch.QueueBind(queue, exchangeName, queue, null);
  94. _queueCreated = true;
  95. } catch { success = false; }
  96. return success;
  97. }
  98. private TObject GetObjectByID(string id, bool deleteObjectOnRead) {
  99. var obj = default(TObject);
  100. try {
  101. lock (_lockObject) {
  102. Query((ch, exchangeName, queue) =>
  103. {
  104. while (true) {
  105. try {
  106. var result = ch.BasicGet(queue, !deleteObjectOnRead);
  107. if (result == null) break;
  108. var body = result.Body.Deserialize<TObject>();
  109. var prop = result.BasicProperties;
  110. if (body != null && (id == null || (id != null && prop.MessageId == id))) {
  111. if (deleteObjectOnRead) ch.BasicAck(result.DeliveryTag, false);
  112. obj = body;
  113. break;
  114. }
  115. } catch (Exception) { break; }
  116. }
  117. });
  118. }
  119. }
  120. catch {
  121. }
  122. return obj;
  123. }
  124. #region IObjectProvider<TObject> Members
  125. public bool Refresh(TObject obj) {
  126. throw new NotImplementedException();
  127. }
  128. public bool Add(IEnumerable<TObject> list) {
  129. var success = true;
  130. try {
  131. Query((ch, exchangeName, queue) =>
  132. {
  133. foreach (var data in list) {
  134. var prop = ch.CreateBasicProperties();
  135. prop.SetPersistent(true);
  136. prop.DeliveryMode = 2;
  137. prop.MessageId = IDFunc(data).ToString();
  138. ch.BasicPublish(exchangeName, queue, prop, data.Serialize());
  139. }
  140. });
  141. } catch {
  142. success = false;
  143. }
  144. return success;
  145. }
  146. public bool Add(TObject obj) {
  147. Query((ch, exchangeName, queue) =>
  148. {
  149. var prop = ch.CreateBasicProperties();
  150. prop.SetPersistent(true);
  151. prop.DeliveryMode = 2;
  152. prop.MessageId = IDFunc(obj).ToString();
  153. ch.BasicPublish(exchangeName, queue, prop, obj.Serialize());
  154. });
  155. return true;
  156. }
  157. public void Delete() {
  158. Query((ch, exchangeName, queue) =>
  159. {
  160. try {
  161. ch.QueueUnbind(queue, exchangeName, queue, null);
  162. ch.ExchangeDelete(exchangeName, true);
  163. ch.QueueDelete(queue, true, false);
  164. } catch {
  165. throw;
  166. }
  167. });
  168. }
  169. public bool Delete(IEnumerable<TObject> list) {
  170. var success = true;
  171. foreach (var obj in list)
  172. success &= GetObjectByID(IDFunc(obj).ToString(), true) != null;
  173. return success;
  174. }
  175. public bool Delete(IEnumerable<Func<TObject, bool>> conditions) {
  176. var success = true;
  177. foreach (var condition in conditions) {
  178. var deleteObj = this.FirstOrDefault(obj => obj != null && condition(obj));
  179. success &= deleteObj != null
  180. && GetObjectByID(IDFunc(deleteObj).ToString(), true) != null;
  181. }
  182. return success;
  183. }
  184. public bool Delete(Func<TObject, bool> condition) {
  185. var deleteObj = this.FirstOrDefault(obj => obj != null && condition(obj));
  186. return deleteObj != null
  187. && GetObjectByID(IDFunc(deleteObj).ToString(), true) != null;
  188. }
  189. public bool Exists(Func<TObject, bool> condition) {
  190. return Get(condition) != null;
  191. }
  192. public TObject Get(Func<TObject, bool> condition) {
  193. return this.FirstOrDefault(obj => condition(obj));
  194. }
  195. public bool Exists(TObject obj) {
  196. return GetObjectByID(IDFunc(obj).ToString(), false) != null;
  197. }
  198. public TObject Get(Guid id) {
  199. return GetObjectByID(id.ToString(), false);
  200. }
  201. public bool Delete(TObject obj) {
  202. return GetObjectByID(IDFunc(obj).ToString(), true) != null;
  203. }
  204. public string Endpoint { get; set; }
  205. public string EndpointAlias { get; set; }
  206. public bool AppendTypeNameToEndpoint { get; set; }
  207. public bool DeleteObjectOnRead { get; set; }
  208. public Func<TObject, Guid> IDFunc { get; set; }
  209. #endregion
  210. #region IEnumerable<TObject> Members
  211. public IEnumerator<TObject> GetEnumerator() {
  212. var factory = ConnectionProviderFactory;
  213. CreateQueue(Model, factory.ExchangeName, factory.Queue);
  214. var body = default(TObject);
  215. while (true) {
  216. try {
  217. var result = Model.BasicGet(factory.Queue, !DeleteObjectOnRead);
  218. if (result != null)
  219. MethodHelper.Try(() => body = result.Body.Deserialize<TObject>());
  220. else break;
  221. if (DeleteObjectOnRead) Model.BasicAck(result.DeliveryTag, false);
  222. } catch (Exception) { break; }
  223. if (body != null) yield return body;
  224. }
  225. }
  226. #endregion
  227. #region IEnumerable Members
  228. IEnumerator IEnumerable.GetEnumerator() {
  229. return GetEnumerator();
  230. }
  231. #endregion
  232. #region IDisposable Members
  233. public void Dispose() {
  234. MethodHelper.Try(() => {
  235. foreach (var kv in _models) kv.Value.Close();
  236. });
  237. MethodHelper.Try(() => {
  238. foreach (var kv in _connections) kv.Value.Close();
  239. });
  240. _models.Clear();
  241. _connections.Clear();
  242. _factories.Clear();
  243. }
  244. #endregion
  245. }
  246. }