org.curjent.impl.agent
Class Message

java.lang.Object
  extended by org.curjent.impl.agent.Message
All Implemented Interfaces:
Awaiter
Direct Known Subclasses:
CopyMessage_Copy, CopyMessage_Count, CopyMessage_Exists, CopyMessage_File, CopyMessage_Flush, CopyMessage_Length, CopyMessage_Read, CopyMessage_Status, SyntheticMessage

public abstract class Message
extends Object
implements Awaiter

Base class for generated message classes. This base class manages the state of a call.

Generated subclasses dispatch calls to the task. Because they're generated, they are able to call their corresponding task methods without using reflection or boxed parameters.

Sometimes it is desirable to atomically apply an operation to both the message and the agent. One example is canceling and/or finishing execution of a message where the agent guarantees a single visible state change. To help protect against deadlock in these cases, the protocol is to always lock the agent before synchronizing the message.


Field Summary
private  Object[] cachedArguments
          Cached Object argument values.
protected  Object cachedResult
          Cached Object result.
private  MessageCall call
          Implements AgentCall and delegates most functionality to this message.
private  CallCompletion completion
          Reason the message finished.
(package private)  Controller controller
          Agent's controller for this message.
private  boolean deadcheck
          Set to true if Awaiters.await(Awaiter, boolean, CallState, long) should check for deadlock.
private  Throwable exception
          Set to an exception thrown by the task's method or explicitly via AgentCall.setException(Throwable).
(package private)  CallInfo info
          Information on the interface and task methods for this message.
private  CallStateListener<?>[] listeners
          Reference to the effective agent listeners for each of the possible message states, starting from the ordinal value for STARTING to the ordinal for FINISHED.
private  boolean listening
          Set and cleared before and after a listener is called.
(package private)  Mark mark
          Marker state for this message.
(package private)  MarkerType markerType
          Type of Marker.
(package private)  Message next
          The next message in the queue.
(package private) static Throwable NOEXCEPTION
          Used to finish the message without changing the exception.
(package private) static Object NORESULT
          Used to finish the message without changing the result.
(package private)  Message prev
          The previous message in the queue.
(package private)  Queue queue
          The owning queue of this message or null if not owned.
private  boolean reentry
          Set to true if this message is reentering the agent.
(package private)  boolean started
          Initially false and set to true by the controller when it pulls the message from the queue for dispatching.
protected  CallState state
          Current state of the message.
(package private)  boolean synthetic
          Non-standard synthesized call.
private  Thread thread
          The background thread executing the call to the task's method.
(package private)  ExpirationsTimer timer
          Expiration state for calls with an expiration timeout.
 
Constructor Summary
protected Message(CallInfo info)
          Saves the message's controller and call site information.
 
Method Summary
 void await()
          Used by the agent's proxy to implement a synchronous call.
 boolean await(CallState state, long timeout, TimeUnit unit)
          Implementation for AgentCall.await(CallState, long, TimeUnit).
 void await(long nanos)
          Waits on this message's monitor.
(package private)  void awaitPending(long nanos)
          Used by the controller to wait for the agent to accept this message.
(package private)  boolean cancel(boolean interruptably)
          Attempts to cancel the call's execution.
 void clearDeadcheckRequest()
          Clears any outstanding deadcheck request.
 void deadcheck()
          Notification that Awaiters.await(Awaiter, boolean, CallState, long) should check for deadlock.
protected abstract  void dispatch(Object task)
          Delegates execution of the call to the subclass of this message.
(package private)  boolean expire()
          Expires a call.
(package private)  boolean finish(boolean interrupt, boolean abandon, Object result, Throwable exception)
          Implementation for AgentCall.finish(boolean, boolean, Object, Throwable).
(package private)  Object get(long timeout, TimeUnit unit)
          Waits for the call to finish and returns the result.
(package private)  Object getArgument(int index)
          Returns the value of an argument that will be passed to the task's method.
(package private)  int getArgumentCount()
          Returns the number of arguments this call's method takes.
protected  Object getArgumentValue(int index)
          Method implemented by generated message subtypes for boxing and unboxing arguments.
 Thread[] getBlockingThreads()
          Returns this message's thread if any; otherwise, delegates to Controller.getBlockingThreads().
 MessageCall getCall()
          Returns the internal implementation for AgentCall.
(package private)  CallCompletion getCompletion()
          Returns the reason the call finished.
 Controller getController()
          Returns the agent's controller for this message.
(package private)  Throwable getException()
          Returns the exception thrown by the task's method if any.
(package private)  Object getResult()
          Boxes, caches, and returns the message result.
protected  Object getResultValue()
          Converts the task's result to an object.
(package private)  CallState getState()
          Returns the current state.
 boolean isDeadcheckRequested()
          Returns true if a deadcheck request is outstanding.
 boolean isExecuting()
          Returns true if the state is EXECUTING.
(package private)  boolean isFinished()
          Returns true if the message's state is FINISHED.
(package private)  boolean isReentry()
          Returns true if call is dispatched reentrantly.
 boolean isSatisfied(CallState state)
          Returns true if the current state is the same or later than the given state.
private  Object[] loadArguments(int index)
          Validates the argument index, and initializes and returns the cached arguments.
 void lock()
          Empty placeholder that does nothing.
private  boolean notify(CallStateListener<?>[] listeners, int ordinal, CallState previous)
          Notifies the appropriate listener if any.
(package private)  void setArgument(int index, Object value)
          Sets the value of an argument to pass to the task's method.
protected  void setArgumentValue(int index, Object value)
          Method implemented by generated message subtypes for boxing and unboxing arguments.
(package private)  void setException(Throwable exception)
          Sets or clears the exception thrown by the task's method.
(package private)  void setReentry()
          The call is being dispatched reentrantly.
(package private)  void setResult(Object value)
          Saves and caches the boxed result.
protected  void setResultValue(Object value)
          Implemented by generated message subtypes to unbox and save a result value.
(package private)  boolean setState(CallState state, CallCompletion completion, Object result, Throwable exception)
          Changes the state of the message and notifies the listener.
(package private)  boolean startable(boolean head)
          Returns true if this message is ready to be executed.
 String toString()
          Returns a description of the interface's method that corresponds to this message.
 void unlock()
          Empty placeholder that does nothing.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

controller

final Controller controller
Agent's controller for this message. Used for two-way communication, such as cancellation notification.


info

final CallInfo info
Information on the interface and task methods for this message. This is state information for the associated agent, cached here for lookup efficiency.

See Also:
CallSite

markerType

final MarkerType markerType
Type of Marker. null for non-marker calls.


synthetic

final boolean synthetic
Non-standard synthesized call.


queue

Queue queue
The owning queue of this message or null if not owned. A message may be dequeued but still owned by a queue. This special state is represented by null next and prev fields but a non-null queue field.


next

Message next
The next message in the queue. The first message in the queue is the first message that was queued and the next message to be processed. Queues are doubly linked and circular, so the next message after the last message is the first message, and the previous message of the first message is the last message in the queue.

See Also:
queue

prev

Message prev
The previous message in the queue.

See Also:
next

mark

Mark mark
Marker state for this message.

See Also:
Controller

started

boolean started
Initially false and set to true by the controller when it pulls the message from the queue for dispatching. This flag is used to close a timing gap with a canceled message's notification and the controller processing a message.


timer

ExpirationsTimer timer
Expiration state for calls with an expiration timeout.

See Also:
Expirations

state

protected CallState state
Current state of the message.


reentry

private boolean reentry
Set to true if this message is reentering the agent.

See Also:
Reentrant, AgentCall.isReentry(), dispatch(Object)

thread

private Thread thread
The background thread executing the call to the task's method. This value is null in any state except EXECUTING.


cachedArguments

private Object[] cachedArguments
Cached Object argument values. Arguments are saved in the generated message subtype using the method's unboxed argument types. The conversion from primitive values to the boxed object equivalents is cached here in order to avoid creating an excessive number of boxed objects.

See Also:
getArgument(int), setArgument(int, Object), loadArguments(int)

cachedResult

protected Object cachedResult
Cached Object result. Initially set to this to indicate the result has not yet been converted to an Object and cached. Calls to getResult() and setResult(Object) convert and cache the result value as an Object. The generated message implementations for dispatch(Object) save the raw result in its type-appropriate generated field and reset this value back to this.

Caching helps avoid creating an excessive number of boxed values for primitive result values.

See Also:
getResult(), setResult(Object)

exception

private Throwable exception
Set to an exception thrown by the task's method or explicitly via AgentCall.setException(Throwable).

See Also:
setState(CallState, CallCompletion, Object, Throwable), setException(Throwable)

completion

private CallCompletion completion
Reason the message finished.

See Also:
setState(CallState, CallCompletion, Object, Throwable)

listeners

private final CallStateListener<?>[] listeners
Reference to the effective agent listeners for each of the possible message states, starting from the ordinal value for STARTING to the ordinal for FINISHED. The elements of this array changes, but the reference to the array does not and remains valid throughout the lifetime of the agent.


listening

private boolean listening
Set and cleared before and after a listener is called. Some calls, such as AgentCall.await(CallState), are illegal for a listener to call in the context of CallStateListener.callStateChanged(AgentCall, CallState) and would otherwise wait forever. This flag is used to detect the most obvious cases and throw an IllegalStateException.


call

private MessageCall call
Implements AgentCall and delegates most functionality to this message. Returned to clients via getCall() instead of a reference to this class in order to avoid synchronization conflicts (i.e., it is safe for clients to synchronize on the returned call value but not on this).


deadcheck

private boolean deadcheck
Set to true if Awaiters.await(Awaiter, boolean, CallState, long) should check for deadlock.

See Also:
deadcheck()

NORESULT

static final Object NORESULT
Used to finish the message without changing the result.

See Also:
setState(CallState, CallCompletion, Object, Throwable)

NOEXCEPTION

static final Throwable NOEXCEPTION
Used to finish the message without changing the exception.

See Also:
setState(CallState, CallCompletion, Object, Throwable)
Constructor Detail

Message

protected Message(CallInfo info)
Saves the message's controller and call site information.

Method Detail

startable

final boolean startable(boolean head)
Returns true if this message is ready to be executed. The head argument is true if this is the first message in the queue (i.e., it is at the head of the queue and next in line to execute).

Non-marker messages are always startable. Whether or not a marker message is startable depends on the following:

See Also:
Controller

dispatch

protected abstract void dispatch(Object task)
                          throws Throwable
Delegates execution of the call to the subclass of this message. The agent's proxy creates the message and saves the call's parameters. Later, the Controller calls the message's dispatch method to execute the call. The message calls the task's method with the previously saved parameters and saves the result. The message saves parameters and results in its fields.

Throws:
Throwable - Any exception thrown by the task's method.
See Also:
MessageFactory

getState

final CallState getState()
Returns the current state.

See Also:
setState(CallState, CallCompletion, Object, Throwable)

setState

final boolean setState(CallState state,
                       CallCompletion completion,
                       Object result,
                       Throwable exception)
Changes the state of the message and notifies the listener.

This is the central location for updating the message's state. This is a synchronized method, and it is assumed the controller is locked.

Waiters are notified as appropriate, including waiters on this message and waiters on the agent.

Calls to the controller or a listener may cause reentry and additional state changes to this message, other messages, and the agent.

Parameters:
state - Updated state. If successful, this method returns true and the message will have the given state on return. If unsuccessful, the state is unchanged or was transitioned to FINISHED by a listener. The state is unchanged either because of an exception, such as from calling setResult(Object), or because the state was already in the given state or was in a later state (i.e., you can change the state from ACCEPTED to EXECUTING but not vice versa).
completion - Reason for transitioning the state to FINISHED. Ignored for other states. Must not be null except for non-null exception values. Will assign a completion value if null based on the type of exception.
result - Message's return value for transitioning the state to FINISHED. Ignored for other states or if the given value is NORESULT. The generated message subtype may throw an exception for invalid non-null values, such as if a listener attempts to finish with a result of the wrong type. null is always an exceptable value and is replaced with the default field value appropriate for the result type, such as null for objects, 0 for int fields, false for boolean fields, etc.
exception - Message's exception value for transitioning the state to FINISHED. May be null. Ignored for other states or if the given value is NOEXCEPTION.
Returns:
true if the state was changed to the given value. false if the message was already in the given state or a later state. false if the state was successfully changed (to something other than FINISHED) but a listener finished the call.
Throws:
NullPointerException - state is null.

notify

private boolean notify(CallStateListener<?>[] listeners,
                       int ordinal,
                       CallState previous)
Notifies the appropriate listener if any. Returns true if the listener finished the call.


getCompletion

final CallCompletion getCompletion()
Returns the reason the call finished. Returns null if the call has not yet finished. The returned value is always null if the state is not yet FINISHED. It is always non-null when the state is FINISHED.


isReentry

final boolean isReentry()
Returns true if call is dispatched reentrantly.

See Also:
reentry

setReentry

final void setReentry()
The call is being dispatched reentrantly.

See Also:
reentry

getArgumentCount

final int getArgumentCount()
Returns the number of arguments this call's method takes.


getArgument

final Object getArgument(int index)
Returns the value of an argument that will be passed to the task's method.


setArgument

final void setArgument(int index,
                       Object value)
Sets the value of an argument to pass to the task's method.


loadArguments

private Object[] loadArguments(int index)
Validates the argument index, and initializes and returns the cached arguments.


getArgumentValue

protected Object getArgumentValue(int index)
Method implemented by generated message subtypes for boxing and unboxing arguments. This default implementation throws an assertion error.


setArgumentValue

protected void setArgumentValue(int index,
                                Object value)
Method implemented by generated message subtypes for boxing and unboxing arguments. This default implementation throws an assertion error.


getResult

final Object getResult()
Boxes, caches, and returns the message result.


setResult

final void setResult(Object value)
Saves and caches the boxed result.


getResultValue

protected Object getResultValue()
Converts the task's result to an object. The subclass of this message returns a boxed value for a primitive result (e.g., Boolean.valueOf(result) for a boolean result). Non-primitive objects, including arrays, are returned unchanged. null is returned for void return types.


setResultValue

protected void setResultValue(Object value)
Implemented by generated message subtypes to unbox and save a result value. This default implementation for void return types does nothing. Subtype implementations throw an exception if value is the wrong type.


getException

final Throwable getException()
Returns the exception thrown by the task's method if any.


setException

final void setException(Throwable exception)
Sets or clears the exception thrown by the task's method.


getCall

public final MessageCall getCall()
Returns the internal implementation for AgentCall.


isFinished

final boolean isFinished()
Returns true if the message's state is FINISHED. Convenience method equivalent to getState() == FINISHED.


await

public final boolean await(CallState state,
                           long timeout,
                           TimeUnit unit)
                    throws InterruptedException
Implementation for AgentCall.await(CallState, long, TimeUnit).

Throws:
NullPointerException - state is null or unit is required but null
IllegalStateException - Cannot await on an agent call within the context of a call listener callback.
InterruptedException

finish

final boolean finish(boolean interrupt,
                     boolean abandon,
                     Object result,
                     Throwable exception)
Implementation for AgentCall.finish(boolean, boolean, Object, Throwable).


expire

final boolean expire()
Expires a call.


getController

public final Controller getController()
Returns the agent's controller for this message.

Specified by:
getController in interface Awaiter

lock

public final void lock()
Empty placeholder that does nothing.

Specified by:
lock in interface Awaiter

unlock

public final void unlock()
Empty placeholder that does nothing.

Specified by:
unlock in interface Awaiter

isExecuting

public final boolean isExecuting()
Returns true if the state is EXECUTING.

Specified by:
isExecuting in interface Awaiter

isSatisfied

public final boolean isSatisfied(CallState state)
Returns true if the current state is the same or later than the given state.

Specified by:
isSatisfied in interface Awaiter

await

public final void await(long nanos)
                 throws InterruptedException
Waits on this message's monitor.

Specified by:
await in interface Awaiter
Throws:
InterruptedException
See Also:
TimeUnit.timedWait(Object, long)

deadcheck

public final void deadcheck()
Notification that Awaiters.await(Awaiter, boolean, CallState, long) should check for deadlock.

Specified by:
deadcheck in interface Awaiter

isDeadcheckRequested

public final boolean isDeadcheckRequested()
Returns true if a deadcheck request is outstanding.

Specified by:
isDeadcheckRequested in interface Awaiter

clearDeadcheckRequest

public final void clearDeadcheckRequest()
Clears any outstanding deadcheck request.

Specified by:
clearDeadcheckRequest in interface Awaiter

getBlockingThreads

public final Thread[] getBlockingThreads()
Returns this message's thread if any; otherwise, delegates to Controller.getBlockingThreads().

Specified by:
getBlockingThreads in interface Awaiter

await

public final void await()
                 throws Throwable
Used by the agent's proxy to implement a synchronous call.

This method emulates a direct method call. It continues waiting until the task finishes executing the call (i.e., until the message state is FINISHED). If interrupted, the task's thread is interrupted (via thread.interrupt()), but otherwise we continue to wait.

While the task is executing the call (i.e., while the message state is EXECUTING), exceptions, such as an InterruptedException, are not thrown, and the unhandled exception handler is not notified. In effect, this method handles the exception, including checking for interrupts, but otherwise waits for the task to finish.

If an exception is thrown before the message enters the EXECUTING state (i.e., it is still queued waiting for a task to executed it), we finish the call and throw the exception. This is analogous to a direct method call resulting in an Error due to a linkage or class versioning problem (e.g., a NoSuchMethodError).

Once the message enters the EXECUTING state and the task's method is called, this method will not return or throw until the task's method returns or throws and the message enters the FINISHED state.

Throws:
InterruptedException - Waiting thread was interrupted.
Throwable - Exception thrown by the task's method.

awaitPending

final void awaitPending(long nanos)
                 throws Throwable
Used by the controller to wait for the agent to accept this message. Waits until the controller transitions the message to any other state except PENDING. If the wait timeout period expires or an exception is thrown, throws a new CapacityExceededException or the caught exception.

Throws:
CapacityExceededException - Timed out waiting for capacity.
InterruptedException - Waiting thread was interrupted.
Throwable - Unexpected exception while waiting.

get

final Object get(long timeout,
                 TimeUnit unit)
          throws InterruptedException,
                 ExecutionException,
                 TimeoutException
Waits for the call to finish and returns the result. Returns null for void return types.

Throws:
NullPointerException - unit is null.
InterruptedException - Waiting thread was interrupted.
TimeoutException - Waited too long.
ExecutionException - Task's method threw an exception.
CancellationException - Call was cancelled.

cancel

final boolean cancel(boolean interruptably)
Attempts to cancel the call's execution. Returns true if successful. Succeeds and sets the state to FINISHED if the current state is not already FINISHED. Interrupts the task's thread if currently EXECUTING and requested by the caller. Does nothing and returns false if the state is already FINISHED.

In order to cancel the message atomically (from the caller's perspective), this method delegates cancellation to the controller.


toString

public String toString()
Returns a description of the interface's method that corresponds to this message.

Overrides:
toString in class Object


Copyright 2009-2011 Tom Landon
Apache License 2.0