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