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