diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java index 1dcadfc..4889147 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java @@ -9,6 +9,7 @@ package org.olap4j.driver.xmla; import org.olap4j.*; + import static org.olap4j.driver.xmla.XmlaOlap4jUtil.*; import org.olap4j.driver.xmla.proxy.*; @@ -575,7 +576,7 @@ void populateList( Element root = xxx(request); for (Element o : childElements(root)) { if (o.getLocalName().equals("row")) { - handler.handle(o, context, list); + handler.handle(o, context, list, this); } } handler.sortList(list); @@ -809,7 +810,9 @@ public void handle(Element row, Context context, List list) { } static class CubeHandler extends HandlerImpl { - public void handle(Element row, Context context, List list) + + public void handle(Element row, Context context, + List list, XmlaOlap4jConnection connection) throws OlapException { /* @@ -834,7 +837,13 @@ public void handle(Element row, Context context, List list) String description = stringElement(row, "DESCRIPTION"); list.add( new XmlaOlap4jCube( - context.olap4jSchema, cubeName, description)); + context.olap4jSchema, cubeName, description, connection)); + } + + public void handle(Element row, Context context, + List list) throws OlapException { + throw new RuntimeException( + "A cube object needs a reference to the connection who created it."); } } @@ -1274,6 +1283,28 @@ void handle( Element row, Context context, List list) throws OlapException; + + /** + * Converts an XML element from an XMLA result set into a metadata + * element and appends it to a list of metadata elements. + * + * @param row XMLA element + * + * @param context Context (schema, cube, dimension, etc.) that the + * request was executed in and that the element will belong to + * + * @param list List of metadata elements to append new metadata element + * + * @param connection A reference to the connection object which populated + * the object. + * + * @throws OlapException on error + */ + void handle( + Element row, + Context context, + List list, + XmlaOlap4jConnection connection) throws OlapException; /** * Sorts a list of metadata elements. @@ -1290,6 +1321,20 @@ static abstract class HandlerImpl implements Handler { public void sortList(List list) { // do nothing - assume XMLA returned list in correct order } + + /** + *

Default implementation of the handle method with a reference to the + * connection object. + * + * @see org.olap4j.driver.xmla.XmlaOlap4jConnection.Handler + * #handle(org.w3c.dom.Element, + * org.olap4j.driver.xmla.XmlaOlap4jConnection.Context, + * java.util.List, org.olap4j.driver.xmla.XmlaOlap4jConnection) + */ + public void handle(Element row, Context context, List list, + XmlaOlap4jConnection connection) throws OlapException { + this.handle(row, context, list); + } } static class Context { diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java b/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java index a1f3229..1751b5b 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jCube.java @@ -45,6 +45,7 @@ class XmlaOlap4jCube implements Cube, Named private final NamedList namedSets = new NamedListImpl(); private final MetadataReader metadataReader; + private XmlaOlap4jConnection connection; /** * Creates an XmlaOlap4jCube. @@ -52,11 +53,13 @@ class XmlaOlap4jCube implements Cube, Named * @param olap4jSchema Schema * @param name Name * @param description Description + * @param connection */ XmlaOlap4jCube( XmlaOlap4jSchema olap4jSchema, String name, - String description) throws OlapException + String description, + XmlaOlap4jConnection connection) throws OlapException { assert olap4jSchema != null; assert description != null; @@ -64,6 +67,7 @@ class XmlaOlap4jCube implements Cube, Named this.olap4jSchema = olap4jSchema; this.name = name; this.description = description; + this.connection = connection; this.metadataReader = new CachingMetadataReader( new RawMetadataReader()); @@ -427,28 +431,80 @@ public XmlaOlap4jMember lookupMemberByUniqueName( /* (non-Javadoc) * @see org.olap4j.driver.xmla.MetadataReader * #lookupMembersByUniqueName(java.util.List, java.util.Map) - * TODO Optimize this process so we don't always send N requests for N members. */ public void lookupMembersByUniqueName( List memberUniqueNames, Map memberMap) throws OlapException { - List memberList = + if (connection.getDataSourceInfo() + .indexOf("Provider=Mondrian") != -1) + { + memberMap.putAll(this.mondrianMembersLookup(memberUniqueNames)); + } else { + memberMap.putAll(this.genericMembersLookup(memberUniqueNames)); + } + } + + /** + * This is an optimized method for Mondrian servers members lookup. + * @param memberUniqueNames A list of the members to lookup + * @return A map of members with their unique name as a key + * @throws OlapException Gets thrown for communication errors + */ + private Map mondrianMembersLookup( + List memberUniqueNames) throws OlapException + { + final XmlaOlap4jConnection.Context context = + new XmlaOlap4jConnection.Context( + XmlaOlap4jCube.this, null, null, null); + final List memberList = new ArrayList(); - for (String currentMemberName : memberUniqueNames) { - memberList.add( - this.lookupMemberByUniqueName(currentMemberName)); + olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection + .populateList( + memberList, + context, + XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEMBERS, + new XmlaOlap4jConnection.MemberHandler(), + new Object[] { + "CATALOG_NAME", olap4jSchema.olap4jCatalog.getName(), + "SCHEMA_NAME", olap4jSchema.getName(), + "CUBE_NAME", getName(), + "MEMBER_UNIQUE_NAME", memberUniqueNames + }); + final Map memberMap = + new HashMap(memberUniqueNames.size()); + for (XmlaOlap4jMember member : memberList) { + if (member != null) { + memberMap.put(member.getUniqueName(), member); + } } - // All members have been found without errors, - // we can populate the map. - for (XmlaOlap4jMember currentMember : memberList) { - if (currentMember != null && - !memberMap.containsKey(currentMember.getUniqueName())) - { - memberMap.put(currentMember.getUniqueName(), - currentMember); + return memberMap; + } + + /** + * This is an generic method for members lookup. + * @param memberUniqueNames A list of the members to lookup + * @return A map of members with their unique name as a key + * @throws OlapException Gets thrown for communication errors + */ + private Map genericMembersLookup( + List memberUniqueNames) throws OlapException + { + final Map memberMap = + new HashMap(memberUniqueNames.size()); + // Iterates through member names + for (String currentMemberName : memberUniqueNames) { + // Only lookup if it is not in the map yet + if (!memberMap.containsKey(currentMemberName)) { + XmlaOlap4jMember member = + this.lookupMemberByUniqueName(currentMemberName); + // Null members might mean calculated members + if (member != null) { + memberMap.put(member.getUniqueName(), member); + } } } + return memberMap; } public void lookupMemberRelatives(