package bluej.extensions;
import bluej.BlueJEvent;
import bluej.debugger.DebuggerObject;
import bluej.debugger.ExceptionDescription;
import bluej.debugmgr.ExecutionEvent;
import bluej.debugmgr.Invoker;
import bluej.debugmgr.ResultWatcher;
import bluej.debugmgr.objectbench.ObjectWrapper;
import bluej.pkgmgr.PkgMgrFrame;
import bluej.testmgr.record.InvokerRecord;
import bluej.utility.Utility;
import bluej.views.CallableView;
import bluej.views.ConstructorView;
import bluej.views.MethodView;
| Provides a gateway to invoke methods on objects using a specified set of parameters.
|
| @author Damiano Bolla, University of Kent at Canterbury, 2003,2004
| @author Clive Miller, University of Kent at Canterbury, 2002
|
class DirectInvoker
{
private final PkgMgrFrame pkgFrame;
private String resultName;
| For use by the bluej.extensions
|
| @param i_pkgFrame Description of the Parameter
| @param i_callable Description of the Parameter
|
DirectInvoker(PkgMgrFrame i_pkgFrame)
{
pkgFrame = i_pkgFrame;
}
| Call this if you want to call a constructor
|
| <p>The arguments passed in the args array may have any type,
| but the type will determine exactly what is passed to the
| constructor:
|
| <ul>
| <li>String - the String will be passed directly to the constructor
| <li>BObject - the object will be passed directly to the constructor,
| though it must be on the object bench for this to work
| <li>Anything else - toString() is called on the object and the
| result is treated as a Java expression, which is
| evaluated and passed to the constructor.
| </ul>
|
| <p>An attempt is made to ensure that the argument types are suitable
| for the constructor. InvocationArgumentException will be thrown if
| the arguments are clearly unsuitable, however some cases will
| generate an InvocationErrorException instead. In such cases no
| expression arguments will be evaluated.
|
| @param callable The constructor to call
| @param args Arguments to the constructor
| @return The newly created object
| @throws InvocationArgumentException if the argument list is not consistent with the signature
| @throws InvocationErrorException if there is a system error
|
p.public DebuggerObject invokeConstructor(ConstructorView callable, Object[] args)
throws InvocationArgumentException, InvocationErrorException
{
if (!paramsAlmostMatch(args, callable.getParameters())) {
throw new InvocationArgumentException("invokeConstructor: bad arglist");
}
DirectResultWatcher watcher = new DirectResultWatcher();
Invoker invoker = new Invoker(pkgFrame, callable, watcher);
String [] argStrings = convObjToString(args);
invoker.invokeDirect(argStrings);
DebuggerObject result = watcher.getResult();
String resultType = watcher.getResultType();
if (resultType != null) {
ExecutionEvent ee = new ExecutionEvent(pkgFrame.getPackage(), callable.getClassName(), null);
raiseEvent(ee, callable, argStrings, watcher);
}
if (watcher.isFailed()) {
throw new InvocationErrorException("invokeConstructor: Error=" + watcher.getError());
}
if (result == null) {
throw new InvocationErrorException("invokeConstructor: ERROR: result==null");
}
resultName = watcher.getResultName();
return result;
}
| Call a method on an object.
| You need to pass the object where you want it applied.
|
| <p>The arguments passed in the args array may have any type,
| but the type will determine exactly what is passed to the
| method:
|
| <ul>
| <li>String - the String will be passed directly to the method
| <li>BObject - the object will be passed directly to the method,
| though it must be on the object bench for this to work
| <li>Anything else - toString() is called on the object and the
| result is treated as a Java expression, which is
| evaluated and passed to the method.
| </ul>
|
| <p>An attempt is made to ensure that the argument types are suitable
| for the method. InvocationArgumentException will be thrown if
| the arguments are clearly unsuitable, however some cases will
| generate an InvocationErrorException instead. In such cases no
| expression arguments will be evaluated.
|
| @param onThisObjectInstance the method is called on this object
| @param args The arguments for the method
| @return The result object; for a constructor call this is the
| constructed object; for any other invocation this will be
| an object with a 'result' field containing the actual result,
| or the null object (i.e. isNullObject() == true) if the result
| type is void.
| @exception InvocationArgumentException Thrown if the arglist is not consistent with the signature
| @exception InvocationErrorException Thrown if there is a system error
|
p.public DebuggerObject invokeMethod(ObjectWrapper onThisObjectInstance, MethodView callable, Object[] args)
throws InvocationArgumentException, InvocationErrorException
{
if (!paramsAlmostMatch(args, callable.getParameters())) {
throw new InvocationArgumentException("invokeMethod: bad arglist");
}
DirectResultWatcher watcher = new DirectResultWatcher();
Invoker invoker;
if (callable.isStatic()) {
invoker = new Invoker(pkgFrame, callable, watcher);
}
else {
invoker = new Invoker(pkgFrame, (MethodView) callable, onThisObjectInstance.getName(), onThisObjectInstance.getObject(), watcher);
}
String [] argStrings = convObjToString(args);
invoker.invokeDirect(convObjToString(args));
DebuggerObject result = watcher.getResult();
String resultType = watcher.getResultType();
if (resultType != null) {
ExecutionEvent ee = new ExecutionEvent(pkgFrame.getPackage(), callable.getClassName(),
(onThisObjectInstance==null)?null:onThisObjectInstance.getName());
ee.setMethodName(callable.getName());
raiseEvent(ee, callable, argStrings, watcher);
}
if (watcher.isFailed()) {
throw new InvocationErrorException("invokeMethod: Error=" + watcher.getError());
}
resultName = watcher.getResultName();
return result;
}
| Raise an appropriate execution event, after a result has been received.
|
private static void raiseEvent(ExecutionEvent event, CallableView callable, String [] argStrings,
DirectResultWatcher watcher)
{
DebuggerObject result = watcher.getResult();
String resultType = watcher.getResultType();
event.setParameters(callable.getParamTypes(false), argStrings);
event.setResult(resultType);
if (resultType == ExecutionEvent.NORMAL_EXIT) {
event.setResultObject(result);
event.setObjectName(watcher.getResultName());
}
else if (resultType == ExecutionEvent.EXCEPTION_EXIT) {
event.setException(watcher.getException());
}
BlueJEvent.raiseEvent(BlueJEvent.EXECUTION_RESULT, event);
}
| Returns the result object name of an invocation
|
| @return The resultName value
|
String getResultName()
{
return resultName;
}
| Converts an array of Object into an array of String with java
| expressions representing the objects, as per the convOneObj method.
|
| @param i_array Input object values
| @return Objects transformed into an array of strings
|
private String[] convObjToString(Object[] i_array)
{
if (i_array == null) {
return null;
}
if (i_array.length <= 0) {
return new String[0];
}
String[] o_array = new String[i_array.length];
for (int index = 0; index < i_array.length; index++) {
o_array[index] = convOneObj(i_array[index]);
}
return o_array;
}
| Does one conversion of a supplied object to a java expression
| representing that object, according to the following rules:
|
| <ul>
| <li>String - the String will be quoted according to Java quoting
| rules, and enclosed in quotes
| <li>BObject - the name of the BObject on the object bench will be
| returned
| <li>Anything else - toString() is called on the object and the
| result is treated as a Java expression, which is
| returned.
| </ul>
|
| @param i_obj Input object to convert
| @return The resulting string representation
|
private String convOneObj(Object i_obj)
{
if (i_obj == null) {
return null;
}
if (i_obj instanceof String) {
return "\"" + Utility.quoteString(i_obj.toString()) + "\"";
}
if (i_obj instanceof BObject) {
return ((BObject) i_obj).getInstanceName();
}
return i_obj.toString();
}
| Simple utility to decide when two params list do not match.
| The test is done on params length but not on the type.
|
| @param params The params given
| @param paramClass The reference params array
| @return true if they match, false othervise
|
private boolean paramsAlmostMatch(Object[] params, Class<?>[] paramClass)
{
if (params != null && params.length < 1) {
params = null;
}
if (paramClass != null && paramClass.length < 1) {
paramClass = null;
}
if (params == null && paramClass == null) {
return true;
}
if (params == null || paramClass == null) {
return false;
}
if (params.length != paramClass.length) {
return false;
}
return true;
}
| This is used to interface with the core BlueJ
| This new version does return when there is an INTERRUPT
|
class DirectResultWatcher
implements ResultWatcher
{
private boolean resultReady;
private boolean isFailed;
private String resultType;
private DebuggerObject result;
private ExceptionDescription exception;
private String errorMsg;
private String resultName;
| Constructor for the DirectResultWatcher object
|
public DirectResultWatcher()
{
resultReady = false;
isFailed = false;
result = null;
errorMsg = null;
}
| This will try to get the result of an invocation.
| null can be returned if the thread is interrupted !!!
|
| @return The result value
|
public synchronized DebuggerObject getResult()
{
while (!resultReady){
try {
wait();
}
catch (InterruptedException exc) {
isFailed = true;
errorMsg = "getResult: Interrupt: Exception=" + exc.getMessage();
return null;
}
}
return result;
}
| I need a way to reliably detect if there is an error or not.
| Careful... should I look for resultReady too ?
|
| @return The failed value
|
public synchronized boolean isFailed()
{
return isFailed;
}
|
| @see bluej.debugmgr.ResultWatcher#beginExecution()
|
public void beginCompile()
{
}
|
| @see bluej.debugmgr.ResultWatcher#beginExecution()
|
public void beginExecution(InvokerRecord ir)
{
}
| Used to return a result. We know that it is a good one.
|
| @param aResult The actual result object
| @param anObjectName The object name in the object bench
| @param ir Further parameter, see ResultWatcher
|
public synchronized void putResult(DebuggerObject aResult, String anObjectName, InvokerRecord ir)
{
result = aResult;
resultType = ExecutionEvent.NORMAL_EXIT;
resultName = anObjectName;
resultReady = true;
notifyAll();
}
| This is used to return an error.
| @param error The error message
|
public synchronized void putError(String error, InvokerRecord ir)
{
errorMsg = "Invocation: Error=" + error;
isFailed = true;
resultReady = true;
notifyAll();
}
| Treat run-time error the same as compile-time error.
| @param msg The exception message
|
public synchronized void putException(ExceptionDescription exception, InvokerRecord ir)
{
this.exception = exception;
resultType = ExecutionEvent.EXCEPTION_EXIT;
putError(exception.getText(), ir);
}
| Treat termination as an error
|
public void putVMTerminated(InvokerRecord ir)
{
resultType = ExecutionEvent.TERMINATED_EXIT;
putError("Terminated", ir);
}
| Gets the error attribute of the DirectResultWatcher object
|
| @return The error value
|
public String getError()
{
return errorMsg;
}
| Gets the resultName attribute of the DirectResultWatcher object
|
| @return The resultName value
|
public String getResultName()
{
return resultName;
}
| Returns the result type:
| ExecutionEvent.NORMAL_EXIT if execution completed normally;
| ExecutionEvent.EXCEPTION_EXIT if an exception occurred in user code;
| ExecutionEvent.TERMINATED_EXIT if the user VM exited for any reason;
| null if compilation failure occurred.
|
public String getResultType()
{
return resultType;
}
| Get the exception which occurred (if result type == EXCEPTION_EXIT).
|
public ExceptionDescription getException()
{
return exception;
}
}
}
. - DirectInvoker
. invokeConstructor
. invokeMethod
. raiseEvent
. convObjToString
. convOneObj
. paramsAlmostMatch
. - DirectResultWatcher
. DirectResultWatcher
. getResult
. isFailed
. beginCompile
. beginExecution
. putResult
. putError
. putException
. putVMTerminated
. getError
. getResultName
. getResultType
. getException
401 neLoCode
+ 112 LoComm