View Javadoc

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  }