Clover icon

Coverage Report

  1. Project Clover database Thu Dec 4 2025 16:11:35 GMT
  2. Package jalview.bin

File ApplicationSingletonProvider.java

 

Coverage histogram

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

Code metrics

8
20
4
2
163
63
9
0.45
5
2
2.25

Classes

Class Line # Actions
ApplicationSingletonProvider 49 20 9
0.7812578.1%
ApplicationSingletonProvider.ApplicationSingletonI 60 0 0
-1.0 -
 

Contributing tests

This file is covered by 713 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 jalview.util.Platform;
24   
25    import java.lang.reflect.Constructor;
26    import java.lang.reflect.InvocationTargetException;
27    import java.util.HashMap;
28    import java.util.Map;
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  2344891 toggle private static Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> getContextMap()
84    {
85  2344894 @SuppressWarnings("unused")
86  2344849 ThreadGroup g = (Platform.isJS()
87    ? Thread.currentThread().getThreadGroup()
88    : null);
89  2344854 Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = singletons;
90    /** @j2sNative map = g._swingjsSingletons; */
91  2344862 if (map == null)
92    {
93  0 map = new HashMap<>();
94    /** @j2sNative g._swingjsSingletons = map; */
95    }
96   
97  2344868 return map;
98    }
99   
100    /**
101    * Answers the singleton instance of the given class for the current context
102    * (JVM or SwingJS 'applet'). If no instance yet exists, one is created, by
103    * calling the class's no-argument constructor. Answers null if any error
104    * occurs (or occurred previously for the same class).
105    *
106    * @param c
107    * @return
108    */
 
109  2344212 toggle @SuppressWarnings("unchecked")
110    public static <T extends ApplicationSingletonI> T getInstance(Class<T> c)
111    {
112  2344223 Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = getContextMap();
113  2344223 if (map.containsKey(c))
114    {
115    /*
116    * singleton already created _or_ creation failed (null value stored)
117    */
118  2343559 return (T) map.get(c);
119    }
120   
121    /*
122    * create and save the singleton
123    */
124  647 T o = null;
125  647 try
126    {
127  647 Constructor<T> con = c.getDeclaredConstructor();
128  647 con.setAccessible(true);
129  647 o = con.newInstance();
130    } catch (IllegalAccessException | InstantiationException
131    | IllegalArgumentException | InvocationTargetException
132    | NoSuchMethodException | SecurityException e)
133    {
134  0 Console.error("Failed to create singleton for " + c.toString()
135    + ", error was: " + e.toString());
136  0 e.printStackTrace();
137    }
138   
139    /*
140    * store the new singleton; note that a
141    * null value is saved if construction failed
142    */
143  646 getContextMap().put(c, o);
144  646 return o;
145    }
146   
147    /**
148    * Removes the current singleton instance of the given class from the current
149    * application context. This has the effect of ensuring that a new instance is
150    * created the next time one is requested.
151    *
152    * @param c
153    */
 
154  20 toggle public static void removeInstance(
155    Class<? extends ApplicationSingletonI> c)
156    {
157  20 Map<Class<? extends ApplicationSingletonI>, ApplicationSingletonI> map = getContextMap();
158  20 if (map != null)
159    {
160  20 map.remove(c);
161    }
162    }
163    }