Package org.gwtnode.dev.debug

Source Code of org.gwtnode.dev.debug.HostChannel

/*
* 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.Stack;

import org.gwtnode.core.JavaScriptUtils;
import org.gwtnode.core.node.buffer.Buffer;
import org.gwtnode.core.node.event.ParameterlessEventHandler;
import org.gwtnode.core.node.event.StringOrBufferEventHandler;
import org.gwtnode.core.node.net.Socket;
import org.gwtnode.dev.debug.BufferStream.StreamIndexOutOfBoundsException;
import org.gwtnode.dev.debug.SessionHandler.InvokeResult;
import org.gwtnode.dev.debug.message.CheckVersionsMessage;
import org.gwtnode.dev.debug.message.FatalErrorMessage;
import org.gwtnode.dev.debug.message.FreeValueMessage;
import org.gwtnode.dev.debug.message.InvokeFromClientMessage;
import org.gwtnode.dev.debug.message.InvokeToClientMessage;
import org.gwtnode.dev.debug.message.LoadJsniMessage;
import org.gwtnode.dev.debug.message.LoadModuleMessage;
import org.gwtnode.dev.debug.message.Message;
import org.gwtnode.dev.debug.message.MessageType;
import org.gwtnode.dev.debug.message.ProtocolVersionMessage;
import org.gwtnode.dev.debug.message.QuitMessage;
import org.gwtnode.dev.debug.message.ReturnMessage;

/**
* Channel for communicating w/ GWT code server
*
* @author Chad Retz
*/
class HostChannel {

    private static final int MINIMUM_PROTOCOL_VERSION = 2;
    private static final int MAXIMUM_PROTOCOL_VERSION = 2;
    private static final String HOSTED_HTML_VERSION = "2.1";

    private final String moduleName;
    private final String host;
    private final int port;
    private Socket socket;
    private final BufferStream stream = new BufferStream();
    private SessionHandler session;
    private MessageCallback nextMessageCallback;
    private final Stack<ReturnMessageCallback> returnMessageCallbacks = new Stack<ReturnMessageCallback>();
   
    public HostChannel(String moduleName, String host, int port) {
        this.moduleName = moduleName;
        this.host = host;
        this.port = port;
    }
   
    public void start(SessionHandler sess) {
        this.session = sess;
        if (socket != null) {
            session.getLog().debug("Disconnecting previous channel");
            disconnectFromHost();
        }
        socket = Socket.create();
        socket.onData(new StringOrBufferEventHandler() {
            @Override
            protected void onEvent() {
                try {
                    session.getLog().debug("Got buffer");
                    stream.append(getBuffer());
                    //grab a message
                    Message message;
                    do {
                        message = getNextMessage();
                        if (message != null) {
                            if (session.getLog().isDebugEnabled()) {
                                session.getLog().debug("Received message: %s", message.toString());
                            }
                            handleMessage(message);
                        }
                    } while (message != null);
                    session.getLog().debug("Still have %d bytes available",
                            stream.getBufferLength());
                } catch (Exception e) {
                    session.getLog().error("Error: %s", JavaScriptUtils.
                            appendException(e, new StringBuilder()));
                }
            }
        });
        socket.connect(port, host, new ParameterlessEventHandler() {
            @Override
            public void onEvent() {
                session.getLog().debug("Channel connection complete");
                init();
            }
        });
    }
   
    private void init() {
        session.getLog().debug("Initializing...");
        sendMessage(new CheckVersionsMessage(MINIMUM_PROTOCOL_VERSION,
                MAXIMUM_PROTOCOL_VERSION, HOSTED_HTML_VERSION), new MessageCallback() {
                    @Override
                    public void onMessage(Message message) {
                        if (message instanceof FatalErrorMessage) {
                            session.fatalError(((FatalErrorMessage) message).getError());
                            end();
                        } else if (message instanceof ProtocolVersionMessage) {
                            //yay!
                            //my session and my tab are one based on the current ms and a random number
                            String keyPrefix = Long.toHexString(System.currentTimeMillis()) +
                                    "_" + Integer.toHexString((int) (Math.random() * Integer.MAX_VALUE));
                            sendMessage(new LoadModuleMessage(
                                    //the URL is not really a URL, but rather my host and port
                                    "gwt-node-debug://" + host + ":" + port,
                                    "tab_" + keyPrefix,
                                    "session_" + keyPrefix,
                                    moduleName,
                                    "gwt-node/0.0.1"));
                        } else {
                            throw new IllegalStateException("Unexpected message type: " + message.getType());
                        }
                    }
                });
    }
   
    private void handleMessage(Message message) {
        try {
            if (nextMessageCallback != null) {
                MessageCallback callback = nextMessageCallback;
                nextMessageCallback = null;
                callback.onMessage(message);
            } else {
                switch (message.getType()) {
                case LOAD_JSNI:
                    session.loadJsni(((LoadJsniMessage) message).getJsCode());
                    break;
                case FREE_VALUE:
                    session.freeValues(((FreeValueMessage) message).getRefIds());
                    break;
                case INVOKE:
                    InvokeToClientMessage invokeMessage = (InvokeToClientMessage) message;
                    InvokeResult result = session.invoke(
                            invokeMessage.getMethodName(), invokeMessage.getThisValue(), invokeMessage.getArgValues());
                    sendMessage(new ReturnMessage(result.isException(), result.getValue()));
                    break;
                case RETURN:
                    ReturnMessage returnMessage = (ReturnMessage) message;
                    if (returnMessageCallbacks.isEmpty()) {
                        session.getLog().error("Unexpected return message");
                    } else {
                        ReturnMessageCallback callback = returnMessageCallbacks.pop();
                        callback.onMessage(returnMessage);
                    }
                    break;
                case FATAL_ERROR:
                    session.fatalError(((FatalErrorMessage) message).getError());
                    end();
                case QUIT:
                    end();
                    break;
                default:
                    throw new IllegalArgumentException("Unrecognized message type: " +
                            message.getType());
                }
            }
        } catch (Exception e) {
            session.getLog().error("Error handling message: %s",
                    JavaScriptUtils.appendException(e, new StringBuilder()));
        }
    }
   
    private void end() {
        if (socket != null) {
            session.getLog().debug("Ending connection");
            socket.end();
            socket = null;
        }
    }

    public void disconnectFromHost() {
        if (socket != null) {
            sendMessage(new QuitMessage());
            end();
        }
    }
    public void sendMessage(Message message) {
        if (session.getLog().isDebugEnabled()) {
            session.getLog().debug("Sending message: %s", message.toString());
        }
        Buffer buffer = message.toBuffer();
        socket.write(buffer);
    }
   
    public void sendMessage(Message message, MessageCallback callback) {
        if (session.getLog().isDebugEnabled()) {
            session.getLog().debug("Sending message: %s", message.toString());
        }
        Buffer buffer = message.toBuffer();
        socket.write(buffer);
        nextMessageCallback = callback;
    }
   
    public void sendMessage(InvokeFromClientMessage message, ReturnMessageCallback callback) {
        if (session.getLog().isDebugEnabled()) {
            session.getLog().debug("Sending message: %s", message.toString());
        }
        Buffer buffer = message.toBuffer();
        socket.write(buffer);
        returnMessageCallbacks.push(callback);
    }
   
    private Message getNextMessage() {
        try {
            stream.beginTransaction();
            MessageType type = MessageType.getMessageType(stream);
            Message message = type.createMessage(stream, false);
            stream.commitTransaction();
            return message;
        } catch (StreamIndexOutOfBoundsException e) {
            stream.rollbackTransaction();
            return null;
        }
    }
   
    public SessionHandler getSession() {
        return session;
    }
   
    public static interface MessageCallback {
        void onMessage(Message message);
    }
   
    public static interface ReturnMessageCallback {
        void onMessage(ReturnMessage message);
    }
}
TOP

Related Classes of org.gwtnode.dev.debug.HostChannel

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.