blob: 7fcc4e1cca698fe44487533125d18e04d122c99b [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 com.sun.jdi.Location;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.StackFrame;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.modules.debugger.jpda.jdi.InternalExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.InvalidStackFrameExceptionWrapper;
import org.netbeans.modules.debugger.jpda.jdi.ObjectCollectedExceptionWrapper;
import org.netbeans.spi.debugger.ContextProvider;
import org.netbeans.api.debugger.jpda.CallStackFrame;
import org.netbeans.api.debugger.jpda.Field;
import org.netbeans.api.debugger.jpda.JPDAClassType;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.JPDAThread;
import org.netbeans.modules.debugger.jpda.jdi.LocationWrapper;
import org.netbeans.modules.debugger.jpda.jdi.ReferenceTypeWrapper;
import org.netbeans.modules.debugger.jpda.jdi.StackFrameWrapper;
import org.netbeans.modules.debugger.jpda.jdi.VMDisconnectedExceptionWrapper;
import org.netbeans.modules.debugger.jpda.models.CallStackFrameImpl;
import org.netbeans.spi.debugger.jpda.SourcePathProvider;
import org.netbeans.spi.debugger.jpda.EditorContext;
import org.openide.util.Exceptions;
/**
* Utility methods for sources.
*
* @see Similar class in debuggerjpda/ui when modifying this.
*
* @author Jan Jancura
*/
public class SourcePath {
private ContextProvider lookupProvider;
private SourcePathProvider contextProvider;
private JPDADebugger debugger;
public SourcePath (ContextProvider lookupProvider) {
this.lookupProvider = lookupProvider;
debugger = lookupProvider.lookupFirst(null, JPDADebugger.class);
}
public SourcePathProvider getContext () {
if (contextProvider == null) {
List l = lookupProvider.lookup (null, SourcePathProvider.class);
contextProvider = (SourcePathProvider) l.get (0);
int i, k = l.size ();
for (i = 1; i < k; i++) {
contextProvider = new CompoundContextProvider (
(SourcePathProvider) l.get (i),
contextProvider
);
}
}
return contextProvider;
}
// ContextProvider methods .................................................
/**
* Returns relative path for given url.
*
* @param url a url of resource file
* @param directorySeparator a directory separator character
* @param includeExtension whether the file extension should be included
* in the result
*
* @return relative path
*/
public String getRelativePath (
String url,
char directorySeparator,
boolean includeExtension
) {
return getContext ().getRelativePath
(url, directorySeparator, includeExtension);
}
/**
* Returns the source root (if any) for given url.
*
* @param url a url of resource file
*
* @return the source root or <code>null</code> when no source root was found.
*/
public String getSourceRoot(String url) {
return getContext().getSourceRoot(url);
}
/**
* Translates a relative path ("java/lang/Thread.java") to url
* ("file:///C:/Sources/java/lang/Thread.java"). Uses GlobalPathRegistry
* if global == true.
*
* @param relativePath a relative path (java/lang/Thread.java)
* @param global true if global path should be used
* @return url
*/
public String getURL (String relativePath, boolean global) {
String url = getContext ().getURL (relativePath, global);
if (url != null) {
try {
new java.net.URL(url);
} catch (java.net.MalformedURLException muex) {
Logger.getLogger(SourcePath.class.getName()).log(Level.WARNING,
"Malformed URL '"+url+"' produced by "+getContext (), muex);
return null;
}
}
return url;
}
public String getURL(JPDAClassType clazz, String stratum) {
SourcePathProvider context = getContext();
try {
String url = (String) context.getClass().
getMethod("getURL", JPDAClassType.class, String.class).
invoke(context, clazz, stratum);
if (url != null) {
try {
new java.net.URL(url);
} catch (java.net.MalformedURLException muex) {
Logger.getLogger(SourcePath.class.getName()).log(Level.WARNING,
"Malformed URL '"+url+"' produced by "+getContext (), muex);
return null;
}
return url;
}
} catch (NoSuchMethodException ex) {
} catch (SecurityException ex) {
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException ex) {
} catch (InvocationTargetException ex) {
}
String typePath = EditorContextBridge.getRelativePath (clazz.getName());
return getURL(typePath, true);
}
public String getURL (
CallStackFrame csf,
String stratumn
) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, InvalidStackFrameExceptionWrapper, ObjectCollectedExceptionWrapper {
return getURL(StackFrameWrapper.location(((CallStackFrameImpl) csf).getStackFrame()), stratumn);
}
public String getURL (
StackFrame sf,
String stratumn
) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, InvalidStackFrameExceptionWrapper, ObjectCollectedExceptionWrapper {
return getURL(StackFrameWrapper.location(sf), stratumn);
}
public String getURL(JPDAThread t, String stratum) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, InvalidStackFrameExceptionWrapper, ObjectCollectedExceptionWrapper {
String url;
try {
CallStackFrame[] callStacks = t.getCallStack(0, 1);
if (callStacks.length > 0) {
url = getURL(callStacks[0], stratum);
} else {
String sourcePath = convertSlash (t.getSourcePath (stratum));
url = getURL (sourcePath, true);
}
} catch (AbsentInformationException e) {
String sourcePath = convertClassNameToRelativePath (t.getClassName ());
url = getURL (sourcePath, true);
}
return url;
}
public String getURL (
Location loc,
String stratumn
) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, ObjectCollectedExceptionWrapper {
ReferenceType declaringType = LocationWrapper.declaringType(loc);
JPDAClassType classType = ((JPDADebuggerImpl) debugger).getClassType(declaringType);
return getURL(classType, loc, stratumn);
}
private String getURL (
JPDAClassType classType,
Location loc,
String stratumn
) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper, ObjectCollectedExceptionWrapper {
if (classType != null) {
SourcePathProvider context = getContext();
try {
String url = (String) context.getClass().
getMethod("getURL", JPDAClassType.class, String.class).
invoke(context, classType, stratumn);
if (url != null) {
try {
new java.net.URL(url);
return url;
} catch (java.net.MalformedURLException muex) {
Logger.getLogger(SourcePath.class.getName()).log(Level.WARNING,
"Malformed URL '"+url+"' produced by "+getContext (), muex);
}
}
} catch (NoSuchMethodException ex) {
} catch (SecurityException ex) {
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException ex) {
} catch (InvocationTargetException ex) {
}
}
String sourcePath;
if (loc == null) {
sourcePath = EditorContextBridge.getRelativePath (classType.getName());
} else {
try {
sourcePath = convertSlash(LocationWrapper.sourcePath(loc, stratumn));
} catch (AbsentInformationException e) {
sourcePath = convertClassNameToRelativePath (
ReferenceTypeWrapper.name(LocationWrapper.declaringType(loc))
);
}
}
return getURL(sourcePath, true);
}
/**
* Returns array of source roots.
*/
public String[] getSourceRoots () {
return getContext ().getSourceRoots ();
}
/**
* Sets array of source roots.
*
* @param sourceRoots a new array of sourceRoots
*/
public void setSourceRoots (String[] sourceRoots) {
getContext ().setSourceRoots (sourceRoots);
}
/**
* Returns set of original source roots.
*
* @return set of original source roots
*/
public String[] getOriginalSourceRoots () {
return getContext ().getOriginalSourceRoots ();
}
/**
* Returns the project's source roots.
*
* @return array of source roots belonging to the project
*/
public String[] getProjectSourceRoots() {
try {
java.lang.reflect.Method getProjectSourceRootsMethod = getContext().getClass().getMethod("getProjectSourceRoots", new Class[] {}); // NOI18N
String[] projectSourceRoots = (String[]) getProjectSourceRootsMethod.invoke(getContext(), new Object[] {});
return projectSourceRoots;
} catch (Exception ex) {
Exceptions.printStackTrace(ex);
return new String[] {};
}
}
/**
* Adds property change listener.
*
* @param l new listener.
*/
public void addPropertyChangeListener (PropertyChangeListener l) {
getContext ().addPropertyChangeListener (l);
}
/**
* Removes property change listener.
*
* @param l removed listener.
*/
public void removePropertyChangeListener (
PropertyChangeListener l
) {
getContext ().removePropertyChangeListener (l);
}
// utility methods .........................................................
public static String convertSlash (String original) {
return original.replace (File.separatorChar, '/');
}
public static String convertClassNameToRelativePath (
String className
) {
int i = className.indexOf ('$');
if (i > 0) className = className.substring (0, i);
String sourceName = className.replace
('.', '/') + ".java";
return sourceName;
}
// innerclasses ............................................................
private static class CompoundContextProvider extends SourcePathProvider {
private SourcePathProvider cp1, cp2;
CompoundContextProvider (
SourcePathProvider cp1,
SourcePathProvider cp2
) {
this.cp1 = cp1;
this.cp2 = cp2;
}
public String getURL (String relativePath, boolean global) {
String p1 = cp1.getURL (relativePath, global);
if (p1 != null) {
try {
new java.net.URL(p1);
return p1;
} catch (java.net.MalformedURLException muex) {
Logger.getLogger(SourcePath.class.getName()).log(Level.WARNING,
"Malformed URL '"+p1+"' produced by "+cp1, muex);
}
}
p1 = cp2.getURL (relativePath, global);
if (p1 != null) {
try {
new java.net.URL(p1);
} catch (java.net.MalformedURLException muex) {
Logger.getLogger(SourcePath.class.getName()).log(Level.WARNING,
"Malformed URL '"+p1+"' produced by "+cp2, muex);
p1 = null;
}
}
return p1;
}
public String getURL(JPDAClassType clazz, String stratum) {
try {
java.lang.reflect.Method getURLMethod = cp1.getClass().getMethod("getURL", JPDAClassType.class, String.class); // NOI18N
String url = (String) getURLMethod.invoke(cp1, clazz, stratum);
if (url != null) {
return url;
}
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException ex) {
} catch (NoSuchMethodException ex) {
} catch (SecurityException ex) {
} catch (InvocationTargetException ex) {
}
try {
java.lang.reflect.Method getURLMethod = cp2.getClass().getMethod("getURL", JPDAClassType.class, String.class); // NOI18N
String url = (String) getURLMethod.invoke(cp2, clazz, stratum);
if (url != null) {
return url;
}
} catch (IllegalAccessException ex) {
} catch (IllegalArgumentException ex) {
} catch (NoSuchMethodException ex) {
} catch (SecurityException ex) {
} catch (InvocationTargetException ex) {
}
return null;
}
public String getRelativePath (
String url,
char directorySeparator,
boolean includeExtension
) {
String p1 = cp1.getRelativePath (
url,
directorySeparator,
includeExtension
);
if (p1 != null) return p1;
return cp2.getRelativePath (
url,
directorySeparator,
includeExtension
);
}
public String getSourceRoot(String url) {
String sourceRoot = cp1.getSourceRoot(url);
if (sourceRoot == null) {
sourceRoot = cp2.getSourceRoot(url);
}
return sourceRoot;
}
public String[] getSourceRoots () {
String[] fs1 = cp1.getSourceRoots ();
String[] fs2 = cp2.getSourceRoots ();
String[] fs = new String [fs1.length + fs2.length];
System.arraycopy (fs1, 0, fs, 0, fs1.length);
System.arraycopy (fs2, 0, fs, fs1.length, fs2.length);
return fs;
}
public String[] getOriginalSourceRoots () {
String[] fs1 = cp1.getOriginalSourceRoots ();
String[] fs2 = cp2.getOriginalSourceRoots ();
String[] fs = new String [fs1.length + fs2.length];
System.arraycopy (fs1, 0, fs, 0, fs1.length);
System.arraycopy (fs2, 0, fs, fs1.length, fs2.length);
return fs;
}
public String[] getProjectSourceRoots() {
String[] projectSourceRoots1;
String[] projectSourceRoots2;
//System.err.println("\nCompoundContextProvider["+toString()+"].getProjectSourceRoots()...\n");
try {
java.lang.reflect.Method getProjectSourceRootsMethod = cp1.getClass().getMethod("getProjectSourceRoots", new Class[] {}); // NOI18N
projectSourceRoots1 = (String[]) getProjectSourceRootsMethod.invoke(cp1, new Object[] {});
} catch (Exception ex) {
projectSourceRoots1 = new String[0];
}
try {
java.lang.reflect.Method getProjectSourceRootsMethod = cp2.getClass().getMethod("getProjectSourceRoots", new Class[] {}); // NOI18N
projectSourceRoots2 = (String[]) getProjectSourceRootsMethod.invoke(cp2, new Object[] {});
} catch (Exception ex) {
projectSourceRoots2 = new String[0];
}
if (projectSourceRoots1.length == 0) {
//System.err.println("\nCompoundContextProvider.getProjectSourceRoots() = "+java.util.Arrays.toString(projectSourceRoots2)+"\n");
return projectSourceRoots2;
}
if (projectSourceRoots2.length == 0) {
//System.err.println("\nCompoundContextProvider.getProjectSourceRoots() = "+java.util.Arrays.toString(projectSourceRoots1)+"\n");
return projectSourceRoots1;
}
String[] projectSourceRoots = new String[projectSourceRoots1.length + projectSourceRoots2.length];
System.arraycopy (projectSourceRoots1, 0, projectSourceRoots, 0, projectSourceRoots1.length);
System.arraycopy (projectSourceRoots2, 0, projectSourceRoots, projectSourceRoots1.length, projectSourceRoots2.length);
//System.err.println("\nCompoundContextProvider.getProjectSourceRoots() = "+java.util.Arrays.toString(projectSourceRoots)+"\n");
return projectSourceRoots;
}
public void setSourceRoots (String[] sourceRoots) {
cp1.setSourceRoots (sourceRoots);
cp2.setSourceRoots (sourceRoots);
}
public void addPropertyChangeListener (PropertyChangeListener l) {
cp1.addPropertyChangeListener (l);
cp2.addPropertyChangeListener (l);
}
public void removePropertyChangeListener (PropertyChangeListener l) {
cp1.removePropertyChangeListener (l);
cp2.removePropertyChangeListener (l);
}
@Override
public String toString() {
return "CompoundContextProvider["+cp1.toString()+", "+cp2.toString()+"]";
}
}
}