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.CompilingClassLoader;
019: import com.google.gwt.dev.shell.JsValue;
020: import com.google.gwt.dev.shell.JsValueGlue;
021: import com.google.gwt.dev.shell.ModuleSpace;
022: import com.google.gwt.dev.shell.moz.LowLevelMoz.DispatchMethod;
023:
024: import java.lang.reflect.InvocationTargetException;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Modifier;
027:
028: /**
029: * Wraps an arbitrary Java Method as a Dispatchable component. The class was
030: * motivated by the need to expose Java objects into JavaScript.
031: */
032: class MethodDispatch implements DispatchMethod {
033:
034: private final CompilingClassLoader classLoader;
035:
036: private final Method method;
037:
038: public MethodDispatch(CompilingClassLoader classLoader,
039: Method method) {
040: this .classLoader = classLoader;
041: this .method = method;
042: }
043:
044: /**
045: * Invoke a Java method from JavaScript. This is called solely from native
046: * code.
047: *
048: * @param jsthis JavaScript reference to Java object
049: * @param jsargs array of JavaScript values for parameters
050: * @param returnValue JavaScript value to return result in
051: * @throws RuntimeException if improper arguments are supplied
052: *
053: * TODO(jat): lift most of this interface to platform-independent code (only
054: * exceptions still need to be made platform-independent)
055: */
056: public void invoke(int jsthis Int, int[] jsargsInt,
057: int returnValueInt) {
058: JsValue jsthis = new JsValueMoz(jsthis Int);
059: JsValue jsargs[] = new JsValue[jsargsInt.length];
060: for (int i = 0; i < jsargsInt.length; ++i) {
061: jsargs[i] = new JsValueMoz(jsargsInt[i]);
062: }
063: JsValue returnValue = new JsValueMoz(returnValueInt);
064: Class<?>[] paramTypes = method.getParameterTypes();
065: int argc = paramTypes.length;
066: Object args[] = new Object[argc];
067: // too many arguments are ok: the extra will be silently ignored
068: if (jsargs.length < argc) {
069: throw new RuntimeException("Not enough arguments to "
070: + method);
071: }
072: Object jthis = null;
073: if ((method.getModifiers() & Modifier.STATIC) == 0) {
074: jthis = JsValueGlue.get(jsthis , method.getDeclaringClass(),
075: "invoke this");
076: }
077: for (int i = 0; i < argc; ++i) {
078: args[i] = JsValueGlue.get(jsargs[i], paramTypes[i],
079: "invoke arguments");
080: }
081: try {
082: Object result;
083: try {
084: result = method.invoke(jthis , args);
085: } catch (IllegalAccessException e) {
086: // should never, ever happen
087: e.printStackTrace();
088: throw new RuntimeException(e);
089: }
090: JsValueGlue.set(returnValue, classLoader, method
091: .getReturnType(), result);
092: } catch (InvocationTargetException e) {
093: // If we get here, it means an exception is being thrown from
094: // Java back into JavaScript
095: Throwable t = e.getTargetException();
096: // TODO(jat): if this was originally JavaScript exception, re-throw the
097: // original exception rather than just a null.
098: ModuleSpace.setThrownJavaException(t);
099: LowLevelMoz.raiseJavaScriptException();
100: } catch (IllegalArgumentException e) {
101: // TODO(jat): log to treelogger instead? If so, how do I get to it?
102: System.err.println("MethodDispatch.invoke, method="
103: + method.toString() + ": argument mismatch");
104: for (int i = 0; i < argc; ++i) {
105: System.err.println(" param " + i + " type is "
106: + paramTypes[i].toString() + " value is type "
107: + jsargs[i].getTypeString() + " = "
108: + args[i].toString());
109: }
110: throw e;
111: }
112: }
113: }
|