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 }