Package com.google.speedtracer.client.model

Source Code of com.google.speedtracer.client.model.DataDispatcher$EventRecordDispatcher

/*
* Copyright 2008 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.model;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.GWT.UncaughtExceptionHandler;
import com.google.gwt.coreext.client.JSOArray;
import com.google.gwt.coreext.client.JSON;
import com.google.speedtracer.client.ClientConfig;
import com.google.speedtracer.client.model.CustomEvent.TypeRegisteringVisitor;

import java.util.ArrayList;
import java.util.List;

/**
* Interface for getting different kinds of Models. Each returned Model exposes
* subscriptions for event callbacks.
*
* Also defines Universal base time, which can be calibrated by subclasses only.
*/
public class DataDispatcher implements HintletInterface.HintListener,
    EventRecordLookup, DataInstance.DataListener {
  /**
   * EventRecordDispatcher, but with API for clearing state.
   */
  public interface DataDispatcherDelegate extends EventRecordDispatcher {
    void clearData();
  }

  /**
   * Wrapper objects to proxy callbacks to correct handler.
   */
  public interface EventRecordDispatcher {
    void onEventRecord(EventRecord data);
  }

  /**
   * Allows clients to confirm that the event stream did actually start.
   */
  public interface EventStreamStatusListener {
    void onEventStreamStarted();
  }

  /**
   * Creates a {@link DataDispatcher} based on an opaque handle.
   *
   * @param tabDescription info about the tab represented by this model
   * @param dataInstance an opaque handle to model functionality.
   * @return a model
   */
  public static DataDispatcher create(TabDescription tabDescription,
      DataInstance dataInstance, EventStreamStatusListener eventStreamStatusListener) {
    final DataDispatcher dispatcher = new DataDispatcher(dataInstance, eventStreamStatusListener);
    dataInstance.load(dispatcher);
    dispatcher.setTabDescription(tabDescription);
    dispatcher.initialize();
    return dispatcher;
  }

  protected JSOArray<String> traceDataCopy = JSOArray.create();

  private final TypeRegisteringVisitor customTypeVisitor = new TypeRegisteringVisitor();

  private final DataInstance dataInstance;

  private final List<DataDispatcherDelegate> eventDispatchers = new ArrayList<DataDispatcherDelegate>();

  private List<EventRecord> eventRecords = new ArrayList<EventRecord>();

  // Wants to be final, but we lazily initialize this to make this class play
  // nice with tests.
  private HintletEngineHost hintletEngineHost;

  private final NetworkEventDispatcher networkEventDispatcher;

  private final JavaScriptProfileModel profileModel;

  private int sequenceBase = 0;

  private final TabChangeDispatcher tabChangeDispatcher;

  private TabDescription tabDescription;

  private final UiEventDispatcher uiEventDispatcher;

  private final EventStreamStatusListener eventStreamStatusListener;

  protected DataDispatcher(DataInstance dataInstance,
      EventStreamStatusListener eventStreamStatusListener) {
    this.dataInstance = dataInstance;
    this.networkEventDispatcher = new NetworkEventDispatcher();
    this.uiEventDispatcher = new UiEventDispatcher();
    this.tabChangeDispatcher = new TabChangeDispatcher();
    this.profileModel = new JavaScriptProfileModel(this);
    this.eventStreamStatusListener = eventStreamStatusListener;
  }

  /**
   * Clears the store of saved EventRecords. Relies on v8 garbage collecting
   * appropriately.
   */
  public void clear() {
    // Shift the sequence base offset.
    sequenceBase += eventRecords.size();
    // Replace the existing global event index.
    eventRecords = new ArrayList<EventRecord>();
    // Replace the backing String store.
    traceDataCopy = JSOArray.create();
    // Clear any state in the event dispatchers;
    for (int i = 0, n = eventDispatchers.size(); i < n; i++) {
      eventDispatchers.get(i).clearData();
    }
  }

  /**
   * Retrieves an EventRecord by sequence number.
   *
   * @param sequence A sequence number to look for.
   * @return the record with the specified sequence number.
   */
  public EventRecord findEventRecordFromSequence(int sequence) {
    // Normalize the sequence number.
    return getEventRecordAt(sequence - sequenceBase);
  }

  public void fireOnEventRecord(EventRecord data) {
    UncaughtExceptionHandler ueh = GWT.getUncaughtExceptionHandler();
    if (ueh != null) {
      try {
        fireOnEventRecordImpl(data);
      } catch (Exception ex) {
        ueh.onUncaughtException(ex);
      }
    } else {
      fireOnEventRecordImpl(data);
    }
  }

  /**
   * Returns the opaque handle associated with this DataDispatcher.
   *
   * @return the opaque handle associated with this DataDispatcher.
   */
  public DataInstance getDataInstance() {
    return dataInstance;
  }

  /**
   * Retrieves an EventRecord by direct index in event list.
   *
   * @param index
   * @return the record at the specified index number.
   */
  public EventRecord getEventRecordAt(int index) {
    // Lookups that are out of bounds will just return null.
    if (index < 0 || index >= eventRecords.size()) {
      return null;
    }
    return eventRecords.get(index);
  }

  public List<EventRecord> getEventRecords() {
    return eventRecords;
  }

  /**
   * Gets the sub-model for Hintlets.
   *
   * @return a HintletEngineHost which exposes API for receiving hints.
   */
  public HintletEngineHost getHintletEngineHost() {
    return hintletEngineHost;
  }

  /**
   * Gets the sub-model for JavaScript profiling data.
   *
   * @return the sub-model for JavaScript profiling data.
   */
  public JavaScriptProfileModel getJavaScriptProfileModel() {
    return profileModel;
  }

  /**
   * Gets the dispatcher for network resource related events.
   *
   * @return a model
   */
  public NetworkEventDispatcher getNetworkEventDispatcher() {
    return networkEventDispatcher;
  }

  public TabChangeDispatcher getTabChangeDispatcher() {
    return tabChangeDispatcher;
  }

  /**
   * Gets info about the tab being monitored. Clients SHOULD NOT mutate the
   * object.
   *
   * @return a shared instance of tab info
   */
  public TabDescription getTabDescription() {
    return tabDescription;
  }

  public JSOArray<String> getTraceCopy() {
    return traceDataCopy;
  }

  /**
   * Gets the dispatcher for DOM events.
   */
  public UiEventDispatcher getUiEventDispatcher() {
    return uiEventDispatcher;
  }

  /**
   * Data sources that drive the DataModel drive it through this single function
   * which passes in an {@link EventRecord}.
   *
   * @param record the timeline {@link EventRecord}
   */
  public void onEventRecord(EventRecord record) {
    record.setSequence(eventRecords.size() + sequenceBase);
    // Possibly register a new custom type.
    record.<UiEvent> cast().apply(customTypeVisitor);

    // Keep a copy of the String for saving later.
    traceDataCopy.push(JSON.stringify(record));
    eventRecords.add(record);
    fireOnEventRecord(record);
  }

  public void onEventStreamStarted() {
    eventStreamStatusListener.onEventStreamStarted();
  }

  public void onHint(HintRecord hintlet) {
    saveHintRecord(hintlet);
  }

  public void resumeMonitoring(int tabId) {
    getDataInstance().resumeMonitoring();
  }

  public void stopMonitoring() {
    getDataInstance().stopMonitoring();
  }

  protected void addDispatcher(DataDispatcherDelegate dispatcher) {
    eventDispatchers.add(dispatcher);
  }

  /**
   * Hook up the various models. In the general case, we want all of them, but
   * subclasses can pick and choose which models make sense for them.
   */
  protected void initialize() {
    // Listen to the hintlet engine.
    hintletEngineHost = new HintletEngineHost();
    hintletEngineHost.addHintListener(this);

    // Add models and dispatchers to our dispatch list,.
    if (ClientConfig.isDebugMode()) {
      // NOTE: the order of adding matters, some modify the record object
      addDispatcherAt(0, new BreakyWorkerHost(this, hintletEngineHost));
    }
    addDispatcher(uiEventDispatcher);
    addDispatcher(networkEventDispatcher);
    addDispatcher(tabChangeDispatcher);
    addDispatcher(profileModel);
    addDispatcher(hintletEngineHost);
  }

  protected void setTabDescription(TabDescription tabDescription) {
    this.tabDescription = tabDescription;
  }

  private void addDispatcherAt(int index, DataDispatcherDelegate dispatcher) {
    eventDispatchers.add(index, dispatcher);
  }

  private void fireOnEventRecordImpl(EventRecord data) {
    for (int i = 0, n = eventDispatchers.size(); i < n; i++) {
      eventDispatchers.get(i).onEventRecord(data);
    }
  }

  /**
   * When a new hint record arrives, update the association between the UI
   * record and the hint record.
   */
  private void saveHintRecord(HintRecord hintletRecord) {
    int sequence = hintletRecord.getRefRecord();
    if (sequence < 0) {
      return;
    }
    EventRecord rec = findEventRecordFromSequence(sequence);
    if (rec != null) {
      rec.addHint(hintletRecord);
    }
  }
}
TOP

Related Classes of com.google.speedtracer.client.model.DataDispatcher$EventRecordDispatcher

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.