/******************************************************************************* * Copyright (c) 2012 Google, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Google, Inc. - initial API and implementation *******************************************************************************/ package com.windowtester.recorder.ui; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugEvent; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.IDebugEventSetListener; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.model.RuntimeProcess; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.PlatformUI; import com.windowtester.codegen.CodegenControllerHandler; import com.windowtester.codegen.ExecutionProfile; import com.windowtester.codegen.ICodegenControllerHandler; import com.windowtester.recorder.ISemanticEventProvider; import com.windowtester.recorder.event.ISemanticEventListener; import com.windowtester.recorder.event.IUISemanticEvent; import com.windowtester.recorder.event.meta.RecorderControllerStartEvent; import com.windowtester.recorder.event.meta.RecorderDisplayNotFoundEvent; import com.windowtester.recorder.event.meta.RecorderErrorEvent; import com.windowtester.recorder.event.meta.RecorderTraceEvent; import com.windowtester.recorder.event.user.SemanticEventHandler; import com.windowtester.recorder.event.user.SemanticKeyDownEvent; import com.windowtester.recorder.event.user.SemanticMenuSelectionEvent; import com.windowtester.recorder.event.user.SemanticTreeItemSelectionEvent; import com.windowtester.recorder.event.user.SemanticWidgetInspectionEvent; import com.windowtester.recorder.event.user.SemanticWidgetSelectionEvent; import com.windowtester.recorder.event.user.UISemanticEvent; import com.windowtester.swt.event.recorder.EventRecorderPlugin; import com.windowtester.swt.event.server.WorkbenchEventController; import com.windowtester.ui.session.IRecordingSessionManager; import com.windowtester.ui.session.RecordingSessionManager; import com.windowtester.ui.util.Logger; import com.windowtester.ui.util.Tracer; /** * * NOTE: this is an in progress refactoring of {@link CodegenControllerHandler} * */ public class RecordingSessionController extends SemanticEventHandler implements IDebugEventSetListener, ICodegenControllerHandler { /** Corresponding to this event listener recording session execution profile */ private ExecutionProfile _profile; /** The workbench shell instance */ private final Shell _workbenchShell; /** Application under recording controller listening port*/ private int _port; /** Workbench event controller reference */ private final WorkbenchEventController _server; private RecordingSessionManager _sessionManager; private RecorderEventGateway _eventGateway = new RecorderEventGateway(); private InspectionEventHandler inspectionEventHandler; protected static class RecorderEventGateway implements ISemanticEventProvider { private List /*<ISemanticEventListener>*/ _listeners = new ArrayList(); public void addListener(ISemanticEventListener listener) { List listeners = getListeners(); if (!listeners.contains(listener)) //multiple adds simply ignored listeners.add(listener); } /* (non-Javadoc) * @see com.windowtester.event.model.IEventRecorder#removeListener(com.windowtester.swt.event.model.ISemanticEventListener) */ public void removeListener(ISemanticEventListener listener) { getListeners().remove(listener); } List getListeners() { return _listeners; } /** * This needs to be thread-safe as events might be produced on the UI thread or the recording thread. */ public synchronized void notify(IUISemanticEvent semanticEvent) { for (Iterator iter = getListeners().iterator(); iter.hasNext(); ) ((ISemanticEventListener)iter.next()).notify(semanticEvent); } } public RecordingSessionController(WorkbenchEventController server, ExecutionProfile profile) { super(); setProfile(profile); _server = server; _workbenchShell = PlatformUI.getWorkbench().getWorkbenchWindows()[0].getShell(); _sessionManager = new RecordingSessionManager(getEventGateway(), profile); inspectionEventHandler = new InspectionEventHandler(getEventGateway()) { /* (non-Javadoc) * @see com.windowtester.recorder.ui.InspectionEventHandler#assertionMade() */ protected void assertionMade() { stopInspecting(); } /* (non-Javadoc) * @see com.windowtester.recorder.ui.InspectionEventHandler#expertDismissed() */ protected void expertDismissed() { stopInspecting(); } private void stopInspecting() { //do a toggle: note this is not the cleanest way to do this... (demeter says...) _sessionManager.getConsole().clickSpyMode(); } }; //disabled experiment w/ event notification // _eventGateway.addListener(new SemanticEventAdapter() { // public void notify(IUISemanticEvent event) { // if (event instanceof SemanticWidgetInspectionEvent) // return; // EventNotification.popupForEvent(event); // } // }); } public IRecordingSessionManager getSessionManager() { return _sessionManager; } protected RecorderEventGateway getEventGateway() { return _eventGateway; } /* (non-Javadoc) * @see com.windowtester.swt.event.model.SemanticEventHandler#handleDisplayNotFound(com.windowtester.swt.event.model.RecorderDisplayNotFoundEvent) */ public void handleDisplayNotFound(RecorderDisplayNotFoundEvent event) { MessageDialog.openError(getWorkbenchShell(), "Application Initialization", "The application user interface is not yet initialized"); } /* (non-Javadoc) * @see com.windowtester.swt.event.model.SemanticEventHandler#handleControllerStart(com.windowtester.swt.event.model.RecorderControllerStartEvent) */ public void handleControllerStart(RecorderControllerStartEvent event) { setPort(event.getPort()); if (isInvalidPortNumber()){ Logger.log("Got invalid port number from application under test"); return; } startSession(); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Semantic event relay // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* (non-Javadoc) * @see com.windowtester.recorder.event.user.SemanticEventHandler#handle(com.windowtester.recorder.event.user.SemanticKeyDownEvent) */ public void handle(SemanticKeyDownEvent event) { getEventGateway().notify(event); } /* (non-Javadoc) * @see com.windowtester.recorder.event.user.SemanticEventHandler#handle(com.windowtester.recorder.event.user.SemanticMenuSelectionEvent) */ public void handle(SemanticMenuSelectionEvent event) { getEventGateway().notify(event); } /* (non-Javadoc) * @see com.windowtester.recorder.event.user.SemanticEventHandler#handle(com.windowtester.recorder.event.user.SemanticWidgetSelectionEvent) */ public void handle(SemanticWidgetSelectionEvent event) { getEventGateway().notify(event); } /* (non-Javadoc) * @see com.windowtester.recorder.event.user.SemanticEventHandler#handle(com.windowtester.recorder.event.user.UISemanticEvent) */ public void handle(UISemanticEvent event) { getEventGateway().notify(event); } /* (non-Javadoc) * @see com.windowtester.recorder.event.user.SemanticEventHandler#handle(com.windowtester.recorder.event.user.SemanticTreeItemSelectionEvent) */ public void handle(SemanticTreeItemSelectionEvent event) { getEventGateway().notify(event); } /* (non-Javadoc) * @see com.windowtester.recorder.event.user.SemanticEventHandler#handleInspectionEvent(com.windowtester.recorder.event.user.SemanticWidgetInspectionEvent) */ public void handleInspectionEvent(SemanticWidgetInspectionEvent inspectionEvent) { inspectionEventHandler.handleInspectionEvent(inspectionEvent); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // Meta event handling // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// /* (non-Javadoc) * @see com.windowtester.swt.event.model.SemanticEventHandler#handleError(com.windowtester.swt.event.model.RecorderErrorEvent) */ public void handleError(RecorderErrorEvent event) { Logger.log(event.getMsg(), event.getThrowable()); } /* (non-Javadoc) * @see com.windowtester.swt.event.model.SemanticEventHandler#handleTrace(com.windowtester.swt.event.model.RecorderTraceEvent) */ public void handleTrace(RecorderTraceEvent event) { Tracer.trace(event.getTraceOption(), event.getMsg()); } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // ... // ///////////////////////////////////////////////////////////////////////////////////////////////////////////////// private void startSession() { getSessionManager().setPort(getPort()); getSessionManager().start(); EventRecorderPlugin.inRecording = true; //TODO: disabled for now -- retool and re-enable //UsageHints.openStartRecordingHintDialog(); } private boolean isInvalidPortNumber() { return getPort() <= 0; } /* (non-Javadoc) * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(org.eclipse.debug.core.DebugEvent[]) */ public void handleDebugEvents(DebugEvent[] events) { if (events == null || events.length == 0) return; DebugEvent event = events[0]; if (event.getSource() instanceof RuntimeProcess){ RuntimeProcess process = (RuntimeProcess)event.getSource(); if (isTerminateEvent(event, process)){ stopSession(); // stop the server from listening on socket if not in debug mode if(!EventRecorderPlugin.isInDebugMode()) getServer().stopServer(); getServer().getEvents().clear(); // remove this class from debug listeners DebugPlugin.getDefault().removeDebugEventListener(this); // delete launch configuration if not in debug mode try { if(!EventRecorderPlugin.isInDebugMode()){ ILaunchConfiguration lc = process.getLaunch().getLaunchConfiguration(); if(lc.getName().equals(ExecutionProfile.TMP_APPLICATION_LAUNCH_CONFIG)) lc.delete(); } } catch (CoreException e) { Logger.log(e); } } } } private void stopSession() { // the recording flag EventRecorderPlugin.inRecording = false; getSessionManager().end(); } private boolean isTerminateEvent(DebugEvent event, RuntimeProcess process) { return process.getLaunch().equals(getProfile().getLaunch())&&event.getKind()==DebugEvent.TERMINATE; } private void setPort(int port) { _port = port; } private int getPort() { return _port; } private WorkbenchEventController getServer() { return _server; } private void setProfile(ExecutionProfile profile) { _profile = profile; } private ExecutionProfile getProfile() { return _profile; } private Shell getWorkbenchShell() { return _workbenchShell; } }