/*****************************************************************************
* Copyright (c) 2008-2012, Cloudsmith Inc.
* The code, documentation and other materials contained herein have been
* licensed under the Eclipse Public License - v 1.0 by the copyright holder
* listed above, as the Initial Contributor under such license. The text of
* such license is available at www.eclipse.org.
*****************************************************************************/
package org.eclipse.buckminster.core.commands;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.eclipse.buckminster.core.CorePlugin;
import org.eclipse.buckminster.core.Messages;
import org.eclipse.buckminster.runtime.Buckminster;
import org.eclipse.core.internal.net.Activator;
import org.eclipse.core.internal.net.PreferenceManager;
import org.eclipse.core.net.proxy.IProxyData;
import org.eclipse.core.net.proxy.IProxyService;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.preferences.ConfigurationScope;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
@SuppressWarnings("restriction")
public class ImportProxySettings extends WorkspaceCommand {
protected abstract static class AbstractHttpProxySettingsImporter extends AbstractProxySettingsImporter {
private StringBuilder propertiesPrefix;
private int prefixLength;
protected String getPrefixedPropetyName(String propertyName) {
propertiesPrefix.setLength(prefixLength);
return propertiesPrefix.append(propertyName).toString();
}
protected void importNonProxiedHostsSetting(String nonProxiedHostsPropertyName, Set<String> nonProxiedHosts) {
String nonProxiedHostsString = savedProxyProperties.getProperty(nonProxiedHostsPropertyName);
if (nonProxiedHostsString == null)
return;
for (String nonProxiedHost : nonProxiedHostsString.split("\\|")) { //$NON-NLS-1$
if ((nonProxiedHost = nonProxiedHost.trim()).length() > 0)
nonProxiedHosts.add(nonProxiedHost);
}
}
@Override
public boolean importProxySettings(IProxyData proxyDatum, Set<String> nonProxiedHosts) {
importNonProxiedHostsSetting(getPrefixedPropetyName("nonProxyHosts"), nonProxiedHosts); //$NON-NLS-1$
String proxyHost = savedProxyProperties.getProperty(getPrefixedPropetyName("proxyHost")); //$NON-NLS-1$
if (proxyHost == null || (proxyHost = proxyHost.trim()).length() == 0)
return false;
proxyDatum.setHost(proxyHost);
importProxyPortSetting(getPrefixedPropetyName("proxyPort"), proxyDatum); //$NON-NLS-1$
String proxyUser = savedProxyProperties.getProperty(getPrefixedPropetyName("proxyUser")); //$NON-NLS-1$
if (proxyUser == null)
proxyUser = savedProxyProperties.getProperty(getPrefixedPropetyName("proxyUserName")); //$NON-NLS-1$
if (proxyUser != null) {
proxyDatum.setUserid(proxyUser);
String proxyPassword = savedProxyProperties.getProperty(getPrefixedPropetyName("proxyPassword")); //$NON-NLS-1$
if (proxyPassword != null)
proxyDatum.setPassword(proxyPassword);
}
return true;
}
@Override
protected void init() {
propertiesPrefix = new StringBuilder(getProxyType().toLowerCase());
propertiesPrefix.append('.');
prefixLength = propertiesPrefix.length();
}
@Override
protected void saveProxySettingsSystemProperties() {
saveProxySystemProperty(getPrefixedPropetyName("proxySet")); //$NON-NLS-1$
saveProxySystemProperty(getPrefixedPropetyName("proxyHost")); //$NON-NLS-1$
saveProxySystemProperty(getPrefixedPropetyName("proxyPort")); //$NON-NLS-1$
saveProxySystemProperty(getPrefixedPropetyName("nonProxyHosts")); //$NON-NLS-1$
saveProxySystemProperty(getPrefixedPropetyName("proxyUser")); //$NON-NLS-1$
saveProxySystemProperty(getPrefixedPropetyName("proxyUserName")); //$NON-NLS-1$
saveProxySystemProperty(getPrefixedPropetyName("proxyPassword")); //$NON-NLS-1$
}
@Override
protected void setProxySettingsSystemPropertiesImpl(IProxyData proxyDatum) {
Properties systemProperties = System.getProperties();
String proxyHost = proxyDatum.getHost();
if (proxyHost != null) {
systemProperties.setProperty(getPrefixedPropetyName("proxySet"), Boolean.TRUE.toString()); //$NON-NLS-1$
systemProperties.setProperty(getPrefixedPropetyName("proxyHost"), proxyHost); //$NON-NLS-1$
} else {
systemProperties.remove(getPrefixedPropetyName("proxySet")); //$NON-NLS-1$
systemProperties.remove(getPrefixedPropetyName("proxyHost")); //$NON-NLS-1$
}
setProxyPortSystemProperty(getPrefixedPropetyName("proxyPort"), proxyDatum); //$NON-NLS-1$
}
}
protected abstract static class AbstractProxySettingsImporter {
protected Properties savedProxyProperties = new Properties();
public AbstractProxySettingsImporter() {
init();
saveProxySettingsSystemProperties();
}
public abstract String getProxyType();
public boolean hasSavedProxyProperties() {
return !savedProxyProperties.isEmpty();
}
protected void importProxyPortSetting(String proxyPortPropertyName, IProxyData proxyDatum) {
String proxyPortString = savedProxyProperties.getProperty(proxyPortPropertyName);
if (proxyPortString != null) {
try {
proxyDatum.setPort(Integer.parseInt(proxyPortString));
return;
} catch (NumberFormatException e) {
// fall through
}
}
proxyDatum.setPort(-1);
}
/**
* Imports the proxy settings from the properties saved by
* {@link AbstractProxySettingsImporter#saveProxySettingsSystemProperties()
* saveProxySettingsSystemProperties()} into the supplied
* {@code proxyDatum} and potentially adds any non proxied hosts defined
* in the properties to the {@code nonProxiedHostsList}.
*/
public abstract boolean importProxySettings(IProxyData proxyDatum, Set<String> nonProxiedHosts);
protected void init() {
}
public void restoreProxySettingsSystemProperties() {
System.getProperties().putAll(savedProxyProperties);
savedProxyProperties.clear();
}
/**
* Saves all proxy settings properties recognized by this
* {@link AbstractProxySettingsImporter}. I.e. removes them from the
* system properties and saves them in a private {@link Properties}
* object.
*/
protected abstract void saveProxySettingsSystemProperties();
protected void saveProxySystemProperty(String proxyPropertyName) {
Properties systemProperties = System.getProperties();
String proxyPropertyValue = systemProperties.getProperty(proxyPropertyName);
if (proxyPropertyValue == null)
return;
systemProperties.remove(proxyPropertyName);
savedProxyProperties.setProperty(proxyPropertyName, proxyPropertyValue);
}
protected void setProxyPortSystemProperty(String proxyPortPropertyName, IProxyData proxyDatum) {
int proxyPort = proxyDatum.getPort();
if (proxyPort != -1)
System.getProperties().setProperty(proxyPortPropertyName, Integer.toString(proxyPort));
else
System.getProperties().remove(proxyPortPropertyName);
}
public void setProxySettingsSystemProperties(IProxyData proxyDatum) {
setProxySettingsSystemPropertiesImpl(proxyDatum);
savedProxyProperties.clear();
}
/**
* Sets appropriate system properties to reflect the proxy settings in
* the Platform preferences. But it only sets as few properties as
* absolutely necessary to prevent warnings from the Platform proxy code
* when comparing the values in the preferences with the values in the
* system properties. I.e. the properties set by this function do not
* necessarily reflect the entire proxy settings information in the
* preferences.
*/
protected abstract void setProxySettingsSystemPropertiesImpl(IProxyData proxyDatum);
}
/**
* Creating this class suspends/disables proxies by directly manipulating
* the Pltform's proxy preferences.
* <p>
* Note that this class partially duplicates functionality provided by
* {@link org.eclipse.core.internal.net.PreferenceManager}. The reason for
* not using that class is to avoid starting/initialization of the
* {@code org.eclipse.core.net} bundle.
*/
protected static class DirectProxiesSuspender {
public static final String PREF_ENABLED = "proxiesEnabled"; //$NON-NLS-1$
protected IEclipsePreferences proxyPreferencesScope = ConfigurationScope.INSTANCE.getNode(Activator.ID);
protected Boolean proxiesEnabled;
public DirectProxiesSuspender() {
proxiesEnabled = getBoolean(PREF_ENABLED);
putBoolean(PREF_ENABLED, Boolean.FALSE);
}
public void ensureRestoreEnablesProxies() {
proxiesEnabled = Boolean.TRUE;
}
protected Boolean getBoolean(String key) {
String valueString = proxyPreferencesScope.node(PreferenceManager.ROOT).get(key, null);
return valueString == null ? null : Boolean.valueOf(valueString);
}
protected void putBoolean(String key, Boolean value) {
if (value != null)
proxyPreferencesScope.node(PreferenceManager.ROOT).put(key, value.toString());
else
proxyPreferencesScope.node(PreferenceManager.ROOT).remove(key);
}
/**
* Restores the proxiesEnabled preference value that had been effective
* at the time this {@code DirectProxiesSuspender} was created. (Or set
* it to true if the
* {@link DirectProxiesSuspender#ensureRestoreEnablesProxies()
* ensureRestoreEnablesProxies()} was called).
*/
public void restoreProxies() {
if (proxiesEnabled != Boolean.FALSE) {
putBoolean(PREF_ENABLED, proxiesEnabled);
proxiesEnabled = Boolean.FALSE;
}
}
}
protected static class HttpProxySettingsImporter extends AbstractHttpProxySettingsImporter {
@Override
public String getProxyType() {
return IProxyData.HTTP_PROXY_TYPE;
}
}
protected static class HttpsProxySettingsImporter extends AbstractHttpProxySettingsImporter {
@Override
public String getProxyType() {
return IProxyData.HTTPS_PROXY_TYPE;
}
}
protected static class SocksProxySettingsImporter extends AbstractProxySettingsImporter {
@Override
public String getProxyType() {
return IProxyData.SOCKS_PROXY_TYPE;
}
@Override
public boolean importProxySettings(IProxyData proxyDatum, Set<String> nonProxiedHosts) {
String proxyHost = savedProxyProperties.getProperty("socksProxyHost"); //$NON-NLS-1$
if (proxyHost == null)
return false;
proxyDatum.setHost(proxyHost);
importProxyPortSetting("socksProxyPort", proxyDatum); //$NON-NLS-1$
return true;
}
@Override
protected void saveProxySettingsSystemProperties() {
saveProxySystemProperty("socksProxyHost"); //$NON-NLS-1$
saveProxySystemProperty("socksProxyPort"); //$NON-NLS-1$
}
@Override
protected void setProxySettingsSystemPropertiesImpl(IProxyData proxyDatum) {
String proxyHost = proxyDatum.getHost();
if (proxyHost != null)
System.getProperties().setProperty("socksProxyHost", proxyHost); //$NON-NLS-1$
else
System.getProperties().remove("socksProxyHost"); //$NON-NLS-1$
setProxyPortSystemProperty("socksProxyPort", proxyDatum); //$NON-NLS-1$
}
}
private Map<String, AbstractProxySettingsImporter> buildProxySettingsImportersMap(AbstractProxySettingsImporter... proxySettingsImporters) {
HashMap<String, AbstractProxySettingsImporter> proxySettingsImportersMap = new HashMap<String, AbstractProxySettingsImporter>();
boolean hasSavedProxyProperties = false;
for (AbstractProxySettingsImporter proxySettingsImporter : proxySettingsImporters) {
proxySettingsImportersMap.put(proxySettingsImporter.getProxyType(), proxySettingsImporter);
hasSavedProxyProperties |= proxySettingsImporter.hasSavedProxyProperties();
}
return hasSavedProxyProperties ? proxySettingsImportersMap : null;
}
@Override
protected int internalRun(IProgressMonitor monitor) throws Exception {
Map<String, AbstractProxySettingsImporter> proxySettingsImportersMap = buildProxySettingsImportersMap(new HttpProxySettingsImporter(),
new HttpsProxySettingsImporter(), new SocksProxySettingsImporter());
if (proxySettingsImportersMap == null) {
Buckminster.getLogger().warning(Messages.No_proxy_settings_to_import);
return 0;
}
try {
// suspend the proxies
DirectProxiesSuspender proxiesSuspender = new DirectProxiesSuspender();
try {
BundleContext bundleContext = CorePlugin.getDefault().getBundle().getBundleContext();
ServiceReference<IProxyService> proxyServiceReference;
IProxyService proxyService;
Throwable t;
try {
proxyServiceReference = bundleContext.getServiceReference(IProxyService.class);
proxyService = bundleContext.getService(proxyServiceReference);
t = null;
} catch (Exception e) {
// If we don't even have the classes for this (i.e. the
// org.eclipse.core.net plugin not available)
// then we simply log and ignore
proxyServiceReference = null;
proxyService = null;
t = e;
} catch (NoClassDefFoundError e) {
proxyServiceReference = null;
proxyService = null;
t = e;
}
if (t != null) {
Buckminster.getLogger().warning(t, Messages.Platform_proxy_API_not_available);
return 0;
}
// Only do this if platform service exists
if (proxyService != null) {
try {
IProxyData[] proxyData = proxyService.getProxyData();
Set<String> nonProxiedHosts = new LinkedHashSet<String>();
boolean settingsImported = false;
for (IProxyData proxyDatum : proxyData) {
AbstractProxySettingsImporter proxySettingsImporter = proxySettingsImportersMap.get(proxyDatum.getType());
if (proxySettingsImporter != null)
settingsImported |= proxySettingsImporter.importProxySettings(proxyDatum, nonProxiedHosts);
}
if (!nonProxiedHosts.isEmpty())
proxyService.setNonProxiedHosts(nonProxiedHosts.toArray(new String[nonProxiedHosts.size()]));
if (settingsImported) {
// disable the native proxy provider
proxyService.setSystemProxiesEnabled(false);
// set the proxy data
proxyService.setProxyData(proxyData);
// update the system properties to prevent warnings
for (IProxyData proxyDatum : proxyData) {
AbstractProxySettingsImporter proxySettingsImporter = proxySettingsImportersMap.get(proxyDatum.getType());
if (proxySettingsImporter != null)
proxySettingsImporter.setProxySettingsSystemProperties(proxyDatum);
}
// and finally ensure that the suspender will enable
// the proxies upon restore
proxiesSuspender.ensureRestoreEnablesProxies();
}
} finally {
bundleContext.ungetService(proxyServiceReference);
}
} else
Buckminster.getLogger().warning(Messages.Platform_proxy_service_not_registered);
} finally {
// restore the value of the proxiesEnabled preference
proxiesSuspender.restoreProxies();
}
} finally {
// restore any system properties that we didn't override
for (AbstractProxySettingsImporter proxySettingsImporter : proxySettingsImportersMap.values())
proxySettingsImporter.restoreProxySettingsSystemProperties();
}
return 0;
}
}