1 /*------------------------------------------------------------------------------
  2 Name:      JavascriptCallback.java
  3 Project:   xmlBlaster.org
  4 Copyright: xmlBlaster.org, see xmlBlaster-LICENSE file
  5 ------------------------------------------------------------------------------*/
  6 package org.xmlBlaster.client;
  7 
  8 import org.xmlBlaster.util.XmlBlasterException;
  9 import org.xmlBlaster.util.ReplaceVariable;
 10 import org.xmlBlaster.client.key.UpdateKey;
 11 import org.xmlBlaster.client.qos.UpdateQos;
 12 
 13 import org.mozilla.javascript.Context;
 14 
 15 import org.apache.batik.script.rhino.WindowWrapper;
 16 import org.apache.batik.script.rhino.RhinoInterpreter;
 17 import org.apache.batik.script.Interpreter;
 18 import org.apache.batik.script.Window;
 19 import org.apache.batik.util.RunnableQueue;
 20 
 21 /**
 22  * Forwards callback messages to Javascript code. 
 23  * <p>
 24  * We use this dispatcher for example in the SVG example
 25  * <code>xmlBlaster/demo/javaclients/svg/rhino/chessRhino.svg</code>.
 26  * @author <a href="mailto:michele@laghi.eu">Michele Laghi</a>.
 27  * @see http://xml.apache.org/batik
 28  */
 29 public class JavascriptCallback implements I_Callback
 30 {
 31    private static WindowWrapper javascriptWindow  = null;
 32    private Interpreter interpreter;
 33    private RunnableQueue updateQueue;
 34 
 35    /**
 36     * This constructor is called from Javascript within a SVG document:
 37     * <pre>
 38     * ... // other Javascript code with Rhino live connect
 39     * xmlBlaster.connect(connectQos, new JavascriptCallback(this));
 40     * </pre>
 41     * where this == window (the global object in SVG and HTML browsers)
 42     * and window is of type WindowWrapper.
 43     * The problem is that WindowWrapper has no method to retrieve the
 44     * Javascript context like SVGCanvas or UpdateManager, so we get this
 45     * via the static method getCurrentContext().
 46     *
 47     * @see http://xml.apache.org/batik
 48     * @author laghi
 49     * @author ruff
 50     */
 51    public JavascriptCallback(WindowWrapper javascriptWindow)
 52    {
 53       // http://xml.apache.org/batik/svgcanvas.html
 54       //this.javascriptWindow = org.xmlBlaster.util.Global.instance().getObjectEntry("SVG/Javascript/Interpreter");
 55 
 56       JavascriptCallback.javascriptWindow = javascriptWindow;
 57 
 58       Window window = ((RhinoInterpreter.ExtendedContext)Context.getCurrentContext()).getWindow();
 59       this.updateQueue = window.getBridgeContext().getUpdateManager().getUpdateRunnableQueue();
 60       this.interpreter = window.getInterpreter();
 61 
 62       /*
 63          // Add to svg drawing:
 64          //   function getWindow() {
 65          //     return this;
 66          //   }
 67          // The window handle is returned but it somehow does not work with window.callMethod()
 68 
 69          updateQueue.invokeLater(new Runnable() {
 70             public void run() {
 71                String script = "getWindow();";
 72                try {
 73                   System.out.println("Calling interpreter: '" + script + "'");
 74                   JavascriptCallback.javascriptWindow = (WindowWrapper)interpreter.evaluate(script);
 75                   System.out.println("****JavascriptCallback: GOT WindowWrapper");
 76                }
 77                catch(Throwable ie) { //InterpreterException ie) {
 78                   System.out.println("!!!!!!! Interpreter exception '" + script + ": " + ie.toString());
 79                }
 80             }
 81          });
 82       */
 83       /* blocks forever!?
 84       try {
 85          updateQueue.invokeAndWait(new Runnable() {
 86             public void run() {
 87                String script = "return window";
 88                try {
 89                   System.out.println("Calling interpreter: " + script);
 90                   ScriptableObject obj = (ScriptableObject)interpreter.evaluate(script);
 91                   System.out.println("****JavascriptCallback: GOT WindowWrapper");
 92                }
 93                catch(InterpreterException ie) {
 94                   System.out.println("Interpreter exception '" + script + ": " + ie.toString());
 95                }
 96             }
 97          });
 98       }
 99       catch(InterruptedException ie) {
100          System.out.println("Interpreter exception '" + script + ": " + ie.toString());
101       }
102       */
103 
104       System.out.println("****JavascriptCallback: SUCCESS");
105    }
106 
107    /*
108     * changeElement changes Node Values
109     * JSVGCanvasExtended can = // See xmlBlaster/demo/javaclients/svg/batik
110     * Element ele = can.getElement(id);
111     * @param value contains new Value of element
112     */
113    public void setElementValue(final org.w3c.dom.Element ele, final String value)
114    {
115       if (ele == null || this.updateQueue == null)
116          throw new IllegalArgumentException("JavascriptCallback.setElementValue invalid args: element=" + ele + " updateQueue=" + this.updateQueue);
117 
118       this.updateQueue.invokeLater(new Runnable() {
119          public void run() {
120             org.w3c.dom.Node node = ele.getFirstChild();
121             node.setNodeValue(value);
122          }});
123    }
124 
125    /**
126     * This is the callback method invoked from xmlBlaster
127     * delivering us a new asynchronous message. 
128     *
129     * @param cbSessionId The session ID specified by the client which registered the callback
130     * @param updateKey   The arrived key
131     * @param content     The arrived message content
132     * @param qos         Quality of Service of the MsgUnit
133     *
134     * @see org.xmlBlaster.client.I_Callback#update(String, UpdateKey, byte[], org.xmlBlaster.client.qos.UpdateQos)
135     */
136    public String update(final String cbSessionId, final UpdateKey updateKey,
137                         final byte[] content, final UpdateQos updateQos) throws XmlBlasterException
138    {
139       //System.out.println("*****RECEIVING updateKey=" + updateKey.toXml());
140       String key = ReplaceVariable.replaceAll(updateKey.toXml(), "\n", " ");
141       //key = ReplaceVariable.replaceAll(key, "\"", "\\\"");
142       String con = ReplaceVariable.replaceAll(updateQos.getContentStr(content), "\n", " ");
143       // This code escapes all quotation marks in the XML content.
144       // This is required to fix an error caused when the XML tags include
145       // attributes, which causes an exception to be thrown because of malformed
146       // javascript (in the 'script' variable).
147       // (Paul Wujek Xp2 Telecom Inc.)
148       con = ReplaceVariable.replaceAll(con, "\"", "\\\"");
149       String qos = ReplaceVariable.replaceAll(updateQos.toXml(), "\n", " ");
150       //qos = ReplaceVariable.replaceAll(qos, "\"", "\\\"");
151       final String script =  "update(\"" + cbSessionId + "\", \"" + key + "\", \"" + con + "\", \"" + qos + "\");";
152       //final String script =  "update(\"sdkfjs\", \"<key oid='11A'/>\", \"<chess><id>11A</id><transform>translate(166,210)</transform></chess>\", \"<qos/>\");";
153 
154       // Dispatch the received message to the GUI event thread:
155       updateQueue.invokeLater(new Runnable() {
156          public void run() {
157             try {
158                //System.out.println("Calling interpreter content=" + new String(content));
159                /* This code is much cleaner but it fails with
160                   org.mozilla.javascript.JavaScriptException: java.lang.ClassCastException
161                   The reason is that all global window methods don't work (like alert() or setTimout())
162                Object[] args = new Object[4];
163                args[0] = cbSessionId;
164                args[1] = updateKey;
165                args[2] = new String(content);
166                args[3] = updateQos;
167                javascriptWindow.callMethod(javascriptWindow, "update", args);
168                */
169                interpreter.evaluate(script);
170                /*
171                Context cx = Context.enter();
172                Scriptable scope = cx.initStandardObjects(null);
173 
174                Object fObj = scope.get("f", scope);
175                if (!(fObj instanceof Function)) {
176                    System.out.println("f is undefined or not a function.");
177                } else {
178                    Object functionArgs[] = { "my arg" };
179                    Function f = (Function)fObj;
180                    Object result = f.call(cx, scope, scope, functionArgs);
181                    String report = "f('my args') = " + Context.toString(result);
182                    System.out.println(report);
183                }
184                */
185             }
186             catch (Exception e) {
187                System.out.println("JavascriptCallback update() failed: content=" + new String(content) + ": " + e.toString());
188                //throw new XmlBlasterException(Global.instance(), ErrorCode.USER_UPDATE_ERROR,
189                //             "JavascriptCallback update() failed", e.toString());
190             }
191          }
192       });
193 
194       return "";
195    }
196 
197 }


syntax highlighted by Code2HTML, v. 0.9.1