001: /*******************************************************************************
002: * Copyright (c) 2004, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.debug.core.logicalstructures;
011:
012: import com.ibm.icu.text.MessageFormat;
013:
014: import org.eclipse.core.resources.IResource;
015: import org.eclipse.core.runtime.CoreException;
016: import org.eclipse.core.runtime.IAdaptable;
017: import org.eclipse.core.runtime.IConfigurationElement;
018: import org.eclipse.core.runtime.IStatus;
019: import org.eclipse.core.runtime.Status;
020: import org.eclipse.debug.core.DebugEvent;
021: import org.eclipse.debug.core.DebugException;
022: import org.eclipse.debug.core.DebugPlugin;
023: import org.eclipse.debug.core.ILogicalStructureType;
024: import org.eclipse.debug.core.IStatusHandler;
025: import org.eclipse.debug.core.model.IDebugTarget;
026: import org.eclipse.debug.core.model.ISourceLocator;
027: import org.eclipse.debug.core.model.IThread;
028: import org.eclipse.debug.core.model.IValue;
029: import org.eclipse.debug.core.sourcelookup.ISourceLookupDirector;
030: import org.eclipse.jdt.core.IJavaElement;
031: import org.eclipse.jdt.core.IJavaProject;
032: import org.eclipse.jdt.core.JavaCore;
033: import org.eclipse.jdt.debug.core.IJavaClassType;
034: import org.eclipse.jdt.debug.core.IJavaDebugTarget;
035: import org.eclipse.jdt.debug.core.IJavaInterfaceType;
036: import org.eclipse.jdt.debug.core.IJavaObject;
037: import org.eclipse.jdt.debug.core.IJavaReferenceType;
038: import org.eclipse.jdt.debug.core.IJavaStackFrame;
039: import org.eclipse.jdt.debug.core.IJavaThread;
040: import org.eclipse.jdt.debug.core.IJavaType;
041: import org.eclipse.jdt.debug.core.IJavaValue;
042: import org.eclipse.jdt.debug.core.IJavaVariable;
043: import org.eclipse.jdt.debug.eval.IAstEvaluationEngine;
044: import org.eclipse.jdt.debug.eval.ICompiledExpression;
045: import org.eclipse.jdt.debug.eval.IEvaluationListener;
046: import org.eclipse.jdt.debug.eval.IEvaluationResult;
047: import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
048:
049: public class JavaLogicalStructure implements ILogicalStructureType {
050:
051: private static IStatusHandler fgStackFrameProvider;
052:
053: /**
054: * Fully qualified type name.
055: */
056: private String fType;
057: /**
058: * Indicate if this java logical structure should be used on object
059: * instance of subtype of the specified type.
060: */
061: private boolean fSubtypes;
062: /**
063: * Code snippet to evaluate to create the logical value.
064: */
065: private String fValue;
066: /**
067: * Description of the logical structure.
068: */
069: private String fDescription;
070: /**
071: * Name and associated code snippet of the variables of the logical value.
072: */
073: private String[][] fVariables;
074: /**
075: * The plugin identifier of the plugin which contributed this logical structure
076: * or <code>null</code> if this structure was defined by the user.
077: */
078: private String fContributingPluginId = null;
079:
080: /**
081: * Performs the evaluations.
082: */
083: private class EvaluationBlock implements IEvaluationListener {
084:
085: private IJavaObject fEvaluationValue;
086: private IJavaReferenceType fEvaluationType;
087: private IJavaThread fThread;
088: private IAstEvaluationEngine fEvaluationEngine;
089: private IEvaluationResult fResult;
090:
091: /**
092: * Constructor
093: * @param value
094: * @param type
095: * @param thread
096: * @param evaluationEngine
097: */
098: public EvaluationBlock(IJavaObject value,
099: IJavaReferenceType type, IJavaThread thread,
100: IAstEvaluationEngine evaluationEngine) {
101: fEvaluationValue = value;
102: fEvaluationType = type;
103: fThread = thread;
104: fEvaluationEngine = evaluationEngine;
105: }
106:
107: /* (non-Javadoc)
108: * @see org.eclipse.jdt.debug.eval.IEvaluationListener#evaluationComplete(org.eclipse.jdt.debug.eval.IEvaluationResult)
109: */
110: public void evaluationComplete(IEvaluationResult result) {
111: synchronized (this ) {
112: fResult = result;
113: this .notify();
114: }
115: }
116:
117: /**
118: * Evaluates the specified snippet and returns the <code>IJavaValue</code> from the evaluation
119: * @param snippet the snippet to evaluate
120: * @return the <code>IJavaValue</code> from the evaluation
121: * @throws DebugException
122: */
123: public IJavaValue evaluate(String snippet)
124: throws DebugException {
125: ICompiledExpression compiledExpression = fEvaluationEngine
126: .getCompiledExpression(snippet, fEvaluationType);
127: if (compiledExpression.hasErrors()) {
128: String[] errorMessages = compiledExpression
129: .getErrorMessages();
130: log(errorMessages);
131: return new JavaStructureErrorValue(errorMessages,
132: fEvaluationValue);
133: }
134: fResult = null;
135: fEvaluationEngine.evaluateExpression(compiledExpression,
136: fEvaluationValue, fThread, this ,
137: DebugEvent.EVALUATION_IMPLICIT, false);
138: synchronized (this ) {
139: if (fResult == null) {
140: try {
141: this .wait();
142: } catch (InterruptedException e) {
143: }
144: }
145: }
146: if (fResult == null) {
147: return new JavaStructureErrorValue(
148: LogicalStructuresMessages.JavaLogicalStructure_1,
149: fEvaluationValue);
150: }
151: if (fResult.hasErrors()) {
152: DebugException exception = fResult.getException();
153: String message;
154: if (exception != null) {
155: if (exception.getStatus().getException() instanceof UnsupportedOperationException) {
156: message = LogicalStructuresMessages.JavaLogicalStructure_0;
157: } else {
158: message = MessageFormat
159: .format(
160: LogicalStructuresMessages.JavaLogicalStructure_2,
161: new String[] { exception
162: .getMessage() });
163: }
164: } else {
165: message = LogicalStructuresMessages.JavaLogicalStructure_3;
166: }
167: return new JavaStructureErrorValue(message,
168: fEvaluationValue);
169: }
170: return fResult.getValue();
171: }
172:
173: /**
174: * Logs the given error messages if this logical structure was contributed
175: * via extension.
176: */
177: private void log(String[] messages) {
178: if (isContributed()) {
179: StringBuffer log = new StringBuffer();
180: for (int i = 0; i < messages.length; i++) {
181: log.append(messages[i]).append('\n');
182: }
183: JDIDebugPlugin.log(new Status(IStatus.ERROR,
184: JDIDebugPlugin.getUniqueIdentifier(),
185: IStatus.ERROR, log.toString(), null));
186: }
187: }
188: }
189:
190: /**
191: * Constructor from parameters.
192: */
193: public JavaLogicalStructure(String type, boolean subtypes,
194: String value, String description, String[][] variables) {
195: fType = type;
196: fSubtypes = subtypes;
197: fValue = value;
198: fDescription = description;
199: fVariables = variables;
200: }
201:
202: /**
203: * Constructor from configuration element.
204: */
205: public JavaLogicalStructure(
206: IConfigurationElement configurationElement)
207: throws CoreException {
208: fType = configurationElement.getAttribute("type"); //$NON-NLS-1$
209: if (fType == null) {
210: throw new CoreException(new Status(IStatus.ERROR,
211: JDIDebugPlugin.getUniqueIdentifier(),
212: JDIDebugPlugin.ERROR,
213: LogicalStructuresMessages.JavaLogicalStructures_0,
214: null));
215: }
216: fSubtypes = Boolean
217: .valueOf(configurationElement.getAttribute("subtypes")).booleanValue(); //$NON-NLS-1$
218: fValue = configurationElement.getAttribute("value"); //$NON-NLS-1$
219: fDescription = configurationElement.getAttribute("description"); //$NON-NLS-1$
220: if (fDescription == null) {
221: throw new CoreException(new Status(IStatus.ERROR,
222: JDIDebugPlugin.getUniqueIdentifier(),
223: JDIDebugPlugin.ERROR,
224: LogicalStructuresMessages.JavaLogicalStructures_4,
225: null));
226: }
227: IConfigurationElement[] variableElements = configurationElement
228: .getChildren("variable"); //$NON-NLS-1$
229: if (fValue == null && variableElements.length == 0) {
230: throw new CoreException(new Status(IStatus.ERROR,
231: JDIDebugPlugin.getUniqueIdentifier(),
232: JDIDebugPlugin.ERROR,
233: LogicalStructuresMessages.JavaLogicalStructures_1,
234: null));
235: }
236: fVariables = new String[variableElements.length][2];
237: for (int j = 0; j < fVariables.length; j++) {
238: String variableName = variableElements[j]
239: .getAttribute("name"); //$NON-NLS-1$
240: if (variableName == null) {
241: throw new CoreException(
242: new Status(
243: IStatus.ERROR,
244: JDIDebugPlugin.getUniqueIdentifier(),
245: JDIDebugPlugin.ERROR,
246: LogicalStructuresMessages.JavaLogicalStructures_2,
247: null));
248: }
249: fVariables[j][0] = variableName;
250: String variableValue = variableElements[j]
251: .getAttribute("value"); //$NON-NLS-1$
252: if (variableValue == null) {
253: throw new CoreException(
254: new Status(
255: IStatus.ERROR,
256: JDIDebugPlugin.getUniqueIdentifier(),
257: JDIDebugPlugin.ERROR,
258: LogicalStructuresMessages.JavaLogicalStructures_3,
259: null));
260: }
261: fVariables[j][1] = variableValue;
262: }
263: fContributingPluginId = configurationElement.getContributor()
264: .getName();
265: }
266:
267: /**
268: * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate#providesLogicalStructure(IValue)
269: */
270: public boolean providesLogicalStructure(IValue value) {
271: if (!(value instanceof IJavaObject)) {
272: return false;
273: }
274: return getType((IJavaObject) value) != null;
275: }
276:
277: /**
278: * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate#getLogicalStructure(IValue)
279: */
280: public IValue getLogicalStructure(IValue value) {
281: if (!(value instanceof IJavaObject)) {
282: return value;
283: }
284: IJavaObject javaValue = (IJavaObject) value;
285: try {
286: IJavaReferenceType type = getType(javaValue);
287: if (type == null) {
288: return value;
289: }
290: IJavaStackFrame stackFrame = getStackFrame(javaValue);
291: if (stackFrame == null) {
292: return value;
293: }
294:
295: // find the project the snippets will be compiled in.
296: ISourceLocator locator = javaValue.getLaunch()
297: .getSourceLocator();
298: Object sourceElement = null;
299: if (locator instanceof ISourceLookupDirector) {
300: String[] sourcePaths = type.getSourcePaths(null);
301: if (sourcePaths != null && sourcePaths.length > 0) {
302: sourceElement = ((ISourceLookupDirector) locator)
303: .getSourceElement(sourcePaths[0]);
304: }
305: if (!(sourceElement instanceof IJavaElement)
306: && sourceElement instanceof IAdaptable) {
307: sourceElement = ((IAdaptable) sourceElement)
308: .getAdapter(IJavaElement.class);
309: }
310: }
311: if (sourceElement == null) {
312: sourceElement = locator.getSourceElement(stackFrame);
313: if (!(sourceElement instanceof IJavaElement)
314: && sourceElement instanceof IAdaptable) {
315: sourceElement = ((IAdaptable) sourceElement)
316: .getAdapter(IJavaElement.class);
317: }
318: }
319: IJavaProject project = null;
320: if (sourceElement instanceof IJavaElement) {
321: project = ((IJavaElement) sourceElement)
322: .getJavaProject();
323: } else if (sourceElement instanceof IResource) {
324: IJavaProject resourceProject = JavaCore
325: .create(((IResource) sourceElement)
326: .getProject());
327: if (resourceProject.exists()) {
328: project = resourceProject;
329: }
330: }
331: if (project == null) {
332: return value;
333: }
334:
335: IAstEvaluationEngine evaluationEngine = JDIDebugPlugin
336: .getDefault().getEvaluationEngine(
337: project,
338: (IJavaDebugTarget) stackFrame
339: .getDebugTarget());
340:
341: EvaluationBlock evaluationBlock = new EvaluationBlock(
342: javaValue, type, (IJavaThread) stackFrame
343: .getThread(), evaluationEngine);
344: if (fValue == null) {
345: // evaluate each variable
346: IJavaVariable[] variables = new IJavaVariable[fVariables.length];
347: for (int i = 0; i < fVariables.length; i++) {
348: variables[i] = new JDIPlaceholderVariable(
349: fVariables[i][0], evaluationBlock
350: .evaluate(fVariables[i][1]));
351: }
352: return new LogicalObjectStructureValue(javaValue,
353: variables);
354: }
355: // evaluate the logical value
356: return evaluationBlock.evaluate(fValue);
357:
358: } catch (CoreException e) {
359: JDIDebugPlugin.log(e);
360: }
361: return value;
362: }
363:
364: /**
365: * Returns the <code>IJavaReferenceType</code> from the specified <code>IJavaObject</code>
366: * @param value
367: * @return the <code>IJavaReferenceType</code> from the specified <code>IJavaObject</code>
368: */
369: private IJavaReferenceType getType(IJavaObject value) {
370: try {
371: IJavaType type = value.getJavaType();
372: if (!(type instanceof IJavaClassType)) {
373: return null;
374: }
375: IJavaClassType classType = (IJavaClassType) type;
376: if (classType.getName().equals(fType)) {
377: // found the type
378: return classType;
379: }
380: if (!fSubtypes) {
381: // if not checking the subtypes, stop here
382: return null;
383: }
384: IJavaClassType super Class = classType.getSuperclass();
385: while (super Class != null) {
386: if (super Class.getName().equals(fType)) {
387: // found the type, it's a super class
388: return super Class;
389: }
390: super Class = super Class.getSuperclass();
391: }
392: IJavaInterfaceType[] super Interfaces = classType
393: .getAllInterfaces();
394: for (int i = 0; i < super Interfaces.length; i++) {
395: if (super Interfaces[i].getName().equals(fType)) {
396: // found the type, it's a super interface
397: return super Interfaces[i];
398: }
399: }
400: } catch (DebugException e) {
401: JDIDebugPlugin.log(e);
402: return null;
403: }
404: return null;
405: }
406:
407: /**
408: * Return the current stack frame context, or a valid stack frame for the given value.
409: * @param value
410: * @return the current stack frame context, or a valid stack frame for the given value.
411: * @throws CoreException
412: */
413: private IJavaStackFrame getStackFrame(IValue value)
414: throws CoreException {
415: IStatusHandler handler = getStackFrameProvider();
416: if (handler != null) {
417: IJavaStackFrame stackFrame = (IJavaStackFrame) handler
418: .handleStatus(
419: JDIDebugPlugin.STATUS_GET_EVALUATION_FRAME,
420: value);
421: if (stackFrame != null) {
422: return stackFrame;
423: }
424: }
425: IDebugTarget target = value.getDebugTarget();
426: IJavaDebugTarget javaTarget = (IJavaDebugTarget) target
427: .getAdapter(IJavaDebugTarget.class);
428: if (javaTarget != null) {
429: IThread[] threads = javaTarget.getThreads();
430: for (int i = 0; i < threads.length; i++) {
431: IThread thread = threads[i];
432: if (thread.isSuspended()) {
433: return (IJavaStackFrame) thread.getTopStackFrame();
434: }
435: }
436: }
437: return null;
438: }
439:
440: /**
441: * Returns the singleton stackframe provider
442: * @return the singleton stackframe provider
443: */
444: private static IStatusHandler getStackFrameProvider() {
445: if (fgStackFrameProvider == null) {
446: fgStackFrameProvider = DebugPlugin.getDefault()
447: .getStatusHandler(
448: JDIDebugPlugin.STATUS_GET_EVALUATION_FRAME);
449: }
450: return fgStackFrameProvider;
451: }
452:
453: /**
454: * Returns if this logical structure should be used for subtypes too.
455: * @return if this logical structure should be used for subtypes too.
456: */
457: public boolean isSubtypes() {
458: return fSubtypes;
459: }
460:
461: /**
462: * Sets if this logical structure should be used for subtypes or not.
463: * @param subtypes
464: */
465: public void setSubtypes(boolean subtypes) {
466: fSubtypes = subtypes;
467: }
468:
469: /**
470: * Returns the name of the type this logical structure should be used for.
471: * @return the name of the type this logical structure should be used for.
472: */
473: public String getQualifiedTypeName() {
474: return fType;
475: }
476:
477: /**
478: * Sets the name of the type this logical structure should be used for.
479: * @param type
480: */
481: public void setType(String type) {
482: fType = type;
483: }
484:
485: /**
486: * Returns the code snippet to use to generate the logical structure.
487: * @return the code snippet to use to generate the logical structure.
488: */
489: public String getValue() {
490: return fValue;
491: }
492:
493: /**
494: * Sets the code snippet to use to generate the logical structure.
495: * @param value
496: */
497: public void setValue(String value) {
498: fValue = value;
499: }
500:
501: /**
502: * Returns the variables of this logical structure.
503: * @return the variables of this logical structure.
504: */
505: public String[][] getVariables() {
506: return fVariables;
507: }
508:
509: /**
510: * Sets the variables of this logical structure.
511: * @param variables
512: */
513: public void setVariables(String[][] variables) {
514: fVariables = variables;
515: }
516:
517: /**
518: * Set the description of this logical structure.
519: * @param description
520: */
521: public void setDescription(String description) {
522: fDescription = description;
523: }
524:
525: /* (non-Javadoc)
526: * @see org.eclipse.debug.core.model.ILogicalStructureTypeDelegate2#getDescription(org.eclipse.debug.core.model.IValue)
527: */
528: public String getDescription(IValue value) {
529: return getDescription();
530: }
531:
532: /* (non-Javadoc)
533: * @see org.eclipse.debug.core.ILogicalStructureType#getDescription()
534: */
535: public String getDescription() {
536: return fDescription;
537: }
538:
539: /**
540: * Indicates if this logical structure was contributed by a plug-in
541: * or defined by a user.
542: * @return if this logical structure is contributed
543: */
544: public boolean isContributed() {
545: return fContributingPluginId != null;
546: }
547:
548: /**
549: * Returns the plugin identifier of the plugin which contributed this logical
550: * structure or <code>null</code> if this structure was defined by the user.
551: * @return the plugin identifier of the plugin which contributed this
552: * structure or <code>null</code>
553: */
554: public String getContributingPluginId() {
555: return fContributingPluginId;
556: }
557:
558: /* (non-Javadoc)
559: * @see org.eclipse.debug.core.ILogicalStructureType#getId()
560: */
561: public String getId() {
562: return JDIDebugPlugin.getUniqueIdentifier() + fType
563: + fDescription;
564: }
565: }
|