31da9c005bbcc0b5cf151ba30b39d142098a49b5
[jalview.git] / src / jalview / ext / ensembl / EnsemblLookup.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.ext.ensembl;
22
23 import jalview.datamodel.AlignmentI;
24
25 import java.io.BufferedReader;
26 import java.io.IOException;
27 import java.net.MalformedURLException;
28 import java.net.URL;
29 import java.util.Arrays;
30 import java.util.List;
31
32 import org.json.simple.JSONObject;
33 import org.json.simple.parser.JSONParser;
34 import org.json.simple.parser.ParseException;
35
36 /**
37  * A client for the Ensembl lookup REST endpoint; used to find the Parent gene
38  * identifier given a transcript identifier.
39  * 
40  * @author gmcarstairs
41  *
42  */
43 public class EnsemblLookup extends EnsemblRestClient
44 {
45
46   private static final String OBJECT_TYPE_TRANSLATION = "Translation";
47   private static final String PARENT = "Parent";
48   private static final String OBJECT_TYPE_TRANSCRIPT = "Transcript";
49   private static final String ID = "id";
50   private static final String OBJECT_TYPE_GENE = "Gene";
51   private static final String OBJECT_TYPE = "object_type";
52
53   /**
54    * Default constructor (to use rest.ensembl.org)
55    */
56   public EnsemblLookup()
57   {
58     super();
59   }
60
61   /**
62    * Constructor given the target domain to fetch data from
63    * 
64    * @param
65    */
66   public EnsemblLookup(String d)
67   {
68     super(d);
69   }
70
71   @Override
72   public String getDbName()
73   {
74     return "ENSEMBL";
75   }
76
77   @Override
78   public AlignmentI getSequenceRecords(String queries) throws Exception
79   {
80     return null;
81   }
82
83   @Override
84   protected URL getUrl(List<String> ids) throws MalformedURLException
85   {
86     String identifier = ids.get(0);
87     return getUrl(identifier);
88   }
89
90   /**
91    * @param identifier
92    * @return
93    */
94   protected URL getUrl(String identifier)
95   {
96     String url = getDomain() + "/lookup/id/" + identifier
97             + CONTENT_TYPE_JSON;
98     try
99     {
100       return new URL(url);
101     } catch (MalformedURLException e)
102     {
103       return null;
104     }
105   }
106
107   @Override
108   protected boolean useGetRequest()
109   {
110     return true;
111   }
112
113   @Override
114   protected String getRequestMimeType(boolean multipleIds)
115   {
116     return "application/json";
117   }
118
119   @Override
120   protected String getResponseMimeType()
121   {
122     return "application/json";
123   }
124
125   /**
126    * Calls the Ensembl lookup REST endpoint and retrieves the 'Parent' for the
127    * given identifier, or null if not found
128    * 
129    * @param identifier
130    * @return
131    */
132   public String getGeneId(String identifier)
133   {
134     List<String> ids = Arrays.asList(new String[] { identifier });
135
136     BufferedReader br = null;
137     try
138     {
139       URL url = getUrl(identifier);
140       if (url != null)
141       {
142         br = getHttpResponse(url, ids);
143       }
144       return br == null ? null : parseResponse(br);
145     } catch (IOException e)
146     {
147       // ignore
148       return null;
149     } finally
150     {
151       if (br != null)
152       {
153         try
154         {
155           br.close();
156         } catch (IOException e)
157         {
158           // ignore
159         }
160       }
161     }
162   }
163
164   /**
165    * Parses the JSON response and returns the gene identifier, or null if not
166    * found. If the returned object_type is Gene, returns the id, if Transcript
167    * returns the Parent. If it is Translation (peptide identifier), then the
168    * Parent is the transcript identifier, so we redo the search with this value.
169    * 
170    * @param br
171    * @return
172    * @throws IOException
173    */
174   protected String parseResponse(BufferedReader br) throws IOException
175   {
176     String geneId = null;
177     JSONParser jp = new JSONParser();
178     try
179     {
180       JSONObject val = (JSONObject) jp.parse(br);
181       String type = val.get(OBJECT_TYPE).toString();
182       if (OBJECT_TYPE_GENE.equalsIgnoreCase(type))
183       {
184         geneId = val.get(ID).toString();
185       }
186       else if (OBJECT_TYPE_TRANSCRIPT.equalsIgnoreCase(type))
187       {
188         geneId = val.get(PARENT).toString();
189       }
190       else if (OBJECT_TYPE_TRANSLATION.equalsIgnoreCase(type))
191       {
192         String transcriptId = val.get(PARENT).toString();
193         try
194         {
195           geneId = getGeneId(transcriptId);
196         } catch (StackOverflowError e)
197         {
198           /*
199            * unlikely data condition error!
200            */
201           System.err
202                   .println("** Ensembl lookup "
203                           + getUrl(transcriptId).toString()
204                           + " looping on Parent!");
205         }
206       }
207     } catch (ParseException e)
208     {
209       // ignore
210     }
211     return geneId;
212   }
213
214 }