diff --git a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java index 752a409..45d3025 100644 --- a/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java +++ b/src/org/olap4j/driver/xmla/XmlaOlap4jConnection.java @@ -406,6 +406,7 @@ void populateList( handler.handle(o, context, list); } } + handler.sortList(list); } Element xxx(String request) throws OlapException { @@ -571,6 +572,7 @@ private static String xmlEncode(String value){ // ~ inner classes -------------------------------------------------------- + @SuppressWarnings({"ThrowableInstanceNeverThrown"}) static class Helper { OlapException createException(String msg) { return new OlapException(msg); @@ -849,6 +851,20 @@ public void handle(Element row, Context context, List list) { measureCaption, description, null, measureAggregator, datatype, measureIsVisible)); } + + public void sortList(List list) { + Collections.sort( + list, + new Comparator() { + public int compare( + XmlaOlap4jMeasure o1, + XmlaOlap4jMeasure o2) + { + return o1.getOrdinal() - o2.getOrdinal(); + } + } + ); + } } static class MemberHandler extends HandlerImpl { @@ -983,13 +999,43 @@ public void handle( } } + /** + * Callback for converting XMLA results into metadata elements. + */ interface Handler { + /** + * 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 + * + * @throws OlapException on error + */ void handle( Element row, - Context context, List list) throws OlapException; + Context context, + List list) throws OlapException; + + /** + * Sorts a list of metadata elements. + * + *

For most element types, the order returned by XMLA is correct, and + * this method will no-op. + * + * @param list List of metadata elements + */ + void sortList(List list); } static abstract class HandlerImpl implements Handler { + public void sortList(List list) { + // do nothing - assume XMLA returned list in correct order + } } static class Context { diff --git a/src/org/olap4j/metadata/Cube.java b/src/org/olap4j/metadata/Cube.java index 75e76ad..03ee78b 100644 --- a/src/org/olap4j/metadata/Cube.java +++ b/src/org/olap4j/metadata/Cube.java @@ -61,6 +61,10 @@ public interface Cube extends MetadataElement { /** * Returns a list of {@link Measure} objects in this Cube. * + *

The list includes both stored and calculated members, and (unlike + * the {@link org.olap4j.OlapDatabaseMetaData#getMeasures} method or the + * MDSCHEMA_MEASURES XMLA request) is sorted by ordinal. + * * @see org.olap4j.OlapDatabaseMetaData#getMeasures(String,String,String,String,String) * * @return list of Measures diff --git a/testsrc/org/olap4j/ConnectionTest.java b/testsrc/org/olap4j/ConnectionTest.java index 0fc96fb..d1cfbe3 100644 --- a/testsrc/org/olap4j/ConnectionTest.java +++ b/testsrc/org/olap4j/ConnectionTest.java @@ -1309,9 +1309,10 @@ public void testMetadata() throws Exception { assertEquals( 2, timeWeeklyHierarchy.getDimension().getHierarchies().size()); - cube = olapConnection.getSchema().getCubes().get("Warehouse"); + Cube warehouseCube = + olapConnection.getSchema().getCubes().get("Warehouse"); int count = 0; - for (NamedSet namedSet : cube.getSets()) { + for (NamedSet namedSet : warehouseCube.getSets()) { ++count; assertNotNull(namedSet.getName()); assertNotNull(namedSet.getUniqueName()); @@ -1375,7 +1376,14 @@ public void testMetadata() throws Exception { assertEquals(Datatype.STRING, property.getDatatype()); // Measures + int k = -1; 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()); + } assertNotNull(measure.getName()); assertNotNull(measure.getAggregator()); assertTrue(measure.getDatatype() != null); @@ -1843,6 +1851,7 @@ public void testBuildQuery2() throws ClassNotFoundException, SQLException { Schema schema = olapConnection.getSchema(); Cube cube = schema.getCubes().get("Sales"); Measure measure = cube.getMeasures().get(0); + assertEquals("Unit Sales", measure.getName()); Dimension dimPromotionMedia = cube.getDimensions().get("Promotion Media"); // // IdentifierNode cubeNode = new IdentifierNode(new IdentifierNode.Segment(cube.getUniqueName())); @@ -1897,20 +1906,20 @@ public void testBuildQuery2() throws ClassNotFoundException, SQLException { pw.flush(); TestContext.assertEqualsVerbose( TestContext.fold( - "ROW:[Bulk Mail] COL:[Customer Count] CELL:333\n" + - "ROW:[Cash Register Handout] COL:[Customer Count] CELL:482\n" + - "ROW:[Daily Paper] COL:[Customer Count] CELL:528\n" + - "ROW:[Daily Paper, Radio] COL:[Customer Count] CELL:499\n" + - "ROW:[Daily Paper, Radio, TV] COL:[Customer Count] CELL:687\n" + - "ROW:[In-Store Coupon] COL:[Customer Count] CELL:290\n" + - "ROW:[No Media] COL:[Customer Count] CELL:5,043\n" + - "ROW:[Product Attachment] COL:[Customer Count] CELL:532\n" + - "ROW:[Radio] COL:[Customer Count] CELL:186\n" + - "ROW:[Street Handout] COL:[Customer Count] CELL:381\n" + - "ROW:[Sunday Paper] COL:[Customer Count] CELL:307\n" + - "ROW:[Sunday Paper, Radio] COL:[Customer Count] CELL:422\n" + - "ROW:[Sunday Paper, Radio, TV] COL:[Customer Count] CELL:196\n" + - "ROW:[TV] COL:[Customer Count] CELL:274\n"), + "ROW:[Bulk Mail] COL:[Unit Sales] CELL:4,320\n" + + "ROW:[Cash Register Handout] COL:[Unit Sales] CELL:6,697\n" + + "ROW:[Daily Paper] COL:[Unit Sales] CELL:7,738\n" + + "ROW:[Daily Paper, Radio] COL:[Unit Sales] CELL:6,891\n" + + "ROW:[Daily Paper, Radio, TV] COL:[Unit Sales] CELL:9,513\n" + + "ROW:[In-Store Coupon] COL:[Unit Sales] CELL:3,798\n" + + "ROW:[No Media] COL:[Unit Sales] CELL:195,448\n" + + "ROW:[Product Attachment] COL:[Unit Sales] CELL:7,544\n" + + "ROW:[Radio] COL:[Unit Sales] CELL:2,454\n" + + "ROW:[Street Handout] COL:[Unit Sales] CELL:5,753\n" + + "ROW:[Sunday Paper] COL:[Unit Sales] CELL:4,339\n" + + "ROW:[Sunday Paper, Radio] COL:[Unit Sales] CELL:5,945\n" + + "ROW:[Sunday Paper, Radio, TV] COL:[Unit Sales] CELL:2,726\n" + + "ROW:[TV] COL:[Unit Sales] CELL:3,607\n"), sw.toString()); } }