blob: b44d1e983f4e00977f8334460ee61efb7e3f3586 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.netbeans.spi.debugger.jpda;
import java.beans.PropertyChangeListener;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.netbeans.api.debugger.jpda.JPDAThread;
import org.netbeans.api.debugger.jpda.Variable;
import org.netbeans.modules.debugger.jpda.apiregistry.DebuggerProcessor;
import org.netbeans.spi.debugger.ContextAwareService;
import org.netbeans.spi.debugger.ContextAwareSupport;
import org.netbeans.spi.debugger.ContextProvider;
/**
* Defines bridge to editor and src hierarchy. It allows to use different
* source viewer for debugger (like some UML view).
*
* @author Jan Jancura
*/
public abstract class EditorContext {
/** Annotation type constant. */
public static final String BREAKPOINT_ANNOTATION_TYPE = "Breakpoint";
/** Annotation type constant. */
public static final String DISABLED_BREAKPOINT_ANNOTATION_TYPE = "DisabledBreakpoint";
/** Annotation type constant. */
public static final String CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE = "CondBreakpoint";
/** Annotation type constant. */
public static final String DISABLED_CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE = "DisabledCondBreakpoint";
/** Annotation type constant. */
public static final String FIELD_BREAKPOINT_ANNOTATION_TYPE = "FieldBreakpoint";
/** Annotation type constant. */
public static final String CLASS_BREAKPOINT_ANNOTATION_TYPE = "ClassBreakpoint";
/** Annotation type constant. */
public static final String DISABLED_FIELD_BREAKPOINT_ANNOTATION_TYPE = "DisabledFieldBreakpoint";
/** Annotation type constant. */
public static final String METHOD_BREAKPOINT_ANNOTATION_TYPE = "MethodBreakpoint";
/** Annotation type constant. */
public static final String DISABLED_METHOD_BREAKPOINT_ANNOTATION_TYPE = "DisabledMethodBreakpoint";
/** Annotation type constant. */
public static final String DISABLED_CLASS_BREAKPOINT_ANNOTATION_TYPE = "DisabledClassBreakpoint";
/** Annotation type constant. */
public static final String CURRENT_LINE_ANNOTATION_TYPE = "CurrentPC";
/** Annotation type constant. */
public static final String CALL_STACK_FRAME_ANNOTATION_TYPE = "CallSite";
/** Annotation type constant. */
public static final String CURRENT_LAST_OPERATION_ANNOTATION_TYPE = "LastOperation";
/** Annotation type constant. */
public static final String CURRENT_OUT_OPERATION_ANNOTATION_TYPE = "StepOutOperation";
/** Annotation type constant. */
public static final String CURRENT_EXPRESSION_SECONDARY_LINE_ANNOTATION_TYPE = "CurrentExpression";
/** Annotation type constant. */
public static final String CURRENT_EXPRESSION_CURRENT_LINE_ANNOTATION_TYPE = "CurrentExpressionLine";
/** Annotation type constant.
* @since 2.16 */
public static final String OTHER_THREAD_ANNOTATION_TYPE = "OtherThread";
/** Property name constant. */
public static final String PROP_LINE_NUMBER = "lineNumber";
/**
* Shows source with given url on given line number.
*
* @param url a url of source to be shown
* @param lineNumber a number of line to be shown
* @param timeStamp a time stamp to be used
*/
public abstract boolean showSource (
String url,
int lineNumber,
Object timeStamp
);
/**
* Creates a new time stamp.
*
* @param timeStamp a new time stamp
*/
public abstract void createTimeStamp (Object timeStamp);
/**
* Disposes given time stamp.
*
* @param timeStamp a time stamp to be disposed
*/
public abstract void disposeTimeStamp (Object timeStamp);
/**
* Updates timeStamp for gived url.
*
* @param timeStamp time stamp to be updated
* @param url an url
*/
public abstract void updateTimeStamp (Object timeStamp, String url);
/**
* Adds annotation to given url on given line.
*
* @param url a url of source annotation should be set into
* @param lineNumber a number of line annotation should be set into
* @param annotationType a type of annotation to be set
* @param timeStamp a time stamp to be used
*
* @return annotation or <code>null</code>, when the annotation can not be
* created at the given URL or line number.
*/
public abstract Object annotate (
String url,
int lineNumber,
String annotationType,
Object timeStamp
);
/**
* Adds annotation to given url on given line.
*
* @param url a url of source annotation should be set into
* @param lineNumber a number of line annotation should be set into
* @param annotationType a type of annotation to be set
* @param timeStamp a time stamp to be used
* @param thread the thread to annotate
*
* @return annotation or <code>null</code>, when the annotation can not be
* created at the given URL or line number.
* @since 2.16
*/
public Object annotate (
String url,
int lineNumber,
String annotationType,
Object timeStamp,
JPDAThread thread
) {
return null;
}
/**
* Adds annotation to given url on given character range.
*
* @param url a url of source annotation should be set into
* @param startPosition the offset of the starting position of the annotation
* @param endPosition the offset of the ending position of the annotation
* @param annotationType a type of annotation to be set
* @return annotation or <code>null</code>, when the annotation can not be
* created at the given URL or line number.
*/
public Object annotate (
String url,
int startPosition,
int endPosition,
String annotationType,
Object timeStamp
) {
return null;
}
/**
* Returns line number given annotation is associated with.
*
* @param annotation a annotation
* @param timeStamp a time stamp to be used
*
* @return line number given annotation is associated with
*/
public abstract int getLineNumber (
Object annotation,
Object timeStamp
);
/**
* Removes given annotation.
*/
public abstract void removeAnnotation (
Object annotation
);
/**
* Returns number of line currently selected in editor or <code>-1</code>.
*
* @return number of line currently selected in editor or <code>-1</code>
*/
public abstract int getCurrentLineNumber ();
/**
* Returns name of class currently selected in editor or empty string.
*
* @return name of class currently selected in editor or empty string
*/
public abstract String getCurrentClassName ();
/**
* Returns URL of source currently selected in editor or empty string.
*
* @return URL of source currently selected in editor or empty string
*/
public abstract String getCurrentURL ();
/**
* Returns name of method currently selected in editor or empty string.
*
* @return name of method currently selected in editor or empty string
*/
public abstract String getCurrentMethodName ();
/**
* Returns name of field currently selected in editor or <code>null</code>.
*
* @return name of field currently selected in editor or <code>null</code>
*/
public abstract String getCurrentFieldName ();
/**
* Returns identifier currently selected in editor or <code>null</code>.
*
* @return identifier currently selected in editor or <code>null</code>
*/
public abstract String getSelectedIdentifier ();
/**
* Returns method name currently selected in editor or empty string.
*
* @return method name currently selected in editor or empty string
*/
public abstract String getSelectedMethodName ();
/**
* Returns line number of given field in given class.
*
* @param url the url of source file the class is deined in
* @param className the name of class (or innerclass) the field is
* defined in
* @param fieldName the name of field
*
* @return line number or -1
*/
public abstract int getFieldLineNumber (
String url,
String className,
String fieldName
);
/**
* Returns line number of given method in given class.
*
* @param url the url of source file the class is deined in
* @param className the name of class (or innerclass) the method is
* defined in
* @param methodName the name of the method
* @param methodSignature the JNI-style signature of the method.
* If <code>null</code>, then the first method found is returned.
*
* @return line number or -1
*/
public int getMethodLineNumber (
String url,
final String className,
final String methodName,
final String methodSignature
) {
return -1;
}
/**
* Returns name and signature of method declaration currently selected in editor,
* or <code>null</code>.
*
* @return name and signature of the method, or <code>null</code>.
*/
public String[] getCurrentMethodDeclaration() {
return null;
}
/**
* Returns class name for given url and line number or null.
*
* @param url a url
* @param lineNumber a line number
*
* @return class name for given url and line number or null
*/
public abstract String getClassName (
String url,
int lineNumber
);
/**
* Returns list of imports for given source url.
*
* @param url the url of source file
*
* @return list of imports for given source url
*/
public abstract String[] getImports (String url);
/**
* Creates an operation which is determined by starting and ending position.
*
protected final Operation createOperation(Position startPosition,
Position endPosition,
int bytecodeIndex) {
return new Operation(startPosition, endPosition, bytecodeIndex);
}
*/
/**
* Creates a method operation.
* @param startPosition The starting position of the operation
* @param endPosition The ending position of the operation
* @param methodStartPosition The starting position of the method name
* @param methodEndPosition The ending position of the method name
* @param methodName The string representation of the method name
* @param methodClassType The class type, which defines this method
* @param bytecodeIndex The bytecode index of this method call
*/
protected final Operation createMethodOperation(Position startPosition,
Position endPosition,
Position methodStartPosition,
Position methodEndPosition,
String methodName,
String methodClassType,
int bytecodeIndex) {
return new Operation(startPosition, endPosition,
methodStartPosition, methodEndPosition,
methodName, methodClassType, bytecodeIndex, false);
}
/**
* Creates a method operation.
* @param startPosition The starting position of the operation
* @param endPosition The ending position of the operation
* @param methodStartPosition The starting position of the method name
* @param methodEndPosition The ending position of the method name
* @param methodName The string representation of the method name
* @param methodClassType The class type, which defines this method
* @param bytecodeIndex The bytecode index of this method call
* @param isNative <code>true</code> when the method is determined as a native
* method by the parser.
* @since 2.51
*/
protected final Operation createMethodOperation(Position startPosition,
Position endPosition,
Position methodStartPosition,
Position methodEndPosition,
String methodName,
String methodClassType,
int bytecodeIndex,
boolean isNative) {
return new Operation(startPosition, endPosition,
methodStartPosition, methodEndPosition,
methodName, methodClassType, bytecodeIndex,
isNative);
}
/**
* Assign a next operation, concatenates operations.
* @param operation The first operation
* @param next The next operation
*/
protected final void addNextOperationTo(Operation operation, Operation next) {
operation.addNextOperation(next);
}
/**
* Creates a new {@link Position} object.
* @param offset The offset
* @param line The line number
* @param column The column number
*/
protected final Position createPosition(
int offset, int line, int column) {
return new Position(offset, line, column);
}
/**
* Get the list of operations that are in expression(s) located at the given line.
* @param url The file's URL
* @param lineNumber The line number
* @param bytecodeProvider The provider of method bytecodes.
*/
public Operation[] getOperations(String url, int lineNumber,
BytecodeProvider bytecodeProvider) {
throw new UnsupportedOperationException("This method is not implemented.");
}
/**
* Get a list of arguments to the given operation.
* @param url The URL of the source file with the operation
* @param operation The operation
*/
public MethodArgument[] getArguments(String url, Operation operation) {
throw new UnsupportedOperationException("This method is not implemented by "+this);
}
/**
* Get a list of arguments passed to method located at the given line.
* @param url The URL of the source file
* @param methodLineNumber The line number of the method header
*/
public MethodArgument[] getArguments(String url, int methodLineNumber) {
throw new UnsupportedOperationException("This method is not implemented by "+this);
}
/**
* Adds a property change listener.
*
* @param l the listener to add
*/
public abstract void addPropertyChangeListener (PropertyChangeListener l);
/**
* Removes a property change listener.
*
* @param l the listener to remove
*/
public abstract void removePropertyChangeListener (PropertyChangeListener l);
/**
* Adds a property change listener.
*
* @param propertyName the name of property
* @param l the listener to add
*/
public abstract void addPropertyChangeListener (
String propertyName,
PropertyChangeListener l
);
/**
* Removes a property change listener.
*
* @param propertyName the name of property
* @param l the listener to remove
*/
public abstract void removePropertyChangeListener (
String propertyName,
PropertyChangeListener l
);
/**
* A provider of method bytecode information.
*/
public interface BytecodeProvider {
/**
* Retrieve the class' constant pool.
*/
byte[] constantPool();
/**
* Retrieve the bytecodes of the method.
*/
byte[] byteCodes();
/**
* Get an array of bytecode indexes of operations between the starting
* and ending line.
* @param startLine The starting line
* @param endLine The ending line
*/
int[] indexAtLines(int startLine, int endLine);
}
/**
* The operation definition.
*/
public static final class Operation {
private final Position startPosition;
private final Position endPosition;
private final int bytecodeIndex;
private Position methodStartPosition;
private Position methodEndPosition;
private String methodName;
private String methodDescriptor; // TODO: Add API get/set, accessed through reflection in the meantime.
private String methodClassType;
private Variable returnValue;
private boolean isNative;
private List<Operation> nextOperations;
/*
Operation(Position startPosition, Position endPosition,
int bytecodeIndex) {
this.startPosition = startPosition;
this.endPosition = endPosition;
this.bytecodeIndex = bytecodeIndex;
}
*/
/**
* Creates a new method operation.
*/
Operation(Position startPosition, Position endPosition,
Position methodStartPosition, Position methodEndPosition,
String methodName, String methodClassType,
int bytecodeIndex, boolean isNative) {
this.startPosition = startPosition;
this.endPosition = endPosition;
this.bytecodeIndex = bytecodeIndex;
this.methodStartPosition = methodStartPosition;
this.methodEndPosition = methodEndPosition;
this.methodName = methodName;
this.methodClassType = methodClassType;
this.isNative = isNative;
}
synchronized void addNextOperation(Operation next) {
if (nextOperations == null) {
nextOperations = new ArrayList<Operation>();
}
nextOperations.add(next);
}
/**
* Get the starting position of this operation.
*/
public Position getStartPosition() {
return startPosition;
}
/**
* Get the ending position of this operation.
*/
public Position getEndPosition() {
return endPosition;
}
/**
* Get the starting position of the method call of this operation.
*/
public Position getMethodStartPosition() {
return methodStartPosition;
}
/**
* Get the ending position of the method call of this operation.
*/
public Position getMethodEndPosition() {
return methodEndPosition;
}
/**
* Get the method name.
*/
public String getMethodName() {
return methodName;
}
/**
* Get the class type declaring the method.
*/
public String getMethodClassType() {
return methodClassType;
}
/**
* Indicates whether the method was determined as native by the parser.
* It can return <code>false</code> for native methods that are resolved
* during runtime.
* @return <code>true</code> when the method is determined as native by
* the parser.
* @since 2.51
*/
public boolean isNative() {
return isNative;
}
/**
* Get the bytecode index of this operation.
*/
public int getBytecodeIndex() {
return bytecodeIndex;
}
/**
* Set the return value of this operation.
*/
public void setReturnValue(Variable returnValue) {
this.returnValue = returnValue;
}
/**
* Get the return value of this operation.
*/
public Variable getReturnValue() {
return returnValue;
}
/**
* Get the list of following operations.
*/
public List<Operation> getNextOperations() {
if (nextOperations == null) {
return Collections.emptyList();
} else {
synchronized (this) {
return Collections.unmodifiableList(nextOperations);
}
}
}
public boolean equals(Object obj) {
if (obj instanceof Operation) {
Operation op2 = (Operation) obj;
return bytecodeIndex == op2.bytecodeIndex &&
((startPosition == null) ?
op2.startPosition == null :
startPosition.equals(op2.startPosition)) &&
((endPosition == null) ?
op2.endPosition == null :
endPosition.equals(op2.endPosition));
}
return false;
}
public int hashCode() {
return bytecodeIndex;
}
}
/**
* Representation of a position in a source code.
*/
public static final class Position {
private final int offset;
private final int line;
private final int column;
Position(int offset, int line, int column) {
this.offset = offset;
this.line = line;
this.column = column;
}
/**
* Get the offset of this position.
*/
public int getOffset() {
return offset;
}
/**
* Get the line number of this position.
*/
public int getLine() {
return line;
}
/**
* Get the column number of this position.
*/
public int getColumn() {
return column;
}
public boolean equals(Object obj) {
if (obj instanceof Position) {
Position pos = (Position) obj;
return pos.offset == offset;
}
return false;
}
public int hashCode() {
return offset;
}
}
/**
* Representation of an argument to a method.
* @since 2.10
*/
public static final class MethodArgument {
private String name;
private String type;
private Position startPos;
private Position endPos;
/**
* Creates a new argument.
* @param name The argument name
* @param type The declared type of the argument
* @param startPos Starting position of the argument in the source code
* @param endPos Ending position of the argument in the source code
*/
public MethodArgument(String name, String type, Position startPos, Position endPos) {
assert name != null;
assert type != null;
this.name = name;
this.type = type;
this.startPos = startPos;
this.endPos = endPos;
}
/**
* Get the name of this argument.
* @return The name.
*/
public String getName() {
return name;
}
/**
* Get the declared type of this argument.
* @return The declared type.
*/
public String getType() {
return type;
}
/**
* Get the starting position of this argument in the source code.
* @return The starting position.
*/
public Position getStartPosition() {
return startPos;
}
/**
* Get the ending position of this argument in the source code.
* @return The ending position.
*/
public Position getEndPosition() {
return endPos;
}
}
/**
* Declarative registration of a EditorContext implementation.
* By marking the implementation class with this annotation,
* you automatically register that implementation for use by debugger.
* The class must be public and have a public constructor which takes
* no arguments or takes {@link ContextProvider} as an argument.
*
* @author Martin Entlicher
* @since 2.19
*/
@Retention(RetentionPolicy.SOURCE)
@Target({ElementType.TYPE})
public @interface Registration {
/**
* An optional path to register this implementation in.
* Usually the session ID.
*/
String path() default "";
}
static class ContextAware extends EditorContext implements ContextAwareService<EditorContext> {
private String serviceName;
private ContextAware(String serviceName) {
this.serviceName = serviceName;
}
public EditorContext forContext(ContextProvider context) {
return (EditorContext) ContextAwareSupport.createInstance(serviceName, context);
}
@Override
public boolean showSource(String url, int lineNumber, Object timeStamp) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void createTimeStamp(Object timeStamp) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void disposeTimeStamp(Object timeStamp) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void updateTimeStamp(Object timeStamp, String url) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public Object annotate(String url, int lineNumber, String annotationType, Object timeStamp) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int getLineNumber(Object annotation, Object timeStamp) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void removeAnnotation(Object annotation) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int getCurrentLineNumber() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getCurrentClassName() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getCurrentURL() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getCurrentMethodName() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getCurrentFieldName() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getSelectedIdentifier() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getSelectedMethodName() {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public int getFieldLineNumber(String url, String className, String fieldName) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String getClassName(String url, int lineNumber) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public String[] getImports(String url) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void addPropertyChangeListener(String propertyName, PropertyChangeListener l) {
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
public void removePropertyChangeListener(String propertyName, PropertyChangeListener l) {
throw new UnsupportedOperationException("Not supported yet.");
}
/**
* Creates instance of <code>ContextAwareService</code> based on layer.xml
* attribute values
*
* @param attrs attributes loaded from layer.xml
* @return new <code>ContextAwareService</code> instance
*/
static ContextAwareService createService(Map attrs) throws ClassNotFoundException {
String serviceName = (String) attrs.get(DebuggerProcessor.SERVICE_NAME);
return new ContextAware(serviceName);
}
}
}