View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.analyzer;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   import java.util.logging.Level;
6   
7   import com.google.inject.Inject;
8   
9   import cz.cuni.amis.pogamut.base.agent.state.level1.IAgentStateUp;
10  import cz.cuni.amis.pogamut.base.communication.command.IAct;
11  import cz.cuni.amis.pogamut.base.communication.connection.impl.socket.SocketConnection;
12  import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
13  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
14  import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectListener;
15  import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectDestroyedEvent;
16  import cz.cuni.amis.pogamut.base.component.bus.IComponentBus;
17  import cz.cuni.amis.pogamut.base.utils.logging.IAgentLogger;
18  import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
19  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Player;
20  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerJoinsGame;
21  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.PlayerLeft;
22  import cz.cuni.amis.pogamut.ut2004.communication.worldview.UT2004WorldView;
23  import cz.cuni.amis.pogamut.ut2004.factory.guice.remoteagent.UT2004AnalyzerFactory;
24  import cz.cuni.amis.pogamut.ut2004.factory.guice.remoteagent.UT2004ObserverFactory;
25  import cz.cuni.amis.pogamut.ut2004.observer.IUT2004Observer;
26  import cz.cuni.amis.pogamut.ut2004.server.impl.UT2004Server;
27  import cz.cuni.amis.pogamut.ut2004.utils.UT2004AnalyzerRunner;
28  import cz.cuni.amis.pogamut.ut2004.utils.UT2004ObserverRunner;
29  import cz.cuni.amis.utils.exception.PogamutInterruptedException;
30  import cz.cuni.amis.utils.listener.Listeners;
31  
32  /**
33   * UT2004Analyzer can be used to automatically observe all bots/players in the game sniff their messages.
34   * <p><p>
35   * It creates and launches {@link IUT2004AnalyzerObserver} that is constructed according to the {@link UT2004AnalyzerParameters#getObserverModule()}.
36   * 
37   * @author Jimmy
38   */
39  public class UT2004Analyzer extends UT2004Server implements IUT2004Analyzer {
40  
41  	private Object mutex = new Object();
42  	
43  	private Listeners<IAnalyzerObserverListener> observerListeners = new Listeners<IAnalyzerObserverListener>();
44  	private IAnalyzerObserverListener.ObserverAddedNotifier observerAddedNotifier = new IAnalyzerObserverListener.ObserverAddedNotifier();
45  	private IAnalyzerObserverListener.ObserverRemovedNotifier observerRemovedNotifier = new IAnalyzerObserverListener.ObserverRemovedNotifier();
46  	
47  	private void addObserver(UnrealId botId) {
48  		synchronized(observers) {
49  			if (observers.containsKey(botId)) return;
50  			if (log.isLoggable(Level.INFO)) log.info("New bot has connected to the game, creating new observer for the bot with id '" + botId.getStringId() + "'.");
51  			String fileName = getParams().getFileNames() != null ? getParams().getFileNames().get(botId) : null;
52  			IUT2004AnalyzerObserver observer = getObserverRunner().startAgents(
53  					new UT2004AnalyzerObserverParameters()
54  						.setObservedAgentId(botId.getStringId())
55  						.setOutputPath(getParams().getOutputPath())
56  						.setWaitForMatchRestart(getParams().isWaitForMatchRestart())
57  						.setFileName(fileName)
58  						.setWorldAddress(getParams().getObserverAddress())
59  			).get(0);
60  			observers.put(botId, observer);
61  			observerAddedNotifier.setBotId(botId);
62  			observerAddedNotifier.setObserver(observer);
63  			observerListeners.notify(observerAddedNotifier);
64  		}
65  	}
66  	
67  	private void removeObserver(UnrealId botId) {
68  		synchronized(observers) {
69  			IUT2004AnalyzerObserver observer = observers.get(botId);
70  			if (log.isLoggable(Level.INFO)) log.info("Bot '" + botId.getStringId() + "' has left the game");			
71  			if (observer != null) {
72  				if (log.isLoggable(Level.INFO)) log.info("Stopping observer for the bot.");
73  				try {
74  					Thread.sleep(50);
75  				} catch (InterruptedException e) {
76  					throw new PogamutInterruptedException(e, this);
77  				}
78  				if (observer.getState().getFlag() instanceof IAgentStateUp) {
79  					try {
80  						observer.stop();
81  					} catch (Exception e) {
82  						log.warning("Observer for the bot '" + observer.getObservedBotId().getStringId() + "' could not be stopped, killing...");
83  						try {
84  							observer.kill();
85  						} catch (Exception e2) {
86  							log.warning("Observer for the bot '" + observer.getObservedBotId().getStringId() + "' could not be killed: " + e2.getMessage());
87  						}
88  					}
89  				}
90  				observers.remove(botId);
91  				observerRemovedNotifier.setBotId(botId);
92  				observerRemovedNotifier.setObserver(observer);
93  				observerListeners.notify(observerRemovedNotifier);				
94  			} else {
95  				if (log.isLoggable(Level.WARNING)) log.warning("The bot '" + botId.getStringId() + "' has no observer attached, was not observer, probably because the analyzer has been started after the bot itself.");
96  			}
97  		}
98  	}
99  	
100 	private IWorldObjectListener<Player> playerListener = new IWorldObjectListener<Player>() {
101 		@Override
102 		public void notify(IWorldObjectEvent<Player> event) {			
103 			Player plr = event.getObject();
104 			if (plr.getJmx() != null && plr.getJmx().length() > 0) {
105 				// CUSTOM BOT
106 				if (event instanceof WorldObjectDestroyedEvent) {
107 					removeObserver(plr.getId());
108 				} else {
109 					addObserver(plr.getId());
110 				}
111 			}
112 		}
113 	};
114 	
115 	private IWorldEventListener<PlayerJoinsGame> playerJoinsGameListener = new IWorldEventListener<PlayerJoinsGame>() {
116 		@Override
117 		public void notify(PlayerJoinsGame event) {
118 			addObserver(event.getId());
119 		}
120 	};
121 	
122 	private IWorldEventListener<PlayerLeft> playerLeftListener = new IWorldEventListener<PlayerLeft>() {
123 
124 		@Override
125 		public void notify(PlayerLeft event) {
126 			removeObserver(event.getId());
127 		}
128 		
129 	};
130 	
131 	/**
132 	 * Stored pointers to observers the analyzer owns.
133 	 */
134 	private Map<UnrealId, IUT2004AnalyzerObserver> observers = new HashMap<UnrealId, IUT2004AnalyzerObserver>();
135 
136 	/**
137 	 * Runner that is used to start new instances of {@link IUT2004AnalyzerObserver}
138 	 */
139 	private UT2004ObserverRunner<IUT2004AnalyzerObserver, UT2004AnalyzerObserverParameters> observerRunner;
140 	
141 	@Inject
142 	public UT2004Analyzer(UT2004AnalyzerParameters params,
143 			IAgentLogger agentLogger, IComponentBus bus,
144 			SocketConnection connection, UT2004WorldView worldView, IAct act) {
145 		super(params, agentLogger, bus, connection, worldView, act);
146 		
147 		observerListeners.setLog(log, "ObserverListeners");
148 		
149 		//getWorldView().addEventListener(PlayerJoinsGame.class, playerJoinsGameListener);
150 		getWorldView().addEventListener(PlayerLeft.class, playerLeftListener);
151 		getWorldView().addObjectListener(Player.class, playerListener);
152 	}
153 	
154 	private UT2004ObserverRunner<IUT2004AnalyzerObserver, UT2004AnalyzerObserverParameters> getObserverRunner() {
155 		if (observerRunner == null) {
156 			synchronized(mutex) {
157 				if (observerRunner == null) observerRunner = new UT2004ObserverRunner(new UT2004ObserverFactory<IUT2004Observer, UT2004AnalyzerObserverParameters>(getParams().getObserverModule()));
158 			}
159 		}		
160 		return observerRunner; 
161 	}
162 	
163 	@Override
164 	public UT2004AnalyzerParameters getParams() {
165 		return (UT2004AnalyzerParameters) super.getParams();
166 	}
167 
168 	@Override
169 	public Map<UnrealId, IUT2004AnalyzerObserver> getObservers() {
170 		synchronized(observers) {
171 			return new HashMap<UnrealId, IUT2004AnalyzerObserver>(observers);
172 		}
173 	}
174 	
175 	@Override
176 	protected void stopAgent() {
177 		super.stopAgent();
178 		cleanUp();
179 	}
180 	
181 	@Override
182 	protected void killAgent() {
183 		super.killAgent();
184 		cleanUp();
185 	}
186 
187 	/**
188 	 * Called from {@link UT2004Analyzer#stopAgent()} and {@link UT2004Analyzer#killAgent()} to clean up stuff (stops observers).
189 	 */
190 	protected void cleanUp() {
191 		synchronized(observers) {
192 			for (IUT2004AnalyzerObserver observer : observers.values()) {
193 				if (observer.getState().getFlag() instanceof IAgentStateUp) {
194 					try {
195 						observer.stop();
196 					} catch (Exception e) {
197 						if (log.isLoggable(Level.WARNING)) log.warning("Observer for the bot '" + observer.getObservedBotId().getStringId() + "' could not be stopped, killing...");
198 						try {
199 							observer.kill();
200 						} catch (Exception e2) {
201 							if (log.isLoggable(Level.WARNING)) log.warning("Observer for the bot '" + observer.getObservedBotId().getStringId() + "' could not be killed: " + e2.getMessage());
202 						}
203 					}
204 				}
205 			}
206 		}
207 	}
208 	
209 	public static void main(String[] args) {
210 		UT2004AnalyzerRunner<IUT2004Analyzer, UT2004AnalyzerParameters> analyzerRunner = new UT2004AnalyzerRunner<IUT2004Analyzer, UT2004AnalyzerParameters>(
211     		new UT2004AnalyzerFactory(
212     			new UT2004AnalyzerModule()
213     		)
214     	);
215     	analyzerRunner.setLogLevel(Level.INFO);
216     	analyzerRunner.setMain(true).startAgent();
217 	}
218 
219 	@Override
220 	public void addListener(IAnalyzerObserverListener listener) {
221 		observerListeners.addWeakListener(listener);
222 	}
223 
224 	@Override
225 	public boolean isListening(IAnalyzerObserverListener listener) {
226 		return observerListeners.isListening(listener);
227 	}
228 
229 	@Override
230 	public void removeListener(IAnalyzerObserverListener listener) {
231 		observerListeners.removeListener(listener);
232 	}
233 
234 }