JAL-2089 patch broken merge to master for Release 2.10.0b1
[jalview.git] / src / jalview / io / BioJsHTMLOutput.java
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.api.AlignExportSettingI;
24 import jalview.api.AlignmentViewPanel;
25 import jalview.datamodel.AlignmentExportData;
26 import jalview.exceptions.NoFileSelectedException;
27 import jalview.gui.IProgressIndicator;
28 import jalview.gui.OOMWarning;
29 import jalview.json.binding.biojs.BioJSReleasePojo;
30 import jalview.json.binding.biojs.BioJSRepositoryPojo;
31 import jalview.util.MessageManager;
32
33 import java.io.BufferedInputStream;
34 import java.io.BufferedReader;
35 import java.io.File;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.io.InputStreamReader;
39 import java.io.PrintWriter;
40 import java.net.URISyntaxException;
41 import java.net.URL;
42 import java.util.Objects;
43 import java.util.TreeMap;
44
45 public class BioJsHTMLOutput
46 {
47   private AlignmentViewPanel ap;
48
49   private long pSessionId;
50
51   private IProgressIndicator pIndicator;
52
53   private boolean headless;
54
55   private static File currentBJSTemplateFile;
56
57   private static TreeMap<String, File> bioJsMSAVersions;
58
59   public static final String DEFAULT_DIR = System.getProperty("user.home")
60           + File.separatorChar + ".biojs_templates" + File.separatorChar;
61
62   public static final String BJS_TEMPLATES_LOCAL_DIRECTORY = jalview.bin.Cache
63           .getDefault("biojs_template_directory", DEFAULT_DIR);
64
65   public static final String BJS_TEMPLATE_GIT_REPO = jalview.bin.Cache
66           .getDefault(
67                   "biojs_template_git_repo",
68                   "https://raw.githubusercontent.com/jalview/exporter-templates/master/biojs/package.json");
69
70   public BioJsHTMLOutput(AlignmentViewPanel ap,
71           IProgressIndicator pIndicator)
72   {
73     if (ap != null)
74     {
75       this.ap = ap;
76       this.pSessionId = System.currentTimeMillis();
77       this.pIndicator = pIndicator;
78       this.headless = (System.getProperty("java.awt.headless") != null && System
79               .getProperty("java.awt.headless").equals("true"));
80     }
81   }
82
83   public void exportJalviewAlignmentAsBioJsHtmlFile()
84   {
85     String outputFile = null;
86     try
87     {
88       outputFile = getOutputFile();
89       AlignExportSettingI exportSettings = new AlignExportSettingI()
90       {
91         @Override
92         public boolean isExportHiddenSequences()
93         {
94           return true;
95         }
96
97         @Override
98         public boolean isExportHiddenColumns()
99         {
100           return true;
101         }
102
103         @Override
104         public boolean isExportAnnotations()
105         {
106           return true;
107         }
108
109         @Override
110         public boolean isExportFeatures()
111         {
112           return true;
113         }
114
115         @Override
116         public boolean isExportGroups()
117         {
118           return true;
119         }
120
121         @Override
122         public boolean isCancelled()
123         {
124           return false;
125         }
126
127       };
128       AlignmentExportData exportData = jalview.gui.AlignFrame
129               .getAlignmentForExport(JSONFile.FILE_DESC,
130                       ap.getAlignViewport(), exportSettings);
131       String bioJSON = new FormatAdapter(ap, exportData.getSettings())
132               .formatSequences(JSONFile.FILE_DESC, exportData
133                       .getAlignment(), exportData.getOmitHidden(),
134                       exportData.getStartEndPostions(), ap
135                               .getAlignViewport().getColumnSelection());
136
137       String bioJSTemplateString = getBioJsTemplateAsString();
138       String generatedBioJsWithJalviewAlignmentAsJson = bioJSTemplateString
139               .replaceAll("#sequenceData#", bioJSON).toString();
140
141       PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter(
142               outputFile));
143       out.print(generatedBioJsWithJalviewAlignmentAsJson);
144       out.flush();
145       out.close();
146       jalview.util.BrowserLauncher.openURL("file:///" + outputFile);
147       if (pIndicator != null && !headless)
148       {
149         pIndicator.setProgressBar(MessageManager.formatMessage(
150                 "status.export_complete", "BioJS"), pSessionId);
151       }
152     } catch (NoFileSelectedException ex)
153     {
154       // do noting if no file was selected
155     } catch (OutOfMemoryError err)
156     {
157       System.out.println("########################\n" + "OUT OF MEMORY "
158               + outputFile + "\n" + "########################");
159       new OOMWarning("Creating Image for " + outputFile, err);
160     } catch (Exception e)
161     {
162       pIndicator.setProgressBar(MessageManager.formatMessage(
163               "info.error_creating_file", "HTML"), pSessionId);
164       e.printStackTrace();
165     }
166   }
167
168   public String getOutputFile() throws NoFileSelectedException
169   {
170     String selectedFile = null;
171     if (pIndicator != null && !headless)
172     {
173       pIndicator.setProgressBar(MessageManager.formatMessage(
174               "status.waiting_for_user_to_select_output_file", "HTML"),
175               pSessionId);
176     }
177
178     JalviewFileChooser jvFileChooser = new JalviewFileChooser(
179             jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
180             new String[] { "html" }, new String[] { "HTML files" },
181             "HTML files");
182     jvFileChooser.setFileView(new JalviewFileView());
183
184     jvFileChooser.setDialogTitle(MessageManager
185             .getString("label.save_as_biojs_html"));
186     jvFileChooser.setToolTipText(MessageManager.getString("action.save"));
187
188     int fileChooserOpt = jvFileChooser.showSaveDialog(null);
189     if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION)
190     {
191       jalview.bin.Cache.setProperty("LAST_DIRECTORY", jvFileChooser
192               .getSelectedFile().getParent());
193       selectedFile = jvFileChooser.getSelectedFile().getPath();
194     }
195     else
196     {
197       pIndicator.setProgressBar(MessageManager.formatMessage(
198               "status.cancelled_image_export_operation", "BioJS"),
199               pSessionId);
200       throw new NoFileSelectedException("No file was selected.");
201     }
202     return selectedFile;
203   }
204
205   public static String getBioJsTemplateAsString() throws IOException
206   {
207     InputStreamReader isReader = null;
208     BufferedReader buffReader = null;
209     StringBuilder sb = new StringBuilder();
210     Objects.requireNonNull(getCurrentBJSTemplateFile(),
211             "BioJsTemplate File not initialized!");
212     @SuppressWarnings("deprecation")
213     URL url = getCurrentBJSTemplateFile().toURL();
214     if (url != null)
215     {
216       try
217       {
218         isReader = new InputStreamReader(url.openStream());
219         buffReader = new BufferedReader(isReader);
220         String line;
221         String lineSeparator = System.getProperty("line.separator");
222         while ((line = buffReader.readLine()) != null)
223         {
224           sb.append(line).append(lineSeparator);
225         }
226
227       } catch (Exception ex)
228       {
229         ex.printStackTrace();
230       } finally
231       {
232         if (isReader != null)
233         {
234           isReader.close();
235         }
236
237         if (buffReader != null)
238         {
239           buffReader.close();
240         }
241       }
242     }
243     return sb.toString();
244   }
245
246   public static void refreshBioJSVersionsInfo(String dirName)
247           throws URISyntaxException
248   {
249     File directory = new File(BJS_TEMPLATES_LOCAL_DIRECTORY);
250     Objects.requireNonNull(dirName, "dirName MUST not be null!");
251     Objects.requireNonNull(directory, "directory MUST not be null!");
252     TreeMap<String, File> versionFileMap = new TreeMap<String, File>();
253
254     for (File file : directory.listFiles())
255     {
256       if (file.isFile())
257       {
258         String fileName = file.getName().substring(0,
259                 file.getName().lastIndexOf("."));
260         String fileMeta[] = fileName.split("_");
261         if (fileMeta.length > 2)
262         {
263           setCurrentBJSTemplateFile(file);
264           versionFileMap.put(fileMeta[2], file);
265         }
266         else if (fileMeta.length > 1)
267         {
268           versionFileMap.put(fileMeta[1], file);
269         }
270       }
271     }
272     if (getCurrentBJSTemplateFile() == null && versionFileMap.size() > 0)
273     {
274       setCurrentBJSTemplateFile(versionFileMap.lastEntry().getValue());
275     }
276     setBioJsMSAVersions(versionFileMap);
277   }
278
279   public static void updateBioJS()
280   {
281     Thread updateThread = new Thread()
282     {
283       @Override
284       public void run()
285       {
286         try
287         {
288           String gitRepoPkgJson = getURLContentAsString(BJS_TEMPLATE_GIT_REPO);
289           if (gitRepoPkgJson != null)
290           {
291             BioJSRepositoryPojo release = new BioJSRepositoryPojo(
292                     gitRepoPkgJson);
293             syncUpdates(BJS_TEMPLATES_LOCAL_DIRECTORY, release);
294             refreshBioJSVersionsInfo(BJS_TEMPLATES_LOCAL_DIRECTORY);
295           }
296         } catch (URISyntaxException e)
297         {
298           e.printStackTrace();
299         }
300       }
301     };
302     updateThread.start();
303
304   }
305
306   public static void syncUpdates(String localDir, BioJSRepositoryPojo repo)
307   {
308     for (BioJSReleasePojo bjsRelease : repo.getReleases())
309     {
310       String releaseUrl = bjsRelease.getUrl();
311       String releaseVersion = bjsRelease.getVersion();
312       String releaseFile = "BioJsMSA_" + releaseVersion + ".txt";
313       if (releaseVersion.equals(repo.getLatestReleaseVersion()))
314       {
315         releaseFile = "Latest_BioJsMSA_" + releaseVersion + ".txt";
316       }
317
318       File biojsDirectory = new File(BJS_TEMPLATES_LOCAL_DIRECTORY);
319       if (!biojsDirectory.exists())
320       {
321         if (!biojsDirectory.mkdirs())
322         {
323           System.out.println("Couldn't create local directory : "
324                   + BJS_TEMPLATES_LOCAL_DIRECTORY);
325           return;
326         }
327       }
328
329       File file = new File(BJS_TEMPLATES_LOCAL_DIRECTORY + releaseFile);
330       if (!file.exists())
331       {
332
333         PrintWriter out = null;
334         try
335         {
336           out = new java.io.PrintWriter(new java.io.FileWriter(file));
337           out.print(getURLContentAsString(releaseUrl));
338         } catch (IOException e)
339         {
340           e.printStackTrace();
341         } finally
342         {
343           if (out != null)
344           {
345             out.flush();
346             out.close();
347           }
348         }
349       }
350     }
351
352   }
353
354   public static String getURLContentAsString(String url)
355           throws OutOfMemoryError
356   {
357     StringBuilder responseStrBuilder = null;
358     InputStream is = null;
359     try
360     {
361       URL resourceUrl = new URL(url);
362       is = new BufferedInputStream(resourceUrl.openStream());
363       BufferedReader br = new BufferedReader(new InputStreamReader(is));
364       responseStrBuilder = new StringBuilder();
365       String lineContent;
366
367       while ((lineContent = br.readLine()) != null)
368       {
369         responseStrBuilder.append(lineContent).append("\n");
370       }
371     } catch (OutOfMemoryError er)
372     {
373       er.printStackTrace();
374     } catch (Exception ex)
375     {
376       ex.printStackTrace();
377     } finally
378     {
379       if (is != null)
380       {
381         try
382         {
383           is.close();
384         } catch (IOException e)
385         {
386           e.printStackTrace();
387         }
388       }
389     }
390     return responseStrBuilder == null ? null : responseStrBuilder
391             .toString();
392   }
393
394   public static File getCurrentBJSTemplateFile()
395   {
396     return currentBJSTemplateFile;
397   }
398
399   public static void setCurrentBJSTemplateFile(File currentBJSTemplateFile)
400   {
401     BioJsHTMLOutput.currentBJSTemplateFile = currentBJSTemplateFile;
402   }
403
404   public static TreeMap<String, File> getBioJsMSAVersions()
405   {
406     return bioJsMSAVersions;
407   }
408
409   public static void setBioJsMSAVersions(
410           TreeMap<String, File> bioJsMSAVersions)
411   {
412     BioJsHTMLOutput.bioJsMSAVersions = bioJsMSAVersions;
413   }
414
415 }