/* * 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 Micro//S ystems, Inc. Portions Copyright 1997-2007 Sun * Micro//S ystems, Inc. All Rights Reserved. * * If you wish your version of this file to be governed by only the CDDL * or only the GPL Version 2, indicate your decision by adding * "[Contributor] elects to include this software in this distribution * under the [CDDL or GPL Version 2] license." If you do not indicate a * single choice of license, a recipient has the option to distribute * your version of this file under either the CDDL, the GPL Version 2 or * to extend the choice of license to its licensees as provided above. * However, if you add GPL Version 2 code and therefore, elected the GPL * Version 2 license, then the option applies only if the new code is * made subject to such option by the copyright holder. */ package org.netbeans.modules.scala.debugger; import com.sun.jdi.AbsentInformationException; import java.beans.PropertyChangeListener; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.netbeans.api.debugger.Breakpoint.VALIDITY; import org.netbeans.api.debugger.DebuggerManager; import org.netbeans.api.debugger.jpda.FieldBreakpoint; import org.netbeans.api.debugger.jpda.JPDABreakpoint; import org.netbeans.api.debugger.jpda.LineBreakpoint; import org.netbeans.api.debugger.jpda.MethodBreakpoint; import org.netbeans.api.debugger.jpda.CallStackFrame; import org.netbeans.api.debugger.jpda.JPDAThread; import org.netbeans.spi.debugger.jpda.EditorContext; import org.netbeans.spi.debugger.jpda.SourcePathProvider; import org.openide.ErrorManager; /** * * @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; } // ContextProvider methods ................................................. /** * Returns signature of method currently selected in editor or <code>null</code>. * * @return signature of method currently selected in editor or <code>null</code> */ public static String getCurrentMethodSignature () { // TODO: return getContext ().getCurrentMethodSignature (); try { return (String) getContext ().getClass().getMethod("getCurrentMethodSignature", new Class[] {}). invoke(getContext(), new Object[] {}); } catch (java.lang.reflect.InvocationTargetException itex) { Throwable tex = itex.getTargetException(); if (tex instanceof RuntimeException) { throw (RuntimeException) tex; } else { ErrorManager.getDefault().notify(tex); return ""; } } catch (Exception ex) { ErrorManager.getDefault().notify(ex); return ""; } } // 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 EditorContextBridge.getContext().showSource ( b.getURL (), 1, timeStamp ); return EditorContextBridge.getContext().showSource ( b.getURL (), b.getLineNumber (), timeStamp ); } public static String getDefaultType () { String id = getContext().getSelectedIdentifier (); try { if (id != null) { if (id.equals(getContext().getCurrentMethodName())) return METHOD; String s = getContext().getCurrentClassName(); int i = s.lastIndexOf ('.'); if (i >= 0) s = s.substring (i + 1); if (id.equals (s)) return CLASS; return FIELD; } else { String s = getContext().getCurrentFieldName (); if (s != null && s.length () > 0) return FIELD; s = getContext().getCurrentMethodName(); if (s != null && s.length () > 0) return METHOD; if (s != null && s.length () < 1) { s = getContext().getCurrentClassName (); if (s.length () > 0) return CLASS; } } } catch (java.awt.IllegalComponentStateException icsex) {} return null; } public static Object annotate ( LineBreakpoint b ) { String url = b.getURL (); int lineNumber = b.getLineNumber (); if (lineNumber < 1) return null; String condition = b.getCondition (); boolean isConditional = (condition != null) && !"".equals (condition.trim ()); // NOI18N boolean isInvalid = b.getValidity() == VALIDITY.INVALID; String annotationType = b.isEnabled () ? (isConditional ? EditorContext.CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE : EditorContext.BREAKPOINT_ANNOTATION_TYPE) : (isConditional ? EditorContext.DISABLED_CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE : EditorContext.DISABLED_BREAKPOINT_ANNOTATION_TYPE); if (isInvalid && b.isEnabled ()) annotationType += "_broken"; return getContext().annotate ( url, lineNumber, annotationType, null ); } public static Object[] annotate ( JPDABreakpoint b ) { String[] URLs; int[] lineNumbers; String condition; if (b instanceof LineBreakpoint) { URLs = new String[] { ((LineBreakpoint) b).getURL () }; lineNumbers = new int[] { ((LineBreakpoint) b).getLineNumber() }; condition = ((LineBreakpoint) b).getCondition(); } else if (b instanceof FieldBreakpoint) { String className = ((FieldBreakpoint) b).getClassName(); URLs = getClassURLs(SourcePath.convertClassNameToRelativePath(className)); lineNumbers = new int[URLs.length]; for (int i = 0; i < URLs.length; i++) { lineNumbers[i] = getContext().getFieldLineNumber(URLs[i], className, ((FieldBreakpoint) b).getFieldName()); } condition = ((FieldBreakpoint) b).getCondition(); } else if (b instanceof MethodBreakpoint) { String[] filters = ((MethodBreakpoint) b).getClassFilters(); String[] urls = new String[] {}; int[] lns = new int[] {}; for (int i = 0; i < filters.length; i++) { // TODO: annotate also other matched classes if (!filters[i].startsWith("*") && !filters[i].endsWith("*")) { String[] newUrls = getClassURLs(SourcePath.convertClassNameToRelativePath(filters[i])); int[] newlns = new int[newUrls.length]; for (int j = 0; j < newUrls.length; j++) { newlns[j] = getContext().getMethodLineNumber(newUrls[j], filters[i], ((MethodBreakpoint) b).getMethodName(), ((MethodBreakpoint) b).getMethodSignature()); } if (urls.length == 0) { urls = newUrls; lns = newlns; } else { String[] l = new String[urls.length + newUrls.length]; System.arraycopy(urls, 0, l, 0, urls.length); System.arraycopy(newUrls, 0, l, urls.length, newUrls.length); urls = l; int[] ln = new int[urls.length + newUrls.length]; System.arraycopy(lns, 0, ln, 0, lns.length); System.arraycopy(newlns, 0, ln, lns.length, newlns.length); lns = ln; } } } URLs = urls; lineNumbers = lns; condition = ((MethodBreakpoint) b).getCondition(); } else { return null; } boolean isConditional = (condition != null) && !"".equals (condition.trim ()); // NOI18N boolean isInvalid = b.getValidity() == VALIDITY.INVALID; String annotationType; if (b instanceof LineBreakpoint) { annotationType = b.isEnabled () ? (isConditional ? EditorContext.CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE : EditorContext.BREAKPOINT_ANNOTATION_TYPE) : (isConditional ? EditorContext.DISABLED_CONDITIONAL_BREAKPOINT_ANNOTATION_TYPE : EditorContext.DISABLED_BREAKPOINT_ANNOTATION_TYPE); } else if (b instanceof FieldBreakpoint) { annotationType = b.isEnabled () ? EditorContext.FIELD_BREAKPOINT_ANNOTATION_TYPE : EditorContext.DISABLED_FIELD_BREAKPOINT_ANNOTATION_TYPE; } else if (b instanceof MethodBreakpoint) { annotationType = b.isEnabled () ? EditorContext.METHOD_BREAKPOINT_ANNOTATION_TYPE : EditorContext.DISABLED_METHOD_BREAKPOINT_ANNOTATION_TYPE; } else { return null; } if (isInvalid && b.isEnabled ()) annotationType += "_broken"; List annotations = new ArrayList(URLs.length); for (int i = 0; i < URLs.length; i++) { if (lineNumbers[i] >= 1) { Object annotation = getContext().annotate (URLs[i], lineNumbers[i], annotationType, null); if (annotation != null) { annotations.add(annotation); } } } if (annotations.size() == 0) { return null; } else { return annotations.toArray(); } } private static String[] getClassURLs(String className) { SourcePathProvider spp = SourcePath.getDefaultContext(); // TODO: spp.getAllURLs(className, true); try { return (String[]) spp.getClass().getMethod("getAllURLs", new Class[] { String.class, Boolean.TYPE }). invoke(spp, new Object[] { className, Boolean.TRUE }); } catch (Exception ex) { ErrorManager.getDefault().notify(ex); return new String[0]; } } 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 ('.', '/') + ".scala"; return sourceName; } private static String convertSlash (String original) { return original.replace (File.separatorChar, '/'); } // 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 String getCurrentMethodName () { String s = cp1.getCurrentMethodName (); if ( (s == null) || (s.trim ().length () < 1)) return cp2.getCurrentMethodName (); return s; } public String getCurrentMethodSignature() { String s = null; try { s = (String) cp1.getClass().getMethod("getCurrentMethodSignature", new Class[] {}). // NOI18N invoke(getContext(), new Object[] {}); } 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) { // Ignore, we have another attempt with cp2 //ErrorManager.getDefault().notify(ex); } if ( (s == null) || (s.trim ().length () < 1)) { try { s = (String) cp2.getClass().getMethod("getCurrentMethodSignature", new Class[] {}). // NOI18N invoke(getContext(), new Object[] {}); } 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; } } 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 value) { if (value instanceof List) { for (Iterator iter = ((List) value).iterator(); iter.hasNext();) { CompoundAnnotation ca = (CompoundAnnotation) iter.next(); if (ca.annotation1 != null) { cp1.removeAnnotation (ca.annotation1); } if (ca.annotation2 != null) { cp2.removeAnnotation (ca.annotation2); } } return; } CompoundAnnotation ca = (CompoundAnnotation) value; if (ca.annotation1 != null) { cp1.removeAnnotation (ca.annotation1); } if (ca.annotation2 != null) { 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); if (ca.annotation1 != null || ca.annotation2 != null) { return ca; } else { return null; } } @Override public Object annotate(String url, int lineNumber, String annotationType, Object timeStamp, JPDAThread thread) { CompoundAnnotation ca = new CompoundAnnotation (); ca.annotation1 = cp1.annotate (url, lineNumber, annotationType, timeStamp, thread); ca.annotation2 = cp2.annotate (url, lineNumber, annotationType, timeStamp, thread); if (ca.annotation1 != null || ca.annotation2 != null) { return ca; } else { return null; } } @Override public Object annotate(String url, int startPosition, int endPosition, String annotationType, Object timeStamp) { CompoundAnnotation ca = new CompoundAnnotation (); ca.annotation1 = cp1.annotate (url, startPosition, endPosition, annotationType, timeStamp); ca.annotation2 = cp2.annotate (url, startPosition, endPosition, annotationType, timeStamp); if (ca.annotation1 != null || ca.annotation2 != null) { return ca; } else { return null; } } public int getLineNumber (Object annotation, Object timeStamp) { CompoundAnnotation ca = new CompoundAnnotation (); int ln; if (ca.annotation1 != null) { ln = cp1.getLineNumber (ca.annotation1, timeStamp); } else { ln = -1; } if (ln >= 0) return ln; if (ca.annotation2 != null) { return cp2.getLineNumber (ca.annotation2, timeStamp); } else { return -1; } } 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) 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); } } private static class CompoundAnnotation { Object annotation1; Object annotation2; } }