KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > debug > ui > JavaDetailFormattersManager


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.internal.debug.ui;
12
13 import java.util.Collection JavaDoc;
14 import java.util.HashMap JavaDoc;
15 import java.util.Iterator JavaDoc;
16
17 import org.eclipse.core.resources.IResource;
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.core.runtime.IAdaptable;
20 import org.eclipse.core.runtime.IProgressMonitor;
21 import org.eclipse.debug.core.DebugEvent;
22 import org.eclipse.debug.core.DebugException;
23 import org.eclipse.debug.core.DebugPlugin;
24 import org.eclipse.debug.core.IDebugEventSetListener;
25 import org.eclipse.debug.core.ILaunch;
26 import org.eclipse.debug.core.ILaunchesListener;
27 import org.eclipse.debug.core.model.IDebugTarget;
28 import org.eclipse.debug.core.model.IStackFrame;
29 import org.eclipse.debug.core.model.IVariable;
30 import org.eclipse.debug.ui.DebugUITools;
31 import org.eclipse.debug.ui.IDebugUIConstants;
32 import org.eclipse.debug.ui.IValueDetailListener;
33 import org.eclipse.jdt.core.IJavaElement;
34 import org.eclipse.jdt.core.IJavaProject;
35 import org.eclipse.jdt.core.IType;
36 import org.eclipse.jdt.core.JavaCore;
37 import org.eclipse.jdt.core.Signature;
38 import org.eclipse.jdt.debug.core.IEvaluationRunnable;
39 import org.eclipse.jdt.debug.core.IJavaArray;
40 import org.eclipse.jdt.debug.core.IJavaArrayType;
41 import org.eclipse.jdt.debug.core.IJavaClassType;
42 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
43 import org.eclipse.jdt.debug.core.IJavaInterfaceType;
44 import org.eclipse.jdt.debug.core.IJavaObject;
45 import org.eclipse.jdt.debug.core.IJavaPrimitiveValue;
46 import org.eclipse.jdt.debug.core.IJavaReferenceType;
47 import org.eclipse.jdt.debug.core.IJavaStackFrame;
48 import org.eclipse.jdt.debug.core.IJavaThread;
49 import org.eclipse.jdt.debug.core.IJavaType;
50 import org.eclipse.jdt.debug.core.IJavaValue;
51 import org.eclipse.jdt.debug.eval.IAstEvaluationEngine;
52 import org.eclipse.jdt.debug.eval.ICompiledExpression;
53 import org.eclipse.jdt.debug.eval.IEvaluationListener;
54 import org.eclipse.jdt.debug.eval.IEvaluationResult;
55 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
56 import org.eclipse.jdt.internal.debug.core.JavaDebugUtils;
57 import org.eclipse.jdt.internal.debug.core.logicalstructures.JDIAllInstancesValue;
58 import org.eclipse.jdt.internal.debug.core.model.JDINullValue;
59 import org.eclipse.jdt.internal.debug.core.model.JDIReferenceListValue;
60 import org.eclipse.jface.util.IPropertyChangeListener;
61 import org.eclipse.jface.util.PropertyChangeEvent;
62
63 import com.ibm.icu.text.MessageFormat;
64 import com.sun.jdi.InvocationException;
65
66 /**
67  * Generates strings for the detail pane of views displaying java elements.
68  */

69 public class JavaDetailFormattersManager implements IPropertyChangeListener, IDebugEventSetListener, ILaunchesListener {
70     /**
71      * The default detail formatters manager.
72      */

73     static private JavaDetailFormattersManager fgDefault;
74     
75     /**
76      * Return the default detail formatters manager.
77      *
78      * @return default detail formatters manager.
79      */

80     static public JavaDetailFormattersManager getDefault() {
81         if (fgDefault == null) {
82             fgDefault= new JavaDetailFormattersManager();
83         }
84         return fgDefault;
85     }
86     
87     /**
88      * Map of types to the associated formatter (code snippet).
89      * (<code>String</code> -> <code>String</code>)
90      */

91     private HashMap JavaDoc fDetailFormattersMap;
92     
93     /**
94      * Cache of compiled expressions.
95      * Associate a pair type name/debug target to a compiled expression.
96      */

97     private HashMap JavaDoc fCacheMap;
98     
99     /**
100      * JavaDetailFormattersManager constructor.
101      */

102     private JavaDetailFormattersManager() {
103         populateDetailFormattersMap();
104         JDIDebugUIPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
105         DebugPlugin.getDefault().getLaunchManager().addLaunchListener(this);
106         DebugPlugin.getDefault().addDebugEventListener(this);
107         DebugUITools.getPreferenceStore().addPropertyChangeListener(this);
108         fCacheMap= new HashMap JavaDoc();
109     }
110     
111     /**
112      * Populate the detail formatters map with data from preferences.
113      */

114     private void populateDetailFormattersMap() {
115         String JavaDoc[] detailFormattersList= JavaDebugOptionsManager.parseList(JDIDebugUIPlugin.getDefault().getPreferenceStore().getString(IJDIPreferencesConstants.PREF_DETAIL_FORMATTERS_LIST));
116         fDetailFormattersMap= new HashMap JavaDoc(detailFormattersList.length / 3);
117         for (int i= 0, length= detailFormattersList.length; i < length;) {
118             String JavaDoc typeName= detailFormattersList[i++];
119             String JavaDoc snippet= detailFormattersList[i++].replace('\u0000', ',');
120             boolean enabled= ! JavaDetailFormattersPreferencePage.DETAIL_FORMATTER_IS_DISABLED.equals(detailFormattersList[i++]);
121             fDetailFormattersMap.put(typeName, new DetailFormatter(typeName, snippet, enabled));
122         }
123     }
124     
125     /**
126      * Compute asynchronously the 'toString' of the given value. If a formatter is associated to
127      * the type of the given value, this formatter is used instead of the <code>toString()</code>
128      * method.
129      * The result is return through the listener.
130      *
131      * @param objectValue the value to 'format'
132      * @param thread the thread to use to performed the evaluation
133      * @param listener the listener
134      */

135     public void computeValueDetail(final IJavaValue objectValue, final IJavaThread thread, final IValueDetailListener listener) {
136         Runnable JavaDoc postEventDispatch = new Runnable JavaDoc() {
137             public void run() {
138                 if (!thread.isSuspended() && !thread.isPerformingEvaluation()) {
139                     listener.detailComputed(objectValue, DebugUIMessages.JavaDetailFormattersManager_9);
140                 } else {
141                     thread.queueRunnable(new Runnable JavaDoc() {
142                         public void run() {
143                             resolveFormatter(objectValue, thread, listener);
144                         }
145                     });
146                 }
147             }
148         };
149         DebugPlugin.getDefault().asyncExec(postEventDispatch);
150     }
151     
152     private void resolveFormatter(final IJavaValue value, final IJavaThread thread, final IValueDetailListener listener) {
153         EvaluationListener evaluationListener= new EvaluationListener(value, thread, listener);
154         if (value instanceof IJavaObject) {
155             IJavaObject objectValue= (IJavaObject) value;
156             try {
157                 if(value instanceof JDIAllInstancesValue) {
158                     listener.detailComputed(value, ((JDIAllInstancesValue)value).getDetailString());
159                     return;
160                 }
161                 if(value instanceof JDIReferenceListValue) {
162                     listener.detailComputed(value, ((JDIReferenceListValue)value).getDetailString());
163                     return;
164                 }
165                 IJavaDebugTarget debugTarget= (IJavaDebugTarget) thread.getDebugTarget();
166                 // get the compiled expression to use
167
Expression expression= getCompiledExpression(objectValue, debugTarget, thread);
168                 if (expression != null) {
169                     expression.getEngine().evaluateExpression(expression.getExpression(), objectValue, thread,
170                             evaluationListener, DebugEvent.EVALUATION_IMPLICIT, false);
171                     return;
172                 }
173             } catch (CoreException e) {
174                 listener.detailComputed(value, e.toString());
175                 return;
176             }
177         }
178         try {
179             evaluationListener.valueToString(value);
180         } catch (DebugException e) {
181             listener.detailComputed(value, e.getStatus().getMessage());
182         }
183     }
184     
185     private IJavaProject getJavaProject(IJavaObject javaValue, IJavaThread thread) throws CoreException {
186
187         IType type = null;
188         if (javaValue instanceof IJavaArray) {
189             IJavaArrayType arrType = (IJavaArrayType) javaValue.getJavaType();
190             IJavaType compType = arrType.getComponentType();
191             while (compType instanceof IJavaArrayType) {
192                 compType = ((IJavaArrayType)compType).getComponentType();
193             }
194             type = JavaDebugUtils.resolveType(compType);
195         } else {
196             type = JavaDebugUtils.resolveType(javaValue);
197         }
198         if (type != null) {
199             return type.getJavaProject();
200         }
201         IStackFrame stackFrame= null;
202         IJavaDebugTarget target = (IJavaDebugTarget)javaValue.getDebugTarget().getAdapter(IJavaDebugTarget.class);
203         if (target != null) {
204             stackFrame= thread.getTopStackFrame();
205             if (stackFrame != null && !stackFrame.getDebugTarget().equals(target)) {
206                 stackFrame= null;
207             }
208         }
209         if (stackFrame == null) {
210             return null;
211         }
212         Object JavaDoc sourceElement = JavaDebugUtils.resolveSourceElement(stackFrame, stackFrame.getLaunch());
213         if (!(sourceElement instanceof IJavaElement) && sourceElement instanceof IAdaptable) {
214             sourceElement = ((IAdaptable)sourceElement).getAdapter(IJavaElement.class);
215         }
216         IJavaProject project= null;
217         if (sourceElement instanceof IJavaElement) {
218             project= ((IJavaElement) sourceElement).getJavaProject();
219         } else if (sourceElement instanceof IResource) {
220             IJavaProject resourceProject = JavaCore.create(((IResource)sourceElement).getProject());
221             if (resourceProject.exists()) {
222                 project= resourceProject;
223             }
224         }
225         return project;
226     }
227     
228     /**
229      * Searches the listing of implemented interfaces to see if one of them has a detail formatter
230      * @param type the type whose interfaces you want to inspect
231      * @return an associated details formatter of <code>null</code> if none is found
232      * @since 3.2
233      */

234     public DetailFormatter getDetailFormatterFromInterface(IJavaClassType type) {
235         try {
236             IJavaInterfaceType[] inter = type.getAllInterfaces();
237             Object JavaDoc formatter = null;
238             for (int i = 0; i < inter.length; i++) {
239                 formatter = fDetailFormattersMap.get(inter[i].getName());
240                 if(formatter != null) {
241                     return (DetailFormatter) formatter;
242                 }
243             }
244             return null;
245             }
246         catch(DebugException e) {return null;}
247     }
248     
249     /**
250      * Returns if the specified <code>IJavaType</code> has a detail formatter on one of its interfaces
251      * @param type the type to inspect
252      * @return true if there is an existing detail formatter on one of the types' interfaces, false otherwise
253      * @since 3.2
254      */

255     public boolean hasInterfaceDetailFormatter(IJavaType type) {
256         if(type instanceof IJavaClassType) {
257             return getDetailFormatterFromInterface((IJavaClassType) type) != null;
258         }
259         return false;
260     }
261     
262     /**
263      * Searches the superclass hierarchy to see if any of the specified classes parents have a detail formatter
264      * @param type the current type. Ideally this should be the first parent class.
265      * @return the first detail formatter located walking up the superclass hierarchy or <code>null</code> if none are found
266      * @since 3.2
267      */

268     public DetailFormatter getDetailFormatterFromSuperclass(IJavaClassType type) {
269         try {
270             if(type == null) {
271                 return null;
272             }
273             DetailFormatter formatter = (DetailFormatter) fDetailFormattersMap.get(type.getName());
274             if(formatter != null && formatter.isEnabled()) {
275                 return formatter;
276             }
277             return getDetailFormatterFromSuperclass(type.getSuperclass());
278             }
279         catch(DebugException e) {return null;}
280     }
281     
282     /**
283      * Returns if one of the parent classes of the specified type has a detail formatter
284      * @param type the type to inspect
285      * @return true if one of the parent classes of the type has a detail formatter, false otherwise
286      * @since 3.2
287      */

288     public boolean hasSuperclassDetailFormatter(IJavaType type) {
289         if(type instanceof IJavaClassType) {
290             return getDetailFormatterFromSuperclass((IJavaClassType) type) != null;
291         }
292         return false;
293     }
294     
295     public boolean hasAssociatedDetailFormatter(IJavaType type) {
296         return getAssociatedDetailFormatter(type) != null;
297     }
298     
299     public DetailFormatter getAssociatedDetailFormatter(IJavaType type) {
300         String JavaDoc typeName = ""; //$NON-NLS-1$
301
try {
302             while (type instanceof IJavaArrayType) {
303                 type = ((IJavaArrayType)type).getComponentType();
304             }
305             if (type instanceof IJavaClassType) {
306                 typeName = type.getName();
307             }
308             else {
309                 return null;
310             }
311         }
312         catch (DebugException e) {return null;}
313         return (DetailFormatter)fDetailFormattersMap.get(typeName);
314     }
315     
316     public void setAssociatedDetailFormatter(DetailFormatter detailFormatter) {
317         fDetailFormattersMap.put(detailFormatter.getTypeName(), detailFormatter);
318         savePreference();
319     }
320     
321     
322     private void savePreference() {
323         Collection JavaDoc valuesList= fDetailFormattersMap.values();
324         String JavaDoc[] values= new String JavaDoc[valuesList.size() * 3];
325         int i= 0;
326         for (Iterator JavaDoc iter= valuesList.iterator(); iter.hasNext();) {
327             DetailFormatter detailFormatter= (DetailFormatter) iter.next();
328             values[i++]= detailFormatter.getTypeName();
329             values[i++]= detailFormatter.getSnippet().replace(',','\u0000');
330             values[i++]= detailFormatter.isEnabled() ? JavaDetailFormattersPreferencePage.DETAIL_FORMATTER_IS_ENABLED : JavaDetailFormattersPreferencePage.DETAIL_FORMATTER_IS_DISABLED;
331         }
332         String JavaDoc pref = JavaDebugOptionsManager.serializeList(values);
333         JDIDebugUIPlugin.getDefault().getPreferenceStore().setValue(IJDIPreferencesConstants.PREF_DETAIL_FORMATTERS_LIST, pref);
334     }
335     
336     /**
337      * Return the detail formatter (code snippet) associate with
338      * the given type or one of its super types, super interfaces.
339      */

340     private String JavaDoc getDetailFormatter(IJavaClassType type) throws DebugException {
341         String JavaDoc snippet= getDetailFormatterSuperClass(type);
342         if (snippet != null) {
343             return snippet;
344         }
345         IJavaInterfaceType[] allInterfaces= type.getAllInterfaces();
346         for (int i= 0; i < allInterfaces.length; i++) {
347             DetailFormatter detailFormatter= (DetailFormatter)fDetailFormattersMap.get(allInterfaces[i].getName());
348             if (detailFormatter != null && detailFormatter.isEnabled()) {
349                 return detailFormatter.getSnippet();
350             }
351         }
352         return null;
353     }
354     
355     /**
356      * Return the detail formatter (code snippet) associate with
357      * the given type or one of its super types.
358      */

359     private String JavaDoc getDetailFormatterSuperClass(IJavaClassType type) throws DebugException {
360         if (type == null) {
361             return null;
362         }
363         DetailFormatter detailFormatter= (DetailFormatter)fDetailFormattersMap.get(type.getName());
364         if (detailFormatter != null && detailFormatter.isEnabled()) {
365             return detailFormatter.getSnippet();
366         }
367         return getDetailFormatterSuperClass(type.getSuperclass());
368     }
369     
370     /**
371      * Return the expression which corresponds to the code formatter associated with the type of
372      * the given object or <code>null</code> if none.
373      *
374      * The code snippet is compiled in the context of the given object.
375      */

376     private Expression getCompiledExpression(IJavaObject javaObject, IJavaDebugTarget debugTarget, IJavaThread thread) throws CoreException {
377         IJavaType type = javaObject.getJavaType();
378         if (type == null) {
379             return null;
380         }
381         String JavaDoc typeName = type.getName();
382         Key key = new Key(typeName, debugTarget);
383         if (fCacheMap.containsKey(key)) {
384             return (Expression) fCacheMap.get(key);
385         }
386         String JavaDoc snippet = null;
387         if (type instanceof IJavaClassType) {
388             snippet = getDetailFormatter((IJavaClassType) type);
389         } else if (type instanceof IJavaArrayType) {
390             snippet = getArraySnippet((IJavaArray) javaObject);
391         }
392         if (snippet != null) {
393             IJavaProject project = getJavaProject(javaObject, thread);
394             if (project != null) {
395                 IAstEvaluationEngine evaluationEngine = JDIDebugPlugin
396                         .getDefault().getEvaluationEngine(project, debugTarget);
397                 ICompiledExpression res = evaluationEngine
398                         .getCompiledExpression(snippet, javaObject);
399                 if (res != null) {
400                     Expression exp = new Expression(res, evaluationEngine);
401                     fCacheMap.put(key, exp);
402                     return exp;
403                 }
404             }
405         }
406         return null;
407     }
408     
409     protected String JavaDoc getArraySnippet(IJavaArray value) throws DebugException {
410         String JavaDoc signature = value.getSignature();
411         int nesting = Signature.getArrayCount(signature);
412         if (nesting > 1) {
413             // for nested primitive arrays, print everything
414
String JavaDoc sig = Signature.getElementType(signature);
415             if (sig.length() == 1 || "Ljava/lang/String;".equals(sig)) { //$NON-NLS-1$
416
// return null so we get to "valueToString(IJavaValue)" for primitive and string types
417
return null;
418             }
419         }
420         if (((IJavaArrayType)value.getJavaType()).getComponentType() instanceof IJavaReferenceType) {
421             int length = value.getLength();
422             // guestimate at max entries to print based on char/space/comma per entry
423
int maxLength = getMaxDetailLength();
424             if (maxLength > 0){
425                 int maxEntries = (maxLength / 3) + 1;
426                 if (length > maxEntries) {
427                     StringBuffer JavaDoc snippet = new StringBuffer JavaDoc();
428                     snippet.append("Object[] shorter = new Object["); //$NON-NLS-1$
429
snippet.append(maxEntries);
430                     snippet.append("]; System.arraycopy(this, 0, shorter, 0, "); //$NON-NLS-1$
431
snippet.append(maxEntries);
432                     snippet.append("); "); //$NON-NLS-1$
433
snippet.append("return java.util.Arrays.asList(shorter).toString();"); //$NON-NLS-1$
434
return snippet.toString();
435                 }
436             }
437             return "java.util.Arrays.asList(this).toString()"; //$NON-NLS-1$
438
}
439         return null;
440     }
441     
442     /**
443      * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(PropertyChangeEvent)
444      */

445     public void propertyChange(PropertyChangeEvent event) {
446         String JavaDoc property = event.getProperty();
447         if (property.equals(IJDIPreferencesConstants.PREF_DETAIL_FORMATTERS_LIST) ||
448                 property.equals(IJDIPreferencesConstants.PREF_SHOW_DETAILS) ||
449                 property.equals(IDebugUIConstants.PREF_MAX_DETAIL_LENGTH)) {
450             populateDetailFormattersMap();
451             fCacheMap.clear();
452             // If a Java stack frame is selected in the Debug view, fire a change event on
453
// it so the variables view will update for any formatter changes.
454
IAdaptable selected = DebugUITools.getDebugContext();
455             if (selected != null) {
456                 IJavaStackFrame frame= (IJavaStackFrame) selected.getAdapter(IJavaStackFrame.class);
457                 if (frame != null) {
458                     DebugPlugin.getDefault().fireDebugEventSet(new DebugEvent[] {
459                             new DebugEvent(frame, DebugEvent.CHANGE)
460                     });
461                 }
462             }
463         }
464     }
465     /**
466      * @see org.eclipse.debug.core.IDebugEventSetListener#handleDebugEvents(DebugEvent[])
467      */

468     public void handleDebugEvents(DebugEvent[] events) {
469         for (int i = 0; i < events.length; i++) {
470             DebugEvent event = events[i];
471             if (event.getSource() instanceof IJavaDebugTarget && event.getKind() == DebugEvent.TERMINATE) {
472                 deleteCacheForTarget((IJavaDebugTarget) event.getSource());
473             }
474         }
475     }
476     
477     /**
478      * @see org.eclipse.debug.core.ILaunchesListener#launchesAdded(ILaunch[])
479      */

480     public void launchesAdded(ILaunch[] launches) {
481     }
482     
483     /**
484      * @see org.eclipse.debug.core.ILaunchesListener#launchesChanged(ILaunch[])
485      */

486     public void launchesChanged(ILaunch[] launches) {
487     }
488     
489     /**
490      * @see org.eclipse.debug.core.ILaunchesListener#launchesRemoved(ILaunch[])
491      */

492     public void launchesRemoved(ILaunch[] launches) {
493         for (int i = 0; i < launches.length; i++) {
494             ILaunch launch = launches[i];
495             IDebugTarget[] debugTargets= launch.getDebugTargets();
496             for (int j = 0; j < debugTargets.length; j++) {
497                 if (debugTargets[j] instanceof IJavaDebugTarget) {
498                     deleteCacheForTarget((IJavaDebugTarget)debugTargets[j]);
499                 }
500             }
501         }
502     }
503     
504     /**
505      * Remove from the cache compiled expression associated with
506      * the given debug target.
507      *
508      * @param debugTarget
509      */

510     private synchronized void deleteCacheForTarget(IJavaDebugTarget debugTarget) {
511         for (Iterator JavaDoc iter= fCacheMap.keySet().iterator(); iter.hasNext();) {
512             Key key= (Key) iter.next();
513             if ((key).fDebugTarget == debugTarget) {
514                 iter.remove();
515             }
516         }
517     }
518     
519     /**
520      * Object used as the key in the cache map for associate a compiled
521      * expression with a pair type name/debug target
522      */

523     static private class Key {
524         private String JavaDoc fTypeName;
525         private IJavaDebugTarget fDebugTarget;
526         
527         Key(String JavaDoc typeName, IJavaDebugTarget debugTarget) {
528             fTypeName= typeName;
529             fDebugTarget= debugTarget;
530         }
531         
532         public boolean equals(Object JavaDoc obj) {
533             if (obj instanceof Key) {
534                 Key key= (Key) obj;
535                 return fTypeName != null && fDebugTarget != null && fTypeName.equals(key.fTypeName) && fDebugTarget.equals(key.fDebugTarget);
536             }
537             return false;
538         }
539         
540         public int hashCode() {
541             return fTypeName.hashCode() / 2 + fDebugTarget.hashCode() / 2;
542         }
543     }
544     
545     /**
546      * Stores a compiled expression and evaluation engine used to eval the expression.
547      */

548     static private class Expression {
549         private ICompiledExpression fExpression;
550         private IAstEvaluationEngine fEngine;
551         
552         Expression(ICompiledExpression expression, IAstEvaluationEngine engine) {
553             fExpression = expression;
554             fEngine = engine;
555         }
556         public ICompiledExpression getExpression() {
557             return fExpression;
558         }
559         public IAstEvaluationEngine getEngine() {
560             return fEngine;
561         }
562     }
563     
564     /**
565      * Listener use to manage the result of the formatter.
566      * Utilizes the 'standard' pretty printer methods to return the result.
567      */

568     static private class EvaluationListener implements IEvaluationListener {
569         
570         /**
571          * The selector of <code>java.lang.Object#toString()</code>,
572          * used to evaluate 'toString()' for displaying details of values.
573          */

574         private static final String JavaDoc fgToString= "toString"; //$NON-NLS-1$
575

576         
577         /**
578          * The signature of <code>java.lang.Object#toString()</code>,
579          * used to evaluate 'toString()' for displaying details of values.
580          */

581         private static final String JavaDoc fgToStringSignature= "()Ljava/lang/String;"; //$NON-NLS-1$
582

583         /**
584          * Signature of a string object
585          */

586         private static final String JavaDoc STRING_SIGNATURE = "Ljava/lang/String;"; //$NON-NLS-1$
587

588         private IJavaValue fValue;
589         
590         private IValueDetailListener fListener;
591         
592         private IJavaThread fThread;
593         
594         public EvaluationListener(IJavaValue value, IJavaThread thread, IValueDetailListener listener) {
595             fValue= value;
596             fThread= thread;
597             fListener= listener;
598         }
599         
600         public void evaluationComplete(IEvaluationResult result) {
601             if (result.hasErrors()) {
602                 StringBuffer JavaDoc error= new StringBuffer JavaDoc(DebugUIMessages.JavaDetailFormattersManager_Detail_formatter_error___1);
603                 DebugException exception= result.getException();
604                 if (exception != null) {
605                     Throwable JavaDoc throwable= exception.getStatus().getException();
606                     error.append("\n\t\t"); //$NON-NLS-1$
607
if (throwable instanceof InvocationException) {
608                         error.append(MessageFormat.format(DebugUIMessages.JavaDetailFormattersManager_An_exception_occurred___0__3, new String JavaDoc[] {((InvocationException) throwable).exception().referenceType().name()}));
609                     } else {
610                         error.append(exception.getStatus().getMessage());
611                     }
612                 } else {
613                     String JavaDoc[] errors= result.getErrorMessages();
614                     for (int i= 0, length= errors.length; i < length; i++) {
615                         error.append("\n\t\t").append(errors[i]); //$NON-NLS-1$
616
}
617                 }
618                 fListener.detailComputed(fValue, error.toString());
619             } else {
620                 try {
621                     valueToString(result.getValue());
622                 } catch (DebugException e) {
623                     fListener.detailComputed(fValue, e.getStatus().getMessage());
624                 }
625             }
626         }
627         
628         public void valueToString(final IJavaValue objectValue) throws DebugException {
629             String JavaDoc nonEvalResult = null;
630             StringBuffer JavaDoc result= null;
631             if (objectValue.getSignature() == null) {
632                 // no need to spawn eval for a null fValue
633
nonEvalResult = DebugUIMessages.JavaDetailFormattersManager_null;
634             } else if (objectValue instanceof IJavaPrimitiveValue) {
635                 // no need to spawn eval for a primitive value
636
result = new StringBuffer JavaDoc();
637                 appendJDIPrimitiveValueString(result, objectValue);
638             } else if (fThread == null || !fThread.isSuspended()) {
639                 // no thread available
640
result = new StringBuffer JavaDoc();
641                 result.append(DebugUIMessages.JavaDetailFormattersManager_no_suspended_threads);
642                 appendJDIValueString(result, objectValue);
643             } else if (objectValue instanceof IJavaObject && STRING_SIGNATURE.equals(objectValue.getSignature())) {
644                 // no need to spawn eval for a java.lang.String
645
result = new StringBuffer JavaDoc();
646                 appendJDIValueString(result, objectValue);
647             }
648             if (result != null) {
649                 nonEvalResult = result.toString();
650             }
651             if (nonEvalResult != null) {
652                 fListener.detailComputed(fValue, nonEvalResult);
653                 return;
654             }
655             
656             IEvaluationRunnable eval = new IEvaluationRunnable() {
657                 public void run(IJavaThread thread, IProgressMonitor monitor) throws DebugException {
658                     StringBuffer JavaDoc buf= new StringBuffer JavaDoc();
659                     if (objectValue instanceof IJavaArray) {
660                         appendArrayDetail(buf, (IJavaArray) objectValue);
661                     } else if (objectValue instanceof IJavaObject) {
662                         appendObjectDetail(buf, (IJavaObject) objectValue);
663                     } else {
664                         appendJDIValueString(buf, objectValue);
665                     }
666                     fListener.detailComputed(fValue, buf.toString());
667                 }
668             };
669             fThread.runEvaluation(eval, null, DebugEvent.EVALUATION_IMPLICIT, false);
670         }
671         
672         /*
673          * Gets all values in array and appends the toString() if it is an array of Objects or the value if primitive.
674          * NB - this method is only called if there is no compiled expression for an array to perform an
675          * Arrays.asList().toString() to minimize toString() calls on remote target (ie one call to
676          * List.toString() instead of one call per item in the array).
677          */

678         protected void appendArrayDetail(StringBuffer JavaDoc result, IJavaArray arrayValue) throws DebugException {
679             result.append('[');
680             boolean partial = false;
681             IJavaValue[] arrayValues = null;
682             int maxLength = getMaxDetailLength();
683             int maxEntries = (maxLength / 3) + 1; // guess at char/comma/space per entry
684
int length = -1;
685             try {
686                 length = arrayValue.getLength();
687                 if (maxLength > 0 && length > maxEntries) {
688                     partial = true;
689                     IVariable[] variables = arrayValue.getVariables(0, maxEntries);
690                     arrayValues = new IJavaValue[variables.length];
691                     for (int i = 0; i < variables.length; i++) {
692                         arrayValues[i] = (IJavaValue) variables[i].getValue();
693                     }
694                 } else {
695                     arrayValues= arrayValue.getValues();
696                 }
697             } catch (DebugException de) {
698                 JDIDebugUIPlugin.log(de);
699                 result.append(de.getStatus().getMessage());
700                 return;
701             }
702             
703             for (int i= 0; i < arrayValues.length; i++) {
704                 IJavaValue value= arrayValues[i];
705                 if (value instanceof IJavaArray) {
706                     appendArrayDetail(result, (IJavaArray) value);
707                 } else if (value instanceof IJavaObject) {
708                     appendObjectDetail(result, (IJavaObject) value);
709                 } else {
710                     appendJDIValueString(result, value);
711                 }
712                 if (i < arrayValues.length - 1) {
713                     result.append(',');
714                     result.append(' ');
715                 }
716                 if (partial && result.length() > maxLength) {
717                     break;
718                 }
719             }
720             if (!partial) {
721                 result.append(']');
722             }
723         }
724         
725         protected void appendJDIPrimitiveValueString(StringBuffer JavaDoc result, IJavaValue value) throws DebugException {
726             result.append(value.getValueString());
727         }
728         
729         
730         protected void appendJDIValueString(StringBuffer JavaDoc result, IJavaValue value) throws DebugException {
731             result.append(value.getValueString());
732         }
733         
734         
735         protected void appendObjectDetail(StringBuffer JavaDoc result, IJavaObject objectValue) throws DebugException {
736             if(objectValue instanceof JDINullValue) {
737                 appendJDIValueString(result, objectValue);
738                 return;
739             }
740             // optimize if the result is a string - no need to send toString to a string
741
if (STRING_SIGNATURE.equals(objectValue.getSignature())) {
742                 appendJDIValueString(result, objectValue);
743             } else {
744                 
745                 IJavaValue toStringValue= objectValue.sendMessage(EvaluationListener.fgToString, EvaluationListener.fgToStringSignature, null, fThread, false);
746                 if (toStringValue == null) {
747                     result.append(DebugUIMessages.JavaDetailFormattersManager__unknown_);
748                 } else {
749                     appendJDIValueString(result, toStringValue);
750                 }
751             }
752         }
753         
754         
755         
756     }
757     
758     /**
759      * (non java-doc)
760      * Remove the provided <code>detailFormatter</code> from the map
761      * @param detailFormatter
762      */

763     public void removeAssociatedDetailFormatter(DetailFormatter detailFormatter) {
764         fDetailFormattersMap.remove(detailFormatter.getTypeName());
765         savePreference();
766     }
767     
768     /**
769      * Returns the maximum number of chars to display in the details area or 0 if
770      * there is no maximum.
771      *
772      * @return maximum number of chars to display or 0 for no max
773      */

774     private static int getMaxDetailLength() {
775         return DebugUITools.getPreferenceStore().getInt(IDebugUIConstants.PREF_MAX_DETAIL_LENGTH);
776     }
777     
778 }
779
Popular Tags