JAL-1807 explicit imports (jalview.ws.*)
[jalview.git] / src / jalview / ws / dbsources / das / datamodel / DasSequenceSource.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.ws.dbsources.das.datamodel;
22
23 import jalview.bin.Cache;
24 import jalview.datamodel.Alignment;
25 import jalview.datamodel.AlignmentI;
26 import jalview.datamodel.DBRefEntry;
27 import jalview.datamodel.Sequence;
28 import jalview.datamodel.SequenceI;
29 import jalview.util.MessageManager;
30 import jalview.ws.DasSequenceFeatureFetcher;
31 import jalview.ws.dbsources.das.api.jalviewSourceI;
32 import jalview.ws.seqfetcher.DbSourceProxy;
33 import jalview.ws.seqfetcher.DbSourceProxyImpl;
34
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40 import java.util.StringTokenizer;
41 import java.util.Vector;
42
43 import org.biodas.jdas.client.SequenceClient;
44 import org.biodas.jdas.client.adapters.sequence.DasSequenceAdapter;
45 import org.biodas.jdas.client.threads.MultipleConnectionPropertyProviderI;
46 import org.biodas.jdas.client.threads.SequenceClientMultipleSources;
47 import org.biodas.jdas.schema.sequence.SEQUENCE;
48 import org.biodas.jdas.schema.sources.COORDINATES;
49 import org.biodas.jdas.schema.sources.SOURCE;
50 import org.biodas.jdas.schema.sources.VERSION;
51
52 import com.stevesoft.pat.Regex;
53
54 /**
55  * an instance of this class is created for each unique DAS Sequence source (ie
56  * one capable of handling the 'sequence' for a particular MapMaster)
57  * 
58  * @author JimP
59  * 
60  */
61 public class DasSequenceSource extends DbSourceProxyImpl implements
62         DbSourceProxy
63 {
64   private jalviewSourceI jsrc;
65
66   protected SOURCE source = null;
67
68   protected VERSION version = null;
69
70   protected COORDINATES coordsys = null;
71
72   protected String dbname = "DASCS";
73
74   protected String dbrefname = "das:source";
75
76   protected MultipleConnectionPropertyProviderI connprops = null;
77
78   /**
79    * DAS sources are tier 1 - if we have a direct DB connection then we should
80    * prefer it
81    */
82   private int tier = 1;
83
84   /**
85    * create a new DbSource proxy for a DAS 1 source
86    * 
87    * @param dbnbame
88    *          Human Readable Name to use when fetching from this source
89    * @param dbrefname
90    *          DbRefName for DbRefs attached to sequences retrieved from this
91    *          source
92    * @param source
93    *          Das1Source
94    * @param coordsys
95    *          specific coordinate system to use for this source
96    * @throws Exception
97    *           if source is not capable of the 'sequence' command
98    */
99   public DasSequenceSource(String dbname, String dbrefname, SOURCE source,
100           VERSION version, COORDINATES coordsys,
101           MultipleConnectionPropertyProviderI connprops) throws Exception
102   {
103     if (!(jsrc = new JalviewSource(source, connprops, false))
104             .isSequenceSource())
105     {
106       throw new Exception(MessageManager.formatMessage("exception.das_source_doesnt_support_sequence_command", new String[]{source.getTitle()}));
107     }
108     this.tier = 1 + ((jsrc.isLocal() || jsrc.isReferenceSource()) ? 0 : 1);
109     this.source = source;
110     this.dbname = dbname;
111     this.dbrefname = dbrefname.toUpperCase();
112     if (coordsys != null)
113     {
114       this.coordsys = coordsys;
115     }
116     this.connprops = connprops;
117   }
118
119   public String getAccessionSeparator()
120   {
121     return "\t";
122   }
123
124   public Regex getAccessionValidator()
125   {
126     /** ? * */
127     return Regex.perlCode("m/([^:]+)(:\\d+,\\d+)?/");
128   }
129
130   public String getDbName()
131   {
132     // TODO: map to
133     return dbname + " (DAS)";
134   }
135
136   public String getDbSource()
137   {
138     return dbrefname;
139   }
140
141   public String getDbVersion()
142   {
143     return coordsys != null ? coordsys.getVersion() : "";
144   }
145
146   public AlignmentI getSequenceRecords(String queries) throws Exception
147   {
148     StringTokenizer st = new StringTokenizer(queries, "\t");
149     List<String> toks = new ArrayList<String>(), src = new ArrayList<String>(), acIds = new ArrayList<String>();
150     while (st.hasMoreTokens())
151     {
152       String t;
153       toks.add(t = st.nextToken());
154       acIds.add(t.replaceAll(":[0-9,]+", ""));
155     }
156     src.add(jsrc.getSourceURL());
157     Map<String, Map<List<String>, DasSequenceAdapter>> resultset = new HashMap<String, Map<List<String>, DasSequenceAdapter>>();
158     Map<String, Map<List<String>, Exception>> errors = new HashMap<String, Map<List<String>, Exception>>();
159
160     // First try multiple sources
161     boolean multiple = true, retry = false;
162     do
163     {
164       if (!multiple)
165       {
166         retry = false;
167         // slow, fetch one at a time.
168         for (String sr : src)
169         {
170           System.err
171                   .println("Retrieving IDs individually from das source: "
172                           + sr);
173           org.biodas.jdas.client.SequenceClient sq = new SequenceClient(
174                   connprops.getConnectionPropertyProviderFor(sr));
175           for (String q : toks)
176           {
177             List<String> qset = Arrays.asList(new String[]
178             { q });
179             try
180             {
181               DasSequenceAdapter s = sq.fetchData(sr, qset);
182               Map<List<String>, DasSequenceAdapter> dss = resultset.get(sr);
183               if (dss == null)
184               {
185                 resultset
186                         .put(sr,
187                                 dss = new HashMap<List<String>, DasSequenceAdapter>());
188               }
189               dss.put(qset, s);
190             } catch (Exception x)
191             {
192               Map<List<String>, Exception> ers = errors.get(sr);
193               if (ers == null)
194               {
195                 errors.put(sr, ers = new HashMap<List<String>, Exception>());
196               }
197               ers.put(qset, x);
198             }
199           }
200         }
201       }
202       else
203       {
204         SequenceClientMultipleSources sclient;
205         sclient = new SequenceClientMultipleSources();
206         sclient.fetchData(src, toks, resultset, errors);
207         sclient.shutDown();
208         while (!sclient.isTerminated())
209         {
210           try
211           {
212             Thread.sleep(200);
213
214           } catch (InterruptedException x)
215           {
216           }
217         }
218         if (resultset.isEmpty() && !errors.isEmpty())
219         {
220           retry = true;
221           multiple = false;
222         }
223       }
224     } while (retry);
225
226     if (resultset.isEmpty())
227     {
228       System.err.println("Sequence Query to " + jsrc.getTitle() + " with '"
229               + queries + "' returned no sequences.");
230       return null;
231     }
232     else
233     {
234       Vector<SequenceI> seqs = null;
235       for (Map.Entry<String, Map<List<String>, DasSequenceAdapter>> resset : resultset
236               .entrySet())
237       {
238         for (Map.Entry<List<String>, DasSequenceAdapter> result : resset
239                 .getValue().entrySet())
240         {
241           DasSequenceAdapter dasseqresp = result.getValue();
242           List<String> accessions = result.getKey();
243           for (SEQUENCE e : dasseqresp.getSequence())
244           {
245             String lbl = e.getId();
246
247             if (acIds.indexOf(lbl) == -1)
248             {
249               System.err
250                       .println("Warning - received sequence event for strange accession code ("
251                               + lbl + ")");
252             }
253             else
254             {
255               if (seqs == null)
256               {
257                 if (e.getContent().length() == 0)
258                 {
259                   System.err
260                           .println("Empty sequence returned for accession code ("
261                                   + lbl
262                                   + ") from "
263                                   + resset.getKey()
264                                   + " (source is " + getDbName());
265                   continue;
266                 }
267               }
268               seqs = new java.util.Vector<SequenceI>();
269               // JDAS returns a sequence complete with any newlines and spaces
270               // in the XML
271               Sequence sq = new Sequence(lbl, e.getContent().replaceAll(
272                       "\\s+", ""));
273               sq.setStart(e.getStart().intValue());
274               sq.addDBRef(new DBRefEntry(getDbSource(), getDbVersion()
275                       + ":" + e.getVersion(), lbl));
276               seqs.addElement(sq);
277             }
278           }
279         }
280       }
281
282       if (seqs == null || seqs.size() == 0)
283       {
284         return null;
285       }
286       SequenceI[] sqs = new SequenceI[seqs.size()];
287       for (int i = 0, iSize = seqs.size(); i < iSize; i++)
288       {
289         sqs[i] = seqs.elementAt(i);
290       }
291       Alignment al = new Alignment(sqs);
292       if (jsrc.isFeatureSource())
293       {
294         java.util.Vector<jalviewSourceI> srcs = new java.util.Vector<jalviewSourceI>();
295         srcs.addElement(jsrc);
296         try
297         {
298           DasSequenceFeatureFetcher dssf = new DasSequenceFeatureFetcher(
299                   sqs, null, srcs, false, false, multiple);
300           while (dssf.isRunning())
301           {
302             try
303             {
304               Thread.sleep(200);
305             } catch (InterruptedException x)
306             {
307
308             }
309           }
310
311         } catch (Exception x)
312         {
313           Cache.log
314                   .error("Couldn't retrieve features for sequence from its source.",
315                           x);
316         }
317       }
318
319       return al;
320     }
321   }
322
323   public String getTestQuery()
324   {
325     return coordsys == null ? "" : coordsys.getTestRange();
326   }
327
328   public boolean isValidReference(String accession)
329   {
330     // TODO try to validate an accession against source
331     // We don't really know how to do this without querying source
332
333     return true;
334   }
335
336   /**
337    * @return the source
338    */
339   public SOURCE getSource()
340   {
341     return source;
342   }
343
344   /**
345    * @return the coordsys
346    */
347   public COORDINATES getCoordsys()
348   {
349     return coordsys;
350   }
351
352   @Override
353   public int getTier()
354   {
355     return tier;
356   }
357 }