com.google.speedtracer.client.model.UiEventDispatcher.java Source code

Java tutorial

Introduction

Here is the source code for com.google.speedtracer.client.model.UiEventDispatcher.java

Source

/*
 * 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.coreext.client.JsIntegerMap;
import com.google.speedtracer.client.model.DataDispatcher.DataDispatcherDelegate;
import com.google.speedtracer.client.model.DataDispatcher.EventRecordDispatcher;
import com.google.speedtracer.client.model.UiEvent.LeafFirstTraversalVoid;

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

/**
 * Dispatches Ui/DOM Events.
 */
public class UiEventDispatcher implements DataDispatcherDelegate {
    /**
     * Listener interface for handling load events.
     */
    public interface LoadEventListener {
        void onDomContentLoaded(DomContentLoadedEvent event);

        void onWindowLoad(WindowLoadEvent event);
    }

    /**
     * Listener interface for handling UiEvent events.
     */
    public interface UiEventListener {
        void onUiEventFinished(UiEvent event);
    }

    /**
     * Visitor that synthesizes top level timer installs if it detects a timer
     * installation in a trace tree.
     */
    private class TimerInstallationVisitor implements LeafFirstTraversalVoid {
        public void visit(UiEvent event) {
            if (TimerInstalled.TYPE == event.getType()) {
                onTimerInstalled(event.<TimerInstalled>cast());
            }
        }
    }

    /**
     * This sets up the function routing for EventRecord TYPES corresponding to
     * top level events that we want to special case.
     * 
     * @param dispatcher
     * @param typeMap
     */
    private static void setSpecialCasedEventCallbacks(final UiEventDispatcher dispatcher,
            JsIntegerMap<EventRecordDispatcher> typeMap) {

        typeMap.put(TimerCleared.TYPE, new EventRecordDispatcher() {
            public void onEventRecord(EventRecord data) {
                dispatcher.onTimerCleared(data.<TimerCleared>cast());
            }
        });

        typeMap.put(TimerInstalled.TYPE, new EventRecordDispatcher() {
            public void onEventRecord(EventRecord data) {
                dispatcher.onTimerInstalled(data.<TimerInstalled>cast());
            }
        });

        typeMap.put(ResourceResponseEvent.TYPE, new EventRecordDispatcher() {
            public void onEventRecord(EventRecord data) {
                // TODO(jaimeyap): For now we ignore this event. But this event seems to
                // measure things coming out of Application cache, and possibly XHR
                // callbacks coming out of memory cache. We should try to show this
                // properly on the sluggishness view without confusing it with Resource
                // Data Received events.
            }
        });

        typeMap.put(WindowLoadEvent.TYPE, new EventRecordDispatcher() {
            public void onEventRecord(EventRecord data) {
                List<LoadEventListener> listeners = dispatcher.loadEventListeners;
                for (int i = 0, n = listeners.size(); i < n; i++) {
                    listeners.get(i).onWindowLoad(data.<WindowLoadEvent>cast());
                }
            }
        });

        typeMap.put(DomContentLoadedEvent.TYPE, new EventRecordDispatcher() {
            public void onEventRecord(EventRecord data) {
                List<LoadEventListener> listeners = dispatcher.loadEventListeners;
                for (int i = 0, n = listeners.size(); i < n; i++) {
                    listeners.get(i).onDomContentLoaded(data.<DomContentLoadedEvent>cast());
                }
            }
        });
    }

    private final List<UiEvent> eventList = new ArrayList<UiEvent>();

    private final List<LoadEventListener> loadEventListeners = new ArrayList<LoadEventListener>();

    private final JsIntegerMap<EventRecordDispatcher> specialCasedTypeMap = JsIntegerMap.create();

    private final TimerInstallationVisitor timerInstallationVisitor = new TimerInstallationVisitor();

    private final JsIntegerMap<TimerInstalled> timerMetaData = JsIntegerMap.create();

    private final List<UiEventListener> uiEventListeners = new ArrayList<UiEventListener>();

    UiEventDispatcher() {
        setSpecialCasedEventCallbacks(this, specialCasedTypeMap);
    }

    public void addLoadEventListener(LoadEventListener listener) {
        loadEventListeners.add(listener);
    }

    public void addUiEventListener(UiEventListener listener) {
        uiEventListeners.add(listener);
    }

    public void clearData() {
        eventList.clear();
    }

    public List<UiEvent> getEventList() {
        return eventList;
    }

    public TimerInstalled getTimerMetaData(int timerId) {
        return timerMetaData.get(timerId);
    }

    /**
     * If the incoming EventRecord belongs to one of the special cased types, we
     * return a proxy object to handle those types. Otherwise, we use the default
     * UiEvent dispatch proxy.
     */
    public void onEventRecord(EventRecord data) {
        final EventRecordDispatcher specialHandler = specialCasedTypeMap.get(data.getType());
        if (specialHandler != null) {
            specialHandler.onEventRecord(data);
        } else if (UiEvent.isUiEvent(data)) {
            onUiEventFinished(data.<UiEvent>cast());
        }
    }

    public void removeLoadEventListener(LoadEventListener listener) {
        loadEventListeners.remove(listener);
    }

    public void removeUiEventListener(UiEventListener listener) {
        uiEventListeners.remove(listener);
    }

    private void onTimerCleared(TimerCleared event) {
        // TODO (jaimeyap): handle this.
    }

    // This does not dispatch to the listener. All we need to do here is book keep
    // the Timer Data.
    private void onTimerInstalled(TimerInstalled timerData) {
        assert (!Double.isNaN(timerData.getTime()));
        timerMetaData.put(timerData.getTimerId(), timerData);
    }

    private void onUiEventFinished(UiEvent event) {
        assert (!Double.isNaN(event.getTime()));

        // Run some visitors here to extract Timer Installations.
        event.apply(timerInstallationVisitor);

        // Keep a copy of the event.
        eventList.add(event);

        for (int i = 0, n = uiEventListeners.size(); i < n; i++) {
            UiEventListener listener = uiEventListeners.get(i);
            listener.onUiEventFinished(event);
        }
    }
}