Skip to content

Commit

Permalink
Ensure that members of the Measures dimension implement Measure inter…
Browse files Browse the repository at this point in the history
…face, and that list inclues calculated members defined against the cube.

git-svn-id: https://olap4j.svn.sourceforge.net/svnroot/olap4j/trunk@92 c6a108a4-781c-0410-a6c6-c2d559e19af0
  • Loading branch information
julianhyde committed Apr 17, 2008
1 parent d7bfc03 commit ecad30c
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 30 deletions.
2 changes: 2 additions & 0 deletions src/org/olap4j/driver/xmla/XmlaOlap4jCatalog.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class XmlaOlap4jCatalog implements Catalog, Named {
XmlaOlap4jDatabaseMetaData olap4jDatabaseMetaData,
String name)
{
assert olap4jDatabaseMetaData != null;
assert name != null;
this.olap4jDatabaseMetaData = olap4jDatabaseMetaData;
this.name = name;
this.schemas =
Expand Down
42 changes: 24 additions & 18 deletions src/org/olap4j/driver/xmla/XmlaOlap4jCellSet.java
Original file line number Diff line number Diff line change
Expand Up @@ -305,37 +305,43 @@ void populate() throws OlapException {
* are supported, but no dates are yet supported. Those not supported
* fall back to Strings.
*
* <p>If any exception is encountered, it returns null.
*
* @param cell The cell of which we want the casted object.
* @return The object with a correct value.
* @throws OlapException gets thrown if any error is encountered while casting the cell value.
* @throws OlapException if any error is encountered while casting the cell
* value
*/
private Object getTypedValue(Element cell) throws OlapException {
try {
Element elm = findChild(cell, MDDATASET_NS, "Value");
Element elm = findChild(cell, MDDATASET_NS, "Value");
if (elm == null) {
// Cell is null.
return null;
}

// The object type is contained in xsi:type attribute.
String type = elm.getAttribute("xsi:type");
if (type.equals( "xsd:int")) {
return XmlaOlap4jUtil.intElement(cell, "Value");
// The object type is contained in xsi:type attribute.
String type = elm.getAttribute("xsi:type");
try {
if (type.equals( "xsd:int")) {
return XmlaOlap4jUtil.intElement(cell, "Value");
} else if (type.equals( "xsd:integer")) {
return XmlaOlap4jUtil.integerElement(cell, "Value");
return XmlaOlap4jUtil.integerElement(cell, "Value");
} else if (type.equals( "xsd:double")) {
return XmlaOlap4jUtil.doubleElement(cell, "Value");
return XmlaOlap4jUtil.doubleElement(cell, "Value");
} else if (type.equals( "xsd:float")) {
return XmlaOlap4jUtil.floatElement(cell, "Value");
return XmlaOlap4jUtil.floatElement(cell, "Value");
} else if (type.equals( "xsd:long")) {
return XmlaOlap4jUtil.longElement(cell, "Value");
return XmlaOlap4jUtil.longElement(cell, "Value");
} else if (type.equals( "xsd:boolean")) {
return XmlaOlap4jUtil.booleanElement(cell, "Value");
return XmlaOlap4jUtil.booleanElement(cell, "Value");
} else {
return XmlaOlap4jUtil.stringElement(cell, "Value");
return XmlaOlap4jUtil.stringElement(cell, "Value");
}
} catch (Exception e) {
throw new OlapException("En exception was encountered while casting a cell value to it's correct data type.", e); //$NON-NLS-1$
}
}
throw new OlapException(
"Error while casting a cell value to the correct java type for"
+ " its XSD type " + type,
e);
}
}

/**
* Creates metadata for a cell set, given the DOM of the XMLA result.
Expand Down
18 changes: 14 additions & 4 deletions src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,9 @@ String getDataSourceInfo() throws OlapException {
throw new OlapException("Datasource name not found.", e);
} finally {
try {
rSet.close();
if (rSet != null) {
rSet.close();
}
} catch (SQLException e) {
// ignore
}
Expand Down Expand Up @@ -985,11 +987,14 @@ public void handle(Element row, Context context, List<XmlaOlap4jMeasure> list)
Olap4jUtil.discard(measureMembers);
}
Member member =
context.getCube(row).getMetadataReader().lookupMemberByUniqueName(
measureUniqueName);
int ordinal = -1;
context.getCube(row).getMetadataReader()
.lookupMemberByUniqueName(
measureUniqueName);
final int ordinal;
if (member != null) {
ordinal = member.getOrdinal();
} else {
ordinal = -1;
}

list.add(
Expand Down Expand Up @@ -1055,6 +1060,11 @@ public void handle(Element row, Context context, List<XmlaOlap4jMember> list) {
stringElement(row, "MEMBER_CAPTION");
int childrenCardinality =
integerElement(row, "CHILDREN_CARDINALITY");
// If this member is a measure, we want to return an object that
// implements the Measure interface to all API calls. But we also
// need to retrieve the properties that occur in MDSCHEMA_MEMBERS
// that are not available in MDSCHEMA_MEASURES, so we create a
// member for internal use.
list.add(
new XmlaOlap4jMember(
context.getLevel(row), memberUniqueName, memberName,
Expand Down
26 changes: 23 additions & 3 deletions src/org/olap4j/driver/xmla/XmlaOlap4jCube.java
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,7 @@ class XmlaOlap4jCube implements Cube, Named
this.description = description;
this.metadataReader =
new CachingMetadataReader(
new RawMetadataReader()
)
;
new RawMetadataReader());
final XmlaOlap4jConnection olap4jConnection =
olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection;

Expand Down Expand Up @@ -115,6 +113,13 @@ class XmlaOlap4jCube implements Cube, Named
XmlaOlap4jConnection.MetadataRequest.MDSCHEMA_MEASURES,
new XmlaOlap4jConnection.MeasureHandler(),
restrictions);
// replace temporary member versions of measures in cache with final
// measures
for (XmlaOlap4jMeasure measure : measures) {
((CachingMetadataReader) metadataReader).memberMap.put(
measure.getUniqueName(),
new SoftReference<XmlaOlap4jMember>(measure));
}
// populate named sets
olap4jConnection.populateList(
namedSets, context,
Expand Down Expand Up @@ -436,6 +441,21 @@ public List<XmlaOlap4jMember> getLevelMembers(
final XmlaOlap4jConnection.Context context =
new XmlaOlap4jConnection.Context(level);
List<XmlaOlap4jMember> list = new ArrayList<XmlaOlap4jMember>();
// If this is a level in the [Measures] dimension, we want to
// return objects that implement the Measure interface. During
// bootstrap, the list will be empty, and we need to return the
// regular Member objects which have the extra properties that are
// returned by MSCHEMA_MEMBERS but not MDSCHEMA_MEASURES.
switch (level.getDimension().getDimensionType()) {
case MEASURE:
if (!level.olap4jHierarchy.olap4jDimension.olap4jCube.measures
.isEmpty()) {
return Olap4jUtil.cast(
level.olap4jHierarchy.olap4jDimension.olap4jCube
.measures);
}
break;
}
olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection
.populateList(
list,
Expand Down
2 changes: 1 addition & 1 deletion src/org/olap4j/driver/xmla/XmlaOlap4jDimension.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class XmlaOlap4jDimension
implements Dimension, Named
{
final XmlaOlap4jCube olap4jCube;
private final Type type;
final Type type;
final NamedList<XmlaOlap4jHierarchy> hierarchies =
new NamedListImpl<XmlaOlap4jHierarchy>();
private final String defaultHierarchyUniqueName;
Expand Down
9 changes: 6 additions & 3 deletions src/org/olap4j/driver/xmla/XmlaOlap4jMeasure.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@
package org.olap4j.driver.xmla;

import org.olap4j.impl.Named;
import org.olap4j.metadata.Datatype;
import org.olap4j.metadata.Measure;
import org.olap4j.metadata.*;

/**
* Implementation of {@link org.olap4j.metadata.Measure}
Expand Down Expand Up @@ -42,7 +41,11 @@ class XmlaOlap4jMeasure
{
super(
olap4jLevel, uniqueName, name, caption, description,
parentMemberUniqueName, Type.MEASURE, 0, ordinal);
parentMemberUniqueName,
aggregator == Aggregator.CALCULATED ? Type.FORMULA : Type.MEASURE,
0, ordinal);
assert olap4jLevel.olap4jHierarchy.olap4jDimension.type
== Dimension.Type.MEASURE;
this.aggregator = aggregator;
this.datatype = datatype;
this.visible = visible;
Expand Down
64 changes: 63 additions & 1 deletion testsrc/org/olap4j/ConnectionTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ void assertIsValid(Connection connection, int timeout) {
} else {
throw new RuntimeException(e);
}
} catch (AbstractMethodError e) {
// This happens in commons-dbcp. Somehow the method exists in
// the connection class, but it fails later. Not the fault of
// olap4j or the olapj driver, so ignore the error.
Olap4jUtil.discard(e);
}
}

Expand Down Expand Up @@ -204,7 +209,7 @@ public void testConnection() throws ClassNotFoundException, SQLException {
case DBCP:
// DBCP complains if you close a connection twice. Even though the
// JDBC spec is clear that it is OK.
break;
break;
default:
connection.close();
break;
Expand Down Expand Up @@ -348,6 +353,32 @@ public void testStatement() throws SQLException {
connection.close();
}

public void testAxes() throws SQLException {
connection = tester.createConnection();
Statement statement = connection.createStatement();

OlapStatement olapStatement =
tester.getWrapper().unwrap(statement, OlapStatement.class);

CellSet cellSet =
olapStatement.executeOlapQuery(
"SELECT {[Measures].[Unit Sales]} on 0,\n"
+ "{[Store].Children} on 1\n"
+ "FROM [Sales]");
List<CellSetAxis> axesList = cellSet.getAxes();
assertEquals(2, axesList.size());
final Member rowsMember =
axesList.get(0).getPositions().get(0).getMembers().get(0);
assertTrue(
rowsMember.getUniqueName(),
rowsMember instanceof Measure);
final Member columnsMember =
axesList.get(1).getPositions().get(0).getMembers().get(0);
assertTrue(
columnsMember.getUniqueName(),
!(columnsMember instanceof Measure));
}

public void testInvalidStatement() throws SQLException {
connection = tester.createConnection();
Statement statement = connection.createStatement();
Expand Down Expand Up @@ -1313,6 +1344,9 @@ public void testMetadata() throws Exception {
for (Member rootMember : rootMemberList) {
assertNull(rootMember.getParentMember());
}
assertEquals(
rootMemberList,
hierarchy.getLevels().get(0).getMembers());
assertNotNull(hierarchy.getDefaultMember());
assertNotNull(hierarchy.getName());
assertNotNull(hierarchy.getUniqueName());
Expand All @@ -1328,6 +1362,10 @@ public void testMetadata() throws Exception {
for (Member member : level.getMembers()) {
assertNotNull(member.getName());
assertEquals(level, member.getLevel());
if (dimension.getDimensionType()
== Dimension.Type.MEASURE) {
assertTrue(member instanceof Measure);
}
if (++k > 3) {
break;
}
Expand Down Expand Up @@ -1422,17 +1460,41 @@ public void testMetadata() throws Exception {

// Measures
int k = -1;
Set<String> measureNameSet = new HashSet<String>();
for (Measure measure : cube.getMeasures()) {
++k;
// The first measure is [Unit Sales], because the list must be
// sorted by ordinal.
if (k == 0) {
assertEquals("Unit Sales", measure.getName());
}
if (measure.getName().equals("Profit Growth")
|| measure.getName().equals("Profit last Period")
|| measure.getName().equals("Profit")) {
assertEquals(Member.Type.FORMULA, measure.getMemberType());
assertTrue(measure.isCalculated());
} else {
assertEquals(Member.Type.MEASURE, measure.getMemberType());
assertFalse(measure.isCalculated());
}
assertNotNull(measure.getName());
assertNotNull(measure.getAggregator());
assertTrue(measure.getDatatype() != null);
measureNameSet.add(measure.getName());
}
assertEquals(
new HashSet<String>(
Arrays.asList(
"Unit Sales",
"Customer Count",
"Profit last Period",
"Profit",
"Profit Growth",
"Promotion Sales",
"Sales Count",
"Store Sales",
"Store Cost")),
measureNameSet);
}

/**
Expand Down

0 comments on commit ecad30c

Please sign in to comment.