001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.io.IOException; 007import java.net.InetSocketAddress; 008import java.net.Proxy; 009import java.net.Proxy.Type; 010import java.net.ProxySelector; 011import java.net.SocketAddress; 012import java.net.URI; 013import java.util.Collections; 014import java.util.List; 015 016import org.openstreetmap.josm.Main; 017import org.openstreetmap.josm.gui.preferences.server.ProxyPreferencesPanel; 018import org.openstreetmap.josm.gui.preferences.server.ProxyPreferencesPanel.ProxyPolicy; 019 020/** 021 * This is the default proxy selector used in JOSM. 022 * 023 */ 024public class DefaultProxySelector extends ProxySelector { 025 /** 026 * The {@link ProxySelector} provided by the JDK will retrieve proxy information 027 * from the system settings, if the system property <tt>java.net.useSystemProxies</tt> 028 * is defined <strong>at startup</strong>. It has no effect if the property is set 029 * later by the application. 030 * 031 * We therefore read the property at class loading time and remember it's value. 032 */ 033 private static boolean JVM_WILL_USE_SYSTEM_PROXIES = false; 034 static { 035 String v = System.getProperty("java.net.useSystemProxies"); 036 if (v != null && v.equals(Boolean.TRUE.toString())) { 037 JVM_WILL_USE_SYSTEM_PROXIES = true; 038 } 039 } 040 041 /** 042 * The {@link ProxySelector} provided by the JDK will retrieve proxy information 043 * from the system settings, if the system property <tt>java.net.useSystemProxies</tt> 044 * is defined <strong>at startup</strong>. If the property is set later by the application, 045 * this has no effect. 046 * 047 * @return true, if <tt>java.net.useSystemProxies</tt> was set to true at class initialization time 048 * 049 */ 050 public static boolean willJvmRetrieveSystemProxies() { 051 return JVM_WILL_USE_SYSTEM_PROXIES; 052 } 053 054 private ProxyPolicy proxyPolicy; 055 private InetSocketAddress httpProxySocketAddress; 056 private InetSocketAddress socksProxySocketAddress; 057 private ProxySelector delegate; 058 059 /** 060 * A typical example is: 061 * <pre> 062 * PropertySelector delegate = PropertySelector.getDefault(); 063 * PropertySelector.setDefault(new DefaultPropertySelector(delegate)); 064 * </pre> 065 * 066 * @param delegate the proxy selector to delegate to if system settings are used. Usually 067 * this is the proxy selector found by ProxySelector.getDefault() before this proxy 068 * selector is installed 069 */ 070 public DefaultProxySelector(ProxySelector delegate) { 071 this.delegate = delegate; 072 initFromPreferences(); 073 } 074 075 protected int parseProxyPortValue(String property, String value) { 076 if (value == null) return 0; 077 int port = 0; 078 try { 079 port = Integer.parseInt(value); 080 } catch (NumberFormatException e) { 081 Main.error(tr("Unexpected format for port number in in preference ''{0}''. Got ''{1}''.", property, value)); 082 Main.error(tr("The proxy will not be used.")); 083 return 0; 084 } 085 if (port <= 0 || port > 65535) { 086 Main.error(tr("Illegal port number in preference ''{0}''. Got {1}.", property, port)); 087 Main.error(tr("The proxy will not be used.")); 088 return 0; 089 } 090 return port; 091 } 092 093 /** 094 * Initializes the proxy selector from the setting in the preferences. 095 * 096 */ 097 public void initFromPreferences() { 098 String value = Main.pref.get(ProxyPreferencesPanel.PROXY_POLICY); 099 if (value.length() == 0) { 100 proxyPolicy = ProxyPolicy.NO_PROXY; 101 } else { 102 proxyPolicy = ProxyPolicy.fromName(value); 103 if (proxyPolicy == null) { 104 Main.warn(tr("Unexpected value for preference ''{0}'' found. Got ''{1}''. Will use no proxy.", ProxyPreferencesPanel.PROXY_POLICY, value)); 105 proxyPolicy = ProxyPolicy.NO_PROXY; 106 } 107 } 108 String host = Main.pref.get(ProxyPreferencesPanel.PROXY_HTTP_HOST, null); 109 int port = parseProxyPortValue(ProxyPreferencesPanel.PROXY_HTTP_PORT, Main.pref.get(ProxyPreferencesPanel.PROXY_HTTP_PORT, null)); 110 httpProxySocketAddress = null; 111 if (proxyPolicy.equals(ProxyPolicy.USE_HTTP_PROXY)) { 112 if (host != null && !host.trim().isEmpty() && port > 0) { 113 httpProxySocketAddress = new InetSocketAddress(host, port); 114 } else { 115 Main.warn(tr("Unexpected parameters for HTTP proxy. Got host ''{0}'' and port ''{1}''.", host, port)); 116 Main.warn(tr("The proxy will not be used.")); 117 } 118 } 119 120 host = Main.pref.get(ProxyPreferencesPanel.PROXY_SOCKS_HOST, null); 121 port = parseProxyPortValue(ProxyPreferencesPanel.PROXY_SOCKS_PORT, Main.pref.get(ProxyPreferencesPanel.PROXY_SOCKS_PORT, null)); 122 socksProxySocketAddress = null; 123 if (proxyPolicy.equals(ProxyPolicy.USE_SOCKS_PROXY)) { 124 if (host != null && !host.trim().isEmpty() && port > 0) { 125 socksProxySocketAddress = new InetSocketAddress(host,port); 126 } else { 127 Main.warn(tr("Unexpected parameters for SOCKS proxy. Got host ''{0}'' and port ''{1}''.", host, port)); 128 Main.warn(tr("The proxy will not be used.")); 129 } 130 } 131 } 132 133 @Override 134 public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { 135 // Just log something. The network stack will also throw an exception which will be caught somewhere else 136 // 137 Main.error(tr("Connection to proxy ''{0}'' for URI ''{1}'' failed. Exception was: {2}", sa.toString(), uri.toString(), ioe.toString())); 138 } 139 140 @Override 141 public List<Proxy> select(URI uri) { 142 Proxy proxy; 143 switch(proxyPolicy) { 144 case USE_SYSTEM_SETTINGS: 145 if (!JVM_WILL_USE_SYSTEM_PROXIES) { 146 Main.warn(tr("The JVM is not configured to lookup proxies from the system settings. The property ''java.net.useSystemProxies'' was missing at startup time. Will not use a proxy.")); 147 return Collections.singletonList(Proxy.NO_PROXY); 148 } 149 // delegate to the former proxy selector 150 List<Proxy> ret = delegate.select(uri); 151 return ret; 152 case NO_PROXY: 153 return Collections.singletonList(Proxy.NO_PROXY); 154 case USE_HTTP_PROXY: 155 if (httpProxySocketAddress == null) 156 return Collections.singletonList(Proxy.NO_PROXY); 157 proxy = new Proxy(Type.HTTP, httpProxySocketAddress); 158 return Collections.singletonList(proxy); 159 case USE_SOCKS_PROXY: 160 if (socksProxySocketAddress == null) 161 return Collections.singletonList(Proxy.NO_PROXY); 162 proxy = new Proxy(Type.SOCKS, socksProxySocketAddress); 163 return Collections.singletonList(proxy); 164 } 165 // should not happen 166 return null; 167 } 168}