/*******************************************************************************
* Copyright (c) 2010 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.debugger.handlers;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.IBreakpointManager;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IBreakpoint;
import org.eclipse.dltk.core.environment.EnvironmentPathUtils;
import org.eclipse.php.debug.core.debugger.handlers.IDebugMessageHandler;
import org.eclipse.php.debug.core.debugger.messages.IDebugMessage;
import org.eclipse.php.debug.core.debugger.parameters.IDebugParametersKeys;
import org.eclipse.php.internal.core.phar.PharPath;
import org.eclipse.php.internal.core.util.FileUtils;
import org.eclipse.php.internal.debug.core.IPHPDebugConstants;
import org.eclipse.php.internal.debug.core.Logger;
import org.eclipse.php.internal.debug.core.PHPDebugPlugin;
import org.eclipse.php.internal.debug.core.launching.PHPLaunchUtilities;
import org.eclipse.php.internal.debug.core.model.IPHPExceptionBreakpoint;
import org.eclipse.php.internal.debug.core.model.PHPConditionalBreakpoint;
import org.eclipse.php.internal.debug.core.model.PHPLineBreakpoint;
import org.eclipse.php.internal.debug.core.pathmapper.VirtualPath;
import org.eclipse.php.internal.debug.core.zend.debugger.Breakpoint;
import org.eclipse.php.internal.debug.core.zend.debugger.RemoteDebugger;
import org.eclipse.php.internal.debug.core.zend.debugger.messages.ContinueProcessFileNotification;
import org.eclipse.php.internal.debug.core.zend.debugger.messages.StartProcessFileNotification;
import org.eclipse.php.internal.debug.core.zend.model.PHPDebugTarget;
import org.eclipse.wst.sse.ui.internal.StructuredResourceMarkerAnnotationModel;
public class StartProcessFileNotificationHandler implements IDebugMessageHandler {
protected boolean isFirstFileToDebug;
public StartProcessFileNotificationHandler() {
isFirstFileToDebug = true;
}
public void handle(IDebugMessage message, PHPDebugTarget debugTarget) {
// do everything we need in order to prepare for processing current file
StartProcessFileNotification notification = (StartProcessFileNotification) message;
String remoteFileName = notification.getFileName();
prepareForProcessing(remoteFileName, debugTarget);
// send notification to tell debugger to continue processing file
RemoteDebugger remoteDebugger = (RemoteDebugger) debugTarget.getRemoteDebugger();
remoteDebugger.sendCustomNotification(new ContinueProcessFileNotification());
}
protected void prepareForProcessing(String remoteFileName, PHPDebugTarget debugTarget) {
if (isFirstFileToDebug && PHPDebugPlugin.isDummyFile(remoteFileName)) {
debugTarget.setLastFileName(remoteFileName);
return;
}
RemoteDebugger remoteDebugger = (RemoteDebugger) debugTarget.getRemoteDebugger();
ILaunchConfiguration launchConfiguration = debugTarget.getLaunch().getLaunchConfiguration();
debugTarget.setLastFileName(remoteFileName);
boolean isWebServerDebugger = Boolean.toString(true)
.equals(debugTarget.getLaunch().getAttribute(IDebugParametersKeys.WEB_SERVER_DEBUGGER));
boolean isBuiltinServerDebugger = Boolean.toString(true)
.equals(debugTarget.getLaunch().getAttribute(IDebugParametersKeys.BUILTIN_SERVER_DEBUGGER));
String debugType = ""; //$NON-NLS-1$
try {
debugType = launchConfiguration.getAttribute(IDebugParametersKeys.PHP_DEBUG_TYPE, ""); //$NON-NLS-1$
} catch (CoreException e) {
PHPDebugPlugin.log(e);
}
if (isFirstFileToDebug) { // we suppose that we always get full path
// here
if (isWebServerDebugger || isBuiltinServerDebugger) {
debugTarget.mapFirstDebugFile(remoteFileName);
// set current working directory to the current script directory
// on debugger side
if (debugType.equals(IDebugParametersKeys.PHP_WEB_SCRIPT_DEBUG)) {
VirtualPath remotePath = new VirtualPath(remoteFileName);
remotePath.removeLastSegment();
remoteDebugger.setCurrentWorkingDirectory(remotePath.toString());
}
}
debugTarget.addBreakpointFiles(debugTarget.getProject());
}
String localPath = remoteDebugger.convertToLocalFilename(remoteFileName);
// send found breakpoints with remote file name
if (localPath != null && ILaunchManager.DEBUG_MODE.equals(debugTarget.getLaunch().getLaunchMode())) {
IBreakpoint[] breakPoints = findBreakpoints(localPath, debugTarget);
for (IBreakpoint bp : breakPoints) {
try {
if (bp.isEnabled()) {
PHPConditionalBreakpoint phpBP = (PHPConditionalBreakpoint) bp;
Breakpoint runtimeBreakpoint = phpBP.getRuntimeBreakpoint();
int lineNumber = (Integer) bp.getMarker().getAttribute(IMarker.LINE_NUMBER);
int bpID = runtimeBreakpoint.getID();
int bpType = runtimeBreakpoint.getType();
int bpLifeTime = runtimeBreakpoint.getLifeTime();
Breakpoint bpToSend = new Breakpoint(remoteFileName, lineNumber);
bpToSend.setID(bpID);
bpToSend.setType(bpType);
bpToSend.setLifeTime(bpLifeTime);
bpToSend.setConditionalFlag(runtimeBreakpoint.getConditionalFlag());
bpToSend.setExpression(runtimeBreakpoint.getExpression());
debugTarget.getRemoteDebugger().addBreakpoint(bpToSend);
runtimeBreakpoint.setID(bpToSend.getID());
}
} catch (CoreException e) {
PHPDebugPlugin.log(e);
}
}
}
isFirstFileToDebug = false;
}
protected IBreakpoint[] findBreakpoints(String processFileLocation, PHPDebugTarget debugTarget) {
IBreakpointManager breakpointManager = debugTarget.getBreakpointManager();
if (!breakpointManager.isEnabled()) {
return new IBreakpoint[0];
}
IBreakpoint[] breakpoints = breakpointManager.getBreakpoints(IPHPDebugConstants.ID_PHP_DEBUG_CORE);
List<IBreakpoint> matches = new LinkedList<IBreakpoint>();
for (IBreakpoint bp : breakpoints) {
if (bp instanceof IPHPExceptionBreakpoint || PharPath.isPharPath(new Path(processFileLocation))) {
/*
* Not supported by Zend Debugger engine - exception breakpoints
* and handling breakpoints in PHAR files.
*/
continue;
}
IResource resource = ResourcesPlugin.getWorkspace().getRoot().findMember(processFileLocation);
/*
* Check if breakpoint marker resource is the same as the one found
* for file location that should be processed.
*/
if (bp.getMarker().getResource().equals(resource)) {
matches.add(bp);
continue;
}
try {
/*
* If previous check failed, try to establish if PHP breakpoint
* file location is pointing to the same file as the one that
* should be processed. Symbolic links will also be resolved.
*/
String bpMarkerFileLocation = bp.getMarker().getResource().getLocation().toOSString();
String phpBpFileLocation = ((PHPLineBreakpoint) bp).getRuntimeBreakpoint().getFileName();
if (FileUtils.isSameFile(bpMarkerFileLocation, processFileLocation)
|| FileUtils.isSameFile(phpBpFileLocation, processFileLocation)) {
/*
* If there is a debug target related project then we can
* filter out possible breakpoint duplicates (in case of
* symbolic links)
*/
IProject debugProject = PHPLaunchUtilities.getProject(debugTarget);
IProject bpProject = bp.getMarker().getResource().getProject();
if (debugProject == null || bpProject == null || debugProject.equals(bpProject)) {
matches.add(bp);
continue;
}
}
} catch (Exception e) {
/*
* Ignore as some path descriptors might be illegal for this
* check e.g. DLTK external library scripts (see next step).
*/
}
/*
* Breakpoint may also correspond to a PHP script from project
* external libraries. Try to check it as well.
*/
String secondaryId = null;
try {
secondaryId = (String) bp.getMarker()
.getAttribute(StructuredResourceMarkerAnnotationModel.SECONDARY_ID_KEY);
} catch (CoreException e) {
// Should never be thrown, anyway...
Logger.logException(e);
}
if (secondaryId != null) {
IPath path = Path.fromPortableString(secondaryId);
if ((path.getDevice() == null) && (path.toString().startsWith("org.eclipse.dltk"))) { //$NON-NLS-1$
String fullPathString = path.toString();
String absolutePath = fullPathString.substring(fullPathString.indexOf(':') + 1);
path = Path.fromPortableString(absolutePath);
} else {
path = EnvironmentPathUtils.getLocalPath(path);
}
secondaryId = path.toString();
if ((VirtualPath.isAbsolute(processFileLocation)
&& new VirtualPath(processFileLocation).equals(new VirtualPath(secondaryId)))
|| (resource != null && resource.getLocation() != null
&& secondaryId.equals(resource.getLocation().toString()))) {
matches.add(bp);
}
}
}
return matches.toArray(new IBreakpoint[matches.size()]);
}
}