954,518 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

fireEvent() and custom Listeners

I'm trying to get hang of custom events and listeners. I found example of single event-listener, but I'm curious how to extend from single method to multiple that are related.

public interface CountListener{
	
	public void countEvent(int count);
	
	public void multiplyEvent(int multi);    
}
public class Counter implements CountListener{

    public void countEvent(int count){
    	System.out.println("Counter: "+count);
    }
    
    public void multiplyEvent(int multi){
    	System.out.println("Multiply: " +multi*multi);
    }
}
import java.util.*;
import java.lang.reflect.Method;

public class CountTest {

    ArrayList listeners;
    
    public void addCountListener(CountListener c){
    	listeners.add(c);
    }
    
    public void removeCountListener(CountListener c){
    	if(listeners.contains(c)){
    		listeners.remove(listeners.indexOf(c));
    	}
    }
    
    public void fireEvent(int count, Object methodObj){
    	Iterator i = listeners.iterator();
    	while(i.hasNext()){    		
    		//((CountListener)i.next()).countEvent(count);
    		Object obj = i.next();
    		System.out.println(obj.getClass().getName());
    		
    		Method[] meth = obj.getClass().getDeclaredMethods();
    		for(Method m : meth){
    			
    			if(m.equals(methodObj)){
    				System.out.println(m.getName());
    				try{
    					m.invoke(methodObj, count);
    				}
    				catch(Exception e){
    				}
    			}
    		}
    	}
    }
    
    public CountTest(){
    	listeners = new ArrayList();
    }
    
    public void count(int i){
    	fireEvent(i, (Object) "countEvent");
    }
    
    public void multiply(int i){
    	fireEvent(i, (Object) "multiplyEvent");
    }
    
    public static void main(String[] args){
    	CountTest c = new CountTest();
    	c.addCountListener(new Counter());
    	
    	/*for(int i = 0; i < 10; i++){
    		c.count(i);
    	}*/
    	c.count(5);
    	c.multiply(5);
    }
}

As you can see from above example I'm able to break down class on all methods provided by this class. However I'm not bale to call appropriate method that much my listener call. fireEvent(i, (Object) "countEvent"); is just blatant attempt because I know compile will not fire errors. So question is how do I declare this Object so it will work? Or am I completely of the hock with my attempt?

peter_budo
Code tags enforcer
Moderator
15,436 posts since Dec 2004
Reputation Points: 2,806
Solved Threads: 902
 

I can't understand what you are trying to do with all the Reflection methods here! What do you need to do that is different from the standard pattern:

ArrayList<CountListener> listeners = new ...

...

void fireCountEvent(int count) {
   for (CountListener cl : listeners) {
      cl . countEvent(count);
   }
}

...

void fireMultiplyEvent(int mult) {
   for (CountListener cl : listeners) {
      cl . multiplyEvent(mult);
   }
}

public void count(int count) {
   ...
   fireCountEvent(count);
}
JamesCherrill
Posting Genius
Moderator
6,371 posts since Apr 2008
Reputation Points: 2,130
Solved Threads: 1,073
 

In your code you have the wrong comparisson:
m.equals(methodObj) should be m.getName().equals(methodObj)
since m contains "public void bla bla()"

And when you invoke the method you need to invoke it with an instance of the class, e.g: m.invoke(new Counter(), count);

I think :)

di2daer
Junior Poster in Training
66 posts since Sep 2008
Reputation Points: 22
Solved Threads: 13
 
I can't understand what you are trying to do with all the Reflection methods here!


Just trying to fill in empty spaces in my knowledge. Above example op-up on Google search and I tried to expand, unfortunately I may not chosen wisely.In your code you have the wrong comparisson:
m.equals(methodObj) should be m.getName().equals(methodObj)
since m contains "public void bla bla()"

And when you invoke the method you need to invoke it with an instance of the class, e.g: m.invoke(new Counter(), count);

I think :)
Correct assumption. It did work.

However James proposal is better approach at this point. Or has anybody better idea?

peter_budo
Code tags enforcer
Moderator
15,436 posts since Dec 2004
Reputation Points: 2,806
Solved Threads: 902
 
James proposal is better approach at this point.

Sorry, I can't take any credit for that - it's just the standard boiler-plate way of doing it. One small tweek: there's a danger of a problem if the list of Listeners is updated while the fireEvent code is looping through it (either because its multi-threaded, or maybe because a listener receives the event and, in the event handling method, decides to remove itself from the list). For that reason it's normal to use a temporary copy for the loop:

ArrayList<CountListener> safeCopy = new ArrayList<CountListener>(listeners);
   for (CountListener cl : safeCopy ) {
      cl . countEvent(count);
   }
JamesCherrill
Posting Genius
Moderator
6,371 posts since Apr 2008
Reputation Points: 2,130
Solved Threads: 1,073
 

I have added the JC's suggestion.

I think two method of CountListener interface has no value and also I have added CountEvent object as an argument of event method.

public interface CountListener{
        public void countEvent(CountEvent e);
}
public class CountEvent{
   private int result;
   private String action;
   private Object source;
   public CountEvent(int result,String action,Object source) {
      this.result=result; this.action=action; this.source=source;
   }
   public int getResult() { return result;}
   public String getAction() { return action;}
   public Object getSource() { return source;}
}
public class Counter implements CountListener{
    public void countEvent(CountEvent e){
        System.out.println(e.getResult() + " " + e.getAction());
    }
}
import java.util.*;

public class CountTest {

    ArrayList<CountListener> countlisteners;
    
    public void addCountListener(CountListener c){
        if(countlisteners==null)
             countlisteners=new ArrayList<CountListener>();
    	countlisteners.add(c);
    }
   
    public void removeCountListener(CountListener c){
    	if(countlisteners.contains(c)){
    		countlisteners.remove(countlisteners.indexOf(c));
    	}
    }
    
    public CountTest(){
    }
    
    public void count(int i){
         ArrayList<CountListener> safeCopy = new 

ArrayList<CountListener>(listeners);
         for(CountListener c:safeCopy) {
            if(c!=null) c.countEvent(new CountEvent(i,"Count",this));
         }
    }
   
    public void multiply(int i){
      ArrayList<CountListener> safeCopy = new 
ArrayList<CountListener>(listeners);
         for(CountListener c:safeCopy) {
            if(c!=null) c.countEvent(new CountEvent(i,"Mul",this));
         }
    }
   
    public static void main(String[] args){
    	CountTest c = new CountTest();
        Counter t=new Counter();
        c.addCountListener(t);
    	
        c.count(2);
    	c.multiply(5);
        c.removeCountListener(t);
        c.count(22);
        c.multiply(55);
    }
}
__avd
Posting Genius (adatapost)
Moderator
8,648 posts since Oct 2008
Reputation Points: 2,136
Solved Threads: 1,241
 

for loosely related info, you could check out this thread that James and Ezzaral helped me out in before:

http://www.daniweb.com/forums/showthread.php?t=187103&highlight=mvc

BestJewSinceJC
Posting Maven
2,772 posts since Sep 2008
Reputation Points: 874
Solved Threads: 354
 

I like the solution with a custom event class to carry the info to the listeners. Very nice. Particularly good if there is any chance that there will be more functionality added later, because you can add more event sub-types without changing the formal definition of the listener interface and thus invalidating existing code.

JamesCherrill
Posting Genius
Moderator
6,371 posts since Apr 2008
Reputation Points: 2,130
Solved Threads: 1,073
 

for loosely related info, you could check out this thread that James and Ezzaral helped me out in before:

http://www.daniweb.com/forums/thread187103.html&highlight=mvc


Link doesn't work

peter_budo
Code tags enforcer
Moderator
15,436 posts since Dec 2004
Reputation Points: 2,806
Solved Threads: 902
 

Without the ending parameter "&highlight=mvc", the link works:
http://www.daniweb.com/forums/thread187103.html

svedrenne
Newbie Poster
3 posts since Dec 2010
Reputation Points: 10
Solved Threads: 0
 

This article has been dead for over three months

Post: Markdown Syntax: Formatting Help
You