Skip to content

Commit

Permalink
Added two parameters to the XMLA driver url.
Browse files Browse the repository at this point in the history
DataSource: defines the datasource name to use.
Provider: defines the provider name to use.

Both these parameters are retrocompatible. Default behavior is to use the first datasource returned by the XMLA server backend.

git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@82 c6a108a4-781c-0410-a6c6-c2d559e19af0
  • Loading branch information
lucboudreau committed Apr 1, 2008
1 parent 6a62a7d commit e1b7a59
Show file tree
Hide file tree
Showing 3 changed files with 211 additions and 32 deletions.
228 changes: 198 additions & 30 deletions src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,66 @@
*/
package org.olap4j.driver.xmla;

import org.olap4j.*;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*;
import org.olap4j.impl.*;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.ROWSET_NS;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.SOAP_NS;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.XMLA_NS;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.booleanElement;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.childElements;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.findChild;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.integerElement;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.parse;
import static org.olap4j.driver.xmla.XmlaOlap4jUtil.stringElement;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Savepoint;
import java.sql.Statement;
import java.util.AbstractMap;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.regex.Pattern;

import org.olap4j.Cell;
import org.olap4j.OlapConnection;
import org.olap4j.OlapDatabaseMetaData;
import org.olap4j.OlapException;
import org.olap4j.OlapStatement;
import org.olap4j.PreparedOlapStatement;
import org.olap4j.impl.ConnectStringParser;
import org.olap4j.impl.Named;
import org.olap4j.impl.Olap4jUtil;
import org.olap4j.mdx.ParseTreeWriter;
import org.olap4j.mdx.SelectNode;
import org.olap4j.mdx.parser.*;
import org.olap4j.mdx.parser.MdxParser;
import org.olap4j.mdx.parser.MdxParserFactory;
import org.olap4j.mdx.parser.MdxValidator;
import org.olap4j.mdx.parser.impl.DefaultMdxParserImpl;
import org.olap4j.metadata.*;
import org.olap4j.metadata.Catalog;
import org.olap4j.metadata.Datatype;
import org.olap4j.metadata.Dimension;
import org.olap4j.metadata.Level;
import org.olap4j.metadata.Measure;
import org.olap4j.metadata.Member;
import org.olap4j.metadata.NamedList;
import org.olap4j.metadata.Property;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.sql.*;
import java.util.*;
import java.util.regex.Pattern;

/**
* Implementation of {@link org.olap4j.OlapConnection}
* for XML/A providers.
Expand Down Expand Up @@ -58,16 +99,39 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
final XmlaOlap4jDriver.Proxy proxy;

private boolean closed;

/**
* URL of the HTTP server to which to send XML requests.
*/
final URL serverUrl;

private Locale locale;
private String catalogName;
private static final boolean DEBUG = true;
private static final boolean DEBUG = false;
private String roleName;

/**
* Holds on to the provider name
*/
private String providerName = null;

/**
* Holds on to the datasource name.
*/
private String datasourceName = null;

/**
* Holds on to the datasource name as specified by the
* server. Some servers (mondrian...) return both the provider
* name and the datasource name in their response.
*
* It's bad but hey, you gotta live with it.
*
* It's this value that we use inside queries, and not the jdbc
* query value.
*
*/
private String nativeDatasourceName = null;

/**
* Creates an Olap4j connection an XML/A provider.
Expand Down Expand Up @@ -106,6 +170,8 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
map.put(entry.getKey(), entry.getValue());
}

this.providerName = map.get(XmlaOlap4jDriver.Property.Provider.name());
this.datasourceName = map.get(XmlaOlap4jDriver.Property.DataSource.name());
this.catalogName = map.get(XmlaOlap4jDriver.Property.Catalog.name());

// Set URL of HTTP server.
Expand All @@ -121,7 +187,7 @@ abstract class XmlaOlap4jConnection implements OlapConnection {
// as part of the standard URL scheme.
if (map.containsKey("user") && map.containsKey("password")) {
serverUrl = serverUrl.replaceFirst(
":\\/\\/(.*\\@){0,1}",
":\\/\\/([^@]*@){0,1}",
"://"
.concat(map.get("user"))
.concat(":")
Expand Down Expand Up @@ -149,10 +215,75 @@ static boolean acceptsURL(String url) {
return url.startsWith(CONNECT_STRING_PREFIX);
}




// not part of public API
String getDataSourceInfo() {
// todo:
return "MondrianFoodMart";
String getDataSourceInfo() throws OlapException
{
// If we already know it, return it.
if ( this.nativeDatasourceName != null )
return this.nativeDatasourceName;

try
{
// We need to query for it
ResultSet rSet = this.olap4jDatabaseMetaData.getDatasources();



// Check if the user requested a particular one.
if (this.datasourceName != null || this.providerName != null)
{
// We iterate through the datasources
datasources : while ( rSet.next() )
{
// Get current values
String currentDatasource = rSet.getString("DATA_SOURCE_NAME"); //$NON-NLS-1$
String currentProvider = rSet.getString("PROVIDER_NAME"); //$NON-NLS-1$

// If datasource and provider match, we got it.
// If datasource matches but no provider is specified, we got it.
// If provider matches but no datasource specified, we consider it good.
if (
( currentDatasource.equals(this.datasourceName)
&& currentProvider.equals(this.providerName) )
||
( currentDatasource.equals(this.datasourceName)
&& this.providerName == null )
||
( currentProvider.equals(this.providerName)
&& this.datasourceName == null )
)
{
// Got it
this.nativeDatasourceName = rSet.getString("DATA_SOURCE_NAME");
break datasources;
}

} // datasources loop
}
else
{
// Use first
rSet.first();

// Keep it
this.nativeDatasourceName = rSet.getString("DATA_SOURCE_NAME"); //$NON-NLS-1$
}

// Crash if no valid datasource is found.
if ( this.nativeDatasourceName == null )
throw new OlapException("No datasource could be found.");

// If there is a provider
return this.nativeDatasourceName;

} catch (SQLException e)
{
// We tried...
throw new OlapException("Datasource name not found.", e);
}
}

public OlapStatement createStatement() {
Expand Down Expand Up @@ -484,6 +615,35 @@ Element xxx(String request) throws OlapException {
return findChild(returnElement, ROWSET_NS, "root");
}


/**
* Generates a metadata request.
*
* <p>The list of restrictions must have even length. Even elements must
* be a string (the name of the restriction); odd elements must be either
* a string (the value of the restriction) or a list of strings (multiple
* values of the restriction)
*
* <p>This signature only relays the execution to
* {@link XmlaOlap4jConnection.generateRequest(Context,MetadataRequest,Object[])}
* but passes it a true value to mark any request as datasource name
* specific.
*
* @param context Context
* @param metadataRequest Metadata request
* @param restrictions List of restrictions
* @return XMLA request
* @throws OlapException
*/
public String generateRequest(
Context context,
MetadataRequest metadataRequest,
Object[] restrictions) throws OlapException
{
return this.generateRequest(context, metadataRequest, restrictions, true);
}


/**
* Generates a metadata request.
*
Expand All @@ -496,15 +656,16 @@ Element xxx(String request) throws OlapException {
* @param context Context
* @param metadataRequest Metadata request
* @param restrictions List of restrictions
* @param datasourceDependentRequest Should we lookup the datasource name ?
* @return XMLA request
* @throws OlapException
*/
public String generateRequest(
Context context,
MetadataRequest metadataRequest,
Object[] restrictions)
Object[] restrictions,
boolean datasourceDependentRequest) throws OlapException
{
final String dataSourceInfo =
context.olap4jConnection.getDataSourceInfo();
final String catalog =
context.olap4jConnection.getCatalog();
final String content = "Data";
Expand Down Expand Up @@ -549,14 +710,22 @@ public String generateRequest(
buf.append(" </RestrictionList>\n"
+ " </Restrictions>\n"
+ " <Properties>\n"
+ " <PropertyList>\n"
+ " <DataSourceInfo>");
buf.append(dataSourceInfo);
buf.append("</DataSourceInfo>\n"
+ " <Catalog>");
buf.append(catalog);
buf.append("</Catalog>\n"
+ " <Content>" + content + "</Content>\n"
+ " <PropertyList>\n");


// Add the datasource node only if this request requires it.
if ( datasourceDependentRequest )
{
buf.append(" <DataSourceInfo>");
buf.append( context.olap4jConnection.getDataSourceInfo() );
buf.append("</DataSourceInfo>\n <Catalog>");
buf.append(catalog);
buf.append("</Catalog>\n");
}



buf.append(" <Content>" + content + "</Content>\n"
+ " </PropertyList>\n"
+ " </Properties>\n"
+ " </Discover>\n"
Expand Down Expand Up @@ -592,7 +761,6 @@ private static String xmlEncode(String value){

// ~ inner classes --------------------------------------------------------

@SuppressWarnings({"ThrowableInstanceNeverThrown"})
static class Helper {
OlapException createException(String msg) {
return new OlapException(msg);
Expand Down
5 changes: 4 additions & 1 deletion src/org/olap4j/driver/xmla/XmlaOlap4jDatabaseMetaData.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,12 +101,15 @@ private ResultSet getMetadata(
patternValueList.add((String) value);
}
}

String request =
olap4jConnection.generateRequest(
context,
metadataRequest,
patternValueList.toArray(
new String[patternValueList.size()]));
new String[patternValueList.size()]),
metadataRequest.equals( XmlaOlap4jConnection.MetadataRequest.DISCOVER_DATASOURCES ) ? false : true);

final Element root = olap4jConnection.xxx(request);
List<List<Object>> rowList = new ArrayList<List<Object>>();
rowLoop:
Expand Down
10 changes: 9 additions & 1 deletion src/org/olap4j/driver/xmla/XmlaOlap4jDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@
* <tr> <th>Property</th> <th>Description</th> </tr>
*
* <tr> <td>Server</td> <td>URL of HTTP server.</td> </tr>
*
* <tr> <td>Catalog</td> <td>Catalog name to use</td> </tr>
*
* <tr> <td>Provider</td> <td>Name of the XMLA provider. This option is facultative. By default, the first one available will be used.</td> </tr>
*
* <tr> <td>DataSource</td> <td>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.</td> </tr>
*
* <tr> <td>UseThreadProxy</td> <td>If true, use the proxy object in the
* {@link #THREAD_PROXY} field. For testing.
Expand Down Expand Up @@ -290,7 +296,9 @@ public enum Property {
+ "For testing. Default is false."),

Server("URL of HTTP server"),
Catalog("Catalog name");
Catalog("Catalog name"),
Provider("Name of the datasource provider"),
DataSource("Name of the datasource");

Property(String description) {
}
Expand Down

0 comments on commit e1b7a59

Please sign in to comment.