JAL-1062 - recognise and split off the range qualifier in a DAS sequence fetch query
[jalview.git] / src / jalview / ws / dbsources / das / datamodel / DasSequenceSource.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7)\r
3  * Copyright (C) 2011 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle\r
4  * \r
5  * This file is part of Jalview.\r
6  * \r
7  * Jalview is free software: you can redistribute it and/or\r
8  * modify it under the terms of the GNU General Public License \r
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.\r
10  * \r
11  * Jalview is distributed in the hope that it will be useful, but \r
12  * WITHOUT ANY WARRANTY; without even the implied warranty \r
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR \r
14  * PURPOSE.  See the GNU General Public License for more details.\r
15  * \r
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.\r
17  */\r
18 package jalview.ws.dbsources.das.datamodel;\r
19 \r
20 import java.util.ArrayList;\r
21 import java.util.HashMap;\r
22 import java.util.List;\r
23 import java.util.Map;\r
24 import java.util.StringTokenizer;\r
25 import java.util.Vector;\r
26 \r
27 import org.biodas.jdas.client.adapters.sequence.DasSequenceAdapter;\r
28 import org.biodas.jdas.client.threads.SequenceClientMultipleSources;\r
29 import org.biodas.jdas.schema.sequence.SEQUENCE;\r
30 import org.biodas.jdas.schema.sources.COORDINATES;\r
31 import org.biodas.jdas.schema.sources.SOURCE;\r
32 import org.biodas.jdas.schema.sources.VERSION;\r
33 \r
34 import com.stevesoft.pat.Regex;\r
35 \r
36 import jalview.ws.dbsources.das.api.jalviewSourceI;\r
37 import jalview.ws.seqfetcher.*;\r
38 import jalview.bin.Cache;\r
39 import jalview.datamodel.Alignment;\r
40 import jalview.datamodel.AlignmentI;\r
41 import jalview.datamodel.DBRefEntry;\r
42 import jalview.datamodel.Sequence;\r
43 import jalview.datamodel.SequenceI;\r
44 \r
45 /**\r
46  * an instance of this class is created for each unique DAS Sequence source (ie\r
47  * one capable of handling the 'sequence' for a particular MapMaster)\r
48  * \r
49  * @author JimP\r
50  * \r
51  */\r
52 public class DasSequenceSource extends DbSourceProxyImpl implements\r
53         DbSourceProxy\r
54 {\r
55   private jalviewSourceI jsrc;\r
56 \r
57   protected SOURCE source = null;\r
58 \r
59   protected VERSION version = null;\r
60 \r
61   protected COORDINATES coordsys = null;\r
62 \r
63   protected String dbname = "DASCS";\r
64 \r
65   protected String dbrefname = "das:source";\r
66 \r
67   /**\r
68    * create a new DbSource proxy for a DAS 1 source\r
69    * \r
70    * @param dbnbame\r
71    *          Human Readable Name to use when fetching from this source\r
72    * @param dbrefname\r
73    *          DbRefName for DbRefs attached to sequences retrieved from this\r
74    *          source\r
75    * @param source\r
76    *          Das1Source\r
77    * @param coordsys\r
78    *          specific coordinate system to use for this source\r
79    * @throws Exception\r
80    *           if source is not capable of the 'sequence' command\r
81    */\r
82   public DasSequenceSource(String dbname, String dbrefname, SOURCE source,\r
83           VERSION version, COORDINATES coordsys) throws Exception\r
84   {\r
85     if (!(jsrc = new JalviewSource(source, false)).isSequenceSource())\r
86     {\r
87       throw new Exception("Source " + source.getTitle()\r
88               + " does not support the sequence command.");\r
89     }\r
90     this.source = source;\r
91     this.dbname = dbname;\r
92     this.dbrefname = dbrefname;\r
93     this.coordsys = coordsys;\r
94   }\r
95 \r
96   public String getAccessionSeparator()\r
97   {\r
98     return "\t";\r
99   }\r
100 \r
101   public Regex getAccessionValidator()\r
102   {\r
103     /** ? * */\r
104     return Regex.perlCode("\\S+");\r
105   }\r
106 \r
107   public String getDbName()\r
108   {\r
109     // TODO: map to\r
110     return dbname + " (DAS)";\r
111   }\r
112 \r
113   public String getDbSource()\r
114   {\r
115     return dbrefname;\r
116   }\r
117 \r
118   public String getDbVersion()\r
119   {\r
120     return coordsys.getVersion();\r
121   }\r
122 \r
123 \r
124   public AlignmentI getSequenceRecords(String queries) throws Exception\r
125   {\r
126     StringTokenizer st = new StringTokenizer(queries, "\t");\r
127     List<String> toks = new ArrayList<String>(), src = new ArrayList<String>(),acIds=new ArrayList<String>();\r
128     while (st.hasMoreTokens())\r
129     {\r
130       String t;\r
131       toks.add(t=st.nextToken());\r
132       acIds.add(t.replaceAll(":[0-9,]+", ""));\r
133     }\r
134     src.add(jsrc.getSourceURL());\r
135     Map<String, Map<List<String>, DasSequenceAdapter>> resultset = new HashMap<String, Map<List<String>, DasSequenceAdapter>>();\r
136     Map<String, Map<List<String>, Exception>> errors = new HashMap<String, Map<List<String>, Exception>>();\r
137     SequenceClientMultipleSources sclient;\r
138     sclient = new SequenceClientMultipleSources();\r
139     sclient.fetchData(src, toks, resultset, errors);\r
140     sclient.shutDown();\r
141     while (!sclient.isTerminated())\r
142     {\r
143       try {Thread.sleep(200);\r
144       \r
145       } catch (InterruptedException x) {}\r
146     }\r
147             \r
148     if (resultset.isEmpty())\r
149     {\r
150       System.err.println("Sequence Query to " + jsrc.getTitle() + " with '"\r
151               + queries + "' returned no sequences.");\r
152       return null;\r
153     }\r
154     else\r
155     {\r
156       Vector<SequenceI> seqs=null;\r
157       for (Map.Entry<String, Map<List<String>, DasSequenceAdapter>> resset : resultset\r
158               .entrySet())\r
159       {\r
160         for (Map.Entry<List<String>, DasSequenceAdapter> result : resset\r
161                 .getValue().entrySet())\r
162         {\r
163           DasSequenceAdapter dasseqresp = result.getValue();\r
164           List<String> accessions = result.getKey();\r
165           for (SEQUENCE e : dasseqresp.getSequence())\r
166           {\r
167             String lbl = e.getId();\r
168 \r
169             if (acIds.indexOf(lbl) == -1)\r
170             {\r
171               System.err\r
172                       .println("Warning - received sequence event for strange accession code ("\r
173                               + lbl + ")");\r
174             }\r
175             else\r
176             {\r
177               if (seqs == null)\r
178               {\r
179                 if (e.getContent().length() == 0)\r
180                 {\r
181                   System.err\r
182                           .println("Empty sequence returned for accession code ("\r
183                                   + lbl\r
184                                   + ") from "\r
185                                   + resset.getKey()\r
186                                   + " (source is "\r
187                                   + getDbName());\r
188                   continue;\r
189                 }\r
190               }\r
191               seqs = new java.util.Vector<SequenceI>();\r
192               // JDAS returns a sequence complete with any newlines and spaces in the XML\r
193               Sequence sq = new Sequence(lbl, e.getContent().replaceAll("\\s+", ""));\r
194               sq.addDBRef(new DBRefEntry(getDbSource(), getDbVersion()\r
195                       + ":" + e.getVersion(), lbl));\r
196               seqs.addElement(sq);\r
197             }\r
198           }\r
199         }\r
200       }\r
201 \r
202       if (seqs == null || seqs.size() == 0)\r
203         return null;\r
204       SequenceI[] sqs = new SequenceI[seqs.size()];\r
205       for (int i = 0, iSize = seqs.size(); i < iSize; i++)\r
206       {\r
207         sqs[i] = (SequenceI) seqs.elementAt(i);\r
208       }\r
209       Alignment al = new Alignment(sqs);\r
210       if (jsrc.isFeatureSource())\r
211       {\r
212         java.util.Vector<jalviewSourceI> srcs = new java.util.Vector<jalviewSourceI>();\r
213         srcs.addElement(jsrc);\r
214         try {\r
215           new jalview.ws.DasSequenceFeatureFetcher(sqs, null, srcs, false,\r
216                 false);\r
217         } catch (Exception x)\r
218         {\r
219           Cache.log.error("Couldn't retrieve features for sequence from its source.",x);\r
220         }\r
221       }\r
222 \r
223       return al;\r
224     }\r
225   }\r
226 \r
227   public String getTestQuery()\r
228   {\r
229     return coordsys.getTestRange();\r
230   }\r
231 \r
232   public boolean isValidReference(String accession)\r
233   {\r
234     // TODO try to validate an accession against source\r
235     // We don't really know how to do this without querying source\r
236 \r
237     return true;\r
238   }\r
239 \r
240   /**\r
241    * @return the source\r
242    */\r
243   public SOURCE getSource()\r
244   {\r
245     return source;\r
246   }\r
247 \r
248   /**\r
249    * @return the coordsys\r
250    */\r
251   public COORDINATES getCoordsys()\r
252   {\r
253     return coordsys;\r
254   }\r
255 }\r