1 package cz.cuni.amis.pogamut.base.factory.guice;
2
3 import java.util.ArrayList;
4 import java.util.List;
5
6 import com.google.inject.AbstractModule;
7 import com.google.inject.Injector;
8 import com.google.inject.Module;
9 import com.google.inject.util.Modules;
10
11 import cz.cuni.amis.pogamut.base.agent.IAgent;
12 import cz.cuni.amis.pogamut.base.agent.IAgentId;
13 import cz.cuni.amis.pogamut.base.agent.impl.AbstractAgent;
14 import cz.cuni.amis.pogamut.base.agent.impl.AgentId;
15 import cz.cuni.amis.pogamut.base.agent.params.IAgentParameters;
16 import cz.cuni.amis.pogamut.base.agent.utils.runner.impl.AgentRunner;
17 import cz.cuni.amis.pogamut.base.component.bus.ComponentBus;
18 import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
19 import cz.cuni.amis.pogamut.base.utils.guice.AdaptableProvider;
20 import cz.cuni.amis.pogamut.base.utils.guice.AgentScope;
21 import cz.cuni.amis.pogamut.base.utils.guice.AgentScoped;
22 import cz.cuni.amis.pogamut.base.utils.guice.AgentTeamScoped;
23 import cz.cuni.amis.pogamut.base.utils.guice.IAgentScope;
24 import cz.cuni.amis.pogamut.base.utils.logging.AgentLogger;
25 import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
26 import cz.cuni.amis.utils.NullCheck;
27
28 /**
29 * GuiceAgentModule, implementation of {@link AbstractModule}, provides a way to hierarchically specify the bindings
30 * for interfaces and classes.
31 * <p><p>
32 * The module is a place where you assemble the pieces of the dependency puzzle. You're specifying which implementor
33 * should be created for specific interface, etc. This sounds good but then you find out that it is somehow hard
34 * to override once set bindings.
35 * <p><p>
36 * The {@link GuiceAgentModule} solves this by providing {@link GuiceAgentModule#addModule(AbstractModule)} method
37 * that should be called from {@link GuiceAgentModule#configureModules()} (see their javadocs). The {@link GuiceAgentModule#configureModules()}
38 * is meant to be overridden in every descendant of the {@link GuiceAgentModule} where it should call <i>super.configureModules()</i>
39 * and than add another module to the queue via {@link GuiceAgentModule#addModule(AbstractModule)}. We're simply collecting
40 * respective modules in every <i>configureModules()</i> implementation. These collected modules are than applied inside
41 * standard Guice's method {@link GuiceAgentModule#configure()} where they are applied in the order they have been added (that's
42 * why you have to call <i>super.configureModules</i> as a first command in the descendants).
43 * <p><p>
44 * Additionally, we're introducing {@link AgentScope} under annotation {@link AgentScoped} (concrete scope implementation can
45 * be changed by in descendants via overriding {@link GuiceAgentModule#createAgentScope()}) and convenient providers for {@link IAgentId}
46 * and {@link IAgentParameters} exposed via {@link GuiceAgentModule#getAgentIdProvider()} and {@link GuiceAgentModule#getAgentParamsProvider()}.
47 * <p><p>
48 * <p><p>
49 * <b>IMPORTANT</b> the {@link GuiceAgentModule} introduces public method {@link GuiceAgentModule#prepareNewAgent(IAgentParameters)} that
50 * is meant to configure run-time dependencies inside the module before another agent is instantiated (i.e., for passing run-time
51 * parameters such as {@link IAgentParameters}. The method contains only one parameter - PARAMS, therefore it forces you to create
52 * new descendants of {@link IAgentParameters} if you want to introduce new run-time parameters (which follows the philosophy that
53 * every {@link AbstractAgent} implementation should also defines: 1) own parameters ({@link IAgentParameters} descendants), 2) own module ({@link GuiceAgentModule} descendants), 3) own runners ({@link AgentRunner} descendants).<p>
54 * <b>NOTE</b> that this method <b>MUST BE CALLED</b> before the factory creates another agent (but rest assured, it's already done in {@link GuiceAgentFactory} for
55 * you automatically}).
56 * <p><p>
57 * <p><p>
58 * FINALLY the module is providing basic bindings that are always needed for {@link AbstractAgent}
59 * <table>
60 * <tr><th>Mapped class</th> <th> </th> <th>Target</th> <th>Description</th></tr>
61 *
62 * <tr><td>{@link IComponentBus}</td> <td>-></td> <td>{@link ComponentBus}</td> <td>Agent bus synchronizing starting/stopping/etc. events.</td></tr>
63 * <tr><td>{@link IAgentId}</td> <td>-></td> <td>provided by the {@link GuiceAgentModule#agentIdProvider}.</td>
64 * <td>Id that is provided during runtime, you may use {@link AgentId} implementation of {@link IAgentId}.</td></tr>
65 * <tr><td>{@link IAgentParameters}</td> <td>-></td> <td>provided by the {@link GuiceAgentModule#agentParamsProvider}.</td>
66 * <tr><td>{@link IAgentLogger}</td> <td>-></td> <td>{@link AgentLogger}</td> <td>Takes care about logging.</td></tr>
67 * </table>
68 * <p><p>
69 * To have <b>successful module</b> the descendant <b>must specify</b> these <b>missing bindings</b>:
70 * <table>
71 * <tr><th>Mapped class</th> <th>Description</th></tr>
72 *
73 * <tr><td>{@link IAgent}</td> <td>Agent that should be instantiated (preferable descendant of {@link AbstractAgent}.</td></tr>
74 * </table>
75 * ... plus all newly introduced dependencies (by various implementors of mentioned interfaces).<p>
76 * ... <b>don't forget to call super.configureModules()</b> in the subclasses. ;-)
77 *
78 *
79 * @author Jimmy
80 * @param PARAMS
81 */
82 public class GuiceAgentModule<PARAMS extends IAgentParameters> extends AbstractModule {
83
84 /**
85 * Agent scope used to hold instances annotated with {@link AgentScoped}.
86 */
87 private IAgentScope agentScope;
88
89 /**
90 * Agent-team scope used to hold instances annotated with {@link AgentTeamScoped}.
91 */
92 private IAgentScope agentTeamScope;
93
94 /**
95 * Provider for the {@link IAgentId} run-time dependence.
96 */
97 private AdaptableProvider<IAgentId> agentIdProvider = new AdaptableProvider(null);
98
99 /**
100 * Provider for the {@link IAgentParameters} run-time dependencies.
101 */
102 private AdaptableProvider<PARAMS> agentParamsProvider = new AdaptableProvider(null);
103
104 /**
105 * List of modules that are joined together when the module is used to provide the {@link Injector}.
106 */
107 private List<Module> modules = new ArrayList<Module>();
108
109 /**
110 * Initializes {@link GuiceAgentModule#agentScope} via {@link GuiceAgentModule#createAgentScope()}.
111 */
112 public GuiceAgentModule() {
113 agentScope = createAgentScope();
114 NullCheck.check(this.agentScope, "createAgentScope()");
115 agentTeamScope = createAgentTeamScope();
116 NullCheck.check(this.agentTeamScope, "createAgentTeamScope()");
117 }
118
119 /**
120 * Must be called before another agent instance can be created. It clears the {@link GuiceAgentModule#agentScope}
121 * and binds {@link IAgentParameters#getAgentId()} to the {@link GuiceAgentModule#agentIdProvider}.
122 * <p><p>
123 * Whenever you create your own {@link IAgentParameters} you may need to override this method to utilize your new
124 * run-time dependencies. In such case, always call <i>super.prepareNewAgent(agentParameters)</i> as a first command.
125 *
126 * @param agentParameters
127 */
128 public void prepareNewAgent(PARAMS agentParameters) {
129 NullCheck.check(agentParameters, "agentParameters");
130 NullCheck.check(agentParameters.getAgentId(), "agentParameters.getAgentId()");
131 agentScope.clearScope();
132 agentIdProvider.set(agentParameters.getAgentId());
133 agentParamsProvider.set(agentParameters);
134 }
135
136 /**
137 * Adds next modules containing new bindings that extend (and/or override) previous bindings.
138 * <p><p>
139 * Designed to be used from {@link GuiceAgentModule#configureModules()}.
140 *
141 * @param module
142 */
143 protected final void addModule(AbstractModule module) {
144 this.modules.add(module);
145 }
146
147 /**
148 * Meant to introduce new {@link AbstractModule} into the module's queue {@link GuiceAgentModule#modules} via {@link GuiceAgentModule#addModule(AbstractModule)}.
149 * <p><p>
150 * See {@link GuiceAgentModule#configureModules()} source code for the example (utilizes anonymous class instantiation,
151 * instantiating {@link AbstractModule} where you only have to override {@link AbstractModule#configure()} method where
152 * you use {@link AbstractModule#bind(Class)} method to specify the bindings).
153 */
154 protected void configureModules() {
155 addModule(
156 new AbstractModule() {
157 @Override
158 protected void configure() {
159 bind(IComponentBus.class).to(ComponentBus.class);
160 bind(IAgentId.class).toProvider(getAgentIdProvider());
161 bind(IAgentParameters.class).toProvider(getAgentParamsProvider());
162 bind(IAgentLogger.class).to(AgentLogger.class);
163 }
164 }
165 );
166 }
167
168 /**
169 * Method called from the {@link GuiceAgentModule#GuiceAgentModule()} to initialize the {@link GuiceAgentModule#agentScope},
170 * override if you need you own {@link AgentScope} implementation.
171 * @return
172 */
173 protected IAgentScope createAgentScope() {
174 return new AgentScope();
175 }
176
177 /**
178 * Method called from the {@link GuiceAgentModule#GuiceAgentModule()} to initialize the {@link GuiceAgentModule#agentTeamScope},
179 * override if you need you own {@link AgentScope} implementation.
180 * @return
181 */
182 protected IAgentScope createAgentTeamScope() {
183 return new AgentScope();
184 }
185
186 /**
187 * AgentScope that is holding agent-scope-singletons (classes annotated with {@link AgentScoped}).
188 * <p><p>
189 * Use {@link AgentScope#clearScope()} to release the objects thus preparing the scope for the next initialization
190 * of the {@link IAgent} (automatically called from {@link GuiceAgentModule#prepareNewAgent(IAgentParameters)}.
191 * @return
192 */
193 public IAgentScope getAgentScope() {
194 return agentScope;
195 }
196
197 /**
198 * AgentTeamScope that is holding agent-team-scope-singletons (classes annotated with {@link AgentTeamScoped}).
199 * <p><p>
200 * Use {@link IAgentScope#clearScope()} to release the objects thus preparing the scope for the next team initialization.
201 * @return
202 */
203 public IAgentScope getAgentTeamScope() {
204 return agentTeamScope;
205 }
206
207 /**
208 * Returns a provider for the {@link IAgentId} interface. Use when utilizing descendants of {@link IAgentId}
209 * to provide the same instance for new interface/implementors.
210 *
211 * @return
212 */
213 protected AdaptableProvider<IAgentId> getAgentIdProvider() {
214 return agentIdProvider;
215 }
216
217 /**
218 * Returns a provider for the {@link IAgentParameters} interface. Use when utilizing descendants of {@link IAgentParameters}
219 * to provide the same instace for new interface/implementors.
220 *
221 * @return
222 */
223 protected AdaptableProvider<PARAMS> getAgentParamsProvider() {
224 return agentParamsProvider;
225 }
226
227 /**
228 * Binds {@link GuiceAgentModule#agentScope} into the module and then it iterates over {@link GuiceAgentModule#modules} and
229 * adds all their bindings to the module - each module always overrides previous ones (uses {@link Modules#override(Module...)}).
230 * <p><p>
231 * The advantage over classical {@link AbstractModule#configure()} method is that you may easily re-bind already bound classes
232 * (which is unachievable by simple subclassing).
233 */
234 @Override
235 protected final void configure() {
236 configureModules();
237 bindScope(AgentScoped.class, this.agentScope);
238 bindScope(AgentTeamScoped.class, this.agentTeamScope);
239 if (modules.size() == 0) {
240 throw new IllegalStateException("There is no module defined, nobody has ever called addModule() method to introduce new bindings for the module.");
241 }
242 Module actual = modules.get(0);
243 for (int i = 1; i < modules.size(); ++i) {
244 actual = Modules.override(actual).with(modules.get(i));
245 }
246 install(actual);
247 }
248
249 }