head	1.11;
access;
symbols;
locks; strict;
comment	@# @;


1.11
date	2001.08.29.19.42.49;	author leonardr;	state dead;
branches;
next	1.10;

1.10
date	2001.08.28.23.02.04;	author leonardr;	state Exp;
branches;
next	1.9;

1.9
date	2001.08.21.19.21.59;	author leonardr;	state Exp;
branches;
next	1.8;

1.8
date	2001.08.21.19.20.40;	author leonardr;	state Exp;
branches;
next	1.7;

1.7
date	2001.08.21.18.50.36;	author leonardr;	state Exp;
branches;
next	1.6;

1.6
date	2001.08.21.17.11.05;	author leonardr;	state Exp;
branches;
next	1.5;

1.5
date	2001.08.21.16.34.12;	author leonardr;	state Exp;
branches;
next	1.4;

1.4
date	2001.08.21.01.14.22;	author leonardr;	state Exp;
branches;
next	1.3;

1.3
date	2001.08.20.23.36.55;	author leonardr;	state Exp;
branches;
next	1.2;

1.2
date	2001.08.20.19.09.12;	author leonardr;	state Exp;
branches;
next	1.1;

1.1
date	2001.08.17.21.51.50;	author leonardr;	state Exp;
branches;
next	;


desc
@@


1.11
log
@Moved integration-oriented code into new component package.
@
text
@/* ================================================================
 * Copyright (c) 2001 CollabNet.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 *
 * 3. The end-user documentation included with the redistribution, if
 * any, must include the following acknowlegement: "This product includes
 * software developed by CollabNet <http://www.collab.net/>."
 * Alternately, this acknowlegement may appear in the software itself, if
 * and wherever such third-party acknowlegements normally appear.
 *
 * 4. The hosted project names must not be used to endorse or promote
 * products derived from this software without prior written
 * permission. For written permission, please contact info@@collab.net.
 *
 * 5. Products derived from this software may not use the "Tigris" or
 * "Helm" names nor may "Tigris" or "Helm" appear in their names without
 * prior written permission of CollabNet.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL COLLABNET OR ITS CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of CollabNet.
 */

package org.tigris.helm.tool;

import java.util.*;
import java.lang.*;
import java.lang.reflect.*;

import org.apache.torque.om.BaseObject;
import org.apache.torque.om.ComboKey;
import org.apache.torque.om.ObjectKey;
import org.apache.torque.om.NumberKey;
import org.apache.torque.TorqueException;

import org.apache.fulcrum.TurbineServices;
import org.apache.fulcrum.InitializationException;
import org.apache.fulcrum.ServiceException;
import org.apache.fulcrum.ServiceManager;
import org.apache.fulcrum.velocity.TurbineVelocity;

import org.apache.turbine.util.Log;

import org.apache.commons.util.exception.NestableException;
import org.apache.commons.collections.ExtendedProperties;

import org.apache.velocity.VelocityContext;
import org.apache.velocity.context.Context;

import org.tigris.helm.event.ClusterEvent;
import org.tigris.helm.event.CompletionEvent;
import org.tigris.helm.event.ToolEvent;
import org.tigris.helm.event.PropagationFailed;
import org.tigris.helm.event.PropagationFailedEvent;

import org.tigris.helm.tool.HelmEmailer;
import org.tigris.helm.tool.cluster.ClusteredSingletonService;
import org.tigris.helm.tool.cluster.ClusterService;

import org.tigris.helm.util.MethodSignature;

/**
 * Service for propagating Helm state changes to tools.
 *
 * @@author <a href="mailto:leonardr@@collab.net">Leonard Richardson</a>
 * @@version $Id: ToolEventPropagationService.java,v 1.10 2001/08/28 23:02:04 leonardr Exp $
 */
public class ToolEventPropagationService extends ClusteredSingletonService
{
    /**
     * Name of this service.
     */
    private static final String SERVICE_NAME = "ToolEventPropagationService";

    /**
     * The subject to use for the propagation failure report email.
     * The tool and command will be appended to the subject.
     */
    private static final String PROPAGATION_FAILURE_SUBJECT = 
        "Propagation failure report: ";

    /**
     * The name of the template used to create the body of the propagation
     * failure report email.
     */
    private static final String PROPAGATION_FAILURE_TEMPLATE = 
        TemplateTool.getPathToMessageTemplate("PropagationFailed.vm");

    /**
     * Queue of events which the singleton has yet to process.
     */
    List queue = new ArrayList();

    /**
     * The thread which actually propagates events.
     */
    EventPropagator eventPropagator = new EventPropagator();

    /**
     * A map of task IDs to failure descriptors.
     */
    Map failures = new HashMap();

    /**
     * A map keying Strings to {MethodSignature, Method} arrays.
     */
    private Map methodsByListener = new HashMap();

    /**
     * Prefixes of mappings in TurbineResources.properties of
     * names to listener classes.
     */
    private static final String LISTENER_PREFIX = "component.listener.";
    
    /**
     * Method to use to transform a key into a business object.
     */
    private static final String PEER_KEY_METHOD = "retrieveByPK";

    /**
     * Parameters of method used to transform a key into a business
     * object.
     */
    private static final Class[] PEER_KEY_PARAMETERS = new Class[1];

    /**
     * Initialize the parameters of the method used to transform
     * a key into a business object.
     */
    static
    {
        Class arg;
        try
        {
            arg = Class.forName("org.apache.torque.om.ObjectKey");
        }
        catch (Exception e)
        {
            throw new Error("Unable to initialize " + SERVICE_NAME + '!');
        }
        PEER_KEY_PARAMETERS[0] = arg;
    }

    /**
     * A wrapper method for getting the single instance of this
     * service from the Turbine services list.
     *
     * @@return Turbine's single instance of this service.
     */
    public static final ToolEventPropagationService getService()
    {
        return (ToolEventPropagationService)TurbineServices
            .getInstance().getService(SERVICE_NAME);
    }

    /**
     * Constructor; initialize to not being the singleton.
     */
    public ToolEventPropagationService()
    {
        isSingleton = false;
    }

    /**
     * Descriptor for this service.
     */
    public final String getDescriptor()
    {
        return SERVICE_NAME;
    }

    /**
     * Returns the status of this service. 
     */
    public final String getStatus()
        throws ServiceException
    {
        return describeRegisteredMethods();
    }
    
    /**
     * Queue of unpropagated events.
     */
    public final List getQueue()
    {
        return queue;
    }

    /**
     * Initializes this service.  Called during Fulcrum
     * initialization.  
     */
    public synchronized void init()
        throws InitializationException
    {
        super.init();
        
        methodsByListener.clear();

        ExtendedProperties conf =
            ((ServiceManager)TurbineServices.getInstance()).getConfiguration();
        try
        {
            for (Iterator i = conf.getKeys(LISTENER_PREFIX); i.hasNext();)
            {
                String listenerProp = (String)i.next();
                String listenerName = listenerProp
                    .substring(LISTENER_PREFIX.length());
                String listenerClassName = conf.getString(listenerProp);
                registerClass(listenerName, Class.forName(listenerClassName));
            }
        }
        catch (Exception e)
        {
            Log.error(e);
            throw new InitializationException
                ("Unable to initialize " + SERVICE_NAME + '!');
        }

        Thread propagatorThread = new Thread(eventPropagator);
        propagatorThread.start();
    }

    /**
     * Registers the methods of the named class with the event propagator.
     */
    private void registerClass(String listener, Class classInstance)
        throws Exception
    {
        Method[] methods = classInstance.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++)
        {
            Method m = methods[i];
            MethodSignature sig = new MethodSignature(m);
            Object[] array = {sig, m}; 
            Set mappedMethods = (Set)methodsByListener.get(listener);
            if (mappedMethods == null)
            {
                mappedMethods = new HashSet();
            }
            mappedMethods.add(array);
            methodsByListener.put(listener, mappedMethods);
        }
        if (!listener.equals(ToolEvent.ALL_TOOLS))
        {
            registerClass(ToolEvent.ALL_TOOLS, classInstance);
        }
    }

    /**
     * Sends an event across the wire to be propagated to tools.
     */
    public void propagate(ToolEvent e)
        throws NestableException
    {
        ClusterService.getService().sendEvent(this, e);
    }

    /**
     * Tool event: Adds the event to the queue.<br>
     * Completion event: Removes the specified event from the queue.<br>
     * Propagation failed event: Updates the failure information for the
     *                           specified event.
     */
    public void eventReceived(ClusterEvent e)
        throws NestableException
    {
        if (e instanceof ToolEvent)
        {
            ToolEvent te = (ToolEvent)e;
            queue.add(te);
        }
        else if (e instanceof CompletionEvent)
        {
            CompletionEvent ce = (CompletionEvent)e;
            String toolEventID = ce.getToolEventID();
            failures.remove(toolEventID);
            for (Iterator i = queue.iterator(); i.hasNext();)
            {
                ToolEvent te = (ToolEvent)i.next();
                if (toolEventID.equals(te.getID()))
                {
                    i.remove();
                    break;
                }
            }
        }
        else if (e instanceof PropagationFailedEvent)
        {
            logFailure((PropagationFailedEvent)e);
        }
    }

    /**
     * Returns the current map of failures.
     */
    public Map getFailures()
    {
        return failures;
    }

    /**
     * Logs the failure of an event to propagate. Failures are logged
     * by each member of a cluster.
     */
    private void logFailure(PropagationFailedEvent e)
    {
        String id = e.getEventID();
        Date date = e.getFailureDate();
        String message = e.getFailureMessage();
        List failure = (List)failures.get(id);
        if (failure == null)
        {
            failure = new ArrayList(4);
        }

        if (failure.size() >= 4)
        {
            //The event has failed at least twice before and we're
            //overwriting the most recent failure message with the new
            //one.
            int offset = 2;
            failure.set(offset++, date);
            failure.set(offset++, message);
        }
        else
        {
            failure.add(date);
            failure.add(message);
        }

        failures.put(id, failure);
    }
    
    /**
     * Describes all the methods currently registered with the
     * propagator.
     */
    private String describeRegisteredMethods()
    {
        StringBuffer s = new StringBuffer();
        for (Iterator i = methodsByListener.keySet().iterator();
             i.hasNext();)
        {
            Object z = i.next();
            String listener = (String)z;
            Set methods = (Set)methodsByListener.get(listener);
            for (Iterator j = methods.iterator(); j.hasNext();)
            {
                Object[] a = (Object[])j.next();
                Method m = (Method)a[1];
                s.append("    " + m.getDeclaringClass().getName() 
                         + '.' + m.getName() + '\n');
            }
            s.append('\n');
        }
        return s.toString();
    }

    /**
     * Returns all the methods with which the given signature would
     * work.  
     */
    List getMethodsMatching(String key, MethodSignature sig)
    {
        Set methods = (Set)methodsByListener.get(key);
        List matchingMethods = new ArrayList();
        for (Iterator i = methods.iterator(); i.hasNext();)
        {
            Object[] a = (Object[])i.next();
            MethodSignature s = (MethodSignature)a[0];
            Method m = (Method)a[1];
            if (sig.subclasses(s))
            {
                matchingMethods.add(m);
            }
        }
        return matchingMethods;
    }

    /**
     * The class which actually propagates the events.
     */
    private class EventPropagator implements Runnable
    {      
        private static final int MAX_FAILURES = 10;
        
        /**
         * Event propagator loop.
         */
        public void run()
        {
            while (true)
            {
                if (isSingleton)
                {
                    try
                    {                    
                        doService();
                    }
                    catch (Exception e)
                    {
                        Log.error(e);
                    }
                }
                try
                {
                    Thread.sleep(1000);
                }
                catch (InterruptedException ignore)
                {
                    //Back to work.
                }
            }
        }

        /**
         * Propagates all events in the queue.
         */
        public void doService()
            throws NestableException
        {
            for (Iterator i = queue.iterator(); i.hasNext();)
            {
                ToolEvent e = (ToolEvent)i.next();
                if (processToolEvent(e))
                {
                    i.remove();
                }
            }
        }

        /**
         * Calls previously registered methods corresponding to this
         * event and its arguments.
         *
         * @@return true iff the event should be removed from the
         * queue.
         */
        private boolean processToolEvent(ToolEvent event)
            throws NestableException
        {
            boolean clearEvent = true;
            String listener = event.getTool();
            String[] peerClassNames = event.getPeers();
            String[] keys = event.getKeys();        
            
            Class[] peerClasses = new Class[peerClassNames.length];
            Object[] objects = new Object[keys.length];
            Class[] objectClasses = new Class[keys.length];
            try
            {
                for (int i = 0; i < keys.length; i++)
                {
                    String keyString = keys[i];
                    ObjectKey key = new NumberKey(keyString);
                    
                    //Find the class of this object.
                    Class peerClass = Class.forName(peerClassNames[i]);
                    peerClasses[i] = peerClass;                    
                    
                    //Find the actual object.
                    try 
                    {
                        Method m = peerClass.getMethod
                            (PEER_KEY_METHOD, PEER_KEY_PARAMETERS);
                        ObjectKey[] arguments = {key};
                        objects[i] = (BaseObject)m.invoke(null, arguments);
                    }
                    catch (Exception ex)
                    {
                        //We were passed something that's not a Peer. 
                        //Just store the object itself.
                        objects[i] = key;
                    }
                    objectClasses[i] = objects[i].getClass();
                }
                
                MethodSignature sig = new MethodSignature(event.getName(), 
                                                          objectClasses);
                List methods = getMethodsMatching(listener, sig);
                for (Iterator i = methods.iterator(); i.hasNext();)
                {
                    Method m = (Method)i.next();
                    try
                    {
                        m.invoke(null, objects);
                    }
                    catch (InvocationTargetException e)
                    {                            
                        Throwable t = e.getTargetException();
                        if (t instanceof PropagationFailed)
                        {
                            //Only the singleton calls handleFailure,
                            //but every cluster member logs the
                            //failure after receiving the
                            //PropagationFailedEvent generated by
                            //handleFailure.
                            PropagationFailed pf = (PropagationFailed)t;
                            clearEvent = handleFailure(event, pf);
                        }
                        else
                        {
                            throw e;
                        }
                    }
                }
                if (clearEvent)
                {
                    CompletionEvent ce = new CompletionEvent(event);
                    ClusterService.getService().sendEvent
                        (ToolEventPropagationService.getService(), ce);
                }
            }
            catch (Exception ex)
            {
                throw new NestableException(ex);
            }
            return clearEvent;
        }           

        /**
         * Handles an event propagation failure. 
         *
         * @@return true iff the event that failed should be removed from
         * the queue.
         */
        private boolean handleFailure(ToolEvent event, PropagationFailed e)
            throws NestableException
        {
            boolean removeEvent = false;
            String newID = event.getID();            

            //If a broadcast event failed, we need to resend it to
            //only the tool that failed.
            String newListener = e.getListener();
            if (event.getTool().equals(ToolEvent.ALL_TOOLS))
            {
                ToolEvent newEvent = new ToolEvent
                    (event.getName(), newListener, event.getPeers(), 
                     event.getKeys());
                ToolEventPropagationService.getService().propagate(newEvent);
                removeEvent = true;
                newID = newEvent.getID();
            }

            //If no prior failure exists for this event, send out email
            //about it.
            List failure = (List)failures.get(event.getID());
            if (failure == null)
            {
                Log.error("PROPAGATION ERROR: " + newListener + '/' 
                          + event.getName() + ": " + e.getMessage());

                String subject = PROPAGATION_FAILURE_SUBJECT 
                    + newListener + '/' + event.getName();

                Context ctx = new VelocityContext();
                ctx.put("event", event);
                ctx.put("failure", e);
                try
                {
                    String body = TurbineVelocity.handleRequest
                        (ctx, PROPAGATION_FAILURE_TEMPLATE);
                    new HelmEmailer().messageUsersWithHostOwnership
                        (subject, body);
                }
                catch (Exception ex)
                {
                    Log.error("Unable to notify admins of error!", ex);
                }

            }

            //We need to broadcast news that the propagation failed.
            PropagationFailedEvent pfe = new PropagationFailedEvent(newID, e);
            ClusterService.getService().sendEvent
                (ToolEventPropagationService.getService(), pfe);

            return removeEvent;
        }
    }    
}
@


1.10
log
@The tool events now know that business objects don't always correspond naively to peers, and that it's okay to call a method using a subclass of the formal argument as the actual argument.
@
text
@d89 1
a89 1
 * @@version $Id: ToolEventPropagationService.java,v 1.9 2001/08/21 19:21:59 leonardr Exp $
@


1.9
log
@Changed variable name.
@
text
@d89 1
a89 1
 * @@version $Id: ToolEventPropagationService.java,v 1.8 2001/08/21 19:20:40 leonardr Exp $
d128 1
a128 1
     * A map keying {String, MethodSignature} Sets to Method objects.
d130 1
a130 1
    private Map methodsByListenerAndSignature = new HashMap();
d221 1
a221 1
        methodsByListenerAndSignature.clear();
d257 3
a259 2
            List key = makeKey(listener, new MethodSignature(m));
            List mappedMethods = (List)methodsByListenerAndSignature.get(key);
d262 1
a262 1
                mappedMethods = new ArrayList(1);
d264 2
a265 2
            mappedMethods.add(m);
            methodsByListenerAndSignature.put(key, mappedMethods);
a364 15
        Map methodsByListener = new HashMap();        
        for (Iterator i = methodsByListenerAndSignature.keySet().iterator(); 
             i.hasNext();)
        {
            List key = (List)i.next();            
            String listener = (String)key.get(0);           
            List methods = (List)methodsByListener.get(listener);
            if (methods == null)
            {
                methods = new ArrayList(1);
            }
            methods.addAll((List)methodsByListenerAndSignature.get(key));
            methodsByListener.put(listener, methods);
        }

d368 3
a370 3
            String listener = (String)i.next();
            s.append("For listener " + listener + ":\n");
            List methods = (List)methodsByListener.get(listener);
d373 2
a374 1
                Method m = (Method)j.next();
d384 2
a385 1
     * Makes a key for the method hash.
d387 1
a387 1
    private List makeKey(String listener, MethodSignature sig)
d389 13
a401 4
        List key = new ArrayList(2);
        key.add(listener);
        key.add(sig);
        return key;
d504 2
a505 3
                List key = makeKey(listener, sig);
                List methods = (List)methodsByListenerAndSignature.get(key);
                if (methods != null)
d507 2
a508 1
                    for (Iterator i = methods.iterator(); i.hasNext();)
d510 6
a515 2
                        Method m = (Method)i.next();
                        try
d517 7
a523 1
                            m.invoke(null, objects);
d525 3
a527 18
                        catch (InvocationTargetException e)
                        {                            
                            Throwable t = e.getTargetException();
                            if (t instanceof PropagationFailed)
                            {
                                //Only the singleton calls
                                //handleFailure, but every cluster
                                //member logs the failure after
                                //receiving the
                                //PropagationFailedEvent generated by
                                //handleFailure.
                                PropagationFailed pf = (PropagationFailed)t;
                                clearEvent = handleFailure(event, pf);
                            }
                            else
                            {
                                throw e;
                            }
d605 1
a605 1
    }
@


1.8
log
@All cluster members, not just the singleton, should forget about the failures of completed events.
@
text
@d89 1
a89 1
 * @@version $Id: ToolEventPropagationService.java,v 1.7 2001/08/21 18:50:36 leonardr Exp $
d299 1
a299 1
            failures.remove(ce.getID());
@


1.7
log
@Send email on the first failure of an event to be propagated.
@
text
@d89 1
a89 1
 * @@version $Id: ToolEventPropagationService.java,v 1.6 2001/08/21 17:11:05 leonardr Exp $
d299 1
a516 1
                            failures.remove(event.getID());
@


1.6
log
@Use a List instead of an array for easier use in templates.
@
text
@d63 1
d66 1
d70 3
d79 1
d89 1
a89 1
 * @@version $Id: ToolEventPropagationService.java,v 1.5 2001/08/21 16:34:12 leonardr Exp $
d99 14
d563 1
a563 5
            String newListener = event.getTool();
            if (newListener.equals(ToolEvent.ALL_TOOLS))
            {
                newListener = e.getListener();
            }
d565 4
a568 2
            String newID = event.getID();
            if (!event.getTool().equals(newListener))
a569 2
                //We need to re-broadcast the event as a more specific
                //event.
d576 28
@


1.5
log
@Added failure logging to events. The ToolEventPropagationService keeps track of the first and the most recent failure for each event.
@
text
@d83 1
a83 1
 * @@version $Id: ToolEventPropagationService.java,v 1.4 2001/08/21 01:14:22 leonardr Exp $
d312 1
a312 1
        Object[] failure = (Object[])failures.get(id);
d315 1
a315 2
            failure = new Object[4];
            Arrays.fill(failure, null);
d318 1
a318 4
        //Assume that the event has failed previously and we're
        //overwriting the most recent failure message.
        int offset = 2;
        if (failure[0] == null)
d320 6
a325 2
            //No, this is the first time this event failed;
            offset = 0;
d327 6
a332 2
        failure[offset++] = date;
        failure[offset++] = message;
@


1.4
log
@Tool events are now retried indefinitely. Generic tool events are rebroadcast to the specific tools which had failures.
@
text
@d71 2
a72 1
import org.tigris.helm.event.ToolEventPropagationFailed;
d83 1
a83 1
 * @@version $Id: ToolEventPropagationService.java,v 1.3 2001/08/20 23:36:55 leonardr Exp $
d103 5
d116 1
a116 1
    private static final String LISTENER_PREFIX = "component.listener";
d211 1
a211 1
                    .substring(LISTENER_PREFIX.length()+1);
d262 4
a265 2
     * Tool event: Adds the event to the queue.
     * Completion event: Removes the specified event from the queue.
d289 41
a387 21

        /**
         * Map of tool event IDs to failure exceptions.
         */
        private Map failureExceptions = new HashMap();

        /**
         * Tool event IDs which have resulted in sent email.
         */
        private Set sentMail = new HashSet();

        /**
         * Returns true iff the given id has an associated persistent
         * failure.
         */
        private boolean hasPersistentFailure(String id)
        {
            List failures = (List)failureExceptions.get(id);
            return (failureExceptions != null 
                    && failureExceptions.size() >= MAX_FAILURES);
        }
d492 1
d497 1
a497 1
                            if (t instanceof ToolEventPropagationFailed)
d499 8
a506 2
                                clearEvent = handleFailure
                                    (event, (ToolEventPropagationFailed)t);
d535 1
a535 2
        private boolean handleFailure(ToolEvent event, 
                                      ToolEventPropagationFailed e)
d545 1
d555 1
d557 6
a564 1

@


1.3
log
@Made architectural changes neccessary to support rebroadcast on propagation failure.
@
text
@d82 1
a82 1
 * @@version $Id: ToolEventPropagationService.java,v 1.2 2001/08/20 19:09:12 leonardr Exp $
d341 1
a341 1
         * Map of tool event IDs to failure messages.
d343 6
a348 1
        private Map failureMessages = new HashMap();
d354 1
a354 1
        private boolean persistentFailure(String id)
d356 3
a358 3
            List failures = (List)failureMessages.get(id);
            return (failureMessages != null 
                    && failureMessages.size() >= MAX_FAILURES);
d399 4
a402 2
                processToolEvent(e);
                i.remove();
d409 3
d413 1
a413 1
        private void processToolEvent(ToolEvent event)
d416 1
d461 17
a477 1
                        m.invoke(null, objects);
d480 6
a485 3
                CompletionEvent ce = new CompletionEvent(event);
                ClusterService.getService().sendEvent
                    (ToolEventPropagationService.getService(), ce);
d491 1
d493 31
@


1.2
log
@Tool event propagation now has singleton failover (but not persistence over restarts).
@
text
@d71 1
d82 1
a82 1
 * @@version $Id: ToolEventPropagationService.java,v 1.1 2001/08/17 21:51:50 leonardr Exp $
d102 1
a102 2
     * Contains Sets of Methods with the same signature, keyed by 
     * MethodSignature objects.
d104 1
a104 1
    private Map methodsBySignature = new HashMap();
d136 1
a136 1
            throw new Error("Unable to initialize ToolEventPropagator!");
d177 1
a177 1

d195 1
a195 1
        methodsBySignature.clear();
d204 2
d207 1
a207 1
                registerClass(Class.forName(listenerClassName));
d224 1
a224 1
    private void registerClass(Class classInstance)
d231 8
a238 4
            MethodSignature signature = new MethodSignature(m);
            Set methodsForSignature = methodsWithSignature(signature);
            methodsForSignature.add(m);
            methodsBySignature.put(signature, methodsForSignature);
d240 1
a240 9
    }

    /**
     * Returns all the methods which match the given signature.
     */
    private Set methodsWithSignature(MethodSignature signature)
    {
        Set methodsForSignature = (Set)methodsBySignature.get(signature);
        if (methodsForSignature == null)
d242 1
a242 1
            methodsForSignature = new HashSet();
a243 1
        return methodsForSignature;
d290 17
a306 1
        for (Iterator i = methodsBySignature.keySet().iterator(); i.hasNext();)
d308 3
a310 4
            MethodSignature signature = (MethodSignature)i.next();
            Set methods = methodsWithSignature(signature);

            s.append("For signature " + signature + ":\n");
d323 11
d337 3
a339 1
    {
d341 1
a341 1
         * The number of tasks which have been run
d343 2
a344 2
        private  int runCount = 0;
        
d346 2
a347 1
         * The number of task failures which have occured.
d349 7
a355 2
        private int failureCount = 0;
      
d389 1
a389 1
            throws Exception
d404 1
a404 1
            throws NestableException 
d406 1
d443 3
a445 2
                Set methods = methodsWithSignature(sig);
                for (Iterator i = methods.iterator(); i.hasNext();)
d447 5
a451 2
                    Method m = (Method)i.next();
                    m.invoke(null, objects);
@


1.1
log
@Replaced 'plugins' architecture with ToolEventPropagationService.
@
text
@d69 1
d81 1
a81 1
 * @@version $Id: ToolEventPropagationService.java,v 1.1 2001/08/17 19:40:24 leonardr Exp $
d91 10
d111 1
a111 1

d179 8
d212 1
a212 1
                ("Unable to initialize ToolEventPropagator!");
d214 3
d257 1
a257 1
    
d259 2
a260 2
     * Calls previously registered methods corresponding to this
     * event and its arguments.
d265 109
a373 1
        if (isSingleton && e instanceof ToolEvent)
a374 2
            ToolEvent event = (ToolEvent)e;
            
d391 1
a391 1

a410 1
                Log.debug("Searching for methods with signature " + sig);
a414 1
                    Log.debug("Calling method " + m);
d417 3
d425 1
a425 25
        }
    }    

    /**
     * Describes all the methods currently registered with the
     * propagator.
     */
    private String describeRegisteredMethods()
    {
        StringBuffer s = new StringBuffer();
        for (Iterator i = methodsBySignature.keySet().iterator(); i.hasNext();)
        {
            MethodSignature signature = (MethodSignature)i.next();
            Set methods = methodsWithSignature(signature);

            s.append("For signature " + signature + ":\n");
            for (Iterator j = methods.iterator(); j.hasNext();)
            {
                Method m = (Method)j.next();
                s.append("    " + m.getDeclaringClass().getName() 
                         + '.' + m.getName() + '\n');
            }
            s.append('\n');
        }
        return s.toString();
@

