Sunday, 5 July 2015

Groovy Listeners with AST

Recently while I was exploring Groovy features, I came across a very interesting component, i.e Listeners in Groovy
I will try to explain it with an example:

We have the following interface:


interface SpeakListener {

 void spoke(SpeakEvent event)
 void spoken(SpeakEvent event,String c)
 void spokeString(String str)
}

the Event class

class SpeakEvent {

 String name,origin
}

and a Listener class
i.e.

class GroovyListener {
 
 @groovy.beans.ListenerList
 List lisList
 
 String name
 
 void sayHello()
 {
  fireSpoke(new SpeakEvent(origin: name, name: 'Hello Groovy world!'))
  fireSpoken(new SpeakEvent(origin: name, name: 'Hello Groovy world!--Spoken'),"Mic")
  fireSpokeString("Mickey")
 }
 
}

The SpeakListener & SpeakEvent are just normal interfaces and class respectively. We will soon explore their role in this play :-)

The first thing that is consequential is the annotation @groovy.beans.ListenerList. We have annotated a list of type SpeakListener with @groovy.beans.ListenerList.
So the question arises what does it do?

Now when we add annotation to a List of a specified type which happens to play the role of a Listener adds the following methods to the class:

1) void addSpeakListener(SpeakListener listener)
2) void removeSpeakListener(SpeakListener listener)
3) void SpeakListener[] getSpeakListeners()


And for each method in the Listener Class i.e. SpeakListener there is fire method like
4) void fireSpoke(SpeakEvent event)
5) fireSpoken(SpeakEvent event, String c)
6) fireSpoken(SpeakEvent event, String c)
Here there are only 3 fire methods as there are only three methods in the Listener.
As it is clearly evident, that these fire methods has signature as the original methods.

Now here comes the usage part,
When we will add Speak Listeners to lisList, by adding each implementation of the SpeakListener interface and invoke the sayHello() method then the corresponding implenetation will be invoked, i.e. if the sayHello() has got only fireSpoke call, and we have added two different implementation of the SpeakListener to the lisList, then the spoke(SpeakEvent event) implementation from those two listeners in the lisList will be invoked. i.e.


class GroovyListenerTest {

 static main(args)
 {
  def listener = new GroovyListener(name:'Subha')
  
  /**
   * Implementing Speak Listener interface
   * by prividing implementations of indivudual methods
   */
  
  
  listener.addSpeakListener([spoke:{event -> println "${event.name} has Origin ${event.origin}"},spoken:{event,s -> println "${event.name} has Origin ${event.origin} for $s"},spokeString:{str -> println "The String is $str"}] as SpeakListener)
  //listener.addSpeakListener([spoken:{event -> println "${event.name} has Origin(Spoken) ${event.origin}"}] as SpeakListener)
  
  /**
   * Implementing Interface By providing the 
   * same definitions across all the methods
   * of the interface
   * 
   */
  
  def shout = {Object[] args1  -> println "$args1 has  New Origin"} as SpeakListener
  listener.addSpeakListener(shout)
  
  listener.sayHello()
 }
}

The output in the above case will be:

Hello Groovy world! has Origin Subha
[com.subha.model.SpeakEvent@41d9a8] has New Origin

Assuming that the sayHello() has only the fireSpoke(....) method invoked.
So,the SpeakEvent instance that is being used in the sayHello() is being passed to the registered Listeners added to the lisList.

Interesting right......
That's all on Groovy Listeners. Please share your views and comments.
View Subhankar Paul's profile on LinkedIn

No comments:

Post a Comment