We can use the ProxyMetaClass to replace the metaclass being used by a class within a selected block for the current thread only.
Interceptors with ProxyMetaClass
By using ProxyMetaClass, we can attach an interceptor to a class for a block of code. The Groovy-supplied Interceptor interface has three methods. The beforeInvoke() method specifies code to be executed before the intercepted method, the doInvoke() indicates whether to execute the intercepted method, and afterInvoke() executes after the intercepted method finishes, or after a false-returning doInvoke(). The result parameter passed to afterInvoke() is the result of executing the method, or what was returned from beforeInvoke() if the intercepted method wasn't executed. What afterInvoke() returns is returned from the method call in the main flow of the program.
We can invoke a different method instead of the one called:
We can even use interceptors on predefined Java classes:
The interception is only valid in the current thread. We can also combine categories with interceptors in various ways, also only valid in the current thread:
Usually we don't want to intercept methods inside the interceptor. We need to define our own UninterceptedInterceptor for this:
With the UninterceptedInterceptor class and useInterceptor utility, we can demonstrate a certain method being intercepted outside of the interceptor only:
Intercepting many classes in one block
Often, we want to intercept more than one class in one block. This example is of an aliasing interceptor, which disables some English-language names for selected classes, and replaces them with Spanish-language names. We re-use the UninterceptedInterceptor class and useInterceptor utility from previous examples.
We call the code like so:
We can put the cascadingly indented code into a list to make it neater by defining a utility category method on the List class. Unfortunately, doing so as follows only runs in versions of Groovy up to Groovy-1.0-RC-01. It doesn't work from Groovy-1.0-RC-02 onwards for an unknown reason, perhaps a bug.
Our own ProxyMetaClass
We can define our own proxy meta-classes. However, the following examples only run in versions of Groovy up to Groovy-1.0-RC-01. Due to an unrelated bug, we can't implement them this way in Groovy-1.0-RC-02 or later. The Groovy developers also intend changing the MetaClassImpl class in future releases so we would have to implement our own ProxyMetaClasses differently.
One case for which we'd define our own proxy meta-class is to implement our own style of interceptors, here, an around-interceptor:
We can then run our code:
Using many Interceptors with our own ProxyMetaClass
We can only use one interceptor with the ProxyMetaClass supplied by Groovy, so we need to provide our own when attaching more than one interceptor to a class:
Using a MultiInterceptorProxyMetaClass for the Observer pattern
A common design pattern is the Observer pattern. Using interceptors, we can abstract the observation code into its own class, the ObserverProtocol, which can be used by subclasses. It enables us to add and remove observing objects for an observed object. We use method interception to decouple the observing and observed objects from the observation relationship itself.
We can extend this ObserverProtocol with domain-specific observers. Because this example uses our own ProxyMetaClass, it can only run in Groovy-1.0-RC-01 or earlier. The example is a Groovy rewrite of one first implemented in AspectJ by Jan Hannemann and Gregor Kiczales at http://www.cs.ubc.ca/~jan/AODPs/.
Now we run the program. It first creates five Screen objects (s1, s2, s3, s4, and s5) and one point object, then sets up some observing relationships (namely, s1 and s2 will observe color changes to the point, s3 and s4 will observe coordinate changes to the point, and s5 will observe s2's and s4's display method), and finally, make changes to the point, first, the color, then its x-coordinate. The color change triggers s1 and s2 to each print an appropriate message. s2's message triggers its observer s5 to print a message. The coordinate change triggers s3 and s4 to print a message. s4's message also triggers the observer s5.
Using a MultiInterceptorProxyMetaClass and UninterceptableFriendlyInterceptor for the Decorator pattern
We can use more than one uninterceptable interceptor with a proxy meta-class. A good example where this is necessary is the Decorator pattern. We re-use the MultiInterceptorProxyMetaClass from previous examples, but must write a special unintercepted interceptor, which we call an UninterceptableFriendlyInterceptor, that can be used as one of many with the MultiInterceptorProxyMetaClass.
For our example Decorator pattern, we'll code an OutputStreamWriter that prints extra if necessary. We use decorators extended from the UninterceptableFriendlyInterceptor. Firstly, a NewlineDecorator that uses a line-width policy to perhaps place the output on a new line. And second, a very simple WhitespaceDecorator that ensures there's some whitespace between any two consecutive items output. Each has only very simple logic for this example.
After the classes, interceptors, and code block are matched up, the printing logic and the OutputStreamWriter are both unaware that the output is being decorated. Each decorator will perhaps modify the output, then pass it along to the next decorator to do the same. The distinct items of output sent to the OutputStreamWriter are separated by spaces, whether or not a space was in the output string in the program, and the output fits within a certain width.