1 /**
2  * Skadi.d Web Framework
3  *
4  * Forked from: https://github.com/mbierlee/poodinis
5  * Authors:  Mike Bierlee, Faianca
6  * Copyright: Copyright (c) 2015  Mike Bierlee, Faianca
7  * License: MIT License, see LICENSE
8  */
9 module skadi.container.registration;
10 
11 import skadi.container.interfaces;
12 
13 debug {
14 	import std.stdio;
15 	import std.string;
16 }
17 
18 class Registration
19 {
20 	private TypeInfo _registeredType = null;
21 	private TypeInfo_Class _instantiatableType = null;
22 	private Registration linkedRegistration;
23 
24 	public @property registeredType()
25 	{
26 		return _registeredType;
27 	}
28 
29 	public @property instantiatableType()
30 	{
31 		return _instantiatableType;
32 	}
33 
34 	public CreationScope registationScope = null;
35 
36 	this(TypeInfo registeredType, TypeInfo_Class instantiatableType)
37 	{
38 		this._registeredType = registeredType;
39 		this._instantiatableType = instantiatableType;
40 	}
41 
42 	public Object getInstance(InstantiationContext context = new InstantiationContext())
43 	{
44 		if (linkedRegistration !is null) {
45 			return linkedRegistration.getInstance(context);
46 		}
47 
48 
49 		if (registationScope is null) {
50 			throw new NoScopeDefinedException(registeredType);
51 		}
52 
53 		return registationScope.getInstance();
54 	}
55 
56 	public Registration linkTo(Registration registration)
57 	{
58 		this.linkedRegistration = registration;
59 		return this;
60 	}
61 }
62 
63 class NoScopeDefinedException : Exception
64 {
65 	this(TypeInfo type) {
66 		super("No scope defined for registration of type " ~ type.toString());
67 	}
68 }
69 
70 
71 class NullScope : CreationScope
72 {
73 	public Object getInstance()
74 	{
75 		debug(skadiVerbose) {
76 			writeln("DEBUG: No instance created (NullScope)");
77 		}
78 		return null;
79 	}
80 }
81 
82 class SingleInstanceScope : CreationScope
83 {
84 	TypeInfo_Class instantiatableType = null;
85 	Object instance = null;
86 
87 	this(TypeInfo_Class instantiatableType) {
88 		this.instantiatableType = instantiatableType;
89 	}
90 
91 	public Object getInstance()
92 	{
93 		if (instance is null) {
94 			debug(skadiVerbose) {
95 				writeln(format("DEBUG: Creating new instance of type %s (SingleInstanceScope)", instantiatableType.toString()));
96 			}
97 			instance = instantiatableType.create();
98 		} else {
99 			debug(skadiVerbose) {
100 				writeln(format("DEBUG: Existing instance returned of type %s (SingleInstanceScope)", instantiatableType.toString()));
101 			}
102 		}
103 
104 
105 		return instance;
106 	}
107 }
108 
109 /**
110  * Scopes registrations to return the same instance every time a given registration is resolved.
111  *
112  * Effectively makes the given registration a singleton.
113  */
114 public Registration singleInstance(Registration registration)
115 {
116 	registration.registationScope = new SingleInstanceScope(registration.instantiatableType);
117 	return registration;
118 }
119 
120 class NewInstanceScope : CreationScope
121 {
122 	TypeInfo_Class instantiatableType = null;
123 
124 	this(TypeInfo_Class instantiatableType) {
125 		this.instantiatableType = instantiatableType;
126 	}
127 
128 	public Object getInstance() {
129 		debug(skadiVerbose) {
130 			writeln(format("DEBUG: Creating new instance of type %s (SingleInstanceScope)", instantiatableType.toString()));
131 		}
132 		return instantiatableType.create();
133 	}
134 }
135 
136 /**
137  * Scopes registrations to return a new instance every time the given registration is resolved.
138  */
139 public Registration newInstance(Registration registration)
140 {
141 	registration.registationScope = new NewInstanceScope(registration.instantiatableType);
142 	return registration;
143 }
144 
145 class ExistingInstanceScope : CreationScope
146 {
147 	Object instance = null;
148 
149 	this(Object instance) {
150 		this.instance = instance;
151 	}
152 
153 	public Object getInstance() {
154 		debug(skadiVerbose) {
155 			writeln("DEBUG: Existing instance returned (ExistingInstanceScope)");
156 		}
157 		return instance;
158 	}
159 }
160 
161 /**
162  * Scopes registrations to return the given instance every time the given registration is resolved.
163  */
164 public Registration existingInstance(Registration registration, Object instance)
165 {
166 	registration.registationScope = new ExistingInstanceScope(instance);
167 	return registration;
168 }
169 
170 public string toConcreteTypeListString(Registration[] registrations)
171 {
172 	auto concreteTypeListString = "";
173 	foreach (registration ; registrations) {
174 		if (concreteTypeListString.length > 0) {
175 			concreteTypeListString ~= ", ";
176 		}
177 		concreteTypeListString ~= registration.instantiatableType.toString();
178 	}
179 	return concreteTypeListString;
180 }
181 
182 class InstantiationContext {}