Skip to content

Commit c6eca43

Browse files
committed
*: Add exception handler
Signed-off-by: Ce Gao <[email protected]>
1 parent e1ed12d commit c6eca43

File tree

4 files changed

+114
-30
lines changed

4 files changed

+114
-30
lines changed

src/rprocessing/RLangPApplet.java

Lines changed: 51 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.awt.Window;
55
import java.awt.event.ComponentAdapter;
66
import java.awt.event.ComponentEvent;
7+
import java.lang.Thread.UncaughtExceptionHandler;
78
import java.lang.reflect.Method;
89
import java.util.Arrays;
910
import java.util.concurrent.CountDownLatch;
@@ -12,6 +13,7 @@
1213
import javax.script.ScriptEngineManager;
1314
import javax.script.ScriptException;
1415

16+
import org.renjin.eval.EvalException;
1517
import org.renjin.parser.RParser;
1618
import org.renjin.script.RenjinScriptEngine;
1719
import org.renjin.sexp.Closure;
@@ -20,8 +22,6 @@
2022
import org.renjin.sexp.SEXP;
2123
import org.renjin.sexp.Symbol;
2224

23-
import com.jogamp.newt.opengl.GLWindow;
24-
2525
import processing.awt.PSurfaceAWT;
2626
import processing.core.PApplet;
2727
import processing.core.PConstants;
@@ -30,9 +30,12 @@
3030
import processing.opengl.PSurfaceJOGL;
3131
import rprocessing.applet.BuiltinApplet;
3232
import rprocessing.exception.NotFoundException;
33+
import rprocessing.exception.RSketchError;
3334
import rprocessing.util.Constant;
3435
import rprocessing.util.Printer;
3536

37+
import com.jogamp.newt.opengl.GLWindow;
38+
3639
/**
3740
* RlangPApplet PApplet for R language, powered by Renjin.
3841
*
@@ -57,6 +60,8 @@ public class RLangPApplet extends BuiltinApplet {
5760

5861
private final CountDownLatch finishedLatch = new CountDownLatch(1);
5962

63+
private RSketchError terminalException = null;
64+
6065
/**
6166
* Mode for Processing.
6267
*
@@ -136,7 +141,7 @@ public void addPAppletToRContext() {
136141
this.renjinEngine.put("stdout", stdout);
137142
}
138143

139-
public void runBlock(final String[] arguments) {
144+
public void runBlock(final String[] arguments) throws RSketchError {
140145
log("runBlock");
141146
PApplet.runSketch(arguments, this);
142147
try {
@@ -153,8 +158,7 @@ public void runBlock(final String[] arguments) {
153158
}
154159
} finally {
155160
Thread.setDefaultUncaughtExceptionHandler(null);
156-
if (PApplet.platform == PConstants.MACOSX
157-
&& Arrays.asList(arguments).contains("fullScreen")) {
161+
if (PApplet.platform == PConstants.MACOSX && Arrays.asList(arguments).contains("fullScreen")) {
158162
// Frame should be OS-X fullscreen, and it won't stop being that unless the jvm
159163
// exits or we explicitly tell it to minimize.
160164
// (If it's disposed, it'll leave a gray blank window behind it.)
@@ -174,9 +178,9 @@ public void runBlock(final String[] arguments) {
174178
surface.setVisible(false);
175179
}
176180
}
177-
// if (terminalException != null) {
178-
// throw terminalException;
179-
// }
181+
if (terminalException != null) {
182+
throw terminalException;
183+
}
180184
}
181185

182186
private static void macosxFullScreenToggle(final Window window) {
@@ -234,6 +238,28 @@ public void exitActual() {
234238
finishedLatch.countDown();
235239
}
236240

241+
/**
242+
* @see processing.core.PApplet#start()
243+
*/
244+
@Override
245+
public void start() {
246+
// I want to quit on runtime exceptions.
247+
// Processing just sits there by default.
248+
Thread.setDefaultUncaughtExceptionHandler(new UncaughtExceptionHandler() {
249+
@Override
250+
public void uncaughtException(final Thread t, final Throwable e) {
251+
terminalException = toSketchException(e);
252+
try {
253+
handleMethods("dispose");
254+
} catch (final Exception noop) {
255+
// give up
256+
}
257+
finishedLatch.countDown();
258+
}
259+
});
260+
super.start();
261+
}
262+
237263
/**
238264
* @see processing.core.PApplet#settings()
239265
*/
@@ -262,7 +288,8 @@ public void setup() {
262288
try {
263289
this.renjinEngine.eval(this.programText);
264290
} catch (ScriptException exception) {
265-
log(exception.toString());
291+
terminalException = toSketchException(exception);
292+
exitActual();
266293
}
267294
} else if (this.mode == Mode.ACTIVE) {
268295
Object obj = this.renjinEngine.get(Constant.SETUP_NAME);
@@ -341,4 +368,19 @@ protected void wrapProcessingVariables() {
341368
private static boolean isSameClass(Object obj, Class clazz) {
342369
return obj.getClass().equals(clazz);
343370
}
371+
372+
private static RSketchError toSketchException(Throwable t) {
373+
if (t instanceof RuntimeException && t.getCause() != null) {
374+
t = t.getCause();
375+
}
376+
if (t instanceof RSketchError) {
377+
return (RSketchError) t;
378+
}
379+
if (t instanceof EvalException) {
380+
final RSketchError e = (RSketchError) t;
381+
return e;
382+
}
383+
log("No exception type detected.");
384+
return null;
385+
}
344386
}

src/rprocessing/Runner.java

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
package rprocessing;
22

3-
import org.renjin.eval.EvalException;
43
import rprocessing.exception.NotFoundException;
5-
import rprocessing.exception.REvalException;
4+
import rprocessing.exception.RSketchError;
65
import rprocessing.lancher.StandaloneSketch;
76
import rprocessing.util.Printer;
87
import rprocessing.util.RScriptReader;
@@ -18,8 +17,8 @@ public class Runner {
1817
public static RunnableSketch sketch;
1918

2019
@SuppressWarnings("unused")
21-
private static final String CORE_TEXT =
22-
RScriptReader.readResourceAsText(Runner.class, "r/core.R");
20+
private static final String CORE_TEXT = RScriptReader
21+
.readResourceAsText(Runner.class, "r/core.R");
2322

2423
private static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("VERBOSE_RLANG_MODE"));
2524

@@ -47,26 +46,20 @@ public static void main(final String[] args) throws Exception {
4746
}
4847

4948
public static synchronized void runSketchBlocking(final RunnableSketch sketch,
50-
final Printer stdout, final Printer stderr) throws REvalException, NotFoundException {
49+
final Printer stdout, final Printer stderr) throws NotFoundException, RSketchError {
5150
runSketchBlocking(sketch, stdout, stderr, null);
5251
}
5352

5453
public static synchronized void runSketchBlocking(final RunnableSketch sketch,
5554
final Printer stdout, final Printer stderr,
56-
final SketchPositionListener sketchPositionListener)
57-
throws REvalException, NotFoundException {
55+
final SketchPositionListener sketchPositionListener) throws NotFoundException, RSketchError {
5856
final String[] args = sketch.getPAppletArguments();
5957

6058
log("Tring to initialize RLangPApplet.");
6159
RLangPApplet rp = new RLangPApplet(sketch.getMainCode(), stdout);
6260
log("Adding processing variable into R top context.");
6361
rp.addPAppletToRContext();
6462

65-
try {
66-
// Run Sketch.
67-
rp.runBlock(args);
68-
} catch (EvalException ee) {
69-
throw new REvalException(ee.getMessage());
70-
}
63+
rp.runBlock(args);
7164
}
7265
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package rprocessing.exception;
2+
3+
/**
4+
* Error type for Processing.R
5+
*
6+
* @author github.com/gaocegege
7+
*/
8+
public class RSketchError extends Exception {
9+
private static final long serialVersionUID = 6563629093797155634L;
10+
public final String fileName;
11+
public final int line;
12+
public final int column;
13+
14+
public RSketchError(final String message) {
15+
this(message, null);
16+
}
17+
18+
public RSketchError(final String message, final String fileName) {
19+
this(message, fileName, -1, -1);
20+
}
21+
22+
public RSketchError(final String message, final String fileName, final int line) {
23+
this(message, fileName, line, 0);
24+
}
25+
26+
public RSketchError(final String message, final String fileName, final int line, final int column) {
27+
super(message);
28+
29+
this.fileName = fileName;
30+
this.line = line;
31+
this.column = column;
32+
}
33+
34+
@Override
35+
public String toString() {
36+
if (fileName == null) {
37+
return getMessage();
38+
}
39+
if (line == -1) {
40+
return getMessage() + " in " + fileName;
41+
}
42+
if (column == -1) {
43+
return getMessage() + " at line " + line + " of " + fileName;
44+
}
45+
return getMessage() + " at " + line + ":" + column + " in " + fileName;
46+
}
47+
}

src/rprocessing/mode/run/SketchRunner.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import rprocessing.SketchPositionListener;
1111
import rprocessing.exception.REvalException;
1212
import rprocessing.exception.RMIRuntimeException;
13+
import rprocessing.exception.RSketchError;
1314
import rprocessing.mode.RLangMode;
1415
import rprocessing.mode.run.RMIUtils.RMIProblem;
1516
import rprocessing.util.Printer;
@@ -124,15 +125,16 @@ public void sketchMoved(final Point leftTop) {
124125
}
125126
}
126127
};
128+
log("Run the sketch.");
127129
Runner.runSketchBlocking(sketch, stdout, stderr, sketchPositionListener);
128-
} catch (final REvalException exception) {
130+
} catch (final RSketchError exception) {
129131
log("Sketch runner caught " + exception);
130-
modeService.handleSketchException(id,
131-
convertREvalError(exception, sketch.codeFileNames));
132+
modeService.handleSketchException(id, exception);
132133
} catch (final Exception exception) {
134+
log("Sketch runner caught Exception:" + exception);
133135
if (exception.getCause() != null && exception.getCause() instanceof REvalException) {
134136
modeService.handleSketchException(id,
135-
convertREvalError((REvalException) exception.getCause(), sketch.codeFileNames));
137+
convertREvalError((REvalException) exception.getCause()));
136138
} else {
137139
modeService.handleSketchException(id, exception);
138140
}
@@ -141,6 +143,7 @@ public void sketchMoved(final Point leftTop) {
141143
modeService.handleSketchStopped(id);
142144
}
143145
} catch (final RemoteException exception) {
146+
log("Sketch runner caught RemoteException:" + exception);
144147
log(exception.toString());
145148
}
146149
// Exiting; no need to interrupt and join it later.
@@ -225,8 +228,8 @@ private static void startSketchRunner(final String id) throws RMIRuntimeExceptio
225228
}
226229
}
227230

228-
private static void launch(final String id, final ModeService modeService)
229-
throws RMIProblem, RemoteException {
231+
private static void launch(final String id, final ModeService modeService) throws RMIProblem,
232+
RemoteException {
230233
final SketchRunner sketchRunner = new SketchRunner(id, modeService);
231234
final SketchService stub = (SketchService) RMIUtils.export(sketchRunner);
232235
log("Calling mode's handleReady().");
@@ -244,8 +247,7 @@ public void run() {
244247
}));
245248
}
246249

247-
private SketchException convertREvalError(final REvalException exception,
248-
final String[] fileNames) {
250+
private SketchException convertREvalError(final REvalException exception) {
249251
return new SketchException(exception.getMessage());
250252
}
251253
}

0 commit comments

Comments
 (0)