blob: 065b05cf6d150b4d6ff1d8bc3a718a4c58699a42 [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.modules.debugger.jpda;
import com.sun.jdi.AbsentInformationException;
import org.netbeans.api.java.source.support.ErrorAwareTreePathScanner;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.function.Function;
import org.netbeans.api.debugger.DebuggerManager;
import org.netbeans.api.debugger.jpda.LineBreakpoint;
import org.netbeans.api.debugger.jpda.CallStackFrame;
import org.netbeans.api.debugger.jpda.InvalidExpressionException;
import org.netbeans.api.debugger.jpda.JPDAThread;
import org.netbeans.spi.debugger.jpda.EditorContext;
import org.netbeans.spi.debugger.jpda.EditorContext.MethodArgument;
import org.netbeans.spi.debugger.jpda.EditorContext.Operation;
import org.netbeans.spi.debugger.jpda.Evaluator.Expression;
import org.netbeans.spi.debugger.jpda.SourcePathProvider;
import org.openide.util.Exceptions;
import org.openide.util.Pair;
/**
*
* @author Jan Jancura
*/
public class EditorContextBridge {
public static final String FIELD = "field";
public static final String METHOD = "method";
public static final String CLASS = "class";
public static final String LINE = "line";
private static EditorContext context;
public static EditorContext getContext () {
if (context == null) {
List l = DebuggerManager.getDebuggerManager ().lookup
(null, EditorContext.class);
context = (EditorContext) l.get (0);
int i, k = l.size ();
for (i = 1; i < k; i++)
context = new CompoundContextProvider (
(EditorContext) l.get (i),
context
);
}
return context;
}
/**
* Returns the parsed expression tree or <code>null</code>.
*
* @return the parsed expression tree or <code>null</code>
*
public static Tree getExpressionTree(final String expression, String url, final int line) {
// TODO: return getContext ().getExpressionTree ();
try {
return (Tree) getContext ().getClass().getMethod("getExpressionTree", new Class[] { String.class, String.class, Integer.TYPE }).
invoke(getContext(), new Object[] { expression, url, line });
} catch (java.lang.reflect.InvocationTargetException itex) {
Throwable tex = itex.getTargetException();
if (tex instanceof RuntimeException) {
throw (RuntimeException) tex;
} else {
ErrorManager.getDefault().notify(tex);
return null;
}
} catch (Exception ex) {
ErrorManager.getDefault().notify(ex);
return null;
}
}
*/
public static <R,D> R interpretOrCompileCode(final Expression<Object> expression,
final String url, final int line,
final ErrorAwareTreePathScanner<Boolean,D> canInterpret,
final ErrorAwareTreePathScanner<R,D> interpreter,
final D context, final boolean staticContext,
final Function<Pair<String, byte[]>, Boolean> compiledClassHandler,
final SourcePathProvider sp) throws InvalidExpressionException {
try {
return (R) getContext ().getClass().getMethod(
"interpretOrCompileCode",
new Class[] { Expression.class, String.class, Integer.TYPE,
ErrorAwareTreePathScanner.class, ErrorAwareTreePathScanner.class,
Object.class, Boolean.TYPE, Function.class,
SourcePathProvider.class }).
invoke(getContext(), new Object[] { expression, url, line,
canInterpret,
interpreter,
context, staticContext,
compiledClassHandler,
sp });
} catch (java.lang.reflect.InvocationTargetException itex) {
Throwable tex = itex.getTargetException();
if (tex instanceof RuntimeException) {
throw (RuntimeException) tex;
} else if (tex instanceof InvalidExpressionException) {
throw ((InvalidExpressionException) tex);
} else {
Exceptions.printStackTrace(tex);
return null;
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
return null;
}
}
// Utility methods .........................................................
public static String getFileName (LineBreakpoint b) {
try {
return new File (new URL (b.getURL ()).getFile ()).getName ();
} catch (MalformedURLException e) {
return null;
}
}
public static boolean showSource (LineBreakpoint b, Object timeStamp) {
if (b.getLineNumber () < 1)
return getContext().showSource (
b.getURL (),
1,
timeStamp
);
return getContext().showSource (
b.getURL (),
b.getLineNumber (),
timeStamp
);
}
public static String getRelativePath (
JPDAThread thread,
String stratumn
) {
try {
return convertSlash (thread.getSourcePath (stratumn));
} catch (AbsentInformationException e) {
return getRelativePath (thread.getClassName ());
}
}
public static String getRelativePath (
CallStackFrame csf,
String stratumn
) {
try {
return convertSlash (csf.getSourcePath (stratumn));
} catch (AbsentInformationException e) {
return getRelativePath (csf.getClassName ());
}
}
public static String getRelativePath (
String className
) {
int i = className.indexOf ('$');
if (i > 0) className = className.substring (0, i);
String sourceName = className.replace
('.', '/') + ".java";
return sourceName;
}
private static String convertSlash (String original) {
return original.replace (File.separatorChar, '/');
}
public static int getCurrentOffset() {
// TODO: return getContext ().getCurrentOffset();
try {
return (Integer) getContext ().getClass().getMethod("getCurrentOffset", new Class[] {}).
invoke(getContext(), new Object[] {});
} catch (java.lang.reflect.InvocationTargetException itex) {
Throwable tex = itex.getTargetException();
if (tex instanceof RuntimeException) {
throw (RuntimeException) tex;
} else {
Exceptions.printStackTrace(tex);
return 0;
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
return 0;
}
}
// innerclasses ............................................................
private static class CompoundContextProvider extends EditorContext {
private EditorContext cp1, cp2;
CompoundContextProvider (
EditorContext cp1,
EditorContext cp2
) {
this.cp1 = cp1;
this.cp2 = cp2;
}
public void createTimeStamp (Object timeStamp) {
cp1.createTimeStamp (timeStamp);
cp2.createTimeStamp (timeStamp);
}
public void disposeTimeStamp (Object timeStamp) {
cp1.disposeTimeStamp (timeStamp);
cp2.disposeTimeStamp (timeStamp);
}
public void updateTimeStamp (Object timeStamp, String url) {
cp1.updateTimeStamp (timeStamp, url);
cp2.updateTimeStamp (timeStamp, url);
}
public String getCurrentClassName () {
String s = cp1.getCurrentClassName ();
if (s.trim ().length () < 1)
return cp2.getCurrentClassName ();
return s;
}
public String getCurrentURL () {
String s = cp1.getCurrentURL ();
if (s.trim ().length () < 1)
return cp2.getCurrentURL ();
return s;
}
public String getCurrentFieldName () {
String s = cp1.getCurrentFieldName ();
if ( (s == null) || (s.trim ().length () < 1))
return cp2.getCurrentFieldName ();
return s;
}
public int getCurrentLineNumber () {
int i = cp1.getCurrentLineNumber ();
if (i < 1)
return cp2.getCurrentLineNumber ();
return i;
}
public int getCurrentOffset() {
Integer i = null;
try {
i = (Integer) cp1.getClass().getMethod("getCurrentOffset", new Class[] {}).
invoke(cp1, new Object[] {});
} catch (java.lang.reflect.InvocationTargetException itex) {
Throwable tex = itex.getTargetException();
if (tex instanceof RuntimeException) {
throw (RuntimeException) tex;
} else {
Exceptions.printStackTrace(tex);
return 0;
}
} catch (Exception ex) {
// Ignore, we have another attempt with cp2
//ErrorManager.getDefault().notify(ex);
}
if (i == null || i.intValue() < 1) {
try {
i = (Integer) cp2.getClass().getMethod("getCurrentOffset", new Class[] {}).
invoke(cp2, new Object[] {});
} catch (java.lang.reflect.InvocationTargetException itex) {
Throwable tex = itex.getTargetException();
if (tex instanceof RuntimeException) {
throw (RuntimeException) tex;
} else {
Exceptions.printStackTrace(tex);
return 0;
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
return 0;
}
}
return i.intValue();
}
public String getCurrentMethodName () {
String s = cp1.getCurrentMethodName ();
if ( (s == null) || (s.trim ().length () < 1))
return cp2.getCurrentMethodName ();
return s;
}
public String getSelectedIdentifier () {
String s = cp1.getSelectedIdentifier ();
if ( (s == null) || (s.trim ().length () < 1))
return cp2.getSelectedIdentifier ();
return s;
}
public String getSelectedMethodName () {
String s = cp1.getSelectedMethodName ();
if ( (s == null) || (s.trim ().length () < 1))
return cp2.getSelectedMethodName ();
return s;
}
public void removeAnnotation (Object annotation) {
CompoundAnnotation ca = (CompoundAnnotation) annotation;
cp1.removeAnnotation (ca.annotation1);
cp2.removeAnnotation (ca.annotation2);
}
public Object annotate (
String sourceName,
int lineNumber,
String annotationType,
Object timeStamp
) {
CompoundAnnotation ca = new CompoundAnnotation ();
ca.annotation1 = cp1.annotate
(sourceName, lineNumber, annotationType, timeStamp);
ca.annotation2 = cp2.annotate
(sourceName, lineNumber, annotationType, timeStamp);
return ca;
}
public <R,D> R interpretOrCompileCode(final Expression<Object> expression,
final String url, final int line,
final ErrorAwareTreePathScanner<Boolean,D> canInterpret,
final ErrorAwareTreePathScanner<R,D> interpreter,
final D context, final boolean staticContext,
final Function<Pair<String, byte[]>, Boolean> compiledClassHandler,
final SourcePathProvider sp) throws InvalidExpressionException {
R ret = null;
try {
ret = (R) cp1.getClass().getMethod(
"interpretOrCompileCode",
new Class[] { Expression.class, String.class, Integer.TYPE, ErrorAwareTreePathScanner.class,
ErrorAwareTreePathScanner.class, Object.class, Boolean.TYPE, Function.class,
SourcePathProvider.class }).
invoke(cp1, new Object[] { expression, url, line, canInterpret, interpreter,
context, staticContext, compiledClassHandler, sp });
} catch (java.lang.reflect.InvocationTargetException itex) {
Throwable tex = itex.getTargetException();
if (tex instanceof RuntimeException) {
throw (RuntimeException) tex;
} else {
Exceptions.printStackTrace(tex);
}
} catch (Exception ex) {
// Ignore, we have another attempt with cp2
}
if (ret == null) {
try {
ret = (R) cp2.getClass().getMethod(
"interpretOrCompileCode",
new Class[] { Expression.class, String.class, Integer.TYPE, ErrorAwareTreePathScanner.class,
ErrorAwareTreePathScanner.class, Object.class, Boolean.TYPE, Function.class,
SourcePathProvider.class }).
invoke(cp2, new Object[] { expression, url, line, canInterpret, interpreter,
context, staticContext, compiledClassHandler, sp });
} catch (java.lang.reflect.InvocationTargetException itex) {
Throwable tex = itex.getTargetException();
if (tex instanceof RuntimeException) {
throw (RuntimeException) tex;
} else {
Exceptions.printStackTrace(tex);
}
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
}
}
return ret;
}
public int getLineNumber (Object annotation, Object timeStamp) {
int ln = cp1.getLineNumber (annotation, timeStamp);
if (ln >= 0) return ln;
return cp2.getLineNumber (annotation, timeStamp);
}
public boolean showSource (String sourceName, int lineNumber, Object timeStamp) {
return cp1.showSource (sourceName, lineNumber, timeStamp) |
cp2.showSource (sourceName, lineNumber, timeStamp);
}
public int getFieldLineNumber (
String url,
String className,
String fieldName
) {
int ln = cp1.getFieldLineNumber (url, className, fieldName);
if (ln != -1) return ln;
return cp2.getFieldLineNumber (url, className, fieldName);
}
public String getClassName (
String url,
int lineNumber
) {
String className = cp1.getClassName (url, lineNumber);
if (className != null && className.length() > 0) return className;
return cp2.getClassName (url, lineNumber);
}
public String[] getImports (String url) {
String[] r1 = cp1.getImports (url);
String[] r2 = cp2.getImports (url);
String[] r = new String [r1.length + r2.length];
System.arraycopy (r1, 0, r, 0, r1.length);
System.arraycopy (r2, 0, r, r1.length, r2.length);
return r;
}
public void addPropertyChangeListener (PropertyChangeListener l) {
cp1.addPropertyChangeListener (l);
cp2.addPropertyChangeListener (l);
}
public void removePropertyChangeListener (PropertyChangeListener l) {
cp1.removePropertyChangeListener (l);
cp2.removePropertyChangeListener (l);
}
public void addPropertyChangeListener (
String propertyName,
PropertyChangeListener l
) {
cp1.addPropertyChangeListener (propertyName, l);
cp2.addPropertyChangeListener (propertyName, l);
}
public void removePropertyChangeListener (
String propertyName,
PropertyChangeListener l
) {
cp1.removePropertyChangeListener (propertyName, l);
cp2.removePropertyChangeListener (propertyName, l);
}
@Override
public Operation[] getOperations(String url, int lineNumber, BytecodeProvider bytecodeProvider) {
Operation[] operations = cp1.getOperations(url, lineNumber, bytecodeProvider);
if (operations != null) {
return operations;
} else {
return cp2.getOperations(url, lineNumber, bytecodeProvider);
}
}
@Override
public MethodArgument[] getArguments(String url, Operation operation) {
MethodArgument[] args;
try {
args = cp1.getArguments(url, operation);
} catch (UnsupportedOperationException uoex) {
args = cp2.getArguments(url, operation);
}
return args;
}
@Override
public MethodArgument[] getArguments(String url, int methodLineNumber) {
MethodArgument[] args;
try {
args = cp1.getArguments(url, methodLineNumber);
} catch (UnsupportedOperationException uoex) {
args = cp2.getArguments(url, methodLineNumber);
}
return args;
}
}
private static class CompoundAnnotation {
public CompoundAnnotation() {}
Object annotation1;
Object annotation2;
}
}