/******************************************************************************* * Copyright (c) 1997, 2008 by ProSyst Software GmbH * http://www.prosyst.com * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * ProSyst Software GmbH - initial API and implementation *******************************************************************************/ package org.eclipse.equinox.internal.wireadmin; import java.util.*; import org.osgi.framework.*; import org.osgi.service.wireadmin.*; /** * This class is responsible for dispatching notifications to WireAdminListeners * and Consumers and Producers. * * @author Stoyan Boshev * @author Pavlin Dobrev * * @version 1.0 */ public class EventDispatcher implements Runnable { private BundleContext bc; private WireAdminImpl wa; private Hashtable refToList; private Vector events; private Object synch = new Object(); private Object listenersLock = new Object(); private boolean running = true; private Thread dispatcher; public EventDispatcher(BundleContext bc, WireAdminImpl wa) { this.bc = bc; this.wa = wa; this.refToList = new Hashtable(5); this.events = new Vector(5, 5); ServiceReference[] sRefs = null; try { sRefs = bc.getServiceReferences(WireAdminListener.class.getName(), null); } catch (InvalidSyntaxException ise) { /* filter is null */ } if (sRefs != null) { WireAdminListener listener; for (int i = 0; i < sRefs.length; i++) { listener = (WireAdminListener) bc.getService(sRefs[i]); if (listener != null) { refToList.put(sRefs[i], listener); } } } dispatcher = new Thread(this, "[WireAdmin] - Event Dispatcher"); dispatcher.start(); } void addEvent(WireAdminEvent evt) { if (dispatcher == null) { // synchronous notifyListeners(new EventData(evt, refToList)); } else { // synchronized (listenersLock) { //because it does not change the // Hashtable; events.addElement(new EventData(evt, refToList)); // } synchronized (synch) { synch.notify(); } } } void addNotificationEvent(NotificationEvent ne) { if (dispatcher == null) { // synchronous notifyConsumerProducer(ne); } else { events.addElement(ne); synchronized (synch) { synch.notify(); } } } private String printWires(Wire[] wires) { if (wires != null) { StringBuffer buff = new StringBuffer(100); buff.append("\n"); for (int i = 0; i < wires.length; i++) { buff.append(wires[i]).append("\n"); } return buff.toString(); } return "null"; } private void notifyConsumerProducer(NotificationEvent ne) { if (Activator.LOG_DEBUG) { Activator.log.debug("Notification event " + ((ne.producer != null) ? "; Producer " + ne.producer : "; Consumer " + ne.consumer) + "; source: " + ne.source + "; wires " + printWires(ne.wires), null); Activator.log.debug(0, 10001, ((dispatcher != null) ? "asynchronous" : "synchronous"), null, false); } if (ne.producer != null) { try { ne.producer.consumersConnected(ne.wires); } catch (Throwable t) { wa.notifyListeners(ne.source, WireAdminEvent.PRODUCER_EXCEPTION, t); } } else if (ne.consumer != null) { try { ne.consumer.producersConnected(ne.wires); } catch (Throwable t) { wa.notifyListeners(ne.source, WireAdminEvent.CONSUMER_EXCEPTION, t); } } } private void notifyListeners(EventData event) { WireAdminEvent evt = (WireAdminEvent) event.event; Hashtable refToList = event.listeners; if (Activator.LOG_DEBUG) { Activator.log.debug(0, 10002, getEvent(evt.getType()) + evt.getWire(), evt.getThrowable(), false); Activator.log.debug(0, 10001, ((dispatcher != null) ? "asynchronous" : "synchronous"), null, false); } for (Enumeration en = refToList.keys(); running && en.hasMoreElements();) { ServiceReference current = (ServiceReference) en.nextElement(); Integer accepts = (Integer) current.getProperty(WireConstants.WIREADMIN_EVENTS); if ((accepts != null) && ((accepts.intValue() & evt.getType()) == evt.getType())) { try { ((WireAdminListener) refToList.get(current)).wireAdminEvent(evt); } catch (Throwable t) { if (Activator.LOG_DEBUG) { Activator.log.debug(0, 10003, ((WireAdminListener) refToList.get(current)).toString(), t, false); } } } } } /** * @param ref */ public void removeListener(ServiceReference ref) { if (refToList.containsKey(ref)) { synchronized (listenersLock) { refToList = (Hashtable) refToList.clone(); if (refToList.remove(ref) != null) { bc.ungetService(ref); } } } } /** * @param ref * @param object */ public void addListener(ServiceReference ref, Object object) { synchronized (listenersLock) { refToList = (Hashtable) refToList.clone(); refToList.put(ref, object); } } public void run() { while (running) { synchronized (synch) { while (running && events.size() == 0) { try { synch.wait(); } catch (InterruptedException ie) { } } } EventData evt = null; NotificationEvent ne = null; while (running && events.size() > 0) { Object event = events.elementAt(0); events.removeElementAt(0); if (event instanceof EventData) { evt = (EventData) event; notifyListeners(evt); } else { ne = (NotificationEvent) event; notifyConsumerProducer(ne); } } } } void terminate() { running = false; if (dispatcher != null) { synchronized (synch) { synch.notify(); } } synchronized (listenersLock) { for (Enumeration en = refToList.keys(); en.hasMoreElements();) { bc.ungetService((ServiceReference) en.nextElement()); } refToList.clear(); refToList = null; } events.removeAllElements(); events = null; } private String getEvent(int type) { switch (type) { case WireAdminEvent.WIRE_CREATED : return "WIRE_CREATED"; case WireAdminEvent.WIRE_CONNECTED : return "WIRE_CONNECTED"; case WireAdminEvent.WIRE_UPDATED : return "WIRE_UPDATED"; case WireAdminEvent.WIRE_TRACE : return "WIRE_TRACE"; case WireAdminEvent.WIRE_DISCONNECTED : return "WIRE_DISCONNECTED"; case WireAdminEvent.WIRE_DELETED : return "WIRE_DELETED"; case WireAdminEvent.PRODUCER_EXCEPTION : return "PRODUCER_EXCEPTION"; case WireAdminEvent.CONSUMER_EXCEPTION : return "CONSUMER_EXCEPTION"; default : return null; } } class EventData { Object event; Hashtable listeners; public EventData(Object event, Hashtable listenersData) { this.event = event; listeners = listenersData; } } }