Lesson 6: Side Effects
Until now we have been dealing with the composites constituded by components whose intercepting methods processed the message and did not care about the subsequent message processing. These message processing method I call message receivers or briefly receivers.
Chaplin ACT allows the programmer to develop other type of receivers called wrappers. A wrapper is primarily intended to intercept the message and pass it over to the subsequent processing. It usually performs some actions before and/or after the message is passed over. This is why this type of receiver is called wrapper. At present time there are two types of wrappers - side effects and concerns. Each type differs in how its functionality affects the message processing. In this example I present the side effect wrapper.
Side effects are message receivers whose functionality must not affect the message processing in any way. It means that it is allowed to modify neither the message content nor the replies to the message. In other words it is to say that the arguments passed by the side effect to the subsequent processing are ignored. Similarly, the return value of the side effect is also ignored. Furthermore, any exception thrown by the side effect's logic is captured and its propagation is stopped.
A typical purpose of the side effect is logging or diagnostics. In this example I prepare the PrinterDiag side effect whose purpose is measuring the total time spent by printing text messages.
public class PrinterDiag implements MessagePrinter { private long total; @ToContext(mode = InvocationMode.sideEffect) public void printMessage(String message) { long delta = System.nanoTime(); try { $next(); } finally { delta = System.nanoTime() - delta; total += delta; } } public long getTotal() { return total; } }
As this side effect is interrested in processing the printMessage internal message it contains the printMessage message method with the corresponding signature. Since we use the qualified messages the side effect’s class must implements the MessagePrinter interface.
The fact that this printMessage method behaves as the side effect is indicated by the ToContext annotation having its mode attribute set to InvocationMode.sideEffect.
The logic of this message receiver computes the difference between the moments before and after the message is passed over to the subsequent processing.
The internal message is passed over to the subsequent processing with the help of the $next operator.
This operator is statically imported from the org.iqual.chaplin.DynaCastUtils class.
The time difference is then added to the value held in the total field. This value can be obtained by the getTotal method.
Now, when we have the diagnosing side effect prepared we have to assemble the composite. That's very easy. We create an instance of the side effect and pass it to the $ operator as the first argument. The order of the arguments does matter as it determines the order of the message processing.
public class GreetingApp { public static void main(String[] args) { PrinterDiag diag = new PrinterDiag(); GreetingService greetServ = $(diag, new DefaultMessagePrinter(), new DecoratorPrinter()); greetServ.sayHello(); greetServ.sayGoodBye(); System.out.println("Time spent by printing:" + diag.getTotal() + " ns"); } }
The final statement prints the time spent by printing messsages. The value is obtained by calling the getTotal method on the diag side effect.
Note: It is also possible to create generic side effects. These generic side effects are not interrested in a particular internal message but they can handle any message. (TODO: add link to an example)