Clover icon

Coverage Report

  1. Project Clover database Wed Dec 10 2025 18:09:41 GMT
  2. Package jalview.bin

File ApplicationSingletonProvider.java

 

Coverage histogram

../../img/srcFileCovDistChart8.png
21% of files have more coverage

Code metrics

8
22
5
2
177
69
10
0.45
4.4
2.5
2

Classes

Class Line # Actions
ApplicationSingletonProvider 49 22 10
0.880%
ApplicationSingletonProvider.ApplicationSingletonI 60 0 0
-1.0 -
 

Contributing tests

This file is covered by 761 tests. .

Source view

1    /*
2    * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3    * Copyright (C) $$Year-Rel$$ The Jalview Authors
4    *
5    * This file is part of Jalview.
6    *
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.
11    *
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.
16    *
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.
20    */
21    package jalview.bin;
22   
23    import java.lang.reflect.Constructor;
24    import java.lang.reflect.InvocationTargetException;
25    import java.util.HashMap;
26    import java.util.Map;
27   
28    import jalview.util.Platform;
29   
30    /**
31    * A class to hold singleton objects, whose scope (context) is
32    * <ul>
33    * <li>the Java runtime (JVM) when running as Java</li>
34    * <li>one 'applet', when running as JalviewJS</li>
35    * </ul>
36    * This allows separation of multiple JS applets running on the same browser
37    * page, each with their own 'singleton' instances.
38    * <p>
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.
43    * <p>
44    * Note that when an applet is stopped, its ThreadGroup is removed, allowing any
45    * singleton references to be garbage collected.
46    *
47    * @author hansonr
48    */
 
49    public class ApplicationSingletonProvider
50    {
51    /**
52    * A tagging interface to mark classes whose singleton instances may be served
53    * by {@code ApplicationSingletonProvider}, giving a distinct instance per JS
54    * 'applet'.
55    * <p>
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.
59    */
 
60    public interface ApplicationSingletonI
61    {
62    }
63   
64    /*
65    * Map used to hold singletons in JVM context
66    */
67    private static Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> singletons = new HashMap<>();
68   
69    /**
70    * private constructor for non-instantiable class
71    */
 
72  0 toggle private ApplicationSingletonProvider()
73    {
74    }
75   
76    /**
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
79    * ThreadGroup
80    *
81    * @return
82    */
 
83  2516650 toggle private static Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> getContextMap()
84    {
85  2516651 @SuppressWarnings("unused")
86  2516644 ThreadGroup g = (Platform.isJS()
87    ? Thread.currentThread().getThreadGroup()
88    : null);
89  2516644 Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = singletons;
90    /** @j2sNative map = g._swingjsSingletons; */
91  2516647 if (map == null)
92    {
93  0 map = new HashMap<>();
94    /** @j2sNative g._swingjsSingletons = map; */
95    }
96   
97  2516649 return map;
98    }
99   
100    /**
101    * Returns boolean if the singleton instance has been instantiated for this
102    * Class
103    *
104    * @param c
105    * @return boolean
106    */
 
107  1158 toggle public static boolean instanceExists(
108    Class<? extends ApplicationSingletonI> c)
109    {
110  1158 Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = getContextMap();
111  1158 return map.containsKey(c) && map.get(c) != null;
112    }
113   
114    /**
115    * Answers the singleton instance of the given class for the current context
116    * (JVM or SwingJS 'applet'). If no instance yet exists, one is created, by
117    * calling the class's no-argument constructor. Answers null if any error
118    * occurs (or occurred previously for the same class).
119    *
120    * @param c
121    * @return
122    */
 
123  2514838 toggle @SuppressWarnings("unchecked")
124    public static <T extends ApplicationSingletonI> T getInstance(Class<T> c)
125    {
126  2514830 Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = getContextMap();
127  2514802 if (map.containsKey(c))
128    {
129    /*
130    * singleton already created _or_ creation failed (null value stored)
131    */
132  2514158 return (T) map.get(c);
133    }
134   
135    /*
136    * create and save the singleton
137    */
138  647 T o = null;
139  647 try
140    {
141  647 Constructor<T> con = c.getDeclaredConstructor();
142  647 con.setAccessible(true);
143  647 o = con.newInstance();
144    } catch (IllegalAccessException | InstantiationException
145    | IllegalArgumentException | InvocationTargetException
146    | NoSuchMethodException | SecurityException e)
147    {
148  0 Console.error("Failed to create singleton for " + c.toString()
149    + ", error was: " + e.toString());
150  0 e.printStackTrace();
151    }
152   
153    /*
154    * store the new singleton; note that a
155    * null value is saved if construction failed
156    */
157  647 getContextMap().put(c, o);
158  647 return o;
159    }
160   
161    /**
162    * Removes the current singleton instance of the given class from the current
163    * application context. This has the effect of ensuring that a new instance is
164    * created the next time one is requested.
165    *
166    * @param c
167    */
 
168  20 toggle public static void removeInstance(
169    Class<? extends ApplicationSingletonI> c)
170    {
171  20 Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = getContextMap();
172  20 if (map != null)
173    {
174  20 map.remove(c);
175    }
176    }
177    }