Merge branch 'develop' into Release_2_9_0b1_Branch
[jalview.git] / src / jalview / io / BioJsHTMLOutput.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.9)
3  * Copyright (C) 2015 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.json.binding.biojs.BioJSReleasePojo;
28 import jalview.json.binding.biojs.BioJSRepositoryPojo;
29 import jalview.util.MessageManager;
30
31 import java.io.BufferedInputStream;
32 import java.io.BufferedReader;
33 import java.io.File;
34 import java.io.IOException;
35 import java.io.InputStream;
36 import java.io.InputStreamReader;
37 import java.io.PrintWriter;
38 import java.net.URISyntaxException;
39 import java.net.URL;
40 import java.util.Objects;
41 import java.util.TreeMap;
42
43 public class BioJsHTMLOutput
44 {
45   private AlignmentViewPanel ap;
46
47   private static File currentBJSTemplateFile;
48
49   private static TreeMap<String, File> bioJsMSAVersions;
50
51   public static final String DEFAULT_DIR = System.getProperty("user.home")
52           + File.separatorChar + ".biojs_templates" + File.separatorChar;
53
54   public static final String BJS_TEMPLATES_LOCAL_DIRECTORY = jalview.bin.Cache
55           .getDefault("biojs_template_directory", DEFAULT_DIR);
56
57   public static final String BJS_TEMPLATE_GIT_REPO = jalview.bin.Cache
58           .getDefault(
59                   "biojs_template_git_repo",
60                   "https://raw.githubusercontent.com/jalview/exporter-templates/master/biojs/package.json");
61
62   public BioJsHTMLOutput(AlignmentViewPanel ap)
63   {
64     if (ap != null)
65     {
66       this.ap = ap;
67     }
68   }
69
70   public void exportJalviewAlignmentAsBioJsHtmlFile()
71   {
72     try
73     {
74       String outputFile = getOutputFile();
75       // String jalviewAlignmentJson = JSONFile.getJSONData(ap);
76       AlignExportSettingI exportSettings = new AlignExportSettingI()
77       {
78         @Override
79         public boolean isExportHiddenSequences()
80         {
81           return true;
82         }
83
84         @Override
85         public boolean isExportHiddenColumns()
86         {
87           return true;
88         }
89
90         @Override
91         public boolean isExportAnnotations()
92         {
93           return true;
94         }
95
96         @Override
97         public boolean isExportFeatures()
98         {
99           return true;
100         }
101
102         @Override
103         public boolean isExportGroups()
104         {
105           return true;
106         }
107
108         @Override
109         public boolean isCancelled()
110         {
111           return false;
112         }
113
114       };
115       AlignmentExportData exportData = jalview.gui.AlignFrame
116               .getAlignmentForExport(JSONFile.FILE_DESC,
117                       ap.getAlignViewport(), exportSettings);
118       String bioJSON = new FormatAdapter(ap,
119               exportData.getSettings()).formatSequences(JSONFile.FILE_DESC,
120               exportData.getAlignment(), exportData.getOmitHidden(),
121               exportData.getStartEndPostions(), ap.getAlignViewport()
122                       .getColumnSelection());
123
124       String bioJSTemplateString = getBioJsTemplateAsString();
125       String generatedBioJsWithJalviewAlignmentAsJson = bioJSTemplateString
126               .replaceAll("#sequenceData#", bioJSON)
127               .toString();
128
129       PrintWriter out = new java.io.PrintWriter(new java.io.FileWriter(
130               outputFile));
131       out.print(generatedBioJsWithJalviewAlignmentAsJson);
132       out.flush();
133       out.close();
134       jalview.util.BrowserLauncher.openURL("file:///" + outputFile);
135     } catch (NoFileSelectedException ex)
136     {
137       // do noting if no file was selected
138     } catch (Exception e)
139     {
140       e.printStackTrace();
141     }
142   }
143
144   public String getOutputFile() throws NoFileSelectedException
145   {
146     String selectedFile = null;
147     JalviewFileChooser jvFileChooser = new JalviewFileChooser(
148             jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
149             new String[] { "html" }, new String[] { "HTML files" },
150             "HTML files");
151     jvFileChooser.setFileView(new JalviewFileView());
152
153     jvFileChooser.setDialogTitle(MessageManager
154             .getString("label.save_as_biojs_html"));
155     jvFileChooser.setToolTipText(MessageManager.getString("action.save"));
156
157     int fileChooserOpt = jvFileChooser.showSaveDialog(null);
158     if (fileChooserOpt == JalviewFileChooser.APPROVE_OPTION)
159     {
160       jalview.bin.Cache.setProperty("LAST_DIRECTORY", jvFileChooser
161               .getSelectedFile().getParent());
162       selectedFile = jvFileChooser.getSelectedFile().getPath();
163     }
164     else
165     {
166       throw new NoFileSelectedException("No file was selected.");
167     }
168     return selectedFile;
169   }
170
171   public static String getBioJsTemplateAsString() throws IOException
172   {
173     InputStreamReader isReader = null;
174     BufferedReader buffReader = null;
175     StringBuilder sb = new StringBuilder();
176     Objects.requireNonNull(getCurrentBJSTemplateFile(),
177             "BioJsTemplate File not initialized!");
178     @SuppressWarnings("deprecation")
179     URL url = getCurrentBJSTemplateFile().toURL();
180     if (url != null)
181     {
182       try
183       {
184         isReader = new InputStreamReader(url.openStream());
185         buffReader = new BufferedReader(isReader);
186         String line;
187         String lineSeparator = System.getProperty("line.separator");
188         while ((line = buffReader.readLine()) != null)
189         {
190           sb.append(line).append(lineSeparator);
191         }
192
193       } catch (Exception ex)
194       {
195         ex.printStackTrace();
196       } finally
197       {
198         if (isReader != null)
199         {
200           isReader.close();
201         }
202
203         if (buffReader != null)
204         {
205           buffReader.close();
206         }
207       }
208     }
209     return sb.toString();
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       public void run()
250       {
251         try
252         {
253           String gitRepoPkgJson = getURLContentAsString(BJS_TEMPLATE_GIT_REPO);
254           if (gitRepoPkgJson != null)
255           {
256             BioJSRepositoryPojo release = new BioJSRepositoryPojo(
257                     gitRepoPkgJson);
258             syncUpdates(BJS_TEMPLATES_LOCAL_DIRECTORY, release);
259             refreshBioJSVersionsInfo(BJS_TEMPLATES_LOCAL_DIRECTORY);
260           }
261         } catch (URISyntaxException e)
262         {
263           e.printStackTrace();
264         }
265       }
266     };
267     updateThread.start();
268
269   }
270
271   public static void syncUpdates(String localDir, BioJSRepositoryPojo repo)
272   {
273     for (BioJSReleasePojo bjsRelease : repo.getReleases())
274     {
275       String releaseUrl = bjsRelease.getUrl();
276       String releaseVersion = bjsRelease.getVersion();
277       String releaseFile = "BioJsMSA_" + releaseVersion + ".txt";
278       if (releaseVersion.equals(repo.getLatestReleaseVersion()))
279       {
280         releaseFile = "Latest_BioJsMSA_" + releaseVersion + ".txt";
281       }
282
283       File biojsDirectory = new File(BJS_TEMPLATES_LOCAL_DIRECTORY);
284       if (!biojsDirectory.exists())
285       {
286         if (!biojsDirectory.mkdirs())
287         {
288           System.out.println("Couldn't create local directory : "
289                   + BJS_TEMPLATES_LOCAL_DIRECTORY);
290           return;
291         }
292       }
293
294       File file = new File(BJS_TEMPLATES_LOCAL_DIRECTORY + releaseFile);
295       if (!file.exists())
296       {
297
298         PrintWriter out = null;
299         try
300         {
301           out = new java.io.PrintWriter(new java.io.FileWriter(file));
302           out.print(getURLContentAsString(releaseUrl));
303         } catch (IOException e)
304         {
305           e.printStackTrace();
306         } finally
307         {
308           if (out != null)
309           {
310             out.flush();
311             out.close();
312           }
313         }
314       }
315     }
316
317   }
318
319   public static String getURLContentAsString(String url)
320           throws OutOfMemoryError
321   {
322     StringBuilder responseStrBuilder = null;
323     InputStream is = null;
324     try
325     {
326       URL resourceUrl = new URL(url);
327       is = new BufferedInputStream(resourceUrl.openStream());
328       BufferedReader br = new BufferedReader(new InputStreamReader(is));
329       responseStrBuilder = new StringBuilder();
330       String lineContent;
331
332       while ((lineContent = br.readLine()) != null)
333       {
334         responseStrBuilder.append(lineContent).append("\n");
335       }
336     } catch (OutOfMemoryError er)
337     {
338       er.printStackTrace();
339     } catch (Exception ex)
340     {
341       ex.printStackTrace();
342     } finally
343     {
344       if (is != null)
345       {
346         try
347         {
348           is.close();
349         } catch (IOException e)
350         {
351           e.printStackTrace();
352         }
353       }
354     }
355     return responseStrBuilder == null ? null : responseStrBuilder
356             .toString();
357   }
358
359   public static File getCurrentBJSTemplateFile()
360   {
361     return currentBJSTemplateFile;
362   }
363
364   public static void setCurrentBJSTemplateFile(File currentBJSTemplateFile)
365   {
366     BioJsHTMLOutput.currentBJSTemplateFile = currentBJSTemplateFile;
367   }
368
369   public static TreeMap<String, File> getBioJsMSAVersions()
370   {
371     return bioJsMSAVersions;
372   }
373
374   public static void setBioJsMSAVersions(
375           TreeMap<String, File> bioJsMSAVersions)
376   {
377     BioJsHTMLOutput.bioJsMSAVersions = bioJsMSAVersions;
378   }
379
380 }