diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java
index 3f28e16..f5cee2e 100644
--- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java
+++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java
@@ -72,12 +72,12 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
/**
*
Holds on to the provider name
*/
- private String providerName = null;
+ private String providerName;
/**
*
Holds on to the datasource name.
*/
- private String datasourceName = null;
+ private String datasourceName;
/**
*
Holds on to the datasource name as specified by the
@@ -90,7 +90,9 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
* query value.
*
*/
- private String nativeDatasourceName = null;
+ private String nativeDatasourceName;
+ private boolean autoCommit;
+ private boolean readOnly;
/**
*
Creates an Olap4j connection an XML/A provider.
@@ -122,12 +124,7 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
throw new AssertionError(
"does not start with '" + CONNECT_STRING_PREFIX + "'");
}
- String x = url.substring(CONNECT_STRING_PREFIX.length());
- Map map =
- ConnectStringParser.parseConnectString(x);
- for (Map.Entry entry : toMap(info).entrySet()) {
- map.put(entry.getKey(), entry.getValue());
- }
+ Map map = parseConnectString(url, info);
this.providerName = map.get(XmlaOlap4jDriver.Property.Provider.name());
this.datasourceName = map.get(XmlaOlap4jDriver.Property.DataSource.name());
@@ -170,13 +167,20 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
this.olap4jSchema = new XmlaOlap4jSchema(catalog, catalogName);
}
+ static Map parseConnectString(String url, Properties info) {
+ String x = url.substring(CONNECT_STRING_PREFIX.length());
+ Map map =
+ ConnectStringParser.parseConnectString(x);
+ for (Map.Entry entry : toMap(info).entrySet()) {
+ map.put(entry.getKey(), entry.getValue());
+ }
+ return map;
+ }
+
static boolean acceptsURL(String url) {
return url.startsWith(CONNECT_STRING_PREFIX);
}
-
-
-
// not part of public API
String getDataSourceInfo() throws OlapException
{
@@ -285,11 +289,11 @@ public String nativeSQL(String sql) throws SQLException {
}
public void setAutoCommit(boolean autoCommit) throws SQLException {
- throw new UnsupportedOperationException();
+ this.autoCommit = autoCommit;
}
public boolean getAutoCommit() throws SQLException {
- throw new UnsupportedOperationException();
+ return autoCommit;
}
public void commit() throws SQLException {
@@ -317,11 +321,11 @@ public NamedList getCatalogs() {
}
public void setReadOnly(boolean readOnly) throws SQLException {
- throw new UnsupportedOperationException();
+ this.readOnly = readOnly;
}
public boolean isReadOnly() throws SQLException {
- throw new UnsupportedOperationException();
+ return readOnly;
}
public void setCatalog(String catalog) throws SQLException {
@@ -607,7 +611,7 @@ Element xxx(String request) throws OlapException {
* values of the restriction)
*
* This signature only relays the execution to
- * {@link XmlaOlap4jConnection.generateRequest(Context,MetadataRequest,Object[])}
+ * {@link #generateRequest(Context,MetadataRequest,Object[])}
* but passes it a true value to mark any request as datasource name
* specific.
*
diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java b/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java
index 9e11569..6cdc2a2 100644
--- a/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java
+++ b/src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java
@@ -9,6 +9,7 @@
package org.olap4j.driver.xmla;
import org.olap4j.impl.Base64;
+import org.olap4j.impl.Olap4jUtil;
import java.io.*;
import java.net.URL;
@@ -48,20 +49,27 @@
*
*
Connection properties
*
+ * Unless otherwise stated, properties are optional. If a property occurs
+ * multiple times in the connect string, the first occurrence is used.
+ *
*
* Property | Description |
*
- * Server | URL of HTTP server. |
+ * Server | URL of HTTP server. Required. |
*
- * Catalog | Catalog name to use |
+ * Catalog | Catalog name to use. Required. |
*
- * Provider | Name of the XMLA provider. This option is facultative. By default, the first one available will be used. |
+ * Provider | Name of the XMLA provider. |
*
- * DataSource | Name of the XMLA datasource. This option is facultative. By default, the first one available will be used. When using a Mondrian backed XMLA server, be sure to include the full datasource name between quotes. |
+ * DataSource | Name of the XMLA datasource. When using a
+ * Mondrian backed XMLA server, be sure to
+ * include the full datasource name between
+ * quotes. |
*
- * UseThreadProxy | If true, use the proxy object in the
- * {@link #THREAD_PROXY} field. For testing.
- * Default is false. |
+ * TestProxyCookie | String that uniquely identifies a proxy
+ * object in {@link #PROXY_MAP} via which to
+ * send XMLA requests for testing
+ * purposes. |
*
*
*
@@ -71,9 +79,9 @@
*/
public class XmlaOlap4jDriver implements Driver {
public static final String NAME = "olap4j driver for XML/A";
- public static final String VERSION = "0.9.4";
+ public static final String VERSION = "0.9.5";
public static final int MAJOR_VERSION = 0;
- public static final int MINOR_VERSION = 904;
+ public static final int MINOR_VERSION = 905;
private final Factory factory;
/**
@@ -82,6 +90,8 @@ public class XmlaOlap4jDriver implements Driver {
private static final ExecutorService executor =
Executors.newCachedThreadPool();
+ private static int nextCookie;
+
static {
try {
register();
@@ -93,6 +103,9 @@ public class XmlaOlap4jDriver implements Driver {
}
}
+ /**
+ * Creates an XmlaOlap4jDriver.
+ */
protected XmlaOlap4jDriver() {
String factoryClassName;
try {
@@ -115,6 +128,11 @@ protected XmlaOlap4jDriver() {
}
}
+ /**
+ * Registers this driver.
+ *
+ * @throws SQLException on error
+ */
private static void register() throws SQLException {
DriverManager.registerDriver(new XmlaOlap4jDriver());
}
@@ -123,7 +141,9 @@ public Connection connect(String url, Properties info) throws SQLException {
if (!XmlaOlap4jConnection.acceptsURL(url)) {
return null;
}
- Proxy proxy = createProxy(info);
+ Map map =
+ XmlaOlap4jConnection.parseConnectString(url, info);
+ Proxy proxy = createProxy(map);
return factory.newConnection(proxy, url, info);
}
@@ -166,16 +186,13 @@ public boolean jdbcCompliant() {
* implementation, for testing, which talks to mondrian's XMLA service
* in-process.
*
- * @param info Connection properties
+ * @param map Connection properties
* @return A Proxy with which to submit XML requests
*/
- protected Proxy createProxy(Properties info) {
- String useThreadProxy =
- info.getProperty(
- Property.UseThreadProxy.name());
- if (useThreadProxy != null &&
- Boolean.valueOf(useThreadProxy)) {
- Proxy proxy = THREAD_PROXY.get();
+ protected Proxy createProxy(Map map) {
+ String cookie = map.get(Property.TestProxyCookie.name());
+ if (cookie != null) {
+ Proxy proxy = PROXY_MAP.get(cookie);
if (proxy != null) {
return proxy;
}
@@ -183,6 +200,16 @@ protected Proxy createProxy(Properties info) {
return new HttpProxy();
}
+ /**
+ * Returns a future object representing an asynchronous submission of an
+ * XMLA request to a URL.
+ *
+ * @param proxy Proxy via which to send the request
+ * @param url URL of XMLA server
+ * @param request Request
+ * @return Future object from which the byte array containing the result
+ * of the XMLA call can be obtained
+ */
public Future getFuture(
final Proxy proxy,
final URL url,
@@ -282,25 +309,42 @@ public String getEncodingCharsetName() {
}
/**
- * For testing.
+ * For testing. Map from a cookie value (which is uniquely generated for
+ * each test) to a proxy object. Uses a weak hash map so that, if the code
+ * that created the proxy 'forgets' the cookie value, then the proxy can
+ * be garbage-collected.
*/
- public static final ThreadLocal THREAD_PROXY =
- new ThreadLocal();
+ public static final Map PROXY_MAP =
+ Collections.synchronizedMap(new WeakHashMap());
+
+ /**
+ * Generates and returns a unique string.
+ *
+ * @return unique string
+ */
+ public static synchronized String nextCookie() {
+ return "cookie" + nextCookie++;
+ }
/**
* Properties supported by this driver.
*/
public enum Property {
- UseThreadProxy(
- "If true, use the proxy object in the THREAD_PROXY field. "
- + "For testing. Default is false."),
-
+ TestProxyCookie(
+ "String that uniquely identifies a proxy object via which to send "
+ + "XMLA requests for testing purposes."),
Server("URL of HTTP server"),
Catalog("Catalog name"),
Provider("Name of the datasource provider"),
DataSource("Name of the datasource");
+ /**
+ * Creates a property.
+ *
+ * @param description Description of property
+ */
Property(String description) {
+ Olap4jUtil.discard(description);
}
}
}
diff --git a/testsrc/org/olap4j/XmlaTester.java b/testsrc/org/olap4j/XmlaTester.java
index 4fad0d3..a2988ec 100644
--- a/testsrc/org/olap4j/XmlaTester.java
+++ b/testsrc/org/olap4j/XmlaTester.java
@@ -25,6 +25,7 @@
*/
public class XmlaTester implements TestContext.Tester {
final XmlaOlap4jDriver.Proxy proxy;
+ final String cookie;
private Connection connection;
/**
@@ -57,6 +58,8 @@ public XmlaTester()
this.proxy =
(XmlaOlap4jDriver.Proxy) constructor.newInstance(
catalogNameUrls, urlString);
+ this.cookie = XmlaOlap4jDriver.nextCookie();
+ XmlaOlap4jDriver.PROXY_MAP.put(cookie, proxy);
}
public Connection createConnection() throws SQLException {
@@ -68,21 +71,14 @@ public Connection createConnection() throws SQLException {
} catch (ClassNotFoundException e) {
throw new RuntimeException("oops", e);
}
- try {
- XmlaOlap4jDriver.THREAD_PROXY.set(proxy);
- Properties info = new Properties();
- info.setProperty(
- XmlaOlap4jDriver.Property.UseThreadProxy.name(), "true");
- info.setProperty(
- XmlaOlap4jDriver.Property.Catalog.name(), "FoodMart");
- connection =
- DriverManager.getConnection(
- getURL(),
- info);
- return connection;
- } finally {
- XmlaOlap4jDriver.THREAD_PROXY.set(null);
- }
+ Properties info = new Properties();
+ info.setProperty(
+ XmlaOlap4jDriver.Property.Catalog.name(), "FoodMart");
+ connection =
+ DriverManager.getConnection(
+ getURL(),
+ info);
+ return connection;
}
public Connection createConnectionWithUserPassword() throws SQLException {
@@ -91,15 +87,11 @@ public Connection createConnectionWithUserPassword() throws SQLException {
} catch (ClassNotFoundException e) {
throw new RuntimeException("oops", e);
}
- try {
- XmlaOlap4jDriver.THREAD_PROXY.set(proxy);
- Properties info = new Properties();
- info.setProperty("UseThreadProxy", "true");
- return DriverManager.getConnection(
- getURL(), USER, PASSWORD);
- } finally {
- XmlaOlap4jDriver.THREAD_PROXY.set(null);
- }
+ Properties info = new Properties();
+ info.setProperty(
+ XmlaOlap4jDriver.Property.Catalog.name(), "FoodMart");
+ return DriverManager.getConnection(
+ getURL(), USER, PASSWORD);
}
public String getDriverUrlPrefix() {
@@ -111,7 +103,7 @@ public String getDriverClassName() {
}
public String getURL() {
- return "jdbc:xmla:Server=http://foo;UseThreadProxy=true";
+ return "jdbc:xmla:Server=http://foo;Catalog=FoodMart;TestProxyCookie=" + cookie;
}
public Flavor getFlavor() {