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