Package org.gwtnode.dev.debug

Source Code of org.gwtnode.dev.debug.SessionHandler$InvokeResult

/*
* Copyright 2011 Chad Retz
*
* 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 org.gwtnode.dev.debug;

import java.util.HashMap;
import java.util.Map;

import org.gwtnode.core.JavaScriptReturningFunction;
import org.gwtnode.core.JavaScriptUtils;
import org.gwtnode.core.node.Global;
import org.gwtnode.core.node.NodeJsError;
import org.gwtnode.core.node.vm.Vm;
import org.gwtnode.dev.debug.message.FreeValueMessage;
import org.gwtnode.dev.debug.message.SpecialMethod;
import org.gwtnode.dev.debug.message.Value;
import org.gwtnode.dev.debug.message.ValueType;

import com.google.gwt.core.client.JavaScriptException;
import com.google.gwt.core.client.JavaScriptObject;

/**
* OOHPM session handler
*
* @author Chad Retz
*/
class SessionHandler {
   
    private final Vm vm = Vm.get();
    private final Map<Integer, JavaScriptReturningFunction<?>> javaInvokeFunctions =
            new HashMap<Integer, JavaScriptReturningFunction<?>>();
    private final Map<Integer, JavaScriptReturningFunction<?>> tearOffs =
            new HashMap<Integer, JavaScriptReturningFunction<?>>();
    private final ObjectCache objectCache = new ObjectCache();
    private final HostChannel channel;
    private final DebugLog log;
   
    public SessionHandler(HostChannel channel, DebugLog log) {
        this.channel = channel;
        this.log = log;
        //could start a REPL here too...
        //Repl.get().start();
        initContext();
    }
   
    public DebugLog getLog() {
        return log;
    }
   
    @SuppressWarnings("unchecked")
    private <T extends JavaScriptObject> T runInContext(String code) {
        log.debug("Executing code in context:\n%s", code);
        return (T) vm.runInThisContext(code);
    }
   
    private void initContext() {
        try {
            initGlobalContext();
            initJavaInvokeMethods();
        } catch (Exception e) {
            log.debug("Error initializing");
            throw new DebugRuntimeException("Error initializing context", e);
        }
    }
   
    private native void initGlobalContext() /*-{
        global['window'] = global;
    }-*/;

    private native void initJavaInvokeMethods() /*-{
        //TODO: fix this...I hate this
        global['__gwtnode_sessionHandler'] = this;
        global['__gwt_makeJavaInvoke'] = function(paramCount) {
            var thisRef = global['__gwtnode_sessionHandler'];
            return thisRef.@org.gwtnode.dev.debug.SessionHandler::makeJavaInvoke(I)(paramCount);
        };
        global['__gwt_makeTearOff'] = function(proxy, dispId, paramCount) {
            var thisRef = global['__gwtnode_sessionHandler'];
            return thisRef.@org.gwtnode.dev.debug.SessionHandler::makeTearOff(II)(dispId, paramCount);
        };
    }-*/;
   
    @SuppressWarnings("rawtypes")
    private JavaScriptReturningFunction<?> makeJavaInvoke(int paramCount) {
        JavaScriptReturningFunction<?> ret = javaInvokeFunctions.get(paramCount);
        if (ret == null) {
            ret = new JavaInvoker(channel, this, paramCount).getNativeFunction();
            javaInvokeFunctions.put(paramCount, ret);
        }
        return ret;
    }
   
    @SuppressWarnings("rawtypes")
    private JavaScriptReturningFunction<?> makeTearOff(
            int dispId, int paramCount) {
        JavaScriptReturningFunction<?> ret = tearOffs.get(paramCount);
        if (ret == null) {
            ret = new TearOff(channel, this, paramCount).getNativeFunction();
            tearOffs.put(paramCount, ret);
        }
        return ret;
    }
   
    public void end() {
        channel.disconnectFromHost();
    }
   
    public void disconnectDetected() {
        try {
            runInContext("__gwt_disconnected();");
        } catch (Exception e) {
            throw new DebugRuntimeException("Error disconnecting", e);
        }
    }
   
    public void fatalError(String message) {
        log.error("Fatal error: " + message);
    }
   
    public void freeJavaObject(int id) {
        objectCache.freeJavaObject(id);
    }
   
    public void sendFreeValues() {
        channel.sendMessage(new FreeValueMessage(objectCache.getJavaObjectsToFree().toArray(new Integer[0])));
        objectCache.clearJavaObjectsToFree();
    }
   
    public void freeValues(Integer... ids) {
        for (int id : ids) {
            objectCache.freeJavaScriptObject(id);
        }
    }
   
    Value<?> getValueFromJavaScriptObject(Object jsObject) {
        ValueType type = ValueType.values()[getValueTypeOrdinalFromJavaScriptObject(jsObject)];
        if (type == ValueType.JAVA_OBJECT) {
            Integer val = objectCache.getJavaObjectId((JavaScriptObject) jsObject);
            if (val != null) {
                return type.createValueFromObject(val);
            } else {
                return ValueType.JAVA_SCRIPT_OBJECT.createValueFromObject(
                        objectCache.getJavaScriptObjectId((JavaScriptObject) jsObject, true));
            }
        } else {
            return type.createValueFromObject(jsObject);
        }
    }
   
    Object getJavaScriptObjectFromValue(Value<?> val) {
        switch (val.getType()) {
        case JAVA_OBJECT:
            log.debug("Getting Java object reference");
            return objectCache.getJavaObjectReference((Integer) val.getValue(), true);
        case JAVA_SCRIPT_OBJECT:
            log.debug("Getting JavaScript object reference");
            return objectCache.getJavaScriptObject((Integer) val.getValue());
        default:
            return val.getValue();
        }
    }
   
    private native int getValueTypeOrdinalFromJavaScriptObject(Object obj) /*-{
        if (obj === undefined) {
            return 12;
        } else if (obj === null) {
            return 0;
        } else {
            var typ = typeof obj;
            switch(typ) {
                case 'boolean':
                    return 1;
                case 'string':
                    return 9;
                case 'number':
                    if (obj.toString() != obj.toFixed(0).toString()) {
                        return 8;
                    } else {
                        return 5;
                    }
                case 'object':
                case 'function':
                    return 10;
                default:
                    throw new Error('Unrecognized type: ' + typ);
            }
        }
    }-*/;
   
    public InvokeResult invoke(String methodName, Value<?> thisObj, Value<?>... args) {
        JavaScriptReturningFunction<Object> function;
        log.debug("Getting 'this'");
        Object nativeThis = getJavaScriptObjectFromValue(thisObj);
        if (nativeThis != null) {
            function = JavaScriptUtils.getProperty((JavaScriptObject) nativeThis, methodName).cast();
        } else {
            log.debug("Using global object");
            function = JavaScriptUtils.getProperty(Global.get(), methodName).cast();
        }
        log.debug("Got object");
        log.debug("Got function: ", function);
        Object result;
        boolean exception = false;
        try {
            log.debug("Loading %d native arguments", args.length);
            Object[] nativeArgs = new Object[args.length];
            for (int i = 0; i < args.length; i++) {
                nativeArgs[i] = getJavaScriptObjectFromValue(args[i]);
            }
            log.debug("Getting make invoke");
            log.debug("Invoking function");
            result = function.apply(nativeArgs);
            log.debug("Invocation complete: " + result);
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.debug("Exception occurred %s", JavaScriptUtils.
                        appendException(e, new StringBuilder()));
            }
            if (e instanceof JavaScriptException) {
                result = ((JavaScriptException) e).getException();
            } else {
                result = NodeJsError.create("Ahh!");
            }
            exception = true;
        }
        return new InvokeResult(getValueFromJavaScriptObject(result), exception);
    }

    public InvokeResult invokeSpecial(SpecialMethod specialMethod, Value<?>... args) {
        throw new UnsupportedOperationException("InvokeSpecial not implemented");
    }
   
    public void loadJsni(String jsCode) {
        try {
            runInContext(jsCode);
        } catch (Exception e) {
            throw new DebugRuntimeException("Error loading JSNI", e);
        }
    }
   
    public static class InvokeResult {
        private final Value<?> value;
        private final boolean exception;
       
        private InvokeResult(Value<?> value, boolean exception) {
            this.value = value;
            this.exception = exception;
        }
       
        public Value<?> getValue() {
            return value;
        }
       
        public boolean isException() {
            return exception;
        }
    }
}
TOP

Related Classes of org.gwtnode.dev.debug.SessionHandler$InvokeResult

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.