Package org.apache.cocoon.portal.event.impl

Source Code of org.apache.cocoon.portal.event.impl.DefaultEventManager

/*
* Copyright 1999-2002,2004-2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.portal.event.impl;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.activity.Initializable;
import org.apache.avalon.framework.configuration.Configurable;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;
import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.avalon.framework.context.Context;
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.service.ServiceSelector;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.avalon.framework.thread.ThreadSafe;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.portal.PortalService;
import org.apache.cocoon.portal.event.Event;
import org.apache.cocoon.portal.event.EventConverter;
import org.apache.cocoon.portal.event.EventManager;
import org.apache.cocoon.portal.event.Publisher;
import org.apache.cocoon.portal.event.Receiver;
import org.apache.cocoon.portal.event.Register;
import org.apache.cocoon.portal.event.Subscriber;
import org.apache.cocoon.portal.event.aspect.EventAspect;
import org.apache.cocoon.util.ClassUtils;
import org.apache.cocoon.util.Deprecation;

/**
* This is the default implementation of the event manager.
*
* @author <a href="mailto:cziegeler@s-und-n.de">Carsten Ziegeler</a>
* @author <a href="mailto:volker.schmitt@basf-it-services.com">Volker Schmitt</a>
*
* @version CVS $Id: DefaultEventManager.java 219049 2005-07-14 15:11:52Z cziegeler $
*/
public class DefaultEventManager
    extends AbstractLogEnabled
    implements EventManager,
                Serviceable,
                Initializable,
                ThreadSafe,
                Configurable,
                Disposable,
                Contextualizable,
                Publisher, Register {
                   
    private final String rootEventType = Event.class.getName();
    private Class eventClass;
    /** The list of all subscribers. */
    private List subscribers = new ArrayList();
    /** The list of all receivers */
    private Map receivers = new HashMap();

    private ServiceManager manager;
    private Configuration configuration;
   
    protected EventAspectChain chain;
   
    protected ServiceSelector aspectSelector;

    protected Context context;

    /** The portal service */
    protected PortalService service;

    /** Introspected receiver classes */
    protected Map receiverClasses = new HashMap();

    /**
     * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
     */
    public void service(ServiceManager manager) throws ServiceException {
        this.manager = manager;
        this.service = (PortalService)manager.lookup(PortalService.ROLE);
    }

    /* (non-Javadoc)
     * @see org.apache.cocoon.portal.event.EventManager#getPublisher()
     */
    public Publisher getPublisher() {
        return this;
    }
   
    /* (non-Javadoc)
     * @see org.apache.cocoon.portal.event.EventManager#getRegister()
     */
    public Register getRegister() {
        return this;
    }
   
    /**
     * Helper method to get the current object model
     */
    protected Map getObjectModel() {
        return ContextHelper.getObjectModel( this.context );
    }

    /* (non-Javadoc)
     * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
     */
    public void configure(Configuration conf)
    throws ConfigurationException {
        this.configuration = conf;
    }

    /* (non-Javadoc)
     * @see org.apache.avalon.framework.activity.Disposable#dispose()
     */
    public void dispose() {
        if (this.manager != null) {
            if ( this.chain != null) {
                this.chain.dispose( this.aspectSelector );
            }
            this.manager.release( this.aspectSelector );
            this.aspectSelector = null;
            this.manager.release(this.service);
            this.service = null;
            this.manager = null;
        }
    }

    /* (non-Javadoc)
     * @see org.apache.avalon.framework.activity.Initializable#initialize()
     */
    public void initialize()
    throws Exception {
        this.eventClass = Class.forName( rootEventType );
        if ( this.getLogger().isDebugEnabled() ) {
            this.getLogger().debug("Initialising eventClass " + eventClass);
        }

        // FIXME - the following configuration is not portal specific, it's global!
        // subscribe all configured roles
        Configuration roles = this.configuration.getChild("subscriber-roles", false);
        if ( roles != null ) {
            Configuration[] rolesConf = roles.getChildren("role");
            for(int i=0; i<rolesConf.length;i++) {
                final Configuration current = rolesConf[i];
                final String name = current.getAttribute("name");
               
                Subscriber subscriber = null;
                try {
                    subscriber = (Subscriber) this.manager.lookup(name);
                    Deprecation.logger.warn("Subscriber is deprecated. Please convert the following component to a Receiver: " + subscriber.getClass().getName());
                    this.subscribe(subscriber);
                } finally {
                    this.manager.release(subscriber);
                }
            }
        }
        // subscribe all configured classes
        Configuration classes = this.configuration.getChild("subscriber-classes", false);
        if ( classes != null ) {
            Configuration[] classesConf = classes.getChildren("class");
            for(int i=0; i<classesConf.length;i++) {
                final Configuration current = classesConf[i];
                final String name = current.getAttribute("name");
               
                Deprecation.logger.warn("Subscriber is deprecated. Please convert the following component to a Receiver: " + name);
                Subscriber subscriber = (Subscriber) ClassUtils.newInstance(name);
                ContainerUtil.enableLogging(subscriber, this.getLogger());
                ContainerUtil.contextualize(subscriber, this.context);
                ContainerUtil.service(subscriber, this.manager );
                ContainerUtil.initialize(subscriber);
                this.subscribe(subscriber);
            }
        }
        // subscribe all configured receiver roles
        roles = this.configuration.getChild("receiver-roles", false);
        if ( roles != null ) {
            Configuration[] rolesConf = roles.getChildren("role");
            for(int i=0; i<rolesConf.length;i++) {
                final Configuration current = rolesConf[i];
                final String name = current.getAttribute("name");
               
                Receiver receiver = null;
                try {
                    receiver = (Receiver) this.manager.lookup(name);
                    this.subscribe(receiver);
                } finally {
                    this.manager.release(receiver);
                }
            }
        }
        // subscribe all configured receiver classes
        classes = this.configuration.getChild("receiver-classes", false);
        if ( classes != null ) {
            Configuration[] classesConf = classes.getChildren("class");
            for(int i=0; i<classesConf.length;i++) {
                final Configuration current = classesConf[i];
                final String name = current.getAttribute("name");
               
                Receiver receiver = (Receiver)ClassUtils.newInstance(name);
                ContainerUtil.enableLogging(receiver, this.getLogger());
                ContainerUtil.contextualize(receiver, this.context);
                ContainerUtil.service(receiver, this.manager );
                ContainerUtil.initialize(receiver);
                this.subscribe(receiver);
            }
        }

    }

    /* (non-Javadoc)
     * @see org.apache.cocoon.portal.event.Publisher#publish(org.apache.cocoon.portal.event.Event)
     */
    public void publish( final Event event ) {
        this.send(event);       
    }
   
    /* (non-Javadoc)
     * @see org.apache.cocoon.portal.event.Register#subscribe(org.apache.cocoon.portal.event.Subscriber)
     */
    public void subscribe( final Subscriber subscriber ) {
        if ( !eventClass.isAssignableFrom( subscriber.getEventType() ) ) {
            throw new RuntimeException("Invalid event type " + subscriber.getEventType()
                                      +" for subscriber " + subscriber);
        }

        if ( getLogger().isDebugEnabled() ) {
            getLogger().debug( "Subscribing event " + subscriber.getEventType().getName() );
        }
       
        // Add to list but prevent duplicate subscriptions
        if ( !subscribers.contains( subscriber ) ) {
            subscribers.add( subscriber );
            if ( getLogger().isDebugEnabled() ) {
                getLogger().debug( "Subscribed Event " + subscriber.getEventType().getName() );
                getLogger().debug( "Subscribers now active: " + subscribers.size() );
            }
        }
    }
   
    /* (non-Javadoc)
     * @see org.apache.cocoon.portal.event.Register#unsubscribe(org.apache.cocoon.portal.event.Subscriber)
     */
    public void unsubscribe( Subscriber subscriber ) {
       
        if ( !eventClass.isAssignableFrom( subscriber.getEventType() ) ) {
            throw new RuntimeException("Invalid event type " + subscriber.getEventType()
                    +" for unsubscribing " + subscriber);
        }
        if ( subscribers.contains( subscriber ) ) {
            subscribers.remove( subscriber );
            if ( getLogger().isDebugEnabled() ) {
                getLogger().debug( "Unsubscribed Event " + subscriber.getEventType().getName() );
                getLogger().debug( "Subscribers now active: " + subscribers.size() );
            }
        } else {
            getLogger().warn( "Subscriber " + subscriber + " not found" );
        }
    }

    /* (non-Javadoc)
     * @see org.apache.cocoon.portal.event.EventManager#processEvents()
     */
    public void processEvents()
    throws ProcessingException {
        if ( this.configuration != null ) {
            try {
                this.aspectSelector = (ServiceSelector) this.manager.lookup( EventAspect.ROLE+"Selector");
                this.chain = new EventAspectChain();
                this.chain.configure(this.aspectSelector, this.configuration.getChild("event-aspects"));
            } catch (ConfigurationException ce) {
                throw new ProcessingException("Unable configure component.", ce);
            } catch (ServiceException ce) {
                throw new ProcessingException("Unable to lookup component.", ce);
            }
            this.configuration = null;
        }
        DefaultEventAspectContext context = new DefaultEventAspectContext(this.chain);
        EventConverter converter = null;
        PortalService service = null;
        try {
            service = (PortalService)this.manager.lookup(PortalService.ROLE);
            converter = (EventConverter) this.manager.lookup(EventConverter.ROLE);
            Publisher publisher = this.getPublisher();

            converter.start();
           
            // Invoke aspects
            context.setEventPublisher( publisher );
            context.setObjectModel(this.getObjectModel());
            context.setEventConverter(converter);
            context.invokeNext( service );

            converter.finish();

        } catch (ServiceException ce) {
            throw new ProcessingException("Unable to lookup component.", ce);
        } finally {
            this.manager.release(converter);
            this.manager.release(service);
        }

    }

    /**
     * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
     */
    public void contextualize(Context context)
    throws ContextException {
        this.context = context;
    }

    /**
     * @see org.apache.cocoon.portal.event.EventManager#send(org.apache.cocoon.portal.event.Event)
     */
    public void send(Event event) {
        if ( getLogger().isDebugEnabled() ) {
            getLogger().debug("Publishing event " + event.getClass());
        }
        for ( Iterator e = subscribers.iterator(); e.hasNext(); ){
            Subscriber subscriber = (Subscriber)e.next();
            if (subscriber.getEventType().isAssignableFrom(event.getClass())
            && (subscriber.getFilter() == null || subscriber.getFilter().filter(event))) {
                if ( getLogger().isDebugEnabled() ) {
                    getLogger().info("Informing subscriber "+subscriber+" of event "+event.getClass());
                }
                subscriber.inform(event);
            }
        }
        for (Iterator re = receivers.entrySet().iterator(); re.hasNext(); ) {
            final Map.Entry current = (Map.Entry)re.next();
            final Receiver receiver = (Receiver)current.getKey();
            final List methodInfos = (List)current.getValue();
            boolean found = false;
            final Iterator ci = methodInfos.iterator();
            while ( !found && ci.hasNext() ) {
                final MethodInfo info = (MethodInfo)ci.next();
                if ( info.eventClass.isAssignableFrom(event.getClass()) ) {
                    if ( getLogger().isDebugEnabled() ) {
                        getLogger().info("Informing receiver "+receiver+" of event "+event.getClass());
                    }
                    try {
                        info.method.invoke(receiver, new Object[] {event, this.service});
                    } catch (Exception ignore) {
                        this.getLogger().warn("Exception during event dispatching on receiver " + receiver
                                             +" and event " + event, ignore);
                    }
                    found = true;
                }
            }
        }
    }

    protected static final class MethodInfo {
       
        public Class eventClass;
        public Method method;
    }

    protected synchronized List introspect(Class receiverClass) {
        List result = (List)this.receiverClasses.get(receiverClass.getName());
        if ( result == null ) {
            result = new ArrayList();
            Method[] methods = receiverClass.getMethods();
            for(int i=0; i<methods.length; i++ ) {
                final Method current = methods[i];
                if ( current.getName().equals("inform") ) {
                    final Class[] params = current.getParameterTypes();
                    if ( params.length == 2
                         && params[1].getName().equals(PortalService.class.getName())) {
                        if ( eventClass.isAssignableFrom( params[0] ) ) {
                            MethodInfo info = new MethodInfo();
                            info.eventClass = params[0];
                            info.method = current;
                            result.add(info);
                        }
                    }
                }
            }
            if ( result.size() == 0 ) {
                result = null;
            }
        }
        return result;
    }
    /**
     * @see org.apache.cocoon.portal.event.EventManager#subscribe(org.apache.cocoon.portal.event.Receiver)
     */
    public void subscribe(Receiver receiver) {
        List infos = this.introspect(receiver.getClass());
        if ( infos == null ) {
            throw new RuntimeException("Invalid event receiver type: " + receiver);
        }

        // Add to list but prevent duplicate subscriptions
        List eventClassesForReceiver = (List)this.receivers.get(receiver);
        if ( eventClassesForReceiver == null ) {
            this.receivers.put(receiver, infos);
        }
        if ( getLogger().isDebugEnabled() ) {
            for(int i=0; i<infos.size();i++) {
                getLogger().debug( "Receiver " + receiver + " subscribed for event: " + ((MethodInfo)infos.get(i)).eventClass.getName() );
            }
        }
    }

    /**
     * @see org.apache.cocoon.portal.event.EventManager#unsubscribe(org.apache.cocoon.portal.event.Receiver)
     */
    public void unsubscribe(Receiver receiver) {
        if ( getLogger().isDebugEnabled() ) {
            getLogger().debug( "Receiver " + receiver + " unsubscribed.");
        }
        this.receivers.remove(receiver);
    }

}
TOP

Related Classes of org.apache.cocoon.portal.event.impl.DefaultEventManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.