Merge branch 'releases/Release_2_11_4_Branch'
[jalview.git] / javascript / JSFunctionExec.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
3  * Copyright (C) 2014 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 java.net.URL;
24 import java.util.Vector;
25
26 import netscape.javascript.JSObject;
27 import jalview.bin.JalviewLite;
28
29 public class JSFunctionExec implements Runnable
30 {
31   public JalviewLite jvlite;
32
33   public JSFunctionExec(JalviewLite applet)
34   {
35     jvlite = applet;
36
37     jsExecQueue = jvlite.getJsExecQueue();
38     jvlite.setExecutor(this);
39   }
40
41   public void finalize()
42   {
43     jvlite = null;
44     executor = null;
45     if (jsExecQueue != null)
46     {
47       jsExecQueue.clear();
48     }
49     jsExecQueue = null;
50   }
51
52   private Vector jsExecQueue;
53
54   private Thread executor = null;
55
56   public void stopQueue()
57   {
58     if (jsExecQueue != null)
59     {
60       Vector<JSFunctionExec> q = null;
61       synchronized (jsExecQueue)
62       {
63         q = jsExecQueue;
64         jsExecQueue = null;
65       }
66       if (q != null)
67       {
68         for (JSFunctionExec jx : q)
69         {
70           jx.jvlite = null;
71
72         }
73         q.removeAllElements();
74         synchronized (q)
75         {
76           q.notifyAll();
77         }
78       }
79     }
80     jvlite = null;
81     executor = null;
82   }
83
84   public void run()
85   {
86     while (jsExecQueue != null)
87     {
88       if (jsExecQueue.size() > 0)
89       {
90         Runnable r = (Runnable) jsExecQueue.elementAt(0);
91         jsExecQueue.removeElementAt(0);
92         try
93         {
94           r.run();
95         } catch (Exception ex)
96         {
97           ex.printStackTrace();
98         } catch (Error ex)
99         {
100           ex.printStackTrace();
101         }
102       }
103       else
104       {
105         try
106         {
107           synchronized (jsExecQueue)
108           {
109             jsExecQueue.wait(1000);
110           }
111         } catch (Exception ex)
112         {
113         }
114         ;
115       }
116     }
117
118   }
119
120   /**
121    * execute a javascript callback synchronously
122    * 
123    * @param _listener
124    * @param objects
125    * @throws Exception
126    */
127   public void executeJavascriptFunction(final String _listener,
128           final Object[] objects) throws Exception
129   {
130     executeJavascriptFunction(false, _listener, objects);
131   }
132
133   /**
134    * execute a javascript callback synchronously or asynchronously
135    * 
136    * @param async
137    *          - true to execute asynchronously (do this for gui events)
138    * @param _listener
139    *          - javascript function
140    * @param objects
141    *          - arguments
142    * @throws Exception
143    *           - only if call is synchronous
144    */
145   public void executeJavascriptFunction(final boolean async,
146           final String _listener, Object[] arguments) throws Exception
147   {
148
149     executeJavascriptFunction(async, _listener, arguments, null);
150
151   }
152
153   public void executeJavascriptFunction(final boolean async,
154           final String _listener, Object[] arguments, final String dbgMsg)
155           throws Exception
156   {
157     final Object[] objects = new Object[arguments != null ? arguments.length
158             : 0];
159     if (arguments != null)
160     {
161       System.arraycopy(arguments, 0, objects, 0, arguments.length);
162     }
163     final Exception[] jsex = new Exception[1];
164     Runnable exec = new Runnable()
165     {
166       public void run()
167       {
168         try
169         {
170           JSObject scriptObject = null;
171           try
172           {
173             scriptObject = JSObject.getWindow(jvlite);
174           } catch (Exception ex)
175           {
176           }
177           ;
178           if (scriptObject != null)
179           {
180             if (jvlite.debug && dbgMsg != null)
181             {
182               System.err.println(dbgMsg);
183             }
184             scriptObject.call(_listener, objects);
185           }
186         } catch (Exception jex)
187         {
188           // squash any malformedURLExceptions thrown by windows/safari
189           if (!(jex instanceof java.net.MalformedURLException))
190           {
191             if (jvlite.debug)
192             {
193               System.err.println(jex);
194             }
195             if (jex instanceof netscape.javascript.JSException
196                     && jvlite.jsfallbackEnabled)
197             {
198               jsex[0] = (netscape.javascript.JSException) jex;
199               if (jvlite.debug)
200               {
201                 System.err.println("Falling back to javascript: url call");
202               }
203               StringBuffer sb = new StringBuffer("javascript:" + _listener
204                       + "(");
205               for (int i = 0; objects != null && i < objects.length; i++)
206               {
207                 if (i > 0)
208                 {
209                   sb.append(",");
210                 }
211                 sb.append("\"");
212                 // strip out nulls and complex objects that we can't pass this
213                 // way.
214                 if (objects[i] != null
215                         && !(objects[i].getClass().getName()
216                                 .indexOf("jalview") == 0))
217                 {
218                   sb.append(objects[i].toString());
219                 }
220                 sb.append("\"");
221               }
222               sb.append(")");
223               if (jvlite.debug)
224               {
225                 System.err.println(sb.toString());
226               }
227               // alternate
228               URL url = null;
229               try
230               {
231                 url = new URL(sb.toString());
232                 jvlite.getAppletContext().showDocument(url);
233                 jex = null;
234               } catch (Exception uex)
235               {
236                 jex = uex;
237               }
238             }
239             if (jex != null)
240             {
241               if (async)
242               {
243                 jex.printStackTrace();
244               }
245               else
246               {
247                 jsex[0] = jex;
248               }
249             }
250             ;
251           }
252
253         }
254       }
255     };
256     if (async)
257     {
258       if (executor == null)
259       {
260         executor = new Thread(new JSFunctionExec(jvlite));
261         executor.start();
262       }
263       synchronized (jsExecQueue)
264       {
265         jsExecQueue.addElement(exec);
266         jsExecQueue.notify();
267       }
268     }
269     else
270     {
271       // wat for executor to notify us if it's running.
272       exec.run();
273       if (jsex[0] != null)
274       {
275         throw (jsex[0]);
276       }
277     }
278   }
279
280 }