1 package cz.cuni.amis.pogamut.base.factory.guice; 2 3 import com.google.inject.Injector; 4 import com.google.inject.Provider; 5 6 import cz.cuni.amis.pogamut.base.agent.IAgent; 7 import cz.cuni.amis.pogamut.base.agent.IAgentId; 8 import cz.cuni.amis.pogamut.base.agent.params.IAgentParameters; 9 import cz.cuni.amis.pogamut.base.factory.IAgentFactory; 10 import cz.cuni.amis.utils.exception.PogamutException; 11 12 /** 13 * Guice-based {@link IAgent} factory that instantiates the agent according to the bindigs that are found inside 14 * the {@link GuiceAgentModule}, which is provided during the construction. 15 * <p><p> 16 * Additionally to the classic {@link Injector#getInstance(Class)} method, the class offers a place where to 17 * slip runtime dependencies. I.e., if you are unable to specify some dependencies during class coding, you need 18 * to create {@link Provider}s for the runtime dependency (such as desired {@link IAgentId} for the {@link IAgent}). 19 * These dependencies are injected into the module via the method {@link GuiceAgentFactory#configureModule(IAgentParameters)} 20 * that is called before the new instance is created. 21 * <p><p> 22 * Additionally, the factory method {@link GuiceAgentFactory#newAgent(IAgentParameters)} clears the agent scope 23 * that is defined by the {@link GuiceAgentModule}. 24 * <p><p> 25 * <b>NOTE:</b> if you are going to extend the implementation, than the only place that should suffice you for hacking is 26 * {@link GuiceAgentFactory#configureModule(IAgentParameters)} where you slip runtime dependencies that the base {@link GuiceAgentFactory} 27 * is unaware of, taking these dependencies from your custom {@link IAgentParameters} implementation. 28 * <p><p> 29 * <b>NOTE:</b> you might not need to override the {@link GuiceAgentFactory#configureModule(IAgentParameters)} as the 30 * module configuration might be also done inside {@link GuiceAgentModule#prepareNewAgent(IAgentParameters)} which 31 * is implicitly called from the {@link GuiceAgentFactory#configureModule(IAgentParameters)}. 32 * <p><p> 33 * <b>THREAD-SAFE</b> 34 * 35 * @author Jimmy 36 * 37 * @param <AGENT> 38 * @param <PARAMS> 39 */ 40 public class GuiceAgentFactory<AGENT extends IAgent, PARAMS extends IAgentParameters> extends AbstractGuiceAgentFactory implements IAgentFactory<AGENT, PARAMS> { 41 42 /** 43 * Creates a Guice-based factory that will use {@link Injector} created using the 'module'. 44 * <p><p> 45 * The module MUST specify bindings for the {@link IAgent} interface as that is what's going to be 46 * instantiated using the injector from {@link GuiceAgentFactory#getInjector()}. 47 * 48 * @param module module that configures bindings between classes, may be null (specify module later using {@link AbstractGuiceAgentFactory#setAgentModule(GuiceAgentModule)}) 49 */ 50 public GuiceAgentFactory(GuiceAgentModule module) { 51 super(module); 52 } 53 54 /** 55 * Called from within the {@link GuiceAgentFactory#newAgent(IAgentParameters)} to configure the {@link GuiceAgentFactory#getAgentModule()} 56 * with variables from 'agentParams'. 57 * <p><p> 58 * Just calls {@link GuiceAgentModule#prepareNewAgent(IAgentParameters)}. 59 * <p><p> 60 * NOTE: You will probably need to override this method in subclasses. If you do - do not forget to call 61 * super.configureModule(agentParameters) first! So other runtime-dependencies can be set too. 62 * 63 * @param agentParameters 64 */ 65 protected void configureModule(PARAMS agentParameters) { 66 getAgentModule().prepareNewAgent(agentParameters); 67 } 68 69 /** 70 * Creates a new instance of the {@link IAgent} interface that is cast to AGENT parameter. 71 * <p><p> 72 * Firstly, it calls {@link GuiceAgentFactory#configureModule(IAgentParameters)} to configure run-time 73 * dependencies of the module and prepare it for the new agent instance, secondly, 74 * it instantiates a new {@link IAgent} instance. 75 * <p><p> 76 * NOTE: that the {@link GuiceAgentFactory} must be correctly instantiated, i.e., 77 * the module passed into the constructor must bind {@link IAgent} interface to the 78 * AGENT (or descendant) class, otherwise you may experience {@link ClassCastException}. 79 * 80 * @param agentParameters 81 * @return agent instance configured with 'agentParameters' 82 */ 83 @Override 84 public synchronized AGENT newAgent(PARAMS agentParameters) throws PogamutException { 85 // configure the module with passed parameters 86 configureModule(agentParameters); 87 // instantiate the agent 88 return (AGENT) getInjector().getInstance(IAgent.class); 89 } 90 }