Java tutorial
/* * Copyright 2000-2012 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.intellij.util.net; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.components.*; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.options.ShowSettingsUtil; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.ui.DialogWrapper; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.popup.util.PopupUtil; import com.intellij.openapi.util.*; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.openapi.wm.IdeFrame; import com.intellij.util.WaitForProgressToShow; import com.intellij.util.proxy.CommonProxy; import com.intellij.util.proxy.JavaProxyProperty; import com.intellij.util.xmlb.XmlSerializer; import com.intellij.util.xmlb.XmlSerializerUtil; import com.intellij.util.xmlb.annotations.Transient; import org.apache.commons.codec.binary.Base64; import org.jdom.Element; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.*; import java.util.*; /** * Created by IntelliJ IDEA. * User: stathik * Date: Oct 7, 2003 * Time: 3:58:23 PM * To change this template use Options | File Templates. */ @State(name = "HttpConfigurable", storages = { // we use two storages due to backward compatibility, see http://crucible.labs.intellij.net/cru/CR-IC-5142 @Storage(file = StoragePathMacros.APP_CONFIG + "/other.xml"), @Storage(file = StoragePathMacros.APP_CONFIG + "/proxy.settings.xml") }, storageChooser = LastStorageChooserForWrite.class) public class HttpConfigurable implements PersistentStateComponent<HttpConfigurable>, ApplicationComponent, JDOMExternalizable { private static final Logger LOG = Logger.getInstance("#com.intellij.util.net.HttpConfigurable"); public boolean PROXY_TYPE_IS_SOCKS = false; public boolean USE_HTTP_PROXY = false; public boolean USE_PROXY_PAC = false; public volatile transient boolean AUTHENTICATION_CANCELLED = false; public String PROXY_HOST = ""; public int PROXY_PORT = 80; public volatile boolean PROXY_AUTHENTICATION = false; public volatile String PROXY_LOGIN = ""; public volatile String PROXY_PASSWORD_CRYPT = ""; public boolean KEEP_PROXY_PASSWORD = false; public transient String LAST_ERROR; public Map<CommonProxy.HostInfo, ProxyInfo> myGenericPasswords = new HashMap<CommonProxy.HostInfo, ProxyInfo>(); public Set<CommonProxy.HostInfo> myGenericCancelled = new HashSet<CommonProxy.HostInfo>(); private transient final Object myLock = new Object(); private IdeaWideProxySelector mySelector; private IdeaWideAuthenticator myAuthenticator; public transient Getter<PasswordAuthentication> myTestAuthRunnable = new StaticGetter<PasswordAuthentication>( null); public transient Getter<PasswordAuthentication> myTestGenericAuthRunnable = new StaticGetter<PasswordAuthentication>( null); public String PROXY_EXCEPTIONS = ""; public static HttpConfigurable getInstance() { return ServiceManager.getService(HttpConfigurable.class); } public static boolean editConfigurable(final JComponent parent) { return ShowSettingsUtil.getInstance().editConfigurable(parent, new HTTPProxySettingsPanel(getInstance())); } @Override public HttpConfigurable getState() { final HttpConfigurable state = new HttpConfigurable(); XmlSerializerUtil.copyBean(this, state); if (!KEEP_PROXY_PASSWORD) { state.PROXY_PASSWORD_CRYPT = ""; } correctPasswords(this, state); return state; } @Override public void initComponent() { mySelector = new IdeaWideProxySelector(this); myAuthenticator = new IdeaWideAuthenticator(this); final String name = getClass().getName(); CommonProxy.getInstance().setCustom(name, mySelector); CommonProxy.getInstance().setCustomAuth(name, myAuthenticator); } @NotNull public ProxySelector getOnlyBySettingsSelector() { return mySelector; } @Override public void disposeComponent() { final String name = getClass().getName(); CommonProxy.getInstance().removeCustom(name); CommonProxy.getInstance().removeCustomAuth(name); } @NotNull @Override public String getComponentName() { return getClass().getName(); } private void correctPasswords(HttpConfigurable from, HttpConfigurable to) { synchronized (myLock) { to.myGenericPasswords = new HashMap<CommonProxy.HostInfo, ProxyInfo>(); for (Map.Entry<CommonProxy.HostInfo, ProxyInfo> entry : from.myGenericPasswords.entrySet()) { if (Boolean.TRUE.equals(entry.getValue().isStore())) { to.myGenericPasswords.put(entry.getKey(), entry.getValue()); } } } } @Override public void loadState(HttpConfigurable state) { XmlSerializerUtil.copyBean(state, this); if (!KEEP_PROXY_PASSWORD) { PROXY_PASSWORD_CRYPT = ""; } correctPasswords(state, this); } public boolean isGenericPasswordCanceled(final String host, final int port) { synchronized (myLock) { return myGenericCancelled.contains(Pair.create(host, port)); } } public void setGenericPasswordCanceled(final String host, final int port) { synchronized (myLock) { myGenericCancelled.add(new CommonProxy.HostInfo("", host, port)); } } public PasswordAuthentication getGenericPassword(final String host, final int port) { final ProxyInfo proxyInfo; synchronized (myLock) { proxyInfo = myGenericPasswords.get(new CommonProxy.HostInfo("", host, port)); } if (proxyInfo == null) return null; return new PasswordAuthentication(proxyInfo.getUsername(), decode(String.valueOf(proxyInfo.getPasswordCrypt())).toCharArray()); } public void putGenericPassword(final String host, final int port, final PasswordAuthentication authentication, final boolean remember) { final PasswordAuthentication coded = new PasswordAuthentication(authentication.getUserName(), encode(String.valueOf(authentication.getPassword())).toCharArray()); synchronized (myLock) { myGenericPasswords.put(new CommonProxy.HostInfo("", host, port), new ProxyInfo(remember, coded.getUserName(), String.valueOf(coded.getPassword()))); } } @Transient public String getPlainProxyPassword() { return decode(PROXY_PASSWORD_CRYPT); } private String decode(String value) { return new String(new Base64().decode(value.getBytes())); } @Transient public void setPlainProxyPassword(String password) { PROXY_PASSWORD_CRYPT = encode(password); } private String encode(String password) { return new String(new Base64().encode(password.getBytes())); } public PasswordAuthentication getGenericPromptedAuthentication(final String prefix, final String host, final String prompt, final int port, final boolean remember) { if (ApplicationManager.getApplication().isUnitTestMode()) { return myTestGenericAuthRunnable.get(); } final PasswordAuthentication[] value = new PasswordAuthentication[1]; final Runnable runnable = new Runnable() { public void run() { if (isGenericPasswordCanceled(host, port)) return; final PasswordAuthentication password = getGenericPassword(host, port); if (password != null) { value[0] = password; return; } final AuthenticationDialog dlg = new AuthenticationDialog(PopupUtil.getActiveComponent(), prefix + host, "Please enter credentials for: " + prompt, "", "", remember); dlg.show(); if (dlg.getExitCode() == DialogWrapper.OK_EXIT_CODE) { final AuthenticationPanel panel = dlg.getPanel(); final boolean remember1 = remember && panel.isRememberPassword(); value[0] = new PasswordAuthentication(panel.getLogin(), panel.getPassword()); putGenericPassword(host, port, value[0], remember1); } else { setGenericPasswordCanceled(host, port); } } }; runAboveAll(runnable); return value[0]; } public PasswordAuthentication getPromptedAuthentication(final String host, final String prompt) { if (AUTHENTICATION_CANCELLED) return null; final String password = getPlainProxyPassword(); if (PROXY_AUTHENTICATION && !StringUtil.isEmptyOrSpaces(PROXY_LOGIN) && !StringUtil.isEmptyOrSpaces(password)) { return new PasswordAuthentication(PROXY_LOGIN, password.toCharArray()); } // do not try to show any dialogs if application is exiting if (ApplicationManager.getApplication() == null || ApplicationManager.getApplication().isDisposeInProgress() || ApplicationManager.getApplication().isDisposed()) return null; if (ApplicationManager.getApplication().isUnitTestMode()) { return myTestGenericAuthRunnable.get(); } final String login = PROXY_LOGIN == null ? "" : PROXY_LOGIN; final PasswordAuthentication[] value = new PasswordAuthentication[1]; final Runnable runnable = new Runnable() { public void run() { if (AUTHENTICATION_CANCELLED) return; // password might have changed, and the check below is for that final String password = getPlainProxyPassword(); if (PROXY_AUTHENTICATION && !StringUtil.isEmptyOrSpaces(PROXY_LOGIN) && !StringUtil.isEmptyOrSpaces(password)) { value[0] = new PasswordAuthentication(PROXY_LOGIN, password.toCharArray()); return; } final AuthenticationDialog dlg = new AuthenticationDialog(PopupUtil.getActiveComponent(), "Proxy authentication: " + host, "Please enter credentials for: " + prompt, login, "", KEEP_PROXY_PASSWORD); dlg.show(); if (dlg.getExitCode() == DialogWrapper.OK_EXIT_CODE) { PROXY_AUTHENTICATION = true; final AuthenticationPanel panel = dlg.getPanel(); KEEP_PROXY_PASSWORD = panel.isRememberPassword(); PROXY_LOGIN = panel.getLogin(); setPlainProxyPassword(String.valueOf(panel.getPassword())); value[0] = new PasswordAuthentication(panel.getLogin(), panel.getPassword()); } else { AUTHENTICATION_CANCELLED = true; } } }; runAboveAll(runnable); return value[0]; } @SuppressWarnings("MethodMayBeStatic") private void runAboveAll(final Runnable runnable) { final Runnable throughSwing = new Runnable() { @Override public void run() { if (SwingUtilities.isEventDispatchThread()) { runnable.run(); return; } try { SwingUtilities.invokeAndWait(runnable); } catch (InterruptedException e) { LOG.info(e); } catch (InvocationTargetException e) { LOG.info(e); } } }; if (ProgressManager.getInstance().getProgressIndicator() != null) { if (ProgressManager.getInstance().getProgressIndicator().isModal()) { WaitForProgressToShow.runOrInvokeAndWaitAboveProgress(runnable); } else { throughSwing.run(); } } else { throughSwing.run(); } } //these methods are preserved for compatibility @Override public void readExternal(Element element) throws InvalidDataException { loadState(XmlSerializer.deserialize(element, HttpConfigurable.class)); } @Override public void writeExternal(Element element) throws WriteExternalException { CommonProxy.isInstalledAssertion(); XmlSerializer.serializeInto(getState(), element); if (USE_PROXY_PAC && USE_HTTP_PROXY && !ApplicationManager.getApplication().isDisposed()) { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { final IdeFrame frame = IdeFocusManager.findInstance().getLastFocusedFrame(); if (frame != null) { USE_PROXY_PAC = false; Messages.showMessageDialog(frame.getComponent(), "Proxy: both 'use proxy' and 'autodetect proxy' settings were set." + "\nOnly one of these options should be selected.\nPlease re-configure.", "Proxy setup", Messages.getWarningIcon()); editConfigurable(frame.getComponent()); } } }, ModalityState.NON_MODAL); } } /** * todo [all] It is NOT nessesary to call anything if you obey common IDEA proxy settings; * todo if you want to define your own behaviour, refer to {@link com.intellij.util.proxy.CommonProxy} * * also, this method is useful in a way that it test connection to the host [through proxy] * * @param url URL for HTTP connection * @throws IOException */ public void prepareURL(String url) throws IOException { //setAuthenticator(); CommonProxy.isInstalledAssertion(); final URLConnection connection = openConnection(url); try { connection.setConnectTimeout(3 * 1000); connection.setReadTimeout(3 * 1000); connection.connect(); connection.getInputStream(); } catch (Throwable e) { if (e instanceof IOException) { throw (IOException) e; } } finally { if (connection instanceof HttpURLConnection) { ((HttpURLConnection) connection).disconnect(); } } } public URLConnection openConnection(@NotNull String location) throws IOException { CommonProxy.isInstalledAssertion(); final URL url = new URL(location); URLConnection urlConnection = null; final List<Proxy> proxies = CommonProxy.getInstance().select(url); if (proxies == null || proxies.isEmpty()) { urlConnection = url.openConnection(); } else { IOException ioe = null; for (Proxy proxy : proxies) { try { urlConnection = url.openConnection(proxy); } catch (IOException e) { // continue iteration ioe = e; } } if (urlConnection == null && ioe != null) { throw ioe; } } return urlConnection; } /** * Opens HTTP connection to a given location using configured http proxy settings. * @param location url to connect to * @return instance of {@link HttpURLConnection} * @throws IOException in case of any I/O troubles or if created connection isn't instance of HttpURLConnection. */ @NotNull public HttpURLConnection openHttpConnection(@NotNull String location) throws IOException { URLConnection urlConnection = openConnection(location); if (urlConnection instanceof HttpURLConnection) { return (HttpURLConnection) urlConnection; } else { throw new IOException("Expected " + HttpURLConnection.class + ", but got " + urlConnection.getClass()); } } public static List<KeyValue<String, String>> getJvmPropertiesList(final boolean withAutodetection, @Nullable final URI uri) { final HttpConfigurable me = getInstance(); if (!me.USE_HTTP_PROXY && !me.USE_PROXY_PAC) { return Collections.emptyList(); } final List<KeyValue<String, String>> result = new ArrayList<KeyValue<String, String>>(); if (me.USE_HTTP_PROXY) { final boolean putCredentials = me.KEEP_PROXY_PASSWORD && StringUtil.isNotEmpty(me.PROXY_LOGIN); if (me.PROXY_TYPE_IS_SOCKS) { result.add(KeyValue.create(JavaProxyProperty.SOCKS_HOST, me.PROXY_HOST)); result.add(KeyValue.create(JavaProxyProperty.SOCKS_PORT, String.valueOf(me.PROXY_PORT))); if (putCredentials) { result.add(KeyValue.create(JavaProxyProperty.SOCKS_USERNAME, me.PROXY_LOGIN)); result.add(KeyValue.create(JavaProxyProperty.SOCKS_PASSWORD, me.getPlainProxyPassword())); } } else { result.add(KeyValue.create(JavaProxyProperty.HTTP_HOST, me.PROXY_HOST)); result.add(KeyValue.create(JavaProxyProperty.HTTP_PORT, String.valueOf(me.PROXY_PORT))); result.add(KeyValue.create(JavaProxyProperty.HTTPS_HOST, me.PROXY_HOST)); result.add(KeyValue.create(JavaProxyProperty.HTTPS_PORT, String.valueOf(me.PROXY_PORT))); if (putCredentials) { result.add(KeyValue.create(JavaProxyProperty.HTTP_USERNAME, me.PROXY_LOGIN)); result.add(KeyValue.create(JavaProxyProperty.HTTP_PASSWORD, me.getPlainProxyPassword())); } } } else if (me.USE_PROXY_PAC && withAutodetection && uri != null) { final List<Proxy> proxies = CommonProxy.getInstance().select(uri); // we will just take the first returned proxy, but we have an option to test connection through each of them, // for instance, by calling prepareUrl() if (proxies != null && !proxies.isEmpty()) { for (Proxy proxy : proxies) { if (isRealProxy(proxy)) { final SocketAddress address = proxy.address(); if (address instanceof InetSocketAddress) { final InetSocketAddress inetSocketAddress = (InetSocketAddress) address; if (Proxy.Type.SOCKS.equals(proxy.type())) { result.add(KeyValue.create(JavaProxyProperty.SOCKS_HOST, inetSocketAddress.getHostName())); result.add(KeyValue.create(JavaProxyProperty.SOCKS_PORT, String.valueOf(inetSocketAddress.getPort()))); } else { result.add(KeyValue.create(JavaProxyProperty.HTTP_HOST, inetSocketAddress.getHostName())); result.add(KeyValue.create(JavaProxyProperty.HTTP_PORT, String.valueOf(inetSocketAddress.getPort()))); result.add(KeyValue.create(JavaProxyProperty.HTTPS_HOST, inetSocketAddress.getHostName())); result.add(KeyValue.create(JavaProxyProperty.HTTPS_PORT, String.valueOf(inetSocketAddress.getPort()))); } } } } } } return result; } public static boolean isRealProxy(Proxy proxy) { return !Proxy.NO_PROXY.equals(proxy) && !Proxy.Type.DIRECT.equals(proxy.type()); } public static List<String> convertArguments(@NotNull final List<KeyValue<String, String>> list) { if (list.isEmpty()) return Collections.emptyList(); final List<String> result = new ArrayList<String>(list.size()); for (KeyValue<String, String> value : list) { result.add("-D" + value.getKey() + "=" + value.getValue()); } return result; } public void clearGenericPasswords() { synchronized (myLock) { myGenericPasswords.clear(); myGenericCancelled.clear(); } } public void removeGeneric(CommonProxy.HostInfo info) { synchronized (myLock) { myGenericPasswords.remove(info); } } public static class ProxyInfo { public boolean myStore; public String myUsername; public String myPasswordCrypt; public ProxyInfo() { } public ProxyInfo(boolean store, String username, String passwordCrypt) { myStore = store; myUsername = username; myPasswordCrypt = passwordCrypt; } public boolean isStore() { return myStore; } public void setStore(boolean store) { myStore = store; } public String getUsername() { return myUsername; } public void setUsername(String username) { myUsername = username; } public String getPasswordCrypt() { return myPasswordCrypt; } public void setPasswordCrypt(String passwordCrypt) { myPasswordCrypt = passwordCrypt; } } }