1 package cz.cuni.amis.pogamut.ut2004.tournament.botexecution;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.logging.Level;
6 import java.util.logging.Logger;
7
8 import cz.cuni.amis.pogamut.ut2004.utils.PogamutUT2004Property;
9 import cz.cuni.amis.utils.StreamSink;
10 import cz.cuni.amis.utils.exception.PogamutException;
11 import cz.cuni.amis.utils.exception.PogamutIOException;
12 import cz.cuni.amis.utils.flag.Flag;
13 import cz.cuni.amis.utils.flag.FlagListener;
14 import cz.cuni.amis.utils.flag.ImmutableFlag;
15
16
17
18
19
20
21
22
23 public class UT2004BotExecution {
24
25 protected UT2004BotExecutionConfig config;
26
27
28
29
30
31
32
33 protected Flag<Boolean> running = new Flag<Boolean>(false);
34
35
36
37
38 protected Process botProcess = null;
39
40
41
42
43 protected StreamSink streamSinkOutput = null;
44
45
46
47
48 protected StreamSink streamSinkError = null;
49
50
51
52
53 protected Logger log;
54
55
56
57
58
59 public UT2004BotExecution(UT2004BotExecutionConfig config, Logger log) {
60 this.log = log;
61 this.config = config;
62 }
63
64
65
66
67 protected Runnable shutDownHook = new Runnable(){
68
69 @Override
70 public void run() {
71 if (botProcess != null) botProcess.destroy();
72 }
73 };
74
75 protected Thread shutDownHookThread;
76
77
78
79
80
81 protected Runnable waitForEnd = new Runnable() {
82
83 @Override
84 public void run() {
85 try {
86 botProcess.waitFor();
87
88 } catch (InterruptedException e) {
89
90 synchronized(running) {
91 if (!running.getFlag()) {
92
93 return;
94 }
95 }
96
97 if (log != null && log.isLoggable(Level.WARNING)) {
98 log.warning("Interrupted while waiting for the botProcess(" + config.getBotId().getToken() + ") to end!");
99 }
100
101 } finally {
102
103 synchronized(running) {
104 if (!running.getFlag()) {
105
106 return;
107 }
108 if (waitForEndThread == Thread.currentThread()) {
109
110 shutdown(true);
111 }
112 }
113 }
114 }
115 };
116
117 protected Thread waitForEndThread;
118
119
120
121
122
123
124
125
126
127
128 public void start(String host, int port) throws PogamutIOException {
129 synchronized(running) {
130 if (running.getFlag()) {
131 throw new PogamutException("Could not start the bot again, it is already running! stop() it first!", log, this);
132 }
133
134 if (log != null && log.isLoggable(Level.WARNING)) {
135 log.warning("Starting bot: " + config);
136 }
137
138 if (!config.isBotJarExist()) {
139 throw new PogamutException("Could not start the bot according to config " + config + " as the bot jar does not exist at specified place " + config.getJarFile().getAbsolutePath() + "!", this);
140 }
141
142 String javaHome = System.getProperty("JAVA_HOME");
143
144 boolean linux = System.getProperty("os.name").toLowerCase().contains("linux");
145
146
147
148 String command =
149 (javaHome == null
150 ? (linux ? "java" : "java.exe")
151 : javaHome + (linux ? "/bin/java" : "\\bin\\java.exe"));
152
153 String fullCommand = command + " \"-D" + PogamutUT2004Property.POGAMUT_UT2004_BOT_HOST.getKey() + "=" + host + "\""
154 + " \"-D" + PogamutUT2004Property.POGAMUT_UT2004_BOT_PORT.getKey() + "=" + port + "\""
155 + " -jar \"" + config.getJarFile().getAbsolutePath() + "\"";
156
157 if (log != null && log.isLoggable(Level.INFO)) {
158 log.info("Executing command: " + fullCommand);
159 }
160
161 ProcessBuilder procBuilder =
162 new ProcessBuilder(
163 command,
164 "-D" + PogamutUT2004Property.POGAMUT_UT2004_BOT_HOST.getKey() + "=" + host,
165 "-D" + PogamutUT2004Property.POGAMUT_UT2004_BOT_PORT.getKey() + "=" + port,
166 "-jar",
167 config.getJarFile().getAbsolutePath()
168 );
169 procBuilder.directory(new File(config.getJarFile().getParent()));
170
171 try {
172 botProcess = procBuilder.start();
173 } catch (IOException e) {
174
175 if (log != null && log.isLoggable(Level.SEVERE)) {
176 log.severe("Could not start the bot: " + e.getMessage());
177 }
178 botProcess = null;
179 throw new PogamutIOException("Failed to start the botProcess(" + config.getBotId().getToken() + "). IOException: " + e.getMessage(), e, this);
180 }
181
182
183 if (config.isRedirectStdErr()) {
184 streamSinkError = new StreamSink(config.getBotId().getToken()+"-StdErrSink", botProcess.getErrorStream(), log, config.getBotId().getToken()+"-StdErr");
185 } else {
186 streamSinkError = new StreamSink(config.getBotId().getToken()+"-StdErrSink", botProcess.getErrorStream());
187 }
188 streamSinkError.start();
189 if (config.isRedirectStdOut()) {
190 streamSinkOutput = new StreamSink(config.getBotId().getToken()+"-StdOutSink", botProcess.getInputStream(), log, config.getBotId().getToken()+"-StdOut");
191 } else {
192 streamSinkOutput = new StreamSink(config.getBotId().getToken()+"-StdOutSink", botProcess.getInputStream());
193 }
194 streamSinkOutput.start();
195 shutDownHookThread = new Thread(shutDownHook, config.getBotId().getToken()+"-JVMShutdownHook");
196 Runtime.getRuntime().addShutdownHook(shutDownHookThread);
197 waitForEndThread = new Thread(waitForEnd, config.getBotId().getToken()+"-WaitForProcessEnd");
198 running.setFlag(true);
199 waitForEndThread.start();
200 }
201 }
202
203
204
205
206
207 protected void shutdown(boolean waitForEndThread) {
208 synchronized(running) {
209 if (!running.getFlag()) {
210
211 return;
212 }
213
214 if (log != null && log.isLoggable(Level.WARNING)) {
215 log.warning("Shutting down botProcess(" + config.getBotId().getToken() + ")!");
216 }
217
218 if (log != null && log.isLoggable(Level.WARNING)) {
219 log.warning("... destroying botProcess(" + config.getBotId().getToken() + ").");
220 }
221 if (botProcess != null) {
222 try {
223 botProcess.destroy();
224 } catch (Exception e) {
225 }
226 }
227 botProcess = null;
228
229 if (log != null && log.isLoggable(Level.WARNING)) {
230 log.warning("... destroying streamSinkError(" + config.getBotId().getToken() + ").");
231 }
232 try {
233 if (streamSinkError != null) streamSinkError.interrupt();
234 } catch (Exception e) {
235 }
236 streamSinkError = null;
237
238 if (log != null && log.isLoggable(Level.WARNING)) {
239 log.warning("... destroying streamSinkOutput(" + config.getBotId().getToken() + ").");
240 }
241 try {
242 if (streamSinkOutput != null) streamSinkOutput.interrupt();
243 } catch (Exception e) {
244 }
245 streamSinkOutput = null;
246
247 if (log != null && log.isLoggable(Level.WARNING)) {
248 log.warning("... destroying waitForEnd(" + config.getBotId().getToken() + ").");
249 }
250 if (!waitForEndThread) {
251 try {
252 if (this.waitForEndThread != null) this.waitForEndThread.interrupt();
253 } catch (Exception e) {
254 }
255 }
256 this.waitForEndThread = null;
257
258 if (log != null && log.isLoggable(Level.WARNING)) {
259 log.warning("... removing shutDownHook(" + config.getBotId().getToken() + ").");
260 }
261 if (shutDownHookThread != null) {
262 try {
263 Runtime.getRuntime().removeShutdownHook(shutDownHookThread);
264 } catch (Exception e) {
265 }
266 }
267 shutDownHookThread = null;
268
269 if (log != null && log.isLoggable(Level.WARNING)) {
270 log.warning("... setting running-flag(" + config.getBotId().getToken() + ") to FALSE.");
271 }
272 running.setFlag(false);
273
274 if (log != null && log.isLoggable(Level.WARNING)) {
275 log.warning("Shutdown(" + config.getBotId().getToken() + ") finished.");
276 }
277 }
278 }
279
280
281
282
283 public void stop() {
284 shutdown(false);
285 }
286
287
288
289
290
291 public Process getBotProcess() {
292 return botProcess;
293 }
294
295
296
297
298
299
300 public ImmutableFlag<Boolean> getRunning() {
301 return running.getImmutable();
302 }
303
304
305
306
307
308
309 public boolean isRunning() {
310 return running.getFlag();
311 }
312
313 }