2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.util.Platform;
25 import java.lang.reflect.Constructor;
26 import java.lang.reflect.InvocationTargetException;
27 import java.util.HashMap;
31 * A class to hold singleton objects, whose scope (context) is
33 * <li>the Java runtime (JVM) when running as Java</li>
34 * <li>one 'applet', when running as JalviewJS</li>
36 * This allows separation of multiple JS applets running on the same browser
37 * page, each with their own 'singleton' instances.
39 * Instance objects are held in a separate Map (keyed by Class) for each
40 * context. For Java, this is just a single static Map. For SwingJS, the map is
41 * stored as a field {@code _swingjsSingletons} of
42 * {@code Thread.currentThread.getThreadGroup()}, as a proxy for the applet.
44 * Note that when an applet is stopped, its ThreadGroup is removed, allowing any
45 * singleton references to be garbage collected.
49 public class ApplicationSingletonProvider
52 * A tagging interface to mark classes whose singleton instances may be served
53 * by {@code ApplicationSingletonProvider}, giving a distinct instance per JS
56 * A class whose singleton should have global scope (be shared across all
57 * applets on a page) should <em>not</em> use this mechanism, but just provide
58 * a single instance (class static member) in the normal way.
60 public interface ApplicationSingletonI
65 * Map used to hold singletons in JVM context
67 private static Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> singletons = new HashMap<>();
70 * private constructor for non-instantiable class
72 private ApplicationSingletonProvider()
77 * Returns the singletons map for the current context (JVM for Java,
78 * ThreadGroup for JS), creating the map on the first request for each JS
83 @SuppressWarnings("unchecked")
84 private static Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> getContextMap()
86 return (Platform.isJS()
87 ? (Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI>) Platform
93 * Answers the singleton instance of the given class for the current context
94 * (JVM or SwingJS 'applet'). If no instance yet exists, one is created, by
95 * calling the class's no-argument constructor. Answers null if any error
96 * occurs (or occurred previously for the same class).
101 public static ApplicationSingletonI getInstance(Class<? extends ApplicationSingletonI> c)
103 Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = getContextMap();
104 if (map.containsKey(c))
107 * singleton already created _or_ creation failed (null value stored)
113 * create and save the singleton
115 ApplicationSingletonI o = map.get(c);
118 Constructor<? extends ApplicationSingletonI> con = c
119 .getDeclaredConstructor();
120 con.setAccessible(true);
121 o = con.newInstance();
122 } catch (IllegalAccessException | InstantiationException
123 | IllegalArgumentException | InvocationTargetException
124 | NoSuchMethodException | SecurityException e)
126 Cache.log.error("Failed to create singleton for " + c.toString()
127 + ", error was: " + e.toString());
132 * store the new singleton; note that a
133 * null value is saved if construction failed
135 getContextMap().put(c, o);
140 * Removes the current singleton instance of the given class from the current
141 * application context. This has the effect of ensuring that a new instance is
142 * created the next time one is requested.
146 public static void removeInstance(
147 Class<? extends ApplicationSingletonI> c)
149 Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = getContextMap();