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