Clover icon

Coverage Report

  1. Project Clover database Wed Sep 18 2024 02:54:09 BST
  2. Package jalview.io

File ModellerDescription.java

 

Coverage histogram

../../img/srcFileCovDistChart2.png
54% of files have more coverage

Code metrics

76
127
16
2
431
314
69
0.54
7.94
8
4.31

Classes

Class Line # Actions
ModellerDescription 31 123 67
0.1455399114.6%
ModellerDescription.resCode 80 4 2
0.00%
 

Contributing tests

This file is covered by 1 test. .

Source view

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.io;
22   
23    import jalview.bin.Cache;
24    import jalview.datamodel.DBRefEntry;
25    import jalview.datamodel.SequenceI;
26   
27    import java.util.List;
28   
29    import com.stevesoft.pat.Regex;
30   
 
31    public class ModellerDescription
32    {
33    /**
34    * Translates between a String containing a set of colon-separated values on a
35    * single line, and sequence start/end and other properties. See PIRFile IO
36    * for its use.
37    */
38    final String[] seqTypes = { "sequence", "structure", "structureX",
39    "structureN" };
40   
41    final String[] Fields = { "objectType", "objectId", "startField",
42    "startCode", "endField", "endCode", "description1", "description2",
43    "resolutionField", "tailField" };
44   
45    final int TYPE = 0;
46   
47    final int LOCALID = 1;
48   
49    final int START = 2;
50   
51    final int START_CHAIN = 3;
52   
53    final int END = 4;
54   
55    final int END_CHAIN = 5;
56   
57    final int DESCRIPTION1 = 6;
58   
59    final int DESCRIPTION2 = 7;
60   
61    final int RESOLUTION = 8;
62   
63    final int TAIL = 9;
64   
65    /**
66    * 0 is free text or empty 1 is something that parses to an integer, or \@
67    */
68    final int Types[] = { 0, 0, 1, 0, 1, 0, 0, 0, 0, 0 };
69   
70    final char Padding[] = { ' ', ' ', ' ', '.', ' ', '.', '.', '.', '.',
71    '.' };
72   
73    java.util.Hashtable fields = new java.util.Hashtable();
74   
 
75  0 toggle ModellerDescription()
76    {
77  0 fields.put(Fields[TAIL], "");
78    }
79   
 
80    class resCode
81    {
82    Integer val;
83   
84    String field;
85   
 
86  0 toggle resCode(String f, Integer v)
87    {
88  0 val = v;
89  0 field = f;
90    }
91   
 
92  0 toggle resCode(int v)
93    {
94  0 val = Integer.valueOf(v);
95  0 field = val.toString();
96    }
97    };
98   
 
99  0 toggle private resCode validResidueCode(String field)
100    {
101  0 Integer val = null;
102  0 Regex r = new Regex("\\s*((([-0-9]+).?)|FIRST|LAST|@)");
103   
104  0 if (!r.search(field))
105    {
106  0 return null; // invalid
107    }
108  0 String value = r.stringMatched(3);
109  0 if (value == null)
110    {
111  0 value = r.stringMatched(1);
112    }
113    // Cache.debug("from '" + field + "' matched '" + value +
114    // "'");
115  0 try
116    {
117  0 val = Integer.valueOf(value);
118  0 return new resCode(field, val); // successful numeric extraction
119    } catch (Exception e)
120    {
121    }
122  0 return new resCode(field, null);
123    }
124   
 
125  15 toggle private java.util.Hashtable parseDescription(String desc)
126    {
127  15 java.util.Hashtable fields = new java.util.Hashtable();
128  15 java.util.StringTokenizer st = new java.util.StringTokenizer(desc, ":",
129    true);
130   
131  15 String field;
132  15 int type = -1;
133  15 if (st.countTokens() > 0)
134    {
135    // parse colon-fields
136  15 int i = 0;
137  15 field = st.nextToken(":");
138  15 do
139    {
140  60 if (seqTypes[i].equalsIgnoreCase(field))
141    {
142  0 break;
143    }
144  60 } while (++i < seqTypes.length);
145   
146  15 if (i < seqTypes.length)
147    {
148  0 st.nextToken(); // skip ':'
149    // valid seqType for modeller
150  0 type = i;
151  0 i = 1; // continue parsing fields
152  0 while (i < TAIL && st.hasMoreTokens())
153    {
154  0 if ((field = st.nextToken(":")) != null)
155    {
156  0 if (!field.equals(":"))
157    {
158    // validate residue field value
159  0 if (Types[i] == 1)
160    {
161  0 resCode val = validResidueCode(field);
162  0 if (val != null)
163    {
164  0 fields.put(new String(Fields[i] + "num"), val);
165    }
166    else
167    {
168    // Cache.debug(
169    // "Ignoring non-Modeller description: invalid integer-like
170    // field '" + field + "'");
171  0 type = -1; /* invalid field! - throw the FieldSet away */
172    }
173  0 ;
174    }
175  0 fields.put(Fields[i++], field);
176  0 if (st.hasMoreTokens())
177    {
178  0 st.nextToken(); // skip token sep.
179    }
180    }
181    else
182    {
183  0 i++;
184    }
185    }
186    }
187  0 if (i == TAIL)
188    {
189    // slurp remaining fields
190  0 while (st.hasMoreTokens())
191    {
192  0 String tl = st.nextToken(":");
193  0 field += tl.equals(":") ? tl : (":" + tl);
194    }
195  0 fields.put(Fields[TAIL], field);
196    }
197    }
198    }
199  15 if (type == -1)
200    {
201    // object is not a proper ModellerPIR object
202  15 fields = new java.util.Hashtable();
203  15 fields.put(Fields[TAIL], new String(desc));
204    }
205    else
206    {
207  0 fields.put(Fields[TYPE], seqTypes[type]);
208    }
209  15 return fields;
210    }
211   
 
212  15 toggle ModellerDescription(String desc)
213    {
214  15 if (desc == null)
215    {
216  0 desc = "";
217    }
218  15 fields = parseDescription(desc);
219    }
220   
 
221  0 toggle void setStartCode(int v)
222    {
223  0 resCode r;
224  0 fields.put(Fields[START] + "num", r = new resCode(v));
225  0 fields.put(Fields[START], r.field);
226    }
227   
 
228  0 toggle void setEndCode(int v)
229    {
230  0 resCode r;
231  0 fields.put(Fields[END] + "num", r = new resCode(v));
232  0 fields.put(Fields[END], r.field);
233    }
234   
235    /**
236    * make a possibly updated modeller field line for the sequence object
237    *
238    * @param seq
239    * SequenceI
240    */
 
241  0 toggle ModellerDescription(SequenceI seq)
242    {
243   
244  0 if (seq.getDescription() != null)
245    {
246  0 fields = parseDescription(seq.getDescription());
247    }
248   
249  0 if (isModellerFieldset())
250    {
251    // Set start and end before we update the type (in the case of a
252    // synthesized field set)
253  0 if (getStartCode() == null || (getStartNum() != seq.getStart()
254    && getStartCode().val != null))
255    {
256    // unset or user updated sequence start position
257  0 setStartCode(seq.getStart());
258    }
259   
260  0 if (getEndCode() == null || (getEndNum() != seq.getEnd()
261    && getStartCode() != null && getStartCode().val != null))
262    {
263  0 setEndCode(seq.getEnd());
264    }
265    }
266    else
267    {
268    // synthesize fields
269  0 setStartCode(seq.getStart());
270  0 setEndCode(seq.getEnd());
271  0 fields.put(Fields[LOCALID], seq.getName()); // this may be overwritten
272    // below...
273    // type - decide based on evidence of PDB database references - this also
274    // sets the local reference field
275  0 int t = 0; // sequence
276  0 if (seq.getDatasetSequence() != null
277    && seq.getDatasetSequence().getDBRefs() != null)
278    {
279  0 List<DBRefEntry> dbr = seq.getDatasetSequence().getDBRefs();
280  0 for (int i = 0, ni = dbr.size(); i < ni; i++)
281    {
282  0 DBRefEntry dbri = dbr.get(i);
283  0 if (dbri != null)
284    {
285    // JBPNote PDB dbRefEntry needs properties to propagate onto
286    // ModellerField
287    // JBPNote Need to get info from the user about whether the sequence
288    // is the one being modelled, or if it is a template.
289  0 if (dbri.getSource().equals(jalview.datamodel.DBRefSource.PDB))
290    {
291  0 fields.put(Fields[LOCALID], dbri.getAccessionId());
292  0 t = 2;
293  0 break;
294    }
295    }
296    }
297    }
298  0 fields.put(Fields[TYPE], seqTypes[t]);
299    }
300   
301    }
302   
303    /**
304    * Indicate if fields parsed to a modeller-like colon-separated value line
305    *
306    * @return boolean
307    */
 
308  15 toggle boolean isModellerFieldset()
309    {
310  15 return (fields.containsKey(Fields[TYPE]));
311    }
312   
 
313  0 toggle String getDescriptionLine()
314    {
315  0 String desc = "";
316  0 int lastfield = Fields.length - 1;
317   
318  0 if (isModellerFieldset())
319    {
320  0 String value;
321    // try to write a minimal modeller field set, so..
322   
323    // find the last valid field in the entry
324   
325  0 for (; lastfield > 6; lastfield--)
326    {
327  0 if (fields.containsKey(Fields[lastfield]))
328    {
329  0 break;
330    }
331    }
332   
333  0 for (int i = 0; i < lastfield; i++)
334    {
335  0 value = (String) fields.get(Fields[i]);
336  0 if (value != null && value.length() > 0)
337    {
338  0 desc += ((String) fields.get(Fields[i])) + ":";
339    }
340    else
341    {
342  0 desc += Padding[i] + ":";
343    }
344    }
345    }
346    // just return the last field if no others were defined.
347  0 if (fields.containsKey(Fields[lastfield]))
348    {
349  0 desc += (String) fields.get(Fields[lastfield]);
350    }
351    else
352    {
353  0 desc += ".";
354    }
355  0 return desc;
356    }
357   
 
358  0 toggle int getStartNum()
359    {
360  0 int start = 0;
361  0 resCode val = getStartCode();
362  0 if (val != null && val.val != null)
363    {
364  0 return val.val.intValue();
365    }
366  0 return start;
367    }
368   
 
369  0 toggle resCode getStartCode()
370    {
371  0 if (isModellerFieldset() && fields.containsKey(Fields[START] + "num"))
372    {
373  0 return (resCode) fields.get(Fields[START] + "num");
374    }
375  0 return null;
376    }
377   
 
378  0 toggle resCode getEndCode()
379    {
380  0 if (isModellerFieldset() && fields.containsKey(Fields[END] + "num"))
381    {
382  0 return (resCode) fields.get(Fields[END] + "num");
383    }
384  0 return null;
385    }
386   
 
387  0 toggle int getEndNum()
388    {
389  0 int end = 0;
390  0 resCode val = getEndCode();
391  0 if (val != null && val.val != null)
392    {
393  0 return val.val.intValue();
394    }
395  0 return end;
396    }
397   
398    /**
399    * returns true if sequence object was modifed with a valid modellerField set
400    *
401    * @param newSeq
402    * SequenceI
403    * @return boolean
404    */
 
405  15 toggle boolean updateSequenceI(SequenceI newSeq)
406    {
407  15 if (isModellerFieldset())
408    {
409  0 resCode rc = getStartCode();
410  0 if (rc != null && rc.val != null)
411    {
412  0 newSeq.setStart(getStartNum());
413    }
414    else
415    {
416  0 newSeq.setStart(1);
417    }
418  0 rc = getEndCode();
419  0 if (rc != null && rc.val != null)
420    {
421  0 newSeq.setEnd(getEndNum());
422    }
423    else
424    {
425  0 newSeq.setEnd(newSeq.getStart() + newSeq.getLength());
426    }
427  0 return true;
428    }
429  15 return false;
430    }
431    }