001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     Nuxeo - initial API and implementation
011 *
012 * $Id$
013 */
014
015package org.nuxeo.runtime.services.event;
016
017import java.util.HashMap;
018import java.util.Hashtable;
019import java.util.Map;
020
021import org.apache.commons.logging.Log;
022import org.apache.commons.logging.LogFactory;
023import org.nuxeo.common.collections.ListenerList;
024import org.nuxeo.runtime.model.ComponentContext;
025import org.nuxeo.runtime.model.ComponentName;
026import org.nuxeo.runtime.model.DefaultComponent;
027import org.nuxeo.runtime.model.Extension;
028
029/**
030 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
031 */
032public class EventService extends DefaultComponent {
033
034    public static final ComponentName NAME = new ComponentName("org.nuxeo.runtime.EventService");
035
036    private static final Log log = LogFactory.getLog(EventService.class);
037
038    private final Map<String, ListenerList> topics;
039
040    // private final Map<String, Collection<Event>> pendingEvents;
041
042    private final Map<String, Object[]> contributions;
043
044    // private Executor threadPool = Executors.newCachedThreadPool();
045
046    public EventService() {
047        topics = new HashMap<String, ListenerList>();
048        // pendingEvents = new HashMap<String, Collection<Event>>();
049        contributions = new Hashtable<String, Object[]>();
050    }
051
052    @Override
053    public void deactivate(ComponentContext context) {
054        topics.clear();
055        contributions.clear();
056    }
057
058    @Override
059    public void registerExtension(Extension extension) {
060        Object[] descriptors = extension.getContributions();
061        if (descriptors.length == 0) {
062            return;
063        }
064        String name = extension.getId();
065        synchronized (this) {
066            for (Object desc : descriptors) {
067                ListenerDescriptor lDesc = (ListenerDescriptor) desc;
068                for (String topic : lDesc.topics) {
069                    addListener(topic, lDesc.listener);
070                }
071            }
072            contributions.put(name, descriptors);
073        }
074    }
075
076    @Override
077    public void unregisterExtension(Extension extension) {
078        String name = extension.getId();
079        synchronized (this) {
080            Object[] descriptors = contributions.remove(name);
081            if (descriptors != null) {
082                for (Object desc : descriptors) {
083                    ListenerDescriptor lDesc = (ListenerDescriptor) desc;
084                    for (String topic : lDesc.topics) {
085                        removeListener(topic, lDesc.listener);
086                    }
087                }
088            }
089        }
090    }
091
092    public void sendEvent(Event event) {
093        ListenerList list = topics.get(event.getTopic());
094        if (list == null) {
095            // enqeueEvent(event);
096            if (log.isTraceEnabled()) {
097                log.trace("Event sent to topic " + event.getTopic() + ". Ingnoring");
098            }
099        } else {
100            sendEvent(list, event);
101        }
102    }
103
104    public synchronized void addListener(String topic, EventListener listener) {
105        ListenerList list = topics.get(topic);
106        if (list == null) {
107            list = new ListenerList();
108            topics.put(topic, list);
109            // check if any event is pending
110            // Collection<Event> events = pendingEvents.remove(topic);
111            // if (events != null) {
112            // for (Event event : events) {
113            // sendEvent(list, event);
114            // }
115            // }
116        }
117        list.add(listener);
118    }
119
120    public synchronized void removeListener(String topic, EventListener listener) {
121        ListenerList list = topics.get(topic);
122        if (list != null) {
123            list.remove(listener);
124            if (list.isEmpty()) {
125                topics.remove(topic);
126            }
127        }
128    }
129
130    private static void sendEvent(ListenerList list, Event event) {
131        Object[] listeners = list.getListeners();
132        for (Object listener : listeners) {
133            ((EventListener) listener).handleEvent(event);
134        }
135    }
136
137    // private void enqeueEvent(Event event) {
138    // Collection<Event> events = pendingEvents.get(event.getTopic());
139    // if (events != null) {
140    // events.add(event);
141    // } else {
142    // events = new ArrayList<Event>();
143    // events.add(event);
144    // pendingEvents.put(event.getTopic(), events);
145    // }
146    // }
147
148    // public void sendAsync(final Event event) {
149    // threadPool.execute(new Runnable() {
150    // public void run() {
151    // sendEvent(event);
152    // }
153    // });
154    // }
155
156    @Override
157    @SuppressWarnings("unchecked")
158    public <T> T getAdapter(Class<T> adapter) {
159        return adapter == getClass() ? (T) this : null;
160    }
161
162}