@@ -97,6 +97,12 @@ public class Context implements Disposable, AutoCloseable {
9797 */
9898 private boolean strict ;
9999
100+ /**
101+ * False if the context is currently active; true if the context
102+ * has already been disposed, or is in the process of being disposed.
103+ */
104+ private boolean disposed ;
105+
100106 /**
101107 * Creates a new SciJava application context with all available services.
102108 *
@@ -284,6 +290,9 @@ public Context(final Collection<Class<? extends Service>> serviceClasses,
284290 new ServiceHelper (this , serviceClasses , strict );
285291 serviceHelper .loadServices ();
286292 }
293+
294+ // If JVM shuts down with context still active, clean up after ourselves.
295+ Runtime .getRuntime ().addShutdownHook (new Thread (() -> doDispose (false )));
287296 }
288297
289298 // -- Context methods --
@@ -418,16 +427,8 @@ public boolean isInjectable(final Class<?> type) {
418427
419428 @ Override
420429 public void dispose () {
421- final EventService eventService = getService (EventService .class );
422- if (eventService != null ) eventService .publish (new ContextDisposingEvent ());
423-
424- // NB: Dispose services in reverse order.
425- // This may or may not actually be necessary, but seems safer, since
426- // dependent services will be disposed *before* their dependencies.
427- final List <Service > services = serviceIndex .getAll ();
428- for (int s = services .size () - 1 ; s >= 0 ; s --) {
429- services .get (s ).dispose ();
430- }
430+ if (disposed ) return ;
431+ doDispose (true );
431432 }
432433
433434 // -- AutoCloseable methods --
@@ -580,6 +581,23 @@ private String createMissingServiceMessage(
580581 return msg .toString ();
581582 }
582583
584+ private synchronized void doDispose (final boolean announce ) {
585+ if (disposed ) return ;
586+ disposed = true ;
587+ if (announce ) {
588+ final EventService eventService = getService (EventService .class );
589+ if (eventService != null ) eventService .publish (new ContextDisposingEvent ());
590+ }
591+
592+ // NB: Dispose services in reverse order.
593+ // This may or may not actually be necessary, but seems safer, since
594+ // dependent services will be disposed *before* their dependencies.
595+ final List <Service > services = serviceIndex .getAll ();
596+ for (int s = services .size () - 1 ; s >= 0 ; s --) {
597+ services .get (s ).dispose ();
598+ }
599+ }
600+
583601 private static PluginIndex plugins (final boolean empty ) {
584602 return empty ? new PluginIndex (null ) : null ;
585603 }
0 commit comments