/**
* Copyright 2005 Bushe Enterprises, Inc., Hopkinton, MA, USA, www.bushe.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.bushe.swing.event;
import javax.swing.*;
import java.util.Arrays;
import java.util.List;
/**
* An {@link EventService} implementation for Swing.
* <p/>
* This class is Swing thread-safe. All publish() calls NOT on the Swing EventDispatchThread thread are queued onto the
* EDT. If the calling thread is the EDT, then this is a simple pass-through (i.e the subscribers are notified on the
* same stack frame, just like they would be had they added themselves via Swing addXXListener methods).
*
* @author Michael Bushe michael@bushe.com
*/
public class SwingEventService extends ThreadSafeEventService {
/**
* By default, the SwingEventService is constructed such that any listener that takes over 200 ms causes an
* SubscriberTimingEvent to be published. You will need to add a subscriber to this event. Note that if you use
* event to launch a modal dialog, the timings will be as long as the dialog is up - this is the way Swing works.
*/
public SwingEventService() {
super((long) 200, false, null, null, null);
}
public SwingEventService(Long timeThresholdForEventTimingEventPublication) {
super(timeThresholdForEventTimingEventPublication, false, null, null, null);
}
/**
* Create a SwingEventService is such that any listener that takes over timeThresholdForEventTimingEventPublication
* milliseconds causes an EventSubscriberTimingEvent to be published. You can add a subscriber to this event or set
* subscribeTimingEventsInternally to true to cause the default logging to occur through the protected {@link
* #subscribeTiming(SubscriberTimingEvent)} call.
* <p/>
* Note that if you use event to launch a modal dialog, the timings will be as long as the dialog is up - this is the
* way Swing works.
*
* @param timeThresholdForEventTimingEventPublication the longest time a subscriber should spend handling an event,
* The service will publish an SubscriberTimingEvent after listener processing if the time was exceeded. If null, no
* SubscriberTimingEvent will be issued.
* @param subscribeTimingEventsInternally add a subscriber to the EventSubscriberTimingEvent internally and call the
* protected {@link #subscribeTiming(SubscriberTimingEvent)} method when they occur. This logs a warning to the
* {@link Logger} logger by default.
*
* @throws IllegalArgumentException if timeThresholdForEventTimingEventPublication is null and
* subscribeTimingEventsInternally is true.
*/
public SwingEventService(Long timeThresholdForEventTimingEventPublication, boolean subscribeTimingEventsInternally) {
super(timeThresholdForEventTimingEventPublication, subscribeTimingEventsInternally, null, null, null);
}
/**
* Same as ThreadSafeEventService.publish(), except if the call is coming from a thread that is not the Swing Event
* Dispatch Thread, the request is put on the EDT through a a call to SwingUtilities.invokeLater(). Otherwise this
* DOES NOT post a new event on the EDT. The subscribers are called on the same EDT event, just like addXXXListeners
* would be.
*/
protected void publish(final Object event, final String topic, final Object eventObj,
final List subscribers, final List vetoSubscribers, final StackTraceElement[] callingStack) {
if (SwingUtilities.isEventDispatchThread()) {
super.publish(event, topic, eventObj, subscribers, vetoSubscribers, callingStack);
} else {
//Make call to this method - stick on the EDT if not on the EDT
//Check the params first so that this thread can get the exception thrown
SwingUtilities.invokeLater(new Runnable() {
public void run() {
if (LOG.isLoggable(Logger.Level.DEBUG)) {
LOG.debug("publish(" + event + "," + topic + "," + eventObj
+ "), called from non-EDT Thread:" + Arrays.toString(callingStack));
}
SwingEventService.super.publish(event, topic, eventObj, subscribers, vetoSubscribers, callingStack);
}
});
}
}
}