| /******************************************************************************* |
| * Copyright (c) 2004, 2005 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 |
| *******************************************************************************/ |
| package org.eclipse.jdt.internal.debug.core.logicalstructures; |
| |
| import java.text.MessageFormat; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IAdaptable; |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.debug.core.DebugEvent; |
| import org.eclipse.debug.core.DebugException; |
| import org.eclipse.debug.core.DebugPlugin; |
| import org.eclipse.debug.core.ILogicalStructureType; |
| import org.eclipse.debug.core.IStatusHandler; |
| import org.eclipse.debug.core.model.IDebugTarget; |
| import org.eclipse.debug.core.model.ISourceLocator; |
| import org.eclipse.debug.core.model.IThread; |
| import org.eclipse.debug.core.model.IValue; |
| import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector; |
| import org.eclipse.jdt.core.IJavaElement; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.debug.core.IJavaClassType; |
| import org.eclipse.jdt.debug.core.IJavaDebugTarget; |
| import org.eclipse.jdt.debug.core.IJavaInterfaceType; |
| import org.eclipse.jdt.debug.core.IJavaObject; |
| import org.eclipse.jdt.debug.core.IJavaReferenceType; |
| import org.eclipse.jdt.debug.core.IJavaStackFrame; |
| import org.eclipse.jdt.debug.core.IJavaThread; |
| import org.eclipse.jdt.debug.core.IJavaType; |
| import org.eclipse.jdt.debug.core.IJavaValue; |
| import org.eclipse.jdt.debug.core.IJavaVariable; |
| import org.eclipse.jdt.debug.eval.IAstEvaluationEngine; |
| import org.eclipse.jdt.debug.eval.ICompiledExpression; |
| import org.eclipse.jdt.debug.eval.IEvaluationListener; |
| import org.eclipse.jdt.debug.eval.IEvaluationResult; |
| import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin; |
| |
| public class JavaLogicalStructure implements ILogicalStructureType { |
| |
| |
| // stack frame context provider |
| public static final int INFO_EVALUATION_STACK_FRAME = 111; |
| private static IStatus fgNeedStackFrame = new Status(IStatus.INFO, JDIDebugPlugin.getUniqueIdentifier(), INFO_EVALUATION_STACK_FRAME, "Provides thread context for an evaluation", null); //$NON-NLS-1$ |
| private static IStatusHandler fgStackFrameProvider; |
| |
| /** |
| * Fully qualified type name. |
| */ |
| private String fType; |
| /** |
| * Indicate if this java logical structure should be used on object |
| * instance of subtype of the specified type. |
| */ |
| private boolean fSubtypes; |
| /** |
| * Code snippet to evaluate to create the logical value. |
| */ |
| private String fValue; |
| /** |
| * Description of the logical structure. |
| */ |
| private String fDescription; |
| /** |
| * Name and associated code snippet of the variables of the logical value. |
| */ |
| private String[][] fVariables; |
| /** |
| * The plugin identifier of the plugin which contributed this logical structure |
| * or <code>null</code> if this structure was defined by the user. |
| */ |
| private String fContributingPluginId= null; |
| |
| /** |
| * Performs the evaluations. |
| */ |
| private class EvaluationBlock implements IEvaluationListener { |
| |
| private IJavaObject fEvaluationValue; |
| private IJavaReferenceType fEvaluationType; |
| private IJavaThread fThread; |
| private IAstEvaluationEngine fEvaluationEngine; |
| private IEvaluationResult fResult; |
| |
| public EvaluationBlock(IJavaObject value, IJavaReferenceType type, IJavaThread thread, IAstEvaluationEngine evaluationEngine) { |
| fEvaluationValue= value; |
| fEvaluationType= type; |
| fThread= thread; |
| fEvaluationEngine= evaluationEngine; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jdt.debug.eval.IEvaluationListener#evaluationComplete(org.eclipse.jdt.debug.eval.IEvaluationResult) |
| */ |
| public void evaluationComplete(IEvaluationResult result) { |
| synchronized(this) { |
| fResult= result; |
| this.notify(); |
| } |
| } |
| |
| public IJavaValue evaluate(String snippet) throws DebugException { |
| ICompiledExpression compiledExpression= fEvaluationEngine.getCompiledExpression(snippet, fEvaluationType); |
| if (compiledExpression.hasErrors()) { |
| String[] errorMessages = compiledExpression.getErrorMessages(); |
| log(errorMessages); |
| return new JavaStructureErrorValue(errorMessages, fEvaluationValue); |
| } |
| fResult= null; |
| fEvaluationEngine.evaluateExpression(compiledExpression, fEvaluationValue, fThread, this, DebugEvent.EVALUATION_IMPLICIT, false); |
| synchronized(this) { |
| if (fResult == null) { |
| try { |
| this.wait(); |
| } catch (InterruptedException e) { |
| } |
| } |
| } |
| if (fResult == null) { |
| return new JavaStructureErrorValue(LogicalStructuresMessages.JavaLogicalStructure_1, fEvaluationValue); |
| } |
| if (fResult.hasErrors()) { |
| DebugException exception = fResult.getException(); |
| String message; |
| if (exception != null) { |
| if (isContributed()) { |
| JDIDebugPlugin.log(exception); |
| } |
| message= MessageFormat.format(LogicalStructuresMessages.JavaLogicalStructure_2, new String[] { exception.getMessage() }); |
| } else { |
| log(fResult.getErrorMessages()); |
| message= LogicalStructuresMessages.JavaLogicalStructure_3; |
| } |
| return new JavaStructureErrorValue(message, fEvaluationValue); |
| } |
| return fResult.getValue(); |
| } |
| |
| /** |
| * Logs the given error messages if this logical structure was contributed |
| * via extension. |
| */ |
| private void log(String[] messages) { |
| if (isContributed()) { |
| StringBuffer log= new StringBuffer(); |
| for (int i = 0; i < messages.length; i++) { |
| log.append(messages[i]).append('\n'); |
| } |
| JDIDebugPlugin.log(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), IStatus.ERROR, log.toString(),null)); |
| } |
| } |
| } |
| |
| /** |
| * Constructor from parameters. |
| */ |
| public JavaLogicalStructure(String type, boolean subtypes, String value, String description, String[][] variables) { |
| fType= type; |
| fSubtypes= subtypes; |
| fValue= value; |
| fDescription= description; |
| fVariables= variables; |
| } |
| |
| /** |
| * Constructor from configuration element. |
| */ |
| public JavaLogicalStructure(IConfigurationElement configurationElement) throws CoreException { |
| fType= configurationElement.getAttribute("type"); //$NON-NLS-1$ |
| if (fType == null) { |
| throw new CoreException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.INTERNAL_ERROR, LogicalStructuresMessages.JavaLogicalStructures_0, null)); |
| } |
| fSubtypes= Boolean.valueOf(configurationElement.getAttribute("subtypes")).booleanValue(); //$NON-NLS-1$ |
| fValue= configurationElement.getAttribute("value"); //$NON-NLS-1$ |
| fDescription= configurationElement.getAttribute("description"); //$NON-NLS-1$ |
| if (fDescription == null) { |
| throw new CoreException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.INTERNAL_ERROR, LogicalStructuresMessages.JavaLogicalStructures_4, null)); |
| } |
| IConfigurationElement[] variableElements= configurationElement.getChildren("variable"); //$NON-NLS-1$ |
| if (fValue== null && variableElements.length == 0) { |
| throw new CoreException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.INTERNAL_ERROR, LogicalStructuresMessages.JavaLogicalStructures_1, null)); |
| } |
| fVariables= new String[variableElements.length][2]; |
| for (int j= 0; j < fVariables.length; j++) { |
| String variableName= variableElements[j].getAttribute("name"); //$NON-NLS-1$ |
| if (variableName == null) { |
| throw new CoreException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.INTERNAL_ERROR, LogicalStructuresMessages.JavaLogicalStructures_2, null)); |
| } |
| fVariables[j][0]= variableName; |
| String variableValue= variableElements[j].getAttribute("value"); //$NON-NLS-1$ |
| if (variableValue == null) { |
| throw new CoreException(new Status(IStatus.ERROR, JDIDebugPlugin.getUniqueIdentifier(), JDIDebugPlugin.INTERNAL_ERROR, LogicalStructuresMessages.JavaLogicalStructures_3, null)); |
| } |
| fVariables[j][1]= variableValue; |
| } |
| fContributingPluginId= configurationElement.getNamespace(); |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate#providesLogicalStructure(IValue) |
| */ |
| public boolean providesLogicalStructure(IValue value) { |
| if (!(value instanceof IJavaObject)) { |
| return false; |
| } |
| return getType((IJavaObject) value) != null; |
| } |
| |
| /** |
| * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate#getLogicalStructure(IValue) |
| */ |
| public IValue getLogicalStructure(IValue value) { |
| if (!(value instanceof IJavaObject)) { |
| return value; |
| } |
| IJavaObject javaValue= (IJavaObject) value; |
| try { |
| IJavaReferenceType type = getType(javaValue); |
| if (type == null) { |
| return value; |
| } |
| IJavaStackFrame stackFrame= getStackFrame(javaValue); |
| if (stackFrame == null) { |
| return value; |
| } |
| |
| // find the project the snippets will be compiled in. |
| ISourceLocator locator= javaValue.getLaunch().getSourceLocator(); |
| Object sourceElement= null; |
| if (locator instanceof ISourceLookupDirector) { |
| String[] sourcePaths= type.getSourcePaths(null); |
| if (sourcePaths != null && sourcePaths.length > 0) { |
| sourceElement= ((ISourceLookupDirector) locator).getSourceElement(sourcePaths[0]); |
| } |
| if (!(sourceElement instanceof IJavaElement) && sourceElement instanceof IAdaptable) { |
| sourceElement = ((IAdaptable)sourceElement).getAdapter(IJavaElement.class); |
| } |
| } |
| if (sourceElement == null) { |
| sourceElement = locator.getSourceElement(stackFrame); |
| if (!(sourceElement instanceof IJavaElement) && sourceElement instanceof IAdaptable) { |
| sourceElement = ((IAdaptable)sourceElement).getAdapter(IJavaElement.class); |
| } |
| } |
| IJavaProject project= null; |
| if (sourceElement instanceof IJavaElement) { |
| project= ((IJavaElement) sourceElement).getJavaProject(); |
| } else if (sourceElement instanceof IResource) { |
| IJavaProject resourceProject = JavaCore.create(((IResource)sourceElement).getProject()); |
| if (resourceProject.exists()) { |
| project= resourceProject; |
| } |
| } |
| if (project == null) { |
| return value; |
| } |
| |
| IAstEvaluationEngine evaluationEngine= JDIDebugPlugin.getDefault().getEvaluationEngine(project, (IJavaDebugTarget)stackFrame.getDebugTarget()); |
| |
| EvaluationBlock evaluationBlock= new EvaluationBlock(javaValue, type, (IJavaThread)stackFrame.getThread(), evaluationEngine); |
| if (fValue == null) { |
| // evaluate each variable |
| IJavaVariable[] variables= new IJavaVariable[fVariables.length]; |
| for (int i= 0; i < fVariables.length; i++) { |
| variables[i]= new JDIPlaceholderVariable(fVariables[i][0], evaluationBlock.evaluate(fVariables[i][1])); |
| } |
| return new LogicalObjectStructureValue(javaValue, variables); |
| } |
| // evaluate the logical value |
| return evaluationBlock.evaluate(fValue); |
| |
| } catch (CoreException e) { |
| JDIDebugPlugin.log(e); |
| } |
| return value; |
| } |
| |
| private IJavaReferenceType getType(IJavaObject value) { |
| try { |
| IJavaType type= value.getJavaType(); |
| if (!(type instanceof IJavaClassType)) { |
| return null; |
| } |
| IJavaClassType classType= (IJavaClassType) type; |
| if (classType.getName().equals(fType)) { |
| // found the type |
| return classType; |
| } |
| if (!fSubtypes) { |
| // if not checking the subtypes, stop here |
| return null; |
| } |
| IJavaClassType superClass= classType.getSuperclass(); |
| while (superClass != null) { |
| if (superClass.getName().equals(fType)) { |
| // found the type, it's a super class |
| return superClass; |
| } |
| superClass= superClass.getSuperclass(); |
| } |
| IJavaInterfaceType[] superInterfaces= classType.getAllInterfaces(); |
| for (int i= 0; i < superInterfaces.length; i++) { |
| if (superInterfaces[i].getName().equals(fType)) { |
| // found the type, it's a super interface |
| return superInterfaces[i]; |
| } |
| } |
| } catch (DebugException e) { |
| JDIDebugPlugin.log(e); |
| return null; |
| } |
| return null; |
| } |
| |
| /** |
| * Return the current stack frame context, or a valid stack frame for the given value. |
| */ |
| private IJavaStackFrame getStackFrame(IValue value) throws CoreException { |
| IStatusHandler handler = getStackFrameProvider(); |
| if (handler != null) { |
| IJavaStackFrame stackFrame = (IJavaStackFrame)handler.handleStatus(fgNeedStackFrame, value); |
| if (stackFrame != null) { |
| return stackFrame; |
| } |
| } |
| IDebugTarget target = value.getDebugTarget(); |
| IJavaDebugTarget javaTarget = (IJavaDebugTarget) target.getAdapter(IJavaDebugTarget.class); |
| if (javaTarget != null) { |
| IThread[] threads = javaTarget.getThreads(); |
| for (int i = 0; i < threads.length; i++) { |
| IThread thread = threads[i]; |
| if (thread.isSuspended()) { |
| return (IJavaStackFrame)thread.getTopStackFrame(); |
| } |
| } |
| } |
| return null; |
| } |
| |
| private static IStatusHandler getStackFrameProvider() { |
| if (fgStackFrameProvider == null) { |
| fgStackFrameProvider = DebugPlugin.getDefault().getStatusHandler(fgNeedStackFrame); |
| } |
| return fgStackFrameProvider; |
| } |
| |
| /** |
| * Returns if this logical structure should be used for subtypes too. |
| */ |
| public boolean isSubtypes() { |
| return fSubtypes; |
| } |
| |
| /** |
| * Sets if this logical structure should be used for subtypes or not. |
| */ |
| public void setSubtypes(boolean subtypes) { |
| fSubtypes = subtypes; |
| } |
| |
| /** |
| * Returns the name of the type this logical structure should be used for. |
| */ |
| public String getQualifiedTypeName() { |
| return fType; |
| } |
| /** |
| * Sets the name of the type this logical structure should be used for. |
| */ |
| public void setType(String type) { |
| fType = type; |
| } |
| /** |
| * Returns the code snippet to use to generate the logical structure. |
| */ |
| public String getValue() { |
| return fValue; |
| } |
| /** |
| * Sets the code snippet to use to generate the logical structure. |
| */ |
| public void setValue(String value) { |
| fValue = value; |
| } |
| /** |
| * Returns the variables of this logical structure. |
| */ |
| public String[][] getVariables() { |
| return fVariables; |
| } |
| /** |
| * Sets the variables of this logical structure. |
| */ |
| public void setVariables(String[][] variables) { |
| fVariables = variables; |
| } |
| /** |
| * Set the description of this logical structure. |
| */ |
| public void setDescription(String description) { |
| fDescription = description; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate2#getDescription(org.eclipse.debug.core.model.IValue) |
| */ |
| public String getDescription(IValue value) { |
| return getDescription(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILogicalStructureType#getDescription() |
| */ |
| public String getDescription() { |
| return fDescription; |
| } |
| |
| /** |
| * Indicates if this logical structure was contributed by a plug-in |
| * or defined by a user. |
| */ |
| public boolean isContributed() { |
| return fContributingPluginId != null; |
| } |
| |
| /** |
| * Returns the plugin identifier of the plugin which contributed this logical |
| * structure or <code>null</code> if this structure was defined by the user. |
| * @return the plugin identifier of the plugin which contributed this |
| * structure or <code>null</code> |
| */ |
| public String getContributingPluginId() { |
| return fContributingPluginId; |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.debug.core.ILogicalStructureType#getId() |
| */ |
| public String getId() { |
| return JDIDebugPlugin.getUniqueIdentifier() + fType + fDescription; |
| } |
| |
| } |