Merge branch 'develop' into features/JAL-1793VCF
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 26 Jan 2018 14:53:22 +0000 (14:53 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Fri, 26 Jan 2018 14:53:22 +0000 (14:53 +0000)
Conflicts:
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/ext/ensembl/EnsemblGene.java
src/jalview/ext/ensembl/EnsemblLookup.java
src/jalview/ext/ensembl/EnsemblSeqProxy.java

1  2 
resources/lang/Messages.properties
resources/lang/Messages_es.properties
src/jalview/ext/ensembl/EnsemblGene.java
src/jalview/ext/ensembl/EnsemblLookup.java
src/jalview/ext/ensembl/EnsemblSeqProxy.java
src/jalview/ext/ensembl/EnsemblSequenceFetcher.java
src/jalview/ext/ensembl/EnsemblSymbol.java
test/jalview/ext/ensembl/EnsemblSeqProxyTest.java

@@@ -1324,38 -1320,13 +1325,45 @@@ label.select_hidden_colour = Select hid
  label.overview = Overview
  label.reset_to_defaults = Reset to defaults
  label.oview_calc = Recalculating overview...
 +label.feature_details = Feature details
 +label.matchCondition_contains = Contains
 +label.matchCondition_notcontains = Does not contain
 +label.matchCondition_matches = Matches
 +label.matchCondition_notmatches = Does not match
 +label.matchCondition_present = Is present
 +label.matchCondition_notpresent = Is not present
 +label.matchCondition_eq = =
 +label.matchCondition_ne = not =
 +label.matchCondition_lt = <
 +label.matchCondition_le = <=
 +label.matchCondition_gt = >
 +label.matchCondition_ge = >=
 +label.numeric_required = The value should be numeric
 +label.filter = Filter
 +label.filters = Filters
 +label.join_conditions = Join conditions with
 +label.score = Score
 +label.colour_by_label = Colour by label
 +label.variable_colour = Variable colour
 +label.select_colour = Select colour
- option.enable_disable_autosearch = When ticked, search is performed automatically.
+ option.enable_disable_autosearch = When ticked, search is performed automatically
  option.autosearch = Autosearch
  label.retrieve_ids = Retrieve IDs
 +label.display_settings_for = Display settings for {0} features
 +label.simple = Simple
 +label.simple_colour = Simple Colour
 +label.colour_by_text = Colour by text
 +label.graduated_colour = Graduated Colour
 +label.by_text_of = By text of
 +label.by_range_of = By range of
 +label.filters_tooltip = Click to set or amend filters
 +label.or = Or
 +label.and = And
 +label.sequence_feature_colours = Sequence Feature Colours
+ label.best_quality = Best Quality
+ label.best_resolution = Best Resolution
+ label.most_protein_chain = Most Protein Chain
+ label.most_bound_molecules = Most Bound Molecules
+ label.most_polymer_residues = Most Polymer Residues
+ label.cached_structures = Cached Structures
+ label.free_text_search = Free Text Search
@@@ -337,6 -336,6 +337,8 @@@ label.optimise_order = Optimizar orde
  label.seq_sort_by_score = Ordenar las secuencias por puntuación
  label.load_colours = Cargar colores
  label.save_colours = Guardar colores
++label.load_colours_tooltip = Cargar colores y filtros desde fichero
++label.save_colours_tooltip = Guardar colores y filtros en fichero
  label.fetch_das_features = Recuperar funciones DAS
  label.selected_database_to_fetch_from = Seleccionada {0} Base de datos {1} para buscar de {2} 
  label.database_param = Base de datos: {0}
@@@ -1323,37 -1320,13 +1326,45 @@@ label.select_hidden_colour = Selecciona
  label.overview = Resumen
  label.reset_to_defaults = Restablecen a los predeterminados
  label.oview_calc = Recalculando resumen
 +label.feature_details = Detalles de característica 
 +label.matchCondition_contains = Contiene
 +label.matchCondition_notcontains = No contiene
 +label.matchCondition_matches = Es igual a
 +label.matchCondition_notmatches = No es igual a
 +label.matchCondition_present = Está presente
 +label.matchCondition_notpresent = No está presente
 +label.matchCondition_eq = =
 +label.matchCondition_ne = not =
 +label.matchCondition_lt = <
 +label.matchCondition_le = <=
 +label.matchCondition_gt = >
 +label.matchCondition_ge = >=
 +label.numeric_required = Valor numérico requerido
 +label.filter = Filtro
 +label.filters = Filtros
 +label.join_conditions = Combinar condiciones con
 +label.score = Puntuación
 +label.colour_by_label = Colorear por texto
 +label.variable_colour = Color variable
 +label.select_colour = Seleccionar color
- option.enable_disable_autosearch = Marque para buscar automáticamente
- option.autosearch = Búsqueda automática
+ option.enable_disable_autosearch = Marcar para buscar automáticamente
+ option.autosearch = Auto búsqueda
  label.retrieve_ids = Recuperar IDs
 +label.display_settings_for = Visualización de características {0}
 +label.simple = Simple
 +label.simple_colour = Color simple
 +label.colour_by_text = Colorear por texto
 +label.graduated_colour = Color graduado
 +label.by_text_of = Por texto de
 +label.by_range_of = Por rango de
 +label.filters_tooltip = Haga clic para configurar o modificar los filtros
 +label.or = O
- label.and = Y
++label.and = Y
++label.sequence_feature_colours = Colores de características de las secuencias
+ label.best_quality = Mejor Calidad
+ label.best_resolution = Mejor Resolución
+ label.most_protein_chain = Más Cadena de Proteína
+ label.most_bound_molecules = Más Moléculas Ligadas
+ label.most_polymer_residues = Más Residuos de Polímeros
+ label.cached_structures = Estructuras en Caché
+ label.free_text_search = Búsqueda de texto libre
@@@ -146,10 -150,10 +152,14 @@@ public class EnsemblGene extends Ensemb
        {
          continue;
        }
 +      
        if (geneAlignment.getHeight() == 1)
        {
+         // ensure id has 'correct' case for the Ensembl identifier
+         geneId = geneAlignment.getSequenceAt(0).getName();
++
 +        findGeneLoci(geneAlignment.getSequenceAt(0), geneId);
++
          getTranscripts(geneAlignment, geneId);
        }
        if (al == null)
@@@ -39,22 -34,13 +39,16 @@@ import org.json.simple.parser.JSONParse
  import org.json.simple.parser.ParseException;
  
  /**
-  * A client for the Ensembl lookup REST endpoint
 - * A client for the Ensembl lookup REST endpoint, used to find the gene
 - * identifier given a gene, transcript or protein identifier.
++ * A client for the Ensembl /lookup REST endpoint, used to find the gene
++ * identifier given a gene, transcript or protein identifier, or to extract the
++ * species or chromosomal coordinates from the same service response
   * 
   * @author gmcarstairs
   */
  public class EnsemblLookup extends EnsemblRestClient
  {
 +  private static final String SPECIES = "species";
 +
-   private static final String PARENT = "Parent";
-   private static final String OBJECT_TYPE_TRANSLATION = "Translation";
-   private static final String OBJECT_TYPE_TRANSCRIPT = "Transcript";
-   private static final String ID = "id";
-   private static final String OBJECT_TYPE_GENE = "Gene";
-   private static final String OBJECT_TYPE = "object_type";
    /**
     * Default constructor (to use rest.ensembl.org)
     */
    }
  
    /**
-    * Calls the Ensembl lookup REST endpoint and returns
-    * <ul>
-    * <li>the 'id' for the identifier if its type is "Gene"</li>
-    * <li>the 'Parent' if its type is 'Transcript'</li>
-    * <ul>
-    * If the type is 'Translation', does a recursive call to this method, passing
-    * in the 'Parent' (transcript id).
 -   * Returns the gene id related to the given identifier, which may be for a
 -   * gene, transcript or protein
++   * Returns the gene id related to the given identifier (which may be for a
++   * gene, transcript or protein)
     * 
     * @param identifier
     * @return
     */
    public String getGeneId(String identifier)
    {
-     return (String) getResult(identifier, br -> parseGeneId(br));
 -    return getGeneId(identifier, null);
++    return (String) getResult(identifier, null, br -> parseGeneId(br));
    }
  
    /**
     * given identifier, or null if not found
     * 
     * @param identifier
 +   * @return
 +   */
 +  public String getSpecies(String identifier)
 +  {
-     return (String) getResult(identifier, br -> getAttribute(br, SPECIES));
++    return (String) getResult(identifier, null,
++            br -> getAttribute(br, SPECIES));
 +  }
 +
 +  /**
 +   * Calls the /lookup/id rest service and delegates parsing of the JSON
 +   * response to the supplied parser
 +   * 
 +   * @param identifier
+    * @param objectType
+    *          (optional)
 +   * @param parser
     * @return
     */
-   protected Object getResult(String identifier,
 -  public String getGeneId(String identifier, String objectType)
++  protected Object getResult(String identifier, String objectType,
 +          Function<BufferedReader, Object> parser)
    {
      List<String> ids = Arrays.asList(new String[] { identifier });
  
     * Parses the JSON response and returns the gene identifier, or null if not
     * found. If the returned object_type is Gene, returns the id, if Transcript
     * returns the Parent. If it is Translation (peptide identifier), then the
--   * Parent is the transcript identifier, so we redo the search with this value.
++   * Parent is the transcript identifier, so we redo the search with this value,
++   * specifying that object_type should be Transcript.
     * 
     * @param br
     * @return
        String type = val.get(OBJECT_TYPE).toString();
        if (OBJECT_TYPE_GENE.equalsIgnoreCase(type))
        {
-         geneId = val.get(ID).toString();
+         // got the gene - just returns its id
 -        geneId = val.get(ID).toString();
++        geneId = val.get(JSON_ID).toString();
        }
        else if (OBJECT_TYPE_TRANSCRIPT.equalsIgnoreCase(type))
        {
        }
        else if (OBJECT_TYPE_TRANSLATION.equalsIgnoreCase(type))
        {
+         // got the protein - get its Parent, restricted to type Transcript
          String transcriptId = val.get(PARENT).toString();
-         try
-         {
-           geneId = getGeneId(transcriptId);
-         } catch (StackOverflowError e)
-         {
-           /*
-            * unlikely data condition error!
-            */
-           System.err
-                   .println("** Ensembl lookup "
-                           + getUrl(transcriptId).toString()
-                           + " looping on Parent!");
-         }
 -        geneId = getGeneId(transcriptId, OBJECT_TYPE_TRANSCRIPT);
++        geneId = (String) getResult(transcriptId, OBJECT_TYPE_TRANSCRIPT,
++                reader -> parseGeneId(reader));
        }
 -    } catch (ParseException e)
 +    } catch (ParseException | IOException e)
      {
        // ignore
      }
      return geneId;
    }
  
 +  /**
 +   * Calls the /lookup/id rest service for the given id, and if successful,
 +   * parses and returns the gene's chromosomal coordinates
 +   * 
 +   * @param geneId
 +   * @return
 +   */
 +  public GeneLociI getGeneLoci(String geneId)
 +  {
-     return (GeneLociI) getResult(geneId, br -> parseGeneLoci(br));
++    return (GeneLociI) getResult(geneId, OBJECT_TYPE_GENE,
++            br -> parseGeneLoci(br));
 +  }
 +
 +  /**
 +   * Parses the /lookup/id response for species, asssembly_name,
 +   * seq_region_name, start, end and returns an object that wraps them, or null
 +   * if unsuccessful
 +   * 
 +   * @param br
 +   * @return
 +   */
 +  GeneLociI parseGeneLoci(BufferedReader br)
 +  {
 +    JSONParser jp = new JSONParser();
 +    try
 +    {
 +      JSONObject val = (JSONObject) jp.parse(br);
 +      final String species = val.get("species").toString();
 +      final String assembly = val.get("assembly_name").toString();
 +      final String chromosome = val.get("seq_region_name").toString();
 +      String strand = val.get("strand").toString();
 +      int start = Integer.parseInt(val.get("start").toString());
 +      int end = Integer.parseInt(val.get("end").toString());
 +      int fromEnd = end - start + 1;
 +      boolean reverseStrand = "-1".equals(strand);
 +      int toStart = reverseStrand ? end : start;
 +      int toEnd = reverseStrand ? start : end;
 +      List<int[]> fromRange = Collections.singletonList(new int[] { 1,
 +          fromEnd });
 +      List<int[]> toRange = Collections.singletonList(new int[] { toStart,
 +          toEnd });
 +      final MapList map = new MapList(fromRange, toRange, 1, 1);
 +      return new GeneLociI()
 +      {
 +
 +        @Override
 +        public String getSpeciesId()
 +        {
 +          return species == null ? "" : species;
 +        }
 +
 +        @Override
 +        public String getAssemblyId()
 +        {
 +          return assembly;
 +        }
 +
 +        @Override
 +        public String getChromosomeId()
 +        {
 +          return chromosome;
 +        }
 +
 +        @Override
 +        public MapList getMap()
 +        {
 +          return map;
 +        }
 +      };
 +    } catch (ParseException | NullPointerException | IOException
 +            | NumberFormatException | ClassCastException e)
 +    {
 +      Cache.log.error("Error looking up gene loci: " + e.getMessage());
++      e.printStackTrace();
 +    }
 +    return null;
 +  }
 +
  }
@@@ -60,10 -57,8 +58,6 @@@ import java.util.List
   */
  public abstract class EnsemblSeqProxy extends EnsemblRestClient
  {
-   protected static final String PARENT = "Parent";
-   protected static final String ID = "ID";
 -  private static final String ALLELES = "alleles";
 -
    protected static final String NAME = "Name";
  
    protected static final String DESCRIPTION = "description";
@@@ -45,6 -45,18 +45,18 @@@ abstract class EnsemblSequenceFetcher e
  
    protected static final String ENSEMBL_REST = "http://rest.ensembl.org";
  
+   protected static final String OBJECT_TYPE_TRANSLATION = "Translation";
+   protected static final String OBJECT_TYPE_TRANSCRIPT = "Transcript";
+   protected static final String OBJECT_TYPE_GENE = "Gene";
+   protected static final String PARENT = "Parent";
 -  protected static final String ID = "id";
++  protected static final String JSON_ID = "id";
+   protected static final String OBJECT_TYPE = "object_type";
    /*
     * possible values for the 'feature' parameter of the /overlap REST service
     * @see http://rest.ensembl.org/documentation/info/overlap_id
@@@ -77,7 -75,7 +75,7 @@@ public class EnsemblSymbol extends Ense
        while (rvals.hasNext())
        {
          JSONObject val = (JSONObject) rvals.next();
--        String id = val.get(ID).toString();
++        String id = val.get(JSON_ID).toString();
          String type = val.get(TYPE).toString();
          if (id != null && GENE.equals(type))
          {
@@@ -21,9 -21,9 +21,7 @@@
  package jalview.ext.ensembl;
  
  import static org.testng.AssertJUnit.assertEquals;
--import static org.testng.AssertJUnit.assertFalse;
  import static org.testng.AssertJUnit.assertSame;
--import static org.testng.AssertJUnit.assertTrue;
  
  import jalview.datamodel.Alignment;
  import jalview.datamodel.SequenceFeature;