need to own lock to notify
[jalview.git] / src / jalview / javascript / JSFunctionExec.java
1 package jalview.javascript;
2
3 import java.net.URL;
4 import java.util.Vector;
5
6 import netscape.javascript.JSException;
7 import netscape.javascript.JSObject;
8 import jalview.bin.JalviewLite;
9
10 public class JSFunctionExec implements Runnable
11 {
12   JalviewLite jvlite;
13
14   public JSFunctionExec(JalviewLite applet)
15   {
16     jvlite = applet;
17   }
18
19   private static Vector jsExecQueue;
20
21   private static Thread executor = null;
22
23   public static void stopQueue()
24   {
25     if (jsExecQueue != null)
26     {
27       synchronized (jsExecQueue)
28       {
29         Vector q = jsExecQueue;
30         q.removeAllElements();
31         jsExecQueue = null;
32         executor.notify();
33       }
34       executor = null;
35     }
36   }
37
38   public void run()
39   {
40     while (jsExecQueue != null)
41     {
42       if (jsExecQueue.size() > 0)
43       {
44         Runnable r = (Runnable) jsExecQueue.elementAt(0);
45         jsExecQueue.removeElementAt(0);
46         try
47         {
48           r.run();
49         } catch (Exception ex)
50         {
51           ex.printStackTrace();
52         } catch (Error ex)
53         {
54           ex.printStackTrace();
55         }
56       }
57       else
58       {
59         try
60         {
61           synchronized (jsExecQueue)
62           {
63             jsExecQueue.wait(1000);
64           }
65         } catch (Exception ex)
66         {
67         }
68         ;
69       }
70     }
71
72   }
73
74   /**
75    * execute a javascript callback asynchronously
76    * 
77    * @param _listener
78    * @param objects
79    * @throws Exception
80    */
81   public void executeJavascriptFunction(final String _listener,
82           final Object[] objects) throws Exception
83   {
84     executeJavascriptFunction(false, _listener, objects);
85   }
86
87   /**
88    * execute a javascript callback synchronously or asynchronously
89    * 
90    * @param async
91    *          - true to execute asynchronously (do this for gui events)
92    * @param _listener
93    *          - javascript function
94    * @param objects
95    *          - arguments
96    * @throws Exception
97    *           - only if call is synchronous
98    */
99   public void executeJavascriptFunction(final boolean async,
100           final String _listener, Object[] arguments) throws Exception
101   {
102
103     executeJavascriptFunction(async, _listener, arguments, null);
104
105   }
106
107   public void executeJavascriptFunction(final boolean async,
108           final String _listener, Object[] arguments, final String dbgMsg)
109           throws Exception
110   {
111     final Object[] objects = new Object[arguments != null ? arguments.length
112             : 0];
113     if (arguments != null)
114     {
115       System.arraycopy(arguments, 0, objects, 0, arguments.length);
116     }
117     final Exception[] jsex = new Exception[1];
118     Runnable exec = new Runnable()
119     {
120       public void run()
121       {
122         try
123         {
124           JSObject scriptObject = null;
125           try
126           {
127             scriptObject = JSObject.getWindow(jvlite);
128           } catch (Exception ex)
129           {
130           }
131           ;
132           if (scriptObject != null)
133           {
134             if (jvlite.debug && dbgMsg != null)
135             {
136               System.err.println(dbgMsg);
137             }
138             scriptObject.call(_listener, objects);
139           }
140         } catch (Exception jex)
141         {
142           // squash any malformedURLExceptions thrown by windows/safari
143           if (!(jex instanceof java.net.MalformedURLException))
144           {
145             if (jvlite.debug)
146             {
147               System.err.println(jex);
148             }
149             if (jex instanceof netscape.javascript.JSException)
150             {
151               jsex[0] = (netscape.javascript.JSException) jex;
152               if (jvlite.debug)
153               {
154                 System.err.println("Falling back to javascript: url call");
155               }
156               StringBuffer sb = new StringBuffer("javascript:" + _listener
157                       + "(");
158               for (int i = 0; objects != null && i < objects.length; i++)
159               {
160                 if (i > 0)
161                 {
162                   sb.append(",");
163                 }
164                 sb.append("\"");
165                 // strip out nulls and complex objects that we can't pass this
166                 // way.
167                 if (objects[i] != null
168                         && !(objects[i].getClass().getName()
169                                 .indexOf("jalview") == 0))
170                 {
171                   sb.append(objects[i].toString());
172                 }
173                 sb.append("\"");
174               }
175               sb.append(")");
176               if (jvlite.debug)
177               {
178                 System.err.println(sb.toString());
179               }
180               // alternate
181               URL url = null;
182               try
183               {
184                 url = new URL(sb.toString());
185                 jvlite.getAppletContext().showDocument(url);
186                 jex = null;
187               } catch (Exception uex)
188               {
189                 jex = uex;
190               }
191             }
192             if (jex != null)
193             {
194               if (async)
195               {
196                 jex.printStackTrace();
197               }
198               else
199               {
200                 jsex[0] = jex;
201               }
202             }
203             ;
204           }
205
206         }
207       }
208     };
209     if (async)
210     {
211       if (JSFunctionExec.executor == null)
212       {
213         JSFunctionExec.jsExecQueue = new Vector();
214         JSFunctionExec.executor = new Thread(new JSFunctionExec(jvlite));
215         executor.start();
216       }
217       synchronized (jsExecQueue)
218       {
219         jsExecQueue.addElement(exec);
220         jsExecQueue.notify();
221       }
222     }
223     else
224     {
225       exec.run();
226       if (jsex[0] != null)
227       {
228         throw (jsex[0]);
229       }
230     }
231   }
232
233 }