Java tutorial
/* * 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); } } }