diff options
Diffstat (limited to 'target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals')
15 files changed, 1971 insertions, 0 deletions
diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/TerminalContextPropertiesProviderFactory.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/TerminalContextPropertiesProviderFactory.java new file mode 100644 index 000000000..c0bddc9bc --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/TerminalContextPropertiesProviderFactory.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * Copyright (c) 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.core.terminals; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.expressions.EvaluationContext; +import org.eclipse.core.expressions.EvaluationResult; +import org.eclipse.core.expressions.Expression; +import org.eclipse.core.expressions.ExpressionConverter; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExecutableExtension; +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.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tcf.te.core.terminals.activator.CoreBundleActivator; +import org.eclipse.tcf.te.core.terminals.interfaces.ITerminalContextPropertiesProvider; +import org.eclipse.tcf.te.core.terminals.nls.Messages; + +/** + * Terminal context properties provider factory. + */ +public final class TerminalContextPropertiesProviderFactory { + // Flag to remember if the contributions got loaded + private static boolean contributionsLoaded = false; + + // The list of all loaded contributions + private static final List<Proxy> contributions = new ArrayList<Proxy>(); + + // The proxy used to achieve lazy class loading and plug-in activation + private static class Proxy implements IExecutableExtension { + // Reference to the configuration element + private IConfigurationElement configElement = null; + // The class implementing the provider + public String clazz; + // The context properties provider instance + private ITerminalContextPropertiesProvider provider = null; + // The converted expression + private Expression expression; + + /** + * Constructor. + */ + protected Proxy() { + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { + Assert.isNotNull(config); + this.configElement = config; + + // Read the class attribute. + // Throws an exception if the attribute value is empty or null. + clazz = config.getAttribute("class"); //$NON-NLS-1$ + if (clazz == null || "".equals(clazz.trim())) { //$NON-NLS-1$ + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + NLS.bind(Messages.Extension_error_missingRequiredAttribute, "class", config.getContributor().getName()))); //$NON-NLS-1$ + } + + // Read the "enablement" sub element of the extension + IConfigurationElement[] children = configElement.getChildren("enablement"); //$NON-NLS-1$ + if (children == null || children.length == 0) { + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + NLS.bind(Messages.Extension_error_missingRequiredAttribute, "enablement", config.getContributor().getName()))); //$NON-NLS-1$ + } + // Only one "enablement" element is expected + expression = ExpressionConverter.getDefault().perform(children[0]); + } + + /** + * Return the real terminal context properties provider instance for this proxy. + */ + protected ITerminalContextPropertiesProvider getProvider() { + if (provider == null && configElement != null) { + try { + // Create the service class instance via the configuration element + Object provider = configElement.createExecutableExtension("class"); //$NON-NLS-1$ + if (provider instanceof ITerminalContextPropertiesProvider) { + this.provider = (ITerminalContextPropertiesProvider)provider; + } + else { + IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), "Terminal context properties provider '" + provider.getClass().getName() + "' not of type ITerminalContextPropertiesProvider."); //$NON-NLS-1$ //$NON-NLS-2$ + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); + } + } + catch (CoreException e) { + IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), "Cannot create terminal context properties provider '" + clazz + "'.", e); //$NON-NLS-1$ //$NON-NLS-2$ + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); + } + } + return provider; + } + + /** + * Returns if or if not the context properties provider contribution is enabled for + * the given terminal context. + * + * @param context The terminal context or <code>null</code>. + * @return <code>True</code> if the context properties provider contribution is enabled + * for the given terminal context, <code>false</code> otherwise. + */ + protected boolean isEnabled(Object context) { + if (context == null) { + return getEnablement() == null; + } + + Expression enablement = getEnablement(); + + // The service contribution is enabled by default if no expression is specified. + boolean enabled = enablement == null; + + if (enablement != null) { + // Set the default variable to the service context. + EvaluationContext evalContext = new EvaluationContext(null, context); + // Allow plug-in activation + evalContext.setAllowPluginActivation(true); + // Evaluate the expression + try { + enabled = enablement.evaluate(evalContext).equals(EvaluationResult.TRUE); + } catch (CoreException e) { + IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), e.getLocalizedMessage(), e); + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); + } + } + + return enabled; + } + + /** + * Returns the enablement expression. + * + * @return The enablement expression or <code>null</code>. + */ + protected Expression getEnablement() { + return expression; + } + } + + + /** + * Creates a new terminal context properties provider proxy instance and initialize it. + * + * @param config The configuration element. Must not be <code>null</code>. + * @return The new terminal context properties provider proxy instance. + */ + private static Proxy getProxy(IConfigurationElement config) { + Assert.isNotNull(config); + Proxy proxy = new Proxy(); + try { + proxy.setInitializationData(config, null, null); + } catch (CoreException e) { + if (Platform.inDebugMode()) { + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(e.getStatus()); + } + } + return proxy; + } + + /** + * Load the terminal context properties provider contributions. + */ + private static void loadContributions() { + IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint("org.eclipse.tcf.te.core.terminals.contextPropertiesProviders"); //$NON-NLS-1$ + if (ep != null) { + IExtension[] extensions = ep.getExtensions(); + if (extensions != null) { + for (IExtension extension : extensions) { + IConfigurationElement[] configElements = extension.getConfigurationElements(); + if (configElements != null) { + for (IConfigurationElement configElement : configElements) { + if ("contextPropertiesProvider".equals(configElement.getName())) { //$NON-NLS-1$ + Proxy proxy = getProxy(configElement); + contributions.add(proxy); + } + } + } + } + } + } + } + + /** + * Get the terminal context properties provider for the given context. The first terminal + * context properties provider which is enabled is returned. + * + * @param context The terminal context. Must not be <code>null</code>. + * + * @return The service or <code>null</code>. + */ + public static ITerminalContextPropertiesProvider getProvider(Object context) { + Assert.isNotNull(context); + + // Load the contributions if not yet loaded + synchronized (contributions) { + if (!contributionsLoaded) { + loadContributions(); + contributionsLoaded = true; + } + } + + for (Proxy proxy : contributions) { + if (proxy.isEnabled(context)) { + return proxy.getProvider(); + } + } + + return null; + } + +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/TerminalServiceFactory.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/TerminalServiceFactory.java new file mode 100644 index 000000000..a86287da3 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/TerminalServiceFactory.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 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.core.terminals; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.tcf.te.core.terminals.activator.CoreBundleActivator; +import org.eclipse.tcf.te.core.terminals.interfaces.ITerminalService; +import org.eclipse.tcf.te.core.terminals.nls.Messages; +import org.osgi.framework.Bundle; + +/** + * Terminal service factory implementation. + * <p> + * Provides access to the terminal service instance. + */ +public final class TerminalServiceFactory { + public static ITerminalService instance = null; + + static { + // Tries to instantiate the terminal service implementation + // from the o.e.tcf.te.ui.terminals bundle + Bundle bundle = Platform.getBundle("org.eclipse.tcf.te.ui.terminals"); //$NON-NLS-1$ + if (bundle != null && (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.ACTIVE)) { + try { + Class<?> clazz = bundle.loadClass("org.eclipse.tcf.te.ui.terminals.services.TerminalService"); //$NON-NLS-1$ + instance = (ITerminalService) clazz.newInstance(); + } + catch (Exception e) { + if (Platform.inDebugMode()) { + Platform.getLog(bundle).log(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), Messages.TerminalServiceFactory_error_serviceImplLoadFailed, e)); + } + } + } + } + + /** + * Returns the terminal service instance. + */ + public static ITerminalService getService() { + return instance; + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/activator/CoreBundleActivator.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/activator/CoreBundleActivator.java new file mode 100644 index 000000000..054468888 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/activator/CoreBundleActivator.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 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.core.terminals.activator; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class CoreBundleActivator implements BundleActivator { + // The bundle context + private static BundleContext context; + + /** + * Returns the bundle context + * + * @return the bundle context + */ + public static BundleContext getContext() { + return context; + } + + /** + * Convenience method which returns the unique identifier of this plugin. + */ + public static String getUniqueIdentifier() { + if (getContext() != null && getContext().getBundle() != null) { + return getContext().getBundle().getSymbolicName(); + } + return "org.eclipse.tcf.te.core.terminals"; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext bundleContext) throws Exception { + CoreBundleActivator.context = bundleContext; + } + + /* (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext bundleContext) throws Exception { + CoreBundleActivator.context = null; + } +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalContextPropertiesProvider.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalContextPropertiesProvider.java new file mode 100644 index 000000000..41f2cd3e7 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalContextPropertiesProvider.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 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.core.terminals.interfaces; + +import java.util.Map; + +/** + * Terminal context properties provider. + * <p> + * The context properties provider allows querying desired properties + * for a given context. The context is typically an element from a selection + * and the inner structure of the element is unknown to the terminal. + */ +public interface ITerminalContextPropertiesProvider { + + /** + * Returns a unmodifiable map containing the target address and port for the given context, + * if it can be determined. + * <p> + * A context may return multiple target addresses and ports if the context can be reached using + * different connection methods. + * <p> + * <b>Note:</b> + * <ul> + * <li>See the constants defined in the context provider constants interface for default + * address and port types.</li> + * <li>The target address returned must <b>not</b> necessarily be an IP address.</li> + * <li>The values of the address or port properties might be <code>null</code>.</li> + * </ul> + * + * @param context The context to get the target addresses and ports from. Must not be <code>null</code>. + * @return The unmodifiable map containing the target addresses and ports, or <code>null</code>. + */ + public Map<String, String> getTargetAddress(Object context); + + /** + * Returns the property value stored under the given property key. If the property does not + * exist, <code>null</code> is returned. + * + * @param context The context to get the property from. Must not be <code>null</code>. + * @param key The property key. Must not be <code>null</code>. + * + * @return The stored property value or <code>null</code>. + */ + public Object getProperty(Object context, String key); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalService.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalService.java new file mode 100644 index 000000000..e4c90c587 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalService.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * 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.core.terminals.interfaces; + +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; + +/** + * Terminals service. + */ +public interface ITerminalService { + + /** + * Client call back interface. + */ + public interface Done { + /** + * Called when the terminal service operation is done. + * + * @param status The status of the terminal service operation. + */ + public void done(IStatus status); + } + + /** + * Opens a terminal asynchronously and invokes the given callback if done. + * + * @param properties The terminal properties. Must not be <code>null</code>. + * @param done The callback to invoke if finished or <code>null</code>. + */ + public void openConsole(Map<String, Object> properties, Done done); + + /** + * Close the terminal asynchronously and invokes the given callback if done. + * + * @param properties The terminal properties. Must not be <code>null</code>. + * @param done The callback to invoke if finished or <code>null</code>. + */ + public void closeConsole(Map<String, Object> properties, Done done); + + /** + * Terminate (disconnect) the terminal asynchronously and invokes the given callback if done. + * + * @param properties The terminal properties. Must not be <code>null</code>. + * @param done The callback to invoke if finished or <code>null</code>. + */ + public void terminateConsole(Map<String, Object> properties, Done done); + + /** + * Register the given listener to receive notifications about terminal events. + * Calling this method multiple times with the same listener has no effect. + + * @param listener The terminal tab listener. Must not be <code>null</code>. + */ + public void addTerminalTabListener(ITerminalTabListener listener); + + /** + * Unregister the given listener from receiving notifications about terminal + * events. Calling this method multiple times with the same listener + * has no effect. + * + * @param listener The terminal tab listener. Must not be <code>null</code>. + */ + public void removeTerminalTabListener(ITerminalTabListener listener); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalServiceOutputStreamMonitorListener.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalServiceOutputStreamMonitorListener.java new file mode 100644 index 000000000..dda3704b0 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalServiceOutputStreamMonitorListener.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2014 - 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.core.terminals.interfaces; + +/** + * An interface to be implemented by listeners who want to listen + * to the streams data without interfering with the original data receiver. + * <p> + * Listeners are invoked within the monitor processing thread. + */ +public interface ITerminalServiceOutputStreamMonitorListener { + + /** + * Signals that some content has been read from the monitored stream. + * + * @param byteBuffer The byte stream. Must not be <code>null</code>. + * @param bytesRead The number of bytes that were read into the read buffer. + */ + public void onContentReadFromStream(byte[] byteBuffer, int bytesRead); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalTabListener.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalTabListener.java new file mode 100644 index 000000000..77e3e04eb --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalTabListener.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 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.core.terminals.interfaces; + +/** + * Listener to implement and to register to get notified about + * terminal tabs events, like the disposal of a terminal tab. + */ +public interface ITerminalTabListener { + + /** + * Invoked once a terminal tab got disposed. The source object is + * the disposed tab item and data is the custom data object associated + * with the disposed tab item. + * + * @param source The disposed tab item. Must not be <code>null</code>. + * @param data The custom data object associated with the disposed tab item or <code>null</code>. + */ + public void terminalTabDisposed(Object source, Object data); +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/IContextPropertiesConstants.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/IContextPropertiesConstants.java new file mode 100644 index 000000000..b2e98aacd --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/IContextPropertiesConstants.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 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.core.terminals.interfaces.constants; + +/** + * Defines the terminal context properties constants. + */ +public interface IContextPropertiesConstants { + + /** + * Target name. + * <p> + * The target name is not meant to be identical with the targets network name. It can + * be the targets network name, but it can be any other string identifying the target + * to the user as well. The name is for display only, it is not meant to be used for + * communicating with the target. + */ + public static String PROP_NAME = "name"; //$NON-NLS-1$ + + /** + * Target agent address. + * <p> + * <i>The value is typically the address an agent running at the target.</i> + */ + public static String PROP_ADDRESS = "address"; //$NON-NLS-1$ + + /** + * Target agent port. + * <p> + * <i>The value is typically the port an agent running at the target.</i> + */ + public static String PROP_PORT = "port"; //$NON-NLS-1$ + + /** + * The default user name to use to log into the target. + */ + public static String PROP_DEFAULT_USER = "defaultUser"; //$NON-NLS-1$ + + /** + * The default encoding to use. + */ + public static String PROP_DEFAULT_ENCODING = "defaultEncoding"; //$NON-NLS-1$ +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/ILineSeparatorConstants.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/ILineSeparatorConstants.java new file mode 100644 index 000000000..8fea4b82d --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/ILineSeparatorConstants.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * 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.core.terminals.interfaces.constants; + +/** + * Line separator constants. + * <p> + * Copied from <code>org.eclipse.tcf.internal.terminal.local.ILocalTerminalSettings</code>. + */ +public interface ILineSeparatorConstants { + + /** + * The line separator setting CR (carriage return only; for example, used by Mac OS 9). + */ + public final static String LINE_SEPARATOR_CR = "\\r"; //$NON-NLS-1$ + + /** + * The line separator setting CRLF (carriage return and line feed; for example, used by + * Windows). + */ + public final static String LINE_SEPARATOR_CRLF = "\\r\\n"; //$NON-NLS-1$ + + /** + * The line separator setting LF (line feed only; used by all UNIX-based systems). + */ + public final static String LINE_SEPARATOR_LF = "\\n"; //$NON-NLS-1$ +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/ITerminalsConnectorConstants.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/ITerminalsConnectorConstants.java new file mode 100644 index 000000000..938f76cd4 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/ITerminalsConnectorConstants.java @@ -0,0 +1,338 @@ +/******************************************************************************* + * 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 + * Max Weninger (Wind River) - [361352] [TERMINALS][SSH] Add SSH terminal support + *******************************************************************************/ +package org.eclipse.tcf.te.core.terminals.interfaces.constants; + +import org.eclipse.tcf.te.core.terminals.interfaces.ITerminalServiceOutputStreamMonitorListener; + + +/** + * Defines the terminals connector constants. + */ +public interface ITerminalsConnectorConstants { + + /** + * Property: The unique id of the terminals view to open. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_ID = "id"; //$NON-NLS-1$ + + /** + * Property: The unique secondary id of the terminals view to open. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_SECONDARY_ID = "secondaryId"; //$NON-NLS-1$ + + /** + * Property: The title of the terminal tab to open. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_TITLE = "title"; //$NON-NLS-1$ + + /** + * Property: The encoding of the terminal tab to open. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_ENCODING = "encoding"; //$NON-NLS-1$ + + /** + * Property: Custom data object to associate with the terminal tab. + * <p> + * Property Type: {@link Object} + */ + public static final String PROP_DATA = "data"; //$NON-NLS-1$ + + /** + * Property: External selection to associate with the terminal tab. + * <p> + * Property Type: {@link org.eclipse.jface.viewers.ISelection} + */ + public static final String PROP_SELECTION = "selection"; //$NON-NLS-1$ + + /** + * Property: Flag to force a new terminal tab. + * <p> + * Property Type: {@link Boolean} + */ + public static final String PROP_FORCE_NEW = "terminal.forceNew"; //$NON-NLS-1$ + + /** + * Property: Flag to signal if the terminal tab shall have a disconnect button or not. + * <p> + * Property Type: {@link Boolean} + */ + public static final String PROP_HAS_DISCONNECT_BUTTON = "hasDisconnectButton"; //$NON-NLS-1$ + + /** + * Property: Terminals launcher delegate id. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_DELEGATE_ID = "delegateId"; //$NON-NLS-1$ + + /** + * Property: Terminals connector type id. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_CONNECTOR_TYPE_ID = "connector.type.id"; //$NON-NLS-1$ + + /** + * Property: Specific terminal connector type id. Allows clients to + * override the specifically used terminal connector + * implementation for a given type. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_TERMINAL_CONNECTOR_ID = "tm.terminal.connector.id"; //$NON-NLS-1$ + + // ***** Generic terminals connector properties ***** + + /** + * Property: Timeout to be passed to the terminal connector. The specific terminal + * connector implementation may interpret this value differently. If not + * set, the terminal connector may use a default value. + * <p> + * Property Type: {@link Integer} + */ + public static final String PROP_TIMEOUT = "timeout"; //$NON-NLS-1$ + + /** + * Property: Flag to control if a local echo is needed from the terminal widget. + * <p>Typical for process and streams terminals. + * <p> + * Property Type: {@link Boolean} + */ + public static final String PROP_LOCAL_ECHO = "localEcho"; //$NON-NLS-1$ + + /** + * Property: Data flag to tell the terminal to not reconnect when hitting enter + * in a disconnected terminal. + * The flag can be set by adding an IPropertiesContainer with the set + * flag as PROP_DATA. + * <p> + * Property Type: {@link Boolean} + */ + public static final String PROP_DATA_NO_RECONNECT = "data.noReconnect"; //$NON-NLS-1$ + + /** + * Property: The line separator expected by the remote terminal on input streams and + * send by the remote terminal on output streams. + * <p>Typical for process and streams terminals. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_LINE_SEPARATOR = "lineSeparator"; //$NON-NLS-1$ + + /** + * Property: The list of stdout listeners to attach to the corresponding stream monitor. + * <p>Typical for process and streams terminals. + * <p> + * Property Type: {@link ITerminalServiceOutputStreamMonitorListener} array + */ + public static final String PROP_STDOUT_LISTENERS = "stdoutListeners"; //$NON-NLS-1$ + + /** + * Property: The list of stderr listeners to attach to the corresponding stream monitor. + * <p>Typical for process and streams terminals. + * <p> + * Property Type: {@link ITerminalServiceOutputStreamMonitorListener} array + */ + public static final String PROP_STDERR_LISTENERS = "stderrListeners"; //$NON-NLS-1$ + + /** + * Property: If set to <code>true</code>, backslashes are translated to + * slashes before pasting the text to the terminal widget. + * <p> + * Property Type: {@link Boolean} + */ + public static final String PROP_TRANSLATE_BACKSLASHES_ON_PASTE = "translateBackslashesOnPaste"; //$NON-NLS-1$ + + // ***** IP based terminals connector properties ***** + + /** + * Property: Host name or IP address the terminal server is running. + * <p>Typical for telnet or ssh terminals. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_IP_HOST = "ip.host"; //$NON-NLS-1$ + + /** + * Property: Port at which the terminal server is providing the console input and output. + * <p>Typical for telnet or ssh terminals. + * <p> + * Property Type: {@link Integer} + */ + public static final String PROP_IP_PORT = "ip.port"; //$NON-NLS-1$ + + /** + * Property: An offset to add to the specified port number. + * <p>Typical for telnet or ssh terminals. + * <p> + * Property Type: {@link Integer} + */ + public static final String PROP_IP_PORT_OFFSET = "ip.port.offset"; //$NON-NLS-1$ + + // ***** Process based terminals connector properties ***** + + /** + * Property: Process image path. + * <p>Typical for process terminals. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_PROCESS_PATH = "process.path"; //$NON-NLS-1$ + + /** + * Property: Process arguments. + * <p>Typical for process terminals. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_PROCESS_ARGS = "process.args"; //$NON-NLS-1$ + + /** + * Property: Process arguments. + * <p>Typical for process terminals. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_PROCESS_WORKING_DIR = "process.working_dir"; //$NON-NLS-1$ + + /** + * Property: Process environment. + * <p>Typical for process terminals. + * <p> + * Property Type: {@link String} array + */ + public static final String PROP_PROCESS_ENVIRONMENT = "process.environment"; //$NON-NLS-1$ + + /** + * Property: Flag to merge process environment with native environment. + * <p>Typical for process terminals. + * <p> + * Property Type: {@link Boolean} + */ + public static final String PROP_PROCESS_MERGE_ENVIRONMENT = "process.environment.merge"; //$NON-NLS-1$ + + /** + * Property: Runtime process instance. + * <p>Typical for process terminals. + * <p> + * Property Type: {@link Process} + */ + public static final String PROP_PROCESS_OBJ = "process"; //$NON-NLS-1$ + + /** + * Property: Runtime process PTY instance. + * <p>Typical for process terminals. + * <p> + * Property Type: {@link org.eclipse.cdt.utils.pty.PTY} + */ + public static final String PROP_PTY_OBJ = "pty"; //$NON-NLS-1$ + + // ***** Streams based terminals connector properties ***** + + /** + * Property: Stdin streams instance. + * <p>Typical for streams terminals. + * <p> + * Property Type: {@link OutputStream} + */ + public static final String PROP_STREAMS_STDIN = "streams.stdin"; //$NON-NLS-1$ + + /** + * Property: Stdout streams instance. + * <p>Typical for streams terminals. + * <p> + * Property Type: {@link InputStream} + */ + public static final String PROP_STREAMS_STDOUT = "streams.stdout"; //$NON-NLS-1$ + + /** + * Property: Stderr streams instance. + * <p>Typical for streams terminals. + * <p> + * Property Type: {@link InputStream} + */ + public static final String PROP_STREAMS_STDERR = "streams.stderr"; //$NON-NLS-1$ + + // ***** Ssh specific properties ***** + + /** + * Property: ssh keep alive value. + * <p> + * Property Type: {@link Integer} + */ + public static final String PROP_SSH_KEEP_ALIVE = "ssh.keep_alive"; //$NON-NLS-1$ + + /** + * Property: Ssh password. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_SSH_PASSWORD = "ssh.password"; //$NON-NLS-1$ + + /** + * Property: Ssh user. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_SSH_USER = "ssh.user"; //$NON-NLS-1$ + + // ***** Serial specific properties ***** + + /** + * The serial device name. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_DEVICE = "serial.device"; //$NON-NLS-1$ + + /** + * The baud rate. + * <p> + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_BAUD_RATE = "serial.baudrate"; //$NON-NLS-1$ + + /** + * The data bits + * <p> + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_DATA_BITS = "serial.databits"; //$NON-NLS-1$ + + /** + * The parity + * <p> + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_PARITY = "serial.parity"; //$NON-NLS-1$ + + /** + * The stop bits + * <p> + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_STOP_BITS = "serial.stopbits"; //$NON-NLS-1$ + + /** + * The flow control + * <p> + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_FLOW_CONTROL = "serial.flowcontrol"; //$NON-NLS-1$ +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/nls/Messages.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/nls/Messages.java new file mode 100644 index 000000000..23cc87c46 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/nls/Messages.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 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.core.terminals.nls; + +import org.eclipse.osgi.util.NLS; + +/** + * Externalized strings management. + */ +public class Messages extends NLS { + + // The plug-in resource bundle name + private static final String BUNDLE_NAME = "org.eclipse.tcf.te.core.terminals.nls.Messages"; //$NON-NLS-1$ + + /** + * Static constructor. + */ + static { + // Load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + // **** Declare externalized string id's down here ***** + + public static String TerminalServiceFactory_error_serviceImplLoadFailed; + + public static String Extension_error_missingRequiredAttribute; +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/nls/Messages.properties new file mode 100644 index 000000000..212cd1893 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/nls/Messages.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 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 +############################################################################### + +TerminalServiceFactory_error_serviceImplLoadFailed=Failed to load terminal service implementation. + +Extension_error_missingRequiredAttribute=Required attribute "{0}" missing for extension "{1}"! + diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/preferences/ScopedEclipsePreferences.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/preferences/ScopedEclipsePreferences.java new file mode 100644 index 000000000..e46ad9546 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/preferences/ScopedEclipsePreferences.java @@ -0,0 +1,459 @@ +/******************************************************************************* + * 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.core.terminals.preferences; + +import java.io.OutputStream; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; +import org.eclipse.core.runtime.preferences.IPreferenceFilter; +import org.eclipse.core.runtime.preferences.IScopeContext; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.osgi.service.prefs.BackingStoreException; + +/** + * Helper class to handle scoped Eclipse preferences for plug-in's. Scoped + * preferences means a given preference context plus the default preferences + * scope. + * <p> + * On changes a {@link PreferenceChangeEvent} is sent to inform all listeners of the change. + * + * @see IEclipsePreferences + * @see IEclipsePreferences.PreferenceChangeEvent + * @see IEclipsePreferences.IPreferenceChangeListener + */ +public class ScopedEclipsePreferences { + /** + * The preferences scope qualifier. + */ + private final String qualifier; + + /** + * The default scope preference node. + */ + protected final IEclipsePreferences defaultPrefs; + + /** + * The context scope preference node. + */ + protected final IEclipsePreferences contextScopePrefs; + + /** + * The registered preference change listeners. + */ + private final ListenerList listeners = new ListenerList(); + + /** + * Constructor. + * <p> + * Initialize the scoped preferences with a new instance scope for the given qualifier. The default + * scope is determined by calling <code>DefaultScope().getNode(qualifier)</code>. + * + * @param qualifier The qualifier for the preferences (in example the unique identifier of a plugin). Must not be <code>null</code>. + */ + public ScopedEclipsePreferences(String qualifier) { + this(InstanceScope.INSTANCE, qualifier); + } + + /** + * Constructor. + * <p> + * Initialize the scoped preferences with the given scope. The default scope + * is determined by calling <code>DefaultScope().getNode(qualifier)</code>. + * + * @param context The preference scope context. Must not be <code>null</code>. + * @param qualifier The qualifier for the preferences (in example the unique identifier of a plugin). Must not be <code>null</code>. + */ + public ScopedEclipsePreferences(IScopeContext context, String qualifier) { + Assert.isNotNull(context); + Assert.isNotNull(qualifier); + this.qualifier = qualifier; + defaultPrefs = DefaultScope.INSTANCE.getNode(getQualifier()); + contextScopePrefs = context.getNode(getQualifier()); + } + + /** + * Returns the qualifier that is used to get the preferences. + * For plugin preferences, this is the unique identifier of the plugin. + */ + protected final String getQualifier() { + return qualifier; + } + + /** + * Exports the preferences to the stream. + * <p> + * <b>Note:</b> The stream will be closed after the export. + * + * @param stream The stream to where preferences and defaults should be exported. + */ + public void exportPreferences(OutputStream stream) { + Assert.isNotNull(stream); + try { + IPreferenceFilter filter = new IPreferenceFilter() { + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.IPreferenceFilter#getScopes() + */ + @Override + public String[] getScopes() { + return new String[] { InstanceScope.SCOPE }; + } + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.IPreferenceFilter#getMapping(java.lang.String) + */ + @Override + public Map getMapping(String scope) { + return null; + } + }; + + Platform.getPreferencesService().exportPreferences(contextScopePrefs, new IPreferenceFilter[] { filter }, stream); + stream.close(); + } + catch (Exception e) { + } + } + + /** + * Check whether a key is set or not. + * + * @param key The key to check. + * @return <code>null</code> if the key does not exist. + */ + public boolean containsKey(String key) { + return Platform.getPreferencesService().getString(getQualifier(), key, null, null) != null; + } + + /** + * Get a String preference value. + * + * @param key The preference key. + * @return The value of the preference key or the default value if not set. + */ + public final String getString(String key) { + return Platform.getPreferencesService().getString(getQualifier(), key, null, null); + } + + /** + * Get a boolean preference value. + * + * @param key The preference key. + * @return The value of the preference key or the default value if not set. + */ + public final boolean getBoolean(String key) { + return Platform.getPreferencesService().getBoolean(getQualifier(), key, false, null); + } + + /** + * Get an int preference value. + * + * @param key The preference key. + * @return The value of the preference key or the default value if not set. + */ + public final int getInt(String key) { + return Platform.getPreferencesService().getInt(getQualifier(), key, 0, null); + } + + /** + * Get a long preference value. + * + * @param key The preference key. + * @return The value of the preference key or the default value if not set. + */ + public final long getLong(String key) { + return Platform.getPreferencesService().getLong(getQualifier(), key, 0, null); + } + + /** + * Get a default String preference value. + * + * @param key The preference key. + * @return The default value of the preference key or <code>null</code>. + */ + public final String getDefaultString(String key) { + return defaultPrefs.get(key, null); + } + + /** + * Get a default boolean preference value. + * + * @param key The preference key. + * @return The default value of the preference key or <code>null</code>. + */ + public final boolean getDefaultBoolean(String key) { + return defaultPrefs.getBoolean(key, false); + } + + /** + * Get a default int preference value. + * + * @param key The preference key. + * @return The default value of the preference key or <code>null</code>. + */ + public final int getDefaultInt(String key) { + return defaultPrefs.getInt(key, 0); + } + + /** + * Get a default long preference value. + * + * @param key The preference key. + * @return The default value of the preference key or <code>null</code>. + */ + public final long getDefaultLong(String key) { + return defaultPrefs.getLong(key, 0); + } + + /** + * Set a String preference value. If the value is <code>null</code> or is equal to + * the default value, the entry will be removed. + * <p> + * A {@link PreferenceChangeEvent} is fired, if the value has changed. + * + * @param key The preference key. + * @return The value of the preference key. + */ + public void putString(String key, String value) { + String defValue = defaultPrefs.get(key, null); + String instValue = getString(key); + if (value == null || value.equals(defValue)) { + contextScopePrefs.remove(key); + flushAndNotify(contextScopePrefs, key, instValue, defValue); + } + else if (!value.equals(instValue)) { + contextScopePrefs.put(key, value); + flushAndNotify(contextScopePrefs, key, instValue, value); + } + } + + /** + * Set a boolean preference value. If the value is equal the default value, + * the entry will be removed. + * <p> + * A {@link PreferenceChangeEvent} is fired, if the value has changed. + * + * @param key The preference key. + * @return The value of the preference key. + */ + public void putBoolean(String key, boolean value) { + boolean defValue = defaultPrefs.getBoolean(key, false); + boolean instValue = getBoolean(key); + if (value == defValue) { + contextScopePrefs.remove(key); + flushAndNotify(contextScopePrefs, key, Boolean.toString(instValue), Boolean.toString(defValue)); + } + else if (value != instValue) { + contextScopePrefs.putBoolean(key, value); + flushAndNotify(contextScopePrefs, key, Boolean.toString(instValue), Boolean.toString(value)); + } + } + + /** + * Set an int preference value. If the value is equal to the default value, + * the entry will be removed. + * <p> + * A {@link PreferenceChangeEvent} is fired, if the value has changed. The old + * and new values are string representation in base 10. + * + * @param key The preference key. + * @return The value of the preference key. + */ + public void putInt(String key, int value) { + int defValue = defaultPrefs.getInt(key, 0); + int instValue = getInt(key); + if (value == defValue) { + contextScopePrefs.remove(key); + flushAndNotify(contextScopePrefs, key, Integer.toString(instValue), Integer.toString(defValue)); + } + else if (value != instValue) { + contextScopePrefs.putInt(key, value); + flushAndNotify(contextScopePrefs, key, Integer.toString(instValue), Integer.toString(value)); + } + } + + /** + * Set a long preference value. If the given value is equal to the default + * value, the entry will be removed. + * <p> + * A {@link PreferenceChangeEvent} is fired, if the value has changed. The old + * and new values are string representation in base 10. + * + * @param key The preference key. + * @return The value of the preference key. + */ + public void putLong(String key, long value) { + long defValue = defaultPrefs.getLong(key, 0); + long instValue = getLong(key); + if (value == defValue) { + contextScopePrefs.remove(key); + flushAndNotify(contextScopePrefs, key, Long.toString(instValue), Long.toString(defValue)); + } + else if (value != instValue) { + contextScopePrefs.putLong(key, value); + flushAndNotify(contextScopePrefs, key, Long.toString(instValue), Long.toString(value)); + } + } + + /** + * Set a default String preference value. If the given value is <code>null</code>, + * the entry will be removed. + * <p> + * A {@link PreferenceChangeEvent} is fired, if the value has changed. + * + * @param key The preference key. + * @return The default value of the preference key. + */ + public void putDefaultString(String key, String value) { + String defValue = defaultPrefs.get(key, null); + if (value == null) { + defaultPrefs.remove(key); + flushAndNotify(defaultPrefs, key, defValue, null); + } + else if (!value.equals(defValue)) { + defaultPrefs.put(key, value); + flushAndNotify(defaultPrefs, key, defValue, value); + } + } + + /** + * Set a default boolean preference value. + * <p> + * A {@link PreferenceChangeEvent} is fired, if the value has changed. + * + * @param key The preference key. + * @return The default value of the preference key. + */ + public void putDefaultBoolean(String key, boolean value) { + boolean defValue = defaultPrefs.getBoolean(key, false); + if (value != defValue) { + defaultPrefs.putBoolean(key, value); + flushAndNotify(defaultPrefs, key, Boolean.toString(defValue), Boolean.toString(value)); + } + } + + /** + * Set a default int preference value. + * <p> + * A {@link PreferenceChangeEvent} is fired, if the value has changed. The old + * and new values are string representation in base 10. + * + * @param key The preference key. + * @return The default value of the preference key. + */ + public void putDefaultInt(String key, int value) { + int defValue = defaultPrefs.getInt(key, 0); + if (value != defValue) { + defaultPrefs.putInt(key, value); + flushAndNotify(defaultPrefs, key, Integer.toString(defValue), Integer.toString(value)); + } + } + + /** + * Set a default long preference value. + * <p> + * A {@link PreferenceChangeEvent} is fired, if the value has changed. The old + * and new values are string representation in base 10. + * + * @param key The preference key. + * @return The default value of the preference key. + */ + public void putDefaultLong(String key, long value) { + long defValue = defaultPrefs.getLong(key, 0); + if (value != defValue) { + defaultPrefs.putLong(key, value); + flushAndNotify(defaultPrefs, key, Long.toString(defValue), Long.toString(value)); + } + } + + /** + * Write back the changes to the store and notify all listeners about the changed key. + * + * @param node The preference node which has changed. Must not be <code>null</code>. + * @param key The key of the changed preference. Must not be <code>null</code>. + * @param oldValue The old value as a {@link String}, or <code>null</code>. + * @param newValue The new value as a {@link String}, or <code>null</code>. + */ + protected final void flushAndNotify(IEclipsePreferences node, String key, String oldValue, String newValue) { + // Flush the preferences to the persistence store + try { node.flush(); } catch (BackingStoreException e) { /* Ignored on purpose */ } + + // Notify the listeners + firePreferenceEvent(node, key, oldValue, newValue); + } + + /** + * Register the given listener to receive notifications of preference changes to this node. + * Calling this method multiple times with the same listener has no effect. The given listener + * argument must not be <code>null</code>. + * + * @param listener The preference change listener. Must not be <code>null</code>. + */ + public void addPreferenceChangeListener(IPreferenceChangeListener listener) { + Assert.isNotNull(listener); + listeners.add(listener); + } + + /** + * De-register the given listener from receiving notifications of preference changes + * to this node. Calling this method multiple times with the same listener has no + * effect. The given listener argument must not be <code>null</code>. + * + * @param listener The preference change listener. Must not be <code>null</code>. + */ + public void removePreferenceChangeListener(IPreferenceChangeListener listener) { + Assert.isNotNull(listener); + listeners.remove(listener); + } + + /** + * Convenience method for notifying the registered preference change listeners. + * + * @param node The preference node which has changed. Must not be <code>null</code>. + * @param key The key of the changed preference. Must not be <code>null</code>. + * @param oldValue The old value as a {@link String}, or <code>null</code>. + * @param newValue The new value as a {@link String}, or <code>null</code>. + */ + protected void firePreferenceEvent(IEclipsePreferences node, String key, String oldValue, String newValue) { + Assert.isNotNull(node); + Assert.isNotNull(key); + + // If no listener is registered, we are done here + if (listeners.isEmpty()) return; + + // Get the list or currently registered listeners + Object[] l = listeners.getListeners(); + // Create the preference change event + final PreferenceChangeEvent event = new PreferenceChangeEvent(node, key, oldValue, newValue); + for (int i = 0; i < l.length; i++) { + final IPreferenceChangeListener listener = (IPreferenceChangeListener) l[i]; + ISafeRunnable job = new ISafeRunnable() { + @Override + public void handleException(Throwable exception) { + // already logged in Platform#run() + } + + @Override + public void run() throws Exception { + listener.preferenceChange(event); + } + }; + SafeRunner.run(job); + } + } + +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/tracing/TraceHandler.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/tracing/TraceHandler.java new file mode 100644 index 000000000..d461449d9 --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/tracing/TraceHandler.java @@ -0,0 +1,295 @@ +/******************************************************************************* + * 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.core.terminals.tracing; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.tcf.te.core.terminals.activator.CoreBundleActivator; + +/** + * Helper class to handle tracing using the platforms debug capabilities. + */ +public class TraceHandler { + /** + * The bundle identifier. + */ + private final String identifier; + + /** + * The tracer instance. + */ + private Tracer tracer = null; + + /** + * The tracer is responsible for writing the trace message to the desired + * output media. + */ + protected static class Tracer { + + /** + * The bundle identifier. + */ + private final String fIdentifier; + + /** + * The qualifier for the default "<bundle identifier>/debugmode" + * tracing slot. + */ + private final String fDebugModeQualifier; + + /** + * Constructor. + * + * @param identifier The bundle identifier. Must not be <code>null</code>. + */ + public Tracer(String identifier) { + Assert.isNotNull(identifier); + fIdentifier = identifier; + + // Initialize the debug mode qualifier + fDebugModeQualifier = fIdentifier + "/debugmode"; //$NON-NLS-1$ + } + + /** + * Returns the value of the debug mode tracing slot. + * <p> + * If not set, or the value is not an {@link Integer}, the method returns <code>0</code>. + * + * @return The debug mode value. + */ + protected int getDebugMode() { + try { + String mode = Platform.getDebugOption(fDebugModeQualifier); + if (mode != null && Integer.decode(mode).intValue() > 0) { + return Integer.decode(mode).intValue(); + } + } catch (NumberFormatException e) { /* ignored on purpose */ } + + return 0; + } + + /** + * Check if the specified trace slot is enabled. + * + * @param slotId The name of the slot. + * @return <code>true</code> if the slot is defined and enabled, <code>false</code> otherwise. + */ + protected boolean isSlotEnabled(String slotId) { + return fIdentifier != null ? Boolean.parseBoolean(Platform.getDebugOption(fIdentifier + "/" + slotId)) : false; //$NON-NLS-1$ + } + + /** + * Check if tracing is enabled for given mode and slot. + * + * @param debugMode The debug mode for the current debug. + * @param slotId The name of the slot. + * + * @return <code>true</code> if the debug should be written, <code>false</code> otherwise. + */ + protected final boolean isEnabled(int debugMode, String slotId) { + return getDebugMode() < 0 || + (debugMode <= getDebugMode() && + (slotId == null || slotId.trim().length() == 0 || isSlotEnabled(slotId))); + } + + /** + * Format the trace message. + * + * @param message The trace message. + * @param debugMode The debug mode. + * @param slotId The name of the slot. + * @param severity The severity. See {@link IStatus} for valid severity values. + * @param clazz The class that calls this tracer. + * + * @see IStatus + */ + protected String getFormattedDebugMessage(String message, int debugMode, String slotId, int severity, Object clazz) { + StringBuffer debug = new StringBuffer(); + if (slotId != null || clazz != null) { + if (clazz != null) { + String name = clazz instanceof Class<?> ? ((Class<?>)clazz).getSimpleName() : clazz.getClass().getSimpleName(); + debug.append(name.trim().length() > 0 ? name.trim() : clazz instanceof Class<?> ? ((Class<?>)clazz).getName() : clazz.getClass().getName()); + } + if (slotId != null) { + debug.append(" at "); //$NON-NLS-1$ + debug.append(slotId); + } + if (debugMode >= 0) { + debug.append(" (Mode "); //$NON-NLS-1$ + debug.append(debugMode); + debug.append(')'); + } + debug.append('\n'); + debug.append('\t'); + } + debug.append(message); + + return debug.toString(); + } + + /** + * Write the trace message. + * + * @param message The trace message. + * @param debugMode The debug mode. + * @param slotId The name of the slot. + * @param severity The severity. See {@link IStatus} for valid severity values. + * @param clazz The class that calls this tracer. + * + * @see IStatus + */ + protected void write(String message, int debugMode, String slotId, int severity, Object clazz) { + String formattedMessage = getFormattedDebugMessage(message, debugMode, slotId, severity, clazz); + if (severity == IStatus.ERROR || severity == IStatus.WARNING) { + System.err.println(formattedMessage); + } + else { + System.out.println(formattedMessage); + } + } + + /** + * Trace the given message with the given debug mode and slot. + * + * @param message The trace message. + * @param debugMode The debug mode. + * @param slotId The name of the slot. + * @param severity The severity. See {@link IStatus} for valid severity values. + * @param clazz The class that calls this tracer. + * + * @see IStatus + */ + public final void trace(String message, int debugMode, String slotId, int severity, Object clazz) { + if (isEnabled(debugMode, slotId)) { + write(message, debugMode, slotId, severity, clazz); + } + } + } + + /** + * Constructor. + * <p> + * Initializes the tracing handler with the given bundle identifier. + * + * @param identifier The bundle identifier or <code>null</code>. + */ + public TraceHandler(String identifier) { + this.identifier = identifier != null ? identifier : CoreBundleActivator.getUniqueIdentifier(); + Assert.isNotNull(this.identifier); + } + + /** + * Returns the identifier. + */ + protected final String getIdentifier() { + return identifier; + } + + /** + * Returns the tracer instance. Create a new tracer instance + * on first invocation. + * + * @return The tracer instance. + */ + protected Tracer getTracer() { + if (tracer == null) { + tracer = new Tracer(identifier); + } + return tracer; + } + + /** + * Return the current debug mode. + */ + public final int getDebugMode() { + return getTracer().getDebugMode(); + } + + /** + * Check whether a trace slot is enabled. The debug mode defaults + * to 0. + * + * @param slotId The name of the slot. + * + * @return <code>true</code> if the slot is enabled, <code>false</code> otherwise. + */ + public final boolean isSlotEnabled(String slotId) { + return isSlotEnabled(0, slotId); + } + + /** + * Check whether a trace slot is enabled with the given debug mode. + * + * @param debugMode The debug mode + * @param slotId The name of the slot. + * + * @return <code>true</code> if the slot is enabled, <code>false</code> otherwise. + */ + public final boolean isSlotEnabled(int debugMode, String slotId) { + return getTracer().isEnabled(debugMode, slotId); + } + + /** + * Trace the given message. + * <p> + * The message severity will be {@link IStatus#INFO} and the message will be + * traced unconditionally. + * + * @param message The message. + * @param clazz The class that calls this tracer or <code>null</code>. + */ + public final void trace(String message, Object clazz) { + getTracer().trace(message, 0, null, IStatus.INFO, clazz); + } + + /** + * Trace the given message. + * <p> + * The message severity will be {@link IStatus#INFO}. + * + * @param message The message. + * @param debugMode The minimum debug mode that has to be set to write out the message. + * @param clazz The class that calls this tracer or <code>null</code>. + */ + public final void trace(String message, int debugMode, Object clazz) { + getTracer().trace(message, debugMode, null, IStatus.INFO, clazz); + } + + /** + * Trace the given message. + * <p> + * The message severity will be {@link IStatus#INFO} and the debug mode + * will default to <code>0</code>. + * + * @param message The message. + * @param slotId The slot that has to be enabled to write out the message. + * @param clazz The class that calls this tracer or <code>null</code>. + */ + public final void trace(String message, String slotId, Object clazz) { + getTracer().trace(message, 0, slotId, IStatus.INFO, clazz); + } + + /** + * Trace the given message. + * + * @param message The message. + * @param debugMode The minimum debug mode that has to be set to write out the message. + * @param slotId The slot that has to be enabled to write out the message. + * @param severity The severity. See {@link IStatus} for valid severity values. + * @param clazz The class that calls this tracer or <code>null</code>. + * + * @see IStatus + */ + public final void trace(String message, int debugMode, String slotId, int severity, Object clazz) { + getTracer().trace(message, debugMode, slotId, severity, clazz); + } + +} diff --git a/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/utils/Env.java b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/utils/Env.java new file mode 100644 index 000000000..b19fea37d --- /dev/null +++ b/target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/utils/Env.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * Copyright (c) 2013, 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.core.terminals.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.Platform; +import org.eclipse.osgi.service.environment.Constants; + +/** + * Environment handling utility methods. + */ +public class Env { + + // Reference to the monitor to lock if determining the native environment + private final static Object ENV_GET_MONITOR = new Object(); + + // Reference to the native environment with the case of the variable names preserved + private static Map<String, String> nativeEnvironmentCasePreserved = null; + + /** + * Returns the merged environment of the native environment and the passed + * in environment. Passed in variables will overwrite the native environment + * if the same variables are set there. + * <p> + * For use with terminals, the parameter <code>terminal</code> should be set to + * <code>true</code>. In this case, the method will assure that the <code>TERM</code> + * environment variable is always set to <code>ANSI</code> and is not overwritten + * by the passed in environment. + * + * @param envp The environment to set on top of the native environment or <code>null</code>. + * @param terminal <code>True</code> if used with an terminal, <code>false</code> otherwise. + * + * @return The merged environment. + */ + public static String[] getEnvironment(String[] envp, boolean terminal) { + // Get the cached native environment + Map<String, String> nativeEnv = getNativeEnvironmentCasePreserved(); + // Make a copy of the native environment so it can be manipulated without changing + // the cached environment + Map<String, String> env = new LinkedHashMap<String, String>(nativeEnv); + // Set the TERM environment variable if in terminal mode + if (terminal) env.put("TERM", "xterm"); //$NON-NLS-1$ //$NON-NLS-2$ + + // On Windows, the environment variable names are not case-sensitive. However, + // we desire to preserve the original case. Build up a translation map between + // an all lowercase name and the original environment name + Map<String, String> k2n = null; + if (Platform.OS_WIN32.equals(Platform.getOS())) { + k2n = new HashMap<String, String>(); + for (String name : env.keySet()) { + k2n.put(name.toLowerCase(), name); + } + } + + // If a "local" environment is provided, merge it with the native + // environment. + if (envp != null) { + for (int i = 0; i < envp.length; i++) { + // The full provided variable in form "name=value" + String envpPart = envp[i]; + // Split the variable + String[] parts = envpPart.split("=");//$NON-NLS-1$ + String name = parts[0].trim(); + // Map the variable name to the real environment name (Windows only) + if (Platform.OS_WIN32.equals(Platform.getOS())) { + if (k2n.containsKey(name.toLowerCase())) { + String candidate = k2n.get(name.toLowerCase()); + Assert.isNotNull(candidate); + name = candidate; + } + // Filter out environment variables with bad names + if ("".equals(name.trim()) || name.contains("=") || name.contains(":")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + continue; + } + } + // Get the variable value + String value = parts.length > 1 ? parts[1].trim() : ""; //$NON-NLS-1$ + // Don't overwrite the TERM variable if in terminal mode + if (terminal && "TERM".equals(name)) continue; //$NON-NLS-1$ + // If a variable with the name does not exist, just append it + if (!env.containsKey(name) && !"<unset>".equals(value)) { //$NON-NLS-1$ + env.put(name, value); + } else if (env.containsKey(name)) { + // If the value contains the special placeholder "<unset>", remove the variable from the environment + if ("<unset>".equals(value)) {//$NON-NLS-1$ + env.remove(name); + } else { + // A variable with the name already exist, check if the value is different + String oldValue = env.get(name); + if (oldValue != null && !oldValue.equals(value) || oldValue == null && value != null) { + env.put(name, value); + } + } + } + } + } + + // Convert into an array of strings + List<String> keys = new ArrayList<String>(env.keySet()); + // On Windows hosts, sort the environment keys + if (Platform.OS_WIN32.equals(Platform.getOS())) Collections.sort(keys); + Iterator<String> iter = keys.iterator(); + List<String> strings = new ArrayList<String>(env.size()); + StringBuilder buffer = null; + while (iter.hasNext()) { + String key = iter.next(); + buffer = new StringBuilder(key); + buffer.append('=').append(env.get(key)); + strings.add(buffer.toString()); + } + + return strings.toArray(new String[strings.size()]); + } + + /** + * Determine the native environment. + * + * @return The native environment, or an empty map. + */ + private static Map<String, String> getNativeEnvironmentCasePreserved() { + synchronized (ENV_GET_MONITOR) { + if (nativeEnvironmentCasePreserved == null) { + nativeEnvironmentCasePreserved = new LinkedHashMap<String, String>(); + cacheNativeEnvironment(nativeEnvironmentCasePreserved); + } + return new LinkedHashMap<String, String>(nativeEnvironmentCasePreserved); + } + } + + /** + * Query the native environment and store it to the specified cache. + * + * @param cache The environment cache. Must not be <code>null</code>. + */ + private static void cacheNativeEnvironment(Map<String, String> cache) { + Assert.isNotNull(cache); + + try { + String nativeCommand = null; + if (Platform.getOS().equals(Constants.OS_WIN32)) { + nativeCommand = "cmd.exe /C set"; //$NON-NLS-1$ + } else if (!Platform.getOS().equals(Constants.OS_UNKNOWN)) { + nativeCommand = "env"; //$NON-NLS-1$ + } + if (nativeCommand == null) { return; } + Process process = Runtime.getRuntime().exec(nativeCommand); + + // read process directly on other platforms + // we need to parse out matching '{' and '}' for function declarations in .bash environments + // pattern is [function name]=() { and we must find the '}' on its own line with no trailing ';' + InputStream stream = process.getInputStream(); + InputStreamReader isreader = new InputStreamReader(stream); + BufferedReader reader = new BufferedReader(isreader); + try { + String line = reader.readLine(); + String key = null; + String value = null; + while (line != null) { + int func = line.indexOf("=()"); //$NON-NLS-1$ + if (func > 0) { + key = line.substring(0, func); + // scan until we find the closing '}' with no following chars + value = line.substring(func + 1); + while (line != null && !line.equals("}")) { //$NON-NLS-1$ + line = reader.readLine(); + if (line != null) { + value += line; + } + } + line = reader.readLine(); + } else { + int separator = line.indexOf('='); + if (separator > 0) { + key = line.substring(0, separator); + value = line.substring(separator + 1); + StringBuilder bufValue = new StringBuilder(value); + line = reader.readLine(); + if (line != null) { + // this line has a '=' read ahead to check next line for '=', might be broken on more + // than one line + separator = line.indexOf('='); + while (separator < 0) { + bufValue.append(line.trim()); + line = reader.readLine(); + if (line == null) { + // if next line read is the end of the file quit the loop + break; + } + separator = line.indexOf('='); + } + } + value = bufValue.toString(); + } + } + if (key != null) { + cache.put(key, value); + key = null; + value = null; + } else { + line = reader.readLine(); + } + } + } finally { + reader.close(); + } + } catch (IOException e) { + // Native environment-fetching code failed. + // This can easily happen and is not useful to log. + } + } + +} |