/*
// $Id: XmlaOlap4jCookieManager.java 455 2011-05-24 10:01:26Z jhyde $
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// Copyright (C) 2007-2011 Julian Hyde
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/
package org.olap4j.driver.olap4ld.proxy;
import java.net.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
/**
* <p>CookieManager is a simple utility for handling cookies when working
* with <code>java.net.URL</code> and <code>java.net.URLConnection</code>
* objects.
*
* <p>This code was taken from http://www.hccp.org/java-net-cookie-how-to.html
* and modified by Luc Boudreau to support concurrent access and be more
* thread safe.
*
* <p>Here's a few use cases examples...
*
* <hr>
* <code>
* <p>Cookiemanager cm = new CookieManager();
* <p>URL url = new URL("http://www.hccp.org/test/cookieTest.jsp");
*
* <p> . . .
*
* <p>// getting cookies:
* <p>URLConnection conn = url.openConnection();
* <p>conn.connect();
*
* <p>// setting cookies
* <p>cm.storeCookies(conn);
* <p>cm.setCookies(url.openConnection());
* </code>
* <hr>
*
* @author <a href="mailto:spam@hccp.org">Ian Brown</a>
* @version $Id: XmlaOlap4jCookieManager.java 455 2011-05-24 10:01:26Z jhyde $
**/
@SuppressWarnings("unchecked")
class XmlaOlap4jCookieManager {
private Map store;
private static final String SET_COOKIE = "Set-Cookie";
private static final String COOKIE_VALUE_DELIMITER = ";";
private static final String PATH = "path";
private static final String EXPIRES = "expires";
private static final String DATE_FORMAT = "EEE, dd-MMM-yyyy hh:mm:ss z";
private static final String SET_COOKIE_SEPARATOR = "; ";
private static final String COOKIE = "Cookie";
private static final char NAME_VALUE_SEPARATOR = '=';
private static final char DOT = '.';
private DateFormat dateFormat;
private boolean debug = false;
public XmlaOlap4jCookieManager() {
store = new ConcurrentHashMap();
dateFormat = new SimpleDateFormat(DATE_FORMAT);
}
/**
* Retrieves and stores cookies returned by the host on the other side
* of the the open java.net.URLConnection.
*
* The connection MUST have been opened using the <i>connect()</i>
* method or a IOException will be thrown.
*
* @param conn a java.net.URLConnection - must be open,
* or IOException will be thrown
* @throws java.io.IOException Thrown if <i>conn</i> is not open.
*/
public void storeCookies(URLConnection conn) {
// Determines the domain from where these cookies are being sent
String domain = getDomainFromHost(conn.getURL().getHost());
Map domainStore; // Where we will store cookies for this domain
// Checks the store to see if we have an entry for this domain
if (store.containsKey(domain)) {
// we do, so lets retrieve it from the store
domainStore = (Map) store.get(domain);
} else {
// we don't, so let's create it and put it in the store
domainStore = new ConcurrentHashMap();
store.put(domain, domainStore);
}
// OK, now we are ready to get the cookies out of the URLConnection
String headerName = null;
for (int i = 1; (headerName = conn.getHeaderFieldKey(i)) != null; i++) {
if (headerName.equalsIgnoreCase(SET_COOKIE)) {
Map cookie = new ConcurrentHashMap();
StringTokenizer st = new StringTokenizer(
conn.getHeaderField(i), COOKIE_VALUE_DELIMITER);
// the specification dictates that the first name/value pair
// in the string is the cookie name and value, so let's handle
// them as a special case:
if (st.hasMoreTokens()) {
String token = st.nextToken();
String name = token.substring(
0,
token.indexOf(NAME_VALUE_SEPARATOR));
String value =
token.substring(
token .indexOf(NAME_VALUE_SEPARATOR) + 1,
token.length());
domainStore.put(name, cookie);
cookie.put(name, value);
if (this.debug) {
System.out.println(
"Saving cookie : " + name + "=" + value);
}
}
while (st.hasMoreTokens()) {
String token = st.nextToken();
// Check if the separator does exist
// The other attributes are not stored (Ex: HttpOnly)
int separatorIndex = token.indexOf(NAME_VALUE_SEPARATOR);
if (separatorIndex > 0) {
String tokenName =
token.substring(
0,
separatorIndex)
.toLowerCase();
String tokenValue =
token.substring(
separatorIndex + 1,
token.length());
cookie.put(tokenName, tokenValue);
if (this.debug) {
System.out.println(
"Saving cookie : "
+ tokenName
+ "=" + tokenValue);
}
}
}
}
}
}
/**
* Prior to opening a URLConnection, calling this method will set all
* unexpired cookies that match the path or subpaths for thi underlying URL.
*
* <p>The connection MUST NOT have been opened method or an IOException will
* be thrown.
*
* @param conn a java.net.URLConnection - must NOT be open, or
* IOException will be thrown
*
* @throws java.io.IOException Thrown if <i>conn</i> has already been
* opened.
*/
public void setCookies(URLConnection conn) {
// Determines the domain and path to retrieve the appropriate cookies
URL url = conn.getURL();
String domain = getDomainFromHost(url.getHost());
String path = url.getPath();
Map domainStore = (Map) store.get(domain);
if (domainStore == null) {
return;
}
StringBuffer cookieStringBuffer = new StringBuffer();
Iterator cookieNames = domainStore.keySet().iterator();
while (cookieNames.hasNext()) {
String cookieName = (String) cookieNames.next();
Map cookie = (Map) domainStore.get(cookieName);
// check cookie to ensure path matches and cookie is not expired
// if all is cool, add cookie to header string
if (comparePaths((String) cookie.get(PATH), path)
&& isNotExpired((String) cookie.get(EXPIRES)))
{
cookieStringBuffer.append(cookieName);
cookieStringBuffer.append("=");
cookieStringBuffer.append((String) cookie.get(cookieName));
if (cookieNames.hasNext()) {
cookieStringBuffer.append(SET_COOKIE_SEPARATOR);
}
}
}
try {
if (this.debug
&& !(cookieStringBuffer.toString().equals("")))
{
System.out.println(
"Using cookie : " + cookieStringBuffer.toString());
}
conn.setRequestProperty(COOKIE, cookieStringBuffer.toString());
} catch (java.lang.IllegalStateException ise) {
throw new RuntimeException(
"Illegal State! Cookies cannot be set on a URLConnection that is already connected. Only call setCookies(java.net.URLConnection) AFTER calling java.net.URLConnection.connect().");
}
}
private String getDomainFromHost(String host) {
if (host.indexOf(DOT) != host.lastIndexOf(DOT)) {
return host.substring(host.indexOf(DOT) + 1);
} else {
return host;
}
}
private boolean isNotExpired(String cookieExpires) {
if (cookieExpires == null) {
return true;
}
Date now = new Date();
try {
return (now.compareTo(dateFormat.parse(cookieExpires))) <= 0;
} catch (java.text.ParseException pe) {
pe.printStackTrace();
return false;
}
}
private boolean comparePaths(String cookiePath, String targetPath) {
if (cookiePath == null) {
return true;
} else if (cookiePath.equals("/")) {
return true;
} else if (targetPath.regionMatches(
0, cookiePath, 0, cookiePath.length()))
{
return true;
} else {
return false;
}
}
/**
* Returns a string representation of stored cookies organized by domain.
*/
public String toString() {
return store.toString();
}
}
// End XmlaOlap4jCookieManager.java