JAL-2738 correct handling of reverse strand genes
[jalview.git] / src / jalview / ext / ensembl / EnsemblMap.java
1 package jalview.ext.ensembl;
2
3 import jalview.datamodel.AlignmentI;
4 import jalview.datamodel.DBRefSource;
5
6 import java.io.BufferedReader;
7 import java.io.IOException;
8 import java.net.MalformedURLException;
9 import java.net.URL;
10 import java.util.Iterator;
11 import java.util.List;
12
13 import org.json.simple.JSONArray;
14 import org.json.simple.JSONObject;
15 import org.json.simple.parser.JSONParser;
16 import org.json.simple.parser.ParseException;
17
18 public class EnsemblMap extends EnsemblRestClient
19 {
20
21   /**
22    * Default constructor (to use rest.ensembl.org)
23    */
24   public EnsemblMap()
25   {
26     super();
27   }
28
29   /**
30    * Constructor given the target domain to fetch data from
31    * 
32    * @param
33    */
34   public EnsemblMap(String domain)
35   {
36     super(domain);
37   }
38
39   @Override
40   public String getDbName()
41   {
42     return DBRefSource.ENSEMBL;
43   }
44
45   @Override
46   public AlignmentI getSequenceRecords(String queries) throws Exception
47   {
48     return null; // not used
49   }
50
51   /**
52    * Constructs a URL of the format <code>
53    * http://rest.ensembl.org/map/human/GRCh38/17:45051610..45109016:1/GRCh37?content-type=application/json
54    * </code>
55    * 
56    * @param species
57    * @param chromosome
58    * @param fromRef
59    * @param toRef
60    * @param startPos
61    * @param endPos
62    * @return
63    * @throws MalformedURLException
64    */
65   protected URL getUrl(String species, String chromosome, String fromRef,
66           String toRef, int startPos, int endPos)
67           throws MalformedURLException
68   {
69     /*
70      * start-end might be reverse strand - present forwards to the service
71      */
72     boolean forward = startPos <= endPos;
73     int start = forward ? startPos : endPos;
74     int end = forward ? endPos : startPos;
75     String strand = forward ? "1" : "-1";
76     String url = String.format(
77             "%s/map/%s/%s/%s:%d..%d:%s/%s?content-type=application/json",
78             getDomain(), species, fromRef, chromosome, start, end, strand,
79             toRef);
80     try
81     {
82       return new URL(url);
83     } catch (MalformedURLException e)
84     {
85       return null;
86     }
87   }
88
89   @Override
90   protected boolean useGetRequest()
91   {
92     return true;
93   }
94
95   @Override
96   protected String getRequestMimeType(boolean multipleIds)
97   {
98     return "application/json";
99   }
100
101   @Override
102   protected String getResponseMimeType()
103   {
104     return "application/json";
105   }
106
107   @Override
108   protected URL getUrl(List<String> ids) throws MalformedURLException
109   {
110     return null; // not used
111   }
112
113   public int[] getMapping(String species, String chromosome,
114           String fromRef, String toRef, int[] queryRange)
115   {
116     URL url = null;
117     BufferedReader br = null;
118
119     try
120     {
121       url = getUrl(species, chromosome, fromRef, toRef, queryRange[0],
122               queryRange[1]);
123       // System.out.println("Calling " + url);
124       br = getHttpResponse(url, null);
125       return (parseResponse(br));
126     } catch (Throwable t)
127     {
128       System.out.println("Error calling " + url + ": " + t.getMessage());
129       return null;
130     }
131   }
132
133   /**
134    * Parses the JSON response from the /map REST service. The format is (with
135    * some fields omitted)
136    * 
137    * <pre>
138    *  {"mappings": 
139    *    [{
140    *       "original": {"end":45109016,"start":45051610},
141    *       "mapped"  : {"end":43186384,"start":43128978} 
142    *  }] }
143    * </pre>
144    * 
145    * @param br
146    * @return
147    */
148   protected int[] parseResponse(BufferedReader br)
149   {
150     int[] result = null;
151     JSONParser jp = new JSONParser();
152
153     try
154     {
155       JSONObject parsed = (JSONObject) jp.parse(br);
156       JSONArray mappings = (JSONArray) parsed.get("mappings");
157
158       Iterator rvals = mappings.iterator();
159       while (rvals.hasNext())
160       {
161         // todo check for "mapped"
162         JSONObject val = (JSONObject) rvals.next();
163         JSONObject mapped = (JSONObject) val.get("mapped");
164         int start = Integer.parseInt(mapped.get("start").toString());
165         int end = Integer.parseInt(mapped.get("end").toString());
166         String strand = mapped.get("strand").toString();
167         if ("1".equals(strand))
168         {
169           result = new int[] { start, end };
170         }
171         else
172         {
173           result = new int[] { end, start };
174         }
175       }
176     } catch (IOException | ParseException | NumberFormatException e)
177     {
178       // ignore
179     }
180     return result;
181   }
182
183 }