001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.shell.moz;
017:
018: import com.google.gwt.dev.shell.LowLevel;
019:
020: import java.util.Vector;
021:
022: /**
023: * Various low-level helper methods for dealing with Gecko.
024: */
025: public class LowLevelMoz {
026:
027: /**
028: * Provides interface for methods to be exposed on JavaScript side.
029: */
030: public interface DispatchMethod {
031: /**
032: * Invoke a Java method from JavaScript.
033: *
034: * @param jsthis the wrapped Java object to invoke
035: * @param jsargs an array of JavaScript values to pass as parameters
036: * @param returnValue the JavaScript value in which to store the returned
037: * value
038: */
039: void invoke(int jsthis , int[] jsargs, int returnValue);
040: }
041:
042: /**
043: * Provides interface for objects to be exposed to JavaScript code.
044: */
045: public interface DispatchObject {
046: /**
047: * Retrieve a field from an object.
048: *
049: * @param name the name of the field
050: * @param value pointer to the JsRootedValue to receive the field value
051: */
052: void getField(String name, int value);
053:
054: Object getTarget();
055:
056: /**
057: * Set the value of a field on an object.
058: *
059: * @param name the name of the field
060: * @param value pointer to the JsRootedValue to store into the field
061: */
062: void setField(String name, int value);
063: }
064:
065: interface ExternalFactory {
066: ExternalObject createExternalObject();
067:
068: boolean matchesDOMWindow(int domWindow);
069: }
070:
071: /**
072: * TODO: rip this whole thing out if possible and use DispatchObject like on
073: * Safari.
074: */
075: interface ExternalObject {
076: boolean gwtOnLoad(int scriptGlobalObject, String moduleName);
077: }
078:
079: private static Vector<ExternalFactory> sExternalFactories = new Vector<ExternalFactory>();
080: private static boolean sInitialized = false;
081:
082: /**
083: * Executes JavaScript code, retaining file and line information.
084: *
085: * @param scriptObject An opaque handle to the script frame window
086: * @param code The JavaScript code to execute
087: * @param file A file name associated with the code
088: * @param line A line number associated with the code.
089: */
090: public static void executeScriptWithInfo(int scriptObject,
091: String code, String file, int line) {
092: if (!_executeScriptWithInfo(scriptObject, code, file, line)) {
093: throw new RuntimeException(file + "(" + line
094: + "): Failed to execute script: " + code);
095: }
096: }
097:
098: public static synchronized void init() {
099: // Force LowLevel initialization to load gwt-ll
100: LowLevel.init();
101: if (!sInitialized) {
102: if (!_registerExternalFactoryHandler()) {
103: throw new RuntimeException(
104: "Failed to register external factory handler.");
105: }
106: sInitialized = true;
107: }
108: }
109:
110: /**
111: * Invokes a method implemented in JavaScript.
112: *
113: * @param scriptObject An opaque handle to the script frame window
114: * @param methodName the method name on jsthis to call
115: * @param jsthis A wrapped java object as a JsRootedValue pointer
116: * @param jsargs the arguments to pass to the method as JsRootedValue pointers
117: *
118: * @throws RuntimeException if the invoke fails
119: */
120: public static void invoke(int scriptObject, String methodName,
121: int jsthis , int[] jsargs, int retval) {
122: if (!_invoke(scriptObject, methodName, jsthis , jsargs, retval)) {
123: throw new RuntimeException(
124: "Failed to invoke native method: " + methodName
125: + " with " + jsargs.length + " arguments.");
126: }
127: }
128:
129: /**
130: * Call this to raise an exception in JavaScript before returning control.
131: * Currently, the JavaScript exception throw is always null.
132: */
133: public static void raiseJavaScriptException() {
134: if (!_raiseJavaScriptException()) {
135: throw new RuntimeException(
136: "Failed to raise Java Exception into JavaScript.");
137: }
138: }
139:
140: /**
141: * BrowserWindows register here so that if their contained window gets a call
142: * to window.external, the call can be routed correctly by nsIDOMWindow
143: * pointer.
144: *
145: * @param externalFactory the factory to register
146: */
147: public static void registerExternalFactory(
148: ExternalFactory externalFactory) {
149: synchronized (sExternalFactories) {
150: sExternalFactories.add(externalFactory);
151: }
152: }
153:
154: /**
155: * Unregisters an existing registration.
156: *
157: * @param externalFactory the factory to unregister
158: */
159: public static void unregisterExternalFactory(
160: ExternalFactory externalFactory) {
161: synchronized (sExternalFactories) {
162: sExternalFactories.remove(externalFactory);
163: }
164: }
165:
166: /**
167: * Called from native code to create an external object for a particular
168: * window.
169: *
170: * @param domWindow an nsIDOMWindow to check against our ExternalFactories map
171: * @return a new ExternalObject
172: */
173: protected static ExternalObject createExternalObjectForDOMWindow(
174: int domWindow) {
175: for (ExternalFactory fac : sExternalFactories) {
176: if (fac.matchesDOMWindow(domWindow)) {
177: return fac.createExternalObject();
178: }
179: }
180: return null;
181: }
182:
183: /**
184: * Called from native code to do tracing.
185: *
186: * @param s the string to trace
187: */
188: protected static void trace(String s) {
189: System.out.println(s);
190: System.out.flush();
191: }
192:
193: // CHECKSTYLE_NAMING_OFF: Non JSNI native code may have leading '_'s.
194:
195: private static native boolean _executeScriptWithInfo(
196: int scriptObject, String newScript, String file, int line);
197:
198: /**
199: * Native method for invoking a JavaScript method.
200: *
201: * @param scriptObject nsIScriptGlobalObject* as an int
202: * @param methodName name of JavaScript method
203: * @param jsThisInt JavaScript object to invoke the method on, as a
204: * JsRootedValue int
205: * @param jsArgsInt array of arguments, as an array of JsRootedValue ints
206: * @param jsRetValint pointer to JsRootedValue to receive return value
207: * @return true on success
208: */
209: private static native boolean _invoke(int scriptObject,
210: String methodName, int jsThisInt, int[] jsArgsInt,
211: int jsRetValInt);
212:
213: private static native boolean _raiseJavaScriptException();
214:
215: private static native boolean _registerExternalFactoryHandler();
216:
217: // CHECKSTYLE_NAMING_ON
218:
219: /**
220: * Print debug information for a JS method invocation.
221: *
222: * TODO(jat): remove this method
223: *
224: * @param methodName the name of the JS method being invoked
225: * @param jsthis the JS object with the named method
226: * @param jsargs an array of arguments to the method
227: */
228: @SuppressWarnings("unused")
229: // kept for future debugging purposes
230: private static void printInvocationParams(String methodName,
231: JsValueMoz jsthis , JsValueMoz[] jsargs) {
232: System.out.println("LowLevelMoz.invoke:");
233: System.out.println(" method = " + methodName);
234: System.out.println(" # args = " + (jsargs.length));
235: System.out.println(" jsthis = " + jsthis .toString());
236: for (int i = 0; i < jsargs.length; ++i) {
237: System.out.println(" jsarg[" + i + "] = "
238: + jsargs[i].toString());
239: }
240: System.out.println("");
241: }
242:
243: /**
244: * Not instantiable.
245: */
246: private LowLevelMoz() {
247: }
248: }
|