/******************************************************************************* * Copyright (c) 2011, 2014 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.tcf.core; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdapterManager; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IExtensionRegistry; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.osgi.util.NLS; import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.te.tcf.core.activator.CoreBundleActivator; import org.eclipse.tcf.te.tcf.core.interfaces.IChannelManager; import org.eclipse.tcf.te.tcf.core.internal.Startup; import org.eclipse.tcf.te.tcf.core.internal.channelmanager.ChannelManager; import org.eclipse.tcf.te.tcf.core.listeners.interfaces.IProtocolStateChangeListener; import org.eclipse.tcf.te.tcf.core.nls.Messages; /** * The main entry point to access the TCF framework extensions. */ public final class Tcf { /* default */ IChannelManager channelManager; /* default */ final List<IProtocolStateChangeListener> protocolStateChangeListeners = new ArrayList<IProtocolStateChangeListener>(); /* * Thread save singleton instance creation. */ private static class LazyInstance { public static Tcf instance = new Tcf(); } /** * Constructor. */ /* default */ Tcf() { super(); } /** * Returns the singleton instance. */ /* default */ static Tcf getInstance() { return LazyInstance.instance; } /** * Executes the given runnable within the TCF protocol dispatch thread. * <p> * <b>Note:</b> Code which is executed in the TCF protocol dispatch thread * cannot use any blocking API! * * @param runnable The runnable. Must not be <code>null</code>. */ private static final void runSafe(Runnable runnable) { Assert.isNotNull(runnable); if (Protocol.isDispatchThread()) { runnable.run(); } else { Protocol.invokeAndWait(runnable); } } /** * Adds a listener that will be notified once the TCF framework state changes. * * @param listener The listener. Must not be <code>null</code>. */ public static final void addProtocolStateChangeListener(IProtocolStateChangeListener listener) { Assert.isTrue(Protocol.isDispatchThread()); Assert.isNotNull(listener); Tcf tcf = getInstance(); Assert.isNotNull(tcf); if (!tcf.protocolStateChangeListeners.contains(listener)) { tcf.protocolStateChangeListeners.add(listener); } } /** * Removes the specified protocol state change listener. * * @param listener The listener. Must not be <code>null</code>. */ public static final void removeProtocolStateChangeListener(IProtocolStateChangeListener listener) { Assert.isTrue(Protocol.isDispatchThread()); Assert.isNotNull(listener); Tcf tcf = getInstance(); Assert.isNotNull(tcf); tcf.protocolStateChangeListeners.remove(listener); } /** * Returns if or if not the TCF framework is up and running. * * @return <code>True</code> if the framework is up and running, <code>false</code> otherwise. */ public static final boolean isRunning() { return Startup.isStarted(); } /** * Startup TCF related services and listeners once the core * TCF framework starts up. * <p> * <b>Note:</b> The method is expected to be called within the TCF protocol dispatch thread. * * @see Startup#setStarted(boolean) */ public static void start() { Assert.isTrue(Protocol.isDispatchThread()); Tcf tcf = getInstance(); Assert.isNotNull(tcf); // Create and register listeners contributed via extension point IExtensionRegistry registry = Platform.getExtensionRegistry(); IExtensionPoint point = registry.getExtensionPoint("org.eclipse.tcf.te.tcf.core.listeners"); //$NON-NLS-1$ if (point != null) { IExtension[] extensions = point.getExtensions(); for (IExtension extension : extensions) { IConfigurationElement[] elements = extension.getConfigurationElements(); for (IConfigurationElement element : elements) { if ("protocolStateChangeListener".equals(element.getName())) { //$NON-NLS-1$ try { // Create the protocol state change listener instance IProtocolStateChangeListener listener = (IProtocolStateChangeListener)element.createExecutableExtension("class"); //$NON-NLS-1$ if (listener != null) addProtocolStateChangeListener(listener); } catch (CoreException e) { IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), NLS.bind(Messages.Extension_error_invalidProtocolStateChangeListener, element.getDeclaringExtension().getUniqueIdentifier()), e); Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); } } } } } // Signal (asynchronously) to interested listeners that we've started up final IProtocolStateChangeListener[] listeners = tcf.protocolStateChangeListeners.toArray(new IProtocolStateChangeListener[tcf.protocolStateChangeListeners.size()]); if (listeners.length > 0) { Protocol.invokeLater(new Runnable() { @Override public void run() { for (IProtocolStateChangeListener listener : listeners) { listener.stateChanged(true); } } }); } } /** * Shutdown TCF related services and listeners once the core * TCF framework shuts down. * <p> * <b>Note:</b> The method is expected to be called within the TCF protocol dispatch thread. * * @see Startup#setStarted(boolean) */ public static void stop() { Assert.isTrue(Protocol.isDispatchThread()); Tcf tcf = getInstance(); Assert.isNotNull(tcf); // Signal to interested listeners that we've just went down final IProtocolStateChangeListener[] listeners = tcf.protocolStateChangeListeners.toArray(new IProtocolStateChangeListener[tcf.protocolStateChangeListeners.size()]); if (listeners.length > 0) { // Catch IllegalStateException: TCF event dispatcher might have been shut down already try { Protocol.invokeLater(new Runnable() { @Override public void run() { for (IProtocolStateChangeListener listener : listeners) { listener.stateChanged(false); } } }); } catch (IllegalStateException e) { /* ignored on purpose */ } } } /** * Returns the channel manager instance. * <p> * <b>Note:</b> The method will create the channel manager instance on * first invocation. * * @return The channel manager instance. */ public static IChannelManager getChannelManager() { final Tcf tcf = getInstance(); Assert.isNotNull(tcf); runSafe(new Runnable() { @Override public void run() { Assert.isTrue(Protocol.isDispatchThread()); if (tcf.channelManager == null) { // We have to create the channel manager tcf.channelManager = new ChannelManager(); } } }); return tcf.channelManager; } /** * Returns an object which is an instance of the given class associated with the given object. * Returns <code>null</code> if no such object can be found. * * @param adapter The type of adapter to look up * @return An object castable to the given adapter type, or <code>null</code> * if the given adaptable object does not have an available adapter of the given type * * @see IAdapterManager#getAdapter(Object, Class) */ public static Object getAdapter(Class<?> adapter) { Assert.isNotNull(adapter); Tcf tcf = getInstance(); Assert.isNotNull(tcf); if (IChannelManager.class.equals(adapter)) { return tcf.channelManager; } return Platform.getAdapterManager().getAdapter(tcf, adapter); } }