/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common
* Development and Distribution License("CDDL") (collectively, the
* "License"). You may not use this file except in compliance with the
* License. You can obtain a copy of the License at
* http://www.netbeans.org/cddl-gplv2.html
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
* specific language governing permissions and limitations under the
* License. When distributing the software, include this License Header
* Notice in each file and include the License file at
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the
* License Header, with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Contributor(s):
*
* The Original Software is NetBeans. The Initial Developer of the Original
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
* Micro//S ystems, Inc. All Rights Reserved.
*
* ThorTech L.L.C. elects to include this software in this distribution
* under the GNU General Public License, version 2
* (http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) with classpath
* exception (http://www.gnu.org/software/classpath/license.html).
*
*(comment
*******************************************************************************
* Copyright (c) ThorTech, L.L.C. All rights reserved.
* The use and distribution terms for this software are covered by the
* GNU General Public License, version 2
* (http://www.gnu.org/licenses/old-licenses/gpl-2.0.html) with classpath
* exception (http://www.gnu.org/software/classpath/license.html)
* which can be found in the file GPL-2.0+ClasspathException.txt at the root
* of this distribution.
* By using this software in any fashion, you are agreeing to be bound by
* the terms of this license.
* You must not remove this notice, or any other, from this software.
*******************************************************************************)
*/
package org.enclojure.ide.debugger;
import com.sun.jdi.AbsentInformationException;
import com.sun.jdi.StackFrame;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.netbeans.api.debugger.Properties;
import org.netbeans.spi.debugger.ContextProvider;
import org.netbeans.api.debugger.DebuggerManager;
import org.netbeans.api.debugger.jpda.CallStackFrame;
import org.netbeans.api.debugger.jpda.Field;
import org.netbeans.api.debugger.jpda.JPDADebugger;
import org.netbeans.api.debugger.jpda.JPDAThread;
import org.netbeans.spi.debugger.jpda.EditorContext;
import org.netbeans.spi.debugger.jpda.EditorContext.Operation;
import org.netbeans.spi.debugger.jpda.SourcePathProvider;
import java.util.logging.Level;
import org.enclojure.ide.core.LogAdapter;
@SuppressWarnings("unchecked")
public class CljSourcePath {
private static final LogAdapter LOG = new LogAdapter(CljSourcePath.class.getName());
private ContextProvider contextProvider;
private SourcePathProvider sourcePathProvider;
private JPDADebugger debugger;
public CljSourcePath(ContextProvider contextProvider) {
this.contextProvider = contextProvider;
debugger = contextProvider.lookupFirst(null, JPDADebugger.class);
getContext();// To initialize the source path provider
}
private SourcePathProvider getContext() {
if (sourcePathProvider == null) {
List l = contextProvider.lookup(null, SourcePathProvider.class);
sourcePathProvider = (SourcePathProvider) l.get(0);
int i, k = l.size();
for (i = 1; i < k; i++) {
sourcePathProvider = new CompoundContextProvider(
(SourcePathProvider) l.get(i),
sourcePathProvider);
}
initSourcePaths();
}
return sourcePathProvider;
}
static SourcePathProvider getDefaultContext() {
List providers = DebuggerManager.getDebuggerManager().
lookup("netbeans-JPDASession", SourcePathProvider.class);
for (Iterator it = providers.iterator(); it.hasNext();) {
Object provider = it.next();
// Hack - find our provider:
if (provider.getClass().getName().equals("org.netbeans.modules.debugger.jpda.projects.SourcePathProviderImpl")) {
return (SourcePathProvider) provider;
}
}
return null;
}
// 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);
}
/**
* 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) {
return getContext().getURL(relativePath, global);
}
public String getURL(
StackFrame sf,
String stratumn) {
try {
return getURL(
convertSlash(sf.location().sourcePath(stratumn)),
true);
} catch (AbsentInformationException e) {
return getURL(
convertClassNameToRelativePath(
sf.location().declaringType().name()),
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();
}
/**
* 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 boolean sourceAvailable(
String relativePath,
boolean global) {
return getURL(relativePath, global) != null;
}
public boolean sourceAvailable(
JPDAThread t,
String stratumn,
boolean global) {
try {
return sourceAvailable(
convertSlash(t.getSourcePath(stratumn)), global);
} catch (AbsentInformationException e) {
return sourceAvailable(
convertClassNameToRelativePath(t.getClassName()), global);
}
}
public boolean sourceAvailable(
Field f) {
String className = f.getClassName();
return sourceAvailable(className, true);
}
public boolean sourceAvailable(
CallStackFrame csf,
String stratumn) {
try {
return sourceAvailable(
convertSlash(csf.getSourcePath(stratumn)), true);
} catch (AbsentInformationException e) {
return sourceAvailable(
convertClassNameToRelativePath(csf.getClassName()), true);
}
}
public String getURL(
CallStackFrame csf,
String stratumn) {
try {
return getURL(convertSlash(csf.getSourcePath(stratumn)), true);
} catch (AbsentInformationException e) {
return getURL(
convertClassNameToRelativePath(csf.getClassName()), true);
}
}
public boolean showSource(
JPDAThread t,
String stratumn) {
int lineNumber = t.getLineNumber(stratumn);
if (lineNumber < 1) {
lineNumber = 1;
}
try {
return EditorContextBridge.getContext().showSource(
getURL(convertSlash(t.getSourcePath(stratumn)), true),
lineNumber,
debugger);
} catch (AbsentInformationException e) {
return EditorContextBridge.getContext().showSource(
getURL(
convertClassNameToRelativePath(t.getClassName()), true),
lineNumber,
debugger);
}
}
public boolean showSource(CallStackFrame csf, String stratumn) {
try {
String url = getURL(
convertSlash(csf.getSourcePath(stratumn)), true);
if (url == null) {
stratumn = csf.getDefaultStratum();
url = getURL(
convertSlash(csf.getSourcePath(stratumn)), true);
}
if (url == null) {
LOG.log(Level.WARNING,
"Show Source: No URL for source path " + csf.getSourcePath(stratumn) +
"\nThe reason is likely no opened project for this source file.");
return false;
}
int lineNumber = csf.getLineNumber(stratumn);
if (lineNumber < 1) {
lineNumber = 1;
}
return EditorContextBridge.getContext().showSource(
url,
lineNumber,
debugger);
} catch (AbsentInformationException e) {
String url = getURL(
convertClassNameToRelativePath(csf.getClassName()), true);
if (url == null) {
LOG.log(Level.WARNING,
"Show Source: No source URL for class " + csf.getClassName() +
"\nThe reason is likely no opened project for the source file.");
return false;
}
return EditorContextBridge.getContext().showSource(
url,
1,
debugger);
}
}
public boolean showSource(Field v) {
String fieldName = ((Field) v).getName();
String className = className = ((Field) v).getClassName();
String url = getURL(
EditorContextBridge.getRelativePath(className), true);
if (url == null) {
return false;
}
int lineNumber = lineNumber = EditorContextBridge.getContext().getFieldLineNumber(
url,
className,
fieldName);
if (lineNumber < 1) {
lineNumber = 1;
}
return EditorContextBridge.getContext().showSource(
url,
lineNumber,
debugger);
}
private static String convertSlash(String original) {
return original.replace(File.separatorChar, '/');
}
public static String convertClassNameToRelativePath(
String className) {
LOG.log(Level.WARNING,
"convertClassNameToRelativePath called for class " + className);
return "";
}
public Object annotate(
JPDAThread t,
String stratumn) {
int lineNumber = t.getLineNumber(stratumn);
if (lineNumber < 1) {
return null;
//AST ast = t.getAST(stratumn);
}
Operation operation = t.getCurrentOperation();
String url;
try {
url = getURL(convertSlash(t.getSourcePath(stratumn)), true);
} catch (AbsentInformationException e) {
url = getURL(convertClassNameToRelativePath(t.getClassName()), true);
}
List operationsAnn = annotateOperations(debugger, url, operation, t.getLastOperations(), lineNumber);
if (operation == null) {
if (operationsAnn.size() == 0) {
return EditorContextBridge.getContext().annotate(
url,
lineNumber,
EditorContext.CURRENT_LINE_ANNOTATION_TYPE,
debugger);
} else {
/*
operationsAnn.add(EditorContextBridge.annotate (
url,
lineNumber,
EditorContext.CURRENT_LINE_ANNOTATION_TYPE,
debugger
));
*/
}
}
return operationsAnn;
}
public Object annotate(
CallStackFrame csf,
String stratumn) {
int lineNumber = csf.getLineNumber(stratumn);
if (lineNumber < 1) {
return null;
}
Operation operation = csf.getCurrentOperation(stratumn);
try {
if (operation != null) {
int startOffset;
int endOffset;
if (operation.getMethodName() != null) {
startOffset = operation.getMethodStartPosition().getOffset();
endOffset = operation.getMethodEndPosition().getOffset();
} else {
startOffset = operation.getStartPosition().getOffset();
endOffset = operation.getEndPosition().getOffset();
}
return EditorContextBridge.getContext().annotate(
getURL(convertSlash(csf.getSourcePath(stratumn)), true),
startOffset,
endOffset,
EditorContext.CALL_STACK_FRAME_ANNOTATION_TYPE,
debugger);
} else {
return EditorContextBridge.getContext().annotate(
getURL(convertSlash(csf.getSourcePath(stratumn)), true),
lineNumber,
EditorContext.CALL_STACK_FRAME_ANNOTATION_TYPE,
debugger);
}
} catch (AbsentInformationException e) {
return EditorContextBridge.getContext().annotate(
getURL(
convertClassNameToRelativePath(csf.getClassName()), true),
lineNumber,
EditorContext.CALL_STACK_FRAME_ANNOTATION_TYPE,
debugger);
}
}
private static List annotateOperations(JPDADebugger debugger, String url,
Operation currentOperation, List lastOperations,
int locLineNumber) {
List annotations = null;
if (currentOperation != null) {
annotations = new ArrayList();
annotations.add(createAnnotation(debugger, url, currentOperation,
EditorContext.CURRENT_LINE_ANNOTATION_TYPE,
true));
int lineNumber;
if (currentOperation.getMethodName() != null) {
lineNumber = currentOperation.getMethodStartPosition().getLine();
} else {
lineNumber = currentOperation.getStartPosition().getLine();
}
annotations.add(EditorContextBridge.getContext().annotate(
url,
lineNumber,
EditorContext.CURRENT_EXPRESSION_CURRENT_LINE_ANNOTATION_TYPE,
debugger));
}
boolean isNewLineExp = false;
if (lastOperations != null && lastOperations.size() > 0) {
if (annotations == null) {
annotations = new ArrayList();
}
isNewLineExp = currentOperation == null;
for (int i = 0; i < lastOperations.size(); i++) {
Operation lastOperation = (Operation) lastOperations.get(i);
if (currentOperation == lastOperation && i == lastOperations.size() - 1) {
annotations.add(createAnnotation(debugger, url,
lastOperation,
EditorContext.CURRENT_OUT_OPERATION_ANNOTATION_TYPE,
false));
int lineNumber = lastOperation.getEndPosition().getLine();
annotations.add(EditorContextBridge.getContext().annotate(
url,
lineNumber,
EditorContext.CURRENT_EXPRESSION_CURRENT_LINE_ANNOTATION_TYPE,
debugger));
isNewLineExp = false;
} else {
annotations.add(createAnnotation(debugger, url,
lastOperation,
EditorContext.CURRENT_LAST_OPERATION_ANNOTATION_TYPE,
true));
}
}
}
if (isNewLineExp) {
annotations.add(EditorContextBridge.getContext().annotate(
url,
locLineNumber,
EditorContext.CURRENT_LINE_ANNOTATION_TYPE,
debugger));
}
if (annotations != null) {
return annotations;
} else {
return Collections.EMPTY_LIST;
}
}
private static Object createAnnotation(JPDADebugger debugger, String url,
Operation operation, String type,
boolean method) {
int startOffset;
int endOffset;
if (method && operation.getMethodName() != null) {
startOffset = operation.getMethodStartPosition().getOffset();
endOffset = operation.getMethodEndPosition().getOffset();
} else {
startOffset = operation.getStartPosition().getOffset();
endOffset = operation.getEndPosition().getOffset();
}
return EditorContextBridge.getContext().annotate(
url,
startOffset,
endOffset,
type,
debugger);
}
// 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) {
return p1;
}
return cp2.getURL(relativePath, global);
}
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[] 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 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);
}
}
private void initSourcePaths() {
Properties properties = Properties.getDefault().
getProperties("debugger").getProperties("sources");
Set originalSourceRoots = new HashSet(Arrays.asList(
sourcePathProvider.getOriginalSourceRoots()));
Set sourceRoots = new HashSet(Arrays.asList(
sourcePathProvider.getSourceRoots()));
Iterator enabledSourceRoots = properties.getProperties("source_roots").
getCollection("enabled", Collections.EMPTY_SET).iterator();
while (enabledSourceRoots.hasNext()) {
String root = (String) enabledSourceRoots.next();
if (originalSourceRoots.contains(root)) {
sourceRoots.add(root);
}
}
Iterator disabledSourceRoots = properties.getProperties("source_roots").
getCollection("disabled", Collections.EMPTY_SET).iterator();
while (disabledSourceRoots.hasNext()) {
String root = (String) disabledSourceRoots.next();
sourceRoots.remove(root);
}
String[] ss = new String[sourceRoots.size()];
sourcePathProvider.setSourceRoots((String[]) sourceRoots.toArray(ss));
}
private static class CompoundAnnotation {
Object annotation1;
Object annotation2;
}
}