Line data Source code
1 : using System;
2 : using System.Collections.Concurrent;
3 : using System.Collections.Generic;
4 : using System.Linq;
5 : using Akka.Actor;
6 : using Cqrs.Akka.Configuration;
7 : using Cqrs.Akka.Domain;
8 : using Cqrs.Domain;
9 : using Cqrs.Domain.Factories;
10 : using Cqrs.Ninject.Configuration;
11 : using Ninject;
12 :
13 : namespace Cqrs.Ninject.Akka
14 : {
15 : public class AkkaNinjectDependencyResolver
16 : : NinjectDependencyResolver
17 : , IAkkaAggregateResolver
18 : , IHandlerResolver
19 0 : {
20 : protected global::Akka.DI.Ninject.NinjectDependencyResolver RawAkkaNinjectDependencyResolver { get; set; }
21 :
22 : protected ActorSystem AkkaSystem { get; private set; }
23 :
24 : protected IDictionary<Type, IActorRef> AkkaActors { get; private set; }
25 :
26 : protected IAggregateFactory AggregateFactory { get; private set; }
27 :
28 0 : public AkkaNinjectDependencyResolver(IKernel kernel, ActorSystem system)
29 : : base(kernel)
30 : {
31 : RawAkkaNinjectDependencyResolver = new global::Akka.DI.Ninject.NinjectDependencyResolver(kernel, AkkaSystem = system);
32 : AkkaActors = new ConcurrentDictionary<Type, IActorRef>();
33 : AggregateFactory = Resolve<IAggregateFactory>();
34 : }
35 :
36 0 : protected override void BindDependencyResolver()
37 : {
38 : bool isDependencyResolverBound = Kernel.GetBindings(typeof(Cqrs.Configuration.IDependencyResolver)).Any();
39 : if (isDependencyResolverBound)
40 : Kernel.Unbind<Cqrs.Configuration.IDependencyResolver>();
41 : Kernel.Bind<Cqrs.Configuration.IDependencyResolver>()
42 : .ToConstant(this)
43 : .InSingletonScope();
44 :
45 : isDependencyResolverBound = Kernel.GetBindings(typeof(IAkkaAggregateResolver)).Any();
46 : if (!isDependencyResolverBound)
47 : {
48 : Kernel.Bind<IAkkaAggregateResolver>()
49 : .ToConstant(this)
50 : .InSingletonScope();
51 : }
52 : }
53 :
54 : /// <summary>
55 : /// Starts the <see cref="AkkaNinjectDependencyResolver"/>
56 : /// </summary>
57 : /// <remarks>
58 : /// this exists to the static constructor can be triggered.
59 : /// </remarks>
60 1 : public new static void Start(IKernel kernel = null, bool prepareProvidedKernel = false)
61 : {
62 : // Create the ActorSystem and Dependency Resolver
63 : ActorSystem system = ActorSystem.Create("Cqrs");
64 :
65 : Func<IKernel, NinjectDependencyResolver> originalDependencyResolverCreator = DependencyResolverCreator;
66 : Func<IKernel, NinjectDependencyResolver> dependencyResolverCreator = container => new AkkaNinjectDependencyResolver(container, system);
67 : if (originalDependencyResolverCreator == null)
68 : DependencyResolverCreator = dependencyResolverCreator;
69 : else
70 : DependencyResolverCreator = container =>
71 : {
72 : originalDependencyResolverCreator(container);
73 : return dependencyResolverCreator(container);
74 : };
75 :
76 : NinjectDependencyResolver.Start(kernel, prepareProvidedKernel);
77 : }
78 :
79 0 : public static void Stop()
80 : {
81 : var di = Current as AkkaNinjectDependencyResolver;
82 : if (di != null)
83 : di.AkkaSystem.Shutdown();
84 : }
85 :
86 : #region Overrides of NinjectDependencyResolver
87 :
88 1 : public override object Resolve(Type serviceType)
89 : {
90 : return Resolve(serviceType, null);
91 : }
92 :
93 : #endregion
94 :
95 : #region Implementation of IAkkaAggregateResolver
96 :
97 0 : public virtual IActorRef ResolveActor<TAggregate, TAuthenticationToken>(Guid rsn)
98 : where TAggregate : IAggregateRoot<TAuthenticationToken>
99 : {
100 : return (IActorRef)AkkaResolve(typeof(TAggregate), rsn, true);
101 : }
102 :
103 0 : public IActorRef ResolveActor<T>()
104 : {
105 : return (IActorRef)AkkaResolve(typeof(T), null, true);
106 : }
107 :
108 : #endregion
109 :
110 0 : protected virtual object RootResolve(Type serviceType)
111 : {
112 : return base.Resolve(serviceType);
113 : }
114 :
115 0 : public virtual object Resolve(Type serviceType, object rsn)
116 : {
117 : return AkkaResolve(serviceType, rsn);
118 : }
119 :
120 0 : public virtual object AkkaResolve(Type serviceType, object rsn, bool isAForcedActorSearch = false)
121 : {
122 : IActorRef actorReference;
123 : try
124 : {
125 : if (AkkaActors.TryGetValue(serviceType, out actorReference))
126 : return actorReference;
127 : if (!isAForcedActorSearch)
128 : return base.Resolve(serviceType);
129 : }
130 : catch (ActivationException) { throw; }
131 : catch ( /*ActorInitialization*/Exception) { }
132 :
133 : Props properties;
134 : Type typeToTest = serviceType;
135 : while (typeToTest != null)
136 : {
137 : Type[] types = typeToTest.GenericTypeArguments;
138 : if (types.Length == 1)
139 : {
140 : Type aggregateType = typeof (AkkaAggregateRoot<>).MakeGenericType(typeToTest.GenericTypeArguments.Single());
141 : if (typeToTest == aggregateType)
142 : {
143 : typeToTest = aggregateType;
144 : break;
145 : }
146 : }
147 : typeToTest = typeToTest.BaseType;
148 : }
149 :
150 : // This sorts out an out-of-order binder issue
151 : if (AggregateFactory == null)
152 : AggregateFactory = Resolve<IAggregateFactory>();
153 :
154 : if (typeToTest == null || !(typeToTest).IsAssignableFrom(serviceType))
155 : properties = Props.Create(() => (ActorBase)RootResolve(serviceType));
156 : else
157 : properties = Props.Create(() => (ActorBase) AggregateFactory.CreateAggregate(serviceType, rsn as Guid?, false));
158 : string actorName = serviceType.FullName.Replace("`", string.Empty);
159 : int index = actorName.IndexOf("[[", StringComparison.Ordinal);
160 : if (index > -1)
161 : actorName = actorName.Substring(0, index);
162 : actorReference = AkkaSystem.ActorOf(properties, string.Format("{0}~{1}", actorName, rsn));
163 : AkkaActors.Add(serviceType, actorReference);
164 : return actorReference;
165 : }
166 : }
167 : }
|