Package com.google.speedtracer.client.util

Source Code of com.google.speedtracer.client.util.PostMessageChannel$Responder

/*
* 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.speedtracer.client.util;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.IFrameElement;
import com.google.gwt.events.client.Event;
import com.google.gwt.events.client.EventListener;
import com.google.gwt.events.client.EventListenerRemover;
import com.google.speedtracer.client.util.dom.WindowExt;

/**
* A cross-domain messaging channel that relies on postMessage
* (https://developer.mozilla.org/en/DOM/window.postMessage).
*/
public interface PostMessageChannel {

  /**
   * A channel implementation that is capable of initiating a connection to a
   * foreign server and send it messages. See {@link Responder} for an
   * implementation that only receives and responds to messages.
   */
  public class Client {
    private static IFrameElement createFrame(Document document, String url) {
      final IFrameElement frame = document.createIFrameElement();
      frame.setSrc(url);
      // New WebKit will activate iframes even if they are display:none.
      frame.getStyle().setProperty("cssText", "display:none;");
      return frame;
    }

    private static native WindowExt getContentWindow(IFrameElement frame) /*-{
      return frame.contentWindow;
    }-*/;

    private static native WindowExt getCurrentWindow() /*-{
      return window;
    }-*/;

    private static String getDomain(String url) {
      int protoOffset = url.indexOf("://");
      assert protoOffset >= 0;
      int domainOffset = url.indexOf("/", protoOffset + 3);
      assert domainOffset >= 0;
      return url.substring(0, domainOffset);
    }

    private final String origin;

    private final IFrameElement frame;

    private final EventListenerRemover remover;

    private final Responder receiver;

    // This is only read through assertions, so it should be removed by the
    // compiler.
    private boolean connected;

    /**
     * Creates a new client channel.
     *
     * @param document the document in which to insert the iframe
     * @param url the url to the remote peer
     * @param listener a callback to be notified on channel events
     */
    public Client(Document document, String url, final ClientListener listener) {
      origin = getDomain(url);
      frame = document.getBody().appendChild(createFrame(document, url));
      receiver = new Responder(getCurrentWindow(), origin, listener);
      remover = Event.addEventListener("load", frame, new EventListener() {
        public void handleEvent(Event event) {
          // This should never call synchronously.
          assert remover != null;
          assert !setConnected(true);
          listener.onConnected(Client.this);
          remover.remove();
        }
      });
    }

    public void close() {
      assert setConnected(false);
      remover.remove();
      frame.getParentElement().removeChild(frame);
      receiver.close();
    }

    /**
     * Sends a message to the remote peer.
     *
     * @param message
     */
    public void sendMessage(String message) {
      assert connected;
      Message.sendMessage(getContentWindow(frame), message, origin);
    }

    /**
     * Used for testing.
     *
     * @return
     */
    WindowExt getFrameContentWindow() {
      return getContentWindow(frame);
    }

    /**
     * Used for testing.
     *
     * @return
     */
    String getOrigin() {
      return origin;
    }

    private boolean setConnected(boolean connected) {
      final boolean was = this.connected;
      this.connected = connected;
      return was;
    }
  }

  /**
   * Event-based listener interface for delivering Channel events.
   */
  public interface ClientListener extends ResponseListener {
    /**
     * Called when the {@link Client} connects. It is not safe to call
     * {@link Client#sendMessage(String)} until this occurs.
     *
     * @param client the client that has connected
     */
    void onConnected(Client client);
  }

  /**
   * An encapsulation of a message that was sent with either
   * {@link Client#sendMessage(String)} or {@link #respond(String)}. This
   * contains the string data that was sent and a mechanism to respond directly
   * to that message.
   */
  public static class Message extends JavaScriptObject {
    private static native void sendMessage(WindowExt window, String message,
        String origin) /*-{
      window.postMessage(message, origin);
    }-*/;

    protected Message() {
    }

    public final native String getData() /*-{
      return this.data;
    }-*/;

    public final native String getOrigin() /*-{
      return this.origin;
    }-*/;

    public final void respond(String message) {
      sendMessage(getSource(), message, getOrigin());
    }

    private native WindowExt getSource() /*-{
      return this.source;
    }-*/;
  }

  /**
   * A {@link PostMessageChannel} implementation that is lighter weight (does
   * not create an iframe) but only allows for receiving and responding to
   * messages.
   */
  public class Responder implements PostMessageChannel {

    private final EventListenerRemover remover;

    public Responder(WindowExt window, final String origin,
        final ResponseListener listener) {
      final boolean acceptAllOrigins = "*".equals(origin);
      remover = Event.addEventListener("message", window, new EventListener() {
        public void handleEvent(Event event) {
          final Message e = event.cast();
          if (acceptAllOrigins || origin.equals(e.getOrigin())) {
            listener.onMessageReceived(Responder.this, e);
          }
        }
      });
    }

    public void close() {
      remover.remove();
    }
  }

  /**
   * Event-based listener interface for delivering Channel events.
   */
  public interface ResponseListener {
    /**
     * Called when a message arrives on the channel.
     *
     * @param channel the channel that received the message
     * @param message the message itself
     */
    void onMessageReceived(PostMessageChannel channel, Message message);
  }

  /**
   * Shuts down the client channel and removes all associated resources.
   */
  void close();
}
TOP

Related Classes of com.google.speedtracer.client.util.PostMessageChannel$Responder

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.