|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
java.lang.Objectorg.curjent.impl.agent.Message
public abstract class Message
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 |
---|
final Controller controller
final CallInfo info
CallSite
final MarkerType markerType
Marker
. null
for non-marker calls.
final boolean synthetic
Queue queue
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.
Message next
queue
Message prev
next
Mark mark
Controller
boolean started
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.
ExpirationsTimer timer
Expirations
protected CallState state
private boolean reentry
true
if this message is reentering the agent.
Reentrant
,
AgentCall.isReentry()
,
dispatch(Object)
private Thread thread
null
in any state except EXECUTING
.
private Object[] cachedArguments
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.
getArgument(int)
,
setArgument(int, Object)
,
loadArguments(int)
protected Object cachedResult
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.
getResult()
,
setResult(Object)
private Throwable exception
AgentCall.setException(Throwable)
.
setState(CallState, CallCompletion, Object, Throwable)
,
setException(Throwable)
private CallCompletion completion
setState(CallState, CallCompletion, Object, Throwable)
private final CallStateListener<?>[] listeners
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.
private boolean listening
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
.
private MessageCall call
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
).
private boolean deadcheck
true
if
Awaiters.await(Awaiter, boolean, CallState, long)
should check
for deadlock.
deadcheck()
static final Object NORESULT
setState(CallState, CallCompletion, Object, Throwable)
static final Throwable NOEXCEPTION
setState(CallState, CallCompletion, Object, Throwable)
Constructor Detail |
---|
protected Message(CallInfo info)
Method Detail |
---|
final boolean startable(boolean head)
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:
dispatching
flag is set to
true
to ensure the message runs only once. In contrast,
non-markers are removed from the queue before they start executing.
Controller
protected abstract void dispatch(Object task) throws Throwable
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.
Throwable
- Any exception thrown by the task's method.MessageFactory
final CallState getState()
setState(CallState, CallCompletion, Object, Throwable)
final boolean setState(CallState state, CallCompletion completion, Object result, Throwable exception)
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.
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
.
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.
NullPointerException
- state
is null
.private boolean notify(CallStateListener<?>[] listeners, int ordinal, CallState previous)
true
if
the listener finished the call.
final CallCompletion getCompletion()
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
.
final boolean isReentry()
reentry
final void setReentry()
reentry
final int getArgumentCount()
final Object getArgument(int index)
final void setArgument(int index, Object value)
private Object[] loadArguments(int index)
protected Object getArgumentValue(int index)
protected void setArgumentValue(int index, Object value)
final Object getResult()
final void setResult(Object value)
protected Object getResultValue()
Boolean.valueOf(result)
for a boolean
result).
Non-primitive objects, including arrays, are returned unchanged.
null
is returned for void
return types.
protected void setResultValue(Object value)
void
return types
does nothing. Subtype implementations throw an exception if
value
is the wrong type.
final Throwable getException()
final void setException(Throwable exception)
public final MessageCall getCall()
AgentCall
.
final boolean isFinished()
true
if the message's state is FINISHED
.
Convenience method equivalent to getState() == FINISHED
.
public final boolean await(CallState state, long timeout, TimeUnit unit) throws InterruptedException
AgentCall.await(CallState, long, TimeUnit)
.
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
final boolean finish(boolean interrupt, boolean abandon, Object result, Throwable exception)
AgentCall.finish(boolean, boolean, Object, Throwable)
.
final boolean expire()
public final Controller getController()
getController
in interface Awaiter
public final void lock()
lock
in interface Awaiter
public final void unlock()
unlock
in interface Awaiter
public final boolean isExecuting()
true
if the state is EXECUTING
.
isExecuting
in interface Awaiter
public final boolean isSatisfied(CallState state)
true
if the current state is the same or later than
the given state.
isSatisfied
in interface Awaiter
public final void await(long nanos) throws InterruptedException
await
in interface Awaiter
InterruptedException
TimeUnit.timedWait(Object, long)
public final void deadcheck()
Awaiters.await(Awaiter, boolean, CallState, long)
should check for deadlock.
deadcheck
in interface Awaiter
public final boolean isDeadcheckRequested()
true
if a deadcheck request is outstanding.
isDeadcheckRequested
in interface Awaiter
public final void clearDeadcheckRequest()
clearDeadcheckRequest
in interface Awaiter
public final Thread[] getBlockingThreads()
Controller.getBlockingThreads()
.
getBlockingThreads
in interface Awaiter
public final void await() throws Throwable
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.
InterruptedException
- Waiting thread was interrupted.
Throwable
- Exception thrown by the task's method.final void awaitPending(long nanos) throws Throwable
PENDING
. If the wait timeout period expires or an
exception is thrown, throws a new CapacityExceededException
or the caught exception.
CapacityExceededException
- Timed out waiting for capacity.
InterruptedException
- Waiting thread was interrupted.
Throwable
- Unexpected exception while waiting.final Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
null
for void
return types.
NullPointerException
- unit
is null
.
InterruptedException
- Waiting thread was interrupted.
TimeoutException
- Waited too long.
ExecutionException
- Task's method threw an exception.
CancellationException
- Call was cancelled.final boolean cancel(boolean interruptably)
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.
public String toString()
toString
in class Object
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |