001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Micro//S ystems, Inc. Portions Copyright 1997-2007 Sun
028: * Micro//S ystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.debugger.jpda;
042:
043: import com.sun.jdi.AbsentInformationException;
044: import com.sun.source.tree.Tree;
045: import com.sun.source.tree.TreeVisitor;
046: import com.sun.source.util.TreePathScanner;
047: import java.beans.PropertyChangeListener;
048: import java.io.File;
049: import java.net.MalformedURLException;
050: import java.net.URL;
051: import java.util.List;
052:
053: import org.netbeans.api.debugger.DebuggerManager;
054: import org.netbeans.api.debugger.jpda.LineBreakpoint;
055: import org.netbeans.api.debugger.jpda.CallStackFrame;
056: import org.netbeans.api.debugger.jpda.JPDAThread;
057: import org.netbeans.spi.debugger.jpda.EditorContext;
058: import org.netbeans.spi.debugger.jpda.EditorContext.MethodArgument;
059: import org.netbeans.spi.debugger.jpda.EditorContext.Operation;
060: import org.netbeans.spi.debugger.jpda.SourcePathProvider;
061: import org.openide.ErrorManager;
062:
063: /**
064: *
065: * @author Jan Jancura
066: */
067: public class EditorContextBridge {
068:
069: public static final String FIELD = "field";
070: public static final String METHOD = "method";
071: public static final String CLASS = "class";
072: public static final String LINE = "line";
073:
074: private static EditorContext context;
075:
076: public static EditorContext getContext() {
077: if (context == null) {
078: List l = DebuggerManager.getDebuggerManager().lookup(null,
079: EditorContext.class);
080: context = (EditorContext) l.get(0);
081: int i, k = l.size();
082: for (i = 1; i < k; i++)
083: context = new CompoundContextProvider((EditorContext) l
084: .get(i), context);
085: }
086: return context;
087: }
088:
089: /**
090: * Returns the parsed expression tree or <code>null</code>.
091: *
092: * @return the parsed expression tree or <code>null</code>
093: *
094: public static Tree getExpressionTree(final String expression, String url, final int line) {
095: // TODO: return getContext ().getExpressionTree ();
096: try {
097: return (Tree) getContext ().getClass().getMethod("getExpressionTree", new Class[] { String.class, String.class, Integer.TYPE }).
098: invoke(getContext(), new Object[] { expression, url, line });
099: } catch (java.lang.reflect.InvocationTargetException itex) {
100: Throwable tex = itex.getTargetException();
101: if (tex instanceof RuntimeException) {
102: throw (RuntimeException) tex;
103: } else {
104: ErrorManager.getDefault().notify(tex);
105: return null;
106: }
107: } catch (Exception ex) {
108: ErrorManager.getDefault().notify(ex);
109: return null;
110: }
111: }
112: */
113:
114: /**
115: * Parse the expression into AST tree and traverse is via the provided visitor.
116: *
117: * @return the visitor value or <code>null</code>.
118: */
119: public static <R, D> R parseExpression(String expression,
120: String url, final int line, TreePathScanner<R, D> visitor,
121: D context, SourcePathProvider sp) {
122:
123: // TODO: return getContext ().parseExpression ();
124: try {
125: return (R) getContext().getClass().getMethod(
126: "parseExpression",
127: new Class[] { String.class, String.class,
128: Integer.TYPE, TreePathScanner.class,
129: Object.class, SourcePathProvider.class })
130: .invoke(
131: getContext(),
132: new Object[] { expression, url, line,
133: visitor, context, sp });
134: } catch (java.lang.reflect.InvocationTargetException itex) {
135: Throwable tex = itex.getTargetException();
136: if (tex instanceof RuntimeException) {
137: throw (RuntimeException) tex;
138: } else {
139: ErrorManager.getDefault().notify(tex);
140: return null;
141: }
142: } catch (Exception ex) {
143: ErrorManager.getDefault().notify(ex);
144: return null;
145: }
146: }
147:
148: // Utility methods .........................................................
149:
150: public static String getFileName(LineBreakpoint b) {
151: try {
152: return new File(new URL(b.getURL()).getFile()).getName();
153: } catch (MalformedURLException e) {
154: return null;
155: }
156: }
157:
158: public static boolean showSource(LineBreakpoint b, Object timeStamp) {
159: if (b.getLineNumber() < 1)
160: return getContext().showSource(b.getURL(), 1, timeStamp);
161: return getContext().showSource(b.getURL(), b.getLineNumber(),
162: timeStamp);
163: }
164:
165: public static String getRelativePath(JPDAThread thread,
166: String stratumn) {
167: try {
168: return convertSlash(thread.getSourcePath(stratumn));
169: } catch (AbsentInformationException e) {
170: return getRelativePath(thread.getClassName());
171: }
172: }
173:
174: public static String getRelativePath(CallStackFrame csf,
175: String stratumn) {
176: try {
177: return convertSlash(csf.getSourcePath(stratumn));
178: } catch (AbsentInformationException e) {
179: return getRelativePath(csf.getClassName());
180: }
181: }
182:
183: public static String getRelativePath(String className) {
184: int i = className.indexOf('$');
185: if (i > 0)
186: className = className.substring(0, i);
187: String sourceName = className.replace('.', '/') + ".java";
188: return sourceName;
189: }
190:
191: private static String convertSlash(String original) {
192: return original.replace(File.separatorChar, '/');
193: }
194:
195: public static int getCurrentOffset() {
196: // TODO: return getContext ().getCurrentOffset();
197: try {
198: return (Integer) getContext().getClass().getMethod(
199: "getCurrentOffset", new Class[] {}).invoke(
200: getContext(), new Object[] {});
201: } catch (java.lang.reflect.InvocationTargetException itex) {
202: Throwable tex = itex.getTargetException();
203: if (tex instanceof RuntimeException) {
204: throw (RuntimeException) tex;
205: } else {
206: ErrorManager.getDefault().notify(tex);
207: return 0;
208: }
209: } catch (Exception ex) {
210: ErrorManager.getDefault().notify(ex);
211: return 0;
212: }
213: }
214:
215: // innerclasses ............................................................
216:
217: private static class CompoundContextProvider extends EditorContext {
218:
219: private EditorContext cp1, cp2;
220:
221: CompoundContextProvider(EditorContext cp1, EditorContext cp2) {
222: this .cp1 = cp1;
223: this .cp2 = cp2;
224: }
225:
226: public void createTimeStamp(Object timeStamp) {
227: cp1.createTimeStamp(timeStamp);
228: cp2.createTimeStamp(timeStamp);
229: }
230:
231: public void disposeTimeStamp(Object timeStamp) {
232: cp1.disposeTimeStamp(timeStamp);
233: cp2.disposeTimeStamp(timeStamp);
234: }
235:
236: public void updateTimeStamp(Object timeStamp, String url) {
237: cp1.updateTimeStamp(timeStamp, url);
238: cp2.updateTimeStamp(timeStamp, url);
239: }
240:
241: public String getCurrentClassName() {
242: String s = cp1.getCurrentClassName();
243: if (s.trim().length() < 1)
244: return cp2.getCurrentClassName();
245: return s;
246: }
247:
248: public String getCurrentURL() {
249: String s = cp1.getCurrentURL();
250: if (s.trim().length() < 1)
251: return cp2.getCurrentURL();
252: return s;
253: }
254:
255: public String getCurrentFieldName() {
256: String s = cp1.getCurrentFieldName();
257: if ((s == null) || (s.trim().length() < 1))
258: return cp2.getCurrentFieldName();
259: return s;
260: }
261:
262: public int getCurrentLineNumber() {
263: int i = cp1.getCurrentLineNumber();
264: if (i < 1)
265: return cp2.getCurrentLineNumber();
266: return i;
267: }
268:
269: public int getCurrentOffset() {
270: Integer i = null;
271: try {
272: i = (Integer) cp1.getClass().getMethod(
273: "getCurrentOffset", new Class[] {}).invoke(
274: getContext(), new Object[] {});
275: } catch (java.lang.reflect.InvocationTargetException itex) {
276: Throwable tex = itex.getTargetException();
277: if (tex instanceof RuntimeException) {
278: throw (RuntimeException) tex;
279: } else {
280: ErrorManager.getDefault().notify(tex);
281: return 0;
282: }
283: } catch (Exception ex) {
284: // Ignore, we have another attempt with cp2
285: //ErrorManager.getDefault().notify(ex);
286: }
287: if (i == null || i.intValue() < 1) {
288: try {
289: i = (Integer) cp2.getClass().getMethod(
290: "getCurrentOffset", new Class[] {}).invoke(
291: getContext(), new Object[] {});
292: } catch (java.lang.reflect.InvocationTargetException itex) {
293: Throwable tex = itex.getTargetException();
294: if (tex instanceof RuntimeException) {
295: throw (RuntimeException) tex;
296: } else {
297: ErrorManager.getDefault().notify(tex);
298: return 0;
299: }
300: } catch (Exception ex) {
301: ErrorManager.getDefault().notify(ex);
302: return 0;
303: }
304: }
305: return i.intValue();
306: }
307:
308: public String getCurrentMethodName() {
309: String s = cp1.getCurrentMethodName();
310: if ((s == null) || (s.trim().length() < 1))
311: return cp2.getCurrentMethodName();
312: return s;
313: }
314:
315: public String getSelectedIdentifier() {
316: String s = cp1.getSelectedIdentifier();
317: if ((s == null) || (s.trim().length() < 1))
318: return cp2.getSelectedIdentifier();
319: return s;
320: }
321:
322: public String getSelectedMethodName() {
323: String s = cp1.getSelectedMethodName();
324: if ((s == null) || (s.trim().length() < 1))
325: return cp2.getSelectedMethodName();
326: return s;
327: }
328:
329: public void removeAnnotation(Object annotation) {
330: CompoundAnnotation ca = (CompoundAnnotation) annotation;
331: cp1.removeAnnotation(ca.annotation1);
332: cp2.removeAnnotation(ca.annotation2);
333: }
334:
335: public Object annotate(String sourceName, int lineNumber,
336: String annotationType, Object timeStamp) {
337: CompoundAnnotation ca = new CompoundAnnotation();
338: ca.annotation1 = cp1.annotate(sourceName, lineNumber,
339: annotationType, timeStamp);
340: ca.annotation2 = cp2.annotate(sourceName, lineNumber,
341: annotationType, timeStamp);
342: return ca;
343: }
344:
345: public <R, D> R parseExpression(String expression, String url,
346: final int line, TreePathScanner<R, D> visitor,
347: D context, SourcePathProvider sp) {
348: R ret = null;
349: try {
350: ret = (R) cp1.getClass()
351: .getMethod(
352: "parseExpression",
353: new Class[] { String.class,
354: String.class, Integer.TYPE,
355: TreePathScanner.class,
356: Object.class,
357: SourcePathProvider.class })
358: .invoke(
359: cp1,
360: new Object[] { expression, url, line,
361: visitor, context, sp });
362: } catch (java.lang.reflect.InvocationTargetException itex) {
363: Throwable tex = itex.getTargetException();
364: if (tex instanceof RuntimeException) {
365: throw (RuntimeException) tex;
366: } else {
367: ErrorManager.getDefault().notify(tex);
368: }
369: } catch (Exception ex) {
370: // Ignore, we have another attempt with cp2
371: }
372: if (ret == null) {
373: try {
374: ret = (R) cp2.getClass().getMethod(
375: "parseExpression",
376: new Class[] { String.class, String.class,
377: Integer.TYPE,
378: TreePathScanner.class,
379: Object.class,
380: SourcePathProvider.class }).invoke(
381: cp2,
382: new Object[] { expression, url, line,
383: visitor, context, sp });
384: } catch (java.lang.reflect.InvocationTargetException itex) {
385: Throwable tex = itex.getTargetException();
386: if (tex instanceof RuntimeException) {
387: throw (RuntimeException) tex;
388: } else {
389: ErrorManager.getDefault().notify(tex);
390: }
391: } catch (Exception ex) {
392: ErrorManager.getDefault().notify(ex);
393: }
394: }
395: return ret;
396: }
397:
398: public int getLineNumber(Object annotation, Object timeStamp) {
399: int ln = cp1.getLineNumber(annotation, timeStamp);
400: if (ln >= 0)
401: return ln;
402: return cp2.getLineNumber(annotation, timeStamp);
403: }
404:
405: public boolean showSource(String sourceName, int lineNumber,
406: Object timeStamp) {
407: return cp1.showSource(sourceName, lineNumber, timeStamp)
408: | cp2.showSource(sourceName, lineNumber, timeStamp);
409: }
410:
411: public int getFieldLineNumber(String url, String className,
412: String fieldName) {
413: int ln = cp1.getFieldLineNumber(url, className, fieldName);
414: if (ln != -1)
415: return ln;
416: return cp2.getFieldLineNumber(url, className, fieldName);
417: }
418:
419: public String getClassName(String url, int lineNumber) {
420: String className = cp1.getClassName(url, lineNumber);
421: if (className != null && className.length() > 0)
422: return className;
423: return cp2.getClassName(url, lineNumber);
424: }
425:
426: public String[] getImports(String url) {
427: String[] r1 = cp1.getImports(url);
428: String[] r2 = cp2.getImports(url);
429: String[] r = new String[r1.length + r2.length];
430: System.arraycopy(r1, 0, r, 0, r1.length);
431: System.arraycopy(r2, 0, r, r1.length, r2.length);
432: return r;
433: }
434:
435: public void addPropertyChangeListener(PropertyChangeListener l) {
436: cp1.addPropertyChangeListener(l);
437: cp2.addPropertyChangeListener(l);
438: }
439:
440: public void removePropertyChangeListener(
441: PropertyChangeListener l) {
442: cp1.removePropertyChangeListener(l);
443: cp2.removePropertyChangeListener(l);
444: }
445:
446: public void addPropertyChangeListener(String propertyName,
447: PropertyChangeListener l) {
448: cp1.addPropertyChangeListener(propertyName, l);
449: cp2.addPropertyChangeListener(propertyName, l);
450: }
451:
452: public void removePropertyChangeListener(String propertyName,
453: PropertyChangeListener l) {
454: cp1.removePropertyChangeListener(propertyName, l);
455: cp2.removePropertyChangeListener(propertyName, l);
456: }
457:
458: @Override
459: public Operation[] getOperations(String url, int lineNumber,
460: BytecodeProvider bytecodeProvider) {
461: Operation[] operations = cp1.getOperations(url, lineNumber,
462: bytecodeProvider);
463: if (operations != null) {
464: return operations;
465: } else {
466: return cp2.getOperations(url, lineNumber,
467: bytecodeProvider);
468: }
469: }
470:
471: }
472:
473: private static class CompoundAnnotation {
474: public CompoundAnnotation() {
475: }
476:
477: Object annotation1;
478: Object annotation2;
479: }
480: }
|