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