001/*
002 * (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nuxeo - initial API and implementation
018 *
019 */
020
021package org.nuxeo.runtime.services.event;
022
023import java.util.HashMap;
024import java.util.Hashtable;
025import java.util.Map;
026
027import org.apache.commons.lang.ArrayUtils;
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030
031import org.nuxeo.common.collections.ListenerList;
032import org.nuxeo.runtime.model.ComponentContext;
033import org.nuxeo.runtime.model.ComponentName;
034import org.nuxeo.runtime.model.DefaultComponent;
035import org.nuxeo.runtime.model.Extension;
036
037/**
038 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
039 */
040public class EventService extends DefaultComponent {
041
042    public static final ComponentName NAME = new ComponentName("org.nuxeo.runtime.EventService");
043
044    private static final Log log = LogFactory.getLog(EventService.class);
045
046    private final Map<String, ListenerList> topics;
047
048    // private final Map<String, Collection<Event>> pendingEvents;
049
050    private final Map<String, Object[]> contributions;
051
052    // private Executor threadPool = Executors.newCachedThreadPool();
053
054    public EventService() {
055        topics = new HashMap<>();
056        // pendingEvents = new HashMap<String, Collection<Event>>();
057        contributions = new Hashtable<>();
058    }
059
060    @Override
061    public void deactivate(ComponentContext context) {
062        topics.clear();
063        contributions.clear();
064    }
065
066    @Override
067    public void registerExtension(Extension extension) {
068        Object[] descriptors = extension.getContributions();
069        if (ArrayUtils.isEmpty(descriptors)) {
070            return;
071        }
072        String name = extension.getId();
073        synchronized (this) {
074            for (Object desc : descriptors) {
075                ListenerDescriptor lDesc = (ListenerDescriptor) desc;
076                for (String topic : lDesc.topics) {
077                    addListener(topic, lDesc.listener);
078                }
079            }
080            contributions.put(name, descriptors);
081        }
082    }
083
084    @Override
085    public void unregisterExtension(Extension extension) {
086        String name = extension.getId();
087        synchronized (this) {
088            Object[] descriptors = contributions.remove(name);
089            if (descriptors != null) {
090                for (Object desc : descriptors) {
091                    ListenerDescriptor lDesc = (ListenerDescriptor) desc;
092                    for (String topic : lDesc.topics) {
093                        removeListener(topic, lDesc.listener);
094                    }
095                }
096            }
097        }
098    }
099
100    public void sendEvent(Event event) {
101        ListenerList list = topics.get(event.getTopic());
102        if (list == null) {
103            // enqeueEvent(event);
104            if (log.isTraceEnabled()) {
105                log.trace("Event sent to topic " + event.getTopic() + ". Ingnoring");
106            }
107        } else {
108            sendEvent(list, event);
109        }
110    }
111
112    public synchronized void addListener(String topic, EventListener listener) {
113        ListenerList list = topics.get(topic);
114        if (list == null) {
115            list = new ListenerList();
116            topics.put(topic, list);
117            // check if any event is pending
118            // Collection<Event> events = pendingEvents.remove(topic);
119            // if (events != null) {
120            // for (Event event : events) {
121            // sendEvent(list, event);
122            // }
123            // }
124        }
125        list.add(listener);
126    }
127
128    public synchronized void removeListener(String topic, EventListener listener) {
129        ListenerList list = topics.get(topic);
130        if (list != null) {
131            list.remove(listener);
132            if (list.isEmpty()) {
133                topics.remove(topic);
134            }
135        }
136    }
137
138    private static void sendEvent(ListenerList list, Event event) {
139        Object[] listeners = list.getListeners();
140        for (Object listener : listeners) {
141            ((EventListener) listener).handleEvent(event);
142        }
143    }
144
145    // private void enqeueEvent(Event event) {
146    // Collection<Event> events = pendingEvents.get(event.getTopic());
147    // if (events != null) {
148    // events.add(event);
149    // } else {
150    // events = new ArrayList<Event>();
151    // events.add(event);
152    // pendingEvents.put(event.getTopic(), events);
153    // }
154    // }
155
156    // public void sendAsync(final Event event) {
157    // threadPool.execute(new Runnable() {
158    // public void run() {
159    // sendEvent(event);
160    // }
161    // });
162    // }
163
164    @Override
165    @SuppressWarnings("unchecked")
166    public <T> T getAdapter(Class<T> adapter) {
167        return adapter == getClass() ? (T) this : null;
168    }
169
170}