Jme Application Template with enqueue tracing

So I had an idea yesterday, and while drinking my coffee this morning decided to implement it.

I have been fighting trying to trace exceptions from enqueued tasks due to the heavy use of multithreading in Outside. So I had an idea of adding a wrapper around the enqueue task for tracing back the exception to the actual source of what added the task.

I figured I would share it so that it may be of use to others as well, perhaps it can be improved upon.
This is my standard jme wrapper for Outside with the implemented changes to enqueue:

public class JmeApplication extends SimpleApplication {

    private final static Logger LOGGER = Logger.getLogger(Outside.class.getName());
    private File appSettings = new File("graphics.properties");

    @Override
    public void simpleInitApp() {
        this.getFlyByCamera().setEnabled(false);
        this.setDisplayFps(false);
        this.setDisplayStatView(false);
    }

    public void setPaused(boolean pause) {
        this.paused = pause;
    }

    public boolean getPaused() {
        return paused;
    }

    public void saveSettings() {
        try {
            settings.save(new FileOutputStream(appSettings));
        } catch (Exception ex) {
            LOGGER.log(Level.WARNING, "Failed to save settings", ex);
        }
    }

    public void loadSettings() {
        try {
            if (appSettings.exists()) {
                settings.load(new FileInputStream(appSettings));
            } else {
                settings.save(new FileOutputStream(appSettings));
            }
        } catch (Exception ex) {
            LOGGER.log(Level.WARNING, "Failed to save settings", ex);
        }
    }

    @Override
    public <V> Future<V> enqueue(Callable<V> callable) {
        final Throwable tracer = new Throwable("Enqueue Tracer");
        Callable<V> wrapper = () -> {
            try {
                return callable.call();
            } catch (Exception ex) {
                ex.addSuppressed(tracer);
                throw new RuntimeException("Jme Enqueued Task Exception", ex);
            }
        };
        return super.enqueue(wrapper);
    }


    @Override
    public void enqueue(Runnable runnable) {
        final Throwable tracer = new Throwable("Enqueue Tracer");
        Runnable wrapper = () -> {
            try {
                runnable.run();
            } catch (Exception ex) {
                ex.addSuppressed(tracer);
                throw new RuntimeException("Jme Enqueued Task Exception", ex);
            }
        };
        super.enqueue(wrapper);
    }
}

A sample stack trace:

[2021-02-16 11:11:27] [SEVERE ] Exception 
java.lang.RuntimeException: Jme Enqueued Task Exception
	at io.tlf.outside.jme.JmeApplication.lambda$enqueue$0(JmeApplication.java:63)
	at com.jme3.app.AppTask.invoke(AppTask.java:147)
	at com.jme3.app.LegacyApplication.runQueuedTasks(LegacyApplication.java:733)
	at com.jme3.app.LegacyApplication.update(LegacyApplication.java:748)
	at com.jme3.app.SimpleApplication.update(SimpleApplication.java:247)
	at com.jme3.system.lwjgl.LwjglWindow.runLoop(LwjglWindow.java:537)
	at com.jme3.system.lwjgl.LwjglWindow.run(LwjglWindow.java:639)
	at com.jme3.system.lwjgl.LwjglWindow.create(LwjglWindow.java:473)
	at com.jme3.app.LegacyApplication.start(LegacyApplication.java:481)
	at com.jme3.app.LegacyApplication.start(LegacyApplication.java:441)
	at com.jme3.app.SimpleApplication.start(SimpleApplication.java:128)
	at io.tlf.outside.client.Client.load(Client.java:87)
	at io.tlf.outside.client.Main.launch(Main.java:133)
	at io.tlf.outside.client.Main.main(Main.java:90)
Caused by: java.lang.RuntimeException: Test
	at io.tlf.outside.client.Client.lambda$buildClient$0(Client.java:242)
	at io.tlf.outside.jme.JmeApplication.lambda$enqueue$0(JmeApplication.java:60)
	... 13 more
	Suppressed: java.lang.Throwable: Enqueue Tracer
		at io.tlf.outside.jme.JmeApplication.enqueue(JmeApplication.java:57)
		at io.tlf.outside.client.Client.buildClient(Client.java:240)
		at io.tlf.outside.client.Client$1.run(Client.java:78)

It gives me both the actual exception, and the Enqueue tracer to the code that added the task.

Just thought I would share, I hope this is useful to someone.

8 Likes
1 Like