|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
public interface CallStateListener<V>
Validate, monitor and control call state transitions.
Agent listeners are organized into a hierarchy from the most general to the most specific:
AgentConfig.setCallStateListener(CallStateListener)
AgentConfig.setCallStateListener(CallState, CallStateListener)
CallSite.setCallStateListener(CallStateListener)
CallSite.setCallStateListener(CallState, CallStateListener)
AgentConfig.setCallStateListener(CallStateListener)
, is notified if all call state changes do not have a more specific
listener. If a more specific listener is configured, the more general
listeners are not automatically notified. The more specific listener
can, of course, call the more general listeners directly if desired.
For example:
interface I { void a(); void b(); void c(); void d(); } class T implements I { public void a() {} public void b() {} public void c() {} public void d() {} } class A implements CallStateListenerThe following summarizes the notifications each listener will receive:{ public void callStateChanged(AgentCall call, CallState previous) { System.out.println("A: call=" + call + ", previous=" + previous); } } class B implements CallStateListener { public void callStateChanged(AgentCall call, CallState previous) { System.out.println("B: call=" + call + ", previous=" + previous); } } class C implements CallStateListener { public void callStateChanged(AgentCall call, CallState previous) { System.out.println("C: call=" + call + ", previous=" + previous); } } class D implements CallStateListener { public void callStateChanged(AgentCall call, CallState previous) { System.out.println("D: call=" + call + ", previous=" + previous); } } I agent = Agent.newInstance(I.class, new T()); AgentConfig config = Agent.getConfig(agent); CallSite c = config.getCallSite("c", void.class); CallSite d = config.getCallSite("d", void.class); config.setCallStateListener(new A()); config.setCallStateListener(CallState.PENDING, new B()); c.setCallStateListener(new C()); d.setCallStateListener(CallState.FINISHED, new D());
PENDING
since this is handled by the B
listener;
no notifications for the c
method since these are handled
by the C
listener; and no notifications of transitions to
the FINISHED
state for the d
method since these are
handled by the D
listener.
PENDING
state for all methods except the c
method
since all notifications for the c
method are handled by the
C
listener.c
method.d
method have FINISHED
.
Non-agent listeners, specifically call listeners (see
AgentCall.setCallStateListener(CallState, CallStateListener)
), are
configured and notified independent of the hiearchy of agent listeners
described above. 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.
Agent and call site listeners are not called for a synthetic call. Only the
listerners specifically configured for a synthetic call are notified of state
changes. See AgentMark
and CallSite.isSynthetic()
.
The agent and call remain stable when a listener is notified. In practice, this means the agent and call are locked to prevent changes by other threads until the state change, including notification, are complete. This greatly simplifies the implementation of listeners since they need not typically worry about concurrency issues for any one agent. However, listeners should execute quickly for agents with multiple tasks, such as deferring long operations to another agent, in order to help avoid high contention.
One idiom for providing immediate feedback to callers on bad parameters, even
for asynchronous calls, is to set a listener for transitions to the
STARTING
state. Check for bad parameters or other problems in
the listener. If a problem is detected that you want to notify the caller
about immediately (versus having the task method detect the problem later),
finish the call with the appropriate result or exception, such as in the
following example that checks for a null
value for a required
parameter called name
:
if (call.getArgument(0) == null) { call.finish(); call.setException(new NullPointerException("Value for 'name' is null")); }
Agent.getConfig(Object)
,
AgentConfig.getCallSite(String, Class, Class...)
Method Summary | |
---|---|
void |
callStateChanged(AgentCall<V> call,
CallState previous)
Notification that a call's state has changed. |
Method Detail |
---|
void callStateChanged(AgentCall<V> call, CallState previous) throws Throwable
call.getState()
.
An exception thrown by a listener is treated as an unhandled
exception. The exception is passed to the handler configured with
AgentConfig.setUnhandledExceptionHandler(ExceptionHandler)
. It is
not thrown to the caller.
To throw an exception to the caller, such as for a synchronous call or
for any call transitioning to the STARTING
state, finish the
call with AgentCall.finish()
and set the exception with
AgentCall.setException(Throwable)
.
Throwable
|
|||||||||
PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |