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