MATSIM
MatsimRuntimeModifications.java
Go to the documentation of this file.
1 
2 /* *********************************************************************** *
3  * project: org.matsim.*
4  * MatsimRuntimeModifications.java
5  * *
6  * *********************************************************************** *
7  * *
8  * copyright : (C) 2019 by the members listed in the COPYING, *
9  * LICENSE and WARRANTY file. *
10  * email : info at matsim dot org *
11  * *
12  * *********************************************************************** *
13  * *
14  * This program is free software; you can redistribute it and/or modify *
15  * it under the terms of the GNU General Public License as published by *
16  * the Free Software Foundation; either version 2 of the License, or *
17  * (at your option) any later version. *
18  * See also COPYING, LICENSE and WARRANTY file *
19  * *
20  * *********************************************************************** */
21 
22  package org.matsim.core.controler;
23 
24 import org.apache.logging.log4j.LogManager;
25 import org.apache.logging.log4j.Logger;
26 
27 import java.util.concurrent.atomic.AtomicBoolean;
28 
29 class MatsimRuntimeModifications {
30 
31  private final MyRunnable runnable;
32  // for tests
33  private volatile Throwable uncaughtException;
34 
35  private AtomicBoolean unexpectedShutdown = new AtomicBoolean(false);
36 
37  private static final Logger log = LogManager.getLogger(MatsimRuntimeModifications.class);
38 
39  interface MyRunnable {
40  void run() throws UnexpectedShutdownException;
41  void shutdown(boolean unexpected);
42  }
43 
44 
45  static class UnexpectedShutdownException extends Exception {
46  }
47 
48  MatsimRuntimeModifications(MyRunnable runnable) {
49  this.runnable = runnable;
50  }
51 
52  static void run(MyRunnable runnable) {
53  new MatsimRuntimeModifications(runnable).run();
54  }
55 
56  void run() {
57  Thread.UncaughtExceptionHandler previousDefaultUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
58  final Thread controllerThread = Thread.currentThread();
59  Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
60  @Override
61  public void uncaughtException(Thread t, Throwable e) {
62  // We want to shut down when any Thread dies with an Exception.
63  log.error("Getting uncaught Exception in Thread " + t.getName(), e);
64  uncaughtException = e;
65  unexpectedShutdown.set(true);
66  controllerThread.interrupt();
67  }
68  });
69  try {
70  runnable.run();
71  } catch (UnexpectedShutdownException e) {
72  // Doesn't matter. Just shut down.
73  } catch (Throwable e) {
74  // Don't let it fall through to the UncaughtExceptionHandler. We want to first log the Exception,
75  // then shut down.
76  log.error("Getting uncaught Exception in Thread " + Thread.currentThread().getName(), e);
77  uncaughtException = e;
78  unexpectedShutdown.set(true);
79  } finally {
80  log.info("S H U T D O W N --- start shutdown.");
81  if (unexpectedShutdown.get()) {
82  log.error("ERROR --- This is an unexpected shutdown!");
83  }
84  if (uncaughtException != null) {
85  log.error("Shutdown possibly caused by the following Exception:", uncaughtException);
86  }
87  try {
88  runnable.shutdown(unexpectedShutdown.get());
89  } catch (Exception e) {
90  unexpectedShutdown.set(true);
91  log.error("Exception during shutdown:", e);
92  if (uncaughtException == null) {
93  // If there has been a previous exception, it is likely more important
94  // than this new one. This new one may just be a consequence of the
95  // previous one.
96  uncaughtException = e;
97  }
98  }
99  if (unexpectedShutdown.get()) {
100  log.error("ERROR --- MATSim unexpectedly terminated. Please check the output or the logfile with warnings and errors for hints.");
101  log.error("ERROR --- results should not be used for further analysis.");
102  }
103  log.info("S H U T D O W N --- shutdown completed.");
104  if (unexpectedShutdown.get()) {
105  log.error("ERROR --- This was an unexpected shutdown! See the log file for a possible reason.");
106  }
107  Thread.setDefaultUncaughtExceptionHandler(previousDefaultUncaughtExceptionHandler);
108  // Propagate Exception in case Controler.run is called by someone who wants to catch
109  // it. It is probably not strictly correct to wrap the exception here.
110  // But otherwise, this method would have to declare "throws Throwable".
111  // In theory, a run method for test cases would probably need to
112  // be different from the run method of the "MATSim platform" which
113  // takes control of the JVM by installing hooks and exception
114  // handlers.
115  }
116  if (uncaughtException != null) {
117  if (uncaughtException instanceof RuntimeException) {
118  throw ((RuntimeException) uncaughtException);
119  } else {
120  throw new RuntimeException(uncaughtException);
121  }
122  }
123  }
124 
125 
126 }