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