JAL-2885 uniprot now https, uniprot/ensembl/pfam/xfam configurable
[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   private String lastId;
54
55   /**
56    * Default constructor (to use rest.ensembl.org)
57    */
58   public EnsemblLookup()
59   {
60     super();
61   }
62
63   /**
64    * Constructor given the target domain to fetch data from
65    * 
66    * @param
67    */
68   public EnsemblLookup(String d)
69   {
70     super(d);
71   }
72
73   @Override
74   public String getDbName()
75   {
76     return "ENSEMBL";
77   }
78
79   @Override
80   public AlignmentI getSequenceRecords(String queries) throws Exception
81   {
82     return null;
83   }
84
85   @Override
86   protected URL getUrl(List<String> ids) throws MalformedURLException
87   {
88     String identifier = ids.get(0);
89     return getUrl(identifier);
90   }
91
92   /**
93    * @param identifier
94    * @return
95    */
96   protected URL getUrl(String identifier)
97   {
98     String url = getDomain() + "/lookup/id/" + identifier
99             + CONTENT_TYPE_JSON;
100     try
101     {
102       return new URL(url);
103     } catch (MalformedURLException e)
104     {
105       return null;
106     }
107   }
108
109   @Override
110   protected boolean useGetRequest()
111   {
112     return true;
113   }
114
115   @Override
116   protected String getRequestMimeType(boolean multipleIds)
117   {
118     return "application/json";
119   }
120
121   @Override
122   protected String getResponseMimeType()
123   {
124     return "application/json";
125   }
126
127   /**
128    * Calls the Ensembl lookup REST endpoint and retrieves the 'Parent' for the
129    * given identifier, or null if not found
130    * 
131    * @param identifier
132    * @return
133    */
134   public String getGeneId(String identifier)
135   {
136     List<String> ids = Arrays.asList(new String[] { identifier });
137
138     BufferedReader br = null;
139     try
140     {
141       URL url = getUrl(identifier);
142       if (identifier.equals(lastId))
143       {
144         System.err.println("** Ensembl lookup " + url.toString()
145                 + " looping on Parent!");
146         return null;
147       }
148       lastId = identifier;
149       if (url != null)
150       {
151         br = getHttpResponse(url, ids);
152       }
153       return br == null ? null : parseResponse(br);
154     } catch (IOException e)
155     {
156       // ignore
157       return null;
158     } finally
159     {
160       if (br != null)
161       {
162         try
163         {
164           br.close();
165         } catch (IOException e)
166         {
167           // ignore
168         }
169       }
170     }
171   }
172
173   /**
174    * Parses the JSON response and returns the gene identifier, or null if not
175    * found. If the returned object_type is Gene, returns the id, if Transcript
176    * returns the Parent. If it is Translation (peptide identifier), then the
177    * Parent is the transcript identifier, so we redo the search with this value.
178    * 
179    * @param br
180    * @return
181    * @throws IOException
182    */
183   protected String parseResponse(BufferedReader br) throws IOException
184   {
185     String geneId = null;
186     JSONParser jp = new JSONParser();
187     try
188     {
189       JSONObject val = (JSONObject) jp.parse(br);
190       String type = val.get(OBJECT_TYPE).toString();
191       if (OBJECT_TYPE_GENE.equalsIgnoreCase(type))
192       {
193         geneId = val.get(ID).toString();
194       }
195       else if (OBJECT_TYPE_TRANSCRIPT.equalsIgnoreCase(type))
196       {
197         geneId = val.get(PARENT).toString();
198       }
199       else if (OBJECT_TYPE_TRANSLATION.equalsIgnoreCase(type))
200       {
201         String transcriptId = val.get(PARENT).toString();
202         try
203         {
204           geneId = getGeneId(transcriptId);
205         } catch (StackOverflowError e)
206         {
207           /*
208            * unlikely data condition error!
209            */
210           System.err
211                   .println("** Ensembl lookup "
212                           + getUrl(transcriptId).toString()
213                           + " looping on Parent!");
214         }
215       }
216     } catch (ParseException e)
217     {
218       // ignore
219     }
220     return geneId;
221   }
222
223 }