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