C&P changes
[jalview.git] / src / jalview / io / SequenceFeatureFetcher.java
1 package jalview.io;\r
2 \r
3 import java.io.*;\r
4 import java.util.*;\r
5 import javax.swing.*;\r
6 import jalview.io.*;\r
7 import jalview.gui.*;\r
8 import jalview.datamodel.*;\r
9 \r
10 public class SequenceFeatureFetcher implements Runnable\r
11 {\r
12   AlignmentI align;\r
13   AlignmentPanel ap;\r
14   ArrayList unknownSequences;\r
15   CutAndPasteTransfer output = new CutAndPasteTransfer();\r
16   StringBuffer sbuffer = new StringBuffer();\r
17 \r
18   public SequenceFeatureFetcher(AlignmentI align, AlignmentPanel ap)\r
19   {\r
20     unknownSequences = new ArrayList();\r
21     this.align = align;\r
22     this.ap = ap;\r
23     Thread thread = new Thread(this);\r
24     thread.start();\r
25   }\r
26 \r
27   public void run()\r
28 {\r
29 \r
30   String cache = jalview.bin.Cache.getProperty("UNIPROT_CACHE");\r
31 \r
32   RandomAccessFile out = null;\r
33 \r
34   try{\r
35     if (cache == null)\r
36     {\r
37       jalview.bin.Cache.setProperty("UNIPROT_CACHE", System.getProperty("user.home")+"/uniprot.xml");\r
38       cache = jalview.bin.Cache.getProperty("UNIPROT_CACHE");\r
39     }\r
40 \r
41 \r
42 \r
43     File test = new File(cache);\r
44     if( !test.exists() )\r
45     {\r
46       out = new RandomAccessFile(cache, "rw");\r
47       out.writeBytes("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");\r
48       out.writeBytes("<UNIPROT_CACHE>\n");\r
49     }\r
50     else\r
51     {\r
52       out = new RandomAccessFile(cache, "rw");\r
53       // open exisiting cache and remove </UNIPROT_CACHE> from the end\r
54       long lastLine = 0;\r
55       String data;\r
56       while ( (data = out.readLine()) != null)\r
57       {\r
58         if (data.indexOf("</entry>") > -1)\r
59           lastLine = out.getFilePointer();\r
60 \r
61       }\r
62       out.seek(lastLine);\r
63     }\r
64 \r
65     int seqIndex = 0;\r
66     Vector sequences = align.getSequences();\r
67 \r
68     while (seqIndex < sequences.size())\r
69     {\r
70       ArrayList ids = new ArrayList();\r
71       for (int i = 0; seqIndex < sequences.size() && i < 50; seqIndex++, i++)\r
72       {\r
73         SequenceI sequence = (SequenceI) sequences.get(seqIndex);\r
74         ids.add(sequence.getName());\r
75       }\r
76 \r
77       tryLocalCacheFirst(ids, align);\r
78 \r
79       if (ids.size() > 0)\r
80       {\r
81         StringBuffer remainingIds = new StringBuffer("uniprot:");\r
82         for (int i = 0; i < ids.size(); i++)\r
83           remainingIds.append(ids.get(i) + ";");\r
84 \r
85          EBIFetchClient ebi = new EBIFetchClient();\r
86          String[] result = ebi.fetchData(remainingIds.toString(), "xml", null);\r
87 \r
88         if(result!=null)\r
89           ReadUniprotFile(result, out, align);\r
90       }\r
91 \r
92     }\r
93 \r
94     if (out != null)\r
95     {\r
96       out.writeBytes("</UNIPROT_CACHE>\n");\r
97       out.close();\r
98     }\r
99   }catch(Exception ex){ex.printStackTrace();}\r
100 \r
101   ap.repaint();\r
102   findMissingIds(align);\r
103   if(sbuffer.length()>0)\r
104   {\r
105     output.setText("Your sequences have been matched to Uniprot. Some of the ids have been\n"\r
106                    +"altered, most likely the start/end residue will have been updated.\n"\r
107                    +"Save your alignment to maintain the updated id.\n\n"+sbuffer.toString());\r
108     Desktop.addInternalFrame(output, "Sequence names updated ", 600,300);\r
109 \r
110   }\r
111 \r
112   if(unknownSequences.size()>0)\r
113   {\r
114     //ignore for now!!!!!!!!!!\r
115   //  WSWUBlastClient blastClient = new WSWUBlastClient(align, unknownSequences);\r
116   }\r
117 \r
118 }\r
119 \r
120 void ReadUniprotFile(String [] result, RandomAccessFile out, AlignmentI align)\r
121 {\r
122   SequenceI sequence = null;\r
123   Vector features = null;\r
124   String type, description, status, start, end, pdb = null;\r
125 \r
126 \r
127   for (int r = 0; r < result.length; r++)\r
128   {\r
129     if(sequence==null && result[r].indexOf("<name>")>-1)\r
130     {\r
131       long filePointer = 0;\r
132 \r
133       if(out!=null)\r
134       try{\r
135         filePointer=out.getFilePointer();\r
136         out.writeBytes("<entry>\n");\r
137       }catch(Exception ex){}\r
138 \r
139       String seqName = parseElement( result[r], "<name>" , out);\r
140       sequence = align.findName( seqName ) ;\r
141       if(sequence==null)\r
142       {\r
143         sequence = align.findName( seqName.substring(0, seqName.indexOf('_')));\r
144         if(sequence!=null)\r
145         {\r
146           sbuffer.append("changing "+sequence.getName()+" to "+seqName+"\n");\r
147           sequence.setName(seqName);\r
148         }\r
149       }\r
150       if(sequence==null)\r
151       {\r
152         sbuffer.append("UNIPROT updated suggestion is "+result[r]+"\n");\r
153         sequence = align.findName( result[r] ) ;\r
154 \r
155         // this entry has been suggested by ebi.\r
156         // doesn't match id in alignment file\r
157         try   { out.setLength(filePointer);  }  catch (Exception ex) {}\r
158         // now skip to next entry\r
159         while( result[r].indexOf("</entry>")==-1)\r
160           r++;\r
161       }\r
162 \r
163       features = new Vector();\r
164       type=""; start="0"; end="0"; description=""; status=""; pdb="";\r
165 \r
166     }\r
167 \r
168     if(sequence==null)\r
169       continue;\r
170 \r
171      if( result[r].indexOf("<property type=\"pdb accession\"")>-1)\r
172      {\r
173        pdb = parseValue( result[r], "value=" , out);\r
174        sequence.setPDBId(pdb);\r
175      }\r
176 \r
177      if(result[r].indexOf("feature type")>-1)\r
178      {\r
179        type = parseValue( result[r], "type=" , out);\r
180        description = parseValue( result[r], "description=" , null );\r
181        status = parseValue ( result[r], "status=", null);\r
182 \r
183        while( result[r].indexOf("position")==-1)\r
184        {\r
185            r++;  //<location>\r
186        }\r
187       // r++;\r
188        if(result[r].indexOf("begin")>-1)\r
189        {\r
190          start = parseValue( result[r], "position=" , out);\r
191          end = parseValue( result[++r], "position=" , out);\r
192        }\r
193        else\r
194        {\r
195          start = parseValue( result[r], "position=" , out);\r
196          end = parseValue(   result[r], "position=" , null);\r
197        }\r
198        int sstart = Integer.parseInt(start);\r
199        int eend = Integer.parseInt(end);\r
200        if(out!=null)\r
201          try{ out.writeBytes("</feature>\n"); }catch(Exception ex){}\r
202 \r
203          SequenceFeature sf = new SequenceFeature(type,\r
204              sstart,\r
205              eend,\r
206              description,\r
207              status);\r
208          features.add(sf);\r
209      }\r
210 \r
211      if(result[r].indexOf("<sequence")>-1)\r
212      {\r
213        StringBuffer seqString = new StringBuffer();\r
214 \r
215        if(out!=null)\r
216          try  {  out.writeBytes(result[r]+"\n"); }   catch (Exception ex){}\r
217 \r
218        while(result[++r].indexOf("</sequence>")==-1)\r
219        {\r
220          seqString.append(result[r]);\r
221          if(out!=null)\r
222          try  {  out.writeBytes(result[r]+"\n"); }   catch (Exception ex){}\r
223        }\r
224 \r
225        if(out!=null)\r
226          try  {  out.writeBytes(result[r]+"\n"); }   catch (Exception ex){}\r
227 \r
228        StringBuffer nonGapped = new StringBuffer();\r
229        for (int i = 0; i < sequence.getSequence().length(); i++)\r
230        {\r
231          if (!jalview.util.Comparison.isGap(sequence.getCharAt(i)))\r
232            nonGapped.append(sequence.getCharAt(i));\r
233        }\r
234 \r
235        int absStart = seqString.toString().indexOf(nonGapped.toString());\r
236        if(absStart==-1)\r
237        {\r
238          unknownSequences.add(sequence.getName());\r
239          features = null;\r
240          sbuffer.append(sequence.getName()+ " SEQUENCE NOT %100 MATCH \n");\r
241          continue;\r
242        }\r
243 \r
244        int absEnd =   absStart + nonGapped.toString().length();\r
245        absStart+=1;\r
246 \r
247        if(absStart!=sequence.getStart() || absEnd!=sequence.getEnd())\r
248          sbuffer.append("Updated: "+sequence.getName()+" "+\r
249                            sequence.getStart()+"/"+sequence.getEnd()+"  to  "+ absStart+"/"+absEnd+"\n");\r
250 \r
251 \r
252        sequence.setStart(absStart);\r
253        sequence.setEnd(absEnd);\r
254 \r
255      }\r
256 \r
257      if(result[r].indexOf("</entry>")>-1)\r
258      {\r
259        if(features!=null)\r
260          sequence.setSequenceFeatures( features );\r
261        features = null;\r
262        sequence = null;\r
263        if(out!=null)\r
264          try{  out.writeBytes("</entry>\n"); }catch(Exception ex){}\r
265 \r
266      }\r
267   }\r
268 }\r
269 \r
270 void findMissingIds(AlignmentI align)\r
271 {\r
272   String data;\r
273   ArrayList cachedIds = new ArrayList();\r
274 \r
275   try\r
276   {\r
277     BufferedReader in = new BufferedReader(\r
278         new FileReader(jalview.bin.Cache.getProperty("UNIPROT_CACHE")));\r
279 \r
280     while ( (data = in.readLine()) != null)\r
281     {\r
282       if (data.indexOf("name") > -1)\r
283       {\r
284         String name = parseElement(data, "<name>", null);\r
285         cachedIds.add(name);\r
286       }\r
287     }\r
288   }\r
289   catch (Exception ex)\r
290   {   ex.printStackTrace();  }\r
291 \r
292   for(int i=0; i<align.getHeight(); i++)\r
293     if( !cachedIds.contains( align.getSequenceAt(i).getName() ) )\r
294       unknownSequences.add( align.getSequenceAt(i).getName() );\r
295 \r
296 \r
297 }\r
298 \r
299 void tryLocalCacheFirst(ArrayList ids, AlignmentI align)\r
300 {\r
301   ArrayList cacheData = new ArrayList();\r
302   try{\r
303     BufferedReader in = new BufferedReader(\r
304           new FileReader(jalview.bin.Cache.getProperty("UNIPROT_CACHE")));\r
305 \r
306     // read through cache file, if the cache has sequences we're looking for\r
307     // add the lines to a new String array, Readthis new array and\r
308     // make sure we remove the ids from the list to retrieve from EBI\r
309     String data;\r
310     while( ( data=in.readLine())!=null)\r
311     {\r
312       if(data.indexOf("name")>-1)\r
313       {\r
314         String name = parseElement( data, "<name>" , null) ;\r
315         if(ids.contains( name ) )\r
316         {\r
317           cacheData.add("<entry>");\r
318           cacheData.add(data);\r
319           while( data.indexOf("</entry>")==-1)\r
320           {\r
321             data = in.readLine();\r
322             cacheData.add(data);\r
323           }\r
324           cacheData.add(data);\r
325 \r
326           ids.remove( name );\r
327         }\r
328       }\r
329     }\r
330   }\r
331   catch(Exception ex){ex.printStackTrace();}\r
332 \r
333   String [] localData = new String[cacheData.size()];\r
334   cacheData.toArray( localData );\r
335   if(localData!=null && localData.length>0)\r
336     ReadUniprotFile(localData, null, align);\r
337 }\r
338 \r
339 \r
340 String parseValue(String line, String tag, RandomAccessFile out)\r
341 {\r
342   if(out!=null)\r
343     try{  out.writeBytes(line+"\n"); }catch(Exception ex){}\r
344 \r
345 \r
346   int index = line.indexOf(tag)+tag.length()+1;\r
347   if(index==tag.length())\r
348     return "";\r
349 \r
350   return line.substring( index, line.indexOf("\"", index+1) );\r
351 }\r
352 \r
353 \r
354 String parseElement(String line, String tag, RandomAccessFile out)\r
355 {\r
356   if (out != null)\r
357     try\r
358     {\r
359       out.writeBytes(line + "\n");\r
360     }\r
361     catch (Exception ex)\r
362     {}\r
363 \r
364   int index = line.indexOf(tag) + tag.length();\r
365   return line.substring(index, line.indexOf("</"));\r
366 \r
367   }\r
368 }\r