Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals')
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/TerminalContextPropertiesProviderFactory.java228
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/TerminalServiceFactory.java51
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/activator/CoreBundleActivator.java56
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalContextPropertiesProvider.java53
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalService.java73
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalServiceOutputStreamMonitorListener.java27
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/ITerminalTabListener.java27
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/IContextPropertiesConstants.java50
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/ILineSeparatorConstants.java34
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/interfaces/constants/ITerminalsConnectorConstants.java338
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/nls/Messages.java35
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/nls/Messages.properties14
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/preferences/ScopedEclipsePreferences.java459
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/tracing/TraceHandler.java295
-rw-r--r--target_explorer/plugins/org.eclipse.tcf.te.core.terminals/src/org/eclipse/tcf/te/core/terminals/utils/Env.java231
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 &quot;&lt;bundle identifier&gt;/debugmode&quot;
+ * 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.
+ }
+ }
+
+}

Back to the top