Trace: • Server-Side Call Events
If you call a server-side function or an action, usually you don't need more than the result on the client (UI). If you have complex business logic on server side, or if you call multiple server-side functions or actions in one single call, it would be useful to have server-side events with call information. Sometimes it's really helpful to do something after a single or all calls, e.g., cleanup of states, commit, or rollback connection(s) (if you don't use autocommit).
Our JVx server implementation has some events which could be useful for your application. We've defined the interface javax.rad.server.ICallHandler with the following methods:
public CallEventHandler<IBeforeFirstCallListener> eventBeforeFirstCall(); public CallEventHandler<IAfterLastCallListener> eventAfterLastCall(); public CallEventHandler<IBeforeCallListener> eventBeforeCall(); public CallEventHandler<IAfterCallListener> eventAfterCall(); public void invokeAfterCall(Runnable pRunnable); public void invokeAfterLastCall(Runnable pRunnable); public void invokeFinally(Runnable pRunnable);
The ICallHandler is accessible via
ServerContext.getCurrentInstance().getCallHandler()
or
SessionContext.getCurrentInstance().getCallHandler()
The difference is that ServerContext always returns the call handler for the master session and SessionContext returns the call handler for the current session.
If you register listeners for the ICallHandler of MasterSession, they will be notified about all calls in your application. All other sessions will be notified about own calls.
The events are one feature of ICallHandler. The other feature are one-time method calls via invoke… methods. The concept is similar to invokeLater of GUI toolkits like swing or JavaFX: Execute “something” after all other methods were called. On server-side it's not good to name a method invokeLater because there are different options, e.g., invoke after current call (invokeAfterCall) or invoke after all calls (invokeAfterLastCall).
We have an additional method that invokes “something” after all other operations. It's invokeFinally.
The call stack could look like the following, for a single action call:
connection.callAction("doServerAction");
BEFORE FIRST call BEFORE call doServerAction AFTER Call invokeAfterCall AFTER LAST call invokeAfterLastCall invokeFinally
multiple action calls:
connection.callAction(new String[] {"doServerAction", "doMailAction"});
BEFORE FIRST call BEFORE call doServerAction AFTER Call invokeAfterCall BEFORE call doMailAction AFTER Call invokeAfterCall AFTER LAST call invokeAfterLastCall invokeFinally
Listener Registration
You should register your listeners in a method annotated with @PostConstruct:
@PostConstruct public void createSession() { ICallHandler handler = SessionContext.getCurrentInstance().getCallHandler(); handler.eventBeforeFirstCall().addListener(this, "doBeforeFirstCall"); handler.eventBeforeCall().addListener(this, "doBeforeCall"); handler.eventAfterCall().addListener(this, "doAfterCall"); handler.eventAfterLastCall().addListener(this, "doAfterLastCall"); }
Sure, it would be possible to register listeners in constructor of your life cycle object, but you should know that the constructor could be called unexpectedly, e.g., if you inherit one LCO from another one:
Application |-Session |- Screen |- LockedScreen
If you're using LockedScreen, the constructors of Screen, Session, and Application will be called. You could check the class:
if (getClass() == LockedScreen.class) { //register listeners }
but it's better to use @PostConstruct.
Unregister Listeners
Usually, it's not necessary to unregister listeners because the ICallHandler will be available as long as the session is alive. But if you're working with ServerContext, it's a good idea to remove your listeners because JVx doesn't do this automatically.
Simply use a method, annotated with @PreDestroy:
@PreDestroy public void destroySession() { ICallHandler handler = ServerContext.getCurrentInstance().getCallHandler(); handler.eventAfterLastCall().removeListener(this); }
Invoke Methods or Listener Registration
It's not always possible to register a listener, or you won't do this because you don't need it for all your server calls. If you want to call a one-time function, please use invokeAfterCall or invokeAfterLastCall. Be careful with invokeFinally because this method was “reserved” for JVx objects.