blob: 323e7104f57c321780c76279ec6590fb3ab259ae [file] [log] [blame]
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.gwt.dev.shell;
import com.google.gwt.dev.shell.BrowserChannel.InvokeOnServerMessage;
import com.google.gwt.dev.shell.BrowserChannel.JavaObjectRef;
import com.google.gwt.dev.shell.BrowserChannel.ReturnMessage;
import com.google.gwt.dev.shell.BrowserChannel.Value;
import com.google.gwt.dev.shell.BrowserChannel.SessionHandler.ExceptionOrReturnValue;
import net.sourceforge.htmlunit.corejs.javascript.Context;
import net.sourceforge.htmlunit.corejs.javascript.Function;
import net.sourceforge.htmlunit.corejs.javascript.Scriptable;
import net.sourceforge.htmlunit.corejs.javascript.ScriptableObject;
import net.sourceforge.htmlunit.corejs.javascript.Undefined;
import java.io.IOException;
/**
* Class to encapsulate JavaObject on the server side.
*/
public class JavaObject extends ScriptableObject implements Function {
private static final long serialVersionUID = -7923090130737830902L;
private static final ExceptionOrReturnValue DEFAULT_VALUE = new ExceptionOrReturnValue(
true, new Value());
public static JavaObject getOrCreateJavaObject(JavaObjectRef javaRef,
SessionData sessionData, Context context) {
return sessionData.getSessionHandler().getOrCreateJavaObject(
javaRef.getRefid(), context);
}
/**
* @param cx the Context
*/
static ExceptionOrReturnValue getReturnFromJavaMethod(Context cx,
HtmlUnitSessionHandler sessionHandler, BrowserChannelClient channel,
int dispatchId, Value thisValue, Value valueArgs[]) {
synchronized (sessionHandler.getSynchronizationObject()) {
try {
new InvokeOnServerMessage(channel, dispatchId, thisValue, valueArgs).send();
} catch (IOException e) {
return DEFAULT_VALUE;
}
try {
ReturnMessage returnMessage = channel.reactToMessagesWhileWaitingForReturn(sessionHandler);
return new ExceptionOrReturnValue(returnMessage.isException(),
returnMessage.getReturnValue());
} catch (IOException e) {
return DEFAULT_VALUE;
} catch (BrowserChannelException e) {
return DEFAULT_VALUE;
}
}
}
/**
* @param jsContext the Context
*/
static boolean isJavaObject(Context jsContext, ScriptableObject javaObject) {
return javaObject instanceof JavaObject;
}
private Context jsContext;
private final int objectRef;
private final SessionData sessionData;
public JavaObject(Context jsContext, SessionData sessionData, int objectRef) {
this.objectRef = objectRef;
this.sessionData = sessionData;
this.jsContext = jsContext;
}
/*
* If this function fails for any reason, we return Undefined instead of
* throwing an Exception in all cases except when Java throws an Exception.
*/
public Object call(Context cx, Scriptable scope, Scriptable thisObj,
Object[] args) {
if (args.length < 2) {
return Undefined.instance;
}
Value valueArgs[] = new Value[args.length - 2];
for (int i = 0; i < valueArgs.length; i++) {
valueArgs[i] = sessionData.getSessionHandler().makeValueFromJsval(cx,
args[i + 2]);
}
/**
* Called when the JavaObject is invoked as a function. We ignore the
* thisObj argument, which is usually the window object.
*
* Returns a JS array, with the first element being a boolean indicating
* that an exception occured, and the second element is either the return
* value or the exception which was thrown. In this case, we always return
* false and raise the exception ourselves.
*/
Value thisValue = sessionData.getSessionHandler().makeValueFromJsval(cx,
args[1]);
int dispatchId = ((Number) args[0]).intValue();
ExceptionOrReturnValue returnValue = getReturnFromJavaMethod(cx,
sessionData.getSessionHandler(), sessionData.getChannel(), dispatchId,
thisValue, valueArgs);
/*
* Return a object array ret. ret[0] is a boolean indicating whether an
* exception was thrown or not. ret[1] is the exception or the return value.
*/
Object ret[] = new Object[2];
ret[0] = returnValue.isException();
ret[1] = sessionData.getSessionHandler().makeJsvalFromValue(cx,
returnValue.getReturnValue());
return ret;
}
public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
throw Context.reportRuntimeError("JavaObject can't be used as a "
+ "constructor");
}
// ignoring the 'start' argument.
@Override
public Object get(int index, Scriptable start) {
Value value = ServerMethods.getProperty(sessionData.getChannel(),
sessionData.getSessionHandler(), objectRef, index);
return sessionData.getSessionHandler().makeJsvalFromValue(jsContext, value);
}
// ignoring the 'start' argument.
@Override
public Object get(String name, Scriptable start) {
if ("toString".equals(name)) {
return sessionData.getSessionHandler().getToStringTearOff(jsContext);
}
if ("id".equals(name)) {
return objectRef;
}
if ("__noSuchMethod__".equals(name)) {
return Undefined.instance;
}
System.err.println("Unknown property name in get " + name);
return Undefined.instance;
}
@Override
public String getClassName() {
return "Class JavaObject";
}
@Override
public void put(int dispatchId, Scriptable start, Object value) {
HtmlUnitSessionHandler sessionHandler = sessionData.getSessionHandler();
if (!ServerMethods.setProperty(sessionData.getChannel(), sessionHandler,
objectRef, dispatchId, sessionHandler.makeValueFromJsval(jsContext,
value))) {
// TODO: fix later.
throw new RuntimeException("setProperty failed");
}
}
int getRefId() {
return objectRef;
}
}