001/* 002// This software is subject to the terms of the Eclipse Public License v1.0 003// Agreement, available at the following URL: 004// http://www.eclipse.org/legal/epl-v10.html. 005// You must accept the terms of that agreement to use this software. 006// 007// Copyright (C) 2007-2013 Pentaho 008// All Rights Reserved. 009*/ 010package mondrian.olap4j; 011 012import mondrian.olap.*; 013 014import org.olap4j.OlapException; 015import org.olap4j.impl.*; 016import org.olap4j.mdx.IdentifierSegment; 017import org.olap4j.metadata.Cube; 018import org.olap4j.metadata.Dimension; 019import org.olap4j.metadata.Hierarchy; 020import org.olap4j.metadata.*; 021import org.olap4j.metadata.Member; 022import org.olap4j.metadata.NamedSet; 023import org.olap4j.metadata.Schema; 024 025import java.util.*; 026 027/** 028 * Implementation of {@link Cube} 029 * for the Mondrian OLAP engine. 030 * 031 * @author jhyde 032 * @since May 24, 2007 033 */ 034class MondrianOlap4jCube 035 extends MondrianOlap4jMetadataElement 036 implements Cube, Named 037{ 038 final mondrian.olap.Cube cube; 039 final MondrianOlap4jSchema olap4jSchema; 040 041 MondrianOlap4jCube( 042 mondrian.olap.Cube cube, 043 MondrianOlap4jSchema olap4jSchema) 044 { 045 this.cube = cube; 046 this.olap4jSchema = olap4jSchema; 047 } 048 049 public Schema getSchema() { 050 return olap4jSchema; 051 } 052 053 public int hashCode() { 054 return olap4jSchema.hashCode() 055 ^ cube.hashCode(); 056 } 057 058 public boolean equals(Object obj) { 059 if (obj instanceof MondrianOlap4jCube) { 060 MondrianOlap4jCube that = (MondrianOlap4jCube) obj; 061 return this.olap4jSchema == that.olap4jSchema 062 && this.cube.equals(that.cube); 063 } 064 return false; 065 } 066 067 public NamedList<Dimension> getDimensions() { 068 NamedList<MondrianOlap4jDimension> list = 069 new NamedListImpl<MondrianOlap4jDimension>(); 070 final MondrianOlap4jConnection olap4jConnection = 071 olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; 072 final mondrian.olap.SchemaReader schemaReader = 073 olap4jConnection.getMondrianConnection2().getSchemaReader() 074 .withLocus(); 075 for (mondrian.olap.Dimension dimension 076 : schemaReader.getCubeDimensions(cube)) 077 { 078 list.add( 079 new MondrianOlap4jDimension( 080 olap4jSchema, dimension)); 081 } 082 return Olap4jUtil.cast(list); 083 } 084 085 public NamedList<Hierarchy> getHierarchies() { 086 NamedList<MondrianOlap4jHierarchy> list = 087 new NamedListImpl<MondrianOlap4jHierarchy>(); 088 final MondrianOlap4jConnection olap4jConnection = 089 olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; 090 final mondrian.olap.SchemaReader schemaReader = 091 olap4jConnection.getMondrianConnection2().getSchemaReader() 092 .withLocus(); 093 for (mondrian.olap.Dimension dimension 094 : schemaReader.getCubeDimensions(cube)) 095 { 096 for (mondrian.olap.Hierarchy hierarchy 097 : schemaReader.getDimensionHierarchies(dimension)) 098 { 099 list.add( 100 new MondrianOlap4jHierarchy( 101 olap4jSchema, hierarchy)); 102 } 103 } 104 return Olap4jUtil.cast(list); 105 } 106 107 public List<Measure> getMeasures() { 108 final Dimension dimension = getDimensions().get("Measures"); 109 if (dimension == null) { 110 return Collections.emptyList(); 111 } 112 final MondrianOlap4jConnection olap4jConnection = 113 olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; 114 try { 115 final mondrian.olap.SchemaReader schemaReader = 116 olap4jConnection.getMondrianConnection().getSchemaReader() 117 .withLocus(); 118 final MondrianOlap4jLevel measuresLevel = 119 (MondrianOlap4jLevel) 120 dimension.getDefaultHierarchy() 121 .getLevels().get(0); 122 final List<Measure> measures = 123 new ArrayList<Measure>(); 124 List<mondrian.olap.Member> levelMembers = 125 schemaReader.getLevelMembers( 126 measuresLevel.level, 127 true); 128 for (mondrian.olap.Member member : levelMembers) { 129 // This corrects MONDRIAN-1123, a ClassCastException (see below) 130 // that occurs when you create a calculated member on a 131 // dimension other than Measures: 132 // java.lang.ClassCastException: 133 // mondrian.olap4j.MondrianOlap4jMember cannot be cast to 134 // org.olap4j.metadata.Measure 135 MondrianOlap4jMember olap4jMember = olap4jConnection.toOlap4j( 136 member); 137 if (olap4jMember instanceof Measure) { 138 measures.add((Measure) olap4jMember); 139 } 140 } 141 return measures; 142 } catch (OlapException e) { 143 // OlapException not possible, since measures are stored in memory. 144 // Demote from checked to unchecked exception. 145 throw new RuntimeException(e); 146 } 147 } 148 149 public NamedList<NamedSet> getSets() { 150 final NamedListImpl<MondrianOlap4jNamedSet> list = 151 new NamedListImpl<MondrianOlap4jNamedSet>(); 152 final MondrianOlap4jConnection olap4jConnection = 153 olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; 154 for (mondrian.olap.NamedSet namedSet : cube.getNamedSets()) { 155 list.add(olap4jConnection.toOlap4j(cube, namedSet)); 156 } 157 return Olap4jUtil.cast(list); 158 } 159 160 public Collection<Locale> getSupportedLocales() { 161 throw new UnsupportedOperationException(); 162 } 163 164 public String getName() { 165 return cube.getName(); 166 } 167 168 public String getUniqueName() { 169 return cube.getUniqueName(); 170 } 171 172 public String getCaption() { 173 return cube.getLocalized( 174 OlapElement.LocalizedProperty.CAPTION, olap4jSchema.getLocale()); 175 } 176 177 public String getDescription() { 178 return cube.getLocalized( 179 OlapElement.LocalizedProperty.DESCRIPTION, 180 olap4jSchema.getLocale()); 181 } 182 183 public boolean isVisible() { 184 return cube.isVisible(); 185 } 186 187 public MondrianOlap4jMember lookupMember( 188 List<IdentifierSegment> nameParts) 189 throws OlapException 190 { 191 final MondrianOlap4jConnection olap4jConnection = 192 olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; 193 final Role role = olap4jConnection.getMondrianConnection().getRole(); 194 final SchemaReader schemaReader = 195 cube.getSchemaReader(role).withLocus(); 196 return lookupMember(schemaReader, nameParts); 197 } 198 199 private MondrianOlap4jMember lookupMember( 200 SchemaReader schemaReader, 201 List<IdentifierSegment> nameParts) 202 { 203 final List<mondrian.olap.Id.Segment> segmentList = 204 new ArrayList<mondrian.olap.Id.Segment>(); 205 for (IdentifierSegment namePart : nameParts) { 206 segmentList.add(Util.convert(namePart)); 207 } 208 final mondrian.olap.Member member = 209 schemaReader.getMemberByUniqueName(segmentList, false); 210 if (member == null) { 211 return null; 212 } 213 214 return olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData 215 .olap4jConnection.toOlap4j(member); 216 } 217 218 public List<Member> lookupMembers( 219 Set<Member.TreeOp> treeOps, 220 List<IdentifierSegment> nameParts) throws OlapException 221 { 222 final MondrianOlap4jConnection olap4jConnection = 223 olap4jSchema.olap4jCatalog.olap4jDatabaseMetaData.olap4jConnection; 224 final Role role = olap4jConnection.getMondrianConnection().getRole(); 225 final SchemaReader schemaReader = 226 cube.getSchemaReader(role).withLocus(); 227 final MondrianOlap4jMember member = 228 lookupMember(schemaReader, nameParts); 229 if (member == null) { 230 return Collections.emptyList(); 231 } 232 233 // Add ancestors and/or the parent. Ancestors are prepended, to ensure 234 // hierarchical order. 235 final List<MondrianOlap4jMember> list = 236 new ArrayList<MondrianOlap4jMember>(); 237 if (treeOps.contains(Member.TreeOp.ANCESTORS)) { 238 for (MondrianOlap4jMember m = member.getParentMember(); 239 m != null; 240 m = m.getParentMember()) 241 { 242 list.add(0, m); 243 } 244 } else if (treeOps.contains(Member.TreeOp.PARENT)) { 245 final MondrianOlap4jMember parentMember = member.getParentMember(); 246 if (parentMember != null) { 247 list.add(parentMember); 248 } 249 } 250 251 // Add siblings. Siblings which occur after the member are deferred, 252 // because they occur after children and descendants in the 253 // hierarchical ordering. 254 List<MondrianOlap4jMember> remainingSiblingsList = null; 255 if (treeOps.contains(Member.TreeOp.SIBLINGS)) { 256 final MondrianOlap4jMember parentMember = member.getParentMember(); 257 NamedList<MondrianOlap4jMember> siblingMembers; 258 if (parentMember != null) { 259 siblingMembers = 260 olap4jConnection.toOlap4j( 261 schemaReader.getMemberChildren(parentMember.member)); 262 } else { 263 siblingMembers = 264 olap4jConnection.toOlap4j( 265 schemaReader.getHierarchyRootMembers( 266 member.member.getHierarchy())); 267 } 268 List<MondrianOlap4jMember> targetList = list; 269 for (MondrianOlap4jMember siblingMember : siblingMembers) { 270 if (siblingMember.equals(member)) { 271 targetList = 272 remainingSiblingsList = 273 new ArrayList<MondrianOlap4jMember>(); 274 } else { 275 targetList.add(siblingMember); 276 } 277 } 278 } 279 280 // Add the member itself. 281 if (treeOps.contains(Member.TreeOp.SELF)) { 282 list.add(member); 283 } 284 285 // Add descendants and/or children. 286 if (treeOps.contains(Member.TreeOp.DESCENDANTS)) { 287 addDescendants(list, schemaReader, olap4jConnection, member, true); 288 } else if (treeOps.contains(Member.TreeOp.CHILDREN)) { 289 addDescendants(list, schemaReader, olap4jConnection, member, false); 290 } 291 // Lastly, add siblings which occur after the member itself. They 292 // occur after all of the descendants in the hierarchical ordering. 293 if (remainingSiblingsList != null) { 294 list.addAll(remainingSiblingsList); 295 } 296 return Olap4jUtil.cast(list); 297 } 298 299 private void addDescendants( 300 List<MondrianOlap4jMember> list, 301 SchemaReader schemaReader, 302 MondrianOlap4jConnection olap4jConnection, 303 MondrianOlap4jMember member, 304 boolean recurse) 305 { 306 for (mondrian.olap.Member m 307 : schemaReader.getMemberChildren(member.member)) 308 { 309 MondrianOlap4jMember childMember = olap4jConnection.toOlap4j(m); 310 list.add(childMember); 311 if (recurse) { 312 addDescendants( 313 list, schemaReader, olap4jConnection, childMember, recurse); 314 } 315 } 316 } 317 318 public boolean isDrillThroughEnabled() { 319 return true; 320 } 321 322 protected OlapElement getOlapElement() { 323 return cube; 324 } 325} 326 327// End MondrianOlap4jCube.java