View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.tournament.match;
2   
3   import java.util.Collections;
4   import java.util.HashMap;
5   import java.util.Map;
6   import java.util.concurrent.Callable;
7   import java.util.concurrent.FutureTask;
8   import java.util.concurrent.ThreadPoolExecutor;
9   import java.util.logging.Level;
10  import java.util.logging.Logger;
11  
12  import cz.cuni.amis.pogamut.ut2004.tournament.match.result.UT2004MatchResult;
13  import cz.cuni.amis.utils.ExceptionToString;
14  import cz.cuni.amis.utils.NullCheck;
15  import cz.cuni.amis.utils.token.IToken;
16  
17  /**
18   * {@link UT2004Match} executor that will execute one instance of match a time == NO PARALELIZATION HERE!
19   * <p><p>
20   * Please note that executing more than one match on the same UT2004 instance is not considered to be safe because:
21   * <ol>
22   * <li>GameBots2004.ini file is overwritten during the match execution == different GameBots2004.ini files in match configurations will pose problems</li>
23   * <li>UT2004 (ucc.exe) sometimes hangs if executed multiple times (we do not know why, it should not act that way</li>
24   * </ol>
25   * <p>
26   * If you seek parallelization, consider this:
27   * <ol>
28   * <li>Separate your matches that has the same GameBots2004.ini configuration (usually you are altering only frag limit and time limit, other things are
29   * not configured through GameBots2004.ini</li>
30   * <li>Create multiple UT2004MatchExecutors, each configured with matches of the same config</li>
31   * <li>Use {@link ThreadPoolExecutor}, note that this class is implementing {@link Callable} so it is easy to create {@link FutureTask} out of it and submit
32   * the {@link FutureTask} into {@link ThreadPoolExecutor#execute(Runnable)} and wait for results via {@link FutureTask#get()}.</li>
33   * </ol>
34   * 
35   * @author Jimmy
36   *
37   * @param <MATCH>
38   * @param <RESULT> must be of the same type that the MATCH is producing via {@link UT2004Match#execute()}.
39   */
40  public class UT2004MatchExecutor<MATCH extends UT2004Match, RESULT extends UT2004MatchResult> implements Callable<Map<IToken, RESULT>>, Runnable {
41  	
42  	/**
43  	 * Matches that will be executed.
44  	 */
45  	private MATCH[] matches;
46  
47  	/**
48  	 * Results of all matches, available through {@link UT2004MatchExecutor#getResults()}.
49  	 */
50  	private Map<IToken, RESULT> results = new HashMap<IToken, RESULT>();
51  	
52  	/**
53  	 * Map with exceptions that are stored here for matches which fails.
54  	 */
55  	private Map<IToken, Throwable> exceptions = new HashMap<IToken, Throwable>();
56  
57  	/**
58  	 * Used for logging information about the match.
59  	 */
60  	private Logger log;
61  	
62  	public UT2004MatchExecutor(MATCH[] matches, Logger log) {
63  		this.log = log;		
64  		this.matches = matches;
65  		NullCheck.check(this.matches, "matches");
66  	}
67  	
68  	/**
69  	 * This map holds the results of respective matches. Immutable.
70  	 * @return
71  	 */
72  	public Map<IToken, RESULT> getResults() {
73  		return Collections.unmodifiableMap(results);
74  	}
75  
76  	/**
77  	 * If some match fails, the exception reported is stored within this map. Immutable.
78  	 * @return
79  	 */
80  	public Map<IToken, Throwable> getExceptions() {
81  		return Collections.unmodifiableMap(exceptions);
82  	}
83  
84  	@Override
85  	public Map<IToken, RESULT> call() throws Exception {
86  		run();
87  		return getResults();
88  	}
89  
90  	@Override
91  	public void run() {
92  		if (log != null && log.isLoggable(Level.WARNING)) {
93  			log.warning("Executing " + matches.length + " matches!");
94  		}
95  		
96  		boolean exception = false;
97  		
98  		for (MATCH match : matches) {
99  			try {
100 				if (log != null && log.isLoggable(Level.WARNING)) {
101 					log.warning("Executing match: " + match.getMatchId().getToken());
102 				}
103 				UT2004MatchResult result = match.call();
104 				results.put(match.getMatchId(), (RESULT) result);
105 			} catch (Exception e) {
106 				if (log != null && log.isLoggable(Level.SEVERE)) {
107 					log.severe(ExceptionToString.process("Match[" + match.getMatchId().getToken() + "] failed with exception.", e));
108 				}
109 				exception = true;
110 				exceptions.put(match.getMatchId(), e);
111 			}			
112 		}
113 		
114 		if (exception) {
115 			if (log != null && log.isLoggable(Level.SEVERE)) {
116 				log.warning("Execution finished... SOME MATCHES FAILED!!!");
117 			}
118 		} else {
119 			if (log != null && log.isLoggable(Level.WARNING)) {
120 				log.warning("Execution finished! ALL MATCHES FINISHED SUCCESSFULLY!");
121 			}
122 		}
123 	}
124 	
125 }