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}