temp push
[jalview.git] / src / jalview / javascript / JSFunctionExec.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.javascript;
22
23 import jalview.api.JalviewApp;
24
25 import java.net.URL;
26 import java.util.Hashtable;
27 import java.util.Vector;
28
29 import netscape.javascript.JSObject;
30
31 public class JSFunctionExec implements Runnable
32 {
33   public JalviewApp jvlite;
34
35   protected boolean debug;
36
37   public JSFunctionExec(JalviewApp applet, boolean debug)
38   {
39     jvlite = applet;
40     this.debug = debug;
41     jsExecQueue = jvlite.getJsExecQueue(this);
42   }
43
44   private Vector<Runnable> jsExecQueue;
45
46   private Thread executor = null;
47
48   public void stopQueue()
49   {
50     if (jsExecQueue != null)
51     {
52       Vector<Runnable> q = null;
53       synchronized (jsExecQueue)
54       {
55         q = jsExecQueue;
56         jsExecQueue = null;
57       }
58       if (q != null)
59       {
60         for (Runnable jx : q)
61         {
62           ((JSFunctionExec) jx).jvlite = null;
63
64         }
65         q.removeAllElements();
66         synchronized (q)
67         {
68           q.notifyAll();
69         }
70       }
71     }
72     jvlite = null;
73     executor = null;
74   }
75
76   @Override
77   public void run()
78   {
79     while (jsExecQueue != null)
80     {
81       if (jsExecQueue.size() > 0)
82       {
83         Runnable r = jsExecQueue.elementAt(0);
84         jsExecQueue.removeElementAt(0);
85         try
86         {
87           r.run();
88         } catch (Exception ex)
89         {
90           ex.printStackTrace();
91         } catch (Error ex)
92         {
93           ex.printStackTrace();
94         }
95       }
96       else
97       {
98         try
99         {
100           synchronized (jsExecQueue)
101           {
102             jsExecQueue.wait(1000);
103           }
104         } catch (Exception ex)
105         {
106         }
107         ;
108       }
109     }
110
111   }
112
113   /**
114    * execute a javascript callback synchronously
115    * 
116    * @param _listener
117    * @param objects
118    * @throws Exception
119    */
120   public void executeJavascriptFunction(final String _listener,
121           final Object[] objects) throws Exception
122   {
123     executeJavascriptFunction(false, _listener, objects);
124   }
125
126   /**
127    * execute a javascript callback synchronously or asynchronously
128    * 
129    * @param async
130    *          - true to execute asynchronously (do this for gui events)
131    * @param _listener
132    *          - javascript function
133    * @param objects
134    *          - arguments
135    * @throws Exception
136    *           - only if call is synchronous
137    */
138   public void executeJavascriptFunction(final boolean async,
139           final String _listener, Object[] arguments) throws Exception
140   {
141
142     executeJavascriptFunction(async, _listener, arguments, null);
143
144   }
145
146   public void executeJavascriptFunction(final boolean async,
147           final String _listener, Object[] arguments, final String dbgMsg)
148           throws Exception
149   {
150     final Object[] objects = new Object[arguments != null ? arguments.length
151             : 0];
152     if (arguments != null)
153     {
154       System.arraycopy(arguments, 0, objects, 0, arguments.length);
155     }
156     final Exception[] jsex = new Exception[1];
157     Runnable exec = new Runnable()
158     {
159       @Override
160       public void run()
161       {
162         try
163         {
164           JSObject scriptObject = null;
165           try
166           {
167             scriptObject = jvlite.getJSObject();
168           } catch (Exception ex)
169           {
170           }
171           ;
172           if (scriptObject != null)
173           {
174             if (debug && dbgMsg != null)
175             {
176               System.err.println(dbgMsg);
177             }
178             scriptObject.call(_listener, objects);
179           }
180         } catch (Exception jex)
181         {
182           // squash any malformedURLExceptions thrown by windows/safari
183           if (!(jex instanceof java.net.MalformedURLException))
184           {
185             if (debug)
186             {
187               System.err.println(jex);
188             }
189             if (jex instanceof netscape.javascript.JSException
190                     && jvlite.isJsfallbackEnabled())
191             {
192               jsex[0] = jex;
193               if (debug)
194               {
195                 System.err.println("Falling back to javascript: url call");
196               }
197               StringBuffer sb = new StringBuffer(
198                       "javascript:" + _listener + "(");
199               for (int i = 0; objects != null && i < objects.length; i++)
200               {
201                 if (i > 0)
202                 {
203                   sb.append(",");
204                 }
205                 sb.append("\"");
206                 // strip out nulls and complex objects that we can't pass this
207                 // way.
208                 if (objects[i] != null && !(objects[i].getClass().getName()
209                         .indexOf("jalview") == 0))
210                 {
211                   sb.append(objects[i].toString());
212                 }
213                 sb.append("\"");
214               }
215               sb.append(")");
216               if (debug)
217               {
218                 System.err.println(sb.toString());
219               }
220               // alternate
221               URL url = null;
222               try
223               {
224                 url = new URL(sb.toString());
225                 jvlite.getAppletContext().showDocument(url);
226                 jex = null;
227               } catch (Exception uex)
228               {
229                 jex = uex;
230               }
231             }
232             if (jex != null)
233             {
234               if (async)
235               {
236                 jex.printStackTrace();
237               }
238               else
239               {
240                 jsex[0] = jex;
241               }
242             }
243             ;
244           }
245
246         }
247       }
248     };
249     if (async)
250     {
251       if (executor == null)
252       {
253         executor = new Thread(new JSFunctionExec(jvlite, debug));
254         executor.start();
255       }
256       synchronized (jsExecQueue)
257       {
258         jsExecQueue.addElement(exec);
259         jsExecQueue.notify();
260       }
261     }
262     else
263     {
264       // wat for executor to notify us if it's running.
265       exec.run();
266       if (jsex[0] != null)
267       {
268         throw (jsex[0]);
269       }
270     }
271   }
272
273   public static void setJsMessageSet(String messageclass, String viewId,
274           String[] colcommands, JalviewApp app)
275   {
276     Hashtable<String, Hashtable<String, String[]>> jsmessages = app
277             .getJSMessages();
278     Hashtable<String, int[]> jshashes = app.getJSHashes();
279
280     Hashtable<String, String[]> msgset = jsmessages.get(messageclass);
281     if (msgset == null)
282     {
283       msgset = new Hashtable<>();
284       jsmessages.put(messageclass, msgset);
285     }
286     msgset.put(viewId, colcommands);
287     int[] l = new int[colcommands.length];
288     for (int i = 0; i < colcommands.length; i++)
289     {
290       l[i] = colcommands[i].hashCode();
291     }
292     jshashes.put(messageclass + "|" + viewId, l);
293   }
294
295   /*
296    * (non-Javadoc)
297    * 
298    * @see jalview.bin.JalviewLiteJsApi#getJsMessage(java.lang.String,
299    * java.lang.String)
300    */
301   public static String getJsMessage(String messageclass, String viewId,
302           JalviewApp app)
303   {
304     Hashtable<String, String[]> msgset = app.getJSMessages()
305             .get(messageclass);
306     if (msgset != null)
307     {
308       String[] msgs = msgset.get(viewId);
309       if (msgs != null)
310       {
311         for (int i = 0; i < msgs.length; i++)
312         {
313           if (msgs[i] != null)
314           {
315             String m = msgs[i];
316             msgs[i] = null;
317             return m;
318           }
319         }
320       }
321     }
322     return "";
323   }
324
325   public static boolean isJsMessageSetChanged(String string, String string2,
326           String[] colcommands, JalviewApp app)
327   {
328     int[] l = app.getJSHashes().get(string + "|" + string2);
329     if (l == null && colcommands != null)
330     {
331       return true;
332     }
333     for (int i = 0; i < colcommands.length; i++)
334     {
335       if (l[i] != colcommands[i].hashCode())
336       {
337         return true;
338       }
339     }
340     return false;
341   }
342
343   public void tidyUp()
344   {
345     stopQueue();
346     jvlite = null;
347   }
348
349 }