All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.scijava.event.DefaultEventBus Maven / Gradle / Ivy

/*
 * #%L
 * SciJava Common shared library for SciJava software.
 * %%
 * Copyright (C) 2009 - 2017 Board of Regents of the University of
 * Wisconsin-Madison, Broad Institute of MIT and Harvard, Max Planck
 * Institute of Molecular Cell Biology and Genetics, University of
 * Konstanz, and KNIME GmbH.
 * %%
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * #L%
 */

package org.scijava.event;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;

import org.bushe.swing.event.CleanupEvent;
import org.bushe.swing.event.ThreadSafeEventService;
import org.scijava.log.LogService;
import org.scijava.service.Service;
import org.scijava.thread.ThreadService;

/**
 * An {@link org.bushe.swing.event.EventService} implementation for SciJava.
 * 

* It is called "DefaultEventBus" rather than "DefaultEventService" to avoid a * name clash with {@link DefaultEventService}, which is not an * {@link org.bushe.swing.event.EventService} but rather a SciJava * {@link Service} implementation. *

* * @author Curtis Rueden */ public class DefaultEventBus extends ThreadSafeEventService { private final ThreadService threadService; private final LogService log; public DefaultEventBus(final ThreadService threadService, final LogService log) { super(200L, false, null, null, null); this.threadService = threadService; this.log = log; } // -- DefaultEventBus methods -- public void publishNow(final Object event) { if (event == null) { throw new IllegalArgumentException("Cannot publish null event."); } publishNow(event, null, null, getSubscribers(event.getClass()), getVetoSubscribers(event.getClass()), null); } public void publishNow(final Type genericType, final Object event) { if (genericType == null) { throw new IllegalArgumentException("genericType must not be null."); } if (event == null) { throw new IllegalArgumentException("Cannot publish null event."); } publishNow(event, null, null, getSubscribers(genericType), null, null); } public void publishNow(final String topicName, final Object eventObj) { publishNow(null, topicName, eventObj, getSubscribers(topicName), getVetoEventListeners(topicName), null); } public void publishLater(final Object event) { if (event == null) { throw new IllegalArgumentException("Cannot publish null event."); } publishLater(event, null, null, getSubscribers(event.getClass()), getVetoSubscribers(event.getClass()), null); } public void publishLater(final Type genericType, final Object event) { if (genericType == null) { throw new IllegalArgumentException("genericType must not be null."); } if (event == null) { throw new IllegalArgumentException("Cannot publish null event."); } publishLater(event, null, null, getSubscribers(genericType), null, null); } public void publishLater(final String topicName, final Object eventObj) { publishLater(null, topicName, eventObj, getSubscribers(topicName), getVetoEventListeners(topicName), null); } // -- org.bushe.swing.event.EventService methods -- @Override public void publish(final Object event) { // HACK: Work around a deadlock problem caused by ThreadSafeEventService: // 1) The ThreadSafeEventService superclass has a special cleanup thread // that takes care of cleaning up stale references. Every time it runs, it // publishes some CleanupEvents using publish(Object) to announce that this // is occurring. Normally, such publication delegates to // publishNow, which calls ThreadService#invoke, which calls // EventQueue.invokeAndWait, which queues the publication for execution on // the EDT and then blocks until publication is complete. // 2) When the ThreadSafeEventService publishes the CleanupEvents, it does // so inside a synchronized block that locks on a "listenerLock" object. // 3) Unfortunately, since the CleanupEvent publication is merely *queued*, // any other pending operations on the EDT happen first. If one such // operation meanwhile calls e.g. // ThreadSafeEventService#getSubscribers(Class), it will deadlock because // those getter methods are also synchronized on the listenerLock object. // Hence, our hack workaround is to instead use publishLater for the // CleanupEvents, since no one really cares about them anyway. ;-) if (event instanceof CleanupEvent) { publishLater(event); return; } publishNow(event); } @Override public void publish(final Type genericType, final Object event) { publishNow(genericType, event); } @Override public void publish(final String topicName, final Object eventObj) { publishNow(topicName, eventObj); } // -- Internal methods -- @Override protected void publish(final Object event, final String topic, final Object eventObj, @SuppressWarnings("rawtypes") final List subscribers, @SuppressWarnings("rawtypes") final List vetoSubscribers, final StackTraceElement[] callingStack) { publishNow(event, topic, eventObj, subscribers, vetoSubscribers, callingStack); } // -- Helper methods -- private void publishNow(final Object event, final String topic, final Object eventObj, @SuppressWarnings("rawtypes") final List subscribers, @SuppressWarnings("rawtypes") final List vetoSubscribers, final StackTraceElement[] callingStack) { if (subscribers == null || subscribers.isEmpty()) return; try { threadService.invoke(new Runnable() { @Override public void run() { log.debug("publish(" + event + "," + topic + "," + eventObj + "), called from non-EDT Thread:" + Arrays.toString(callingStack)); DefaultEventBus.super.publish(event, topic, eventObj, subscribers, vetoSubscribers, callingStack); } }); } catch (final InterruptedException exc) { log.error(exc); } catch (final InvocationTargetException exc) { log.error(exc); } } private void publishLater(final Object event, final String topic, final Object eventObj, @SuppressWarnings("rawtypes") final List subscribers, @SuppressWarnings("rawtypes") final List vetoSubscribers, final StackTraceElement[] callingStack) { if (subscribers == null || subscribers.isEmpty()) return; threadService.run(new Runnable() { @Override public void run() { log.debug("publish(" + event + "," + topic + "," + eventObj + "), called from non-EDT Thread:" + Arrays.toString(callingStack)); DefaultEventBus.super.publish(event, topic, eventObj, subscribers, vetoSubscribers, callingStack); } }); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy