~~NOTRANS~~
~~Title: 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 jvx.rad.server.ICallHandler with the following methods:
public CallEventHandler eventBeforeFirstCall();
public CallEventHandler eventAfterLastCall();
public CallEventHandler eventBeforeCall();
public CallEventHandler 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.