KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > debug > eval > LocalEvaluationEngine


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.eval;
12
13
14 import java.io.File JavaDoc;
15 import java.io.FileOutputStream JavaDoc;
16 import java.io.IOException JavaDoc;
17 import com.ibm.icu.text.MessageFormat;
18 import java.util.ArrayList JavaDoc;
19 import java.util.Arrays JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.List JavaDoc;
23
24 import org.eclipse.core.resources.IMarker;
25 import org.eclipse.core.runtime.CoreException;
26 import org.eclipse.core.runtime.IProgressMonitor;
27 import org.eclipse.core.runtime.IStatus;
28 import org.eclipse.core.runtime.Status;
29 import org.eclipse.debug.core.DebugEvent;
30 import org.eclipse.debug.core.DebugException;
31 import org.eclipse.debug.core.model.IVariable;
32 import org.eclipse.jdt.core.IJavaProject;
33 import org.eclipse.jdt.core.IType;
34 import org.eclipse.jdt.core.JavaModelException;
35 import org.eclipse.jdt.core.eval.ICodeSnippetRequestor;
36 import org.eclipse.jdt.core.eval.IEvaluationContext;
37 import org.eclipse.jdt.debug.core.IEvaluationRunnable;
38 import org.eclipse.jdt.debug.core.IJavaClassObject;
39 import org.eclipse.jdt.debug.core.IJavaClassType;
40 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
41 import org.eclipse.jdt.debug.core.IJavaObject;
42 import org.eclipse.jdt.debug.core.IJavaStackFrame;
43 import org.eclipse.jdt.debug.core.IJavaThread;
44 import org.eclipse.jdt.debug.core.IJavaType;
45 import org.eclipse.jdt.debug.core.IJavaValue;
46 import org.eclipse.jdt.debug.core.IJavaVariable;
47 import org.eclipse.jdt.debug.core.JDIDebugModel;
48 import org.eclipse.jdt.debug.eval.IClassFileEvaluationEngine;
49 import org.eclipse.jdt.debug.eval.IEvaluationListener;
50 import org.eclipse.jdt.internal.debug.core.JDIDebugPlugin;
51 import org.eclipse.jdt.internal.debug.core.JavaDebugUtils;
52 import org.eclipse.jdt.internal.debug.core.model.JDIDebugTarget;
53 import org.eclipse.jdt.internal.debug.core.model.JDIValue;
54
55 import com.sun.jdi.InvocationException;
56 import com.sun.jdi.ObjectReference;
57
58 /**
59  * An evaluation engine that deploys class files locally
60  */

61
62 public class LocalEvaluationEngine implements IClassFileEvaluationEngine, ICodeSnippetRequestor , IEvaluationRunnable {
63     
64     private static final String JavaDoc CODE_SNIPPET_NAME= "CodeSnippet.class"; //$NON-NLS-1$
65

66     /**
67      * A count of the number of engines created.
68      * Count is incremented on instantiation and decremented on
69      * dispose. When the count == 0, the special CodeSnippet.class
70      * is deleted as this class file is shared by all.
71      */

72     private static int ENGINE_COUNT= 0;
73
74     /**
75      * The Java project context in which to compile snippets.
76      */

77     private IJavaProject fJavaProject;
78     
79     /**
80      * The debug target on which to execute snippets
81      */

82     private IJavaDebugTarget fDebugTarget;
83     
84     /**
85      * The location in which to deploy snippet class files
86      */

87     private File JavaDoc fOutputDirectory;
88     
89     /**
90      * The listener to notify when the current evaluation
91      * is complete.
92      */

93     private IEvaluationListener fListener;
94     
95     /**
96      * The stack frame context for the current evaluation
97      * or <code>null</code> if there is no stack frame
98      * context.
99      */

100     private IJavaStackFrame fStackFrame;
101     
102     /**
103      * The result of this evaluation
104      */

105     private EvaluationResult fResult;
106     
107     /**
108      * Collection of deployed snippet class files
109      */

110     private List JavaDoc fSnippetFiles;
111     
112     /**
113      * Collection of directories created by this evaluation
114      * engine.
115      */

116     private List JavaDoc fDirectories;
117     
118     /**
119      * Evaluation context for the Java project associated
120      * with this evaluation engine.
121      */

122     private IEvaluationContext fEvaluationContext;
123         
124     /**
125      * Array of modifier constants for visible local variables
126      * in the current evaluation.
127      *
128      * XXX: constants should be 'default' or 'final'. Where
129      * are these constants defined.
130      */

131     private int[] fLocalVariableModifiers;
132     
133     /**
134      * Array of names of visible local variables
135      * in the current evaluation.
136      */

137     private String JavaDoc[] fLocalVariableNames;
138     
139     /**
140      * Array of type names of visible local variables
141      * in the current evaluation.
142      */

143     private String JavaDoc[] fLocalVariableTypeNames;
144     
145     /**
146      * The 'this' object for the current evaluation
147      * or <code>null</code> if there is no 'this'
148      * context (static method, or not context)
149      */

150     private IJavaObject fThis;
151     
152     /**
153      * Whether this engine has been disposed.
154      */

155     private boolean fDisposed = false;
156     
157     /**
158      * The number of evaluations currently being
159      * performed.
160      */

161     private int fEvaluationCount = 0;
162     
163     /**
164      * The name of the code snippet class to instantiate
165      */

166     private String JavaDoc fCodeSnippetClassName = null;
167     
168     /**
169      * Whether to hit breakpoints in the evaluation thread
170      */

171     private boolean fHitBreakpoints = false;
172         
173     /**
174      * Constant for empty array of <code>java.lang.String</code>
175      */

176     private static final String JavaDoc[] EMPTY_STRING_ARRAY = new String JavaDoc[0];
177     
178     /**
179      * Constant for empty array of <code>int</code>
180      */

181     private static final int[] EMPTY_INT_ARRAY = new int[0];
182         
183     /**
184      * Cosntructs a new evaluation engine for the given VM in the context
185      * of the specified project. Class files required for the evaluation will
186      * be deployed to the specified directory (which must be on the class
187      * path of the VM in order for evaluation to work).
188      *
189      * @param project context in which to compile snippets
190      * @param vm debug target in which to evaluate snippets
191      * @param directory location where snippet class files will
192      * be deployed for execution. The directory must exist
193      */

194     public LocalEvaluationEngine(IJavaProject project, IJavaDebugTarget vm, File JavaDoc directory) {
195         setJavaProject(project);
196         setDebugTarget(vm);
197         setOutputDirectory(directory);
198         ENGINE_COUNT++;
199     }
200
201     /**
202      * @see ICodeSnippetRequestor#acceptClassFiles(byte[][], String[][], String)
203      */

204     public boolean acceptClassFiles(
205         byte[][] classFileBytes,
206         String JavaDoc[][] classFileCompoundNames,
207         String JavaDoc codeSnippetClassName) {
208             try {
209                 deploy(classFileBytes, classFileCompoundNames);
210             } catch (DebugException e) {
211                 getResult().setException(e);
212                 return false;
213             }
214             if (codeSnippetClassName != null) {
215                 setCodeSnippetClassName(codeSnippetClassName);
216                 try {
217                     getThread().runEvaluation(this, null, DebugEvent.EVALUATION, getHitBreakpoints());
218                 } catch (DebugException e) {
219                     // exception handling is in evaluation runnable
220
}
221             }
222             return true;
223     }
224     
225     public void run(IJavaThread thread, IProgressMonitor monitor) {
226         IJavaObject codeSnippetInstance = null;
227         try {
228             codeSnippetInstance = newInstance(getCodeSnippetClassName());
229             initializeLocals(codeSnippetInstance);
230             codeSnippetInstance.sendMessage(RUN_METHOD, "()V", null, getThread(), false); //$NON-NLS-1$
231
restoreLocals(codeSnippetInstance);
232             
233             // now retrieve the description of the result
234
IVariable[] fields = codeSnippetInstance.getVariables();
235             IJavaVariable resultValue = null;
236             IJavaVariable resultType = null;
237             for (int i = 0; i < fields.length; i++) {
238                 if (fields[i].getName().equals(RESULT_TYPE_FIELD)) {
239                     resultType = (IJavaVariable)fields[i];
240                 }
241                 if (fields[i].getName().equals(RESULT_VALUE_FIELD)) {
242                     resultValue = (IJavaVariable)fields[i];
243                 }
244             }
245             IJavaValue result = convertResult((IJavaClassObject)resultType.getValue(), (IJavaValue)resultValue.getValue());
246             getResult().setValue(result);
247         } catch (DebugException e) {
248             getResult().setException(e);
249             
250             Throwable JavaDoc underlyingException = e.getStatus().getException();
251             if (underlyingException instanceof InvocationException) {
252                 ObjectReference theException = ((InvocationException)underlyingException).exception();
253                 if (theException != null) {
254                     try {
255                         try {
256                             IJavaObject v = (IJavaObject)JDIValue.createValue((JDIDebugTarget)getDebugTarget(), theException);
257                             v.sendMessage("printStackTrace", "()V", null, getThread(), false); //$NON-NLS-2$ //$NON-NLS-1$
258
} catch (DebugException de) {
259                             JDIDebugPlugin.log(de);
260                         }
261                     } catch (RuntimeException JavaDoc re) {
262                         JDIDebugPlugin.log(re);
263                     }
264                 }
265             }
266         }
267         
268     }
269     
270     /**
271      * Initializes the value of instance variables in the
272      * 'code snippet object' that are used as placeholders
273      * for locals and 'this' in the current stack frame.
274      *
275      * @param object instance of code snippet class that will
276      * be run
277      * @exception DebugException if an exception is thrown
278      * accessing the given object
279      */

280     protected void initializeLocals(IJavaObject object) throws DebugException {
281         IJavaVariable[] locals = null;
282         IJavaObject thisObject = getThis();
283         if (getStackFrame() != null) {
284             locals = getStackFrame().getLocalVariables();
285         }
286         if (locals != null) {
287             for (int i = 0; i < locals.length; i++) {
288                 IJavaVariable local = locals[i];
289                 IJavaVariable field = object.getField(LOCAL_VAR_PREFIX + local.getName(), false);
290                 // internal error if field is not found
291
if (field == null) {
292                     throw new DebugException(
293                         new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
294                         DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__4, null)
295                     );
296                 }
297                 field.setValue(local.getValue());
298             }
299         }
300         if (thisObject != null) {
301             IJavaVariable field = object.getField(DELEGATE_THIS, false);
302             // internal error if field is not found
303
if (field == null) {
304                 throw new DebugException(
305                     new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
306                     DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize___this___context__5, null)
307                 );
308             }
309             field.setValue(thisObject);
310         }
311     }
312     
313     /**
314      * Restores the value local variables from the instance
315      * variables in the 'code snippet object' that are used
316      * as placeholders for locals in the current stack frame.
317      *
318      * @param object instance of code snippet class that was
319      * run
320      * @exception DebugException if an exception is thrown
321      * accessing the given object
322      */

323     protected void restoreLocals(IJavaObject object) throws DebugException {
324         IJavaVariable[] locals = null;
325         if (getStackFrame() != null) {
326             locals = getStackFrame().getLocalVariables();
327         }
328         if (locals != null) {
329             for (int i = 0; i < locals.length; i++) {
330                 IJavaVariable local = locals[i];
331                 IJavaVariable field = object.getField(LOCAL_VAR_PREFIX + local.getName(), false);
332                 // internal error if field is not found
333
if (field == null) {
334                     throw new DebugException(
335                         new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
336                         DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_initialize_local_variables__6, null)
337                     );
338                 }
339                 local.setValue(field.getValue());
340             }
341         }
342     }
343
344     /**
345      * @see ICodeSnippetRequestor#acceptProblem(IMarker, String, int)
346      */

347     public void acceptProblem(IMarker problemMarker, String JavaDoc fragmentSource, int fragmentKind) {
348         if (problemMarker.getAttribute(IMarker.SEVERITY, -1) != IMarker.SEVERITY_ERROR) {
349             return;
350         }
351         getResult().addError(problemMarker.getAttribute(IMarker.MESSAGE, "")); //$NON-NLS-1$
352
}
353     
354     /**
355      * @see IEvaluationEngine#getDebugTarget()
356      */

357     public IJavaDebugTarget getDebugTarget() {
358         return fDebugTarget;
359     }
360
361     /**
362      * Sets the debug target in which snippets are executed.
363      *
364      * @param debugTarget the debug target in which snippets are executed
365      */

366     private void setDebugTarget(IJavaDebugTarget debugTarget) {
367         fDebugTarget = debugTarget;
368     }
369
370     /**
371      * @see IEvaluationEngine#getJavaProject()
372      */

373     public IJavaProject getJavaProject() {
374         return fJavaProject;
375     }
376
377     /**
378      * Sets the Java project in which snippets are compiled.
379      *
380      * @param javaProject the Java project in which snippets are compiled
381      */

382     private void setJavaProject(IJavaProject javaProject) {
383         fJavaProject = javaProject;
384     }
385
386     /**
387      * Returns the directory in which snippet class files are deployed.
388      *
389      * @return the directory in which snippet class files are deployed.
390      */

391     public File JavaDoc getOutputDirectory() {
392         return fOutputDirectory;
393     }
394
395     /**
396      * Sets the directory in which snippet class files are
397      * deployed.
398      *
399      * @param outputDirectory location to deploy snippet class files
400      */

401     private void setOutputDirectory(File JavaDoc outputDirectory) {
402         fOutputDirectory = outputDirectory;
403     }
404
405     /**
406      * @see IClassFileEvaluationEngine#evaluate(String, IJavaThread, IEvaluationListener)
407      */

408     public void evaluate(String JavaDoc snippet, IJavaThread thread, IEvaluationListener listener, boolean hitBreakpoints) throws DebugException {
409             checkDisposed();
410             checkEvaluating();
411             try {
412                 evaluationStarted();
413                 setListener(listener);
414                 setHitBreakpoints(hitBreakpoints);
415                 setResult(new EvaluationResult(this, snippet, thread));
416                 checkThread();
417                 // no receiver/stack frame context
418
setThis(null);
419                 setLocalVariableNames(EMPTY_STRING_ARRAY);
420                 setLocalVariableTypeNames(EMPTY_STRING_ARRAY);
421                 setLocalVariableModifiers(EMPTY_INT_ARRAY);
422                 
423                 // do the evaluation in a different thread
424
Runnable JavaDoc r = new Runnable JavaDoc() {
425                     public void run() {
426                         try {
427                             LocalEvaluationEngine.this.getEvaluationContext().
428                                 evaluateCodeSnippet(LocalEvaluationEngine.this.getSnippet(),
429                                     LocalEvaluationEngine.this, null);
430                         } catch (JavaModelException e) {
431                             LocalEvaluationEngine.this.getResult().setException(new DebugException(e.getStatus()));
432                         } finally {
433                             LocalEvaluationEngine.this.evaluationComplete();
434                         }
435                     }
436                 };
437                 
438                 Thread JavaDoc t = new Thread JavaDoc(r);
439                 t.setDaemon(true);
440                 t.start();
441             } catch (DebugException d) {
442                 evaluationAborted();
443                 throw d;
444             }
445             
446     }
447
448     /**
449      * @see IEvaluationEngine#evaluate(String, IJavaStackFrame, IEvaluationListener, int)
450      */

451     public void evaluate(String JavaDoc snippet, IJavaStackFrame frame, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException {
452             checkDisposed();
453             checkEvaluating();
454             try {
455                 evaluationStarted();
456                 setListener(listener);
457                 setStackFrame(frame);
458                 setHitBreakpoints(hitBreakpoints);
459                 setResult(new EvaluationResult(this, snippet, (IJavaThread)frame.getThread()));
460                 checkThread();
461                 
462                 // set up local variables and 'this' context for evaluation
463
IJavaVariable[] locals = frame.getLocalVariables();
464                 
465                 List JavaDoc typeNames = new ArrayList JavaDoc(locals.length);
466                 List JavaDoc varNames = new ArrayList JavaDoc(locals.length);
467     
468                 for (int i = 0; i < locals.length; i++) {
469                     IJavaVariable var = locals[i];
470                     String JavaDoc typeName = getTranslatedTypeName(var.getReferenceTypeName());
471                     if (typeName != null) {
472                         typeNames.add(typeName);
473                         varNames.add(var.getName());
474                     }
475                 }
476                 
477                 setLocalVariableTypeNames((String JavaDoc[])typeNames.toArray(new String JavaDoc[typeNames.size()]));
478                 setLocalVariableNames((String JavaDoc[])varNames.toArray(new String JavaDoc[varNames.size()]));
479                 int[] modifiers = new int[typeNames.size()];
480                 // cannot determine if local is final, so specify as default
481
Arrays.fill(modifiers, 0);
482                 setLocalVariableModifiers(modifiers);
483                 setThis(frame.getThis());
484                 
485                 final boolean isStatic = frame.isStatic();
486                 final boolean isConstructor = frame.isConstructor();
487                 final IType receivingType = JavaDebugUtils.resolveDeclaringType(frame);
488                 validateReceivingType(receivingType);
489                 
490                 // do the evaluation in a different thread
491
Runnable JavaDoc r = new Runnable JavaDoc() {
492                     public void run() {
493                         try {
494                             LocalEvaluationEngine.this.getEvaluationContext().
495                                 evaluateCodeSnippet(
496                                 LocalEvaluationEngine.this.getSnippet(),
497                                 LocalEvaluationEngine.this.getLocalVariableTypeNames(),
498                                 LocalEvaluationEngine.this.getLocalVariableNames(),
499                                 LocalEvaluationEngine.this.getLocalVariableModifiers(),
500                                 receivingType,
501                                 isStatic,
502                                 isConstructor,
503                                 LocalEvaluationEngine.this,
504                                 null);
505                         } catch (JavaModelException e) {
506                             LocalEvaluationEngine.this.getResult().setException(new DebugException(e.getStatus()));
507                         } finally {
508                             LocalEvaluationEngine.this.evaluationComplete();
509                         }
510                     }
511                 };
512                 
513                 Thread JavaDoc t = new Thread JavaDoc(r);
514                 t.setDaemon(true);
515                 t.start();
516             } catch (DebugException d) {
517                 evaluationAborted();
518                 throw d;
519             } catch (CoreException e) {
520                 evaluationAborted();
521                 throw new DebugException(e.getStatus());
522             }
523     }
524
525     /**
526      * Verifies the receiving type was resovled and is not an inner type.
527      *
528      * @param receivingType
529      * @throws DebugException
530      */

531     private void validateReceivingType(final IType receivingType) throws DebugException {
532         if (receivingType == null) {
533             throw new DebugException(
534                 new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
535                 DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_determine_receiving_type_context__18, null)
536             );
537         }
538         
539         if (receivingType.getDeclaringType() != null) {
540             throw new DebugException(
541                 new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
542                 DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_in_context_of_inner_type_not_supported__19, null)
543             );
544         }
545     }
546     
547     /**
548      * @see IEvaluationEngine#evaluate(String, IJavaObject, IJavaThread, IEvaluationListener, int)
549      */

550     public void evaluate(String JavaDoc snippet, IJavaObject thisContext, IJavaThread thread, IEvaluationListener listener, int evaluationDetail, boolean hitBreakpoints) throws DebugException {
551             checkDisposed();
552             checkEvaluating();
553             try {
554                 evaluationStarted();
555                 setListener(listener);
556                 setHitBreakpoints(hitBreakpoints);
557                 setResult(new EvaluationResult(this, snippet, thread));
558                 checkThread();
559                             
560                 // no locals
561
setLocalVariableTypeNames(new String JavaDoc[0]);
562                 setLocalVariableNames(new String JavaDoc[0]);
563                 setLocalVariableModifiers(new int[0]);
564                 
565                 setThis(thisContext);
566                 
567                 final boolean isStatic = false;
568                 final boolean isConstructor = false;
569                 final IType receivingType = JavaDebugUtils.resolveType(thisContext.getJavaType());
570                 validateReceivingType(receivingType);
571                 
572                 // do the evaluation in a different thread
573
Runnable JavaDoc r = new Runnable JavaDoc() {
574                     public void run() {
575                         try {
576                             LocalEvaluationEngine.this.getEvaluationContext().
577                                 evaluateCodeSnippet(
578                                 LocalEvaluationEngine.this.getSnippet(),
579                                 LocalEvaluationEngine.this.getLocalVariableTypeNames(),
580                                 LocalEvaluationEngine.this.getLocalVariableNames(),
581                                 LocalEvaluationEngine.this.getLocalVariableModifiers(),
582                                 receivingType,
583                                 isStatic,
584                                 isConstructor,
585                                 LocalEvaluationEngine.this,
586                                 null);
587                         } catch (JavaModelException e) {
588                             LocalEvaluationEngine.this.getResult().setException(new DebugException(e.getStatus()));
589                         } finally {
590                             LocalEvaluationEngine.this.evaluationComplete();
591                         }
592                     }
593                 };
594                 
595                 Thread JavaDoc t = new Thread JavaDoc(r);
596                 t.setDaemon(true);
597                 t.start();
598             } catch (DebugException d) {
599                 evaluationAborted();
600                 throw d;
601             } catch (CoreException e) {
602                 evaluationAborted();
603                 throw new DebugException(e.getStatus());
604             }
605     }
606     
607     /**
608      * Throws an exception if this engine has already been
609      * disposed.
610      *
611      * @exception DebugException if this engine has been disposed
612      */

613     protected void checkDisposed() throws DebugException {
614         if (isDisposed()) {
615             throw new DebugException(
616                 new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
617                 DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___evaluation_context_has_been_disposed__7, null)
618             );
619         }
620     }
621     
622     /**
623      * Throws an exception if this engine is already in an
624      * evaluation.
625      *
626      * @exception DebugException if this engine is currently
627      * performing an evaluation
628      */

629     protected void checkEvaluating() throws DebugException {
630         if (isEvaluating()) {
631             throw new DebugException(
632                 new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
633                 DebugException.REQUEST_FAILED, "Cannot perform nested evaluations.", null) //$NON-NLS-1$
634
);
635         }
636     }
637     
638     /**
639      * Throws an exception if this engine's current evaluation
640      * thread is not suspended.
641      *
642      * @exception DebugException if this engine's current evaluation
643      * thread is not suspended
644      */

645     protected void checkThread() throws DebugException {
646         if (!getThread().isSuspended()) {
647             throw new DebugException(
648                 new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
649                 DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___evaluation_thread_must_be_suspended__8, null)
650             );
651         }
652     }
653
654     /**
655      * Deletes deployed class files, and clears state.
656      *
657      * @see IEvaluationEngine#dispose()
658      */

659     public void dispose() {
660         fDisposed = true;
661         ENGINE_COUNT--;
662         if (isEvaluating()) {
663             // cannot dispose if in an evaluation, must
664
// wait for evaluation to complete
665
return;
666         }
667         List JavaDoc snippetFiles = getSnippetFiles();
668         Iterator JavaDoc iter = snippetFiles.iterator();
669         while (iter.hasNext()) {
670             File JavaDoc file = (File JavaDoc)iter.next();
671             if (file.exists()) {
672                 if (CODE_SNIPPET_NAME.equals(file.getName()) && ENGINE_COUNT > 0) {
673                     continue; //do not delete the common file for other engines
674
}
675                 if (!file.delete()) {
676                     JDIDebugPlugin.log(
677                         new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED,
678                             MessageFormat.format("Unable to delete temporary evaluation class file {0}.", new String JavaDoc[] {file.getAbsolutePath()}), null) //$NON-NLS-1$
679
);
680                 }
681             }
682         }
683         List JavaDoc directories = getDirectories();
684         // remove directories in bottom up order
685
int i = directories.size() - 1;
686         while (i >= 0) {
687             File JavaDoc dir = (File JavaDoc)directories.get(i);
688             String JavaDoc[] listing= dir.list();
689             if (dir.exists() && listing != null && listing.length == 0 && !dir.delete()) {
690                 JDIDebugPlugin.log(
691                     new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED,
692                         MessageFormat.format("Unable to delete temporary evaluation directory {0}.", new String JavaDoc[] {dir.getAbsolutePath()}), null) //$NON-NLS-1$
693
);
694             }
695             i--;
696         }
697         reset();
698         setJavaProject(null);
699         setDebugTarget(null);
700         setOutputDirectory(null);
701         setResult(null);
702         setEvaluationContext(null);
703     }
704     
705
706     /**
707      * Resets this engine for another evaluation.
708      */

709     private void reset() {
710         setThis(null);
711         setStackFrame(null);
712         setListener(null);
713     }
714     
715     /**
716      * Returns the listener to notify when the current
717      * evaluation is complete.
718      *
719      * @return the listener to notify when the current
720      * evaluation is complete
721      */

722     protected IEvaluationListener getListener() {
723         return fListener;
724     }
725
726     /**
727      * Sets the listener to notify when the current
728      * evaluation is complete.
729      *
730      * @param listener the listener to notify when the current
731      * evaluation is complete
732      */

733     private void setListener(IEvaluationListener listener) {
734         fListener = listener;
735     }
736
737     /**
738      * Returns the stack frame context for the current
739      * evaluation, or <code>null</code> if none.
740      *
741      * @return the stack frame context for the current
742      * evaluation, or <code>null</code> if none
743      */

744     protected IJavaStackFrame getStackFrame() {
745         return fStackFrame;
746     }
747
748     /**
749      * Sets the stack frame context for the current evaluation.
750      *
751      * @param stackFrame stack frame context or <code>null</code>
752      * if none
753      */

754     private void setStackFrame(IJavaStackFrame stackFrame) {
755         fStackFrame = stackFrame;
756     }
757
758     /**
759      * Returns the thread in which the current evaluation is
760      * to be executed.
761      *
762      * @return the thread in which the current evaluation is
763      * to be executed
764      */

765     protected IJavaThread getThread() {
766         return getResult().getThread();
767     }
768     
769     /**
770      * Returns the code snippet being evaluated.
771      *
772      * @return the code snippet being evaluated.
773      */

774     protected String JavaDoc getSnippet() {
775         return getResult().getSnippet();
776     }
777
778     /**
779      * Returns the current evaluation result.
780      *
781      * @return the current evaluation result
782      */

783     protected EvaluationResult getResult() {
784         return fResult;
785     }
786
787     /**
788      * Sets the current evaluation result.
789      *
790      * @param result the current evaluation result
791      */

792     private void setResult(EvaluationResult result) {
793         fResult = result;
794     }
795     
796     /**
797      * Deploys the given class files to this engine's
798      * output location, and adds the files to this
799      * engines list of temporary files to be deleted
800      * when disposed.
801      *
802      * @exception DebugException if this fails due to a
803      * lower level exception.
804      */

805     protected void deploy(byte[][] classFiles, String JavaDoc[][] classFileNames) throws DebugException {
806         for (int i = 0; i < classFiles.length; i++) {
807             String JavaDoc[] compoundName = classFileNames[i];
808             //create required folders
809
File JavaDoc dir = LocalEvaluationEngine.this.getOutputDirectory();
810             try {
811                 String JavaDoc pkgDirName = dir.getCanonicalPath();
812                 for (int j = 0; j < (compoundName.length - 1); j++) {
813                     pkgDirName += File.separator + compoundName[j];
814                     File JavaDoc pkgDir = new File JavaDoc(pkgDirName);
815                     if (!pkgDir.exists()) {
816                         pkgDir.mkdir();
817                         addDirectory(pkgDir);
818                     }
819                 }
820                 String JavaDoc name = compoundName[compoundName.length - 1] + ".class"; //$NON-NLS-1$
821
File JavaDoc classFile = new File JavaDoc(pkgDirName + File.separator + name);
822                 if (!classFile.exists()) {
823                     classFile.createNewFile();
824                 }
825                 FileOutputStream JavaDoc stream = new FileOutputStream JavaDoc(classFile);
826                 stream.write(classFiles[i]);
827                 stream.close();
828                 LocalEvaluationEngine.this.addSnippetFile(classFile);
829             } catch (IOException JavaDoc e) {
830                 throw new DebugException(
831                     new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(), DebugException.REQUEST_FAILED,
832                         MessageFormat.format(EvaluationMessages.LocalEvaluationEngine__0__occurred_deploying_class_file_for_evaluation_9, new String JavaDoc[] {e.toString()}), e)
833                 );
834             }
835         }
836     }
837     
838     /**
839      * Adds the given file to this engine's collection
840      * of deployed snippet class files, which are to
841      * be deleted when this engine is diposed.
842      *
843      * @param File snippet class file
844      */

845     private void addSnippetFile(File JavaDoc file) {
846         if (fSnippetFiles == null) {
847             fSnippetFiles = new ArrayList JavaDoc();
848         }
849         fSnippetFiles.add(file);
850     }
851     
852     /**
853      * Adds the given file to this engine's collection
854      * of cerated directories, which are to
855      * be deleted when this engine is diposed.
856      *
857      * @param file directory created for class file deployment
858      */

859     private void addDirectory(File JavaDoc file) {
860         if (fDirectories == null) {
861             fDirectories = new ArrayList JavaDoc();
862         }
863         fDirectories.add(file);
864     }
865
866     /**
867      * Returns an evaluation context for this evaluation
868      * engine. An evaluation context is associted with a
869      * specific Java project. The evaluation context is
870      * created lazily on the first access.
871      *
872      * @return evaluation context
873      */

874     protected IEvaluationContext getEvaluationContext() {
875         if (fEvaluationContext == null) {
876             fEvaluationContext = getJavaProject().newEvaluationContext();
877         }
878         return fEvaluationContext;
879     }
880     
881     /**
882      * Sets the evaluation context for this evaluation
883      * engine.
884      *
885      * @param context evaluation context
886      */

887     private void setEvaluationContext(IEvaluationContext context) {
888         fEvaluationContext = context;
889     }
890     
891
892     /**
893      * Returns a collection of snippet class file deployed by
894      * this evaluation engine, possibly empty.
895      *
896      * @return deployed class files
897      */

898     protected List JavaDoc getSnippetFiles() {
899         if (fSnippetFiles == null) {
900             return Collections.EMPTY_LIST;
901         }
902         return fSnippetFiles;
903     }
904     
905     /**
906      * Returns a collection of directories created by
907      * this evaluation engine, possibly empty.
908      *
909      * @return directories created when deploying class files
910      */

911     protected List JavaDoc getDirectories() {
912         if (fDirectories == null) {
913             return Collections.EMPTY_LIST;
914         }
915         return fDirectories;
916     }
917     
918     /**
919      * Returns whether this evaluation engine has been
920      * disposed.
921      *
922      * @return whether this evaluation engine has been
923      * disposed
924      */

925     protected boolean isDisposed() {
926         return fDisposed;
927     }
928     
929     /**
930      * The evaluation is complete. Notify the current listener
931      * and reset for the next evaluation.
932      */

933     protected void evaluationComplete() {
934         // only notify if plug-in not yet shutdown (bug# 8693)
935
if (JDIDebugPlugin.getDefault() != null) {
936             getListener().evaluationComplete(getResult());
937         }
938         evaluationEnded();
939         reset();
940         if (isDisposed()) {
941             // if the engine was disposed during an evaluation
942
// do the cleanup now
943
dispose();
944         }
945     }
946     
947     /**
948      * Increments the evaluation counter.
949      */

950     private void evaluationStarted() {
951         fEvaluationCount++;
952     }
953     
954     /**
955      * Decrements the evaluation counter.
956      */

957     private void evaluationEnded() {
958         if (fEvaluationCount > 0) {
959             fEvaluationCount--;
960         }
961     }
962     
963     /**
964      * Returns whether this engine is currently in the
965      * midst of an evaluation.
966      */

967     protected boolean isEvaluating() {
968         return fEvaluationCount > 0;
969     }
970     
971     /**
972      * Called when an evaluation is aborted due to an
973      * exception. Decrements the evalution count, and
974      * disposes this engine if the target VM disconnected
975      * or terminated during the evaluation attempt.
976      */

977     private void evaluationAborted() {
978         evaluationEnded();
979         if (isDisposed()) {
980             // if the engine was disposed during an evaluation
981
// do the cleanup now
982
dispose();
983         }
984     }
985     
986     /**
987      * Constructs and returns a new instance of the specified
988      * class on the target VM.
989      *
990      * @param className fully qualified class name
991      * @return a new instance on the target, as an <code>IJavaValue</code>
992      * @exception DebugException if creation fails
993      */

994     protected IJavaObject newInstance(String JavaDoc className) throws DebugException {
995         IJavaObject object = null;
996         IJavaClassType clazz = null;
997         IJavaType[] types = getDebugTarget().getJavaTypes(className);
998         if (types != null && types.length > 0) {
999             clazz = (IJavaClassType)types[0];
1000        }
1001        if (clazz == null) {
1002            // The class is not loaded on the target VM.
1003
// Force the load of the class.
1004
types = getDebugTarget().getJavaTypes("java.lang.Class"); //$NON-NLS-1$
1005
IJavaClassType classClass = null;
1006            if (types != null && types.length > 0) {
1007                classClass = (IJavaClassType)types[0];
1008            }
1009            if (classClass == null) {
1010                // unable to load the class
1011
throw new DebugException(
1012                    new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
1013                    DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___unable_to_instantiate_code_snippet_class__11, null)
1014                );
1015            }
1016            IJavaValue[] args = new IJavaValue[] {getDebugTarget().newValue(className)};
1017            IJavaObject classObject = (IJavaObject)classClass.sendMessage("forName", "(Ljava/lang/String;)Ljava/lang/Class;", args, getThread()); //$NON-NLS-2$ //$NON-NLS-1$
1018
object = (IJavaObject)classObject.sendMessage("newInstance", "()Ljava/lang/Object;", null, getThread(), false); //$NON-NLS-2$ //$NON-NLS-1$
1019
} else {
1020            object = clazz.newInstance("<init>", null, getThread()); //$NON-NLS-1$
1021
}
1022        return object;
1023    }
1024    
1025    /**
1026     * Interpretts and returns the result of the running the snippet
1027     * class file. The type of the result is described by an instance of
1028     * <code>java.lang.Class</code>. The value is interpretted based
1029     * on the result type.
1030     * <p>
1031     * Objects as well as primitve data types (boolean, int, etc.),
1032     * have class objects, which are created by the VM. If the class object
1033     * represents a primitive data type, then the associated value
1034     * is stored in an instance of its "object" class. For example, when
1035     * the result type is the class object for <code>int</code>, the result
1036     * object is an instance of <code>java.lang.Integer</code>, and the
1037     * actual <code>int</code> is stored in the </code>intValue()</code>.
1038     * When the result type is the class object for <code>java.lang.Integer</code>
1039     * the result object is an instance of <code>java.lang.Integer</code>,
1040     * to be interpretted as a <ocde>java.lang.Integer</code>.
1041     * </p>
1042     *
1043     * @param resultType the class of the result
1044     * @param resultValue the value of ther result, to be interpretted
1045     * based on resultType
1046     * @return the result of running the code snipped class file
1047     */

1048    protected IJavaValue convertResult(IJavaClassObject resultType, IJavaValue result) throws DebugException {
1049        if (resultType == null) {
1050            // there was an exception or compilation problem - no result
1051
return null;
1052        }
1053
1054        // check the type of the result - if a primitive type, convert it
1055
String JavaDoc sig = resultType.getInstanceType().getSignature();
1056        if (sig.equals("V") || sig.equals("Lvoid;")) { //$NON-NLS-2$ //$NON-NLS-1$
1057
// void
1058
return getDebugTarget().voidValue();
1059        }
1060
1061        if (result.getJavaType() == null) {
1062            // null result
1063
return result;
1064        }
1065        
1066        if (sig.length() == 1) {
1067            // primitive type - find the instance variable with the
1068
// signature of the result type we are looking for
1069
IVariable[] vars = result.getVariables();
1070            IJavaVariable var = null;
1071            for (int i = 0; i < vars.length; i++) {
1072                IJavaVariable jv = (IJavaVariable)vars[i];
1073                if (!jv.isStatic() && jv.getSignature().equals(sig)) {
1074                    var = jv;
1075                    break;
1076                }
1077            }
1078            if (var != null) {
1079                return (IJavaValue)var.getValue();
1080            }
1081        } else {
1082            // an object
1083
return result;
1084        }
1085        throw new DebugException(
1086            new Status(IStatus.ERROR, JDIDebugModel.getPluginIdentifier(),
1087            DebugException.REQUEST_FAILED, EvaluationMessages.LocalEvaluationEngine_Evaluation_failed___internal_error_retreiving_result__17, null)
1088        );
1089    }
1090    
1091    /**
1092     * Returns the modifiers of the local variables
1093     * visible in this evaluation, possibly empty.
1094     *
1095     * @return array of modifiers
1096     */

1097    private int[] getLocalVariableModifiers() {
1098        return fLocalVariableModifiers;
1099    }
1100
1101    /**
1102     * Sets the modifiers of the local variables
1103     * visible in this evaluation, possibly empty.
1104     *
1105     * @param localVariableModifiers array of modifiers
1106     */

1107    private void setLocalVariableModifiers(int[] localVariableModifiers) {
1108        fLocalVariableModifiers = localVariableModifiers;
1109    }
1110    
1111    /**
1112     * Returns the names of the local variables
1113     * visible in this evaluation, possibly empty.
1114     *
1115     * @param array of names
1116     */

1117    private String JavaDoc[] getLocalVariableNames() {
1118        return fLocalVariableNames;
1119    }
1120    
1121    /**
1122     * Sets the names of the local variables
1123     * visible in this evaluation, possibly empty.
1124     *
1125     * @param localVariableNames array of names
1126     */

1127    private void setLocalVariableNames(String JavaDoc[] localVariableNames) {
1128        fLocalVariableNames = localVariableNames;
1129    }
1130
1131    /**
1132     * Returns the type names of the local variables
1133     * visible in this evaluation, possibly empty.
1134     *
1135     * @param array of type names
1136     */

1137    private String JavaDoc[] getLocalVariableTypeNames() {
1138        return fLocalVariableTypeNames;
1139    }
1140
1141    /**
1142     * Sets the type names of the local variables
1143     * visible in this evaluation, possibly empty.
1144     *
1145     * @param localVariableTypeNames array of type names
1146     */

1147    private void setLocalVariableTypeNames(String JavaDoc[] localVariableTypeNames) {
1148        fLocalVariableTypeNames = localVariableTypeNames;
1149    }
1150    
1151    /**
1152     * Sets the receiver context for the associated evaluation,
1153     * possibly <code>null</code> if the evaluation is
1154     * in the context of a static method or there is
1155     * no object context.
1156     *
1157     * @param thisObject the receiver content of the
1158     * associated evaluation, or <code>null</code>
1159     */

1160    private void setThis(IJavaObject thisObject) {
1161        fThis = thisObject;
1162    }
1163    
1164    /**
1165     * Returns the receiver context for the associated evaluation,
1166     * or <code>null</code> if the evaluation is
1167     * in the context of a static method or there is
1168     * no object context.
1169     *
1170     * @return the receiver context of the associated
1171     * evaluation or <code>null</code>
1172     */

1173    private IJavaObject getThis() {
1174        return fThis;
1175    }
1176    
1177    /**
1178     * Returns a copy of the type name with '$' replaced by
1179     * '.', or returns <code>null</code> if the given type
1180     * name refers to an anonymous inner class.
1181     *
1182     * @param typeName a fully qualified type name
1183     * @return a copy of the type name with '$' replaced by
1184     * '.', or returns <code>null</code> if the given type
1185     * name refers to an anonymous inner class.
1186     */

1187    protected String JavaDoc getTranslatedTypeName(String JavaDoc typeName) {
1188        int index = typeName.lastIndexOf('$');
1189        if (index == -1) {
1190            return typeName;
1191        }
1192        if (index + 1 > typeName.length()) {
1193            // invalid name
1194
return typeName;
1195        }
1196        String JavaDoc last = typeName.substring(index + 1);
1197        try {
1198            Integer.parseInt(last);
1199            return null;
1200        } catch (NumberFormatException JavaDoc e) {
1201            return typeName.replace('$', '.');
1202        }
1203    }
1204
1205    /**
1206     * Returns an array of simple type names that are
1207     * part of the given type's qualified name. For
1208     * example, if the given name is <code>x.y.A$B</code>,
1209     * an array with <code>["A", "B"]</code> is returned.
1210     *
1211     * @param typeName fully qualified type name
1212     * @return array of nested type names
1213     */

1214    protected String JavaDoc[] getNestedTypeNames(String JavaDoc typeName) {
1215        int index = typeName.lastIndexOf('.');
1216        if (index >= 0) {
1217            typeName= typeName.substring(index + 1);
1218        }
1219        index = typeName.indexOf('$');
1220        ArrayList JavaDoc list = new ArrayList JavaDoc(1);
1221        while (index >= 0) {
1222            list.add(typeName.substring(0, index));
1223            typeName = typeName.substring(index + 1);
1224            index = typeName.indexOf('$');
1225        }
1226        list.add(typeName);
1227        return (String JavaDoc[])list.toArray(new String JavaDoc[list.size()]);
1228    }
1229    
1230    /**
1231     * @see IClassFileEvaluationEngine#getImports()
1232     */

1233    public String JavaDoc[] getImports() {
1234        return getEvaluationContext().getImports();
1235    }
1236
1237    /**
1238     * @see IClassFileEvaluationEngine#setImports(String[])
1239     */

1240    public void setImports(String JavaDoc[] imports) {
1241        getEvaluationContext().setImports(imports);
1242    }
1243    
1244    /**
1245     * Sets the name of the code snippet to instantiate
1246     * to run the current evaluation.
1247     *
1248     * @param name the name of the deployed code snippet
1249     * to instantiate and run
1250     */

1251    private void setCodeSnippetClassName(String JavaDoc name) {
1252        fCodeSnippetClassName = name;
1253    }
1254
1255    /**
1256     * Returns the name of the code snippet to instantiate
1257     * to run the current evaluation.
1258     *
1259     * @return the name of the deployed code snippet
1260     * to instantiate and run
1261     */

1262    protected String JavaDoc getCodeSnippetClassName() {
1263        return fCodeSnippetClassName;
1264    }
1265
1266    /**
1267     * @see ICodeSnippetRequestor#isRequestingClassFiles()
1268     */

1269    public boolean isRequestingClassFiles() {
1270        return true;
1271    }
1272
1273    /**
1274     * Returns whether to hit breakpoints in the evaluation thread.
1275     *
1276     * @return whether to hit breakpoints in the evaluation thread
1277     */

1278    protected boolean getHitBreakpoints() {
1279        return fHitBreakpoints;
1280    }
1281
1282    /**
1283     * Sets whether to hit breakpoints in the evaluation thread.
1284     * @param hit whether to hit breakpoints in the evaluation thread
1285     */

1286    private void setHitBreakpoints(boolean hit) {
1287        fHitBreakpoints = hit;
1288    }
1289
1290}
1291
Popular Tags