Home | History | Annotate | Download | only in util
      1 /**
      2  * Copyright 2003-2007 Jive Software.
      3  *
      4  * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package org.jivesoftware.smackx.workgroup.util;
     18 
     19 import java.lang.reflect.Method;
     20 import java.util.ArrayList;
     21 import java.util.ListIterator;
     22 
     23 /**
     24  * This class is a very flexible event dispatcher which implements Runnable so that it can
     25  * dispatch easily from a newly created thread. The usage of this in code is more or less:
     26  * create a new instance of this class, use addListenerTriplet to add as many listeners
     27  * as desired to be messaged, create a new Thread using the instance of this class created
     28  * as the argument to the constructor, start the new Thread instance.<p>
     29  *
     30  * Also, this is intended to be used to message methods that either return void, or have
     31  * a return which the developer using this class is uninterested in receiving.
     32  *
     33  * @author loki der quaeler
     34  */
     35 public class ListenerEventDispatcher
     36     implements Runnable {
     37 
     38     protected transient ArrayList<TripletContainer> triplets;
     39 
     40     protected transient boolean hasFinishedDispatching;
     41     protected transient boolean isRunning;
     42 
     43     public ListenerEventDispatcher () {
     44         super();
     45 
     46         this.triplets = new ArrayList<TripletContainer>();
     47 
     48         this.hasFinishedDispatching = false;
     49         this.isRunning = false;
     50     }
     51 
     52     /**
     53      * Add a listener triplet - the instance of the listener to be messaged, the Method on which
     54      *  the listener should be messaged, and the Object array of arguments to be supplied to the
     55      *  Method. No attempts are made to determine whether this triplet was already added.<br>
     56      *
     57      * Messages are dispatched in the order in which they're added via this method; so if triplet
     58      *  X is added after triplet Z, then triplet Z will undergo messaging prior to triplet X.<br>
     59      *
     60      * This method should not be called once the owning Thread instance has been started; if it
     61      *  is called, the triplet will not be added to the messaging queue.<br>
     62      *
     63      * @param listenerInstance the instance of the listener to receive the associated notification
     64      * @param listenerMethod the Method instance representing the method through which notification
     65      *                          will occur
     66      * @param methodArguments the arguments supplied to the notification method
     67      */
     68     public void addListenerTriplet(Object listenerInstance, Method listenerMethod,
     69             Object[] methodArguments)
     70     {
     71         if (!this.isRunning) {
     72             this.triplets.add(new TripletContainer(listenerInstance, listenerMethod,
     73                     methodArguments));
     74         }
     75     }
     76 
     77     /**
     78      * @return whether this instance has finished dispatching its messages
     79      */
     80     public boolean hasFinished() {
     81         return this.hasFinishedDispatching;
     82     }
     83 
     84     public void run() {
     85         ListIterator<TripletContainer> li = null;
     86 
     87         this.isRunning = true;
     88 
     89         li = this.triplets.listIterator();
     90         while (li.hasNext()) {
     91             TripletContainer tc = li.next();
     92 
     93             try {
     94                 tc.getListenerMethod().invoke(tc.getListenerInstance(), tc.getMethodArguments());
     95             } catch (Exception e) {
     96                 System.err.println("Exception dispatching an event: " + e);
     97 
     98                 e.printStackTrace();
     99             }
    100         }
    101 
    102         this.hasFinishedDispatching = true;
    103     }
    104 
    105 
    106     protected class TripletContainer {
    107 
    108         protected Object listenerInstance;
    109         protected Method listenerMethod;
    110         protected Object[] methodArguments;
    111 
    112         protected TripletContainer (Object inst, Method meth, Object[] args) {
    113             super();
    114 
    115             this.listenerInstance = inst;
    116             this.listenerMethod = meth;
    117             this.methodArguments = args;
    118         }
    119 
    120         protected Object getListenerInstance() {
    121             return this.listenerInstance;
    122         }
    123 
    124         protected Method getListenerMethod() {
    125             return this.listenerMethod;
    126         }
    127 
    128         protected Object[] getMethodArguments() {
    129             return this.methodArguments;
    130         }
    131     }
    132 }