/* * This software is subject to the terms of the Eclipse Public License v1.0 * Agreement, available at the following URL: * http://www.eclipse.org/legal/epl-v10.html. * You must accept the terms of that agreement to use this software. * * Copyright (c) 2002-2013 Pentaho Corporation.. All rights reserved. */ package mondrian.olap4j; import mondrian.olap.*; import org.olap4j.OlapException; import org.olap4j.impl.*; import org.olap4j.mdx.IdentifierSegment; import org.olap4j.metadata.Cube; import org.olap4j.metadata.Dimension; import org.olap4j.metadata.Hierarchy; import org.olap4j.metadata.*; import org.olap4j.metadata.Member; import org.olap4j.metadata.NamedSet; import org.olap4j.metadata.Schema; import java.util.*; /** * Implementation of {@link Cube} * for the Mondrian OLAP engine. * * @author jhyde * @since May 24, 2007 */ class MondrianOlap4jCube extends MondrianOlap4jMetadataElement implements Cube, Named { final mondrian.olap.Cube cube; final MondrianOlap4jSchema olap4jSchema; MondrianOlap4jCube( mondrian.olap.Cube cube, MondrianOlap4jSchema olap4jSchema) { this.cube = cube; this.olap4jSchema = olap4jSchema; } public Schema getSchema() { return olap4jSchema; } public int hashCode() { return olap4jSchema.hashCode() ^ cube.hashCode(); } public boolean equals(Object obj) { if (obj instanceof MondrianOlap4jCube) { MondrianOlap4jCube that = (MondrianOlap4jCube) obj; return this.olap4jSchema == that.olap4jSchema && this.cube.equals(that.cube); } return false; } public NamedList<Dimension> getDimensions() { NamedList<MondrianOlap4jDimension> list = new NamedListImpl<MondrianOlap4jDimension>(); final MondrianOlap4jConnection olap4jConnection = olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; final mondrian.olap.SchemaReader schemaReader = olap4jConnection.getMondrianConnection2().getSchemaReader() .withLocus(); for (mondrian.olap.Dimension dimension : schemaReader.getCubeDimensions(cube)) { list.add( new MondrianOlap4jDimension( olap4jSchema, dimension)); } return Olap4jUtil.cast(list); } public NamedList<Hierarchy> getHierarchies() { NamedList<MondrianOlap4jHierarchy> list = new NamedListImpl<MondrianOlap4jHierarchy>(); final MondrianOlap4jConnection olap4jConnection = olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; final mondrian.olap.SchemaReader schemaReader = olap4jConnection.getMondrianConnection2().getSchemaReader() .withLocus(); for (mondrian.olap.Dimension dimension : schemaReader.getCubeDimensions(cube)) { for (mondrian.olap.Hierarchy hierarchy : schemaReader.getDimensionHierarchies(dimension)) { list.add( new MondrianOlap4jHierarchy( olap4jSchema, hierarchy)); } } return Olap4jUtil.cast(list); } public List<Measure> getMeasures() { final Dimension dimension = getDimensions().get("Measures"); if (dimension == null) { return Collections.emptyList(); } final MondrianOlap4jConnection olap4jConnection = olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; try { final mondrian.olap.SchemaReader schemaReader = olap4jConnection.getMondrianConnection().getSchemaReader() .withLocus(); final MondrianOlap4jLevel measuresLevel = (MondrianOlap4jLevel) dimension.getDefaultHierarchy() .getLevels().get(0); final List<Measure> measures = new ArrayList<Measure>(); List<mondrian.olap.Member> levelMembers = schemaReader.getLevelMembers( measuresLevel.level, true); for (mondrian.olap.Member member : levelMembers) { // This corrects MONDRIAN-1123, a ClassCastException (see below) // that occurs when you create a calculated member on a // dimension other than Measures: // java.lang.ClassCastException: // mondrian.olap4j.MondrianOlap4jMember cannot be cast to // org.olap4j.metadata.Measure MondrianOlap4jMember olap4jMember = olap4jConnection.toOlap4j( member); if (olap4jMember instanceof Measure) { measures.add((Measure) olap4jMember); } } return measures; } catch (OlapException e) { // OlapException not possible, since measures are stored in memory. // Demote from checked to unchecked exception. throw new RuntimeException(e); } } public NamedList<NamedSet> getSets() { final NamedListImpl<MondrianOlap4jNamedSet> list = new NamedListImpl<MondrianOlap4jNamedSet>(); final MondrianOlap4jConnection olap4jConnection = olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; for (mondrian.olap.NamedSet namedSet : cube.getNamedSets()) { list.add(olap4jConnection.toOlap4j(cube, namedSet)); } return Olap4jUtil.cast(list); } public Collection<Locale> getSupportedLocales() { throw new UnsupportedOperationException(); } public String getName() { return cube.getName(); } public String getUniqueName() { return cube.getUniqueName(); } public String getCaption() { return cube.getLocalized( OlapElement.LocalizedProperty.CAPTION, olap4jSchema.getLocale()); } public String getDescription() { return cube.getLocalized( OlapElement.LocalizedProperty.DESCRIPTION, olap4jSchema.getLocale()); } public boolean isVisible() { return cube.isVisible(); } public MondrianOlap4jMember lookupMember( List<IdentifierSegment> nameParts) throws OlapException { final MondrianOlap4jConnection olap4jConnection = olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; final Role role = olap4jConnection.getMondrianConnection().getRole(); final SchemaReader schemaReader = cube.getSchemaReader(role).withLocus(); return lookupMember(schemaReader, nameParts); } private MondrianOlap4jMember lookupMember( SchemaReader schemaReader, List<IdentifierSegment> nameParts) { final List<mondrian.olap.Id.Segment> segmentList = new ArrayList<mondrian.olap.Id.Segment>(); for (IdentifierSegment namePart : nameParts) { segmentList.add(Util.convert(namePart)); } final mondrian.olap.Member member = schemaReader.getMemberByUniqueName(segmentList, false); if (member == null) { return null; } return olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData .olap4jConnection.toOlap4j(member); } public List<Member> lookupMembers( Set<Member.TreeOp> treeOps, List<IdentifierSegment> nameParts) throws OlapException { final MondrianOlap4jConnection olap4jConnection = olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; final Role role = olap4jConnection.getMondrianConnection().getRole(); final SchemaReader schemaReader = cube.getSchemaReader(role).withLocus(); final MondrianOlap4jMember member = lookupMember(schemaReader, nameParts); if (member == null) { return Collections.emptyList(); } // Add ancestors and/or the parent. Ancestors are prepended, to ensure // hierarchical order. final List<MondrianOlap4jMember> list = new ArrayList<MondrianOlap4jMember>(); if (treeOps.contains(Member.TreeOp.ANCESTORS)) { for (MondrianOlap4jMember m = member.getParentMember(); m != null; m = m.getParentMember()) { list.add(0, m); } } else if (treeOps.contains(Member.TreeOp.PARENT)) { final MondrianOlap4jMember parentMember = member.getParentMember(); if (parentMember != null) { list.add(parentMember); } } // Add siblings. Siblings which occur after the member are deferred, // because they occur after children and descendants in the // hierarchical ordering. List<MondrianOlap4jMember> remainingSiblingsList = null; if (treeOps.contains(Member.TreeOp.SIBLINGS)) { final MondrianOlap4jMember parentMember = member.getParentMember(); NamedList<MondrianOlap4jMember> siblingMembers; if (parentMember != null) { siblingMembers = olap4jConnection.toOlap4j( schemaReader.getMemberChildren(parentMember.member)); } else { siblingMembers = olap4jConnection.toOlap4j( schemaReader.getHierarchyRootMembers( member.member.getHierarchy())); } List<MondrianOlap4jMember> targetList = list; for (MondrianOlap4jMember siblingMember : siblingMembers) { if (siblingMember.equals(member)) { targetList = remainingSiblingsList = new ArrayList<MondrianOlap4jMember>(); } else { targetList.add(siblingMember); } } } // Add the member itself. if (treeOps.contains(Member.TreeOp.SELF)) { list.add(member); } // Add descendants and/or children. if (treeOps.contains(Member.TreeOp.DESCENDANTS)) { addDescendants(list, schemaReader, olap4jConnection, member, true); } else if (treeOps.contains(Member.TreeOp.CHILDREN)) { addDescendants(list, schemaReader, olap4jConnection, member, false); } // Lastly, add siblings which occur after the member itself. They // occur after all of the descendants in the hierarchical ordering. if (remainingSiblingsList != null) { list.addAll(remainingSiblingsList); } return Olap4jUtil.cast(list); } private void addDescendants( List<MondrianOlap4jMember> list, SchemaReader schemaReader, MondrianOlap4jConnection olap4jConnection, MondrianOlap4jMember member, boolean recurse) { for (mondrian.olap.Member m : schemaReader.getMemberChildren(member.member)) { MondrianOlap4jMember childMember = olap4jConnection.toOlap4j(m); list.add(childMember); if (recurse) { addDescendants( list, schemaReader, olap4jConnection, childMember, recurse); } } } public boolean isDrillThroughEnabled() { return true; } protected OlapElement getOlapElement() { return cube; } } // End MondrianOlap4jCube.java