9b6a15a24fc5f0b0eb2d7c5b4a4250ff89169026
[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(String outputFile)
84   {
85     // String outputFile = null;
86     try
87     {
88       if (outputFile == null)
89       {
90         outputFile = getOutputFile();
91       }
92       AlignExportSettingI exportSettings = new AlignExportSettingI()
93       {
94         @Override
95         public boolean isExportHiddenSequences()
96         {
97           return true;
98         }
99
100         @Override
101         public boolean isExportHiddenColumns()
102         {
103           return true;
104         }
105
106         @Override
107         public boolean isExportAnnotations()
108         {
109           return true;
110         }
111
112         @Override
113         public boolean isExportFeatures()
114         {
115           return true;
116         }
117
118         @Override
119         public boolean isExportGroups()
120         {
121           return true;
122         }
123
124         @Override
125         public boolean isCancelled()
126         {
127           return false;
128         }
129
130       };
131       AlignmentExportData exportData = jalview.gui.AlignFrame
132               .getAlignmentForExport(JSONFile.FILE_DESC,
133                       ap.getAlignViewport(), exportSettings);
134       String bioJSON = new FormatAdapter(ap, exportData.getSettings())
135               .formatSequences(JSONFile.FILE_DESC, exportData
136                       .getAlignment(), exportData.getOmitHidden(),
137                       exportData.getStartEndPostions(), ap
138                               .getAlignViewport().getColumnSelection());
139
140       String bioJSTemplateString = HtmlFile.readFileAsString(getCurrentBJSTemplateFile());
141       String generatedBioJsWithJalviewAlignmentAsJson = bioJSTemplateString
142               .replaceAll("#sequenceData#", bioJSON).toString();
143
144       PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter(
145               outputFile));
146       out.print(generatedBioJsWithJalviewAlignmentAsJson);
147       out.flush();
148       out.close();
149       jalview.util.BrowserLauncher.openURL("file:///" + outputFile);
150       if (pIndicator != null && !headless)
151       {
152         pIndicator.setProgressBar(MessageManager.formatMessage(
153                 "status.export_complete", "BioJS"), pSessionId);
154       }
155     } catch (NoFileSelectedException ex)
156     {
157       // do noting if no file was selected
158     } catch (OutOfMemoryError err)
159     {
160       System.out.println("########################\n" + "OUT OF MEMORY "
161               + outputFile + "\n" + "########################");
162       new OOMWarning("Creating Image for " + outputFile, err);
163     } catch (Exception e)
164     {
165       if (pIndicator != null && !headless)
166       {
167       pIndicator.setProgressBar(MessageManager.formatMessage(
168               "info.error_creating_file", "HTML"), pSessionId);
169       }
170       e.printStackTrace();
171     }
172   }
173
174   public String getOutputFile() throws NoFileSelectedException
175   {
176     String selectedFile = null;
177     if (pIndicator != null && !headless)
178     {
179       pIndicator.setProgressBar(MessageManager.formatMessage(
180               "status.waiting_for_user_to_select_output_file", "HTML"),
181               pSessionId);
182     }
183
184     JalviewFileChooser jvFileChooser = new JalviewFileChooser(
185             jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
186             new String[] { "html" }, new String[] { "HTML files" },
187             "HTML files");
188     jvFileChooser.setFileView(new JalviewFileView());
189
190     jvFileChooser.setDialogTitle(MessageManager
191             .getString("label.save_as_biojs_html"));
192     jvFileChooser.setToolTipText(MessageManager.getString("action.save"));
193
194     int fileChooserOpt = jvFileChooser.showSaveDialog(null);
195     if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION)
196     {
197       jalview.bin.Cache.setProperty("LAST_DIRECTORY", jvFileChooser
198               .getSelectedFile().getParent());
199       selectedFile = jvFileChooser.getSelectedFile().getPath();
200     }
201     else
202     {
203       pIndicator.setProgressBar(MessageManager.formatMessage(
204               "status.cancelled_image_export_operation", "BioJS"),
205               pSessionId);
206       throw new NoFileSelectedException("No file was selected.");
207     }
208     return selectedFile;
209   }
210
211
212   public static void refreshBioJSVersionsInfo(String dirName)
213           throws URISyntaxException
214   {
215     File directory = new File(BJS_TEMPLATES_LOCAL_DIRECTORY);
216     Objects.requireNonNull(dirName, "dirName MUST not be null!");
217     Objects.requireNonNull(directory, "directory MUST not be null!");
218     TreeMap<String, File> versionFileMap = new TreeMap<String, File>();
219
220     for (File file : directory.listFiles())
221     {
222       if (file.isFile())
223       {
224         String fileName = file.getName().substring(0,
225                 file.getName().lastIndexOf("."));
226         String fileMeta[] = fileName.split("_");
227         if (fileMeta.length > 2)
228         {
229           setCurrentBJSTemplateFile(file);
230           versionFileMap.put(fileMeta[2], file);
231         }
232         else if (fileMeta.length > 1)
233         {
234           versionFileMap.put(fileMeta[1], file);
235         }
236       }
237     }
238     if (getCurrentBJSTemplateFile() == null && versionFileMap.size() > 0)
239     {
240       setCurrentBJSTemplateFile(versionFileMap.lastEntry().getValue());
241     }
242     setBioJsMSAVersions(versionFileMap);
243   }
244
245   public static void updateBioJS()
246   {
247     Thread updateThread = new Thread()
248     {
249       @Override
250       public void run()
251       {
252         try
253         {
254           String gitRepoPkgJson = getURLContentAsString(BJS_TEMPLATE_GIT_REPO);
255           if (gitRepoPkgJson != null)
256           {
257             BioJSRepositoryPojo release = new BioJSRepositoryPojo(
258                     gitRepoPkgJson);
259             syncUpdates(BJS_TEMPLATES_LOCAL_DIRECTORY, release);
260             refreshBioJSVersionsInfo(BJS_TEMPLATES_LOCAL_DIRECTORY);
261           }
262         } catch (URISyntaxException e)
263         {
264           e.printStackTrace();
265         }
266       }
267     };
268     updateThread.start();
269
270   }
271
272   public static void syncUpdates(String localDir, BioJSRepositoryPojo repo)
273   {
274     for (BioJSReleasePojo bjsRelease : repo.getReleases())
275     {
276       String releaseUrl = bjsRelease.getUrl();
277       String releaseVersion = bjsRelease.getVersion();
278       String releaseFile = "BioJsMSA_" + releaseVersion + ".txt";
279       if (releaseVersion.equals(repo.getLatestReleaseVersion()))
280       {
281         releaseFile = "Latest_BioJsMSA_" + releaseVersion + ".txt";
282       }
283
284       File biojsDirectory = new File(BJS_TEMPLATES_LOCAL_DIRECTORY);
285       if (!biojsDirectory.exists())
286       {
287         if (!biojsDirectory.mkdirs())
288         {
289           System.out.println("Couldn't create local directory : "
290                   + BJS_TEMPLATES_LOCAL_DIRECTORY);
291           return;
292         }
293       }
294
295       File file = new File(BJS_TEMPLATES_LOCAL_DIRECTORY + releaseFile);
296       if (!file.exists())
297       {
298
299         PrintWriter out = null;
300         try
301         {
302           out = new java.io.PrintWriter(new java.io.FileWriter(file));
303           out.print(getURLContentAsString(releaseUrl));
304         } catch (IOException e)
305         {
306           e.printStackTrace();
307         } finally
308         {
309           if (out != null)
310           {
311             out.flush();
312             out.close();
313           }
314         }
315       }
316     }
317
318   }
319
320   public static String getURLContentAsString(String url)
321           throws OutOfMemoryError
322   {
323     StringBuilder responseStrBuilder = null;
324     InputStream is = null;
325     try
326     {
327       URL resourceUrl = new URL(url);
328       is = new BufferedInputStream(resourceUrl.openStream());
329       BufferedReader br = new BufferedReader(new InputStreamReader(is));
330       responseStrBuilder = new StringBuilder();
331       String lineContent;
332
333       while ((lineContent = br.readLine()) != null)
334       {
335         responseStrBuilder.append(lineContent).append("\n");
336       }
337     } catch (OutOfMemoryError er)
338     {
339       er.printStackTrace();
340     } catch (Exception ex)
341     {
342       ex.printStackTrace();
343     } finally
344     {
345       if (is != null)
346       {
347         try
348         {
349           is.close();
350         } catch (IOException e)
351         {
352           e.printStackTrace();
353         }
354       }
355     }
356     return responseStrBuilder == null ? null : responseStrBuilder
357             .toString();
358   }
359
360   public static File getCurrentBJSTemplateFile()
361   {
362     return currentBJSTemplateFile;
363   }
364
365   public static void setCurrentBJSTemplateFile(File currentBJSTemplateFile)
366   {
367     BioJsHTMLOutput.currentBJSTemplateFile = currentBJSTemplateFile;
368   }
369
370   public static TreeMap<String, File> getBioJsMSAVersions()
371   {
372     return bioJsMSAVersions;
373   }
374
375   public static void setBioJsMSAVersions(
376           TreeMap<String, File> bioJsMSAVersions)
377   {
378     BioJsHTMLOutput.bioJsMSAVersions = bioJsMSAVersions;
379   }
380
381 }