001/*
002 * (C) Copyright 2006-2017 Nuxeo (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 *     Kevin Leturc <kleturc@nuxeo.com>
019 */
020package org.nuxeo.runtime.services.event;
021
022import java.util.HashMap;
023import java.util.Hashtable;
024import java.util.Map;
025
026import org.apache.commons.lang3.ArrayUtils;
027import org.apache.commons.logging.Log;
028import org.apache.commons.logging.LogFactory;
029import org.nuxeo.common.collections.ListenerList;
030import org.nuxeo.runtime.model.ComponentContext;
031import org.nuxeo.runtime.model.ComponentName;
032import org.nuxeo.runtime.model.DefaultComponent;
033import org.nuxeo.runtime.model.Extension;
034
035/**
036 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
037 */
038public class EventService extends DefaultComponent {
039
040    public static final ComponentName NAME = new ComponentName("org.nuxeo.runtime.EventService");
041
042    private static final Log log = LogFactory.getLog(EventService.class);
043
044    private final Map<String, ListenerList> topics;
045
046    private final Map<String, Object[]> contributions;
047
048    public EventService() {
049        topics = new HashMap<>();
050        contributions = new Hashtable<>();
051    }
052
053    @Override
054    public void deactivate(ComponentContext context) {
055        topics.clear();
056        contributions.clear();
057    }
058
059    @Override
060    public void registerExtension(Extension extension) {
061        Object[] descriptors = extension.getContributions();
062        if (ArrayUtils.isEmpty(descriptors)) {
063            return;
064        }
065        String name = extension.getId();
066        synchronized (this) {
067            for (Object desc : descriptors) {
068                ListenerDescriptor lDesc = (ListenerDescriptor) desc;
069                for (String topic : lDesc.topics) {
070                    addListener(topic, lDesc.listener);
071                }
072            }
073            contributions.put(name, descriptors);
074        }
075    }
076
077    @Override
078    public void unregisterExtension(Extension extension) {
079        String name = extension.getId();
080        synchronized (this) {
081            Object[] descriptors = contributions.remove(name);
082            if (descriptors != null) {
083                for (Object desc : descriptors) {
084                    ListenerDescriptor lDesc = (ListenerDescriptor) desc;
085                    for (String topic : lDesc.topics) {
086                        removeListener(topic, lDesc.listener);
087                    }
088                }
089            }
090        }
091    }
092
093    public void sendEvent(Event event) {
094        ListenerList list = topics.get(event.getTopic());
095        if (list == null) {
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        }
110        list.add(listener);
111    }
112
113    public synchronized void removeListener(String topic, EventListener listener) {
114        ListenerList list = topics.get(topic);
115        if (list != null) {
116            list.remove(listener);
117            if (list.isEmpty()) {
118                topics.remove(topic);
119            }
120        }
121    }
122
123    private static void sendEvent(ListenerList list, Event event) {
124        Object[] listeners = list.getListeners();
125        for (Object listener : listeners) {
126            ((EventListener) listener).handleEvent(event);
127        }
128    }
129
130    @Override
131    @SuppressWarnings("unchecked")
132    public <T> T getAdapter(Class<T> adapter) {
133        return adapter == getClass() ? (T) this : null;
134    }
135
136}