+++ /dev/null
-/*
- * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
- * Copyright (C) $$Year-Rel$$ The Jalview Authors
- *
- * This file is part of Jalview.
- *
- * Jalview is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation, either version 3
- * of the License, or (at your option) any later version.
- *
- * Jalview is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
- * The Jalview Authors are detailed in the 'AUTHORS' file.
- */
-package jalview.bin;
-
-import jalview.util.Platform;
-
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * A class to hold singleton objects, whose scope (context) is
- * <ul>
- * <li>the Java runtime (JVM) when running as Java</li>
- * <li>one 'applet', when running as JalviewJS</li>
- * </ul>
- * This allows separation of multiple JS applets running on the same browser
- * page, each with their own 'singleton' instances.
- * <p>
- * Instance objects are held in a separate Map (keyed by Class) for each
- * context. For Java, this is just a single static Map. For SwingJS, the map is
- * stored as a field {@code _swingjsSingletons} of
- * {@code Thread.currentThread.getThreadGroup()}, as a proxy for the applet.
- * <p>
- * Note that when an applet is stopped, its ThreadGroup is removed, allowing any
- * singleton references to be garbage collected.
- *
- * @author hansonr
- */
-public class ApplicationSingletonProvider
-{
- /**
- * A tagging interface to mark classes whose singleton instances may be served
- * by {@code ApplicationSingletonProvider}, giving a distinct instance per JS
- * 'applet'.
- * <p>
- * A class whose singleton should have global scope (be shared across all
- * applets on a page) should <em>not</em> use this mechanism, but just provide
- * a single instance (class static member) in the normal way.
- */
- public interface ApplicationSingletonI
- {
- }
-
- /*
- * Map used to hold singletons in JVM context
- */
- private static Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> singletons = new HashMap<>();
-
- /**
- * private constructor for non-instantiable class
- */
- private ApplicationSingletonProvider()
- {
- }
-
- /**
- * Returns the singletons map for the current context (JVM for Java,
- * ThreadGroup for JS), creating the map on the first request for each JS
- * ThreadGroup
- *
- * @return
- */
- private static Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> getContextMap()
- {
- @SuppressWarnings("unused")
- ThreadGroup g = (Platform.isJS()
- ? Thread.currentThread().getThreadGroup()
- : null);
- Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = singletons;
- /** @j2sNative map = g._swingjsSingletons; */
- if (map == null)
- {
- map = new HashMap<>();
- /** @j2sNative g._swingjsSingletons = map; */
- }
-
- return map;
- }
-
- /**
- * Answers the singleton instance of the given class for the current context
- * (JVM or SwingJS 'applet'). If no instance yet exists, one is created, by
- * calling the class's no-argument constructor. Answers null if any error
- * occurs (or occurred previously for the same class).
- *
- * @param c
- * @return
- */
- public static ApplicationSingletonI getInstance(Class<? extends ApplicationSingletonI> c)
- {
- Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = getContextMap();
- if (map.containsKey(c))
- {
- /*
- * singleton already created _or_ creation failed (null value stored)
- */
- return map.get(c);
- }
-
- /*
- * create and save the singleton
- */
- ApplicationSingletonI o = map.get(c);
- try
- {
- Constructor<? extends ApplicationSingletonI> con = c
- .getDeclaredConstructor();
- con.setAccessible(true);
- o = con.newInstance();
- } catch (IllegalAccessException | InstantiationException
- | IllegalArgumentException | InvocationTargetException
- | NoSuchMethodException | SecurityException e)
- {
- Cache.log.error("Failed to create singleton for " + c.toString()
- + ", error was: " + e.toString());
- e.printStackTrace();
- }
-
- /*
- * store the new singleton; note that a
- * null value is saved if construction failed
- */
- getContextMap().put(c, o);
-
- return o;
- }
-
- /**
- * Removes the current singleton instance of the given class from the current
- * application context. This has the effect of ensuring that a new instance is
- * created the next time one is requested.
- *
- * @param c
- */
- public static void removeInstance(
- Class<? extends ApplicationSingletonI> c)
- {
- Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = getContextMap();
- if (map != null)
- {
- map.remove(c);
- }
- }
-}