Documentation Coverage Report
Current view: top level - Cqrs/Configuration - BusRegistrar.cs Hit Total Coverage
Version: 2.2 Artefacts: 10 10 100.0 %
Date: 2017-09-22

          Line data    Source code
       1             : #region Copyright
       2             : // // -----------------------------------------------------------------------
       3             : // // <copyright company="Chinchilla Software Limited">
       4             : // //   Copyright Chinchilla Software 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             : using Cqrs.Messages;
      19             : 
      20             : namespace Cqrs.Configuration
      21             : {
      22             :         /// <summary>
      23             :         /// Triggers the <see cref="IEventHandlerRegistrar"/> and <see cref="ICommandHandlerRegistrar"/> if they are registered in the <see cref="IDependencyResolver"/>.
      24             :         /// </summary>
      25             :         public class BusRegistrar
      26           1 :         {
      27             :                 /// <summary>
      28             :                 /// Gets or set the <see cref="IDependencyResolver"/>.
      29             :                 /// </summary>
      30             :                 protected IDependencyResolver DependencyResolver { get; private set; }
      31             : 
      32             :                 /// <summary>
      33             :                 /// A <see cref="Func{Type, Type, THandlerRegistrar}"/> to use in-place of <see cref="IEventHandlerRegistrar"/>
      34             :                 /// </summary>
      35             :                 public static Func<Type, Type, IHandlerRegistrar> GetEventHandlerRegistrar { get; set; }
      36             : 
      37             :                 /// <summary>
      38             :                 /// A <see cref="Func{Type, Type, THandlerRegistrar}"/> to use in-place of <see cref="ICommandHandlerRegistrar"/>
      39             :                 /// </summary>
      40             :                 public static Func<Type, Type, IHandlerRegistrar> GetCommandHandlerRegistrar { get; set; }
      41             : 
      42             :                 /// <summary>
      43             :                 /// Instantiates a new instance of <see cref="BusRegistrar"/>.
      44             :                 /// </summary>
      45           1 :                 public BusRegistrar(IDependencyResolver dependencyResolver)
      46             :                 {
      47             :                         if(dependencyResolver == null)
      48             :                                 throw new ArgumentNullException("dependencyResolver");
      49             : 
      50             :                         DependencyResolver = dependencyResolver;
      51             :                         if (GetEventHandlerRegistrar == null)
      52             :                                 GetEventHandlerRegistrar = (messageType, handlerDelegateTargetedType) => DependencyResolver.Resolve<IEventHandlerRegistrar>();
      53             :                         if (GetCommandHandlerRegistrar == null)
      54             :                                 GetCommandHandlerRegistrar = (messageType, handlerDelegateTargetedType) => DependencyResolver.Resolve<ICommandHandlerRegistrar>();
      55             :                 }
      56             : 
      57             :                 /// <summary>
      58             :                 /// Registers all <see cref="IEventHandler"/> and <see cref="ICommandHandler{TAuthenticationToken,TCommand}"/> instances found in the <see cref="Assembly"/> for each <see cref="Type"/> in <paramref name="typesFromAssemblyContainingMessages"/>.
      59             :                 /// </summary>
      60             :                 /// <param name="typesFromAssemblyContainingMessages">A collection of <see cref="Type"/> to track back to their containing <see cref="Assembly"/> and scan.</param>
      61           1 :                 public virtual void Register(params Type[] typesFromAssemblyContainingMessages)
      62             :                 {
      63             :                         var eventHandlerRegistrar = DependencyResolver.Resolve<IEventHandlerRegistrar>();
      64             :                         if (eventHandlerRegistrar != null)
      65             :                                 Register(true, ResolveEventHandlerInterface, true, typesFromAssemblyContainingMessages);
      66             : 
      67             :                         var commandHandlerRegistrar = DependencyResolver.Resolve<ICommandHandlerRegistrar>();
      68             :                         if (commandHandlerRegistrar != null)
      69             :                                 Register(false, ResolveCommandHandlerInterface, false, typesFromAssemblyContainingMessages);
      70             :                 }
      71             : 
      72             :                 /// <summary>
      73             :                 /// Registers all <see cref="IHandler"/> instances found in the <see cref="Assembly"/> for each <see cref="Type"/> in <paramref name="typesFromAssemblyContainingMessages"/>.
      74             :                 /// </summary>
      75             :                 /// <param name="trueForEventsFalseForCommands">Indicates if this is registers <see cref="IEventHandler"/> or <see cref="ICommandHandler{TAuthenticationToken,TCommand}"/>.</param>
      76             :                 /// <param name="resolveMessageHandlerInterface"><see cref="ResolveEventHandlerInterface"/> or <see cref="ResolveCommandHandlerInterface"/></param>
      77             :                 /// <param name="skipCommandHandlers">Indicates if registering of <see cref="ICommandHandler{TAuthenticationToken,TCommand}"/> is enabled.</param>
      78             :                 /// <param name="typesFromAssemblyContainingMessages">A collection of <see cref="Type"/> to track back to their containing <see cref="Assembly"/> and scan.</param>
      79           1 :                 public virtual void Register(bool trueForEventsFalseForCommands, Func<Type, IEnumerable<Type>> resolveMessageHandlerInterface, bool skipCommandHandlers, params Type[] typesFromAssemblyContainingMessages)
      80             :                 {
      81             :                         foreach (Type typesFromAssemblyContainingMessage in typesFromAssemblyContainingMessages)
      82             :                         {
      83             :                                 Assembly executorsAssembly = typesFromAssemblyContainingMessage.Assembly;
      84             :                                 var executorTypes = executorsAssembly
      85             :                                         .GetTypes()
      86             :                                         .Select(type => new { Type = type, Interfaces = resolveMessageHandlerInterface(type) })
      87             :                                         .Where(type => type.Interfaces != null && type.Interfaces.Any());
      88             : 
      89             :                                 foreach (var executorType in executorTypes)
      90             :                                 {
      91             :                                         foreach (Type @interface in executorType.Interfaces)
      92             :                                         {
      93             :                                                 Type safeExecutorType = executorType.Type;
      94             :                                                 if (typesFromAssemblyContainingMessage.IsGenericType && typesFromAssemblyContainingMessage.Name == typeof(DtoCommandHandler<,>).Name)
      95             :                                                 {
      96             :                                                         if (skipCommandHandlers)
      97             :                                                                 continue;
      98             :                                                         Type[] genericArguments = typesFromAssemblyContainingMessage.GetGenericArguments().Take(2).ToArray();
      99             :                                                         safeExecutorType = safeExecutorType.MakeGenericType(genericArguments.Take(2).ToArray());
     100             :                                                 }
     101             :                                                 InvokeHandler(@interface, trueForEventsFalseForCommands, resolveMessageHandlerInterface, safeExecutorType);
     102             :                                         }
     103             :                                 }
     104             :                         }
     105             :                 }
     106             : 
     107             :                 /// <summary>
     108             :                 /// Extract the <see cref="IHandlerRegistrar.RegisterHandler{TMessage}(System.Action{TMessage},System.Type,bool)"/> method of <see cref="GetEventHandlerRegistrar"/> or <see cref="GetCommandHandlerRegistrar"/>.
     109             :                 /// Create an <see cref="Action"/> around the provided <paramref name="executorType"/>
     110             :                 /// Then register the created <see cref="Action"/> using the extracted <see cref="IHandlerRegistrar.RegisterHandler{TMessage}(System.Action{TMessage},System.Type,bool)"/> method
     111             :                 /// </summary>
     112             :                 /// <param name="interface">The <see cref="Type"/> of <see cref="IHandler"/></param>
     113             :                 /// <param name="trueForEventsFalseForCommands">Indicates if this is registers <see cref="IEventHandler"/> or <see cref="ICommandHandler{TAuthenticationToken,TCommand}"/>.</param>
     114             :                 /// <param name="resolveMessageHandlerInterface"><see cref="ResolveEventHandlerInterface"/> or <see cref="ResolveCommandHandlerInterface"/></param>
     115             :                 /// <param name="executorType">The <see cref="Type"/> of the event handler that will do the handling</param>
     116           1 :                 protected virtual void InvokeHandler(Type @interface, bool trueForEventsFalseForCommands, Func<Type, IEnumerable<Type>> resolveMessageHandlerInterface, Type executorType)
     117             :                 {
     118             :                         MethodInfo registerExecutorMethod = null;
     119             : 
     120             :                         MethodInfo originalRegisterExecutorMethod = (trueForEventsFalseForCommands ? GetEventHandlerRegistrar(null, executorType) : GetCommandHandlerRegistrar(null, executorType))
     121             :                                 .GetType()
     122             :                                 .GetMethods(BindingFlags.Instance | BindingFlags.Public)
     123             :                                 .Where(mi => mi.Name == "RegisterHandler")
     124             :                                 .Where(mi => mi.IsGenericMethod)
     125             :                                 .Where(mi => mi.GetGenericArguments().Count() == 1)
     126             :                                 .Single(mi => mi.GetParameters().Count() == 3);
     127             : 
     128             :                         IList<Type> interfaceGenericArguments = @interface.GetGenericArguments().ToList();
     129             :                         if (interfaceGenericArguments.Count == 2)
     130             :                         {
     131             :                                 Type commandType = interfaceGenericArguments[1];
     132             :                                 Type[] genericArguments = commandType.GetGenericArguments();
     133             :                                 if (genericArguments.Length == 1)
     134             :                                         if (typeof (IEvent<>).MakeGenericType(genericArguments.First()) == commandType)
     135             :                                                 return;
     136             : 
     137             :                                 registerExecutorMethod = BuildExecutorMethod(originalRegisterExecutorMethod, executorType, commandType);
     138             :                         }
     139             :                         else
     140             :                         {
     141             :                                 foreach (Type commandType in interfaceGenericArguments)
     142             :                                 {
     143             :                                         try
     144             :                                         {
     145             :                                                 registerExecutorMethod = BuildExecutorMethod(originalRegisterExecutorMethod, executorType, commandType);
     146             :                                                 break;
     147             :                                         }
     148             :                                         catch (VerificationException)
     149             :                                         {
     150             :                                         }
     151             :                                         catch (ArgumentException)
     152             :                                         {
     153             :                                         }
     154             :                                 }
     155             :                         }
     156             : 
     157             :                         if (registerExecutorMethod == null)
     158             :                                 throw new InvalidOperationException("No executor method could be compiled for " + @interface.FullName);
     159             : 
     160             :                         HandlerDelegate handlerDelegate = BuildDelegateAction(executorType, resolveMessageHandlerInterface);
     161             : 
     162             :                         InvokeHandlerDelegate(registerExecutorMethod, trueForEventsFalseForCommands, handlerDelegate);
     163             :                 }
     164             : 
     165             :                 /// <summary>
     166             :                 /// Invokes <paramref name="handlerDelegate"/>, fetching the corresponding "HoldMessageLock" configuration setting 
     167             :                 /// </summary>
     168             :                 /// <param name="registerExecutorMethod">The <see cref="MethodInfo"/> to use to invoke <paramref name="handlerDelegate"/>.</param>
     169             :                 /// <param name="trueForEventsFalseForCommands">Indicates if this is registers <see cref="IEventHandler"/> or <see cref="ICommandHandler{TAuthenticationToken,TCommand}"/>.</param>
     170             :                 /// <param name="handlerDelegate">The actual <see cref="HandlerDelegate"/> that gets executed.</param>
     171           1 :                 protected virtual void InvokeHandlerDelegate(MethodInfo registerExecutorMethod, bool trueForEventsFalseForCommands, HandlerDelegate handlerDelegate)
     172             :                 {
     173             :                         Type messageType = null;
     174             :                         bool holdMessageLock;
     175             :                         try
     176             :                         {
     177             :                                 messageType = registerExecutorMethod.GetParameters()[0].ParameterType.GetGenericArguments()[0];
     178             :                                 string messageTypeName = messageType.FullName;
     179             :                                 string configuration = string.Format("{0}<{1}>.HoldMessageLock", handlerDelegate.TargetedType.FullName, messageTypeName);
     180             :                                 // If this cannot be parsed then assume the safe route that this must be required to hold the lock.
     181             :                                 if (!bool.TryParse(DependencyResolver.Resolve<IConfigurationManager>().GetSetting(configuration), out holdMessageLock))
     182             :                                         holdMessageLock = true;
     183             :                         }
     184             :                         catch
     185             :                         {
     186             :                                 holdMessageLock = true;
     187             :                         }
     188             :                         registerExecutorMethod.Invoke(trueForEventsFalseForCommands ? GetEventHandlerRegistrar(messageType, handlerDelegate.TargetedType) : GetCommandHandlerRegistrar(messageType, handlerDelegate.TargetedType), new object[] { handlerDelegate.Delegate, handlerDelegate.TargetedType, holdMessageLock });
     189             :                 }
     190             : 
     191             :                 /// <summary>
     192             :                 /// Builds a <see cref="HandlerDelegate"/> that will resolve the provided <paramref name="executorType"/> and invoke the Handle method, when executed.
     193             :                 /// </summary>
     194             :                 /// <param name="executorType">The type of <see cref="IHandler"/> to resolve.></param>
     195             :                 /// <param name="resolveMessageHandlerInterface">Not used.</param>
     196           1 :                 protected virtual HandlerDelegate BuildDelegateAction(Type executorType, Func<Type, IEnumerable<Type>> resolveMessageHandlerInterface)
     197             :                 {
     198             :                         Action<dynamic> handlerDelegate = x =>
     199             :                         {
     200             :                                 dynamic handler = DependencyResolver.Resolve(executorType);
     201             :                                 try
     202             :                                 {
     203             :                                         handler.Handle(x);
     204             :                                 }
     205             :                                 catch (NotImplementedException exception)
     206             :                                 {
     207             :                                         var logger = DependencyResolver.Resolve<ILogger>();
     208             :                                         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);
     209             :                                 }
     210             :                         };
     211             : 
     212             :                         return new HandlerDelegate { Delegate = handlerDelegate, TargetedType = executorType };
     213             :                 }
     214             : 
     215             :                 /// <summary>
     216             :                 /// Builds a method replacing the generic type with <paramref name="commandType"/>.
     217             :                 /// </summary>
     218           1 :                 protected virtual MethodInfo BuildExecutorMethod(MethodInfo originalRegisterExecutorMethod, Type executorType, Type commandType)
     219             :                 {
     220             :                         Type safeCommandType = commandType;
     221             :                         if (safeCommandType.IsGenericType && safeCommandType.Name == typeof(DtoCommand<,>).Name && executorType.IsGenericType && executorType.Name == typeof(DtoCommandHandler<,>).Name)
     222             :                         {
     223             :                                 Type[] genericArguments = executorType.GetGenericArguments().Take(2).ToArray();
     224             :                                 safeCommandType = typeof(DtoCommand<,>).MakeGenericType(genericArguments);
     225             :                         }
     226             : 
     227             :                         return originalRegisterExecutorMethod.MakeGenericMethod(safeCommandType);
     228             :                 }
     229             : 
     230             :                 /// <summary>
     231             :                 /// Finds all <see cref="Type"/> that implement <see cref="IEventHandler{TAuthenticationToken,TEvent}"/> that are implemented by <paramref name="type"/>.
     232             :                 /// </summary>
     233             :                 /// <param name="type">The <see cref="Type"/> to find all <see cref="IEventHandler{TAuthenticationToken,TEvent}"/> of.</param>
     234           1 :                 protected virtual IEnumerable<Type> ResolveEventHandlerInterface(Type type)
     235             :                 {
     236             :                         return type
     237             :                                 .GetInterfaces()
     238             :                                 .Where
     239             :                                 (
     240             :                                         @interface =>
     241             :                                                 @interface.IsGenericType &&
     242             :                                                 (
     243             :                                                         @interface.GetGenericTypeDefinition() == typeof(IEventHandler<,>)
     244             :                                                 )
     245             :                                 );
     246             :                 }
     247             : 
     248             :                 /// <summary>
     249             :                 /// Finds all <see cref="Type"/> that implement <see cref="ICommandHandler{TAuthenticationToken,TCommand}"/> that are implemented by <paramref name="type"/>.
     250             :                 /// </summary>
     251             :                 /// <param name="type">The <see cref="Type"/> to find all <see cref="ICommandHandler{TAuthenticationToken,TCommand}"/> of.</param>
     252           1 :                 protected virtual IEnumerable<Type> ResolveCommandHandlerInterface(Type type)
     253             :                 {
     254             :                         return type
     255             :                                 .GetInterfaces()
     256             :                                 .Where
     257             :                                 (
     258             :                                         @interface =>
     259             :                                                 @interface.IsGenericType &&
     260             :                                                 (
     261             :                                                         @interface.GetGenericTypeDefinition() == typeof(ICommandHandler<,>)
     262             :                                                 )
     263             :                                 );
     264             :                 }
     265             :         }
     266             : }

Generated by: LCOV version 1.10