package com.btr.proxy.search;
import java.awt.GraphicsEnvironment;
import java.net.ProxySelector;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import com.btr.proxy.search.browser.firefox.FirefoxProxySearchStrategy;
import com.btr.proxy.search.browser.ie.IEProxySearchStrategy;
import com.btr.proxy.search.desktop.DesktopProxySearchStrategy;
import com.btr.proxy.search.desktop.gnome.GnomeProxySearchStrategy;
import com.btr.proxy.search.desktop.kde.KdeProxySearchStrategy;
import com.btr.proxy.search.desktop.win.WinProxySearchStrategy;
import com.btr.proxy.search.env.EnvProxySearchStrategy;
import com.btr.proxy.search.java.JavaProxySearchStrategy;
import com.btr.proxy.selector.misc.BufferedProxySelector;
import com.btr.proxy.selector.misc.ProxyListFallbackSelector;
import com.btr.proxy.selector.pac.PacProxySelector;
import com.btr.proxy.util.Logger;
import com.btr.proxy.util.PlatformUtil;
import com.btr.proxy.util.ProxyException;
import com.btr.proxy.util.Logger.LogBackEnd;
import com.btr.proxy.util.Logger.LogLevel;
/*****************************************************************************
* Main class to setup and initialize the proxy detection system.<br/>
* This class can be used to select a proxy discovery strategy.<br/>
* Implements the "Builder" pattern.<br/>
* Use <code>addStrategy</code> to add one or more search strategies.<br/>
* If you are done call the <code>getProxySelector</code> method. <br/>
* Then the strategies are asked one after the other for a ProxySelector until
* an valid selector is found. <br/>
* <p>
* Invoke the static <code>getDefaultProxySearch</code> method to use a default search strategy.
* </p>
* @author Bernd Rosstauscher (proxyvole@rosstauscher.de) Copyright 2009
****************************************************************************/
public class ProxySearch implements ProxySearchStrategy {
private static final int DEFAULT_PAC_CACHE_SIZE = 20;
private static final long DEFAULT_PAC_CACHE_TTL = 1000*60*10; // 10 Minutes
private List<ProxySearchStrategy> strategies;
private int pacCacheSize;
private long pacCacheTTL;
/*****************************************************************************
* Types of proxy detection supported by the builder.
****************************************************************************/
public enum Strategy {
/// Use the platform settings.
OS_DEFAULT,
/// Use the settings of the platforms default browser.
BROWSER,
/// Use Firefox settings
FIREFOX,
/// Use InternetExplorer settings
IE,
/// Use environment variables for proxy settings.
ENV_VAR,
/// Use windows default proxy settings.
WIN,
/// Use KDE desktop default proxy settings.
KDE,
/// Use KDE desktop default proxy settings.
GNOME,
/// Use Java Networking system properties
JAVA
}
/*************************************************************************
* Constructor
************************************************************************/
public ProxySearch() {
super();
this.strategies = new ArrayList<ProxySearchStrategy>();
this.pacCacheSize = DEFAULT_PAC_CACHE_SIZE;
this.pacCacheTTL = DEFAULT_PAC_CACHE_TTL;
}
/*************************************************************************
* Sets up a ProxySearch that uses a default search strategy suitable for
* every platform.
* @return a ProxySearch initialized with default settings.
************************************************************************/
public static ProxySearch getDefaultProxySearch() {
ProxySearch s = new ProxySearch();
// Test if we are a server or a client.
boolean headless = GraphicsEnvironment.isHeadless();
if (headless) {
s.addStrategy(Strategy.JAVA);
s.addStrategy(Strategy.OS_DEFAULT);
s.addStrategy(Strategy.ENV_VAR);
} else {
s.addStrategy(Strategy.JAVA);
s.addStrategy(Strategy.BROWSER);
s.addStrategy(Strategy.OS_DEFAULT);
s.addStrategy(Strategy.ENV_VAR);
}
Logger.log(ProxySearch.class, LogLevel.TRACE, "Using default search priority: {0}", s);
return s;
}
/*************************************************************************
* Adds an search strategy to the list of proxy searches strategies.
* @param strategy the search strategy to add.
************************************************************************/
public void addStrategy(Strategy strategy) {
switch (strategy) {
case OS_DEFAULT:
this.strategies.add(new DesktopProxySearchStrategy());
break;
case BROWSER:
this.strategies.add(getDefaultBrowserStrategy());
break;
case FIREFOX:
this.strategies.add(new FirefoxProxySearchStrategy());
break;
case IE:
this.strategies.add(new IEProxySearchStrategy());
break;
case ENV_VAR:
this.strategies.add(new EnvProxySearchStrategy());
break;
case WIN:
this.strategies.add(new WinProxySearchStrategy());
break;
case KDE:
this.strategies.add(new KdeProxySearchStrategy());
break;
case GNOME:
this.strategies.add(new GnomeProxySearchStrategy());
break;
case JAVA:
this.strategies.add(new JavaProxySearchStrategy());
break;
default:
throw new IllegalArgumentException("Unknown strategy code!");
}
}
/*************************************************************************
* Sets the cache size of the PAC proxy selector cache.
* This defines the number of URLs that are cached together with the PAC
* script result. This improves performance because for URLs that are
* in the cache the script is not executed again.
* You have to set this before you add any strategies that may create a
* PAC script proxy selector.
* @param size of the cache. Set it to 0 to disable caching.
* @param ttl is the time to live of the cache entries as amount of milliseconds.
************************************************************************/
public void setPacCacheSettings(int size, long ttl) {
this.pacCacheSize = size;
this.pacCacheTTL = ttl;
}
/*************************************************************************
* Gets the search strategy for the platforms default browser.
* @return a ProxySearchStrategy, null if no supported browser was found.
************************************************************************/
private ProxySearchStrategy getDefaultBrowserStrategy() {
switch (PlatformUtil.getDefaultBrowser()) {
case IE:
return new IEProxySearchStrategy();
case FIREFOX:
return new FirefoxProxySearchStrategy();
}
return null;
}
/*************************************************************************
* Gets the proxy selector that will use the configured search order.
* @return a ProxySelector, null if none was found for the current
* builder configuration.
************************************************************************/
public ProxySelector getProxySelector() {
Logger.log(getClass(), LogLevel.TRACE, "Executing search strategies to find proxy selector");
for (ProxySearchStrategy strat : this.strategies) {
try {
ProxySelector selector = strat.getProxySelector();
if (selector != null) {
selector = installBufferingAndFallbackBehaviour(selector);
return selector;
}
} catch (ProxyException e) {
Logger.log(getClass(), LogLevel.DEBUG, "Strategy {0} failed trying next one.", e);
// Ignore and try next strategy.
}
}
return null;
}
/*************************************************************************
* If it is PAC and we have caching enabled set it here.
* @param selector
* @return
************************************************************************/
private ProxySelector installBufferingAndFallbackBehaviour(ProxySelector selector) {
if (selector instanceof PacProxySelector) {
if (this.pacCacheSize > 0) {
selector = new BufferedProxySelector(this.pacCacheSize, this.pacCacheTTL, selector);
}
selector = new ProxyListFallbackSelector(selector);
}
return selector;
}
/*************************************************************************
* toString
* @see java.lang.Object#toString()
************************************************************************/
@Override
public String toString() {
StringBuilder sb = new StringBuilder("Proxy search: ");
for (ProxySearchStrategy strat : this.strategies) {
sb.append(strat);
sb.append(" ");
}
return sb.toString();
}
/*************************************************************************
* For testing only. Will print the logging & proxy information to the console.
* @param args the command line arguments.
************************************************************************/
public static void main(String[] args) {
ProxySearch ps = ProxySearch.getDefaultProxySearch();
Logger.setBackend(new LogBackEnd() {
public void log(Class<?> clazz, LogLevel loglevel, String msg,
Object... params) {
System.out.println(MessageFormat.format(msg, params));
}
public boolean isLogginEnabled(LogLevel logLevel) {
return true;
}
});
ps.getProxySelector();
}
}