From 48c011dd640a75d2623294e5fb2c34b70806e85e Mon Sep 17 00:00:00 2001 From: Olivier Coanet Date: Fri, 15 Aug 2014 18:09:14 +0200 Subject: [PATCH 1/2] wip on SubscriptionModeAttribute --- src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj | 3 +++ .../Dispatch/DispatchMessages/ManualCommand.cs | 9 +++++++++ .../DispatchMessages/ManualCommandHandler.cs | 7 +++++++ ...outableCommandHandlerWithAutoSubscription.cs | 10 ++++++++++ src/Abc.Zebus/Abc.Zebus.csproj | 2 ++ src/Abc.Zebus/SubscriptionMode.cs | 16 ++++++++++++++++ src/Abc.Zebus/SubscriptionModeAttribute.cs | 17 +++++++++++++++++ 7 files changed, 64 insertions(+) create mode 100644 src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommand.cs create mode 100644 src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommandHandler.cs create mode 100644 src/Abc.Zebus.Tests/Dispatch/DispatchMessages/RoutableCommandHandlerWithAutoSubscription.cs create mode 100644 src/Abc.Zebus/SubscriptionMode.cs create mode 100644 src/Abc.Zebus/SubscriptionModeAttribute.cs diff --git a/src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj b/src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj index 950580d..ec3cb19 100644 --- a/src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj +++ b/src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj @@ -100,6 +100,9 @@ + + + diff --git a/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommand.cs b/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommand.cs new file mode 100644 index 0000000..254f3eb --- /dev/null +++ b/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommand.cs @@ -0,0 +1,9 @@ +using ProtoBuf; + +namespace Abc.Zebus.Tests.Dispatch.DispatchMessages +{ + [ProtoContract] + public class ManualCommand : ICommand + { + } +} \ No newline at end of file diff --git a/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommandHandler.cs b/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommandHandler.cs new file mode 100644 index 0000000..3f8b2b9 --- /dev/null +++ b/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/ManualCommandHandler.cs @@ -0,0 +1,7 @@ +namespace Abc.Zebus.Tests.Dispatch.DispatchMessages +{ + public class ManualCommandHandler + { + + } +} \ No newline at end of file diff --git a/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/RoutableCommandHandlerWithAutoSubscription.cs b/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/RoutableCommandHandlerWithAutoSubscription.cs new file mode 100644 index 0000000..828870e --- /dev/null +++ b/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/RoutableCommandHandlerWithAutoSubscription.cs @@ -0,0 +1,10 @@ +namespace Abc.Zebus.Tests.Dispatch.DispatchMessages +{ + [SubscriptionMode(SubscriptionMode.Auto)] + public class RoutableCommandHandlerWithAutoSubscription : IMessageHandler + { + public void Handle(RoutableCommand message) + { + } + } +} \ No newline at end of file diff --git a/src/Abc.Zebus/Abc.Zebus.csproj b/src/Abc.Zebus/Abc.Zebus.csproj index c40ac71..0df0f99 100644 --- a/src/Abc.Zebus/Abc.Zebus.csproj +++ b/src/Abc.Zebus/Abc.Zebus.csproj @@ -178,6 +178,8 @@ + + diff --git a/src/Abc.Zebus/SubscriptionMode.cs b/src/Abc.Zebus/SubscriptionMode.cs new file mode 100644 index 0000000..b5527f6 --- /dev/null +++ b/src/Abc.Zebus/SubscriptionMode.cs @@ -0,0 +1,16 @@ +namespace Abc.Zebus +{ + public enum SubscriptionMode + { + /// + /// A subscription for the handler message type will be automatically performed on startup. + /// This is the default mode for non-routable messages. + /// + Auto, + /// + /// The subscription for the handler message type must be manually performed with IBus.Subscribe. + /// This is the default mode for routable messages. + /// + Manual, + } +} \ No newline at end of file diff --git a/src/Abc.Zebus/SubscriptionModeAttribute.cs b/src/Abc.Zebus/SubscriptionModeAttribute.cs new file mode 100644 index 0000000..508a88d --- /dev/null +++ b/src/Abc.Zebus/SubscriptionModeAttribute.cs @@ -0,0 +1,17 @@ +using System; + +namespace Abc.Zebus +{ + /// + /// Specifies the subscription mode of the target message handler. + /// + public class SubscriptionModeAttribute : Attribute + { + public SubscriptionModeAttribute(SubscriptionMode subscriptionMode) + { + SubscriptionMode = subscriptionMode; + } + + public SubscriptionMode SubscriptionMode { get; private set; } + } +} \ No newline at end of file From 6b9f05e6b8431c413726a21a05899cd0b90d740d Mon Sep 17 00:00:00 2001 From: Olivier Coanet Date: Tue, 19 Aug 2014 18:09:23 +0200 Subject: [PATCH 2/2] SubscriptionModeAttribute implemented --- src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj | 1 - ...tableCommandHandlerWithAutoSubscription.cs | 10 ----- .../SyncMessageHandlerInvokerLoaderTests.cs | 44 ++++++++++++++++++- .../Dispatch/MessageHandlerInvoker.cs | 7 ++- .../Scan/MessageHandlerInvokerLoader.cs | 25 ++++++++--- 5 files changed, 65 insertions(+), 22 deletions(-) delete mode 100644 src/Abc.Zebus.Tests/Dispatch/DispatchMessages/RoutableCommandHandlerWithAutoSubscription.cs diff --git a/src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj b/src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj index ec3cb19..5ced311 100644 --- a/src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj +++ b/src/Abc.Zebus.Tests/Abc.Zebus.Tests.csproj @@ -102,7 +102,6 @@ - diff --git a/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/RoutableCommandHandlerWithAutoSubscription.cs b/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/RoutableCommandHandlerWithAutoSubscription.cs deleted file mode 100644 index 828870e..0000000 --- a/src/Abc.Zebus.Tests/Dispatch/DispatchMessages/RoutableCommandHandlerWithAutoSubscription.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace Abc.Zebus.Tests.Dispatch.DispatchMessages -{ - [SubscriptionMode(SubscriptionMode.Auto)] - public class RoutableCommandHandlerWithAutoSubscription : IMessageHandler - { - public void Handle(RoutableCommand message) - { - } - } -} \ No newline at end of file diff --git a/src/Abc.Zebus.Tests/Scan/SyncMessageHandlerInvokerLoaderTests.cs b/src/Abc.Zebus.Tests/Scan/SyncMessageHandlerInvokerLoaderTests.cs index c8e57a8..399d14c 100644 --- a/src/Abc.Zebus.Tests/Scan/SyncMessageHandlerInvokerLoaderTests.cs +++ b/src/Abc.Zebus.Tests/Scan/SyncMessageHandlerInvokerLoaderTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Abc.Zebus.Dispatch; +using Abc.Zebus.Routing; using Abc.Zebus.Scan; using Abc.Zebus.Testing.Extensions; using Abc.Zebus.Util; @@ -16,9 +17,27 @@ public class SyncMessageHandlerInvokerLoaderTests public void should_load_queue_name() { var invokerLoader = new SyncMessageHandlerInvokerLoader(new Container()); - var invokers = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType()).ToList(); + var invoker = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType()).ExpectedSingle(); - invokers[0].DispatchQueueName.ShouldEqual("DispatchQueue1"); + invoker.DispatchQueueName.ShouldEqual("DispatchQueue1"); + } + + [Test] + public void should_switch_to_manual_subscription_mode_when_specified() + { + var invokerLoader = new SyncMessageHandlerInvokerLoader(new Container()); + var invoker = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType()).ExpectedSingle(); + + invoker.ShouldBeSubscribedOnStartup.ShouldBeFalse(); + } + + [Test] + public void should_switch_to_auto_subscription_mode_when_specified() + { + var invokerLoader = new SyncMessageHandlerInvokerLoader(new Container()); + var invoker = invokerLoader.LoadMessageHandlerInvokers(TypeSource.FromType()).ExpectedSingle(); + + invoker.ShouldBeSubscribedOnStartup.ShouldBeTrue(); } [Test] @@ -43,6 +62,11 @@ public class FakeMessage2 : IMessage { } + [Routable] + public class FakeRoutableMessage : IMessage + { + } + public class FakeHandler : IMessageHandler, IMessageHandler { public void Handle(FakeMessage message) @@ -71,5 +95,21 @@ public void Handle(FakeMessage message) { } } + + [SubscriptionMode(SubscriptionMode.Manual)] + public class FakeHandlerWithManualSubscriptionMode : IMessageHandler + { + public void Handle(FakeMessage message) + { + } + } + + [SubscriptionMode(SubscriptionMode.Auto)] + public class FakeRoutableHandlerWithAutoSubscriptionMode : IMessageHandler + { + public void Handle(FakeRoutableMessage message) + { + } + } } } \ No newline at end of file diff --git a/src/Abc.Zebus/Dispatch/MessageHandlerInvoker.cs b/src/Abc.Zebus/Dispatch/MessageHandlerInvoker.cs index 32534d9..84d79b5 100644 --- a/src/Abc.Zebus/Dispatch/MessageHandlerInvoker.cs +++ b/src/Abc.Zebus/Dispatch/MessageHandlerInvoker.cs @@ -44,9 +44,12 @@ public virtual Task InvokeMessageHandlerAsync(IMessageHandlerInvocation invocati return new Task(() => InvokeMessageHandler(invocation), TaskCreationOptions.HideScheduler); } - protected internal static bool MessageShouldBeSubscribedOnStartup(Type messageType, bool isNoScanHandler = false) + protected internal static bool MessageShouldBeSubscribedOnStartup(Type messageType, SubscriptionMode? subscriptionMode = null) { - return !isNoScanHandler && !Attribute.IsDefined(messageType, typeof(Routable)); + if (subscriptionMode != null) + return subscriptionMode == SubscriptionMode.Auto; + + return !Attribute.IsDefined(messageType, typeof(Routable)); } protected object CreateHandler(IContainer container, MessageContext messageContext) diff --git a/src/Abc.Zebus/Scan/MessageHandlerInvokerLoader.cs b/src/Abc.Zebus/Scan/MessageHandlerInvokerLoader.cs index 7cb672c..3d4cfdd 100644 --- a/src/Abc.Zebus/Scan/MessageHandlerInvokerLoader.cs +++ b/src/Abc.Zebus/Scan/MessageHandlerInvokerLoader.cs @@ -24,14 +24,13 @@ protected MessageHandlerInvokerLoader(IContainer container, Type genericHandlerT public IEnumerable LoadMessageHandlerInvokers(TypeSource typeSource) { - foreach (var type in typeSource.GetTypes()) + foreach (var handlerType in typeSource.GetTypes()) { - if (!type.IsClass || type.IsAbstract || !type.IsVisible || !_handlerType.IsAssignableFrom(type)) + if (!handlerType.IsClass || handlerType.IsAbstract || !handlerType.IsVisible || !_handlerType.IsAssignableFrom(handlerType)) continue; - var isNoScanHandler = Attribute.IsDefined(type, typeof(NoScanAttribute)); - - var interfaces = type.GetInterfaces(); + var subscriptionMode = GetExplicitSubscriptionMode(handlerType); + var interfaces = handlerType.GetInterfaces(); var excludedMessageTypes = interfaces.Where(IsExtendedMessageHandlerInterface) .Select(handleInterface => handleInterface.GetGenericArguments()[0]) @@ -44,13 +43,25 @@ public IEnumerable LoadMessageHandlerInvokers(TypeSource if (excludedMessageTypes.Contains(messageType)) continue; - var shouldBeSubscribedOnStartup = MessageHandlerInvoker.MessageShouldBeSubscribedOnStartup(messageType, isNoScanHandler); - var invoker = BuildMessageHandlerInvoker(type, messageType, shouldBeSubscribedOnStartup); + var shouldBeSubscribedOnStartup = MessageHandlerInvoker.MessageShouldBeSubscribedOnStartup(messageType, subscriptionMode); + var invoker = BuildMessageHandlerInvoker(handlerType, messageType, shouldBeSubscribedOnStartup); yield return invoker; } } } + private SubscriptionMode? GetExplicitSubscriptionMode(Type handlerType) + { + var subscriptionModeAttribute = (SubscriptionModeAttribute)Attribute.GetCustomAttribute(handlerType, typeof(SubscriptionModeAttribute)); + if (subscriptionModeAttribute != null) + return subscriptionModeAttribute.SubscriptionMode; + + var isNoScanHandler = Attribute.IsDefined(handlerType, typeof(NoScanAttribute)); + if (isNoScanHandler) + return SubscriptionMode.Manual; + + return null; + } protected abstract IMessageHandlerInvoker BuildMessageHandlerInvoker(Type handlerType, Type messageType, bool shouldBeSubscribedOnStartup);