/******************************************************************************* * Copyright (c) 2009 IBM Corporation and others. * 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: * IBM Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.debug.core.zend.model; import java.io.File; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.*; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.php.debug.core.debugger.parameters.IDebugParametersKeys; import org.eclipse.php.internal.debug.core.IPHPConsoleEventListener; import org.eclipse.php.internal.debug.core.IPHPDebugConstants; import org.eclipse.php.internal.debug.core.Logger; import org.eclipse.php.internal.debug.core.PHPDebugCoreMessages; import org.eclipse.php.internal.debug.core.model.SimpleDebugHandler; import org.eclipse.php.internal.debug.core.pathmapper.PathEntry; import org.eclipse.php.internal.debug.core.pathmapper.PathEntry.Type; import org.eclipse.php.internal.debug.core.pathmapper.PathMapper; import org.eclipse.php.internal.debug.core.pathmapper.PathMapper.Mapping.MappingSource; import org.eclipse.php.internal.debug.core.pathmapper.PathMapperRegistry; import org.eclipse.php.internal.debug.core.preferences.PHPProjectPreferences; import org.eclipse.php.internal.debug.core.zend.communication.DebugConnection; import org.eclipse.php.internal.debug.core.zend.debugger.*; import org.eclipse.php.internal.debug.core.zend.debugger.parameters.DefaultDebugParametersInitializer; import org.eclipse.php.internal.server.core.Server; import org.eclipse.php.internal.server.core.manager.ServersManager; /** * A PHP debug server handler. * * @author Shalom Gibly */ public class ServerDebugHandler extends SimpleDebugHandler { protected IRemoteDebugger fRemoteDebugger; protected boolean fStatus; protected PHPDebugTarget fDebugTarget; protected DebugConnection fDebugConnection; protected boolean fCodeCoverage; protected boolean fUseLocalCopy; protected CodeCoverageData[] fCodeCoverageData; public ServerDebugHandler() { } public IRemoteDebugger getRemoteDebugger() { return fRemoteDebugger; } public void sessionStarted(String remoteFile, String uri, String query, String options) { super.sessionStarted(remoteFile, uri, query, options); fUseLocalCopy = true; ILaunchConfiguration launchConfiguration = fDebugTarget.getLaunch().getLaunchConfiguration(); try { fUseLocalCopy = !launchConfiguration.getAttribute(IPHPDebugConstants.DEBUGGING_USE_SERVER_FILES, false); } catch (CoreException e) { DebugPlugin.log(e); } if (fUseLocalCopy) { // Bind server with this launch configuration if we can find any: final String serverURL = fDebugTarget.getURL(); if (serverURL != null) { try { String serverName = null; Server serverLookup = ServersManager.findByURL(serverURL); if (serverLookup != null) serverName = serverLookup.getName(); if (serverName != null) { ILaunchConfigurationWorkingCopy wc = launchConfiguration.getWorkingCopy(); wc.setAttribute(Server.NAME, serverName); synchronized (launchConfiguration) { wc.doSave(); } } } catch (CoreException e) { DebugPlugin.log(e); } } // XXX: add initial mapping for debugging via PHP Web Script (needed // for the first breakpoint) try { String debugType = launchConfiguration.getAttribute(IDebugParametersKeys.PHP_DEBUG_TYPE, ""); //$NON-NLS-1$ if (debugType.equals(IDebugParametersKeys.PHP_WEB_SCRIPT_DEBUG)) { PathMapper pathMapper = PathMapperRegistry.getByLaunchConfiguration(launchConfiguration); String debugFilePath = launchConfiguration.getAttribute(IPHPDebugConstants.ATTR_FILE, (String) null); String debugFileFullPath = launchConfiguration.getAttribute(IPHPDebugConstants.ATTR_FILE_FULL_PATH, (String) null); if (pathMapper != null && debugFilePath != null && debugFileFullPath != null && pathMapper.getLocalFile(debugFileFullPath) == null) { IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(debugFilePath); if (resource instanceof IFile) { pathMapper.addEntry(debugFileFullPath, new PathEntry(debugFilePath, Type.WORKSPACE, resource.getParent()), MappingSource.ENVIRONMENT); } else if (new File(debugFilePath).exists()) { pathMapper.addEntry(debugFilePath, new PathEntry(debugFilePath, Type.EXTERNAL, new File(debugFilePath).getParentFile()), MappingSource.ENVIRONMENT); } } } } catch (CoreException e) { Logger.logException(e); } } if (isUsingPathMapper()) { /* * Hack for the case when htdocs is symlinked to the workspace. Zend * Debugger resolves symbolic links later and it breaks path mapper. */ try { String lcServerName = launchConfiguration.getAttribute(Server.NAME, (String) null); if ((lcServerName == null || lcServerName.isEmpty()) && fDebugTarget.getURL() != null) { // Bind server with this configuration, if we can find any. String serverName = null; Server serverLookup = ServersManager.findByURL(fDebugTarget.getURL()); if (serverLookup != null) serverName = serverLookup.getName(); if (serverName != null) { ILaunchConfigurationWorkingCopy wc = launchConfiguration.getWorkingCopy(); wc.setAttribute(Server.NAME, serverName); synchronized (launchConfiguration) { wc.doSave(); } } } } catch (CoreException e) { DebugPlugin.log(e); } try { File file = new File(remoteFile); if (file.exists()) { remoteFile = file.getCanonicalPath(); } } catch (Exception e) { } fDebugTarget.mapFirstDebugFile(remoteFile); } fDebugTarget.setLastFileName(remoteFile); if (!fDebugTarget.isPHPCGI()) { fDebugTarget.setServerWindows(false); } StartLock startLock = fDebugTarget.getStartLock(); synchronized (startLock) { if (startLock.isRunStart()) { startLock.setStarted(true); fDebugTarget.started(); fStatus = getRemoteDebugger().start(fDebugTarget.getStartResponseHandler()); if (!fStatus) { Logger.log(Logger.ERROR, "ServerDebugHandler: debugger.start return false"); //$NON-NLS-1$ try { fDebugTarget.disconnect(); } catch (DebugException e) { Logger.logException(e); } } fDebugTarget.setLastCommand("start"); //$NON-NLS-1$ } else { startLock.setRunStart(true); } } fCodeCoverage = query.indexOf(DefaultDebugParametersInitializer.CODE_COVERAGE) != -1; } public void connectionEstablished() { super.connectionEstablished(); StartLock startLock = fDebugTarget.getStartLock(); synchronized (startLock) { if (startLock.isRunStart()) { startLock.setStarted(true); fDebugTarget.started(); fStatus = getRemoteDebugger().start(fDebugTarget.getStartResponseHandler()); if (!fStatus) { Logger.log(Logger.ERROR, "ServerDebugHandler: debugger.start return false"); //$NON-NLS-1$ } fDebugTarget.setLastCommand("start"); //$NON-NLS-1$ } else { startLock.setRunStart(true); } } } public void ready(String fileName, int lineNumber) { super.ready(fileName, lineNumber); fDebugTarget.setLastStop(lineNumber); fDebugTarget.setLastFileName(fileName); String fLastcmd = fDebugTarget.getLastCommand(); Logger.debugMSG("ServerDebugHandler: lastCMD " + fLastcmd); //$NON-NLS-1$ fDebugTarget.setBreakpoints(new IBreakpoint[] {}); ILaunchConfiguration launchConfiguration = fDebugTarget.getLaunch().getLaunchConfiguration(); try { fDebugTarget.setExpressionManager( new DefaultExpressionsManager(fRemoteDebugger, launchConfiguration.getAttribute( IDebugParametersKeys.TRANSFER_ENCODING, PHPProjectPreferences.getTransferEncoding(null)))); } catch (CoreException e) { } if (fLastcmd.equals("start")) { //$NON-NLS-1$ fDebugTarget.breakpointHit(fDebugTarget.getLastFileName(), lineNumber); } else if (fLastcmd.equals("resume")) { //$NON-NLS-1$ fDebugTarget.breakpointHit(fDebugTarget.getLastFileName(), lineNumber); } else if (fLastcmd.equals("suspend")) { //$NON-NLS-1$ fDebugTarget.suspended(DebugEvent.CLIENT_REQUEST); } else if (fLastcmd.equals("stepReturn")) { //$NON-NLS-1$ fDebugTarget.suspended(DebugEvent.STEP_RETURN); } else if (fLastcmd.equals("stepOver")) { //$NON-NLS-1$ fDebugTarget.suspended(DebugEvent.STEP_OVER); } else if (fLastcmd.equals("stepInto")) { //$NON-NLS-1$ fDebugTarget.suspended(DebugEvent.STEP_INTO); } else if (fLastcmd.equals("terminate")) { //$NON-NLS-1$ // Shouldn't happen, try to shut down cleanly fRemoteDebugger.finish(); fDebugTarget.terminated(); } else if (fLastcmd.equals("breakpointAdded")) { //$NON-NLS-1$ } else if (fLastcmd.equals("breakpointRemoved")) { //$NON-NLS-1$ } } public void sessionEnded() { Logger.debugMSG("ServerDebugHandler: Starting sessionEnded()"); //$NON-NLS-1$ super.sessionEnded(); } public void connectionClosed() { Logger.debugMSG("ServerDebugHandler: Starting connectionClosed()"); //$NON-NLS-1$ super.connectionClosed(); fRemoteDebugger.finish(); // if (fDebugTarget.isPHPCGI()) { // Logger.debugMSG("ServerDebugHandler: Calling Terminated() for PHP // CGI"); Logger.debugMSG("ServerDebugHandler: Calling Terminated()"); //$NON-NLS-1$ fDebugTarget.terminated(); // } } public void handleScriptEnded() { try { if (fCodeCoverage) { IRemoteDebugger remoteDebugger = getRemoteDebugger(); if (remoteDebugger instanceof RemoteDebugger) { fCodeCoverageData = ((RemoteDebugger) remoteDebugger).getCodeCoverageData(); } } } finally { Logger.debugMSG("ServerDebugHandler: handleScriptEnded"); //$NON-NLS-1$ try { Logger.debugMSG("ServerDebugHandler: Calling Terminate()"); //$NON-NLS-1$ fDebugTarget.terminate(); } catch (DebugException e1) { Logger.logException("ServerDebugHandler: terminate failed", e1); //$NON-NLS-1$ } } } public void multipleBindOccured() { super.multipleBindOccured(); Logger.log(Logger.WARNING, "ServerDebugHandler: Multiple Bind Occured"); //$NON-NLS-1$ String errorMessage = PHPDebugCoreMessages.DebuggerDebugPortInUse_1; fRemoteDebugger.closeConnection(); fDebugTarget.fireError(errorMessage, null); fDebugTarget.terminated(); } public void parsingErrorOccured(DebugError debugError) { super.parsingErrorOccured(debugError); // resolve path String localFileName = ((RemoteDebugger) fRemoteDebugger).convertToLocalFilename(debugError.getFullPathName(), null, null); if (localFileName == null) { localFileName = debugError.getFullPathName(); } debugError.setFileName(localFileName); if (fDebugTarget.getDebugErrors().add(debugError)) { Object[] listeners = fDebugTarget.getConsoleEventListeners().toArray(); for (Object element : listeners) { ((IPHPConsoleEventListener) element).handleEvent(debugError); } } } /* * (non-Javadoc) * * @see org.eclipse.php.internal.debug.core.model.SimpleDebugHandler# * wrongDebugServer () */ public void wrongDebugServer() { super.wrongDebugServer(); fDebugTarget.fireError(PHPDebugCoreMessages.ServerDebugHandler_0, null); fRemoteDebugger.finish(); } public void newOutput(String output) { super.newOutput(output); fDebugTarget.getOutputBuffer().append(output); } public void newHeaderOutput(String output) { super.newHeaderOutput(output); fDebugTarget.getOutputBuffer().appendHeader(output); } public void setDebugTarget(PHPDebugTarget debugTarget) { this.fDebugTarget = debugTarget; fDebugConnection = fDebugTarget.getDebugConnection(); fRemoteDebugger = createRemoteDebugger(); fDebugConnection.getCommunicationAdministrator().connectionEstablished(); } public PHPDebugTarget getDebugTarget() { return fDebugTarget; } /** * Returns code coverage data from the last debug session. * * @return CodeCoverage data or <code>null</code> if there wasn't directive * to retreive code coverage data. */ public CodeCoverageData[] getLastCodeCoverageData() { return fCodeCoverageData; } protected IRemoteDebugger createRemoteDebugger() { return new RemoteDebugger(this, fDebugConnection); } protected boolean isUsingPathMapper() { return fUseLocalCopy; } }