Thanks to everyone.
I reviewed all the answers, but no one had a complete solution.
Since google'ing this problem leads to this page here, I will lay out a complete solution and accept my answer:
HowTo:
1 Extend CookieHandler to SessionCookieManager
this is based on How to use different cookies for each connection using HttpURLConnection and CookieManager in Java , nivs describes it correctly, does not provide a complete tho solution, So most / all credits go to it, I just do a full HowTo. SessionCookieManager is based on the Java source code http://docs.oracle.com/javase/7/docs/api/java/net/CookieManager.html
import java.io.IOException; import java.net.CookieHandler; import java.net.CookiePolicy; import java.net.CookieStore; import java.net.HttpCookie; import java.net.URI; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; public class SessionCookieManager extends CookieHandler { private CookiePolicy policyCallback; public SessionCookieManager() { this(null, null); } private final static SessionCookieManager ms_instance = new SessionCookieManager(); public static SessionCookieManager getInstance() { return ms_instance; } private final static ThreadLocal<CookieStore> ms_cookieJars = new ThreadLocal<CookieStore>() { @Override protected synchronized CookieStore initialValue() { return new InMemoryCookieStore(); } }; public void clear() { getCookieStore().removeAll(); } public SessionCookieManager(CookieStore store, CookiePolicy cookiePolicy) { // use default cookie policy if not specify one policyCallback = (cookiePolicy == null) ? CookiePolicy.ACCEPT_ALL //note that I changed it to ACCEPT_ALL : cookiePolicy; // if not specify CookieStore to use, use default one } public void setCookiePolicy(CookiePolicy cookiePolicy) { if (cookiePolicy != null) policyCallback = cookiePolicy; } public CookieStore getCookieStore() { return ms_cookieJars.get(); } public Map<String, List<String>> get(URI uri, Map<String, List<String>> requestHeaders) throws IOException { // pre-condition check if (uri == null || requestHeaders == null) { throw new IllegalArgumentException("Argument is null"); } Map<String, List<String>> cookieMap = new java.util.HashMap<String, List<String>>(); // if there no default CookieStore, no way for us to get any cookie if (getCookieStore() == null) return Collections.unmodifiableMap(cookieMap); List<HttpCookie> cookies = new java.util.ArrayList<HttpCookie>(); for (HttpCookie cookie : getCookieStore().get(uri)) { // apply path-matches rule (RFC 2965 sec. 3.3.4) if (pathMatches(uri.getPath(), cookie.getPath())) { cookies.add(cookie); } } // apply sort rule (RFC 2965 sec. 3.3.4) List<String> cookieHeader = sortByPath(cookies); cookieMap.put("Cookie", cookieHeader); return Collections.unmodifiableMap(cookieMap); } public void put(URI uri, Map<String, List<String>> responseHeaders) throws IOException { // pre-condition check if (uri == null || responseHeaders == null) { throw new IllegalArgumentException("Argument is null"); } // if there no default CookieStore, no need to remember any cookie if (getCookieStore() == null) return; for (String headerKey : responseHeaders.keySet()) { // RFC 2965 3.2.2, key must be 'Set-Cookie2' // we also accept 'Set-Cookie' here for backward compatibility if (headerKey == null || !(headerKey.equalsIgnoreCase("Set-Cookie2") || headerKey.equalsIgnoreCase("Set-Cookie") ) ) { continue; } for (String headerValue : responseHeaders.get(headerKey)) { try { List<HttpCookie> cookies = HttpCookie.parse(headerValue); for (HttpCookie cookie : cookies) { if (shouldAcceptInternal(uri, cookie)) { getCookieStore().add(uri, cookie); } } } catch (IllegalArgumentException e) { // invalid set-cookie header string // no-op } } } } /* ---------------- Private operations -------------- */ // to determine whether or not accept this cookie private boolean shouldAcceptInternal(URI uri, HttpCookie cookie) { try { return policyCallback.shouldAccept(uri, cookie); } catch (Exception ignored) { // pretect against malicious callback return false; } } /* * path-matches algorithm, as defined by RFC 2965 */ private boolean pathMatches(String path, String pathToMatchWith) { if (path == pathToMatchWith) return true; if (path == null || pathToMatchWith == null) return false; if (path.startsWith(pathToMatchWith)) return true; return false; } /* * sort cookies with respect to their path: those with more specific Path attributes * precede those with less specific, as defined in RFC 2965 sec. 3.3.4 */ private List<String> sortByPath(List<HttpCookie> cookies) { Collections.sort(cookies, new CookiePathComparator()); List<String> cookieHeader = new java.util.ArrayList<String>(); for (HttpCookie cookie : cookies) { // Netscape cookie spec and RFC 2965 have different format of Cookie // header; RFC 2965 requires a leading $Version="1" string while Netscape // does not. // The workaround here is to add a $Version="1" string in advance if (cookies.indexOf(cookie) == 0 && cookie.getVersion() > 0) { cookieHeader.add("$Version=\"1\""); } cookieHeader.add(cookie.toString()); } return cookieHeader; } static class CookiePathComparator implements Comparator<HttpCookie> { public int compare(HttpCookie c1, HttpCookie c2) { if (c1 == c2) return 0; if (c1 == null) return -1; if (c2 == null) return 1; // path rule only applies to the cookies with same name if (!c1.getName().equals(c2.getName())) return 0; // those with more specific Path attributes precede those with less specific if (c1.getPath().startsWith(c2.getPath())) return -1; else if (c2.getPath().startsWith(c1.getPath())) return 1; else return 0; } } }
Please note that in my case I changed the default value of CookiePolicy to ACCEPT_ALL
2 In the global scope, before starting any threads, call:
CookieHandler.setDefault(SessionCookieManager.getInstance());
3 When your thread is finished, call it inside:
SessionCookieManager.getInstance().clear();
again: not my idea, just putting it together. All loans are Java and https://stackoverflow.com/users/1442259/nivs