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