org.curjent.agent
Interface CallStateListener<V>

All Known Implementing Classes:
FileVerifyListener

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:

The more general listeners serve as default listeners for call state transitions that do not have a more specific listener. The most general listener, 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 CallStateListener {
      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());
 
The following summarizes the notifications each listener will receive:

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"));
 }
 

See Also:
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

callStateChanged

void callStateChanged(AgentCall<V> call,
                      CallState previous)
                      throws Throwable
Notification that a call's state has changed. The listener is notified after the call's state has changed. Therefore, the new call state is available via 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).

Throws:
Throwable


Copyright 2009-2011 Tom Landon
Apache License 2.0