JAL_1641 added unit test and minor house keeping
[jalview.git] / src / jalview / io / JSONFile.java
1 package jalview.io;
2
3 import jalview.api.FeaturesDisplayedI;
4 import jalview.datamodel.AlignmentAnnotation;
5 import jalview.datamodel.Annotation;
6 import jalview.datamodel.Sequence;
7 import jalview.datamodel.SequenceFeature;
8 import jalview.datamodel.SequenceGroup;
9 import jalview.datamodel.SequenceI;
10 import jalview.gui.AlignFrame;
11 import jalview.gui.Desktop;
12 import jalview.json.binding.v1.AlignmentAnnotationPojo;
13 import jalview.json.binding.v1.AlignmentPojo;
14 import jalview.json.binding.v1.AnnotationPojo;
15 import jalview.json.binding.v1.JalviewSettingsPojo;
16 import jalview.json.binding.v1.JalviewSettingsPojo.JalviewBioJsColorSchemeMapper;
17 import jalview.json.binding.v1.SequenceFeaturesPojo;
18 import jalview.json.binding.v1.SequenceGrpPojo;
19 import jalview.json.binding.v1.SequencePojo;
20 import jalview.schemes.ColourSchemeI;
21 import jalview.schemes.ColourSchemeProperty;
22 import jalview.viewmodel.AlignmentViewport;
23
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Hashtable;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Vector;
30
31 import org.json.simple.JSONArray;
32 import org.json.simple.JSONObject;
33 import org.json.simple.parser.JSONParser;
34
35 public class JSONFile extends AlignFile
36 {
37   private static ColourSchemeI colourScheme;
38
39   private static boolean seqFeaturesEnabled;
40
41   private String jalviewVersion;
42
43   private String webStartLaunchServletUrl = "http://www.jalview.org/services/launchApp";
44
45   public static final String FILE_EXT = "json";
46
47   public static final String FILE_DESC = "JSON";
48
49   private String globalColorScheme;
50
51   private boolean showSeqFeatures;
52
53   private Hashtable<String, Sequence> seqMap;
54
55   private FeaturesDisplayedI displayedFeatures;
56
57   private AlignmentViewport av;
58
59   private JSONExportSettings jsonExportSettings;
60
61   public JSONFile()
62   {
63     super();
64   }
65
66   public JSONFile(FileParse source) throws IOException
67   {
68     super(source);
69   }
70
71   public JSONFile(String inFile, String type) throws IOException
72   {
73     super(inFile, type);
74   }
75
76   @Override
77   public void parse() throws IOException
78   {
79     StringBuilder jsonStringBuilder = new StringBuilder();
80     String currentLine;
81     while ((currentLine = nextLine()) != null)
82     {
83       jsonStringBuilder.append(currentLine);
84     }
85     parse(jsonStringBuilder.toString());
86
87   }
88
89   @Override
90   public String print()
91   {
92     try
93     {
94       if (getJsonExportSettings() == null)
95       {
96         jsonExportSettings = new JSONExportSettings();
97         jsonExportSettings.setExportAnnotations(true);
98         jsonExportSettings.setExportGroups(true);
99         jsonExportSettings.setExportJalviewSettings(true);
100         jsonExportSettings.setExportSequenceFeatures(true);
101       }
102
103       AlignmentPojo jsonAlignmentPojo = new AlignmentPojo();
104       if (Desktop.getCurrentAlignFrame() != null)
105       {
106         globalColorScheme = ColourSchemeProperty.getColourName(Desktop
107                 .getCurrentAlignFrame().getViewport()
108                 .getGlobalColourScheme());
109         this.av = Desktop.getCurrentAlignFrame().getCurrentView();
110         setDisplayedFeatures(av.getFeaturesDisplayed());
111         showSeqFeatures = Desktop.getCurrentAlignFrame().showSeqFeatures
112                 .isSelected();
113       }
114
115       int count = 0;
116       for (SequenceI seq : seqs)
117       {
118         StringBuilder name = new StringBuilder();
119         name.append(seq.getName()).append("/").append(seq.getStart())
120                 .append("-").append(seq.getEnd());
121         SequencePojo jsonSeqPojo = new SequencePojo();
122         jsonSeqPojo.setId(seq.getName() + "_" + seq.hashCode());
123         jsonSeqPojo.setOrder(++count);
124         jsonSeqPojo.setEnd(seq.getEnd());
125         jsonSeqPojo.setStart(seq.getStart());
126         jsonSeqPojo.setName(name.toString());
127         jsonSeqPojo.setSeq(seq.getSequenceAsString());
128         jsonAlignmentPojo.getSeqs().add(jsonSeqPojo);
129       }
130
131       if (jsonExportSettings.isExportJalviewSettings())
132       {
133         JalviewSettingsPojo jvSettings = new JalviewSettingsPojo();
134         jvSettings.setGlobalColorScheme(globalColorScheme);
135         jvSettings.setJalviewVersion(jalviewVersion);
136         jvSettings.setWebStartUrl(webStartLaunchServletUrl);
137         jvSettings.setShowSeqFeatures(showSeqFeatures);
138         jsonAlignmentPojo.setJalviewSettings(jvSettings);
139       }
140
141       if (jsonExportSettings.isExportAnnotations())
142       {
143         jsonAlignmentPojo
144                 .setAlignAnnotation(annotationToJsonPojo(annotations));
145       }
146
147       if (jsonExportSettings.isExportSequenceFeatures())
148       {
149         jsonAlignmentPojo.setSeqFeatures(sequenceFeatureToJsonPojo(seqs,
150                 getDisplayedFeatures()));
151       }
152
153       if (jsonExportSettings.isExportGroups() && seqGroups != null
154               && seqGroups.size() > 0)
155       {
156         for (SequenceGroup seqGrp : seqGroups)
157         {
158           SequenceGrpPojo seqGrpPojo = new SequenceGrpPojo();
159           seqGrpPojo.setGroupName(seqGrp.getName());
160           seqGrpPojo.setColourScheme(ColourSchemeProperty
161                   .getColourName(seqGrp.cs));
162           seqGrpPojo.setColourText(seqGrp.getColourText());
163           seqGrpPojo.setDescription(seqGrp.getDescription());
164           seqGrpPojo.setDisplayBoxes(seqGrp.getDisplayBoxes());
165           seqGrpPojo.setDisplayText(seqGrp.getDisplayText());
166           seqGrpPojo.setEndRes(seqGrp.getEndRes());
167           seqGrpPojo.setStartRes(seqGrp.getStartRes());
168           seqGrpPojo.setShowNonconserved(seqGrp.getShowNonconserved());
169           for (SequenceI seq : seqGrp.getSequences())
170           {
171             seqGrpPojo.getSeqsHash().add(
172                     seq.getName() + "_" + seq.hashCode());
173           }
174           jsonAlignmentPojo.getSeqGroups().add(seqGrpPojo);
175         }
176       }
177       com.json.JSONObject generatedJSon = new com.json.JSONObject(
178               jsonAlignmentPojo);
179       String jsonOutput = generatedJSon.toString();
180       return jsonOutput.replaceAll("xstart", "xStart").replaceAll("xend",
181               "xEnd");
182     } catch (Exception e)
183     {
184       e.printStackTrace();
185       throw e;
186     }
187   }
188
189   public static List<SequenceFeaturesPojo> sequenceFeatureToJsonPojo(
190           List<SequenceI> seqs, FeaturesDisplayedI displayedFeatures)
191   {
192     List<SequenceFeaturesPojo> sequenceFeaturesPojo = new ArrayList<SequenceFeaturesPojo>();
193     for (SequenceI seq : seqs)
194     {
195       SequenceI dataSetSequence = seq.getDatasetSequence();
196       SequenceFeature[] seqFeatures = (dataSetSequence == null) ? null
197               : seq.getDatasetSequence().getSequenceFeatures();
198
199       if (seqFeatures == null)
200       {
201         continue;
202       }
203
204       for (SequenceFeature sf : seqFeatures)
205       {
206         if (displayedFeatures != null
207                 && displayedFeatures.isVisible(sf.getType()))
208         {
209           SequenceFeaturesPojo jsonFeature = new SequenceFeaturesPojo(
210                   seq.getName() + "_" + seq.hashCode());
211           jsonFeature.setXstart(seq.findIndex(sf.getBegin()) - 1);
212           jsonFeature.setXend(seq.findIndex(sf.getEnd()));
213           jsonFeature.setType(sf.getType());
214           jsonFeature.setDescription(sf.getDescription());
215           jsonFeature.setLinks(sf.links);
216           jsonFeature.setOtherDetails(sf.otherDetails);
217           jsonFeature.setScore(sf.getScore());
218           jsonFeature.setFeatureGroup(sf.getFeatureGroup());
219           sequenceFeaturesPojo.add(jsonFeature);
220         }
221       }
222     }
223     return sequenceFeaturesPojo;
224   }
225
226   public static List<AlignmentAnnotationPojo> annotationToJsonPojo(
227           Vector<AlignmentAnnotation> annotations)
228   {
229     List<AlignmentAnnotationPojo> jsonAnnotations = new ArrayList<AlignmentAnnotationPojo>();
230     if (annotations == null)
231     {
232       return jsonAnnotations;
233     }
234     for (AlignmentAnnotation annot : annotations)
235     {
236       AlignmentAnnotationPojo alignAnnotPojo = new AlignmentAnnotationPojo();
237       alignAnnotPojo.setDescription(annot.description);
238       alignAnnotPojo.setLabel(annot.label);
239       for (Annotation annotation : annot.annotations)
240       {
241         AnnotationPojo annotationPojo = new AnnotationPojo();
242         if (annotation != null)
243         {
244           annotationPojo.setDescription(annotation.description);
245           annotationPojo.setValue(annotation.value);
246           annotationPojo
247                   .setSecondaryStructure(annotation.secondaryStructure);
248           annotationPojo.setDisplayCharacter(annotation.displayCharacter);
249           alignAnnotPojo.getAnnotations().add(annotationPojo);
250         }
251         else
252         {
253           alignAnnotPojo.getAnnotations().add(annotationPojo);
254         }
255       }
256       jsonAnnotations.add(alignAnnotPojo);
257     }
258     return jsonAnnotations;
259   }
260
261   @SuppressWarnings("unchecked")
262   public JSONFile parse(String jsonAlignmentString)
263   {
264     try
265     {
266       JSONParser jsonParser = new JSONParser();
267       JSONObject alignmentJsonObj = (JSONObject) jsonParser
268               .parse(jsonAlignmentString);
269       JSONArray seqJsonArray = (JSONArray) alignmentJsonObj.get("seqs");
270       JSONArray alAnnotJsonArray = (JSONArray) alignmentJsonObj
271               .get("alignAnnotation");
272       JSONArray jsonSeqArray = (JSONArray) alignmentJsonObj
273               .get("seqFeatures");
274       JSONArray seqGrpJsonArray = (JSONArray) alignmentJsonObj
275               .get("seqGroups");
276       JSONObject jvSettingsJsonObj = (JSONObject) alignmentJsonObj
277               .get("jalviewSettings");
278
279       if (jvSettingsJsonObj != null)
280       {
281         String jsColourScheme = (String) jvSettingsJsonObj
282                 .get("globalColorScheme");
283         Boolean showFeatures = Boolean.valueOf(jvSettingsJsonObj.get(
284                 "showSeqFeatures").toString());
285         setColourScheme(getJalviewColorScheme(jsColourScheme));
286         JSONFile.setSeqFeaturesEnabled(showFeatures);
287       }
288
289       seqMap = new Hashtable<String, Sequence>();
290       for (Iterator<JSONObject> sequenceIter = seqJsonArray.iterator(); sequenceIter
291               .hasNext();)
292       {
293         JSONObject sequence = sequenceIter.next();
294         String sequcenceString = sequence.get("seq").toString();
295         String sequenceName = sequence.get("name").toString();
296         String seqUniqueId = sequence.get("id").toString();
297         int start = Integer.valueOf(sequence.get("start").toString());
298         int end = Integer.valueOf(sequence.get("end").toString());
299         Sequence seq = new Sequence(sequenceName, sequcenceString, start,
300                 end);
301         seqs.add(seq);
302         seqMap.put(seqUniqueId, seq);
303       }
304       parseFeatures(jsonSeqArray);
305
306       for (Iterator<JSONObject> seqGrpIter = seqGrpJsonArray.iterator(); seqGrpIter
307               .hasNext();)
308       {
309         JSONObject seqGrpObj = seqGrpIter.next();
310         String grpName = seqGrpObj.get("groupName").toString();
311         String colourScheme = seqGrpObj.get("colourScheme").toString();
312         String description = (seqGrpObj.get("description") == null) ? null
313                 : seqGrpObj.get("description").toString();
314         boolean displayBoxes = Boolean.valueOf(seqGrpObj
315                 .get("displayBoxes").toString());
316         boolean displayText = Boolean.valueOf(seqGrpObj.get("displayText")
317                 .toString());
318         boolean colourText = Boolean.valueOf(seqGrpObj.get("colourText")
319                 .toString());
320         boolean showNonconserved = Boolean.valueOf(seqGrpObj.get(
321                 "showNonconserved").toString());
322         int startRes = Integer
323                 .valueOf(seqGrpObj.get("startRes").toString());
324         int endRes = Integer.valueOf(seqGrpObj.get("endRes").toString());
325         JSONArray seqsHashArray = (JSONArray) seqGrpObj.get("seqsHash");
326
327         ArrayList<SequenceI> grpSeqs = new ArrayList<SequenceI>();
328         if (seqsHashArray.size() > 0)
329         {
330           Iterator<String> seqHashIter = seqsHashArray.iterator();
331           while (seqHashIter.hasNext())
332           {
333             String seqHash = seqHashIter.next();
334             Sequence sequence = seqMap.get(seqHash);
335             if (sequence != null)
336             {
337               grpSeqs.add(sequence);
338             }
339           }
340         }
341         ColourSchemeI scheme = getJalviewColorScheme(colourScheme);
342         SequenceGroup seqGrp = new SequenceGroup(grpSeqs, grpName, scheme,
343                 displayBoxes, displayText, colourText, startRes, endRes);
344         seqGrp.setShowNonconserved(showNonconserved);
345         seqGrp.setDescription(description);
346         this.seqGroups.add(seqGrp);
347
348       }
349
350       for (Iterator<JSONObject> alAnnotIter = alAnnotJsonArray.iterator(); alAnnotIter
351               .hasNext();)
352       {
353         JSONObject alAnnot = alAnnotIter.next();
354         JSONArray annotJsonArray = (JSONArray) alAnnot.get("annotations");
355         Annotation[] annotations = new Annotation[annotJsonArray.size()];
356         int count = 0;
357         for (Iterator<JSONObject> annotIter = annotJsonArray.iterator(); annotIter
358                 .hasNext();)
359         {
360           JSONObject annot = annotIter.next();
361           if (annot == null)
362           {
363             annotations[count] = null;
364           }
365           else
366           {
367             float val = annot.get("value") == null ? null : Float
368                     .valueOf(annot.get("value").toString());
369             String desc = annot.get("description") == null ? null : annot
370                     .get("description").toString();
371
372             char ss = annot.get("secondaryStructure") == null ? null
373                     : annot.get("secondaryStructure").toString().charAt(0);
374             String displayChar = annot.get("displayCharacter").toString();
375
376             annotations[count] = new Annotation(displayChar, desc, ss, val);
377           }
378           ++count;
379         }
380
381         AlignmentAnnotation alignAnnot = new AlignmentAnnotation(alAnnot
382                 .get("label").toString(), alAnnot.get("description")
383                 .toString(), annotations);
384         this.annotations.add(alignAnnot);
385       }
386
387     } catch (Exception e)
388     {
389       e.printStackTrace();
390     }
391     return this;
392   }
393
394
395   @SuppressWarnings("unchecked")
396   private void parseFeatures(JSONArray jsonSeqFeatures)
397   {
398     if (jsonSeqFeatures != null)
399     {
400       for (Iterator<JSONObject> seqFeatureItr = jsonSeqFeatures.iterator(); seqFeatureItr
401               .hasNext();)
402       {
403         JSONObject jsonFeature = seqFeatureItr.next();
404         Long begin = (Long) jsonFeature.get("xStart");
405         Long end = (Long) jsonFeature.get("xEnd");
406         String type = (String) jsonFeature.get("type");
407         String featureGrp = (String) jsonFeature.get("featureGroup");
408         String descripiton = (String) jsonFeature.get("description");
409         String seqRef = (String) jsonFeature.get("sequenceRef");
410         Float score = Float.valueOf(jsonFeature.get("score").toString());
411         // Hashtable otherDetails = (Hashtable) jsonFeature
412         // .get("otherDetails");
413         // sequenceFeature.otherDetails = otherDetails;
414
415         Sequence seq = seqMap.get(seqRef);
416         SequenceFeature sequenceFeature = new SequenceFeature();
417         JSONArray linksJsonArray = (JSONArray) jsonFeature.get("links");
418         if (linksJsonArray != null && linksJsonArray.size() > 0)
419         {
420           Iterator<String> linkList = linksJsonArray.iterator();
421           while (linkList.hasNext())
422           {
423             String link = linkList.next();
424             sequenceFeature.addLink(link);
425           }
426         }
427         sequenceFeature.setFeatureGroup(featureGrp);
428         sequenceFeature.setScore(score);
429         sequenceFeature.setDescription(descripiton);
430         sequenceFeature.setType(type);
431         sequenceFeature.setBegin(seq.findPosition(begin.intValue()));
432         sequenceFeature.setEnd(seq.findPosition(end.intValue()) - 1);
433         seq.addSequenceFeature(sequenceFeature);
434       }
435     }
436   }
437
438   public ColourSchemeI getJalviewColorScheme(String bioJsColourSchemeName)
439   {
440     ColourSchemeI jalviewColor = null;
441     for (JalviewBioJsColorSchemeMapper cs : JalviewBioJsColorSchemeMapper
442             .values())
443     {
444       if (cs.getBioJsName().equalsIgnoreCase(bioJsColourSchemeName))
445       {
446         jalviewColor = cs.getJvColourScheme();
447         break;
448       }
449     }
450     return jalviewColor;
451   }
452
453   public void LoadAlignmentFeatures(AlignFrame af)
454   {
455     af.setShowSeqFeatures(JSONFile.isSeqFeaturesEnabled());
456     af.changeColour(getColourScheme());
457     af.setMenusForViewport();
458   }
459
460   public String getGlobalColorScheme()
461   {
462     return globalColorScheme;
463   }
464
465   public void setGlobalColorScheme(String globalColorScheme)
466   {
467     this.globalColorScheme = globalColorScheme;
468   }
469
470   public static ColourSchemeI getColourScheme()
471   {
472     return colourScheme;
473   }
474
475   public static void setColourScheme(ColourSchemeI colourScheme)
476   {
477     JSONFile.colourScheme = colourScheme;
478   }
479
480   public static boolean isSeqFeaturesEnabled()
481   {
482     return seqFeaturesEnabled;
483   }
484
485   public static void setSeqFeaturesEnabled(boolean seqFeaturesEnabled)
486   {
487     JSONFile.seqFeaturesEnabled = seqFeaturesEnabled;
488   }
489
490   public FeaturesDisplayedI getDisplayedFeatures()
491   {
492     return displayedFeatures;
493   }
494
495   public void setDisplayedFeatures(FeaturesDisplayedI displayedFeatures)
496   {
497     this.displayedFeatures = displayedFeatures;
498   }
499
500   public JSONExportSettings getJsonExportSettings()
501   {
502     return jsonExportSettings;
503   }
504
505   public void setJsonExportSettings(JSONExportSettings jsonExportSettings)
506   {
507     this.jsonExportSettings = jsonExportSettings;
508   }
509
510   public class JSONExportSettings
511   {
512     private boolean exportSequence;
513
514     private boolean exportSequenceFeatures;
515
516     private boolean exportAnnotations;
517
518     private boolean exportGroups;
519
520     private boolean exportJalviewSettings;
521
522     public boolean isExportSequence()
523     {
524       return exportSequence;
525     }
526
527     public void setExportSequence(boolean exportSequence)
528     {
529       this.exportSequence = exportSequence;
530     }
531
532     public boolean isExportSequenceFeatures()
533     {
534       return exportSequenceFeatures;
535     }
536
537     public void setExportSequenceFeatures(boolean exportSequenceFeatures)
538     {
539       this.exportSequenceFeatures = exportSequenceFeatures;
540     }
541
542     public boolean isExportAnnotations()
543     {
544       return exportAnnotations;
545     }
546
547     public void setExportAnnotations(boolean exportAnnotations)
548     {
549       this.exportAnnotations = exportAnnotations;
550     }
551
552     public boolean isExportGroups()
553     {
554       return exportGroups;
555     }
556
557     public void setExportGroups(boolean exportGroups)
558     {
559       this.exportGroups = exportGroups;
560     }
561
562     public boolean isExportJalviewSettings()
563     {
564       return exportJalviewSettings;
565     }
566
567     public void setExportJalviewSettings(boolean exportJalviewSettings)
568     {
569       this.exportJalviewSettings = exportJalviewSettings;
570     }
571   }
572 }