18be43b13a27c215e70f7ff94baa029b94c83e1c
[jalview.git] / src / jalview / bin / JalviewJS.java
1 package jalview.bin;
2
3 import jalview.analysis.AlignmentUtils;
4 import jalview.datamodel.AlignmentI;
5 import jalview.gui.AlignFrame;
6 import jalview.gui.SplitFrame;
7 import jalview.io.AppletFormatAdapter;
8 import jalview.io.DataSourceType;
9 import jalview.io.FileFormatException;
10 import jalview.io.FileFormatI;
11 import jalview.io.FileLoader;
12 import jalview.io.IdentifyFile;
13 import jalview.structure.StructureSelectionManager;
14
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19
20 import javax.swing.JFrame;
21 import javax.swing.JInternalFrame;
22
23 /**
24  * Entry point for Jalview as Javascript. Expects parameter names as for the
25  * JalviewLite applet, formatted as for the Jalview application, for example
26  * 
27  * <pre>
28  *   JalviewJS file /examples/uniref50.fa features /examples/exampleFeatures.txt \
29  *       PDBFile "/examples/pdb1.txt seq1"
30  * </pre>
31  * 
32  * Note that (unlike the applet) parameter names are case sensitive
33  */
34 // TODO or format as file=/examples/uniref50.fa (etc)?
35 public class JalviewJS
36 {
37   private static final String PARAM_FILE = "file";
38
39   private static final String PARAM_FILE2 = "file2";
40
41   private static final String PARAM_TREE = "tree";
42
43   private static final String PARAM_FEATURES = "features";
44
45   private static final String PARAM_ANNOTATIONS = "annotations";
46
47   private static final String PARAM_SHOW_ANNOTATION = "showAnnotation";
48
49   private static final String PARAM_PDBFILE = "PDBFile";
50
51   private static final String PARAM_PROPS = "props";
52
53   private Map<String, String> params;
54
55   private List<String> pdbFileParams;
56
57   public static void main(String[] args)
58   {
59     try
60     {
61       new JalviewJS().doMain(args);
62     } catch (Throwable e)
63     {
64       e.printStackTrace();
65     }
66   }
67
68   /**
69    * Parses parameters and shows the frame and any loaded panels
70    * 
71    * @throws FileFormatException
72    */
73   void doMain(String[] args) throws FileFormatException
74   {
75     loadParameters(args);
76     if (getParameter(PARAM_FILE) == null)
77     {
78       usage();
79     }
80     else
81     {
82       showFrame();
83     }
84   }
85
86   /**
87    * Answers the value of the given runtime parameter, or null if not provided
88    * 
89    * @param paramName
90    * @return
91    */
92   private String getParameter(String paramName)
93   {
94     return params.get(paramName);
95   }
96
97   /**
98    * Prints a chastising, yet helpful, error message on syserr
99    */
100   private void usage()
101   {
102     System.err.println(
103             "Usage: JalviewJS file <alignmentFile> [features <featuresFile>]");
104     System.err.println("See documentation for full parameter list");
105   }
106
107   /**
108    * Parses any supplied parameters. Note that (unlike for the applet),
109    * parameter names are case sensitive.
110    * 
111    * @param args
112    * 
113    * @see http://www.jalview.org/examples/index.html#appletParameters
114    */
115   void loadParameters(String[] args)
116   {
117     ArgsParser parser = new ArgsParser(args);
118     params = new HashMap<>();
119
120     // TODO javascript-friendly source of properties
121     Cache.loadProperties(parser.getValue(PARAM_PROPS));
122     loadParameter(parser, PARAM_FILE);
123     loadParameter(parser, PARAM_FILE2);
124     loadParameter(parser, PARAM_TREE);
125     loadParameter(parser, PARAM_FEATURES);
126     loadParameter(parser, PARAM_ANNOTATIONS);
127     loadParameter(parser, PARAM_SHOW_ANNOTATION);
128     pdbFileParams = loadPdbParameters(parser);
129   }
130
131   /**
132    * Reads one command line parameter value and saves it against the parameter
133    * name. Note the saved value is null if the parameter is not present.
134    * 
135    * @param parser
136    * @param param
137    */
138   protected void loadParameter(ArgsParser parser, String param)
139   {
140     params.put(param, parser.getValue(param));
141   }
142
143   /**
144    * Reads parameter PDBFile, PDBFile1, PDFile2, ... and saves the value(s) (if
145    * any)
146    * 
147    * @param parser
148    * @return
149    */
150   List<String> loadPdbParameters(ArgsParser parser)
151   {
152     List<String> values = new ArrayList<>();
153     String value = parser.getValue(PARAM_PDBFILE);
154     if (value != null)
155     {
156       values.add(value);
157     }
158     int i = 1;
159     while (true)
160     {
161       value = parser.getValue(PARAM_PDBFILE + String.valueOf(i));
162       if (value != null)
163       {
164         values.add(value);
165       }
166       else
167       {
168         break;
169       }
170     }
171     return values;
172   }
173
174   /**
175    * Constructs and displays a JFrame containing an alignment panel (and any
176    * additional panels depending on parameters supplied)
177    * 
178    * @throws FileFormatException
179    */
180   void showFrame() throws FileFormatException
181   {
182     JFrame frame = new JFrame(getParameter(PARAM_FILE));
183     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
184
185     /*
186      * construct an AlignFrame (optionally with features)
187      */
188     AlignFrame alignFrame = createAlignFrame(PARAM_FILE);
189     loadFeatures(alignFrame, getParameter(PARAM_FEATURES));
190
191     JInternalFrame internalFrame = alignFrame;
192
193     /*
194      * convert to SplitFrame if a valid file2 is supplied
195      */
196     AlignFrame alignFrame2 = createAlignFrame(PARAM_FILE2);
197     if (alignFrame2 != null)
198     {
199       SplitFrame splitFrame = loadSplitFrame(alignFrame, alignFrame2);
200       if (splitFrame != null)
201       {
202         internalFrame = splitFrame;
203       }
204     }
205
206     /*
207      * move AlignFrame (or SplitFrame) menu bar and content pane to our frame
208      * TODO there may be a less obscure way to do this
209      */
210     frame.setContentPane(internalFrame.getContentPane());
211     frame.setJMenuBar(internalFrame.getJMenuBar());
212
213     // fudge so that dialogs can be opened with this frame as parent
214     // todo JAL-3031 also override Desktop.addInternalFrame etc
215     // Desktop.parent = frame.getContentPane();
216
217     frame.pack();
218     frame.setSize(AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
219     frame.setVisible(true);
220   }
221
222   /**
223    * Constructs a SplitFrame if cdna-protein mappings can be made between the
224    * given alignment frames, else returns null. Any mappings made are registered
225    * with StructureSelectionManager to enable broadcast to listeners.
226    * 
227    * @param alignFrame
228    * @param alignFrame2
229    * @return
230    */
231   protected SplitFrame loadSplitFrame(AlignFrame alignFrame,
232           AlignFrame alignFrame2)
233   {
234     // code borrowed from AlignViewport.openLinkedAlignment
235     AlignmentI al1 = alignFrame.getViewport().getAlignment();
236     AlignmentI al2 = alignFrame2.getViewport().getAlignment();
237     boolean al1Nuc = al1.isNucleotide();
238     if (al1Nuc == al2.isNucleotide())
239     {
240       System.err.println("Can't make split frame as alignments are both "
241               + (al1Nuc ? "nucleotide" : "protein"));
242       return null;
243     }
244     AlignmentI protein = al1Nuc ? al2 : al1;
245     AlignmentI cdna = al1Nuc ? al1 : al2;
246     boolean mapped = AlignmentUtils.mapProteinAlignmentToCdna(protein,
247             cdna);
248     if (!mapped)
249     {
250       System.err.println("Can't make any mappings for split frame");
251       return null;
252     }
253
254     /*
255      * register sequence mappings
256      */
257     StructureSelectionManager ssm = StructureSelectionManager
258             .getStructureSelectionManager(null);
259     ssm.registerMappings(protein.getCodonFrames());
260
261     cdna.alignAs(protein);
262
263     SplitFrame splitFrame = new SplitFrame(
264             al1Nuc ? alignFrame : alignFrame2,
265             al1Nuc ? alignFrame2 : alignFrame);
266
267     return splitFrame;
268   }
269
270   /**
271    * Loads on a features file if one was specified as a parameter
272    * 
273    * @param alignFrame
274    * @param featureFile
275    */
276   protected void loadFeatures(AlignFrame alignFrame, String featureFile)
277   {
278     if (featureFile != null)
279     {
280       // todo extract helper for protocol resolution from JalviewLite
281       DataSourceType sourceType = featureFile.startsWith("http")
282               ? DataSourceType.URL
283               : DataSourceType.FILE;
284       alignFrame.parseFeaturesFile(featureFile, sourceType);
285     }
286   }
287
288   /**
289    * Constructs and returns the frame containing the alignment and its
290    * annotations. Returns null if the specified parameter value is not set.
291    * 
292    * @param fileParam
293    * 
294    * @return
295    * @throws FileFormatException
296    */
297   AlignFrame createAlignFrame(String fileParam) throws FileFormatException
298   {
299     AlignFrame af = null;
300     String file = getParameter(fileParam);
301     if (file != null)
302     {
303       DataSourceType protocol = AppletFormatAdapter.checkProtocol(file);
304       FileFormatI format = new IdentifyFile().identify(file, protocol);
305       FileLoader fileLoader = new FileLoader(false);
306       af = fileLoader.LoadFileWaitTillLoaded(file, protocol, format);
307     }
308
309     return af;
310   }
311
312 }