1 13 14 package mondrian.rolap; 15 16 import mondrian.olap.*; 17 import mondrian.olap.fun.BuiltinFunTable; 18 import mondrian.olap.type.Type; 19 import mondrian.olap.type.MemberType; 20 import mondrian.rolap.sql.SqlQuery; 21 import mondrian.resource.MondrianResource; 22 import mondrian.mdx.HierarchyExpr; 23 import mondrian.mdx.UnresolvedFunCall; 24 25 import org.apache.log4j.Logger; 26 27 import java.util.List ; 28 import java.util.ArrayList ; 29 30 37 public class RolapHierarchy extends HierarchyBase { 38 39 private static final Logger LOGGER = Logger.getLogger(RolapHierarchy.class); 40 41 46 private MemberReader memberReader; 47 MondrianDef.Hierarchy xmlHierarchy; 48 private String memberReaderClass; 49 private MondrianDef.Relation relation; 50 private Member defaultMember; 51 private String defaultMemberName; 52 private RolapNullMember nullMember; 53 54 65 private String sharedHierarchyName; 66 67 private Exp aggregateChildrenExpression; 68 69 private String primaryKey; 71 72 75 final Type memberType = MemberType.forHierarchy(this); 76 77 80 private final RolapLevel nullLevel; 81 82 86 private RolapMember allMember; 87 private static final String ALL_LEVEL_CARDINALITY = "1"; 88 89 RolapHierarchy(RolapDimension dimension, String subName, boolean hasAll) { 90 super(dimension, subName, hasAll); 91 92 this.levels = new RolapLevel[0]; 93 setCaption(dimension.getCaption()); 94 95 this.allLevelName = "(All)"; 96 this.allMemberName = "All " + name + "s"; 97 if (hasAll) { 98 Util.discard(newLevel(this.allLevelName, 99 RolapLevel.ALL | RolapLevel.UNIQUE)); 100 } 101 102 this.nullLevel = new RolapLevel( 105 this, 0, this.allLevelName, null, null, null, null, null, null, 106 null, RolapProperty.emptyArray, 107 RolapLevel.ALL | RolapLevel.UNIQUE, 108 null, 109 RolapLevel.HideMemberCondition.Never, 110 LevelType.Null, ""); 111 } 112 113 119 RolapHierarchy(RolapCube cube, RolapDimension dimension, 120 MondrianDef.Hierarchy xmlHierarchy, 121 MondrianDef.CubeDimension xmlCubeDimension) { 122 this(dimension, xmlHierarchy.name, xmlHierarchy.hasAll); 123 124 if (xmlHierarchy.relation == null && 125 xmlHierarchy.memberReaderClass == null && 126 cube != null) { 127 xmlHierarchy.relation = cube.fact; 128 } 129 this.xmlHierarchy = xmlHierarchy; 130 this.relation = xmlHierarchy.relation; 131 if (xmlHierarchy.relation instanceof MondrianDef.InlineTable) { 132 this.relation = convertInlineTableToRelation( 133 (MondrianDef.InlineTable) xmlHierarchy.relation); 134 } 135 this.memberReaderClass = xmlHierarchy.memberReaderClass; 136 137 if (xmlHierarchy.allMemberName != null) { 140 this.allMemberName = xmlHierarchy.allMemberName; 141 } 142 if (xmlHierarchy.allLevelName != null) { 143 this.allLevelName = xmlHierarchy.allLevelName; 144 } 145 RolapLevel allLevel = new RolapLevel( 146 this, 0, this.allLevelName, null, null, null, null, null, null, 147 null, RolapProperty.emptyArray, 148 RolapLevel.ALL | RolapLevel.UNIQUE, 149 null, 150 RolapLevel.HideMemberCondition.Never, 151 LevelType.Regular, ALL_LEVEL_CARDINALITY); 152 this.allMember = new RolapMember( 153 null, allLevel, null, allMemberName, Member.MemberType.ALL); 154 if (xmlHierarchy.allMemberCaption != null && 156 xmlHierarchy.allMemberCaption.length() > 0) { 157 this.allMember.setCaption(xmlHierarchy.allMemberCaption); 158 } 159 this.allMember.setOrdinal(0); 160 161 if (hasAll) { 163 this.levels = new RolapLevel[xmlHierarchy.levels.length + 1]; 164 this.levels[0] = allLevel; 165 for (int i = 0; i < xmlHierarchy.levels.length; i++) { 166 final MondrianDef.Level xmlLevel = xmlHierarchy.levels[i]; 167 if (xmlLevel.getKeyExp() == null && 168 xmlHierarchy.memberReaderClass == null) { 169 throw MondrianResource.instance().LevelMustHaveNameExpression.ex(xmlLevel.name); 170 } 171 levels[i + 1] = new RolapLevel(this, i + 1, xmlLevel); 172 } 173 } else { 174 this.levels = new RolapLevel[xmlHierarchy.levels.length]; 175 for (int i = 0; i < xmlHierarchy.levels.length; i++) { 176 levels[i] = new RolapLevel(this, i, xmlHierarchy.levels[i]); 177 } 178 } 179 180 if (xmlCubeDimension instanceof MondrianDef.DimensionUsage) { 181 String sharedDimensionName = 182 ((MondrianDef.DimensionUsage) xmlCubeDimension).source; 183 this.sharedHierarchyName = sharedDimensionName; 184 if (subName != null) { 185 this.sharedHierarchyName += "." + subName; } 187 } else { 188 this.sharedHierarchyName = null; 189 } 190 if (xmlHierarchy.relation != null && 191 xmlHierarchy.memberReaderClass != null) { 192 throw MondrianResource.instance(). 193 HierarchyMustNotHaveMoreThanOneSource.ex(getUniqueName()); 194 } 195 this.primaryKey = xmlHierarchy.primaryKey; 196 if (!Util.isEmpty(xmlHierarchy.caption)) { 197 setCaption(xmlHierarchy.caption); 198 } 199 defaultMemberName = xmlHierarchy.defaultMember; 200 } 201 202 private MondrianDef.Relation convertInlineTableToRelation( 203 MondrianDef.InlineTable inlineTable) { 204 MondrianDef.View view = new MondrianDef.View(); 205 view.alias = inlineTable.alias; 206 view.selects = new MondrianDef.SQL[1]; 207 final MondrianDef.SQL select = view.selects[0] = new MondrianDef.SQL(); 208 select.dialect = "generic"; 209 final SqlQuery.Dialect dialect; 210 dialect = getRolapSchema().getDialect(); 211 212 final int columnCount = inlineTable.columnDefs.array.length; 213 List <String > columnNames = new ArrayList <String >(); 214 List <String > columnTypes = new ArrayList <String >(); 215 for (int i = 0; i < columnCount; i++) { 216 columnNames.add(inlineTable.columnDefs.array[i].name); 217 columnTypes.add(inlineTable.columnDefs.array[i].type); 218 } 219 List <String []> valueList = new ArrayList <String []>(); 220 for (MondrianDef.Row row : inlineTable.rows.array) { 221 String [] values = new String [columnCount]; 222 for (MondrianDef.Value value : row.values) { 223 final int columnOrdinal = columnNames.indexOf(value.column); 224 if (columnOrdinal < 0) { 225 throw Util.newError( 226 "Unknown column '" + value.column + "'"); 227 } 228 values[columnOrdinal] = value.cdata; 229 } 230 valueList.add(values); 231 } 232 select.cdata = dialect.generateInline( 233 columnNames, 234 columnTypes, 235 valueList); 236 return view; 237 } 238 239 protected Logger getLogger() { 240 return LOGGER; 241 } 242 243 public boolean equals(Object o) { 244 if (this == o) { 245 return true; 246 } 247 if (!(o instanceof RolapHierarchy)) { 248 return false; 249 } 250 251 RolapHierarchy that = (RolapHierarchy)o; 252 if (sharedHierarchyName == null || that.sharedHierarchyName == null) { 253 return false; 254 } else { 255 return sharedHierarchyName.equals(that.sharedHierarchyName) && 256 getUniqueName().equals(that.getUniqueName()); 257 } 258 } 259 260 public int hashCode() { 261 return super.hashCode() ^ (sharedHierarchyName == null 262 ? 0 263 : sharedHierarchyName.hashCode()); 264 } 265 266 269 void init(RolapCube cube, MondrianDef.CubeDimension xmlDimension) { 270 if (this.memberReader == null) { 272 this.memberReader = getRolapSchema().createMemberReader( 273 sharedHierarchyName, this, memberReaderClass); 274 } 275 for (int i = 0; i < levels.length; i++) { 276 ((RolapLevel) levels[i]).init(cube, xmlDimension); 277 } 278 if (defaultMemberName != null) { 279 String [] uniqueNameParts = Util.explode(defaultMemberName); 280 281 if (this.name.equals(uniqueNameParts[0])) { 287 String [] tmp = new String [uniqueNameParts.length-1]; 288 System.arraycopy(uniqueNameParts, 1, tmp, 0, 289 uniqueNameParts.length-1); 290 uniqueNameParts = tmp; 291 } 292 293 defaultMember = memberReader.lookupMember(uniqueNameParts, false); 295 if (defaultMember == null) { 296 throw Util.newInternal( 297 "Can not find Default Member with name \"" 298 + defaultMemberName + "\" in Hierarchy \"" + 299 getName() + "\""); 300 } 301 } 302 } 303 void setMemberReader(MemberReader memberReader) { 304 this.memberReader = memberReader; 305 } 306 MemberReader getMemberReader() { 307 return this.memberReader; 308 } 309 310 RolapLevel newLevel(String name, int flags) { 311 RolapLevel level = new RolapLevel( 312 this, this.levels.length, name, null, null, null, null, 313 null, null, null, RolapProperty.emptyArray, flags, null, 314 RolapLevel.HideMemberCondition.Never, LevelType.Regular, ""); 315 this.levels = (RolapLevel[]) RolapUtil.addElement(this.levels, level); 316 return level; 317 } 318 319 324 MondrianDef.Relation getUniqueTable() { 325 if (relation instanceof MondrianDef.Table || 326 relation instanceof MondrianDef.View) { 327 return relation; 328 } else if (relation instanceof MondrianDef.Join) { 329 return null; 330 } else { 331 throw Util.newInternal( 332 "hierarchy's relation is a " + relation.getClass()); 333 } 334 } 335 336 boolean tableExists(String tableName) { 337 return (relation != null) && tableExists(tableName, relation); 338 } 339 340 private static boolean tableExists(String tableName, 341 MondrianDef.Relation relation) { 342 if (relation instanceof MondrianDef.Table) { 343 MondrianDef.Table table = (MondrianDef.Table) relation; 344 return table.name.equals(tableName) || 346 ((table.alias != null) && table.alias.equals(tableName)); 347 } 348 if (relation instanceof MondrianDef.Join) { 349 MondrianDef.Join join = (MondrianDef.Join) relation; 350 return tableExists(tableName, join.left) || 351 tableExists(tableName, join.right); 352 } 353 return false; 354 } 355 356 public RolapSchema getRolapSchema() { 357 return (RolapSchema) dimension.getSchema(); 358 } 359 360 public MondrianDef.Relation getRelation() { 361 return relation; 362 } 363 364 public Member getDefaultMember() { 365 if (defaultMember == null) { 367 List rootMembers = memberReader.getRootMembers(); 368 if (rootMembers.size() == 0) { 369 throw MondrianResource.instance().InvalidHierarchyCondition.ex(this.getUniqueName()); 370 375 } 376 defaultMember = (RolapMember) rootMembers.get(0); 377 } 378 return defaultMember; 379 } 380 381 public Member getNullMember() { 382 if (nullMember == null) { 384 nullMember = new RolapNullMember(nullLevel); 385 } 386 return nullMember; 387 } 388 389 392 public RolapMember getAllMember() { 393 return allMember; 394 } 395 396 public Member createMember( 397 Member parent, 398 Level level, 399 String name, 400 Formula formula) { 401 if (formula == null) { 402 return new RolapMember( 403 (RolapMember) parent, (RolapLevel) level, name); 404 } else if (level.getDimension().isMeasures()) { 405 return new RolapCalculatedMeasure( 406 (RolapMember) parent, (RolapLevel) level, name, formula); 407 } else { 408 return new RolapCalculatedMember( 409 (RolapMember) parent, (RolapLevel) level, name, formula); 410 } 411 } 412 413 String getAlias() { 414 return getName(); 415 } 416 417 429 void addToFrom(SqlQuery query, MondrianDef.Expression expression) { 430 if (relation == null) { 431 throw Util.newError( 432 "cannot add hierarchy " + getUniqueName() + 433 " to query: it does not have a <Table>, <View> or <Join>"); 434 } 435 final boolean failIfExists = false; 436 MondrianDef.Relation subRelation = relation; 437 if (relation instanceof MondrianDef.Join) { 438 if (expression != null) { 439 subRelation = relationSubset(relation, expression.getTableAlias()); 448 449 } 450 } 451 query.addFrom(subRelation, null, failIfExists); 452 } 453 454 459 private static MondrianDef.Relation relationSubset( 460 MondrianDef.Relation relation, 461 String alias) { 462 463 if (relation instanceof MondrianDef.Table) { 464 MondrianDef.Table table = (MondrianDef.Table) relation; 465 return (table.getAlias().equals(alias)) 467 ? relation 468 : (table.name.equals(alias) ? relation : null); 469 470 } else if (relation instanceof MondrianDef.Join) { 471 MondrianDef.Join join = (MondrianDef.Join) relation; 472 MondrianDef.Relation rightRelation = relationSubset(join.right, alias); 473 return (rightRelation == null) 474 ? relationSubset(join.left, alias) 475 : join; 476 477 } else { 478 throw Util.newInternal("bad relation type " + relation); 479 } 480 } 481 482 489 MemberReader getMemberReader(Role role) { 490 final Access access = role.getAccess(this); 491 switch (access) { 492 case NONE: 493 throw Util.newInternal("Illegal access to members of hierarchy " 494 + this); 495 case ALL: 496 return (isRagged()) 497 ? new RestrictedMemberReader(memberReader, role) 498 : memberReader; 499 500 case CUSTOM: 501 return new RestrictedMemberReader(memberReader, role); 502 default: 503 throw Util.badValue(access); 504 } 505 } 506 507 511 public boolean isRagged() { 512 for (int i = 0; i < levels.length; i++) { 513 RolapLevel level = (RolapLevel) levels[i]; 514 if (level.getHideMemberCondition() != 515 RolapLevel.HideMemberCondition.Never) { 516 return true; 517 } 518 } 519 return false; 520 } 521 522 530 synchronized Exp getAggregateChildrenExpression() { 531 if (aggregateChildrenExpression == null) { 532 UnresolvedFunCall fc = new UnresolvedFunCall( 533 "$AggregateChildren", 534 Syntax.Internal, 535 new Exp[] {new HierarchyExpr(this)}); 536 Validator validator = 537 Util.createSimpleValidator(BuiltinFunTable.instance()); 538 aggregateChildrenExpression = fc.accept(validator); 539 } 540 return aggregateChildrenExpression; 541 } 542 543 605 RolapDimension createClosedPeerDimension( 606 RolapLevel src, 607 MondrianDef.Closure clos, 608 RolapCube cube, 609 MondrianDef.CubeDimension xmlDimension) { 610 611 613 RolapDimension peerDimension = new RolapDimension( 615 dimension.getSchema(), 616 dimension.getName() + "$Closure", 617 ((RolapDimension)dimension).getNextOrdinal(), 618 DimensionType.StandardDimension); 619 620 RolapHierarchy peerHier = peerDimension.newHierarchy(subName, true); 622 peerHier.allMemberName = allMemberName; 623 peerHier.allMember = allMember; 624 peerHier.allLevelName = allLevelName; 625 peerHier.sharedHierarchyName = sharedHierarchyName; 626 peerHier.primaryKey = primaryKey; 627 MondrianDef.Join join = new MondrianDef.Join(); 628 peerHier.relation = join; 629 join.left = clos.table; join.leftKey = clos.parentColumn; 631 join.right = relation; join.rightKey = clos.childColumn; 633 634 int index = peerHier.levels.length; 638 int flags = src.getFlags() &~ RolapLevel.UNIQUE; 639 MondrianDef.Expression keyExp = 640 new MondrianDef.Column(clos.table.name, clos.parentColumn); 641 642 RolapLevel level = new RolapLevel(peerHier, index++, 643 "Closure", 644 keyExp, null, null, null, 645 null, null, null, 647 RolapProperty.emptyArray, 648 flags, 649 src.getDatatype(), 650 src.getHideMemberCondition(), 651 src.getLevelType(), 652 ""); 653 peerHier.levels = 654 (RolapLevel[]) RolapUtil.addElement(peerHier.levels, level); 655 656 flags = src.getFlags() | RolapLevel.UNIQUE; 662 keyExp = new MondrianDef.Column(clos.table.name, clos.childColumn); 663 RolapLevel sublevel = new RolapLevel( 664 peerHier, 665 index++, 666 "Item", 667 keyExp, 668 null, 669 null, 670 null, 671 null, 672 null, null, 674 RolapProperty.emptyArray, 675 flags, 676 src.getDatatype(), 677 src.getHideMemberCondition(), 678 src.getLevelType(), ""); 679 peerHier.levels = 680 (RolapLevel[]) RolapUtil.addElement(peerHier.levels, sublevel); 681 682 685 cube.createUsage(peerHier, xmlDimension); 686 687 return peerDimension; 688 } 689 690 691 692 699 class RolapNullMember extends RolapMember { 700 RolapNullMember(final RolapLevel level) { 701 super(null, level, null, "#Null", MemberType.NULL); 702 assert level != null; 703 } 704 705 public boolean isNull() { 706 return true; 707 } 708 } 709 710 private static class RolapCalculatedMeasure 711 extends RolapCalculatedMember 712 implements RolapMeasure 713 { 714 public RolapCalculatedMeasure( 715 RolapMember parent, RolapLevel level, String name, Formula formula) { 716 super(parent, level, name, formula); 717 } 718 719 public CellFormatter getFormatter() { 720 return null; 721 } 722 } 723 } 724 | Popular Tags |