/*******************************************************************************
* Copyright (c) 2011, 2015 Wind River Systems, Inc. and others. 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:
* Wind River Systems - initial API and implementation
*******************************************************************************/
package org.eclipse.tcf.te.runtime.events;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.EventListener;
import java.util.EventObject;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtension;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.tcf.te.runtime.activator.CoreBundleActivator;
import org.eclipse.tcf.te.runtime.interfaces.events.IEventFireDelegate;
import org.eclipse.tcf.te.runtime.interfaces.events.IEventListener;
import org.eclipse.tcf.te.runtime.interfaces.tracing.ITraceIds;
import org.eclipse.tcf.te.runtime.utils.Host;
import org.osgi.framework.Bundle;
/**
* The event manager implementation.
*/
public final class EventManager {
// Flag to remember if the extension point has been processed.
private boolean extensionPointProcessed;
// The list of registered listeners.
private final List<ListenerListEntry> listeners = new ArrayList<ListenerListEntry>();
/**
* Runnable implementation to fire a given event to a given listener.
*/
protected static class FireRunnable implements Runnable {
private final IEventListener listener;
private final EventObject event;
/**
* Constructor.
*
* @param listener The event listener. Must not be <code>null</code>.
* @param event The event. Must not be <code>null</code>.
*/
public FireRunnable(IEventListener listener, EventObject event) {
Assert.isNotNull(listener);
Assert.isNotNull(event);
this.listener = listener;
this.event = event;
}
/* (non-Javadoc)
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
listener.eventFired(event);
}
}
/**
* Listener list entry.
* <p>
* Each entry contains a reference to the listener and a list of valid source classes.
* If an event source can be casted to one of the classes the listener is invoked.
*/
private static class ListenerListEntry {
private final IEventListener listener;
private Object[] eventSources;
private ClassNotLoadedItem[] eventSourcesNotLoaded;
private Class<?>[] eventTypes;
private ClassNotLoadedItem[] eventTypesNotLoaded;
/**
* Constructor.
*
* @param listener The listener.
*/
protected ListenerListEntry(IEventListener listener) {
this(listener, null, null, null, null);
}
/**
* Constructor.
*
* @param listener The listener.
* @param eventTypes The event types the listener is interested in.
* @param eventTypesNotLoaded The event types this listener wants to be invoked but could not be loaded.
* @param eventSources The source types for which events should be fired to the listener.
* @param eventSourceNotLoaded The event types this listener wants to be invoked but could not be loaded.
*/
protected ListenerListEntry(IEventListener listener, Class<?>[] eventTypes, ClassNotLoadedItem[] eventTypesNotLoaded, Object[] eventSources, ClassNotLoadedItem[] eventSourcesNotLoaded) {
this.listener = listener;
if (eventTypes == null || eventTypes.length == 0) {
this.eventTypes = null;
} else {
this.eventTypes = eventTypes;
}
if (eventTypesNotLoaded == null || eventTypesNotLoaded.length == 0) {
this.eventTypesNotLoaded = null;
} else {
this.eventTypesNotLoaded = eventTypesNotLoaded;
}
if (eventSources == null || eventSources.length == 0) {
this.eventSources = null;
} else {
this.eventSources = eventSources;
}
if (eventSourcesNotLoaded == null || eventSourcesNotLoaded.length == 0) {
this.eventSourcesNotLoaded = null;
} else {
this.eventSourcesNotLoaded = eventSourcesNotLoaded;
}
}
/**
* Get the listener of this entry.
*/
protected EventListener getListener() {
return listener;
}
/**
* Attempts to load the class specified by the given class
* not found item.
*
* @param item The class not found item. Must not be <code>null</code>.
* @return The class object or <code>null</code>.
*/
private Class<?> loadClass(ClassNotLoadedItem item, String type) {
Assert.isNotNull(item);
Assert.isNotNull(type);
Class<?> clazz = null;
// If a bundle id got specified, use the specified bundle to load the service class
Bundle bundle = Platform.getBundle(item.bundleId);
// If we don't have a bundle to load from yet, fallback to the declaring bundle
if (bundle == null) bundle = Platform.getBundle(item.declaringBundleId);
// And finally, use our own bundle to load the class. This fallback is expected
// to never be used.
if (bundle == null) bundle = CoreBundleActivator.getContext().getBundle();
// If the specified bundle is active, or "forceBundleActivation" is true, the class can be loaded
if (bundle != null && bundle.getState() == Bundle.ACTIVE) {
try {
clazz = bundle.loadClass(item.className);
} catch (Exception ex) {
if (isTracingEnabled())
CoreBundleActivator.getTraceHandler().trace("Error instantiating event listener " + type + " object instance: " + item.className, //$NON-NLS-1$ //$NON-NLS-2$
0, ITraceIds.TRACE_EVENTS, IStatus.ERROR, this);
}
}
return clazz;
}
/**
* Attempt to load event type class objects which could not be loaded
* before because the parent plug-in's are not activated.
*/
private void loadNotLoadedEventTypes() {
if (eventTypesNotLoaded == null || eventTypesNotLoaded.length == 0) return;
List<Class<?>> types = new ArrayList<Class<?>>();
if (eventTypes != null && eventTypes.length > 0) types.addAll(Arrays.asList(eventTypes));
List<ClassNotLoadedItem> notLoaded = new ArrayList<ClassNotLoadedItem>(Arrays.asList(eventTypesNotLoaded));
boolean changed = false;
Iterator<ClassNotLoadedItem> it = notLoaded.iterator();
while (it.hasNext()) {
ClassNotLoadedItem item = it.next();
Class<?> clazz = loadClass(item, "event type"); //$NON-NLS-1$
if (clazz != null) {
it.remove();
changed = true;
if (!types.contains(clazz)) types.add(clazz);
}
}
if (changed) {
eventTypes = types.toArray(new Class<?>[types.size()]);
eventTypesNotLoaded = notLoaded.toArray(new ClassNotLoadedItem[notLoaded.size()]);
}
}
/**
* Attempt to load event source class objects which could not be loaded
* before because the parent plug-in's are not activated.
*/
private void loadNotLoadedEventSources() {
if (eventSourcesNotLoaded == null || eventSourcesNotLoaded.length == 0) return;
List<Object> sources = new ArrayList<Object>();
if (eventSources != null && eventSources.length > 0) sources.addAll(Arrays.asList(eventSources));
List<ClassNotLoadedItem> notLoaded = new ArrayList<ClassNotLoadedItem>(Arrays.asList(eventSourcesNotLoaded));
boolean changed = false;
Iterator<ClassNotLoadedItem> it = notLoaded.iterator();
while (it.hasNext()) {
ClassNotLoadedItem item = it.next();
Class<?> clazz = loadClass(item, "event source type"); //$NON-NLS-1$
if (clazz != null) {
it.remove();
changed = true;
if (!sources.contains(clazz)) sources.add(clazz);
}
}
if (changed) {
eventSources = sources.toArray(new Object[sources.size()]);
eventSourcesNotLoaded = notLoaded.toArray(new ClassNotLoadedItem[notLoaded.size()]);
}
}
/**
* Check whether the listener wants to be called for changes of the source.
* The check is made through <code>instanceof</code>.
*
* @param source The source of the event.
* @return True, if the source can be casted to one of the registered event source types
* or no event sources are registered.
*/
protected boolean listensTo(EventObject event) {
boolean types = ((eventTypes == null || eventTypes.length == 0) && (eventTypesNotLoaded == null || eventTypesNotLoaded.length == 0));
boolean sources = ((eventSources == null || eventSources.length == 0) && (eventSourcesNotLoaded == null || eventSourcesNotLoaded.length == 0));
if (!types) loadNotLoadedEventTypes();
int t = 0;
while (!types && eventTypes != null && t < eventTypes.length) {
types = eventTypes[t].isInstance(event);
t++;
}
if (!sources) loadNotLoadedEventSources();
int s = 0;
while (!sources && eventSources != null && s < eventSources.length) {
Object eventSource = eventSources[s];
if (eventSource instanceof Class<?>) {
Class<?> eventSourceClass = (Class<?>)eventSource;
sources = eventSourceClass.isInstance(event.getSource());
} else {
sources = eventSource == event.getSource();
}
s++;
}
return types && sources;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
if (getListener() != null) {
return getListener().hashCode();
}
return super.hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof ListenerListEntry) {
ListenerListEntry other = (ListenerListEntry)obj;
return this.getListener() == other.getListener();
}
return false;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return getClass().getName() + "{" + //$NON-NLS-1$
"listener=" + listener + //$NON-NLS-1$
",eventTypes=" + Arrays.deepToString(eventTypes) + //$NON-NLS-1$
",eventTypesNotLoaded=" + Arrays.deepToString(eventTypesNotLoaded) + //$NON-NLS-1$
",eventSources=" + Arrays.deepToString(eventSources) + //$NON-NLS-1$
",eventSourcesNotLoaded=" + Arrays.deepToString(eventSourcesNotLoaded) + //$NON-NLS-1$
"}"; //$NON-NLS-1$
}
}
/**
* eventType or eventSourceType extension elements which could not be loaded.
*/
private static class ClassNotLoadedItem {
public final String bundleId;
public final String className;
public final String declaringBundleId;
/**
* Constructor
*
*/
public ClassNotLoadedItem(String bundleId, String className, String declaringBundleId) {
Assert.isNotNull(bundleId);
this.bundleId = bundleId;
Assert.isNotNull(className);
this.className = className;
Assert.isNotNull(declaringBundleId);
this.declaringBundleId = declaringBundleId;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof ClassNotLoadedItem) {
return bundleId.equals(((ClassNotLoadedItem)obj).bundleId)
&& className.equals(((ClassNotLoadedItem)obj).className)
&& declaringBundleId.equals(((ClassNotLoadedItem)obj).declaringBundleId);
}
return false;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return bundleId.hashCode() ^ className.hashCode() ^ declaringBundleId.hashCode();
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return getClass().getName() + "{" + //$NON-NLS-1$
"bundleId=" + bundleId + //$NON-NLS-1$
",className=" + className + //$NON-NLS-1$
",declaringBundleId=" + declaringBundleId + //$NON-NLS-1$
"}"; //$NON-NLS-1$
}
}
/*
* Thread save singleton instance creation.
*/
private static class LazyInstance {
public static EventManager instance = new EventManager();
}
/**
* Private Constructor.
*/
EventManager() {
extensionPointProcessed = false;
}
/**
* Returns the singleton instance for the event manager.
*/
public static EventManager getInstance() {
return LazyInstance.instance;
}
/**
* Add a change listener to listen to a single event.
*
* @param listener The listener to add.
* @param eventType The event type this listeners wants to be invoked.
*/
public void addEventListener(IEventListener listener, Class<?> eventType) {
addEventListener(listener, eventType != null ? new Class[] { eventType } : null, null, null, null);
}
/**
* Add a change listener to listen to multiple events.
*
* @param listener The listener to add.
* @param eventTypes The event types this listeners wants to be invoked.
*/
public void addEventListener(IEventListener listener, Class<?>[] eventTypes) {
addEventListener(listener, eventTypes, null, null, null);
}
/**
* Add a change listener to listen to event from the specified event
* source. If the listener instance had been registered already, the listener
* event sources are updated
*
* @param listener The listener to add.
* @param eventType The event type this listeners wants to be invoked.
* @param eventSource The event source type this listeners wants to be invoked.
*/
public void addEventListener(IEventListener listener, Class<?> eventType, Object eventSource) {
addEventListener(listener, eventType != null ? new Class[] { eventType } : null, null, eventSource != null ? new Object[] { eventSource } : null, null);
}
/**
* Add a change listener to listen to events from the specified event
* sources. If the listener instance had been registered already, the listener
* event sources are updated
*
* @param listener The listener to add.
* @param eventType The event type this listeners wants to be invoked.
* @param eventSources The event sources type this listeners wants to be invoked.
*/
public void addEventListener(IEventListener listener, Class<?> eventType, Object[] eventSources) {
addEventListener(listener, eventType != null ? new Class[] { eventType } : null, null, eventSources, null);
}
/**
* Add a change listener to listen to event from the specified event
* sources. If the listener instance had been registered already, the listener
* event sources are updated
*
* @param listener The listener to add.
* @param eventTypes The event types this listener wants to be invoked.
* @param eventTypesNotLoaded The event types this listener wants to be invoked but could not be loaded.
* @param eventSources The event source types this listener wants to be invoked.
* @param eventSourceTypesNotLoaded The event source types this listener wants to be invoked but could not be loaded.
*/
public void addEventListener(IEventListener listener, Class<?>[] eventTypes, ClassNotLoadedItem[] eventTypesNotLoaded, Object[] eventSources, ClassNotLoadedItem[] eventSourcesNotLoaded) {
ListenerListEntry listEntry = new ListenerListEntry(listener, eventTypes, eventTypesNotLoaded, eventSources, eventSourcesNotLoaded);
// We must assure that the existing list entries can _never_ change!
synchronized (listeners) {
if (listeners.contains(listEntry)) {
listeners.remove(listEntry);
}
listeners.add(listEntry);
}
}
/**
* Remove a change listener for all event types and sources.
*
* @param listener The listener to remove.
*/
public void removeEventListener(IEventListener listener) {
ListenerListEntry listEntry = new ListenerListEntry(listener);
listeners.remove(listEntry);
}
/**
* Remove all change listeners for all event types and sources.
*/
public void clear() {
listeners.clear();
synchronized (this) {
extensionPointProcessed = false;
}
}
/**
* Notify all registered listeners.
*
* @param event The event. Must not be <code>null</code>
*/
public void fireEvent(final EventObject event) {
Assert.isNotNull(event);
// In non-interactive mode, the notification events are suppressed.
if (event instanceof NotifyEvent && !Host.isInteractive()) return;
synchronized (this) {
// if the extension point has not been processed till here, now we have to do
if (!extensionPointProcessed) {
addExtensionPointNotificationListeners();
extensionPointProcessed = true;
}
}
// Based on the current listener listener list, compile a list of event
// listeners to where this event would have been send to in a synchronous invocation scheme.
List<ListenerListEntry> affected = new ArrayList<ListenerListEntry>();
// Get the array of registered event listeners.
ListenerListEntry[] registered = listeners.toArray(new ListenerListEntry[listeners.size()]);
for (ListenerListEntry listEntry : registered) {
// ignore listeners not listening to the event type and source
if (listEntry.listensTo(event)) {
affected.add(listEntry);
}
}
// If no current listener is affected, return now immediately
if (affected.size() == 0) {
return;
}
// Loop over the list of affected listeners and fire the event.
// If the affected listener is a fire delegate -> use it itself to fire the event
for (ListenerListEntry listEntry : affected) {
if (!(listEntry.getListener() instanceof IEventListener)) {
continue;
}
// Create the runnable to use for executing the event firing
Runnable runnable = new FireRunnable((IEventListener)listEntry.getListener(), event);
// Check on how to fire the runnable
if (listEntry.getListener() instanceof IEventFireDelegate) {
// The listener is a fire delegate -> use it itself to fire the runnable
((IEventFireDelegate)listEntry.getListener()).fire(runnable);
} else {
// Listener isn't a fire delegate -> fire the runnable directly
runnable.run();
}
}
}
/*
* Register change listeners defined by extension.
*/
private void addExtensionPointNotificationListeners() {
IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint("org.eclipse.tcf.te.runtime.eventListeners"); //$NON-NLS-1$
if (ep != null) {
IExtension[] extensions = ep.getExtensions();
if (extensions != null && extensions.length > 0) {
for (IExtension extension : extensions) {
IConfigurationElement[] configElements = extension.getConfigurationElements();
if (configElements != null && configElements.length > 0) {
for (IConfigurationElement configElement : configElements) {
String name = configElement.getName();
if ("eventListener".equals(name)) { //$NON-NLS-1$
// try to read the "eventType" and "eventSourceType" configuration elements if any.
List<Class<?>> eventTypes = new ArrayList<Class<?>>();
List<Class<?>> eventSourceTypes = new ArrayList<Class<?>>();
List<ClassNotLoadedItem> eventTypesNotLoaded = new ArrayList<ClassNotLoadedItem>();
List<ClassNotLoadedItem> eventSourceTypesNotLoaded = new ArrayList<ClassNotLoadedItem>();
IConfigurationElement[] children = configElement.getChildren();
for (IConfigurationElement child : children) {
if ("eventType".equals(child.getName())) { //$NON-NLS-1$
String className = child.getAttribute("class"); //$NON-NLS-1$
if (className == null || className.trim().length() == 0) {
continue;
}
String bundleId = child.getAttribute("bundleId"); //$NON-NLS-1$
// If a bundle id got specified, use the specified bundle to load the service class
Bundle bundle = bundleId != null ? Platform.getBundle(bundleId) : null;
// If we don't have a bundle to load from yet, fallback to the declaring bundle
if (bundle == null) bundle = Platform.getBundle(child.getDeclaringExtension().getNamespaceIdentifier());
// And finally, use our own bundle to load the class. This fallback is expected
// to never be used.
if (bundle == null) bundle = CoreBundleActivator.getContext().getBundle();
// If the specified bundle is active, or "forceBundleActivation" is true, the class can be loaded
if (bundle != null && bundle.getState() == Bundle.ACTIVE) {
try {
Class<?> eventType = bundle.loadClass(className);
if (eventType != null && !eventTypes.contains(eventType)) {
eventTypes.add(eventType);
}
} catch (Exception ex) {
if (isTracingEnabled())
CoreBundleActivator.getTraceHandler().trace("Error instantiating event listener event type object instance: " + child.getAttribute("class"), //$NON-NLS-1$ //$NON-NLS-2$
0, ITraceIds.TRACE_EVENTS, IStatus.ERROR, this);
}
}
// If the bundle could not be found or is not yet active, don't try to load the class
else {
ClassNotLoadedItem item = new ClassNotLoadedItem(bundleId, className, child.getDeclaringExtension().getNamespaceIdentifier());
if (!eventTypesNotLoaded.contains(item)) eventTypesNotLoaded.add(item);
}
}
if ("eventSourceType".equals(child.getName())) { //$NON-NLS-1$
String className = child.getAttribute("class"); //$NON-NLS-1$
if (className == null || className.trim().length() == 0) {
continue;
}
String bundleId = child.getAttribute("bundleId"); //$NON-NLS-1$
// If a bundle id got specified, use the specified bundle to load the service class
Bundle bundle = bundleId != null ? Platform.getBundle(bundleId) : null;
// If we don't have a bundle to load from yet, fallback to the declaring bundle
if (bundle == null) bundle = Platform.getBundle(child.getDeclaringExtension().getNamespaceIdentifier());
// And finally, use our own bundle to load the class. This fallback is expected
// to never be used.
if (bundle == null) bundle = CoreBundleActivator.getContext().getBundle();
// If the specified bundle is active, the class can be loaded
if (bundle != null && bundle.getState() == Bundle.ACTIVE) {
try {
Class<?> eventSourceType = bundle.loadClass(className);
if (eventSourceType != null && !eventSourceTypes.contains(eventSourceType)) {
eventSourceTypes.add(eventSourceType);
}
} catch (Exception ex) {
if (isTracingEnabled())
CoreBundleActivator.getTraceHandler().trace("Error instantiating event listener event source type object instance: " + child.getAttribute("class"), //$NON-NLS-1$ //$NON-NLS-2$
0, ITraceIds.TRACE_EVENTS, IStatus.ERROR, this);
}
}
// If the bundle could not be found or is not yet active, don't try to load the class
else {
ClassNotLoadedItem item = new ClassNotLoadedItem(bundleId, className, child.getDeclaringExtension().getNamespaceIdentifier());
if (!eventSourceTypesNotLoaded.contains(item)) eventSourceTypesNotLoaded.add(item);
}
}
}
// For extension point contributed event listeners, we use delegating
// event listener instances
IEventListener listener = new EventListenerProxy(configElement);
addEventListener(listener,
!eventTypes.isEmpty() ? eventTypes.toArray(new Class[eventTypes.size()]) : null,
!eventTypesNotLoaded.isEmpty() ? eventTypesNotLoaded.toArray(new ClassNotLoadedItem[eventTypesNotLoaded.size()]) : null,
!eventSourceTypes.isEmpty() ? eventSourceTypes.toArray(new Class[eventSourceTypes.size()]) : null,
!eventSourceTypesNotLoaded.isEmpty() ? eventSourceTypesNotLoaded.toArray(new ClassNotLoadedItem[eventSourceTypesNotLoaded.size()]) : null
);
if (isTracingEnabled())
CoreBundleActivator.getTraceHandler().trace("Add extension point change listener: " + configElement.getAttribute("class"), //$NON-NLS-1$ //$NON-NLS-2$
0, ITraceIds.TRACE_EVENTS, IStatus.INFO, this);
}
}
}
}
}
}
}
/**
* Internal class used to delay the instantiation and plug-in activation of
* event listeners which are contributed via extension point till they
* are really fired.
*/
private class EventListenerProxy implements IEventListener, IEventFireDelegate {
private final IConfigurationElement configElement;
private IEventListener delegate;
/**
* Constructor.
*
* @param configElement The contributing configuration element of the encapsulated event listener.
* Must not be <code>null</code>.
*/
public EventListenerProxy(IConfigurationElement configElement) {
Assert.isNotNull(configElement);
this.configElement = configElement;
delegate = null;
}
/**
* Returns the event listener delegate and instantiate the delegate
* if not yet done.
*
* @return The event listener delegate or <code>null</code> if the instantiation fails.
*/
private IEventListener getDelegate() {
if (delegate == null) {
// Check the contributing plug-in state
boolean forcePluginActivation = Boolean.parseBoolean(configElement.getAttribute("forcePluginActivation")); //$NON-NLS-1$
if (!forcePluginActivation) {
Bundle bundle = Platform.getBundle(configElement.getContributor().getName());
forcePluginActivation = bundle != null ? bundle.getState() == Bundle.ACTIVE : false;
}
// Load the event listener implementation class if plug-in activations is allowed.
if (forcePluginActivation) {
try {
Object executable = configElement.createExecutableExtension("class"); //$NON-NLS-1$
if (executable instanceof IEventListener) {
delegate = (IEventListener)executable;
}
} catch (Exception ex) {
if (isTracingEnabled())
CoreBundleActivator.getTraceHandler().trace("Error instantiating extension point event listener: " + configElement.getAttribute("class") //$NON-NLS-1$ //$NON-NLS-2$
+ "(Possible Cause: " + ex.getLocalizedMessage() + ")", //$NON-NLS-1$ //$NON-NLS-2$
0, ITraceIds.TRACE_EVENTS, IStatus.ERROR, this);
}
}
}
return delegate;
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.runtime.interfaces.events.IEventListener#eventFired(java.util.EventObject)
*/
@Override
public void eventFired(EventObject event) {
Assert.isNotNull(event);
// Get the delegate (may force instantiation)
IEventListener delegate = getDelegate();
// And pass on the event to the delegate if we got a valid delegate
if (delegate != null) delegate.eventFired(event);
}
/* (non-Javadoc)
* @see org.eclipse.tcf.te.runtime.interfaces.events.IEventFireDelegate#fire(java.lang.Runnable)
*/
@Override
public void fire(Runnable runnable) {
Assert.isNotNull(runnable);
// Pass on to the delegate if the delegate itself is an fire delegate,
if (getDelegate() instanceof IEventFireDelegate) {
((IEventFireDelegate)getDelegate()).fire(runnable);
}
else {
runnable.run();
}
}
}
/**
* Return <code>true</code> if the tracing mode is enabled for the
* event manager and trace messages shall be printed to the debug console.
*/
public static boolean isTracingEnabled() {
return CoreBundleActivator.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_EVENTS);
}
}