LCOV - code coverage report
Current view: top level - Cqrs/Configuration - BusRegistrar.cs Hit Total Coverage
Test: doc-coverage.info Lines: 2 10 20.0 %
Date: 2017-07-26

          Line data    Source code
       1             : #region Copyright
       2             : // // -----------------------------------------------------------------------
       3             : // // <copyright company="cdmdotnet Limited">
       4             : // //   Copyright cdmdotnet Limited. All rights reserved.
       5             : // // </copyright>
       6             : // // -----------------------------------------------------------------------
       7             : #endregion
       8             : 
       9             : using System;
      10             : using System.Collections.Generic;
      11             : using System.Linq;
      12             : using System.Reflection;
      13             : using System.Security;
      14             : using cdmdotnet.Logging;
      15             : using Cqrs.Bus;
      16             : using Cqrs.Commands;
      17             : using Cqrs.Events;
      18             : 
      19             : namespace Cqrs.Configuration
      20             : {
      21             :         /// <summary>
      22             :         /// Triggers the <see cref="IEventHandlerRegistrar"/> and <see cref="ICommandHandlerRegistrar"/> if they are registered in the <see cref="IDependencyResolver"/>.
      23             :         /// </summary>
      24             :         public class BusRegistrar
      25           1 :         {
      26             :                 protected IDependencyResolver DependencyResolver { get; private set; }
      27             : 
      28             :                 public static Func<Type, Type, IHandlerRegistrar> GetEventHandlerRegistrar { get; set; }
      29             : 
      30             :                 public static Func<Type, Type, IHandlerRegistrar> GetCommandHandlerRegistrar { get; set; }
      31             : 
      32           0 :                 public BusRegistrar(IDependencyResolver dependencyResolver)
      33             :                 {
      34             :                         if(dependencyResolver == null)
      35             :                                 throw new ArgumentNullException("dependencyResolver");
      36             : 
      37             :                         DependencyResolver = dependencyResolver;
      38             :                         if (GetEventHandlerRegistrar == null)
      39             :                                 GetEventHandlerRegistrar = (messageType, handlerDelegateTargetedType) => DependencyResolver.Resolve<IEventHandlerRegistrar>();
      40             :                         if (GetCommandHandlerRegistrar == null)
      41             :                                 GetCommandHandlerRegistrar = (messageType, handlerDelegateTargetedType) => DependencyResolver.Resolve<ICommandHandlerRegistrar>();
      42             :                 }
      43             : 
      44           0 :                 public virtual void Register(params Type[] typesFromAssemblyContainingMessages)
      45             :                 {
      46             :                         var eventHandlerRegistrar = DependencyResolver.Resolve<IEventHandlerRegistrar>();
      47             :                         if (eventHandlerRegistrar != null)
      48             :                                 Register(true, ResolveEventHandlerInterface, true, typesFromAssemblyContainingMessages);
      49             : 
      50             :                         var commandHandlerRegistrar = DependencyResolver.Resolve<ICommandHandlerRegistrar>();
      51             :                         if (commandHandlerRegistrar != null)
      52             :                                 Register(false, ResolveCommandHandlerInterface, false, typesFromAssemblyContainingMessages);
      53             :                 }
      54             : 
      55           0 :                 public virtual void Register(bool trueForEventsFalseForCommands, Func<Type, IEnumerable<Type>> resolveMessageHandlerInterface, bool skipCommandHandlers, params Type[] typesFromAssemblyContainingMessages)
      56             :                 {
      57             :                         foreach (Type typesFromAssemblyContainingMessage in typesFromAssemblyContainingMessages)
      58             :                         {
      59             :                                 Assembly executorsAssembly = typesFromAssemblyContainingMessage.Assembly;
      60             :                                 var executorTypes = executorsAssembly
      61             :                                         .GetTypes()
      62             :                                         .Select(type => new { Type = type, Interfaces = resolveMessageHandlerInterface(type) })
      63             :                                         .Where(type => type.Interfaces != null && type.Interfaces.Any());
      64             : 
      65             :                                 foreach (var executorType in executorTypes)
      66             :                                 {
      67             :                                         foreach (Type @interface in executorType.Interfaces)
      68             :                                         {
      69             :                                                 Type safeExecutorType = executorType.Type;
      70             :                                                 if (typesFromAssemblyContainingMessage.IsGenericType && typesFromAssemblyContainingMessage.Name == typeof(DtoCommandHandler<,>).Name)
      71             :                                                 {
      72             :                                                         if (skipCommandHandlers)
      73             :                                                                 continue;
      74             :                                                         Type[] genericArguments = typesFromAssemblyContainingMessage.GetGenericArguments().Take(2).ToArray();
      75             :                                                         safeExecutorType = safeExecutorType.MakeGenericType(genericArguments.Take(2).ToArray());
      76             :                                                 }
      77             :                                                 InvokeHandler(@interface, trueForEventsFalseForCommands, resolveMessageHandlerInterface, safeExecutorType);
      78             :                                         }
      79             :                                 }
      80             :                         }
      81             :                 }
      82             : 
      83             :                 /// <summary>
      84             :                 /// Extract the <see cref="IHandlerRegistrar.RegisterHandler{TMessage}"/> method from the provided <paramref name="bus"/>
      85             :                 /// Create an <see cref="Action"/> around the provided <paramref name="executorType"/>
      86             :                 /// Then register the created <see cref="Action"/> using the extracted <see cref="IHandlerRegistrar.RegisterHandler{TMessage}"/> method
      87             :                 /// </summary>
      88             :                 /// <param name="executorType">The <see cref="Type"/> of the event handler that will do the handling</param>
      89           1 :                 protected virtual void InvokeHandler(Type @interface, bool trueForEventsFalseForCommands, Func<Type, IEnumerable<Type>> resolveMessageHandlerInterface, Type executorType)
      90             :                 {
      91             :                         MethodInfo registerExecutorMethod = null;
      92             : 
      93             :                         MethodInfo originalRegisterExecutorMethod = (trueForEventsFalseForCommands ? GetEventHandlerRegistrar(null, executorType) : GetCommandHandlerRegistrar(null, executorType))
      94             :                                 .GetType()
      95             :                                 .GetMethods(BindingFlags.Instance | BindingFlags.Public)
      96             :                                 .Where(mi => mi.Name == "RegisterHandler")
      97             :                                 .Where(mi => mi.IsGenericMethod)
      98             :                                 .Where(mi => mi.GetGenericArguments().Count() == 1)
      99             :                                 .Single(mi => mi.GetParameters().Count() == 3);
     100             : 
     101             :                         IList<Type> interfaceGenericArguments = @interface.GetGenericArguments().ToList();
     102             :                         if (interfaceGenericArguments.Count == 2)
     103             :                         {
     104             :                                 Type commandType = interfaceGenericArguments[1];
     105             :                                 registerExecutorMethod = BuildExecutorMethod(originalRegisterExecutorMethod, executorType, commandType);
     106             :                         }
     107             :                         else
     108             :                         {
     109             :                                 foreach (Type commandType in interfaceGenericArguments)
     110             :                                 {
     111             :                                         try
     112             :                                         {
     113             :                                                 registerExecutorMethod = BuildExecutorMethod(originalRegisterExecutorMethod, executorType, commandType);
     114             :                                                 break;
     115             :                                         }
     116             :                                         catch (VerificationException)
     117             :                                         {
     118             :                                         }
     119             :                                         catch (ArgumentException)
     120             :                                         {
     121             :                                         }
     122             :                                 }
     123             :                         }
     124             : 
     125             :                         if (registerExecutorMethod == null)
     126             :                                 throw new InvalidOperationException("No executor method could be compiled for " + @interface.FullName);
     127             : 
     128             :                         HandlerDelegate handlerDelegate = BuildDelegateAction(executorType, resolveMessageHandlerInterface);
     129             : 
     130             :                         InvokeHandlerDelegate(registerExecutorMethod, trueForEventsFalseForCommands, handlerDelegate);
     131             :                 }
     132             : 
     133           0 :                 protected virtual void InvokeHandlerDelegate(MethodInfo registerExecutorMethod, bool trueForEventsFalseForCommands, HandlerDelegate handlerDelegate)
     134             :                 {
     135             :                         Type messageType = null;
     136             :                         bool holdMessageLock;
     137             :                         try
     138             :                         {
     139             :                                 messageType = registerExecutorMethod.GetParameters()[0].ParameterType.GetGenericArguments()[0];
     140             :                                 string messageTypeName = messageType.FullName;
     141             :                                 string configuration = string.Format("{0}<{1}>.HoldMessageLock", handlerDelegate.TargetedType.FullName, messageTypeName);
     142             :                                 // If this cannot be parsed then assume the safe route that this must be required to hold the lock.
     143             :                                 if (!bool.TryParse(DependencyResolver.Resolve<IConfigurationManager>().GetSetting(configuration), out holdMessageLock))
     144             :                                         holdMessageLock = true;
     145             :                         }
     146             :                         catch
     147             :                         {
     148             :                                 holdMessageLock = true;
     149             :                         }
     150             :                         registerExecutorMethod.Invoke(trueForEventsFalseForCommands ? GetEventHandlerRegistrar(messageType, handlerDelegate.TargetedType) : GetCommandHandlerRegistrar(messageType, handlerDelegate.TargetedType), new object[] { handlerDelegate.Delegate, handlerDelegate.TargetedType, holdMessageLock });
     151             :                 }
     152             : 
     153           0 :                 protected virtual HandlerDelegate BuildDelegateAction(Type executorType, Func<Type, IEnumerable<Type>> resolveMessageHandlerInterface)
     154             :                 {
     155             :                         Action<dynamic> handlerDelegate = x =>
     156             :                         {
     157             :                                 dynamic handler = DependencyResolver.Resolve(executorType);
     158             :                                 try
     159             :                                 {
     160             :                                         handler.Handle(x);
     161             :                                 }
     162             :                                 catch (NotImplementedException exception)
     163             :                                 {
     164             :                                         var logger = DependencyResolver.Resolve<ILogger>();
     165             :                                         logger.LogInfo(string.Format("An event message arrived of the type '{0}' went to a handler of type '{1}' but was not implemented.", x.GetType().FullName, handler.GetType().FullName), exception: exception);
     166             :                                 }
     167             :                         };
     168             : 
     169             :                         return new HandlerDelegate { Delegate = handlerDelegate, TargetedType = executorType };
     170             :                 }
     171             : 
     172           0 :                 protected virtual MethodInfo BuildExecutorMethod(MethodInfo originalRegisterExecutorMethod, Type executorType, Type commandType)
     173             :                 {
     174             :                         Type safeCommandType = commandType;
     175             :                         if (safeCommandType.IsGenericType && safeCommandType.Name == typeof(DtoCommand<,>).Name && executorType.IsGenericType && executorType.Name == typeof(DtoCommandHandler<,>).Name)
     176             :                         {
     177             :                                 Type[] genericArguments = executorType.GetGenericArguments().Take(2).ToArray();
     178             :                                 safeCommandType = typeof(DtoCommand<,>).MakeGenericType(genericArguments);
     179             :                         }
     180             : 
     181             :                         return originalRegisterExecutorMethod.MakeGenericMethod(safeCommandType);
     182             :                 }
     183             : 
     184           0 :                 protected virtual IEnumerable<Type> ResolveEventHandlerInterface(Type type)
     185             :                 {
     186             :                         return type
     187             :                                 .GetInterfaces()
     188             :                                 .Where
     189             :                                 (
     190             :                                         @interface =>
     191             :                                                 @interface.IsGenericType &&
     192             :                                                 (
     193             :                                                         @interface.GetGenericTypeDefinition() == typeof(IEventHandler<,>)
     194             :                                                 )
     195             :                                 );
     196             :                 }
     197             : 
     198           0 :                 protected virtual IEnumerable<Type> ResolveCommandHandlerInterface(Type type)
     199             :                 {
     200             :                         return type
     201             :                                 .GetInterfaces()
     202             :                                 .Where
     203             :                                 (
     204             :                                         @interface =>
     205             :                                                 @interface.IsGenericType &&
     206             :                                                 (
     207             :                                                         @interface.GetGenericTypeDefinition() == typeof(ICommandHandler<,>)
     208             :                                                 )
     209             :                                 );
     210             :                 }
     211             :         }
     212             : }

Generated by: LCOV version 1.10