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


1.2
date	2001.08.17.21.51.50;	author leonardr;	state dead;
branches;
next	1.1;

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


desc
@@


1.2
log
@Replaced 'plugins' architecture with ToolEventPropagationService.
@
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.turbine.util.Log;
import org.apache.commons.util.exception.NestableException;
import org.apache.commons.collections.ExtendedProperties;

import org.tigris.helm.event.ClusterEvent;
import org.tigris.helm.event.ToolEvent;

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: ToolEventPropagatorService.java,v 1.1 2001/08/17 19:40:24 leonardr Exp $
 */
public class ToolEventPropagatorService extends ClusteredSingletonService
{
    /**
     * Name of this service.
     */
    private static final String SERVICE_NAME = "ToolEventPropagator";

    /**
     * Contains Sets of Methods with the same signature, keyed by 
     * MethodSignature objects.
     */
    private Map methodsBySignature = 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 ToolEventPropagator!");
        }
        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 ToolEventPropagatorService getService()
    {
        return (ToolEventPropagatorService)TurbineServices
            .getInstance().getService(SERVICE_NAME);
    }

    /**
     * Constructor; initialize to not being the singleton.
     */
    public ToolEventPropagatorService()
    {
        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();
    }

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

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

    /**
     * Registers the methods of the named class with the event propagator.
     */
    private void registerClass(Class classInstance)
        throws Exception
    {
        Method[] methods = classInstance.getDeclaredMethods();
        for (int i = 0; i < methods.length; i++)
        {
            Method m = methods[i];
            MethodSignature signature = new MethodSignature(m);
            Set methodsForSignature = methodsWithSignature(signature);
            methodsForSignature.add(m);
            methodsBySignature.put(signature, methodsForSignature);
        }
    }

    /**
     * Returns all the methods which match the given signature.
     */
    private Set methodsWithSignature(MethodSignature signature)
    {
        Set methodsForSignature = (Set)methodsBySignature.get(signature);
        if (methodsForSignature == null)
        {
            methodsForSignature = new HashSet();
        }
        return methodsForSignature;
    }

    /**
     * Sends an event across the wire to be propagated to tools.
     */
    public void propagate(ToolEvent e)
        throws NestableException
    {
        ClusterService.getService().sendEvent(this, e);
    }
    
    /**
     * Calls previously registered methods corresponding to this
     * event and its arguments.
     */
    public void eventReceived(ClusterEvent e)
        throws NestableException
    {
        if (isSingleton && e instanceof ToolEvent)
        {
            ToolEvent event = (ToolEvent)e;
            
            String[] peerClassNames = event.getPeers();
            String[] keys = event.getKeys();        
            
            Class[] peerClasses = new Class[peerClassNames.length];
            BaseObject[] objects = new BaseObject[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.
                    Method m = peerClass.getMethod
                        (PEER_KEY_METHOD, PEER_KEY_PARAMETERS);
                    ObjectKey[] arguments = {key};
                    objects[i] = (BaseObject)m.invoke(null, arguments);
                    objectClasses[i] = objects[i].getClass();
                }
                
                MethodSignature sig = new MethodSignature(event.getName(), 
                                                          objectClasses);
                Set methods = methodsWithSignature(sig);
                for (Iterator i = methods.iterator(); i.hasNext();)
                {
                    Method m = (Method)i.next();
                    Log.debug("Calling method " + m);
                    m.invoke(null, objects);
                }
            }
            catch (Exception ex)
            {
                throw new NestableException(ex);
            }
        }
    }    

    /**
     * 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();
    }
}
@


1.1
log
@First stab at an implementation of the Helm event propagation mechanism.
@
text
@d80 1
a80 1
 * @@version $Id: EventPropagator.java,v 1.31 2001/05/14 12:40:12 edk Exp $
@

