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}