org.curjent.agent
Interface AgentCall<V>

All Superinterfaces:
Future<V>
All Known Implementing Classes:
AgentResult, MessageCall

public interface AgentCall<V>
extends Future<V>

Monitor and control an agent call. Agents can return an AgentCall instead of a Future for additional agent-specific capabilities. See Futures in org.curjent.agent for background information on future results. An AgentCall is also passed to call listeners; see CallStateListener.

In the following example, parser.parse(file) is an agent call. The call is queued and executed asynchronously in the Parser agent's background thread. The listener uses the call argument to report failure:

 interface Parser {
     void parse(File file);
 }
 
 class ParserTask implements Parser {
     public void parse(File file) {
         // parse the file and do something with the results...
     }
 }
 
 class Example {
     void init() {
         Parser parser = Agent.newInstance(Parser.class, new ParserTask());
         AgentConfig config = Agent.getConfig(parser);
         CallSite site = config.getCallSite("parse", void.class, File.class);
         site.setCallStateListener(CallState.FINISHED, new CallStateListener() {
             public void callStateChanged(AgentCall call, CallState previous) {
                 if (call.getCompletion() != CallCompletion.TASK_FINISHED) {
                     File file = (File)call.getArgument(0);
                     System.out.println("Parsing aborted: file=" + file);
                 }
             }
         });
     }
 
     void example(Parser parser, File file) {
         parser.parse(file);
     }
 }
 

The state of a call and its agent is stable within the context of a CallStateListener callback. This ensures a consistent state of the call and agent without race conditions while performing multiple related but independent operations:

This is not the case outside the context of a CallStateListener callback. The run(Runnable) method is provided to establish a stable state while making multiple queries and updates. In most scenarios you'll query a call's state after completion when the call is in a stable state anyway. The run method is needed only for unusual scenarios.

Some methods are intended for use primarily, or exclusively in the case of the await methods, outside the context of a listener callback:

Outside the context of the listener callback, the state of the call and its agent can change at any time. This creates race conditions for using setResult(Object), setException(Throwable), and finish(). The finish(boolean, boolean, Object, Throwable) method is provided to safely finish a call and set the call's result and exception values atomically in a single operation without race conditions.


Method Summary
 void await()
          Waits indefinitely for this call to finish.
 void await(CallState state)
          Waits indefinitely for this call to reach or pass the given state.
 boolean await(CallState state, long timeout, TimeUnit unit)
          Waits for this call to reach or pass the given state.
 boolean finish()
          Transitions the call to the CallState.FINISHED state.
 boolean finish(boolean interrupt, boolean abandon, V result, Throwable exception)
          Transitions the call to the CallState.FINISHED state.
 boolean finish(Throwable exception)
          Sets the call's result and exception and transitions the call to the CallState.FINISHED state.
 boolean finish(V result)
          Sets the call's result and exception and transitions the call to the CallState.FINISHED state.
 Object getArgument(int index)
          Returns the value for a call's argument.
 int getArgumentCount()
          Returns the number of arguments for the call.
 CallSite getCallSite()
          Returns this agent's call site for this call.
 CallStateListener<?> getCallStateListener()
          Returns the default call state listener for this call.
 CallStateListener<?> getCallStateListener(CallState state)
          Returns the listener for the given call state.
 CallCompletion getCompletion()
          Returns the reason the call finished.
 Object getData()
          Returns the data associated with this call.
 Throwable getException()
          Returns the execution exception if any.
 long getExpirationTimeoutNanos()
          Returns the number of NANOSECONDS until this call expires.
 V getResult()
          Returns the execution result value if any.
 CallState getState()
          Returns the current state of this call.
 boolean isReentry()
          Agent is executing a reentrant call.
 void run(Runnable runnable)
          Runs the runnable object within a stable call and agent context.
 void setArgument(int index, Object value)
          Sets an argument value.
 boolean setCallStateListener(CallState state, CallStateListener<?> listener)
          Sets a listener for the given call state.
 CallState setCallStateListener(CallStateListener<?> listener)
          Sets a default call state listener for this call.
 void setData(Object data)
          Sets the data associated with this call.
 void setException(Throwable exception)
          Sets the execution exception.
 boolean setExpirationTimeout(long value, TimeUnit unit)
          Sets the expiration timeout for this call.
 void setResult(V value)
          Sets the result value.
 
Methods inherited from interface java.util.concurrent.Future
cancel, get, get, isCancelled, isDone
 

Method Detail

getState

CallState getState()
Returns the current state of this call.

See Also:
CallState

getCompletion

CallCompletion getCompletion()
Returns the reason the call finished.

See Also:
CallCompletion

isReentry

boolean isReentry()
Agent is executing a reentrant call. Returns true for a Reentrant call that is executing within the context of another agent call. This is only detectable within a CallStateListener for a reentrant call in the CallState.EXECUTING state. The returned value is false in all other cases.


getArgumentCount

int getArgumentCount()
Returns the number of arguments for the call. This is equal to the number of parameters defined for the interface method. Returns 0 if the method has an empty parameter list.


getArgument

Object getArgument(int index)
Returns the value for a call's argument. Primitive values are returned boxed (e.g., an Integer is returned for an int parameter).

Parameters:
index - Index of the argument. The first value is at index 0 and the last at index getArgumentCount() - 1.
Throws:
IndexOutOfBoundsException - index is less than 0 or greater than or equal to getArgumentCount()

setArgument

void setArgument(int index,
                 Object value)
Sets an argument value. The updated value is passed to the agent's task method when the call is executed. If the call has already executed, the value is saved but has no affect on the execution.

Use boxed values for primitives, such as new Integer(value) for arguments of type int.

Setting a value to null is always valid, even for primitives. This sets the argument to the default value appropriate for the argument's type, such as null for objects and 0 for integer primitives.

Throws:
ClassCastException - value could not be cast to the argument's type.
IndexOutOfBoundsException - index is less than 0 or greater than or equal to getArgumentCount()
See Also:
getArgument(int)

getResult

V getResult()
Returns the execution result value if any. Primitive values are returned boxed (e.g., an Integer is returned for an int parameter).

Whereas Future.get() waits for the call to finish executing, this method returns immediately.

Returns the default value for the result type if the call has not executed, or null if the call has a void return type.


setResult

void setResult(V value)
Sets the result value. If the call has not yet finished executing, this value is overwritten with the task method's result when it does finish.

Use boxed values for primitives, such as new Integer(value) for a result type of int.

Setting the result to null is always valid, even for primitives and methods with void return types. This sets the result to the default value appropriate for the argument's type, such as null for objects and 0 for integer primitives. For void return types, a null value is ignored.

Throws:
ClassCastException - value could not be cast to the method's return type.
IllegalArgumentException - Attempted to set the result value of a method with a void return type to something other than null.
See Also:
getResult()

getException

Throwable getException()
Returns the execution exception if any.

See Also:
setException(Throwable)

setException

void setException(Throwable exception)
Sets the execution exception. Any exception is permitted and may be null. If set prior to call completion, the new value is overwritten by the exception result of the finished call, either the exception thrown by the task's method or null if an exception was not thrown.

See Also:
getException()

finish

boolean finish()
Transitions the call to the CallState.FINISHED state.

If the call is EXECUTING, it is abandoned, and the call's state is transitioned to FINISHED. The task's method continues executing normally, but the agent no longer tracks it. However, the executing task is not released until the method returns.

If successful (i.e., the call is not already in the FINISHED state), the call completion is set to CallCompletion.LISTENER_FINISHED (whether this method is called in a CallStateListener context or in any other context).

Listeners for FINISHED call states are notified of the state change within the context of this method before it returns.

This method does not change the call's result or exception. Typically setResult(Object) or setException(Throwable) are called before calling this method. This ensures a consistent state when listeners for FINISHED call states are notified.

This method is normally called within the context of CallStateListener.callStateChanged(AgentCall, CallState). The call is not interruptable in this context since even if the call's state has transitioned to EXECUTING, no thread has been assigned to execute the task's method yet. You will typically use finish(boolean, boolean, Object, Throwable) in other contexts.

The primary difference between finish() and cancel(false) is that callers waiting on Future.get() or Future.get(long, TimeUnit) will not get a CancellationException if the call is finished but will get a CancellationException if the call is canceled. Callers of a finished call are returned the value set with setResult(Object) instead.

Returns:
false if the call was already FINISHED; true in all other cases.
See Also:
setResult(Object), setException(Throwable)

finish

boolean finish(V result)
Sets the call's result and exception and transitions the call to the CallState.FINISHED state. This is functionally equivalent to the following ordered sequence of calls:
  call.setResult(result);
  call.setException(null);
  call.finish();
 
The primary difference is that this method sets the result, sets the exception, and finishes the call as a single atomic operation. It is therefore also functionally equivalent to the following:
  call.finish(false, true, result, null);
 

Parameters:
result - The value of the call's result if successfully finished. May cause this method to throw an exception if the value is invalid. Sets the result value to the system default value (0, false, \u0000, etc.) for primitive types if result is null. Ignored for void result types with a result value of null.
Returns:
true if successfully transitioned to the FINISHED state.
Throws:
ClassCastException - result could not be cast to the method's return type.
IllegalArgumentException - Attempted to set the result value of a method with a void return type to something other than null.
See Also:
setResult(Object), setException(Throwable), finish(), finish(boolean, boolean, Object, Throwable)

finish

boolean finish(Throwable exception)
Sets the call's result and exception and transitions the call to the CallState.FINISHED state. This is functionally equivalent to the following ordered sequence of calls:
  call.setResult(null);
  call.setException(exception);
  call.finish();
 
The primary difference is that this method sets the result, sets the exception, and finishes the call as a single atomic operation. It is therefore also functionally equivalent to the following:
  call.finish(false, true, result, null);
 

Parameters:
exception - The call's exception value if successfully finished. This value takes precedence over the result value; i.e., if exception is non-null, it is thrown regardless of the result value.
Returns:
true if successfully transitioned to the FINISHED state.
See Also:
setResult(Object), setException(Throwable), finish(), finish(boolean, boolean, Object, Throwable)

finish

boolean finish(boolean interrupt,
               boolean abandon,
               V result,
               Throwable exception)
Transitions the call to the CallState.FINISHED state.

Returns true if the call was transitioned to the CallState.FINISHED state. Returns false if the call was already in the FINISHED state or if finishing was otherwise unsuccessful.

If the call is EXECUTING and abandon is true, transitions the call's state to FINISHED. The task's method continues executing normally, but the agent no longer tracks it. However, the executing task is not released until the method returns.

If the call is transitioned to the FINISHED state, the call completion is set to CallCompletion.LISTENER_FINISHED (whether this method is called in a CallStateListener context or in any other context).

Listeners for FINISHED call states are notified of the state change within the context of this method before it returns.

Typically setResult(Object) or setException(Throwable) are called before calling this method. This ensures a consistent state when listeners for FINISHED call states are notified.

finish() is normally called within the context of CallStateListener.callStateChanged(AgentCall, CallState). You will typically use this method in other contexts.

The primary difference between this method and cancel(boolean) is that callers waiting on Future.get() or Future.get(long, TimeUnit) will not get a CancellationException if the call is finished but will get a CancellationException if the call is canceled. Callers of a finished call are returned the given result value instead.

Parameters:
interrupt - If true and the call is in the EXECUTING state with an assigned thread, the executing thread is interrupted. Ignored if false.
abandon - If true and the call is in the EXECUTING state, finishes the call and abandons the running task, leaving it running orphaned in the background. Ignored if false.
result - The value of the call's result if successfully finished. May cause this method to throw an exception if the value is invalid. Sets the result value to the system default value (0, false, \u0000, etc.) for primitive types if result is null. Ignored for void result types with a result value of null.
exception - The call's exception value if successfully finished. This value takes precedence over the result value; i.e., if exception is non-null, it is thrown regardless of the result value.
Returns:
true if successfully transitioned to the FINISHED state.
Throws:
ClassCastException - result could not be cast to the method's return type.
IllegalArgumentException - Attempted to set the result value of a method with a void return type to something other than null.

await

void await()
           throws InterruptedException
Waits indefinitely for this call to finish. Equivalent to calling await(CallState.FINISHED, Long.MAX_VALUE, null).

Throws:
IllegalStateException - Cannot await on an agent call within the context of a call listener callback.
InterruptedException - The caller's thread was interrupted.
DeadlockException - The caller has deadlocked with other agents.

await

void await(CallState state)
           throws InterruptedException
Waits indefinitely for this call to reach or pass the given state. Equivalent to calling await(state, Long.MAX_VALUE, null).

Parameters:
state - Call state to reach or pass.
Throws:
NullPointerException - state is null.
IllegalStateException - Cannot await on an agent call within the context of a call listener callback.
InterruptedException - The caller's thread was interrupted.
DeadlockException - The caller has deadlocked with other agents.

await

boolean await(CallState state,
              long timeout,
              TimeUnit unit)
              throws InterruptedException
Waits for this call to reach or pass the given state. For example, if state is EXECUTING, this method waits until the call's state is either EXECUTING or FINISHED.

Whereas await(CallState) waits indefinitely, this method can timeout. It returns true if state was reached or passed, or false if the timeout period expired. If the timeout value is 0 or negative, it times out immediately without waiting. It never times out if the timeout value is Long.MAX_VALUE.

Parameters:
state - Call state to reach or pass. For example, if state is EXECUTING, this method waits until the call's state is either EXECUTING or FINISHED.
timeout - The timeout period. 0 or negative to timeout immediately. Long.MAX_VALUE to never timeout.
unit - The timeout units. May be null if timeout is 0 or Long.MAX_VALUE.
Returns:
true if the call state was reached or passed. false if the call state was not reached when the timeout period expired.
Throws:
NullPointerException - state or unit is required but null.
IllegalStateException - Cannot await on an agent call within the context of a call listener callback.
InterruptedException - The caller's thread was interrupted.
DeadlockException - The caller has deadlocked with other agents.

setExpirationTimeout

boolean setExpirationTimeout(long value,
                             TimeUnit unit)
Sets the expiration timeout for this call.

Throws:
IllegalArgumentException - value is less than 1.
NullPointerException - unit is null and value is not Long.MAX_VALUE
See Also:
Expiration

getExpirationTimeoutNanos

long getExpirationTimeoutNanos()
Returns the number of NANOSECONDS until this call expires. Returns Long.MAX_VALUE if the call is not configured to expire. Returns 0 if the call has already reached its expiration time (the call may or may not have finished with a CALL_EXPIRED completion).


getCallStateListener

CallStateListener<?> getCallStateListener()
Returns the default call state listener for this call. Returns null if none has been assigned.

See Also:
setCallStateListener(CallStateListener)

setCallStateListener

CallState setCallStateListener(CallStateListener<?> listener)
Sets a default call state listener for this call. Clears the default listener if the given listener is null. If a listener for a specific state is not set, the default listener is called instead.

Returns the current call state at the time the listener was set. The listener is called for future state changes. It is not called for the current or prior states.

Call listeners are independent of agent listeners. If call and agent listeners are both set, both are called, first the agent's listener and then the call's listener. If the agent's listener finishes the call, the call's listener will only see the final FINISHED state.

See Also:
setCallStateListener(CallState, CallStateListener)

getCallStateListener

CallStateListener<?> getCallStateListener(CallState state)
Returns the listener for the given call state. Returns null if none has been assigned.

Throws:
NullPointerException - state is null
See Also:
setCallStateListener(CallState, CallStateListener)

setCallStateListener

boolean setCallStateListener(CallState state,
                             CallStateListener<?> listener)
Sets a listener for the given call state. Clears the listener for the given state if the given listener is null. If a listener for a specific state is not set, the default listener is called instead.

Returns true if the call has already reached or passed the given state. The listener is not automatically called if the state has already been reached or passed. You can use the following idiom if the listener's functionality should execute anyway:

  CallStateListener listener = new CallStateListener() {
      public void callStateChanged(AgentCall call, CallState previous) {
          doSomethingCritical();
      }
  };
  if (call.setCallStateListener(CallState.FINISHED, listener)) {
      doSomethingCritical();
  }
 

Call listeners are independent of agent listeners. If call and agent listeners are both set, both are called, first the agent's listener and then the call's listener. If the agent's listener finishes the call, the call's listener will only see the final FINISHED state.

Throws:
NullPointerException - state is null
See Also:
setCallStateListener(CallStateListener)

run

void run(Runnable runnable)
Runs the runnable object within a stable call and agent context. The state of the call and agent does not change while the runnable object is running unless changed by the runnable object. For example, this allows you to change all arguments atomically. Note that this method is safe to use but not needed within the context of CallStateListener.callStateChanged(AgentCall, CallState) since the call and agent are already in a stable context.

Parameters:
runnable - Object to run.
Throws:
NullPointerException - runnable is null.

getData

Object getData()
Returns the data associated with this call. Initially null.


setData

void setData(Object data)
Sets the data associated with this call. Any value is valid.


getCallSite

CallSite getCallSite()
Returns this agent's call site for this call.



Copyright 2009-2011 Tom Landon
Apache License 2.0