From 5721b73c6d5de84b21a989a8734e4c161f5dc630 Mon Sep 17 00:00:00 2001 From: hansonr Date: Wed, 8 May 2019 16:42:23 -0500 Subject: [PATCH] JAL-3253 preliminary static fixes for JavaScript part 2 Includes lazy dynamic loading of SequenceFetcher database options. Note that if WebServices menu is enabled (Java, not JavaScript), then all web-based database proxies are instantiated anyway. --- src/jalview/analysis/AlignmentSorter.java | 28 ++-- src/jalview/bin/Cache.java | 177 ++++++++++++++++---- src/jalview/bin/Jalview.java | 2 +- src/jalview/commands/ChangeCaseCommand.java | 16 +- src/jalview/datamodel/Alignment.java | 3 +- src/jalview/datamodel/DBRefSource.java | 15 +- src/jalview/datamodel/ResidueCount.java | 5 +- .../datamodel/SecondaryStructureAnnotation.java | 6 +- src/jalview/ext/ensembl/EnsemblInfo.java | 131 ++++++++++----- src/jalview/ext/ensembl/EnsemblMap.java | 12 +- src/jalview/ext/ensembl/EnsemblRestClient.java | 2 +- src/jalview/fts/service/pdb/PDBFTSRestClient.java | 44 ++++- .../fts/service/uniprot/UniProtFTSRestClient.java | 44 ++++- src/jalview/gui/AlignFrame.java | 35 ++-- src/jalview/gui/AnnotationColumnChooser.java | 6 +- src/jalview/gui/AnnotationLabels.java | 6 +- src/jalview/gui/AppVarnaBinding.java | 7 +- src/jalview/gui/ColourMenuHelper.java | 2 +- src/jalview/gui/Console.java | 3 +- src/jalview/gui/CrossRefAction.java | 2 +- src/jalview/gui/Desktop.java | 22 +-- src/jalview/gui/JalviewAppender.java | 10 +- src/jalview/gui/LineartOptions.java | 2 +- src/jalview/gui/MenuChooser.java | 13 +- src/jalview/gui/Preferences.java | 153 ++++++++--------- src/jalview/jbgui/GPreferences.java | 19 ++- .../structures/models/AAStructureBindingModel.java | 16 +- src/jalview/ws/SequenceFetcher.java | 40 +++-- src/jalview/ws/dbsources/PfamFull.java | 4 +- src/jalview/ws/dbsources/PfamSeed.java | 4 +- src/jalview/ws/seqfetcher/ASequenceFetcher.java | 127 +++++++++++--- src/jalview/ws/seqfetcher/DbSourceProxy.java | 8 +- src/jalview/ws/seqfetcher/DbSourceProxyRoot.java | 11 ++ test/jalview/analysis/FinderTest.java | 2 +- test/jalview/analysis/GeneticCodesTest.java | 48 +++--- test/jalview/ext/jmol/JmolParserTest.java | 6 +- test/jalview/gui/AlignFrameTest.java | 2 +- test/jalview/gui/AlignViewportTest.java | 14 +- test/jalview/gui/AlignmentPanelTest.java | 2 +- test/jalview/gui/AnnotationChooserTest.java | 10 +- test/jalview/gui/AnnotationColumnChooserTest.java | 10 +- test/jalview/gui/AnnotationRowFilterTest.java | 4 +- test/jalview/gui/CalculationChooserTest.java | 4 +- test/jalview/gui/FreeUpMemoryTest.java | 10 +- test/jalview/gui/SeqPanelTest.java | 16 +- test/jalview/io/AnnotatedPDBFileInputTest.java | 4 +- test/jalview/io/BackupFilesTest.java | 14 +- test/jalview/ws/PDBSequenceFetcherTest.java | 6 +- test/jalview/ws/dbsources/RemoteFormatTest.java | 4 +- test/mc_view/PDBfileTest.java | 6 +- 50 files changed, 733 insertions(+), 404 deletions(-) create mode 100644 src/jalview/ws/seqfetcher/DbSourceProxyRoot.java diff --git a/src/jalview/analysis/AlignmentSorter.java b/src/jalview/analysis/AlignmentSorter.java index e5038ba..427db84 100755 --- a/src/jalview/analysis/AlignmentSorter.java +++ b/src/jalview/analysis/AlignmentSorter.java @@ -55,6 +55,18 @@ import java.util.List; public class AlignmentSorter { + /** + * types of feature ordering: Sort by score : average score - or total score - + * over all features in region Sort by feature label text: (or if null - + * feature type text) - numerical or alphabetical Sort by feature density: + * based on counts - ignoring individual text or scores for each feature + */ + public static final String FEATURE_SCORE = "average_score"; + + public static final String FEATURE_LABEL = "text"; + + public static final String FEATURE_DENSITY = "density"; + static AlignmentSorter instance; public static AlignmentSorter getInstance() @@ -69,7 +81,7 @@ public class AlignmentSorter { g = Thread.currentThread().getThreadGroup(); /** - * @j2sNative i = g._jalviewScoreModelsInstance; + * @j2sNative i = g._jalviewAlignmentSorterInstance; * */ } @@ -80,7 +92,7 @@ public class AlignmentSorter if (Platform.isJS()) { /** - * @j2sNative g._jalviewScoreModelsInstance = i; + * @j2sNative g._jalviewAlignmentSorterInstance = i; * */ } @@ -722,18 +734,6 @@ public class AlignmentSorter } /** - * types of feature ordering: Sort by score : average score - or total score - - * over all features in region Sort by feature label text: (or if null - - * feature type text) - numerical or alphabetical Sort by feature density: - * based on counts - ignoring individual text or scores for each feature - */ - public static String FEATURE_SCORE = "average_score"; - - public static String FEATURE_LABEL = "text"; - - public static String FEATURE_DENSITY = "density"; - - /** * Sort sequences by feature score or density, optionally restricted by * feature types, feature groups, or alignment start/end positions. *

diff --git a/src/jalview/bin/Cache.java b/src/jalview/bin/Cache.java index fe136bc..b2f6e95 100755 --- a/src/jalview/bin/Cache.java +++ b/src/jalview/bin/Cache.java @@ -209,6 +209,50 @@ import org.apache.log4j.SimpleLayout; */ public class Cache { + + static Cache instance; + + /** + * In Java, this will be a static field instance, which will be + * application-specific; in JavaScript it will be an applet-specific instance + * tied to the applet's ThreadGroup. + * + * @return + */ + public static Cache getInstance() + { + + // BH 2019.05.08 need to isolate static fields in JavaScript + + Cache i = instance; + @SuppressWarnings("unused") + ThreadGroup g = null; + if (Platform.isJS()) + { + g = Thread.currentThread().getThreadGroup(); + /** + * @j2sNative i = g._jalviewCacheInstance; + * + */ + } + if (i == null) + { + i = new Cache(); + if (Platform.isJS()) + { + /** + * @j2sNative g._jalviewCacheInstance = i; + * + */ + } + else + { + instance = i; + } + } + return i; + } + /** * property giving log4j level for CASTOR loggers */ @@ -264,8 +308,15 @@ public class Cache */ public static Logger log; + private Cache() + { + // inaccessible + } + /** Jalview Properties */ - public static Properties applicationProperties = new Properties() + // BH 2019.05.08 was static + @SuppressWarnings("serial") + private Properties applicationProperties = new Properties() { // override results in properties output in alphabetical order @Override @@ -276,9 +327,13 @@ public class Cache }; /** Default file is ~/.jalview_properties */ + // BH 2019.05.07 note: Instances of Jalview will share this file. static String propertiesFile; - private static boolean propsAreReadOnly = Platform.isJS(); + /** + * flag to possibly allow properties to be written to a property file + */ + private boolean propsAreReadOnly = Platform.isJS(); private final static String JS_PROPERTY_PREFIX = "jalview_"; @@ -332,20 +387,30 @@ public class Cache */ public static void loadProperties(String propsFile) { + getInstance().loadPropertiesImpl(propsFile); + } + + private void loadPropertiesImpl(String propsFile) + { propertiesFile = propsFile; - if (propsFile == null && !propsAreReadOnly) - { - propertiesFile = System.getProperty("user.home") + File.separatorChar - + ".jalview_properties"; - } - else + if (!propsAreReadOnly) { - // don't corrupt the file we've been given. - propsAreReadOnly = true; + // Java only + if (propsFile == null) + { + propertiesFile = System.getProperty("user.home") + + File.separatorChar + ".jalview_properties"; + } + else + { + // don't corrupt the file we've been given. + propsAreReadOnly = true; + } } if (propertiesFile == null) - { // BH 2019 + { // BH 2019 read properties from the Info object associated with this + // applet Platform.readInfoProperties(JS_PROPERTY_PREFIX, applicationProperties); } @@ -572,7 +637,7 @@ public class Cache } - private static void deleteBuildProperties() + private void deleteBuildProperties() { applicationProperties.remove("LATEST_VERSION"); applicationProperties.remove("VERSION"); @@ -594,6 +659,11 @@ public class Cache */ public static String getProperty(String key) { + return getInstance().getPropertyImpl(key); + } + + private String getPropertyImpl(String key) + { String prop = applicationProperties.getProperty(key); if (prop == null && Platform.isJS()) { @@ -659,11 +729,21 @@ public class Cache */ public static Object setProperty(String key, String obj) { + return getInstance().setPropertyImpl(key, obj, true); + } + + public static void setPropertyNoSave(String key, String obj) + { + getInstance().setPropertyImpl(key, obj, false); + } + + private Object setPropertyImpl(String key, String obj, boolean andSave) + { Object oldValue = null; try { oldValue = applicationProperties.setProperty(key, obj); - if (!propsAreReadOnly) + if (andSave && !propsAreReadOnly) { FileOutputStream out = new FileOutputStream(propertiesFile); applicationProperties.store(out, "---JalviewX Properties File---"); @@ -680,18 +760,36 @@ public class Cache /** * remove the specified property from the jalview properties file * - * @param string + * @param key */ - public static void removeProperty(String string) + public static void removeProperty(String key) + { + getInstance().removePropertyImpl(key, true); + } + + public static void removePropertyNoSave(String key) + { + getInstance().removePropertyImpl(key, false); + } + + private void removePropertyImpl(String key, boolean andSave) + { + applicationProperties.remove(key); + if (andSave) + { + savePropertiesImpl(); + } + } + + public static void saveProperties() { - applicationProperties.remove(string); - saveProperties(); + getInstance().savePropertiesImpl(); } /** * save the properties to the jalview properties path */ - public static void saveProperties() + private void savePropertiesImpl() { if (!propsAreReadOnly) { @@ -707,10 +805,17 @@ public class Cache } } + private final static int UNTESTED = -1; + + private final static int TRUE = 1; + + private final static int FALSE = 0; + /** * internal vamsas class discovery state */ - private static int vamsasJarsArePresent = -1; + private static int vamsasJarsArePresent = (Platform.isJS() ? FALSE + : UNTESTED); /** * Searches for vamsas client classes on class path. @@ -719,7 +824,7 @@ public class Cache */ public static boolean vamsasJarsPresent() { - if (vamsasJarsArePresent == -1) + if (vamsasJarsArePresent == UNTESTED) { try { @@ -728,7 +833,7 @@ public class Cache { jalview.bin.Cache.log.debug( "Found Vamsas Classes (uk.ac..vamsas.client.VorbaId can be loaded)"); - vamsasJarsArePresent = 1; + vamsasJarsArePresent = TRUE; Logger lvclient = Logger.getLogger("uk.ac.vamsas"); lvclient.setLevel(Level.toLevel(Cache .getDefault("logs.Vamsas.Level", Level.INFO.toString()))); @@ -739,17 +844,18 @@ public class Cache } } catch (Exception e) { - vamsasJarsArePresent = 0; + vamsasJarsArePresent = FALSE; jalview.bin.Cache.log.debug("Vamsas Classes are not present"); } } - return (vamsasJarsArePresent > 0); + return (vamsasJarsArePresent == TRUE); } /** * internal vamsas class discovery state */ - private static int groovyJarsArePresent = -1; + private static int groovyJarsArePresent = (Platform.isJS() ? FALSE + : UNTESTED); /** * Searches for vamsas client classes on class path. @@ -758,7 +864,7 @@ public class Cache */ public static boolean groovyJarsPresent() { - if (groovyJarsArePresent == -1) + if (groovyJarsArePresent == UNTESTED) { try { @@ -767,7 +873,7 @@ public class Cache { jalview.bin.Cache.log.debug( "Found Groovy (groovy.lang.GroovyObject can be loaded)"); - groovyJarsArePresent = 1; + groovyJarsArePresent = TRUE; Logger lgclient = Logger.getLogger("groovy"); lgclient.setLevel(Level.toLevel(Cache .getDefault("logs.Groovy.Level", Level.INFO.toString()))); @@ -778,15 +884,15 @@ public class Cache } } catch (Error e) { - groovyJarsArePresent = 0; + groovyJarsArePresent = FALSE; jalview.bin.Cache.log.debug("Groovy Classes are not present", e); } catch (Exception e) { - groovyJarsArePresent = 0; + groovyJarsArePresent = FALSE; jalview.bin.Cache.log.debug("Groovy Classes are not present"); } } - return (groovyJarsArePresent > 0); + return (groovyJarsArePresent == TRUE); } /** @@ -795,15 +901,18 @@ public class Cache */ protected static Object tracker = null; - protected static Class trackerfocus = null; + protected static Class trackerfocus = null; - protected static Class jgoogleanalyticstracker = null; + protected static Class jgoogleanalyticstracker = null; /** * Initialise the google tracker if it is not done already. */ public static void initGoogleTracker() { + + // TODO: SwingJS JavaScript tracker? + if (tracker == null) { if (jgoogleanalyticstracker == null) @@ -1027,11 +1136,11 @@ public class Cache } if (value == null || value.trim().length() < 1) { - Cache.applicationProperties.remove(propName); + getInstance().applicationProperties.remove(propName); } else { - Cache.applicationProperties.setProperty(propName, value); + getInstance().applicationProperties.setProperty(propName, value); } } @@ -1081,7 +1190,7 @@ public class Cache } else { - applicationProperties + getInstance().applicationProperties .remove(UserDefinedColours.USER_DEFINED_COLOURS); } } diff --git a/src/jalview/bin/Jalview.java b/src/jalview/bin/Jalview.java index fcda026..9740423 100755 --- a/src/jalview/bin/Jalview.java +++ b/src/jalview/bin/Jalview.java @@ -124,7 +124,7 @@ public class Jalview @SuppressWarnings("unused") ThreadGroup g = Thread.currentThread().getThreadGroup(); /** - * @j2s g._jalviewInstance = j; + * @j2sNative g._jalviewInstance = j; */ { instance = j; diff --git a/src/jalview/commands/ChangeCaseCommand.java b/src/jalview/commands/ChangeCaseCommand.java index 7f7142f1..f0ea2f6 100644 --- a/src/jalview/commands/ChangeCaseCommand.java +++ b/src/jalview/commands/ChangeCaseCommand.java @@ -29,17 +29,17 @@ public class ChangeCaseCommand implements CommandI { String description; - public static int TO_LOWER = 0; + public final static int TO_LOWER = 0; - public static int TO_UPPER = 1; + public final static int TO_UPPER = 1; - public static int TOGGLE_CASE = 2; + public final static int TOGGLE_CASE = 2; - int caseChange = -1; + private int caseChange; - SequenceI[] seqs; + private SequenceI[] seqs; - List regions; + private List regions; public ChangeCaseCommand(String description, SequenceI[] seqs, List regions, int caseChange) @@ -51,21 +51,25 @@ public class ChangeCaseCommand implements CommandI doCommand(null); } + @Override public String getDescription() { return description; } + @Override public int getSize() { return 1; } + @Override public void doCommand(AlignmentI[] views) { changeCase(true); } + @Override public void undoCommand(AlignmentI[] views) { changeCase(false); diff --git a/src/jalview/datamodel/Alignment.java b/src/jalview/datamodel/Alignment.java index 1956df7..b214934 100755 --- a/src/jalview/datamodel/Alignment.java +++ b/src/jalview/datamodel/Alignment.java @@ -125,8 +125,7 @@ public class Alignment implements AlignmentI /** * Make a new alignment from an array of SeqCigars * - * @param seqs - * SeqCigar[] + * @param alseqs */ public Alignment(SeqCigar[] alseqs) { diff --git a/src/jalview/datamodel/DBRefSource.java b/src/jalview/datamodel/DBRefSource.java index 2f94884..71d6972 100755 --- a/src/jalview/datamodel/DBRefSource.java +++ b/src/jalview/datamodel/DBRefSource.java @@ -42,7 +42,8 @@ public class DBRefSource public static final String UNIPROT = "UNIPROT"; - public static final String UP_NAME = "UNIPROT_NAME".toUpperCase(); + + public static final String UP_NAME = "UNIPROT_NAME"; /** * Uniprot Knowledgebase/TrEMBL as served from EMBL protein products. */ @@ -56,10 +57,18 @@ public class DBRefSource public static final String EMBLCDSProduct = "EMBLCDSProtein".toUpperCase(); public static final String PDB = "PDB"; - public static final String PFAM = "PFAM"; + + public static final String PFAM = "PFAM"; + public static final String RFAM = "RFAM"; public static final String GENEDB = "GeneDB".toUpperCase(); + public static final String PFAM_FULL = "PFAM (Full)"; + + public static final String PFAM_SEED = "PFAM (Seed)"; + + public static final String RFAM_SEED = "RFAM (Seed)"; + public static final String PDB_CANONICAL_NAME = PDB; @@ -135,7 +144,7 @@ public class DBRefSource // CODINGDBS, DNACODINGDBS, PROTEINDBS }; // public static final int PRIMARY_SOURCES_MASK = CODING_MASK | DNA_CODING_MASK | PROTEIN_MASK; - + public static boolean isPrimarySource(String source) { return ((PRIMARY_SOURCES_MASK & getSourceKey(source)) != 0); diff --git a/src/jalview/datamodel/ResidueCount.java b/src/jalview/datamodel/ResidueCount.java index 74eb887..bb604d0 100644 --- a/src/jalview/datamodel/ResidueCount.java +++ b/src/jalview/datamodel/ResidueCount.java @@ -76,9 +76,10 @@ public class ResidueCount * fast lookup tables holding the index into our count * arrays of each symbol; index 0 is reserved for gap counting */ - private static int[] NUC_INDEX = new int[26]; + private final static int[] NUC_INDEX = new int[26]; + + private final static int[] AA_INDEX = new int[26]; - private static int[] AA_INDEX = new int[26]; static { for (int i = 0; i < NUCS.length(); i++) diff --git a/src/jalview/datamodel/SecondaryStructureAnnotation.java b/src/jalview/datamodel/SecondaryStructureAnnotation.java index 476eb19..e395648 100644 --- a/src/jalview/datamodel/SecondaryStructureAnnotation.java +++ b/src/jalview/datamodel/SecondaryStructureAnnotation.java @@ -25,7 +25,9 @@ import fr.orsay.lri.varna.models.rna.RNA; public class SecondaryStructureAnnotation extends AlignmentAnnotation { - private static RNA _rna = null; + // was static, but that cannot work here + + private RNA _rna = null; public SecondaryStructureAnnotation(RNA rna) { @@ -44,7 +46,7 @@ public class SecondaryStructureAnnotation extends AlignmentAnnotation Annotation[] ann = new Annotation[rna.getSize()]; for (int i = 0; i < ann.length; i++) { - ann[i] = new Annotation(_rna.getStructDBN(true), "", ' ', 0f); + ann[i] = new Annotation(rna.getStructDBN(true), "", ' ', 0f); ; } return ann; diff --git a/src/jalview/ext/ensembl/EnsemblInfo.java b/src/jalview/ext/ensembl/EnsemblInfo.java index 97a8e74..7bc4139 100644 --- a/src/jalview/ext/ensembl/EnsemblInfo.java +++ b/src/jalview/ext/ensembl/EnsemblInfo.java @@ -2,9 +2,7 @@ package jalview.ext.ensembl; import jalview.datamodel.AlignmentI; import jalview.datamodel.DBRefSource; -import jalview.util.JSONUtils; -import java.io.BufferedReader; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; @@ -19,6 +17,58 @@ import org.json.simple.parser.ParseException; public class EnsemblInfo extends EnsemblRestClient { + private static EnsemblInfo instance; + + /** + * Some question as to whether it is necessary to do this for each applet. IN + * PRINCIPLE, applets could set different properties for the origin of Ensembl + * data. But I suggest this is unlikely. If we DO care about that possibility, + * then we need to set doICare to Platform.isJS(); + * + */ + private final static boolean doICare = false;// Platform.isJS(); + + /** + * On first request only, populate the lookup map by fetching the list of + * divisions known to EnsemblGenomes. + * + */ + private static EnsemblInfo getInstance() + { + + // BH 2019.05.08 need to isolate static fields in JavaScript + + EnsemblInfo i = instance; + @SuppressWarnings("unused") + ThreadGroup g = null; + + if (doICare) + { + g = Thread.currentThread().getThreadGroup(); + /** + * @j2sNative i = g._jalviewEnsemblInstance; + * + */ + } + if (i == null) + { + i = new EnsemblInfo(); + + if (doICare) + { + /** + * @j2sNative g._jalviewEnsemblInstance = i; + * + */ + } + else + { + instance = i; + } + } + return i; + } + /* * cached results of REST /info/divisions service, currently *

@@ -34,7 +84,35 @@ public class EnsemblInfo extends EnsemblRestClient
    * The values for EnsemblGenomes are retrieved by a REST call, that for
    * Ensembl is added programmatically for convenience of lookup
    */
-  private static Map divisions;
+  private Map divisions = new HashMap<>();
+
+  private EnsemblInfo()
+  {
+
+    /*
+     * for convenience, pre-fill ensembl.org as the domain for "ENSEMBL"
+     */
+    divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ensemblDomain);
+    try
+    {
+      @SuppressWarnings("unchecked")
+      Iterator rvals = (Iterator) getJSON(
+              getDivisionsUrl(ensemblGenomesDomain), null, -1,
+              MODE_ITERATOR, null);
+      if (rvals == null)
+      {
+        return;
+      }
+      while (rvals.hasNext())
+      {
+        String division = rvals.next().toString();
+        divisions.put(division.toUpperCase(), ensemblGenomesDomain);
+      }
+    } catch (IOException | ParseException | NumberFormatException e)
+    {
+      // ignore
+    }
+  }
 
   @Override
   public String getDbName()
@@ -68,42 +146,9 @@ public class EnsemblInfo extends EnsemblRestClient
    * @param division
    * @return
    */
-  public String getDomain(String division)
+  public static String getDomain(String division)
   {
-    if (divisions == null)
-    {
-      fetchDivisions();
-    }
-    return divisions.get(division.toUpperCase());
-  }
-
-  /**
-   * On first request only, populate the lookup map by fetching the list of
-   * divisions known to EnsemblGenomes.
-   */
-  void fetchDivisions()
-  {
-    divisions = new HashMap<>();
-
-    /*
-     * for convenience, pre-fill ensembl.org as the domain for "ENSEMBL"
-     */
-    divisions.put(DBRefSource.ENSEMBL.toUpperCase(), ensemblDomain);
-    try
-    {
-      @SuppressWarnings("unchecked")
-   	  Iterator rvals = (Iterator) getJSON(getDivisionsUrl(ensemblGenomesDomain), null, -1, MODE_ITERATOR, null);
-      if (rvals == null)
-    	  return;
-      while (rvals.hasNext())
-      {
-        String division = rvals.next().toString();
-        divisions.put(division.toUpperCase(), ensemblGenomesDomain);
-      }
-    } catch (IOException | ParseException | NumberFormatException e)
-    {
-      // ignore
-    }
+    return getInstance().divisions.get(division.toUpperCase());
   }
 
   /**
@@ -124,12 +169,8 @@ public class EnsemblInfo extends EnsemblRestClient
    * 
    * @return
    */
-  public Set getDivisions() {
-    if (divisions == null)
-    {
-      fetchDivisions();
-    }
-
-    return divisions.keySet();
+  public static Set getDivisions()
+  {
+    return getInstance().divisions.keySet();
   }
 }
diff --git a/src/jalview/ext/ensembl/EnsemblMap.java b/src/jalview/ext/ensembl/EnsemblMap.java
index add71b3..9789819 100644
--- a/src/jalview/ext/ensembl/EnsemblMap.java
+++ b/src/jalview/ext/ensembl/EnsemblMap.java
@@ -3,10 +3,8 @@ package jalview.ext.ensembl;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.DBRefSource;
 import jalview.datamodel.GeneLociI;
-import jalview.util.JSONUtils;
 import jalview.util.MapList;
 
-import java.io.BufferedReader;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
@@ -154,7 +152,9 @@ public class EnsemblMap extends EnsemblRestClient
     {
       Iterator rvals = (Iterator) getJSON(url, null, -1, MODE_ITERATOR, MAPPINGS);
       if (rvals == null)
-    	  return null;
+      {
+        return null;
+      }
       while (rvals.hasNext())
       {
         // todo check for "mapped"
@@ -221,7 +221,7 @@ public class EnsemblMap extends EnsemblRestClient
     URL url = null;
     try
     {
-      String domain = new EnsemblInfo().getDomain(division);
+      String domain = EnsemblInfo.getDomain(division);
       if (domain != null)
       {
         url = getIdMapUrl(domain, accession, start, end, cdsOrCdna);
@@ -286,7 +286,9 @@ GeneLociI parseIdMappingResponse(URL url, String accession,
     {
       Iterator rvals = (Iterator) getJSON(url, null, -1, MODE_ITERATOR, MAPPINGS);
       if (rvals == null)
-    	  return null;
+      {
+        return null;
+      }
       String assembly = null;
       String chromosome = null;
       int fromEnd = 0;
diff --git a/src/jalview/ext/ensembl/EnsemblRestClient.java b/src/jalview/ext/ensembl/EnsemblRestClient.java
index bf151bf..6d4bc79 100644
--- a/src/jalview/ext/ensembl/EnsemblRestClient.java
+++ b/src/jalview/ext/ensembl/EnsemblRestClient.java
@@ -75,7 +75,7 @@ abstract class EnsemblRestClient extends EnsemblSequenceFetcher
 
   private static final String REST_CHANGE_LOG = "https://github.com/Ensembl/ensembl-rest/wiki/Change-log";
 
-  private static Map domainData;
+  private static final Map domainData;
 
   private final static long AVAILABILITY_RETEST_INTERVAL = 10000L; // 10 seconds
 
diff --git a/src/jalview/fts/service/pdb/PDBFTSRestClient.java b/src/jalview/fts/service/pdb/PDBFTSRestClient.java
index cd3e5c9..3bb3f77 100644
--- a/src/jalview/fts/service/pdb/PDBFTSRestClient.java
+++ b/src/jalview/fts/service/pdb/PDBFTSRestClient.java
@@ -58,6 +58,41 @@ public class PDBFTSRestClient extends FTSRestClient
 
   private static FTSRestClientI instance = null;
 
+  public static FTSRestClientI getInstance()
+  {
+
+    // BH 2019.05.08 need to isolate static fields in JavaScript
+
+    FTSRestClientI i = instance;
+    @SuppressWarnings("unused")
+    ThreadGroup g = null;
+    if (Platform.isJS())
+    {
+      g = Thread.currentThread().getThreadGroup();
+      /**
+       * @j2sNative i = g._jalviewPDBFTSRestClientInstance;
+       * 
+       */
+    }
+    if (i == null)
+    {
+      i = new PDBFTSRestClient();
+
+      if (Platform.isJS())
+      {
+        /**
+         * @j2sNative g._jalviewPDBFTSRestClientInstance = i;
+         * 
+         */
+      }
+      else
+      {
+        instance = i;
+      }
+    }
+    return i;
+  }
+
   public static final String PDB_SEARCH_ENDPOINT = "https://www.ebi.ac.uk/pdbe/search/pdb/select?";
 
   protected PDBFTSRestClient()
@@ -459,15 +494,6 @@ public static String parseJsonExceptionString(String jsonErrorResponse)
     return "/fts/pdb_data_columns.txt";
   }
 
-  public static FTSRestClientI getInstance()
-  {
-    if (instance == null)
-    {
-      instance = new PDBFTSRestClient();
-    }
-    return instance;
-  }
-
   private Collection allDefaultDisplayedStructureDataColumns;
 
   public Collection getAllDefaultDisplayedStructureDataColumns()
diff --git a/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java b/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java
index 3f0b8a4..715b842 100644
--- a/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java
+++ b/src/jalview/fts/service/uniprot/UniProtFTSRestClient.java
@@ -54,6 +54,41 @@ public class UniProtFTSRestClient extends FTSRestClient
 
   private static FTSRestClientI instance = null;
 
+  public static FTSRestClientI getInstance()
+  {
+
+    // BH 2019.05.08 need to isolate static fields in JavaScript
+
+    FTSRestClientI i = instance;
+    @SuppressWarnings("unused")
+    ThreadGroup g = null;
+    if (Platform.isJS())
+    {
+      g = Thread.currentThread().getThreadGroup();
+      /**
+       * @j2sNative i = g._jalviewUniProtFTSRestClientInstance;
+       * 
+       */
+    }
+    if (i == null)
+    {
+      i = new UniProtFTSRestClient();
+
+      if (Platform.isJS())
+      {
+        /**
+         * @j2sNative g._jalviewUniProtFTSRestClientInstance = i;
+         * 
+         */
+      }
+      else
+      {
+        instance = i;
+      }
+    }
+    return i;
+  }
+
   public final String uniprotSearchEndpoint;
 
   public UniProtFTSRestClient()
@@ -347,15 +382,6 @@ public class UniProtFTSRestClient extends FTSRestClient
     };
   }
 
-  public static FTSRestClientI getInstance()
-  {
-    if (instance == null)
-    {
-      instance = new UniProtFTSRestClient();
-    }
-    return instance;
-  }
-
   @Override
   public String getColumnDataConfigFileName()
   {
diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java
index 594319f..f949ef7 100644
--- a/src/jalview/gui/AlignFrame.java
+++ b/src/jalview/gui/AlignFrame.java
@@ -1930,9 +1930,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     StringSelection ss = new StringSelection(output);
 
+    Desktop d = Desktop.getInstance();
     try
     {
-      jalview.gui.Desktop.internalCopy = true;
+      d.internalCopy = true;
       // Its really worth setting the clipboard contents
       // to empty before setting the large StringSelection!!
       Toolkit.getDefaultToolkit().getSystemClipboard()
@@ -1959,7 +1960,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               hiddenCutoff, hiddenOffset);
     }
 
-    Desktop.jalviewClipboard = new Object[] { seqs,
+    d.jalviewClipboard = new Object[] { seqs,
         viewport.getAlignment().getDataset(), hiddenColumns };
     setStatus(MessageManager.formatMessage(
             "label.copied_sequences_to_clipboard", new Object[]
@@ -2031,12 +2032,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       boolean annotationAdded = false;
       AlignmentI alignment = null;
 
-      if (Desktop.jalviewClipboard != null)
+      Desktop d = Desktop.getInstance();
+
+      if (d.jalviewClipboard != null)
       {
         // The clipboard was filled from within Jalview, we must use the
         // sequences
         // And dataset from the copied alignment
-        SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0];
+        SequenceI[] newseq = (SequenceI[]) d.jalviewClipboard[0];
         // be doubly sure that we create *new* sequence objects.
         sequences = new SequenceI[newseq.length];
         for (int i = 0; i < newseq.length; i++)
@@ -2061,10 +2064,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       if (newAlignment)
       {
 
-        if (Desktop.jalviewClipboard != null)
+        if (d.jalviewClipboard != null)
         {
           // dataset is inherited
-          alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]);
+          alignment.setDataset((Alignment) d.jalviewClipboard[1]);
         }
         else
         {
@@ -2080,8 +2083,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         alignment = viewport.getAlignment();
         alwidth = alignment.getWidth() + 1;
         // decide if we need to import sequences from an existing dataset
-        boolean importDs = Desktop.jalviewClipboard != null
-                && Desktop.jalviewClipboard[1] != alignment.getDataset();
+        boolean importDs = d.jalviewClipboard != null
+                && d.jalviewClipboard[1] != alignment.getDataset();
         // importDs==true instructs us to copy over new dataset sequences from
         // an existing alignment
         Vector newDs = (importDs) ? new Vector<>() : null; // used to
@@ -2283,10 +2286,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 DEFAULT_HEIGHT);
         String newtitle = new String("Copied sequences");
 
-        if (Desktop.jalviewClipboard != null
-                && Desktop.jalviewClipboard[2] != null)
+        if (d.jalviewClipboard != null && d.jalviewClipboard[2] != null)
         {
-          HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2];
+          HiddenColumns hc = (HiddenColumns) d.jalviewClipboard[2];
           af.viewport.setHiddenColumns(hc);
         }
 
@@ -2339,10 +2341,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               DEFAULT_HEIGHT);
       String newtitle = new String("Flanking alignment");
 
-      if (Desktop.jalviewClipboard != null
-              && Desktop.jalviewClipboard[2] != null)
+      Desktop d = Desktop.getInstance();
+
+      if (d.jalviewClipboard != null && d.jalviewClipboard[2] != null)
       {
-        HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2];
+        HiddenColumns hc = (HiddenColumns) d.jalviewClipboard[2];
         af.viewport.setHiddenColumns(hc);
       }
 
@@ -5090,9 +5093,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               }
               if (otherdb.size() == 1)
               {
-                final DbSourceProxy[] dassource = otherdb
-                        .toArray(new DbSourceProxy[0]);
                 DbSourceProxy src = otherdb.get(0);
+                DbSourceProxy[] dassource = new DbSourceProxy[] {
+                    src };
                 fetchr = new JMenuItem(src.getDbSource());
                 fetchr.addActionListener(new ActionListener()
                 {
diff --git a/src/jalview/gui/AnnotationColumnChooser.java b/src/jalview/gui/AnnotationColumnChooser.java
index fbc93b5..a1c082c 100644
--- a/src/jalview/gui/AnnotationColumnChooser.java
+++ b/src/jalview/gui/AnnotationColumnChooser.java
@@ -79,11 +79,11 @@ public class AnnotationColumnChooser extends AnnotationRowFilter
 
   public static final int ACTION_OPTION_SELECT = 1;
 
-  public static int ACTION_OPTION_HIDE = 2;
+  public static final int ACTION_OPTION_HIDE = 2;
 
-  public static String NO_GRAPH_VIEW = "0";
+  public static final String NO_GRAPH_VIEW = "0";
 
-  public static String GRAPH_VIEW = "1";
+  public static final String GRAPH_VIEW = "1";
 
   private int actionOption = ACTION_OPTION_SELECT;
 
diff --git a/src/jalview/gui/AnnotationLabels.java b/src/jalview/gui/AnnotationLabels.java
index 399f70f..72d75b8 100755
--- a/src/jalview/gui/AnnotationLabels.java
+++ b/src/jalview/gui/AnnotationLabels.java
@@ -82,7 +82,7 @@ public class AnnotationLabels extends JPanel
   /**
    * height in pixels for allowing height adjuster to be active
    */
-  private static int HEIGHT_ADJUSTER_HEIGHT = 10;
+  private static final int HEIGHT_ADJUSTER_HEIGHT = 10;
 
   private static final Font font = new Font("Arial", Font.PLAIN, 11);
 
@@ -981,7 +981,9 @@ public class AnnotationLabels extends JPanel
               av.getAlignment().getHiddenColumns());
     }
 
-    Desktop.jalviewClipboard = new Object[] { seqs, ds, // what is the dataset
+    Desktop.getInstance().jalviewClipboard = new Object[] { seqs, ds, // what is
+                                                                      // the
+                                                                      // dataset
                                                         // of a consensus
                                                         // sequence ? need to
                                                         // flag
diff --git a/src/jalview/gui/AppVarnaBinding.java b/src/jalview/gui/AppVarnaBinding.java
index 7430856..787ed53 100644
--- a/src/jalview/gui/AppVarnaBinding.java
+++ b/src/jalview/gui/AppVarnaBinding.java
@@ -72,7 +72,7 @@ public class AppVarnaBinding extends JalviewVarnaBinding
 
   private ReorderableJList _sideList = null;
 
-  private static String errorOpt = "error";
+  private final static String errorOpt = "error";
 
   @SuppressWarnings("unused")
   private boolean _error;
@@ -100,7 +100,7 @@ public class AppVarnaBinding extends JalviewVarnaBinding
    */
   private void init()
   {
-    DefaultListModel dlm = new DefaultListModel();
+    DefaultListModel dlm = new DefaultListModel<>();
 
     int marginTools = 40;
 
@@ -122,6 +122,7 @@ public class AppVarnaBinding extends JalviewVarnaBinding
     _sideList.setPreferredSize(new Dimension(100, 0));
     _sideList.addListSelectionListener(new ListSelectionListener()
     {
+      @Override
       public void valueChanged(ListSelectionEvent evt)
       {
         changeSelectedStructure_actionPerformed(evt);
@@ -316,7 +317,7 @@ public class AppVarnaBinding extends JalviewVarnaBinding
   {
     private DefaultListModel _rnalist;
 
-    private List _rnas = new ArrayList();
+    private List _rnas = new ArrayList<>();
 
     JList _l;
 
diff --git a/src/jalview/gui/ColourMenuHelper.java b/src/jalview/gui/ColourMenuHelper.java
index 6d0d0c9..e38b55b 100644
--- a/src/jalview/gui/ColourMenuHelper.java
+++ b/src/jalview/gui/ColourMenuHelper.java
@@ -314,7 +314,7 @@ public class ColourMenuHelper
     }
     else
     {
-      Cache.applicationProperties.remove("USER_DEFINED_COLOURS");
+      Cache.removePropertyNoSave("USER_DEFINED_COLOURS");
     }
   }
 }
diff --git a/src/jalview/gui/Console.java b/src/jalview/gui/Console.java
index 2e88eeb..3ff8c12 100644
--- a/src/jalview/gui/Console.java
+++ b/src/jalview/gui/Console.java
@@ -313,7 +313,8 @@ public class Console extends WindowAdapter
     initConsole(false);
     JalviewAppender jappender = new JalviewAppender();
     jappender.setLayout(new SimpleLayout());
-    JalviewAppender.setTextArea(textArea);
+    // BH 2019 JalviewAppender.setTextArea(textArea);
+    jappender.setTextArea(textArea);
     org.apache.log4j.Logger.getRootLogger().addAppender(jappender);
   }
 
diff --git a/src/jalview/gui/CrossRefAction.java b/src/jalview/gui/CrossRefAction.java
index 1feb15a..cc2e0a9 100644
--- a/src/jalview/gui/CrossRefAction.java
+++ b/src/jalview/gui/CrossRefAction.java
@@ -276,7 +276,7 @@ public class CrossRefAction implements Runnable
       return;
     }
     
-    Set ensemblDivisions = new EnsemblInfo().getDivisions();
+    Set ensemblDivisions = EnsemblInfo.getDivisions();
     
     /*
      * first look for direct dbrefs from sequence to Ensembl
diff --git a/src/jalview/gui/Desktop.java b/src/jalview/gui/Desktop.java
index d2967d7..bdb6de9 100644
--- a/src/jalview/gui/Desktop.java
+++ b/src/jalview/gui/Desktop.java
@@ -215,7 +215,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     @SuppressWarnings("unused")
     ThreadGroup g = Thread.currentThread().getThreadGroup();
     /**
-     * @j2s g._jalviewDesktopInstance = d;
+     * @j2sNative g._jalviewDesktopInstance = d;
      */
     {
       instance = d;
@@ -240,13 +240,13 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   static final int yOffset = 30;
 
-  public static jalview.ws.jws1.Discoverer discoverer;
+  public jalview.ws.jws1.Discoverer discoverer;
 
-  public static Object[] jalviewClipboard;
+  public Object[] jalviewClipboard;
 
-  public static boolean internalCopy = false;
+  public boolean internalCopy = false;
 
-  static int fileLoadingCount = 0;
+  private static int fileLoadingCount = 0;
 
   class MyDesktopManager implements DesktopManager
   {
@@ -890,7 +890,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     // A HEADLESS STATE WHEN NO DESKTOP EXISTS. MUST RETURN
     // IF JALVIEW IS RUNNING HEADLESS
     // ///////////////////////////////////////////////
-    if (instance == null || Jalview.isHeadlessMode())
+    if (getInstance() == null || Jalview.isHeadlessMode())
     {
       return;
     }
@@ -1049,7 +1049,7 @@ public class Desktop extends jalview.jbgui.GDesktop
   {
     if (!internalCopy)
     {
-      Desktop.jalviewClipboard = null;
+      Desktop.getInstance().jalviewClipboard = null;
     }
 
     internalCopy = false;
@@ -1888,7 +1888,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     {
       progressPanel = new JPanel(new GridLayout(1, 1));
       totalProgressCount = 0;
-      instance.getContentPane().add(progressPanel, BorderLayout.SOUTH);
+      getInstance().getContentPane().add(progressPanel, BorderLayout.SOUTH);
     }
     JPanel thisprogress = new JPanel(new BorderLayout(10, 5));
     JProgressBar progressBar = new JProgressBar();
@@ -1901,7 +1901,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     ((GridLayout) progressPanel.getLayout()).setRows(
             ((GridLayout) progressPanel.getLayout()).getRows() + 1);
     ++totalProgressCount;
-    instance.validate();
+    getInstance().validate();
     return thisprogress;
   }
 
@@ -3248,7 +3248,7 @@ public class Desktop extends jalview.jbgui.GDesktop
    */
   java.util.concurrent.Semaphore block = new Semaphore(0);
 
-  private static groovy.ui.Console groovyConsole;
+  private groovy.ui.Console groovyConsole;
 
   /**
    * add another dialog thread to the queue
@@ -3481,7 +3481,7 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   public static groovy.ui.Console getGroovyConsole()
   {
-    return groovyConsole;
+    return getInstance().groovyConsole;
   }
 
   /**
diff --git a/src/jalview/gui/JalviewAppender.java b/src/jalview/gui/JalviewAppender.java
index 1d7064b..c1140a1 100644
--- a/src/jalview/gui/JalviewAppender.java
+++ b/src/jalview/gui/JalviewAppender.java
@@ -33,17 +33,20 @@ import org.apache.log4j.spi.LoggingEvent;
 public class JalviewAppender extends WriterAppender
 {
 
-  static private JTextArea jTextArea = null;
+  // BH 2019 was static
+
+  private JTextArea jTextArea = null;
 
   /** Set the target JTextArea for the logging information to appear. */
-  static public void setTextArea(JTextArea jTextArea)
+  public void setTextArea(JTextArea jTextArea)
   {
-    JalviewAppender.jTextArea = jTextArea;
+    this.jTextArea = jTextArea;
   }
 
   /**
    * Format and then append the loggingEvent to the stored JTextArea.
    */
+  @Override
   public void append(LoggingEvent loggingEvent)
   {
     final String message = this.layout.format(loggingEvent);
@@ -51,6 +54,7 @@ public class JalviewAppender extends WriterAppender
     // Append formatted message to textarea using the Swing Thread.
     SwingUtilities.invokeLater(new Runnable()
     {
+      @Override
       public void run()
       {
         if (jTextArea != null)
diff --git a/src/jalview/gui/LineartOptions.java b/src/jalview/gui/LineartOptions.java
index fc6fd23..62bdd35 100644
--- a/src/jalview/gui/LineartOptions.java
+++ b/src/jalview/gui/LineartOptions.java
@@ -188,7 +188,7 @@ public class LineartOptions extends JPanel
     }
     else
     {
-      Cache.applicationProperties.remove(preferencesKey);
+      Cache.removePropertyNoSave(preferencesKey);
     }
   }
 
diff --git a/src/jalview/gui/MenuChooser.java b/src/jalview/gui/MenuChooser.java
index 0e42a7a..be7f0f6 100644
--- a/src/jalview/gui/MenuChooser.java
+++ b/src/jalview/gui/MenuChooser.java
@@ -32,7 +32,7 @@ import javax.swing.JPanel;
 
 public class MenuChooser implements ActionListener
 {
-  public static boolean protein;
+  // public static boolean protein;
 
   private JFrame choosemenu = new JFrame("Animation");
 
@@ -84,16 +84,21 @@ public class MenuChooser implements ActionListener
   /**
    * C'est la méthode qui sera appelée lors d'un clic sur notre bouton
    */
+  @Override
   public void actionPerformed(ActionEvent arg0)
   {
 
     if (arg0.getSource() == bouton)
-      protein = false;
-    label.setText("RNA menu");
+    {
+      //      protein = false;
+      label.setText("RNA menu");
+    }
 
     if (arg0.getSource() == bouton2)
+     {
       label.setText("Protein menu");
-    protein = true;
+//    protein = true;
+    }
   }
 
 }
diff --git a/src/jalview/gui/Preferences.java b/src/jalview/gui/Preferences.java
index cc2961f..8765b37 100755
--- a/src/jalview/gui/Preferences.java
+++ b/src/jalview/gui/Preferences.java
@@ -80,6 +80,7 @@ import ext.edu.ucsf.rbvi.strucviz2.StructureManager;
  * @author $author$
  * @version $Revision$
  */
+@SuppressWarnings("serial")
 public class Preferences extends GPreferences
 {
   public static final String ENABLE_SPLIT_FRAME = "ENABLE_SPLIT_FRAME";
@@ -126,9 +127,9 @@ public class Preferences extends GPreferences
    * Holds name and link separated with | character. Sequence ID must be
    * $SEQUENCE_ID$ or $SEQUENCE_ID=/.possible | chars ./=$
    */
-  public static UrlProviderI sequenceUrlLinks;
+  public static UrlProviderI sequenceUrlLinks; // must be nonfinal for test
 
-  public static UrlLinkTableModel dataModel;
+  public final static UrlLinkTableModel dataModel;
 
   /**
    * Holds name and link separated with | character. Sequence IDS and Sequences
@@ -138,7 +139,7 @@ public class Preferences extends GPreferences
    * (TODO: proper escape for using | to separate ids or sequences
    */
 
-  public static List groupURLLinks;
+  public static final List groupURLLinks;
   static
   {
     // get links selected to be in the menu (SEQUENCE_LINKS)
@@ -599,65 +600,65 @@ public class Preferences extends GPreferences
     /*
      * Save Visual settings
      */
-    Cache.applicationProperties.setProperty("SHOW_JVSUFFIX",
+    Cache.setPropertyNoSave("SHOW_JVSUFFIX",
             Boolean.toString(seqLimit.isSelected()));
-    Cache.applicationProperties.setProperty("RIGHT_ALIGN_IDS",
+    Cache.setPropertyNoSave("RIGHT_ALIGN_IDS",
             Boolean.toString(rightAlign.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_FULLSCREEN",
+    Cache.setPropertyNoSave("SHOW_FULLSCREEN",
             Boolean.toString(fullScreen.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_OVERVIEW",
+    Cache.setPropertyNoSave("SHOW_OVERVIEW",
             Boolean.toString(openoverv.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
+    Cache.setPropertyNoSave("SHOW_ANNOTATIONS",
             Boolean.toString(annotations.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
+    Cache.setPropertyNoSave("SHOW_CONSERVATION",
             Boolean.toString(conservation.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_QUALITY",
+    Cache.setPropertyNoSave("SHOW_QUALITY",
             Boolean.toString(quality.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+    Cache.setPropertyNoSave("SHOW_IDENTITY",
             Boolean.toString(identity.isSelected()));
 
-    Cache.applicationProperties.setProperty("GAP_SYMBOL",
+    Cache.setPropertyNoSave("GAP_SYMBOL",
             gapSymbolCB.getSelectedItem().toString());
 
-    Cache.applicationProperties.setProperty("FONT_NAME",
+    Cache.setPropertyNoSave("FONT_NAME",
             fontNameCB.getSelectedItem().toString());
-    Cache.applicationProperties.setProperty("FONT_STYLE",
+    Cache.setPropertyNoSave("FONT_STYLE",
             fontStyleCB.getSelectedItem().toString());
-    Cache.applicationProperties.setProperty("FONT_SIZE",
+    Cache.setPropertyNoSave("FONT_SIZE",
             fontSizeCB.getSelectedItem().toString());
 
-    Cache.applicationProperties.setProperty("ID_ITALICS",
+    Cache.setPropertyNoSave("ID_ITALICS",
             Boolean.toString(idItalics.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_UNCONSERVED",
+    Cache.setPropertyNoSave("SHOW_UNCONSERVED",
             Boolean.toString(showUnconserved.isSelected()));
-    Cache.applicationProperties.setProperty(SHOW_OCCUPANCY,
+    Cache.setPropertyNoSave(SHOW_OCCUPANCY,
             Boolean.toString(showOccupancy.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_GROUP_CONSENSUS",
+    Cache.setPropertyNoSave("SHOW_GROUP_CONSENSUS",
             Boolean.toString(showGroupConsensus.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_GROUP_CONSERVATION",
+    Cache.setPropertyNoSave("SHOW_GROUP_CONSERVATION",
             Boolean.toString(showGroupConservation.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_CONSENSUS_HISTOGRAM",
+    Cache.setPropertyNoSave("SHOW_CONSENSUS_HISTOGRAM",
             Boolean.toString(showConsensHistogram.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_CONSENSUS_LOGO",
+    Cache.setPropertyNoSave("SHOW_CONSENSUS_LOGO",
             Boolean.toString(showConsensLogo.isSelected()));
-    Cache.applicationProperties.setProperty("ANTI_ALIAS",
+    Cache.setPropertyNoSave("ANTI_ALIAS",
             Boolean.toString(smoothFont.isSelected()));
-    Cache.applicationProperties.setProperty(SCALE_PROTEIN_TO_CDNA,
+    Cache.setPropertyNoSave(SCALE_PROTEIN_TO_CDNA,
             Boolean.toString(scaleProteinToCdna.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_NPFEATS_TOOLTIP",
+    Cache.setPropertyNoSave("SHOW_NPFEATS_TOOLTIP",
             Boolean.toString(showNpTooltip.isSelected()));
-    Cache.applicationProperties.setProperty("SHOW_DBREFS_TOOLTIP",
+    Cache.setPropertyNoSave("SHOW_DBREFS_TOOLTIP",
             Boolean.toString(showDbRefTooltip.isSelected()));
 
-    Cache.applicationProperties.setProperty("WRAP_ALIGNMENT",
+    Cache.setPropertyNoSave("WRAP_ALIGNMENT",
             Boolean.toString(wrap.isSelected()));
 
-    Cache.applicationProperties.setProperty("STARTUP_FILE",
+    Cache.setPropertyNoSave("STARTUP_FILE",
             startupFileTextfield.getText());
-    Cache.applicationProperties.setProperty("SHOW_STARTUP_FILE",
+    Cache.setPropertyNoSave("SHOW_STARTUP_FILE",
             Boolean.toString(startupCheckbox.isSelected()));
 
-    Cache.applicationProperties.setProperty("SORT_ALIGNMENT",
+    Cache.setPropertyNoSave("SORT_ALIGNMENT",
             sortby.getSelectedItem().toString());
 
     // convert description of sort order to enum name for save
@@ -665,20 +666,20 @@ public class Preferences extends GPreferences
             .forDescription(sortAnnBy.getSelectedItem().toString());
     if (annSortOrder != null)
     {
-      Cache.applicationProperties.setProperty(SORT_ANNOTATIONS,
+      Cache.setPropertyNoSave(SORT_ANNOTATIONS,
               annSortOrder.name());
     }
 
     final boolean showAutocalcFirst = sortAutocalc.getSelectedIndex() == 0;
-    Cache.applicationProperties.setProperty(SHOW_AUTOCALC_ABOVE,
+    Cache.setPropertyNoSave(SHOW_AUTOCALC_ABOVE,
             Boolean.valueOf(showAutocalcFirst).toString());
 
     /*
      * Save Colours settings
      */
-    Cache.applicationProperties.setProperty(DEFAULT_COLOUR_PROT,
+    Cache.setPropertyNoSave(DEFAULT_COLOUR_PROT,
             protColour.getSelectedItem().toString());
-    Cache.applicationProperties.setProperty(DEFAULT_COLOUR_NUC,
+    Cache.setPropertyNoSave(DEFAULT_COLOUR_NUC,
             nucColour.getSelectedItem().toString());
     Cache.setColourProperty("ANNOTATIONCOLOUR_MIN",
             minColour.getBackground());
@@ -690,37 +691,37 @@ public class Preferences extends GPreferences
      */
     Cache.setColourProperty(GAP_COLOUR, gapColour.getBackground());
     Cache.setColourProperty(HIDDEN_COLOUR, hiddenColour.getBackground());
-    Cache.applicationProperties.setProperty(USE_LEGACY_GAP,
+    Cache.setPropertyNoSave(USE_LEGACY_GAP,
             Boolean.toString(useLegacyGap.isSelected()));
-    Cache.applicationProperties.setProperty(SHOW_OV_HIDDEN_AT_START,
+    Cache.setPropertyNoSave(SHOW_OV_HIDDEN_AT_START,
             Boolean.toString(showHiddenAtStart.isSelected()));
 
     /*
      * Save Structure settings
      */
-    Cache.applicationProperties.setProperty(ADD_TEMPFACT_ANN,
+    Cache.setPropertyNoSave(ADD_TEMPFACT_ANN,
             Boolean.toString(addTempFactor.isSelected()));
-    Cache.applicationProperties.setProperty(ADD_SS_ANN,
+    Cache.setPropertyNoSave(ADD_SS_ANN,
             Boolean.toString(addSecondaryStructure.isSelected()));
-    Cache.applicationProperties.setProperty(USE_RNAVIEW,
+    Cache.setPropertyNoSave(USE_RNAVIEW,
             Boolean.toString(useRnaView.isSelected()));
-    Cache.applicationProperties.setProperty(STRUCT_FROM_PDB,
+    Cache.setPropertyNoSave(STRUCT_FROM_PDB,
             Boolean.toString(structFromPdb.isSelected()));
-    Cache.applicationProperties.setProperty(STRUCTURE_DISPLAY,
+    Cache.setPropertyNoSave(STRUCTURE_DISPLAY,
             structViewer.getSelectedItem().toString());
     Cache.setOrRemove(CHIMERA_PATH, chimeraPath.getText());
-    Cache.applicationProperties.setProperty("MAP_WITH_SIFTS",
+    Cache.setPropertyNoSave("MAP_WITH_SIFTS",
             Boolean.toString(siftsMapping.isSelected()));
     SiftsSettings.setMapWithSifts(siftsMapping.isSelected());
 
     /*
      * Save Output settings
      */
-    Cache.applicationProperties.setProperty("EPS_RENDERING",
+    Cache.setPropertyNoSave("EPS_RENDERING",
             ((OptionsParam) epsRendering.getSelectedItem()).getCode());
-    Cache.applicationProperties.setProperty("HTML_RENDERING",
+    Cache.setPropertyNoSave("HTML_RENDERING",
             ((OptionsParam) htmlRendering.getSelectedItem()).getCode());
-    Cache.applicationProperties.setProperty("SVG_RENDERING",
+    Cache.setPropertyNoSave("SVG_RENDERING",
             ((OptionsParam) svgRendering.getSelectedItem()).getCode());
 
     /*
@@ -734,29 +735,29 @@ public class Preferences extends GPreferences
     String menuLinks = sequenceUrlLinks.writeUrlsAsString(true);
     if (menuLinks.isEmpty())
     {
-      Cache.applicationProperties.remove("SEQUENCE_LINKS");
+      Cache.removePropertyNoSave("SEQUENCE_LINKS");
     }
     else
     {
-      Cache.applicationProperties.setProperty("SEQUENCE_LINKS",
+      Cache.setPropertyNoSave("SEQUENCE_LINKS",
               menuLinks.toString());
     }
 
     String nonMenuLinks = sequenceUrlLinks.writeUrlsAsString(false);
     if (nonMenuLinks.isEmpty())
     {
-      Cache.applicationProperties.remove("STORED_LINKS");
+      Cache.removePropertyNoSave("STORED_LINKS");
     }
     else
     {
-      Cache.applicationProperties.setProperty("STORED_LINKS",
+      Cache.setPropertyNoSave("STORED_LINKS",
               nonMenuLinks.toString());
     }
 
-    Cache.applicationProperties.setProperty("DEFAULT_URL",
+    Cache.setPropertyNoSave("DEFAULT_URL",
             sequenceUrlLinks.getPrimaryUrlId());
 
-    Cache.applicationProperties.setProperty("USE_PROXY",
+    Cache.setPropertyNoSave("USE_PROXY",
             Boolean.toString(useProxy.isSelected()));
 
     Cache.setOrRemove("PROXY_SERVER", proxyServerTB.getText());
@@ -795,40 +796,40 @@ public class Preferences extends GPreferences
     /*
      * Save Output settings
      */
-    Cache.applicationProperties.setProperty("BLC_JVSUFFIX",
+    Cache.setPropertyNoSave("BLC_JVSUFFIX",
             Boolean.toString(blcjv.isSelected()));
-    Cache.applicationProperties.setProperty("CLUSTAL_JVSUFFIX",
+    Cache.setPropertyNoSave("CLUSTAL_JVSUFFIX",
             Boolean.toString(clustaljv.isSelected()));
-    Cache.applicationProperties.setProperty("FASTA_JVSUFFIX",
+    Cache.setPropertyNoSave("FASTA_JVSUFFIX",
             Boolean.toString(fastajv.isSelected()));
-    Cache.applicationProperties.setProperty("MSF_JVSUFFIX",
+    Cache.setPropertyNoSave("MSF_JVSUFFIX",
             Boolean.toString(msfjv.isSelected()));
-    Cache.applicationProperties.setProperty("PFAM_JVSUFFIX",
+    Cache.setPropertyNoSave("PFAM_JVSUFFIX",
             Boolean.toString(pfamjv.isSelected()));
-    Cache.applicationProperties.setProperty("PILEUP_JVSUFFIX",
+    Cache.setPropertyNoSave("PILEUP_JVSUFFIX",
             Boolean.toString(pileupjv.isSelected()));
-    Cache.applicationProperties.setProperty("PIR_JVSUFFIX",
+    Cache.setPropertyNoSave("PIR_JVSUFFIX",
             Boolean.toString(pirjv.isSelected()));
-    Cache.applicationProperties.setProperty("PIR_MODELLER",
+    Cache.setPropertyNoSave("PIR_MODELLER",
             Boolean.toString(modellerOutput.isSelected()));
-    Cache.applicationProperties.setProperty("EXPORT_EMBBED_BIOJSON",
+    Cache.setPropertyNoSave("EXPORT_EMBBED_BIOJSON",
             Boolean.toString(embbedBioJSON.isSelected()));
     jalview.io.PIRFile.useModellerOutput = modellerOutput.isSelected();
 
-    Cache.applicationProperties.setProperty("FIGURE_AUTOIDWIDTH",
+    Cache.setPropertyNoSave("FIGURE_AUTOIDWIDTH",
             Boolean.toString(autoIdWidth.isSelected()));
     userIdWidth_actionPerformed();
-    Cache.applicationProperties.setProperty("FIGURE_FIXEDIDWIDTH",
+    Cache.setPropertyNoSave("FIGURE_FIXEDIDWIDTH",
             userIdWidth.getText());
 
     /*
      * Save Editing settings
      */
-    Cache.applicationProperties.setProperty("AUTO_CALC_CONSENSUS",
+    Cache.setPropertyNoSave("AUTO_CALC_CONSENSUS",
             Boolean.toString(autoCalculateConsCheck.isSelected()));
-    Cache.applicationProperties.setProperty("SORT_BY_TREE",
+    Cache.setPropertyNoSave("SORT_BY_TREE",
             Boolean.toString(sortByTree.isSelected()));
-    Cache.applicationProperties.setProperty("PAD_GAPS",
+    Cache.setPropertyNoSave("PAD_GAPS",
             Boolean.toString(padGaps.isSelected()));
 
     if (!Platform.isJS())
@@ -839,21 +840,21 @@ public class Preferences extends GPreferences
     /*
      * Save Backups settings
      */
-    Cache.applicationProperties.setProperty(BackupFiles.CONFIRM_DELETE_OLD,
+    Cache.setPropertyNoSave(BackupFiles.CONFIRM_DELETE_OLD,
             Boolean.toString(backupfilesConfirmDelete.isSelected()));
-    Cache.applicationProperties.setProperty(BackupFiles.ENABLED,
+    Cache.setPropertyNoSave(BackupFiles.ENABLED,
             Boolean.toString(enableBackupFiles.isSelected()));
-    Cache.applicationProperties.setProperty(BackupFiles.NO_MAX,
+    Cache.setPropertyNoSave(BackupFiles.NO_MAX,
             Boolean.toString(backupfilesKeepAll.isSelected()));
-    Cache.applicationProperties.setProperty(BackupFiles.REVERSE_ORDER,
+    Cache.setPropertyNoSave(BackupFiles.REVERSE_ORDER,
             Boolean.toString(suffixReverse.isSelected()));
-    Cache.applicationProperties.setProperty(BackupFiles.SUFFIX,
+    Cache.setPropertyNoSave(BackupFiles.SUFFIX,
             suffixTemplate.getText());
-    Cache.applicationProperties.setProperty(BackupFiles.ROLL_MAX,
+    Cache.setPropertyNoSave(BackupFiles.ROLL_MAX,
             Integer.toString(getSpinnerInt(backupfilesRollMaxSpinner, 4)));
-    Cache.applicationProperties.setProperty(BackupFiles.SUFFIX_DIGITS,
+    Cache.setPropertyNoSave(BackupFiles.SUFFIX_DIGITS,
             Integer.toString(getSpinnerInt(suffixDigitsSpinner, 3)));
-    Cache.applicationProperties.setProperty(BackupFiles.NS+"_PRESET",
+    Cache.setPropertyNoSave(BackupFiles.NS + "_PRESET",
             Integer.toString(getComboIntStringKey(backupfilesPresetsCombo)));
 
     Cache.saveProperties();
@@ -910,7 +911,7 @@ public class Preferences extends GPreferences
       FileFormatI format = chooser.getSelectedFormat();
       if (format != null)
       {
-        Cache.applicationProperties.setProperty("DEFAULT_FILE_FORMAT",
+        Cache.setPropertyNoSave("DEFAULT_FILE_FORMAT",
                 format.getName());
       }
       startupFileTextfield
@@ -1212,7 +1213,7 @@ public class Preferences extends GPreferences
    * Returns true if chimera path is to a valid executable, else show an error
    * dialog.
    */
-  private boolean validateChimeraPath()
+  protected boolean validateChimeraPath()
   {
     if (chimeraPath.getText().trim().length() > 0)
     {
@@ -1331,7 +1332,7 @@ public class Preferences extends GPreferences
     }
   }
 
-  private class UrlListSelectionHandler implements ListSelectionListener
+  protected class UrlListSelectionHandler implements ListSelectionListener
   {
 
     @Override
diff --git a/src/jalview/jbgui/GPreferences.java b/src/jalview/jbgui/GPreferences.java
index 5fbc3d7..c8052bc 100755
--- a/src/jalview/jbgui/GPreferences.java
+++ b/src/jalview/jbgui/GPreferences.java
@@ -92,6 +92,7 @@ import javax.swing.table.TableCellRenderer;
  * @author $author$
  * @version $Revision$
  */
+@SuppressWarnings("serial")
 public class GPreferences extends JPanel
 {
   private static final Font LABEL_FONT = JvSwingUtils.getLabelFont();
@@ -214,13 +215,13 @@ public class GPreferences extends JPanel
   /*
    * Connections tab components
    */
-  protected JTable linkUrlTable = new JTable();
+  public JTable linkUrlTable = new JTable();
 
-  protected JButton editLink = new JButton();
+  public JButton editLink = new JButton();
 
-  protected JButton deleteLink = new JButton();
+  public JButton deleteLink = new JButton();
 
-  protected JTextField filterTB = new JTextField();
+  public JTextField filterTB = new JTextField();
 
   protected JButton doReset = new JButton();
 
@@ -1772,7 +1773,7 @@ public class GPreferences extends JPanel
     updateBackupFilesExampleLabel();
   }
 
-  private boolean warnAboutSuffixReverseChange()
+  protected boolean warnAboutSuffixReverseChange()
   {
     boolean savedSuffixReverse = Cache.getDefault(BackupFiles.REVERSE_ORDER,
             false);
@@ -2005,7 +2006,7 @@ public class GPreferences extends JPanel
     return exampleFilesPanel;
   }
 
-  private void backupsTabUpdatePresets()
+  protected void backupsTabUpdatePresets()
   {
     IntKeyStringValueEntry entry = (IntKeyStringValueEntry) backupfilesPresetsCombo
             .getSelectedItem();
@@ -2188,7 +2189,7 @@ public class GPreferences extends JPanel
     return suffixPanel;
   }
 
-  private boolean confirmSuffixReverseChange()
+  protected boolean confirmSuffixReverseChange()
   {
     boolean ret = false;
     String warningMessage = MessageManager
@@ -2497,7 +2498,7 @@ public class GPreferences extends JPanel
     return i;
   }
 
-  private void keepRollMaxOptionsEnabled()
+  protected void keepRollMaxOptionsEnabled()
   {
     boolean enabled = backupfilesKeepAll.isEnabled()
             && !backupfilesKeepAll.isSelected();
@@ -2506,7 +2507,7 @@ public class GPreferences extends JPanel
     backupfilesConfirmDelete.setEnabled(enabled);
   }
 
-  private void backupfilesKeepAllSetEnabled(boolean tryEnabled)
+  protected void backupfilesKeepAllSetEnabled(boolean tryEnabled)
   {
     boolean enabled = tryEnabled && enableBackupFiles.isSelected()
             && getComboIntStringKey(backupfilesPresetsCombo) == 0
diff --git a/src/jalview/structures/models/AAStructureBindingModel.java b/src/jalview/structures/models/AAStructureBindingModel.java
index 2528286..a98e4b1 100644
--- a/src/jalview/structures/models/AAStructureBindingModel.java
+++ b/src/jalview/structures/models/AAStructureBindingModel.java
@@ -355,8 +355,8 @@ public abstract class AAStructureBindingModel
               { Integer.valueOf(pe).toString() }));
     }
     final String nullChain = "TheNullChain";
-    List s = new ArrayList();
-    List c = new ArrayList();
+    List s = new ArrayList<>();
+    List c = new ArrayList<>();
     if (getChains() == null)
     {
       setChains(new String[getPdbCount()][]);
@@ -425,8 +425,8 @@ public abstract class AAStructureBindingModel
   public synchronized PDBEntry[] addSequenceAndChain(PDBEntry[] pdbe,
           SequenceI[][] seq, String[][] chns)
   {
-    List v = new ArrayList();
-    List rtn = new ArrayList();
+    List v = new ArrayList<>();
+    List rtn = new ArrayList<>();
     for (int i = 0; i < getPdbCount(); i++)
     {
       v.add(getPdbEntry(i));
@@ -512,12 +512,10 @@ public abstract class AAStructureBindingModel
   }
 
   /**
-   * Returns a readable description of all mappings for the wrapped pdbfile to
-   * any mapped sequences
    * 
-   * @param pdbfile
-   * @param seqs
-   * @return
+   * @return a readable description of all mappings for the wrapped pdbfile to
+   *         any mapped sequences
+   * 
    */
   public String printMappings()
   {
diff --git a/src/jalview/ws/SequenceFetcher.java b/src/jalview/ws/SequenceFetcher.java
index 18e25cc..0d9a926 100644
--- a/src/jalview/ws/SequenceFetcher.java
+++ b/src/jalview/ws/SequenceFetcher.java
@@ -20,13 +20,8 @@
  */
 package jalview.ws;
 
+import jalview.datamodel.DBRefSource;
 import jalview.ext.ensembl.EnsemblGene;
-import jalview.ws.dbsources.EmblCdsSource;
-import jalview.ws.dbsources.EmblSource;
-import jalview.ws.dbsources.Pdb;
-import jalview.ws.dbsources.PfamFull;
-import jalview.ws.dbsources.PfamSeed;
-import jalview.ws.dbsources.RfamSeed;
 import jalview.ws.dbsources.Uniprot;
 import jalview.ws.seqfetcher.ASequenceFetcher;
 import jalview.ws.seqfetcher.DbSourceProxy;
@@ -49,15 +44,30 @@ public class SequenceFetcher extends ASequenceFetcher
    */
   public SequenceFetcher()
   {
-    addDBRefSourceImpl(EnsemblGene.class);
-    // addDBRefSourceImpl(EnsemblGenomes.class);
-    addDBRefSourceImpl(EmblSource.class);
-    addDBRefSourceImpl(EmblCdsSource.class);
-    addDBRefSourceImpl(Uniprot.class);
-    addDBRefSourceImpl(Pdb.class);
-    addDBRefSourceImpl(PfamFull.class);
-    addDBRefSourceImpl(PfamSeed.class);
-    addDBRefSourceImpl(RfamSeed.class);
+    addAllDatabases();
+  }
+
+  public void addAllDatabases()
+  {
+    addDBRefSourceImpl(EnsemblGene.class); // includes EnsemblGenomes.class
+    addDBRefSourceImpl(Uniprot.class); // includes UniprotName.class
+    // addDBRefSourceImpl(EmblSource.class);
+    // addDBRefSourceImpl(EmblCdsSource.class);
+    // addDBRefSourceImpl(Pdb.class);
+    // addDBRefSourceImpl(PfamFull.class);
+    // addDBRefSourceImpl(PfamSeed.class);
+    // addDBRefSourceImpl(RfamSeed.class);
+    addDBRefSourceImpl(DBRefSource.EMBL,
+            "jalview.ws.dbsources.EmblSource");
+    addDBRefSourceImpl(DBRefSource.EMBLCDS,
+            "jalview.ws.dbsources.EmblCdsSource");
+    addDBRefSourceImpl(DBRefSource.PDB, "jalview.ws.dbsources.Pdb");
+    addDBRefSourceImpl(DBRefSource.PFAM_FULL,
+            "jalview.ws.dbsources.PfamFull");
+    addDBRefSourceImpl(DBRefSource.PFAM_SEED,
+            "jalview.ws.dbsources.PfamSeed");
+    addDBRefSourceImpl(DBRefSource.RFAM_SEED,
+            "jalview.ws.dbsources.RfamSeed");
   }
 
   /**
diff --git a/src/jalview/ws/dbsources/PfamFull.java b/src/jalview/ws/dbsources/PfamFull.java
index 0600427..6c313ec 100644
--- a/src/jalview/ws/dbsources/PfamFull.java
+++ b/src/jalview/ws/dbsources/PfamFull.java
@@ -20,6 +20,8 @@
  */
 package jalview.ws.dbsources;
 
+import jalview.datamodel.DBRefSource;
+
 /**
  * flyweight class specifying retrieval of Full family alignments from PFAM
  * 
@@ -45,7 +47,7 @@ public class PfamFull extends Pfam
   @Override
   public String getDbName()
   {
-    return "PFAM (Full)";
+    return DBRefSource.PFAM_FULL;
   }
 
   @Override
diff --git a/src/jalview/ws/dbsources/PfamSeed.java b/src/jalview/ws/dbsources/PfamSeed.java
index dff8a17..e4662e1 100644
--- a/src/jalview/ws/dbsources/PfamSeed.java
+++ b/src/jalview/ws/dbsources/PfamSeed.java
@@ -20,6 +20,8 @@
  */
 package jalview.ws.dbsources;
 
+import jalview.datamodel.DBRefSource;
+
 /**
  * flyweight class specifying retrieval of Seed alignments from PFAM
  * 
@@ -47,7 +49,7 @@ public class PfamSeed extends Pfam
   @Override
   public String getDbName()
   {
-    return "PFAM (Seed)";
+    return DBRefSource.PFAM_SEED;
   }
 
   @Override
diff --git a/src/jalview/ws/seqfetcher/ASequenceFetcher.java b/src/jalview/ws/seqfetcher/ASequenceFetcher.java
index 2a27cce..dff08ee 100644
--- a/src/jalview/ws/seqfetcher/ASequenceFetcher.java
+++ b/src/jalview/ws/seqfetcher/ASequenceFetcher.java
@@ -36,6 +36,7 @@ import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
+import java.util.Map.Entry;
 import java.util.Stack;
 import java.util.Vector;
 
@@ -45,7 +46,7 @@ public class ASequenceFetcher
   /*
    * set of databases we can retrieve entries from
    */
-  protected Hashtable> fetchableDbs;
+  protected Hashtable> fetchableDbs;
 
   /*
    * comparator to sort by tier (0/1/2) and name
@@ -305,7 +306,7 @@ public class ASequenceFetcher
   public List getSourceProxy(String db)
   {
     db = DBRefUtils.getCanonicalName(db);
-    Map dblist = fetchableDbs.get(db);
+    Map dblist = fetchableDbs.get(db);
     if (dblist == null)
     {
       return new ArrayList<>();
@@ -314,27 +315,75 @@ public class ASequenceFetcher
     /*
      * sort so that primary sources precede secondary
      */
-    List dbs = new ArrayList<>(dblist.values());
+    List dbs = new ArrayList<>();
+    for (Entry entry : dblist.entrySet())
+    {
+      DbSourceProxyRoot proxy = entry.getValue();
+      if (proxy instanceof DbRoot)
+      {
+        proxy = setProxy((DbRoot) proxy, dblist);
+      }
+      dbs.add((DbSourceProxy) proxy);
+    }
     Collections.sort(dbs, proxyComparator);
     return dbs;
   }
 
+  class DbRoot implements DbSourceProxyRoot
+  {
+
+    private String sourceName;
+
+    private String className;
+
+    DbRoot(String sourceName, String className)
+    {
+      this.sourceName = sourceName;
+      this.className = className;
+    }
+
+    @Override
+    public String getDbSource()
+    {
+      return sourceName;
+    }
+
+    /**
+     * lazy class creation
+     * 
+     * @return the actual proxy object
+     */
+    public DbSourceProxy getProxy()
+    {
+      try
+      {
+        System.err.println("ASeqFetch " + className);
+        return (DbSourceProxy) Class.forName(className).newInstance();
+      } catch (Exception e)
+      {
+        // Serious problems if this happens.
+        throw new Error(MessageManager.getString(
+                "error.dbrefsource_implementation_exception"), e);
+      }
+    }
+
+  }
+
   /**
    * constructs an instance of the proxy and registers it as a valid dbrefsource
    * 
-   * @param dbSourceProxy
+   * @param dbSourceProxyClass
    *          reference for class implementing
    *          jalview.ws.seqfetcher.DbSourceProxy
    */
   protected void addDBRefSourceImpl(
-          Class dbSourceProxy)
+          Class dbSourceProxyClass)
           throws IllegalArgumentException
   {
     DbSourceProxy proxy = null;
     try
     {
-      DbSourceProxy proxyObj = dbSourceProxy.getConstructor().newInstance();
-      proxy = proxyObj;
+      proxy = dbSourceProxyClass.getConstructor().newInstance();
     } catch (IllegalArgumentException e)
     {
       throw e;
@@ -347,13 +396,18 @@ public class ASequenceFetcher
     addDbRefSourceImpl(proxy);
   }
 
+  public void addDBRefSourceImpl(String sourceName, String className)
+  {
+    addDbRefSourceImpl(new DbRoot(sourceName, className));
+  }
+
   /**
    * add the properly initialised DbSourceProxy object 'proxy' to the list of
    * sequence fetchers
    * 
    * @param proxy
    */
-  protected void addDbRefSourceImpl(DbSourceProxy proxy)
+  void addDbRefSourceImpl(DbSourceProxyRoot proxy)
   {
     if (proxy != null)
     {
@@ -361,25 +415,31 @@ public class ASequenceFetcher
       {
         fetchableDbs = new Hashtable<>();
       }
-      Map slist = fetchableDbs
-              .get(proxy.getDbSource());
+      String key = proxy.getDbSource();
+      Map slist = fetchableDbs.get(key);
       if (slist == null)
       {
-        fetchableDbs.put(proxy.getDbSource(),
-                slist = new Hashtable<>());
+        fetchableDbs.put(key, slist = new Hashtable<>());
+      }
+      if (proxy instanceof DbRoot)
+      {
+        slist.put("", proxy);
+      }
+      else
+      {
+        slist.put(((DbSourceProxy) proxy).getDbName(), proxy);
       }
-      slist.put(proxy.getDbName(), proxy);
     }
   }
 
   /**
    * select sources which are implemented by instances of the given class
    * 
-   * @param class
+   * @param class1
    *          that implements DbSourceProxy
    * @return null or vector of source names for fetchers
    */
-  public String[] getDbInstances(Class class1)
+  public String[] getDbInstances(Class class1)
   {
     if (!DbSourceProxy.class.isAssignableFrom(class1))
     {
@@ -392,20 +452,25 @@ public class ASequenceFetcher
     {
       return null;
     }
-    String[] sources = null;
     Vector src = new Vector<>();
-    Enumeration dbs = fetchableDbs.keys();
-    while (dbs.hasMoreElements())
+    for (String dbSource : fetchableDbs.keySet())
     {
-      String dbn = dbs.nextElement();
-      for (DbSourceProxy dbp : fetchableDbs.get(dbn).values())
+      Map dblist = fetchableDbs.get(dbSource);
+      for (Entry entry : dblist.entrySet())
       {
-        if (class1.isAssignableFrom(dbp.getClass()))
+        DbSourceProxyRoot proxy = entry.getValue();
+        if (proxy instanceof DbRoot)
         {
-          src.addElement(dbn);
+          proxy = setProxy((DbRoot) proxy, dblist);
+        }
+        Class c = proxy.getClass();
+        if (class1 == c || class1.isAssignableFrom(c))
+        {
+          src.addElement(dbSource);
         }
       }
     }
+    String[] sources = null;
     if (src.size() > 0)
     {
       src.copyInto(sources = new String[src.size()]);
@@ -413,10 +478,24 @@ public class ASequenceFetcher
     return sources;
   }
 
-  public DbSourceProxy[] getDbSourceProxyInstances(Class class1)
+  private DbSourceProxyRoot setProxy(DbRoot root,
+          Map dblist)
+  {
+    DbSourceProxy proxy = root.getProxy();
+    // Time to create the actual proxy
+    dblist.remove("");
+    dblist.put(proxy.getDbName(), proxy);
+    return proxy;
+  }
+
+  public DbSourceProxy[] getDbSourceProxyInstances(Class class1)
   {
+    if (fetchableDbs == null)
+    {
+      return null;
+    }
     List prlist = new ArrayList<>();
-    for (String fetchable : getSupportedDb())
+    for (String fetchable : fetchableDbs.keySet())
     {
       for (DbSourceProxy pr : getSourceProxy(fetchable))
       {
diff --git a/src/jalview/ws/seqfetcher/DbSourceProxy.java b/src/jalview/ws/seqfetcher/DbSourceProxy.java
index a02ffc9..3e7441a 100644
--- a/src/jalview/ws/seqfetcher/DbSourceProxy.java
+++ b/src/jalview/ws/seqfetcher/DbSourceProxy.java
@@ -34,15 +34,9 @@ import com.stevesoft.pat.Regex;
  * 
  * @author JimP
  */
-public interface DbSourceProxy
+public interface DbSourceProxy extends DbSourceProxyRoot
 {
   /**
-   * 
-   * @return source string constant used for this DB source
-   */
-  String getDbSource();
-
-  /**
    * Short meaningful name for this data source for display in menus or
    * selection boxes.
    * 
diff --git a/src/jalview/ws/seqfetcher/DbSourceProxyRoot.java b/src/jalview/ws/seqfetcher/DbSourceProxyRoot.java
new file mode 100644
index 0000000..7b0c2a7
--- /dev/null
+++ b/src/jalview/ws/seqfetcher/DbSourceProxyRoot.java
@@ -0,0 +1,11 @@
+package jalview.ws.seqfetcher;
+
+public interface DbSourceProxyRoot
+{
+  /**
+   * 
+   * @return source string constant used for this DB source
+   */
+  String getDbSource();
+
+}
diff --git a/test/jalview/analysis/FinderTest.java b/test/jalview/analysis/FinderTest.java
index 5f64b28..bd18abd 100644
--- a/test/jalview/analysis/FinderTest.java
+++ b/test/jalview/analysis/FinderTest.java
@@ -68,7 +68,7 @@ public class FinderTest
   public void setUp()
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.applicationProperties.setProperty("PAD_GAPS",
+    Cache.setPropertyNoSave("PAD_GAPS",
             Boolean.FALSE.toString());
 
     String seqData = "seq1seq1/8-18 ABCD--EF-GHIJI\n" + "seq2 A--BCDefHI\n"
diff --git a/test/jalview/analysis/GeneticCodesTest.java b/test/jalview/analysis/GeneticCodesTest.java
index 5f49092..f80b92d 100644
--- a/test/jalview/analysis/GeneticCodesTest.java
+++ b/test/jalview/analysis/GeneticCodesTest.java
@@ -14,23 +14,23 @@ public class GeneticCodesTest
   @Test(groups = "Functional")
   public void testGetCodeTable()
   {
-    GeneticCodes codes = GeneticCodes.getInstance();
-    assertEquals(codes.getStandardCodeTable().getName(), "Standard");
-    assertEquals(codes.getStandardCodeTable().getId(), "1");
-    assertSame(codes.getStandardCodeTable(), codes.getCodeTable("1"));
-    assertEquals(codes.getCodeTable("2").getName(),
+    assertEquals(GeneticCodes.getStandardCodeTable().getName(), "Standard");
+    assertEquals(GeneticCodes.getStandardCodeTable().getId(), "1");
+    assertSame(GeneticCodes.getStandardCodeTable(),
+            GeneticCodes.getCodeTable("1"));
+    assertEquals(GeneticCodes.getCodeTable("2").getName(),
             "Vertebrate Mitochondrial");
-    assertEquals(codes.getCodeTable("11").getName(),
+    assertEquals(GeneticCodes.getCodeTable("11").getName(),
             "Bacterial, Archaeal and Plant Plastid");
-    assertEquals(codes.getCodeTable("31").getName(),
+    assertEquals(GeneticCodes.getCodeTable("31").getName(),
             "Blastocrithidia Nuclear");
   }
 
   @Test(groups = "Functional")
   public void testGetCodeTables()
   {
-    GeneticCodes codes = GeneticCodes.getInstance();
-    Iterator tableIterator = codes.getCodeTables().iterator();
+    Iterator tableIterator = GeneticCodes.getCodeTables()
+            .iterator();
     String[] ids = new String[] { "1", "2", "3", "4", "5", "6", "9", "10",
         "11", "12", "13", "14", "15", "16", "21", "22", "23", "24", "25",
         "26", "27", "28", "29", "30", "31" };
@@ -44,21 +44,19 @@ public class GeneticCodesTest
   @Test(groups = "Functional")
   public void testTranslate()
   {
-    GeneticCodes codes = GeneticCodes.getInstance();
-
-    GeneticCodeI gc = codes.getCodeTable("1");
+    GeneticCodeI gc = GeneticCodes.getCodeTable("1");
     assertNull(gc.translate("XYZ"));
     assertEquals(gc.translate("AGA"), "R");
 
-    gc = codes.getCodeTable("2");
+    gc = GeneticCodes.getCodeTable("2");
     assertEquals(gc.translate("AGA"), "*"); // variant
     assertEquals(gc.translate("ttc"), "F"); // non-variant
 
     // table 11 has no variant translations - should serve the standard values
-    gc = codes.getCodeTable("11");
+    gc = GeneticCodes.getCodeTable("11");
     assertEquals(gc.translate("ttc"), "F");
 
-    gc = codes.getCodeTable("31");
+    gc = GeneticCodes.getCodeTable("31");
     assertEquals(gc.translate("TGA"), "W"); // variant
     assertEquals(gc.translate("tag"), "E"); // variant
     assertEquals(gc.translate("AGC"), "S"); // non-variant
@@ -70,7 +68,7 @@ public class GeneticCodesTest
   @Test(groups = { "Functional" })
   public void testTranslate_standardTable()
   {
-    GeneticCodeI st = GeneticCodes.getInstance().getStandardCodeTable();
+    GeneticCodeI st = GeneticCodes.getStandardCodeTable();
     assertEquals("F", st.translate("TTT"));
     assertEquals("F", st.translate("TTC"));
     assertEquals("L", st.translate("TTA"));
@@ -144,7 +142,7 @@ public class GeneticCodesTest
   @Test(groups = { "Functional" })
   public void testTranslate_standardTableAmbiguityCodes()
   {
-    GeneticCodeI st = GeneticCodes.getInstance().getStandardCodeTable();
+    GeneticCodeI st = GeneticCodes.getStandardCodeTable();
     // Y is C or T
     assertEquals("C", st.translate("TGY"));
     // Phenylalanine first base variation
@@ -236,13 +234,13 @@ public class GeneticCodesTest
   @Test(groups = { "Functional" })
   public void testTranslate_nonStandardTableAmbiguityCodes()
   {
-    GeneticCodeI standard = GeneticCodes.getInstance()
+    GeneticCodeI standard = GeneticCodes
             .getStandardCodeTable();
 
     /*
      * Vertebrate Mitochondrial (Table 2)
      */
-    GeneticCodeI gc = GeneticCodes.getInstance().getCodeTable("2");
+    GeneticCodeI gc = GeneticCodes.getCodeTable("2");
     // AGR is AGA or AGG - R in standard code, * in table 2
     assertEquals(gc.translate("AGR"), "*");
     assertEquals(standard.translate("AGR"), "R");
@@ -253,7 +251,7 @@ public class GeneticCodesTest
     /*
      * Yeast Mitochondrial (Table 3)
      */
-    gc = GeneticCodes.getInstance().getCodeTable("3");
+    gc = GeneticCodes.getCodeTable("3");
     // CTN is L in standard code, T in table 3
     assertEquals(gc.translate("ctn"), "T");
     assertEquals(standard.translate("CTN"), "L");
@@ -261,7 +259,7 @@ public class GeneticCodesTest
     /*
      * Alternative Yeast Nuclear (Table 12)
      */
-    gc = GeneticCodes.getInstance().getCodeTable("12");
+    gc = GeneticCodes.getCodeTable("12");
     // CTG is S; in the standard code CTN is L
     assertEquals(gc.translate("CTG"), "S");
     assertNull(gc.translate("CTK")); // K is G or T -> S or L
@@ -273,7 +271,7 @@ public class GeneticCodesTest
     /*
      * Trematode Mitochondrial (Table 21)
      */
-    gc = GeneticCodes.getInstance().getCodeTable("21");
+    gc = GeneticCodes.getCodeTable("21");
     // AAR is K in standard code, ambiguous in table 21 as AAA=N not K
     assertNull(gc.translate("AAR"));
     assertEquals(standard.translate("AAR"), "K");
@@ -282,15 +280,13 @@ public class GeneticCodesTest
   @Test(groups = "Functional")
   public void testTranslateCanonical()
   {
-    GeneticCodes codes = GeneticCodes.getInstance();
-
-    GeneticCodeI gc = codes.getCodeTable("1");
+    GeneticCodeI gc = GeneticCodes.getCodeTable("1");
     assertNull(gc.translateCanonical("XYZ"));
     assertEquals(gc.translateCanonical("AGA"), "R");
     // translateCanonical should not resolve ambiguity codes
     assertNull(gc.translateCanonical("TGY"));
 
-    gc = codes.getCodeTable("2");
+    gc = GeneticCodes.getCodeTable("2");
     assertNull(gc.translateCanonical("AGR"));
     assertEquals(gc.translateCanonical("AGA"), "*"); // variant
     assertEquals(gc.translateCanonical("ttc"), "F"); // non-variant
diff --git a/test/jalview/ext/jmol/JmolParserTest.java b/test/jalview/ext/jmol/JmolParserTest.java
index 2832135..0977669 100644
--- a/test/jalview/ext/jmol/JmolParserTest.java
+++ b/test/jalview/ext/jmol/JmolParserTest.java
@@ -98,11 +98,11 @@ public class JmolParserTest
   public void setUp()
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
+    Cache.setPropertyNoSave("STRUCT_FROM_PDB",
             Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("ADD_TEMPFACT_ANN",
+    Cache.setPropertyNoSave("ADD_TEMPFACT_ANN",
             Boolean.FALSE.toString());
-    Cache.applicationProperties.setProperty("ADD_SS_ANN",
+    Cache.setPropertyNoSave("ADD_SS_ANN",
             Boolean.TRUE.toString());
     StructureImportSettings.setDefaultStructureFileFormat("PDB");
     StructureImportSettings
diff --git a/test/jalview/gui/AlignFrameTest.java b/test/jalview/gui/AlignFrameTest.java
index fd10d99..779941b 100644
--- a/test/jalview/gui/AlignFrameTest.java
+++ b/test/jalview/gui/AlignFrameTest.java
@@ -175,7 +175,7 @@ public class AlignFrameTest
   public void setUp()
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+    Cache.setPropertyNoSave("SHOW_IDENTITY",
             Boolean.TRUE.toString());
     af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
             DataSourceType.FILE);
diff --git a/test/jalview/gui/AlignViewportTest.java b/test/jalview/gui/AlignViewportTest.java
index 75e8065..6252cbe 100644
--- a/test/jalview/gui/AlignViewportTest.java
+++ b/test/jalview/gui/AlignViewportTest.java
@@ -280,15 +280,15 @@ public class AlignViewportTest
   @Test(groups = { "Functional" }, timeOut=2000)
   public void testUpdateConservation_qualityOnly()
   {
-    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
+    Cache.setPropertyNoSave("SHOW_ANNOTATIONS",
             Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("SHOW_QUALITY",
+    Cache.setPropertyNoSave("SHOW_QUALITY",
             Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
+    Cache.setPropertyNoSave("SHOW_CONSERVATION",
             Boolean.FALSE.toString());
-    Cache.applicationProperties.setProperty("SHOW_OCCUPANCY",
+    Cache.setPropertyNoSave("SHOW_OCCUPANCY",
             Boolean.FALSE.toString());
-    Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+    Cache.setPropertyNoSave("SHOW_IDENTITY",
             Boolean.FALSE.toString());
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
@@ -327,8 +327,8 @@ public class AlignViewportTest
     /*
      * test for JAL-2283: don't inadvertently turn on colour by conservation
      */
-    Cache.applicationProperties.setProperty("DEFAULT_COLOUR_PROT", "None");
-    Cache.applicationProperties.setProperty("SHOW_CONSERVATION",
+    Cache.setPropertyNoSave("DEFAULT_COLOUR_PROT", "None");
+    Cache.setPropertyNoSave("SHOW_CONSERVATION",
             Boolean.TRUE.toString());
     AlignFrame af = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
diff --git a/test/jalview/gui/AlignmentPanelTest.java b/test/jalview/gui/AlignmentPanelTest.java
index 58f7324..1b0ec35 100644
--- a/test/jalview/gui/AlignmentPanelTest.java
+++ b/test/jalview/gui/AlignmentPanelTest.java
@@ -140,7 +140,7 @@ public class AlignmentPanelTest
     Jalview.main(new String[] { "-nonews", "-props",
         "test/jalview/testProps.jvprops" });
 
-    Cache.applicationProperties.setProperty("SHOW_IDENTITY",
+    Cache.setPropertyNoSave("SHOW_IDENTITY",
             Boolean.TRUE.toString());
     af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
             DataSourceType.FILE);
diff --git a/test/jalview/gui/AnnotationChooserTest.java b/test/jalview/gui/AnnotationChooserTest.java
index fbdda09..f0c4632 100644
--- a/test/jalview/gui/AnnotationChooserTest.java
+++ b/test/jalview/gui/AnnotationChooserTest.java
@@ -88,14 +88,14 @@ public class AnnotationChooserTest
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
     // pin down annotation sort order for test
-    Cache.applicationProperties.setProperty(Preferences.SORT_ANNOTATIONS,
+    Cache.setPropertyNoSave(Preferences.SORT_ANNOTATIONS,
             SequenceAnnotationOrder.NONE.name());
     final String TRUE = Boolean.TRUE.toString();
-    Cache.applicationProperties.setProperty(
+    Cache.setPropertyNoSave(
             Preferences.SHOW_AUTOCALC_ABOVE, TRUE);
-    Cache.applicationProperties.setProperty("SHOW_QUALITY", TRUE);
-    Cache.applicationProperties.setProperty("SHOW_CONSERVATION", TRUE);
-    Cache.applicationProperties.setProperty("SHOW_IDENTITY", TRUE);
+    Cache.setPropertyNoSave("SHOW_QUALITY", TRUE);
+    Cache.setPropertyNoSave("SHOW_CONSERVATION", TRUE);
+    Cache.setPropertyNoSave("SHOW_IDENTITY", TRUE);
 
     AlignmentI al = new FormatAdapter().readFile(TEST_DATA,
             DataSourceType.PASTE, FileFormat.Fasta);
diff --git a/test/jalview/gui/AnnotationColumnChooserTest.java b/test/jalview/gui/AnnotationColumnChooserTest.java
index 912cd27..36d49dc 100644
--- a/test/jalview/gui/AnnotationColumnChooserTest.java
+++ b/test/jalview/gui/AnnotationColumnChooserTest.java
@@ -76,14 +76,14 @@ public class AnnotationColumnChooserTest
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
     // pin down annotation sort order for test
-    Cache.applicationProperties.setProperty(Preferences.SORT_ANNOTATIONS,
+    Cache.setPropertyNoSave(Preferences.SORT_ANNOTATIONS,
             SequenceAnnotationOrder.NONE.name());
     final String TRUE = Boolean.TRUE.toString();
-    Cache.applicationProperties.setProperty(Preferences.SHOW_AUTOCALC_ABOVE,
+    Cache.setPropertyNoSave(Preferences.SHOW_AUTOCALC_ABOVE,
             TRUE);
-    Cache.applicationProperties.setProperty("SHOW_QUALITY", TRUE);
-    Cache.applicationProperties.setProperty("SHOW_CONSERVATION", TRUE);
-    Cache.applicationProperties.setProperty("SHOW_IDENTITY", TRUE);
+    Cache.setPropertyNoSave("SHOW_QUALITY", TRUE);
+    Cache.setPropertyNoSave("SHOW_CONSERVATION", TRUE);
+    Cache.setPropertyNoSave("SHOW_IDENTITY", TRUE);
 
     AlignmentI al = new FormatAdapter().readFile(TEST_DATA,
             DataSourceType.PASTE, FileFormat.Fasta);
diff --git a/test/jalview/gui/AnnotationRowFilterTest.java b/test/jalview/gui/AnnotationRowFilterTest.java
index 69a41c5..47bd924 100644
--- a/test/jalview/gui/AnnotationRowFilterTest.java
+++ b/test/jalview/gui/AnnotationRowFilterTest.java
@@ -27,9 +27,9 @@ public class AnnotationRowFilterTest
   public void setUp()
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS",
+    Cache.setPropertyNoSave("SHOW_ANNOTATIONS",
             Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty(
+    Cache.setPropertyNoSave(
             Preferences.SHOW_AUTOCALC_ABOVE, Boolean.TRUE.toString());
     af = new FileLoader().LoadFileWaitTillLoaded("examples/uniref50.fa",
             DataSourceType.FILE);
diff --git a/test/jalview/gui/CalculationChooserTest.java b/test/jalview/gui/CalculationChooserTest.java
index 6c2e777..595baef 100644
--- a/test/jalview/gui/CalculationChooserTest.java
+++ b/test/jalview/gui/CalculationChooserTest.java
@@ -19,7 +19,7 @@ public class CalculationChooserTest
   {
     // read-only Jalview properties
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.applicationProperties.setProperty("BLOSUM62_PCA_FOR_NUCLEOTIDE",
+    Cache.setPropertyNoSave("BLOSUM62_PCA_FOR_NUCLEOTIDE",
             Boolean.FALSE.toString());
   }
 
@@ -73,7 +73,7 @@ public class CalculationChooserTest
     /*
      * enable inclusion of BLOSUM62 for nucleotide PCA (JAL-2962)
      */
-    Cache.applicationProperties.setProperty("BLOSUM62_PCA_FOR_NUCLEOTIDE",
+    Cache.setPropertyNoSave("BLOSUM62_PCA_FOR_NUCLEOTIDE",
             Boolean.TRUE.toString());
 
     /*
diff --git a/test/jalview/gui/FreeUpMemoryTest.java b/test/jalview/gui/FreeUpMemoryTest.java
index ee2b898..18ff7f2 100644
--- a/test/jalview/gui/FreeUpMemoryTest.java
+++ b/test/jalview/gui/FreeUpMemoryTest.java
@@ -35,11 +35,11 @@ public class FreeUpMemoryTest
     Jalview.main(new String[] { "-nonews", "-props",
         "test/jalview/testProps.jvprops" });
     String True = Boolean.TRUE.toString();
-    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", True);
-    Cache.applicationProperties.setProperty("SHOW_QUALITY", True);
-    Cache.applicationProperties.setProperty("SHOW_CONSERVATION", True);
-    Cache.applicationProperties.setProperty("SHOW_OCCUPANCY", True);
-    Cache.applicationProperties.setProperty("SHOW_IDENTITY", True);
+    Cache.setPropertyNoSave("SHOW_ANNOTATIONS", True);
+    Cache.setPropertyNoSave("SHOW_QUALITY", True);
+    Cache.setPropertyNoSave("SHOW_CONSERVATION", True);
+    Cache.setPropertyNoSave("SHOW_OCCUPANCY", True);
+    Cache.setPropertyNoSave("SHOW_IDENTITY", True);
   }
 
   /**
diff --git a/test/jalview/gui/SeqPanelTest.java b/test/jalview/gui/SeqPanelTest.java
index 54c967f..17e04bf 100644
--- a/test/jalview/gui/SeqPanelTest.java
+++ b/test/jalview/gui/SeqPanelTest.java
@@ -258,8 +258,8 @@ public class SeqPanelTest
   @Test(groups = "Functional")
   public void testFindMousePosition_wrapped_annotations()
   {
-    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true");
-    Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
+    Cache.setPropertyNoSave("SHOW_ANNOTATIONS", "true");
+    Cache.setPropertyNoSave("WRAP_ALIGNMENT", "true");
     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
     AlignViewportI av = alignFrame.getViewport();
@@ -433,8 +433,8 @@ public class SeqPanelTest
   @Test(groups = "Functional")
   public void testFindMousePosition_wrapped_scaleAbove()
   {
-    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "true");
-    Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
+    Cache.setPropertyNoSave("SHOW_ANNOTATIONS", "true");
+    Cache.setPropertyNoSave("WRAP_ALIGNMENT", "true");
     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
     AlignViewportI av = alignFrame.getViewport();
@@ -628,8 +628,8 @@ public class SeqPanelTest
   @Test(groups = "Functional")
   public void testFindMousePosition_wrapped_noAnnotations()
   {
-    Cache.applicationProperties.setProperty("SHOW_ANNOTATIONS", "false");
-    Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
+    Cache.setPropertyNoSave("SHOW_ANNOTATIONS", "false");
+    Cache.setPropertyNoSave("WRAP_ALIGNMENT", "true");
     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
     AlignViewportI av = alignFrame.getViewport();
@@ -716,7 +716,7 @@ public class SeqPanelTest
   @Test(groups = "Functional")
   public void testFindColumn_unwrapped()
   {
-    Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "false");
+    Cache.setPropertyNoSave("WRAP_ALIGNMENT", "false");
     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
     SeqPanel testee = alignFrame.alignPanel.getSeqPanel();
@@ -782,7 +782,7 @@ public class SeqPanelTest
   @Test(groups = "Functional")
   public void testFindColumn_wrapped()
   {
-    Cache.applicationProperties.setProperty("WRAP_ALIGNMENT", "true");
+    Cache.setPropertyNoSave("WRAP_ALIGNMENT", "true");
     AlignFrame alignFrame = new FileLoader().LoadFileWaitTillLoaded(
             "examples/uniref50.fa", DataSourceType.FILE);
     AlignViewport av = alignFrame.getViewport();
diff --git a/test/jalview/io/AnnotatedPDBFileInputTest.java b/test/jalview/io/AnnotatedPDBFileInputTest.java
index b8ac0fa..beeb52f 100644
--- a/test/jalview/io/AnnotatedPDBFileInputTest.java
+++ b/test/jalview/io/AnnotatedPDBFileInputTest.java
@@ -68,9 +68,9 @@ public class AnnotatedPDBFileInputTest
   @BeforeMethod(alwaysRun = true)
   public void setup() throws Exception
   {
-    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
+    Cache.setPropertyNoSave("STRUCT_FROM_PDB",
             Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("ADD_SS_ANN",
+    Cache.setPropertyNoSave("ADD_SS_ANN",
             Boolean.TRUE.toString());
     FileLoader loader = new FileLoader(false);
     AlignFrame af = loader.LoadFileWaitTillLoaded("examples/1gaq.txt",
diff --git a/test/jalview/io/BackupFilesTest.java b/test/jalview/io/BackupFilesTest.java
index 723279d..bb59f28 100644
--- a/test/jalview/io/BackupFilesTest.java
+++ b/test/jalview/io/BackupFilesTest.java
@@ -209,18 +209,18 @@ public class BackupFilesTest
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
 
-    Cache.applicationProperties.setProperty(BackupFiles.ENABLED,
+    Cache.setPropertyNoSave(BackupFiles.ENABLED,
             Boolean.toString(enabled));
-    Cache.applicationProperties.setProperty(BackupFiles.SUFFIX, suffix);
-    Cache.applicationProperties.setProperty(BackupFiles.SUFFIX_DIGITS,
+    Cache.setPropertyNoSave(BackupFiles.SUFFIX, suffix);
+    Cache.setPropertyNoSave(BackupFiles.SUFFIX_DIGITS,
             Integer.toString(digits));
-    Cache.applicationProperties.setProperty(BackupFiles.REVERSE_ORDER,
+    Cache.setPropertyNoSave(BackupFiles.REVERSE_ORDER,
             Boolean.toString(reverse));
-    Cache.applicationProperties.setProperty(BackupFiles.NO_MAX,
+    Cache.setPropertyNoSave(BackupFiles.NO_MAX,
             Boolean.toString(noMax));
-    Cache.applicationProperties.setProperty(BackupFiles.ROLL_MAX,
+    Cache.setPropertyNoSave(BackupFiles.ROLL_MAX,
             Integer.toString(rollMax));
-    Cache.applicationProperties.setProperty(BackupFiles.CONFIRM_DELETE_OLD,
+    Cache.setPropertyNoSave(BackupFiles.CONFIRM_DELETE_OLD,
             "false");
   }
 
diff --git a/test/jalview/ws/PDBSequenceFetcherTest.java b/test/jalview/ws/PDBSequenceFetcherTest.java
index d1e32b9..9992137 100644
--- a/test/jalview/ws/PDBSequenceFetcherTest.java
+++ b/test/jalview/ws/PDBSequenceFetcherTest.java
@@ -57,9 +57,9 @@ public class PDBSequenceFetcherTest
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
     // ensure 'add annotation from structure' is selected
-    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
+    Cache.setPropertyNoSave("STRUCT_FROM_PDB",
             Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("ADD_SS_ANN",
+    Cache.setPropertyNoSave("ADD_SS_ANN",
             Boolean.TRUE.toString());
 
     sf = new SequenceFetcher();
@@ -76,7 +76,7 @@ public class PDBSequenceFetcherTest
   @Test(groups = { "Network" }, enabled = true)
   public void testRnaSeqRetrieve() throws Exception
   {
-    Cache.applicationProperties.setProperty("PDB_DOWNLOAD_FORMAT", "PDB");
+    Cache.setPropertyNoSave("PDB_DOWNLOAD_FORMAT", "PDB");
     List sps = sf.getSourceProxy("PDB");
     AlignmentI response = sps.get(0).getSequenceRecords("2GIS");
     assertTrue(response != null);
diff --git a/test/jalview/ws/dbsources/RemoteFormatTest.java b/test/jalview/ws/dbsources/RemoteFormatTest.java
index 629bd8a..9d40624 100644
--- a/test/jalview/ws/dbsources/RemoteFormatTest.java
+++ b/test/jalview/ws/dbsources/RemoteFormatTest.java
@@ -46,9 +46,9 @@ public class RemoteFormatTest
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
     // ensure 'add annotation from structure' is selected
-    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
+    Cache.setPropertyNoSave("STRUCT_FROM_PDB",
             Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("ADD_SS_ANN",
+    Cache.setPropertyNoSave("ADD_SS_ANN",
             Boolean.TRUE.toString());
 
     sf = new SequenceFetcher();
diff --git a/test/mc_view/PDBfileTest.java b/test/mc_view/PDBfileTest.java
index c99d185..0e34a24 100644
--- a/test/mc_view/PDBfileTest.java
+++ b/test/mc_view/PDBfileTest.java
@@ -325,11 +325,11 @@ public class PDBfileTest
   public void setUp()
   {
     Cache.loadProperties("test/jalview/io/testProps.jvprops");
-    Cache.applicationProperties.setProperty("STRUCT_FROM_PDB",
+    Cache.setPropertyNoSave("STRUCT_FROM_PDB",
             Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("ADD_TEMPFACT_ANN",
+    Cache.setPropertyNoSave("ADD_TEMPFACT_ANN",
             Boolean.TRUE.toString());
-    Cache.applicationProperties.setProperty("ADD_SS_ANN",
+    Cache.setPropertyNoSave("ADD_SS_ANN",
             Boolean.TRUE.toString());
     StructureImportSettings.setDefaultStructureFileFormat("PDB");
   }
-- 
1.7.10.2