/*******************************************************************************
* Copyright (c) 2007, 2008 compeople AG 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:
* compeople AG (Stefan Liebig) - initial API and implementation
*******************************************************************************/
package de.compeople.commons.net.proxy;
import java.io.IOException;
import java.net.Proxy;
import java.net.ProxySelector;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.digitalstep.ntlmproxy.net.proxy.Helper;
/**
* A proxy selector that collects proxies from various other proxy selectors and
* uses all of their proxies for selection.
*/
public class CompoundProxySelector extends ProxySelector {
private Map<Integer, ProxySelector> proxySelectors = new TreeMap<Integer, ProxySelector>();
private ProxySelector savedProxySelector = null;
private Map<Proxy, List<ProxySelector>> proxyToProxySelectors = new HashMap<Proxy, List<ProxySelector>>();
private static final Logger log = LoggerFactory.getLogger(CompoundProxySelector.class);
/**
*
*/
public CompoundProxySelector() {
super();
savedProxySelector = ProxySelector.getDefault();
if (savedProxySelector != null) {
addOrReplace(Integer.MAX_VALUE, savedProxySelector);
}
}
/**
* @param priority
* @param proxySelector
* @return
*/
public ProxySelector addOrReplace(int priority, ProxySelector proxySelector) {
return proxySelectors.put(priority, proxySelector);
}
/**
* @see java.net.ProxySelector#select(java.net.URI)
*/
@Override
public List<Proxy> select(URI uri) {
if (uri == null) {
throw new IllegalArgumentException("uri must not be null");
}
List<Proxy> proxies = new ArrayList<Proxy>();
proxyToProxySelectors.clear();
for (ProxySelector selector : proxySelectors.values()) {
log.debug("Checking selector: {}", selector.toString());
List<Proxy> result;
if (uri.getScheme() == null || uri.getHost() == null) {
result = selector.select(URI.create("http://" + uri.toString()));
} else {
result = selector.select(uri);
}
associateProxiesWithSelector(selector, result);
if (!append(proxies, result)) {
log.debug("Skipping proxy selector '{}'.", selector);
}
}
// plus if necessary the no-proxy
if (proxies.isEmpty() || !proxies.contains(Proxy.NO_PROXY)) {
proxies.add(Proxy.NO_PROXY);
}
return proxies;
}
private void associateProxiesWithSelector(ProxySelector selector, List<Proxy> proxies) {
for (Proxy proxy : proxies) {
List<ProxySelector> selectors = proxyToProxySelectors.get(proxy);
if (selectors == null) {
selectors = new ArrayList<ProxySelector>();
proxyToProxySelectors.put(proxy, selectors);
}
selectors.add(selector);
}
}
/**
* @param result
* @param append
* @return true something has been added; ortherwise false
*/
private boolean append(List<Proxy> result, List<Proxy> append) {
boolean added = false;
for (Proxy proxy : append) {
if (!result.contains(proxy)) {
result.add(proxy);
added = true;
}
}
return added;
}
/**
* @see java.net.ProxySelector#connectFailed(java.net.URI,
* java.net.SocketAddress, java.io.IOException)
*/
@Override
public void connectFailed(URI uri, SocketAddress sa, IOException ioe) {
log.warn("proxy '" + sa + "' not available for url '" + uri + "'.", ioe);
List<ProxySelector> selectors = proxyToProxySelectors.get(Helper.create(Helper.proxyType(uri.getScheme()), sa));
if (selectors != null) {
for (ProxySelector selector : selectors) {
selector.connectFailed(uri, sa, ioe);
}
}
}
}