/* * Copyright (C) 2006-2016 DLR, Germany * * All rights reserved * * http://www.rcenvironment.de/ */ package de.rcenvironment.toolkit.core.internal; import java.util.HashSet; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import de.rcenvironment.toolkit.core.api.Toolkit; /** * Keeps track of all created and undisposed {@link Toolkit} instances to warn about leftover instances on shutdown (especially from * unit/integration tests). * * @author Robert Mischke * */ public final class ToolkitInstanceTracker { private static final ToolkitInstanceTracker sharedInstance = new ToolkitInstanceTracker(); private final Set<Toolkit> activeInstances = new HashSet<>(); /** * The shutdown hook wrapper; moved to a nested class as our code checking rules flag new Thread() as suspicious. * * Note: If actual Thread subclasses ever become a problem and the checks are adapted, they must have special treatment of shutdown * hooks, as the Java API enforces the {@link Thread} approach. * * @author Robert Mischke */ private final class ShutdownHook extends Thread { @Override public void run() { onJvmShutdown(); } } private ToolkitInstanceTracker() { Runtime.getRuntime().addShutdownHook(new ShutdownHook()); } public static ToolkitInstanceTracker getInstance() { return sharedInstance; } /** * Registers a new {@link Toolkit} instance; should be called as part of (or after) each creation of an instance. * * @param newInstance the new instance */ public synchronized void register(Toolkit newInstance) { if (!activeInstances.add(newInstance)) { throw new IllegalArgumentException("This toolkit instance was already registered"); } } /** * Reports that a {@link Toolkit} instance has been shutdown/disposed. * * @param oldInstance the disposed instance */ public synchronized void markDisposed(Toolkit oldInstance) { if (!activeInstances.remove(oldInstance)) { throw new IllegalArgumentException("This toolkit instance was never registered or was already disposed"); } } private synchronized void onJvmShutdown() { final Log log = LogFactory.getLog(getClass()); final int count = activeInstances.size(); if (count == 1) { log.debug("There is a single undisposed toolkit instance on JVM shutdown; this can be safely ignored after unit tests"); } else if (count > 1) { log.warn("There are " + count + " undisposed toolkit instances left on JVM shutdown; these should be explicitly shut down instead if possible"); } if (count != 0) { log.debug("Shutting down " + count + " toolkit instance(s)"); for (Toolkit instance : activeInstances) { instance.shutdown(); } } } }