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