JAL-2089 patch broken merge to master for Release 2.10.0b1
[jalview.git] / src / jalview / ws / seqfetcher / ASequenceFetcher.java
index 1b0d6c1..31168b4 100644 (file)
-/*\r
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)\r
- * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle\r
- * \r
- * This file is part of Jalview.\r
- * \r
- * Jalview is free software: you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License \r
- * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
- * \r
- * Jalview is distributed in the hope that it will be useful, but \r
- * WITHOUT ANY WARRANTY; without even the implied warranty \r
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
- * PURPOSE.  See the GNU General Public License for more details.\r
- * \r
- * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
- */\r
-package jalview.ws.seqfetcher;\r
-\r
-import jalview.datamodel.AlignmentI;\r
-import jalview.datamodel.SequenceI;\r
-\r
-import java.util.Enumeration;\r
-import java.util.Hashtable;\r
-import java.util.Vector;\r
-\r
-public class ASequenceFetcher\r
-{\r
-\r
-  /**\r
-   * set of databases we can retrieve entries from\r
-   */\r
-  protected Hashtable FETCHABLEDBS;\r
-\r
-  public ASequenceFetcher()\r
-  {\r
-    super();\r
-  }\r
-\r
-  /**\r
-   * get list of supported Databases\r
-   * \r
-   * @return database source string for each database - only the latest version\r
-   *         of a source db is bound to each source.\r
-   */\r
-  public String[] getSupportedDb()\r
-  {\r
-    if (FETCHABLEDBS == null)\r
-      return null;\r
-    String[] sf = new String[FETCHABLEDBS.size()];\r
-    Enumeration e = FETCHABLEDBS.keys();\r
-    int i = 0;\r
-    while (e.hasMoreElements())\r
-    {\r
-      sf[i++] = (String) e.nextElement();\r
-    }\r
-    ;\r
-    return sf;\r
-  }\r
-\r
-  public boolean isFetchable(String source)\r
-  {\r
-    Enumeration e = FETCHABLEDBS.keys();\r
-    while (e.hasMoreElements())\r
-    {\r
-      String db = (String) e.nextElement();\r
-      if (source.compareToIgnoreCase(db) == 0)\r
-        return true;\r
-    }\r
-    jalview.bin.Cache.log.warn("isFetchable doesn't know about '" + source\r
-            + "'");\r
-    return false;\r
-  }\r
-\r
-  public SequenceI[] getSequences(jalview.datamodel.DBRefEntry[] refs)\r
-  {\r
-    SequenceI[] ret = null;\r
-    Vector rseqs = new Vector();\r
-    Hashtable queries = new Hashtable();\r
-    for (int r = 0; r < refs.length; r++)\r
-    {\r
-      if (!queries.containsKey(refs[r].getSource()))\r
-      {\r
-        queries.put(refs[r].getSource(), new Vector());\r
-      }\r
-      Vector qset = (Vector) queries.get(refs[r].getSource());\r
-      if (!qset.contains(refs[r].getAccessionId()))\r
-      {\r
-        qset.addElement(refs[r].getAccessionId());\r
-      }\r
-    }\r
-    Enumeration e = queries.keys();\r
-    while (e.hasMoreElements())\r
-    {\r
-      Vector query = null;\r
-      String db = null;\r
-      try\r
-      {\r
-        db = (String) e.nextElement();\r
-        query = (Vector) queries.get(db);\r
-        if (!isFetchable(db))\r
-          throw new Exception(\r
-                  "Don't know how to fetch from this database :" + db);\r
-        DbSourceProxy fetcher = getSourceProxy(db);\r
-        boolean doMultiple = fetcher.getAccessionSeparator() != null; // No\r
-        // separator\r
-        // - no\r
-        // Multiple\r
-        // Queries\r
-        Enumeration qs = query.elements();\r
-        while (qs.hasMoreElements())\r
-        {\r
-          StringBuffer qsb = new StringBuffer();\r
-          do\r
-          {\r
-            qsb.append((String) qs.nextElement());\r
-            if (qs.hasMoreElements() && doMultiple) // and not reached limit for\r
-            // multiple queries at one\r
-            // time for this source\r
-            {\r
-              qsb.append(fetcher.getAccessionSeparator());\r
-            }\r
-          } while (doMultiple && qs.hasMoreElements());\r
-\r
-          AlignmentI seqset = null;\r
-          try\r
-          {\r
-            // create a fetcher and go to it\r
-            seqset = fetcher.getSequenceRecords(qsb.toString());\r
-          } catch (Exception ex)\r
-          {\r
-            System.err.println("Failed to retrieve the following from "\r
-                    + db);\r
-            System.err.println(qsb);\r
-            ex.printStackTrace(System.err);\r
-          }\r
-          // TODO: Merge alignment together - perhaps\r
-          if (seqset != null)\r
-          {\r
-            SequenceI seqs[] = seqset.getSequencesArray();\r
-            if (seqs != null)\r
-            {\r
-              for (int is = 0; is < seqs.length; is++)\r
-              {\r
-                rseqs.addElement(seqs[is]);\r
-                seqs[is] = null;\r
-              }\r
-            }\r
-            else\r
-            {\r
-              if (fetcher.getRawRecords() != null)\r
-              {\r
-                System.out.println("# Retrieved from " + db + ":"\r
-                        + qs.toString());\r
-                StringBuffer rrb = fetcher.getRawRecords();\r
-                /*\r
-                 * for (int rr = 0; rr<rrb.length; rr++) {\r
-                 */\r
-                String hdr;\r
-                // if (rr<qs.length)\r
-                // {\r
-                hdr = "# " + db + ":" + qsb.toString();\r
-                /*\r
-                 * } else { hdr = "# part "+rr; }\r
-                 */\r
-                System.out.println(hdr);\r
-                if (rrb != null)\r
-                  System.out.println(rrb);\r
-                System.out.println("# end of " + hdr);\r
-              }\r
-            }\r
-          }\r
-        }\r
-      } catch (Exception ex)\r
-      {\r
-        System.err\r
-                .println("Failed to retrieve the following references from "\r
-                        + db);\r
-        Enumeration qv = query.elements();\r
-        int n = 0;\r
-        while (qv.hasMoreElements())\r
-        {\r
-          System.err.print(" " + qv.nextElement() + ";");\r
-          if (n++ > 10)\r
-          {\r
-            System.err.println();\r
-            n = 0;\r
-          }\r
-        }\r
-        System.err.println();\r
-        ex.printStackTrace();\r
-      }\r
-    }\r
-    if (rseqs.size() > 0)\r
-    {\r
-      ret = new SequenceI[rseqs.size()];\r
-      Enumeration sqs = rseqs.elements();\r
-      int si = 0;\r
-      while (sqs.hasMoreElements())\r
-      {\r
-        SequenceI s = (SequenceI) sqs.nextElement();\r
-        ret[si++] = s;\r
-        s.updatePDBIds();\r
-      }\r
-    }\r
-    return ret;\r
-  }\r
-\r
-  /**\r
-   * Retrieve an instance of the proxy for the given source\r
-   * \r
-   * @param db\r
-   *          database source string TODO: add version string/wildcard for\r
-   *          retrieval of specific DB source/version combinations.\r
-   * @return an instance of DbSourceProxy for that db.\r
-   */\r
-  public DbSourceProxy getSourceProxy(String db)\r
-  {\r
-    DbSourceProxy dbs = (DbSourceProxy) FETCHABLEDBS.get(db);\r
-    return dbs;\r
-  }\r
-\r
-  /**\r
-   * constructs and instance of the proxy and registers it as a valid\r
-   * dbrefsource\r
-   * \r
-   * @param dbSourceProxy\r
-   *          reference for class implementing\r
-   *          jalview.ws.seqfetcher.DbSourceProxy\r
-   * @throws java.lang.IllegalArgumentException\r
-   *           if class does not implement jalview.ws.seqfetcher.DbSourceProxy\r
-   */\r
-  protected void addDBRefSourceImpl(Class dbSourceProxy)\r
-          throws java.lang.IllegalArgumentException\r
-  {\r
-    DbSourceProxy proxy = null;\r
-    try\r
-    {\r
-      Object proxyObj = dbSourceProxy.getConstructor(null)\r
-              .newInstance(null);\r
-      if (!DbSourceProxy.class.isInstance(proxyObj))\r
-      {\r
-        throw new IllegalArgumentException(\r
-                dbSourceProxy.toString()\r
-                        + " does not implement the jalview.ws.seqfetcher.DbSourceProxy");\r
-      }\r
-      proxy = (DbSourceProxy) proxyObj;\r
-    } catch (IllegalArgumentException e)\r
-    {\r
-      throw e;\r
-    } catch (Exception e)\r
-    {\r
-      // Serious problems if this happens.\r
-      throw new Error("DBRefSource Implementation Exception", e);\r
-    }\r
-    addDbRefSourceImpl(proxy);\r
-  }\r
-\r
-  /**\r
-   * add the properly initialised DbSourceProxy object 'proxy' to the list of\r
-   * sequence fetchers\r
-   * \r
-   * @param proxy\r
-   */\r
-  protected void addDbRefSourceImpl(DbSourceProxy proxy)\r
-  {\r
-    if (proxy != null)\r
-    {\r
-      if (FETCHABLEDBS == null)\r
-      {\r
-        FETCHABLEDBS = new Hashtable();\r
-      }\r
-      FETCHABLEDBS.put(proxy.getDbSource(), proxy);\r
-    }\r
-  }\r
-\r
-  /**\r
-   * test if the database handler for dbName contains the given dbProperty\r
-   * \r
-   * @param dbName\r
-   * @param dbProperty\r
-   * @return true if proxy has the given property\r
-   */\r
-  public boolean hasDbSourceProperty(String dbName, String dbProperty)\r
-  {\r
-    // TODO: decide if invalidDbName exception is thrown here.\r
-    DbSourceProxy proxy = getSourceProxy(dbName);\r
-    if (proxy != null)\r
-    {\r
-      if (proxy.getDbSourceProperties() != null)\r
-      {\r
-        return proxy.getDbSourceProperties().containsKey(dbProperty);\r
-      }\r
-    }\r
-    return false;\r
-  }\r
-\r
-  /**\r
-   * select sources which are implemented by instances of the given class\r
-   * \r
-   * @param class that implements DbSourceProxy\r
-   * @return null or vector of source names for fetchers\r
-   */\r
-  public String[] getDbInstances(Class class1)\r
-  {\r
-    if (!jalview.ws.seqfetcher.DbSourceProxy.class.isAssignableFrom(class1))\r
-    {\r
-      throw new Error(\r
-              "Implmentation Error - getDbInstances must be given a class that implements jalview.ws.seqfetcher.DbSourceProxy (was given '"\r
-                      + class1 + "')");\r
-    }\r
-    if (FETCHABLEDBS == null)\r
-    {\r
-      return null;\r
-    }\r
-    String[] sources = null;\r
-    Vector src = new Vector();\r
-    Enumeration dbs = FETCHABLEDBS.keys();\r
-    while (dbs.hasMoreElements())\r
-    {\r
-      String dbn = (String) dbs.nextElement();\r
-      DbSourceProxy dbp = (DbSourceProxy) FETCHABLEDBS.get(dbn);\r
-      if (class1.isAssignableFrom(dbp.getClass()))\r
-      {\r
-        src.addElement(dbn);\r
-      }\r
-    }\r
-    if (src.size() > 0)\r
-    {\r
-      src.copyInto(sources = new String[src.size()]);\r
-    }\r
-    return sources;\r
-  }\r
-}\r
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
+package jalview.ws.seqfetcher;
+
+import jalview.api.FeatureSettingsModelI;
+import jalview.bin.Cache;
+import jalview.datamodel.AlignmentI;
+import jalview.datamodel.DBRefEntry;
+import jalview.datamodel.SequenceI;
+import jalview.util.DBRefUtils;
+import jalview.util.MessageManager;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import java.util.Vector;
+
+public class ASequenceFetcher
+{
+
+  /*
+   * set of databases we can retrieve entries from
+   */
+  protected Hashtable<String, Map<String, DbSourceProxy>> fetchableDbs;
+
+  /*
+   * comparator to sort by tier (0/1/2) and name
+   */
+  private Comparator<DbSourceProxy> proxyComparator;
+
+  /**
+   * Constructor
+   */
+  protected ASequenceFetcher()
+  {
+    super();
+
+    /*
+     * comparator to sort proxies by tier and name
+     */
+    proxyComparator = new Comparator<DbSourceProxy>()
+    {
+      @Override
+      public int compare(DbSourceProxy o1, DbSourceProxy o2)
+      {
+        /*
+         * Tier 0 precedes 1 precedes 2
+         */
+        int compared = Integer.compare(o1.getTier(), o2.getTier());
+        if (compared == 0)
+        {
+          // defend against NullPointer - should never happen
+          String o1Name = o1.getDbName();
+          String o2Name = o2.getDbName();
+          if (o1Name != null && o2Name != null)
+          {
+            compared = o1Name.compareToIgnoreCase(o2Name);
+          }
+        }
+        return compared;
+      }
+    };
+  }
+
+  /**
+   * get array of supported Databases
+   * 
+   * @return database source string for each database - only the latest version
+   *         of a source db is bound to each source.
+   */
+  public String[] getSupportedDb()
+  {
+    if (fetchableDbs == null)
+    {
+      return null;
+    }
+    String[] sf = fetchableDbs.keySet().toArray(
+            new String[fetchableDbs.size()]);
+    return sf;
+  }
+
+  public boolean isFetchable(String source)
+  {
+    for (String db : fetchableDbs.keySet())
+    {
+      if (source.equalsIgnoreCase(db))
+      {
+        return true;
+      }
+    }
+    Cache.log.warn("isFetchable doesn't know about '" + source + "'");
+    return false;
+  }
+
+  /**
+   * Fetch sequences for the given cross-references
+   * 
+   * @param refs
+   * @param dna
+   *          if true, only fetch from nucleotide data sources, else peptide
+   * @return
+   */
+  public SequenceI[] getSequences(List<DBRefEntry> refs, boolean dna)
+  {
+    Vector<SequenceI> rseqs = new Vector<SequenceI>();
+    Hashtable<String, List<String>> queries = new Hashtable<String, List<String>>();
+    for (DBRefEntry ref : refs)
+    {
+      if (!queries.containsKey(ref.getSource()))
+      {
+        queries.put(ref.getSource(), new ArrayList<String>());
+      }
+      List<String> qset = queries.get(ref.getSource());
+      if (!qset.contains(ref.getAccessionId()))
+      {
+        qset.add(ref.getAccessionId());
+      }
+    }
+    Enumeration<String> e = queries.keys();
+    while (e.hasMoreElements())
+    {
+      List<String> query = null;
+      String db = null;
+      db = e.nextElement();
+      query = queries.get(db);
+      if (!isFetchable(db))
+      {
+        reportStdError(db, query, new Exception(
+                "Don't know how to fetch from this database :" + db));
+        continue;
+      }
+
+      Stack<String> queriesLeft = new Stack<String>();
+      queriesLeft.addAll(query);
+
+      List<DbSourceProxy> proxies = getSourceProxy(db);
+      for (DbSourceProxy fetcher : proxies)
+      {
+        List<String> queriesMade = new ArrayList<String>();
+        HashSet<String> queriesFound = new HashSet<String>();
+        try
+        {
+          if (fetcher.isDnaCoding() != dna)
+          {
+            continue; // wrong sort of data
+          }
+          boolean doMultiple = fetcher.getMaximumQueryCount() > 1;
+          while (!queriesLeft.isEmpty())
+          {
+            StringBuffer qsb = new StringBuffer();
+            do
+            {
+              if (qsb.length() > 0)
+              {
+                qsb.append(fetcher.getAccessionSeparator());
+              }
+              String q = queriesLeft.pop();
+              queriesMade.add(q);
+              qsb.append(q);
+            } while (doMultiple && !queriesLeft.isEmpty());
+
+            AlignmentI seqset = null;
+            try
+            {
+              // create a fetcher and go to it
+              seqset = fetcher.getSequenceRecords(qsb.toString());
+            } catch (Exception ex)
+            {
+              System.err.println("Failed to retrieve the following from "
+                      + db);
+              System.err.println(qsb);
+              ex.printStackTrace(System.err);
+            }
+            // TODO: Merge alignment together - perhaps
+            if (seqset != null)
+            {
+              SequenceI seqs[] = seqset.getSequencesArray();
+              if (seqs != null)
+              {
+                for (int is = 0; is < seqs.length; is++)
+                {
+                  rseqs.addElement(seqs[is]);
+                  List<DBRefEntry> frefs = DBRefUtils.searchRefs(seqs[is]
+                          .getDBRefs(), new DBRefEntry(db, null, null));
+                  for (DBRefEntry dbr : frefs)
+                  {
+                    queriesFound.add(dbr.getAccessionId());
+                    queriesMade.remove(dbr.getAccessionId());
+                  }
+                  seqs[is] = null;
+                }
+              }
+              else
+              {
+                if (fetcher.getRawRecords() != null)
+                {
+                  System.out.println("# Retrieved from " + db + ":"
+                          + qsb.toString());
+                  StringBuffer rrb = fetcher.getRawRecords();
+                  /*
+                   * for (int rr = 0; rr<rrb.length; rr++) {
+                   */
+                  String hdr;
+                  // if (rr<qs.length)
+                  // {
+                  hdr = "# " + db + ":" + qsb.toString();
+                  /*
+                   * } else { hdr = "# part "+rr; }
+                   */
+                  System.out.println(hdr);
+                  if (rrb != null)
+                  {
+                    System.out.println(rrb);
+                  }
+                  System.out.println("# end of " + hdr);
+                }
+
+              }
+            }
+
+          }
+        } catch (Exception ex)
+        {
+          reportStdError(db, queriesMade, ex);
+        }
+        if (queriesMade.size() > 0)
+        {
+          System.out.println("# Adding " + queriesMade.size()
+                  + " ids back to queries list for searching again (" + db
+                  + ")");
+          queriesLeft.addAll(queriesMade);
+        }
+      }
+    }
+
+    SequenceI[] result = null;
+    if (rseqs.size() > 0)
+    {
+      result = new SequenceI[rseqs.size()];
+      int si = 0;
+      for (SequenceI s : rseqs)
+      {
+        result[si++] = s;
+        s.updatePDBIds();
+      }
+    }
+    return result;
+  }
+
+  public void reportStdError(String db, List<String> queriesMade,
+          Exception ex)
+  {
+
+    System.err.println("Failed to retrieve the following references from "
+            + db);
+    int n = 0;
+    for (String qv : queriesMade)
+    {
+      System.err.print(" " + qv + ";");
+      if (n++ > 10)
+      {
+        System.err.println();
+        n = 0;
+      }
+    }
+    System.err.println();
+    ex.printStackTrace();
+  }
+
+  /**
+   * Returns a list of proxies for the given source
+   * 
+   * @param db
+   *          database source string TODO: add version string/wildcard for
+   *          retrieval of specific DB source/version combinations.
+   * @return a list of DbSourceProxy for the db
+   */
+  public List<DbSourceProxy> getSourceProxy(String db)
+  {
+    db = DBRefUtils.getCanonicalName(db);
+    Map<String, DbSourceProxy> dblist = fetchableDbs.get(db);
+    if (dblist == null)
+    {
+      return new ArrayList<DbSourceProxy>();
+    }
+
+    /*
+     * sort so that primary sources precede secondary
+     */
+    List<DbSourceProxy> dbs = new ArrayList<DbSourceProxy>(dblist.values());
+    Collections.sort(dbs, proxyComparator);
+    return dbs;
+  }
+
+  /**
+   * constructs an instance of the proxy and registers it as a valid dbrefsource
+   * 
+   * @param dbSourceProxy
+   *          reference for class implementing
+   *          jalview.ws.seqfetcher.DbSourceProxy
+   */
+  protected void addDBRefSourceImpl(
+          Class<? extends DbSourceProxy> dbSourceProxy)
+          throws IllegalArgumentException
+  {
+    DbSourceProxy proxy = null;
+    try
+    {
+      DbSourceProxy proxyObj = dbSourceProxy.getConstructor().newInstance();
+      proxy = proxyObj;
+    } catch (IllegalArgumentException e)
+    {
+      throw e;
+    } catch (Exception e)
+    {
+      // Serious problems if this happens.
+      throw new Error(
+              MessageManager
+                      .getString("error.dbrefsource_implementation_exception"),
+              e);
+    }
+    addDbRefSourceImpl(proxy);
+  }
+
+  /**
+   * add the properly initialised DbSourceProxy object 'proxy' to the list of
+   * sequence fetchers
+   * 
+   * @param proxy
+   */
+  protected void addDbRefSourceImpl(DbSourceProxy proxy)
+  {
+    if (proxy != null)
+    {
+      if (fetchableDbs == null)
+      {
+        fetchableDbs = new Hashtable<String, Map<String, DbSourceProxy>>();
+      }
+      Map<String, DbSourceProxy> slist = fetchableDbs.get(proxy
+              .getDbSource());
+      if (slist == null)
+      {
+        fetchableDbs.put(proxy.getDbSource(),
+                slist = new Hashtable<String, DbSourceProxy>());
+      }
+      slist.put(proxy.getDbName(), proxy);
+    }
+  }
+
+  /**
+   * select sources which are implemented by instances of the given class
+   * 
+   * @param class that implements DbSourceProxy
+   * @return null or vector of source names for fetchers
+   */
+  public String[] getDbInstances(Class class1)
+  {
+    if (!DbSourceProxy.class.isAssignableFrom(class1))
+    {
+      throw new Error(
+              MessageManager
+                      .formatMessage(
+                              "error.implementation_error_dbinstance_must_implement_interface",
+                              new String[] { class1.toString() }));
+    }
+    if (fetchableDbs == null)
+    {
+      return null;
+    }
+    String[] sources = null;
+    Vector<String> src = new Vector<String>();
+    Enumeration<String> dbs = fetchableDbs.keys();
+    while (dbs.hasMoreElements())
+    {
+      String dbn = dbs.nextElement();
+      for (DbSourceProxy dbp : fetchableDbs.get(dbn).values())
+      {
+        if (class1.isAssignableFrom(dbp.getClass()))
+        {
+          src.addElement(dbn);
+        }
+      }
+    }
+    if (src.size() > 0)
+    {
+      src.copyInto(sources = new String[src.size()]);
+    }
+    return sources;
+  }
+
+  public DbSourceProxy[] getDbSourceProxyInstances(Class class1)
+  {
+    List<DbSourceProxy> prlist = new ArrayList<DbSourceProxy>();
+    for (String fetchable : getSupportedDb())
+    {
+      for (DbSourceProxy pr : getSourceProxy(fetchable))
+      {
+        if (class1.isInstance(pr))
+        {
+          prlist.add(pr);
+        }
+      }
+    }
+    if (prlist.size() == 0)
+    {
+      return null;
+    }
+    return prlist.toArray(new DbSourceProxy[0]);
+  }
+
+  /**
+   * Returns a preferred feature colouring scheme for the given source, or null
+   * if none is defined.
+   * 
+   * @param source
+   * @return
+   */
+  public FeatureSettingsModelI getFeatureColourScheme(String source)
+  {
+    /*
+     * return the first non-null colour scheme for any proxy for
+     * this database source
+     */
+    for (DbSourceProxy proxy : getSourceProxy(source))
+    {
+      FeatureSettingsModelI preferredColours = proxy
+              .getFeatureColourScheme();
+      if (preferredColours != null)
+      {
+        return preferredColours;
+      }
+    }
+    return null;
+  }
+}