Class |
Line # |
Actions |
|||
---|---|---|---|---|---|
Sequencefeature | 46 | 149 | 49 |
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.vamsas; | |
22 | ||
23 | import jalview.bin.Console; | |
24 | import jalview.datamodel.SequenceFeature; | |
25 | import jalview.datamodel.SequenceI; | |
26 | import jalview.io.VamsasAppDatastore; | |
27 | import jalview.util.UrlLink; | |
28 | ||
29 | import java.util.Enumeration; | |
30 | import java.util.Iterator; | |
31 | import java.util.Vector; | |
32 | ||
33 | import uk.ac.vamsas.objects.core.DataSetAnnotations; | |
34 | import uk.ac.vamsas.objects.core.Link; | |
35 | import uk.ac.vamsas.objects.core.Property; | |
36 | import uk.ac.vamsas.objects.core.Provenance; | |
37 | import uk.ac.vamsas.objects.core.RangeAnnotation; | |
38 | import uk.ac.vamsas.objects.core.Score; | |
39 | import uk.ac.vamsas.objects.core.Seg; | |
40 | import uk.ac.vamsas.objects.utils.Properties; | |
41 | ||
42 | /** | |
43 | * @author JimP | |
44 | * | |
45 | */ | |
46 | public class Sequencefeature extends Rangetype | |
47 | { | |
48 | ||
49 | uk.ac.vamsas.objects.core.DataSet dataset; | |
50 | ||
51 | uk.ac.vamsas.objects.core.Sequence sequence; | |
52 | ||
53 | private SequenceI dsSeq; | |
54 | ||
55 | 0 | public Sequencefeature(VamsasAppDatastore vamsasAppDatastore, |
56 | SequenceFeature sequenceFeature, | |
57 | uk.ac.vamsas.objects.core.DataSet dataset, | |
58 | uk.ac.vamsas.objects.core.Sequence sequence) | |
59 | { | |
60 | 0 | super(vamsasAppDatastore, sequenceFeature, DataSetAnnotations.class); |
61 | 0 | this.dataset = dataset; |
62 | 0 | this.sequence = sequence; |
63 | 0 | doSync(); |
64 | } | |
65 | ||
66 | 0 | public Sequencefeature(VamsasAppDatastore vamsasAppDatastore, |
67 | DataSetAnnotations dseta, SequenceI dsSeq) | |
68 | { | |
69 | 0 | super(vamsasAppDatastore, dseta, |
70 | jalview.datamodel.SequenceFeature.class); | |
71 | 0 | this.dsSeq = dsSeq; |
72 | 0 | doJvUpdate(); |
73 | } | |
74 | ||
75 | 0 | @Override |
76 | public void addToDocument() | |
77 | { | |
78 | 0 | DataSetAnnotations dsa = (DataSetAnnotations) vobj; |
79 | 0 | jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj; |
80 | 0 | dsa = (DataSetAnnotations) getDSAnnotationFromJalview( |
81 | new DataSetAnnotations(), feature); | |
82 | 0 | if (dsa.getProvenance() == null) |
83 | { | |
84 | 0 | dsa.setProvenance(new Provenance()); |
85 | } | |
86 | 0 | addProvenance(dsa.getProvenance(), "created"); // JBPNote - need |
87 | // to update | |
88 | 0 | dsa.addSeqRef(sequence); // we have just created this annotation |
89 | // - so safe to use this | |
90 | 0 | bindjvvobj(feature, dsa); |
91 | 0 | dataset.addDataSetAnnotations(dsa); |
92 | } | |
93 | ||
94 | 0 | @Override |
95 | public void addFromDocument() | |
96 | { | |
97 | 0 | DataSetAnnotations dsa = (DataSetAnnotations) vobj; |
98 | 0 | if (dsa.getSeqRefCount() != 1) |
99 | { | |
100 | 0 | Console.warn("Not binding " + dsa.getVorbaId() |
101 | + " to Sequence Feature - has multiple dataset sequence references."); | |
102 | 0 | return; |
103 | } | |
104 | 0 | jalview.datamodel.SequenceFeature sf = (jalview.datamodel.SequenceFeature) jvobj; |
105 | 0 | dsSeq.addSequenceFeature(sf = getJalviewSeqFeature(dsa)); |
106 | 0 | jvobj = sf; |
107 | 0 | bindjvvobj(sf, dsa); |
108 | } | |
109 | ||
110 | 0 | @Override |
111 | public void conflict() | |
112 | { | |
113 | 0 | log.warn("Untested sequencefeature conflict code"); |
114 | 0 | DataSetAnnotations dsa = (DataSetAnnotations) vobj; |
115 | 0 | jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj; |
116 | 0 | jalview.datamodel.SequenceFeature sf = getJalviewSeqFeature(dsa); |
117 | 0 | replaceJvObjMapping(feature, sf); // switch binding of dsa from old feature |
118 | // to newly created feature | |
119 | 0 | dsSeq.addSequenceFeature(sf); // add new imported feature |
120 | 0 | addToDocument(); // and create a new feature in the document |
121 | } | |
122 | ||
123 | 0 | @Override |
124 | public void updateToDoc() | |
125 | { | |
126 | 0 | DataSetAnnotations dsa = (DataSetAnnotations) vobj; |
127 | 0 | jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj; |
128 | 0 | if (dsa.getSeqRefCount() != 1) |
129 | { | |
130 | 0 | replaceJvObjMapping(feature, null); |
131 | 0 | Console.warn( |
132 | "Binding of annotation to jalview feature has changed. Removing binding and recreating."); | |
133 | 0 | doSync(); // re-verify bindings. |
134 | } | |
135 | else | |
136 | { | |
137 | // Sync the features from Jalview | |
138 | 0 | long oldref = dsa.get__last_hash(); |
139 | 0 | getDSAnnotationFromJalview(dsa, feature); |
140 | 0 | if (oldref != dsa.hashCode()) |
141 | { | |
142 | 0 | Console.debug("Updated dataset sequence annotation from feature."); |
143 | 0 | addProvenance(dsa.getProvenance(), "modified"); |
144 | } | |
145 | } | |
146 | ||
147 | } | |
148 | ||
149 | 0 | @Override |
150 | public void updateFromDoc() | |
151 | { | |
152 | 0 | DataSetAnnotations dsa = (DataSetAnnotations) vobj; |
153 | 0 | jalview.datamodel.SequenceFeature feature = (jalview.datamodel.SequenceFeature) jvobj; |
154 | 0 | if (dsa.getSeqRefCount() != 1) |
155 | { | |
156 | // conflicting update from document - we cannot map this feature anymore. | |
157 | 0 | replaceJvObjMapping(feature, null); |
158 | 0 | Console.warn("annotation (" + dsa.getVorbaId() |
159 | + " bound to jalview feature cannot be mapped. Removing binding, deleting feature, and deleting feature."); | |
160 | // - consider deleting the feature ? | |
161 | 0 | dsSeq.deleteFeature(feature); |
162 | // doSync(); | |
163 | } | |
164 | else | |
165 | { | |
166 | // Sync the features to Jalview - easiest to delete and add the feature | |
167 | // again | |
168 | 0 | jalview.datamodel.SequenceFeature newsf = getJalviewSeqFeature(dsa); |
169 | 0 | dsSeq.deleteFeature(feature); |
170 | 0 | replaceJvObjMapping(feature, newsf); |
171 | 0 | dsSeq.addSequenceFeature(newsf); |
172 | 0 | if (feature.otherDetails != null) |
173 | { | |
174 | // TODO later: leave this to finalise method ? | |
175 | 0 | feature.otherDetails.clear(); |
176 | } | |
177 | } | |
178 | } | |
179 | ||
180 | /** | |
181 | * correctly create/update a RangeAnnotation from a jalview sequence feature | |
182 | * TODO: refactor to a method in jalview.io.vamsas.RangeAnnotation class | |
183 | * | |
184 | * @param dsa | |
185 | * (typically DataSetAnnotations or AlignmentSequenceAnnotation) | |
186 | * @param feature | |
187 | * (the feature to be mapped from) | |
188 | * @return | |
189 | */ | |
190 | 0 | private RangeAnnotation getDSAnnotationFromJalview(RangeAnnotation dsa, |
191 | jalview.datamodel.SequenceFeature feature) | |
192 | { | |
193 | 0 | dsa.setType(feature.getType()); |
194 | 0 | Seg vSeg = new Seg(); |
195 | 0 | vSeg.setStart(feature.getBegin()); |
196 | 0 | vSeg.setEnd(feature.getEnd()); |
197 | 0 | vSeg.setInclusive(true); |
198 | 0 | if (dsa.getSegCount() > 1) |
199 | { | |
200 | 0 | Console.debug( |
201 | "About to destroy complex annotation in vamsas document mapped to sequence feature (" | |
202 | + dsa.getVorbaId() + ")"); | |
203 | } | |
204 | 0 | dsa.setSeg(new Seg[] { vSeg }); |
205 | 0 | dsa.setDescription(feature.getDescription()); |
206 | 0 | dsa.setStatus(feature.getStatus()); |
207 | 0 | if (feature.links != null && feature.links.size() > 0) |
208 | { | |
209 | 0 | for (int i = 0, iSize = feature.links.size(); i < iSize; i++) |
210 | { | |
211 | 0 | String link = feature.links.elementAt(i); |
212 | 0 | UrlLink ulink = new UrlLink(link); |
213 | 0 | if (ulink.isValid()) |
214 | { | |
215 | // We only add static links to the document. | |
216 | 0 | Link vLink = new Link(); |
217 | 0 | vLink.setContent(ulink.getLabel()); |
218 | 0 | vLink.setHref(ulink.getTarget()); |
219 | 0 | dsa.addLink(vLink); |
220 | } | |
221 | } | |
222 | } | |
223 | 0 | dsa.setGroup(feature.getFeatureGroup()); |
224 | 0 | if (!Float.isNaN(feature.getScore())) |
225 | { | |
226 | 0 | Score fscore = new Score(); |
227 | 0 | dsa.setScore(new Score[] { fscore }); |
228 | 0 | fscore.setContent(feature.getScore()); |
229 | 0 | fscore.setName(feature.getType()); |
230 | } | |
231 | 0 | if (feature.otherDetails != null) |
232 | { | |
233 | 0 | Iterator<String> iter = feature.otherDetails.keySet().iterator(); |
234 | 0 | Vector props = dsa.getPropertyAsReference(); |
235 | 0 | while (iter.hasNext()) |
236 | { | |
237 | 0 | String key = iter.next(); |
238 | 0 | if (!key.equalsIgnoreCase("score") |
239 | && !key.equalsIgnoreCase("status")) | |
240 | { | |
241 | 0 | Property nprop = new Property(); |
242 | 0 | nprop.setName(key); |
243 | 0 | Object vlu = feature.getValue(key); |
244 | 0 | nprop.setContent(feature.getValue(key).toString()); |
245 | 0 | boolean valid = false; |
246 | 0 | if (vlu instanceof String) |
247 | { | |
248 | 0 | nprop.setType(uk.ac.vamsas.objects.utils.Properties.STRINGTYPE); |
249 | 0 | valid = true; |
250 | } | |
251 | 0 | else if (vlu instanceof Integer) |
252 | { | |
253 | 0 | valid = true; |
254 | 0 | nprop.setType( |
255 | uk.ac.vamsas.objects.utils.Properties.INTEGERTYPE); | |
256 | } | |
257 | 0 | else if (vlu instanceof Float) |
258 | { | |
259 | 0 | nprop.setType(uk.ac.vamsas.objects.utils.Properties.FLOATTYPE); |
260 | 0 | valid = true; |
261 | } | |
262 | 0 | if (valid) |
263 | { | |
264 | 0 | if (props != null) |
265 | { | |
266 | 0 | uk.ac.vamsas.objects.utils.Properties.addOrReplace(props, |
267 | nprop); | |
268 | } | |
269 | else | |
270 | { | |
271 | 0 | dsa.addProperty(nprop); |
272 | } | |
273 | } | |
274 | } | |
275 | } | |
276 | } | |
277 | 0 | return dsa; |
278 | } | |
279 | ||
280 | 0 | private SequenceFeature getJalviewSeqFeature(RangeAnnotation dseta) |
281 | { | |
282 | 0 | int[] se = getBounds(dseta); |
283 | ||
284 | /* | |
285 | * try to identify feature score | |
286 | */ | |
287 | 0 | boolean scoreFound = false; |
288 | 0 | float theScore = 0f; |
289 | 0 | String featureType = dseta.getType(); |
290 | 0 | if (dseta.getScoreCount() > 0) |
291 | { | |
292 | 0 | Enumeration scr = dseta.enumerateScore(); |
293 | 0 | while (scr.hasMoreElements()) |
294 | { | |
295 | 0 | Score score = (Score) scr.nextElement(); |
296 | 0 | if (score.getName().equals(featureType)) |
297 | { | |
298 | 0 | theScore = score.getContent(); |
299 | 0 | scoreFound = true; |
300 | } | |
301 | } | |
302 | } | |
303 | ||
304 | 0 | SequenceFeature sf = null; |
305 | 0 | if (scoreFound) |
306 | { | |
307 | 0 | sf = new SequenceFeature(featureType, dseta.getDescription(), se[0], |
308 | se[1], theScore, dseta.getGroup()); | |
309 | } | |
310 | else | |
311 | { | |
312 | 0 | sf = new SequenceFeature(featureType, dseta.getDescription(), se[0], |
313 | se[1], dseta.getGroup()); | |
314 | } | |
315 | 0 | sf.setStatus(dseta.getStatus()); |
316 | 0 | if (dseta.getLinkCount() > 0) |
317 | { | |
318 | 0 | Link[] links = dseta.getLink(); |
319 | 0 | for (int i = 0; i < links.length; i++) |
320 | { | |
321 | // TODO: use URLLink parsing/validation here. | |
322 | 0 | sf.addLink(links[i].getContent() + "|" + links[i].getHref()); |
323 | } | |
324 | } | |
325 | 0 | if (dseta.getScoreCount() > 0) |
326 | { | |
327 | 0 | Enumeration scr = dseta.enumerateScore(); |
328 | 0 | while (scr.hasMoreElements()) |
329 | { | |
330 | 0 | Score score = (Score) scr.nextElement(); |
331 | 0 | if (!score.getName().equals(sf.getType())) |
332 | { | |
333 | 0 | sf.setValue(score.getName(), "" + score.getContent()); |
334 | } | |
335 | } | |
336 | } | |
337 | // other details | |
338 | 0 | Enumeration props = dseta.enumerateProperty(); |
339 | 0 | while (props.hasMoreElements()) |
340 | { | |
341 | 0 | Property p = (Property) props.nextElement(); |
342 | 0 | Object val = null; |
343 | 0 | if (Properties.isValid(p)) |
344 | { | |
345 | 0 | if (Properties.isString(p)) |
346 | { | |
347 | 0 | val = p.getContent(); |
348 | } | |
349 | 0 | if (Properties.isBoolean(p)) |
350 | { | |
351 | 0 | try |
352 | { | |
353 | 0 | val = Boolean.valueOf(p.getContent()); |
354 | } catch (Exception e) | |
355 | { | |
356 | } | |
357 | } | |
358 | 0 | if (Properties.isFloat(p)) |
359 | { | |
360 | 0 | try |
361 | { | |
362 | 0 | val = Float.valueOf(p.getContent()); |
363 | ||
364 | } catch (Exception e) | |
365 | { | |
366 | } | |
367 | } | |
368 | 0 | if (Properties.isInteger(p)) |
369 | { | |
370 | 0 | try |
371 | { | |
372 | 0 | val = Integer.valueOf(p.getContent()); |
373 | } catch (Exception e) | |
374 | { | |
375 | } | |
376 | } | |
377 | 0 | if (val != null) |
378 | { | |
379 | 0 | sf.setValue(p.getName(), val); |
380 | } | |
381 | } | |
382 | } | |
383 | ||
384 | 0 | return sf; |
385 | } | |
386 | ||
387 | } |