1 13 14 package mondrian.rolap; 15 import mondrian.olap.*; 16 import mondrian.resource.MondrianResource; 17 import mondrian.rolap.agg.*; 18 import mondrian.rolap.sql.SqlQuery; 19 20 import org.apache.log4j.Logger; 21 import java.lang.reflect.Constructor ; 22 import java.util.*; 23 24 31 public class RolapLevel extends LevelBase { 32 33 private static final Logger LOGGER = Logger.getLogger(RolapEvaluator.class); 34 35 public static RolapLevel lookupLevel(RolapLevel[] levels, String levelName) { 36 for (RolapLevel level : levels) { 37 if (level.getName().equals(levelName)) { 38 return level; 39 } 40 } 41 return null; 42 } 43 44 static final int ALL = 2; 45 static final int UNIQUE = 4; 46 47 48 private final MondrianDef.Expression keyExp; 49 50 private final MondrianDef.Expression ordinalExp; 51 52 private final MondrianDef.Expression captionExp; 53 56 private final boolean unique; 57 private final SqlQuery.Datatype datatype; 58 private final int flags; 59 private final RolapProperty[] properties; 60 private final RolapProperty[] inheritedProperties; 61 62 66 private final MondrianDef.Expression nameExp; 67 69 private final MondrianDef.Expression parentExp; 70 71 private final String nullParentValue; 72 73 74 private final HideMemberCondition hideMemberCondition; 75 private final MondrianDef.Closure xmlClosure; 76 77 private LevelReader levelReader; 78 79 87 RolapLevel( 88 RolapHierarchy hierarchy, 89 int depth, 90 String name, 91 MondrianDef.Expression keyExp, 92 MondrianDef.Expression nameExp, 93 MondrianDef.Expression captionExp, 94 MondrianDef.Expression ordinalExp, 95 MondrianDef.Expression parentExp, 96 String nullParentValue, 97 MondrianDef.Closure xmlClosure, 98 RolapProperty[] properties, 99 int flags, 100 SqlQuery.Datatype datatype, 101 HideMemberCondition 102 hideMemberCondition, 103 LevelType levelType, String approxRowCount) 104 { 105 super(hierarchy, name, depth, levelType); 106 107 Util.assertPrecondition(properties != null, "properties != null"); 108 Util.assertPrecondition(hideMemberCondition != null, 109 "hideMemberCondition != null"); 110 Util.assertPrecondition(levelType != null, "levelType != null"); 111 112 if (keyExp instanceof MondrianDef.Column) { 113 checkColumn((MondrianDef.Column) keyExp); 114 } 115 this.approxRowCount = loadApproxRowCount(approxRowCount); 116 this.flags = flags; 117 final boolean isAll = (flags & ALL) == ALL; 118 this.unique = (flags & UNIQUE) == UNIQUE; 119 this.datatype = datatype; 120 this.keyExp = keyExp; 121 if (nameExp != null) { 122 if (nameExp instanceof MondrianDef.Column) { 123 checkColumn((MondrianDef.Column) nameExp); 124 } 125 } 126 this.nameExp = nameExp; 127 if (captionExp != null) { 128 if (captionExp instanceof MondrianDef.Column) { 129 checkColumn((MondrianDef.Column) captionExp); 130 } 131 } 132 this.captionExp = captionExp; 133 if (ordinalExp != null) { 134 if (ordinalExp instanceof MondrianDef.Column) { 135 checkColumn((MondrianDef.Column) ordinalExp); 136 } 137 this.ordinalExp = ordinalExp; 138 } else { 139 this.ordinalExp = this.keyExp; 140 } 141 this.parentExp = parentExp; 142 if (parentExp != null) { 143 Util.assertTrue(!isAll, "'All' level '" + this + "' must not be parent-child"); 144 Util.assertTrue(unique, "Parent-child level '" + this + "' must have uniqueMembers=\"true\""); 145 } 146 this.nullParentValue = nullParentValue; 147 Util.assertPrecondition(parentExp != null || nullParentValue == null, 148 "parentExp != null || nullParentValue == null"); 149 this.xmlClosure = xmlClosure; 150 for (RolapProperty property : properties) { 151 if (property.getExp() instanceof MondrianDef.Column) { 152 checkColumn((MondrianDef.Column) property.getExp()); 153 } 154 } 155 this.properties = properties; 156 List<Property> list = new ArrayList<Property>(); 157 for (Level level = this; level != null; 158 level = level.getParentLevel()) { 159 final Property[] levelProperties = level.getProperties(); 160 for (final Property levelProperty : levelProperties) { 161 Property existingProperty = lookupProperty( 162 list, levelProperty.getName()); 163 if (existingProperty == null) { 164 list.add(levelProperty); 165 } else if (existingProperty.getType() != 166 levelProperty.getType()) { 167 throw Util.newError( 168 "Property " + this.getName() + "." + 169 levelProperty.getName() + " overrides a " + 170 "property with the same name but different type"); 171 } 172 } 173 } 174 this.inheritedProperties = list.toArray(new RolapProperty[list.size()]); 175 176 Dimension dim = hierarchy.getDimension(); 177 if (dim.getDimensionType() == DimensionType.TimeDimension) { 178 if (!levelType.isTime() && !isAll) { 179 throw MondrianResource.instance() 180 .NonTimeLevelInTimeHierarchy.ex(getUniqueName()); 181 } 182 } else if (dim.getDimensionType() == null) { 183 } else { 186 if (levelType.isTime()) { 187 throw MondrianResource.instance() 188 .TimeLevelInNonTimeHierarchy.ex(getUniqueName()); 189 } 190 } 191 this.hideMemberCondition = hideMemberCondition; 192 } 193 194 195 public RolapHierarchy getHierarchy() { 196 return (RolapHierarchy) hierarchy; 197 } 198 199 private int loadApproxRowCount(String approxRowCount) { 200 boolean notNullAndNumeric = approxRowCount != null && approxRowCount.matches("^\\d+$"); 201 if(notNullAndNumeric){ 202 203 return Integer.parseInt(approxRowCount); 204 } else { 205 return Integer.MIN_VALUE; 207 } 208 } 209 210 protected Logger getLogger() { 211 return LOGGER; 212 } 213 214 String getTableName() { 215 String tableName = null; 216 217 MondrianDef.Expression expr = getKeyExp(); 218 if (expr instanceof MondrianDef.Column) { 219 MondrianDef.Column mc = (MondrianDef.Column) expr; 220 tableName = mc.getTableAlias(); 221 } 222 return tableName; 223 } 224 225 LevelReader getLevelReader() { 226 return levelReader; 227 } 228 229 public MondrianDef.Expression getKeyExp() { 230 return keyExp; 231 } 232 233 MondrianDef.Expression getOrdinalExp() { 234 return ordinalExp; 235 } 236 237 public MondrianDef.Expression getCaptionExp() { 238 return captionExp; 239 } 240 241 public boolean hasCaptionColumn(){ 242 return captionExp != null; 243 } 244 245 int getFlags() { 246 return flags; 247 } 248 249 HideMemberCondition getHideMemberCondition() { 250 return hideMemberCondition; 251 } 252 253 public boolean isUnique() { 254 return unique; 255 } 256 257 SqlQuery.Datatype getDatatype() { 258 return datatype; 259 } 260 261 String getNullParentValue() { 262 return nullParentValue; 263 } 264 265 268 public boolean isParentChild() { 269 return parentExp != null; 270 } 271 272 MondrianDef.Expression getParentExp() { 273 return parentExp; 274 } 275 276 public 278 MondrianDef.Expression getNameExp() { 279 return nameExp; 280 } 281 282 private Property lookupProperty(List<Property> list, String propertyName) { 283 for (Property property : list) { 284 if (property.getName().equals(propertyName)) { 285 return property; 286 } 287 } 288 return null; 289 } 290 291 RolapLevel(RolapHierarchy hierarchy, int depth, MondrianDef.Level xmlLevel) { 292 this( 293 hierarchy, depth, xmlLevel.name, xmlLevel.getKeyExp(), 294 xmlLevel.getNameExp(), xmlLevel.getCaptionExp(), xmlLevel.getOrdinalExp(), 295 xmlLevel.getParentExp(), xmlLevel.nullParentValue, 296 xmlLevel.closure, createProperties(xmlLevel), 297 (xmlLevel.uniqueMembers ? UNIQUE : 0), 298 xmlLevel.getDatatype(), 299 HideMemberCondition.valueOf(xmlLevel.hideMemberIf), 300 LevelType.valueOf(xmlLevel.levelType), xmlLevel.approxRowCount); 301 302 if (!Util.isEmpty(xmlLevel.caption)) { 303 setCaption(xmlLevel.caption); 304 } 305 if (!Util.isEmpty(xmlLevel.formatter)) { 306 try { 308 Class <MemberFormatter> clazz = 309 (Class <MemberFormatter>) Class.forName(xmlLevel.formatter); 310 Constructor <MemberFormatter> ctor = clazz.getConstructor(); 311 memberFormatter = ctor.newInstance(); 312 } catch (Exception e) { 313 throw MondrianResource.instance().MemberFormatterLoadFailed.ex( 314 xmlLevel.formatter, getUniqueName(), e); 315 } 316 } 317 } 318 319 private static RolapProperty[] createProperties( 321 MondrianDef.Level xmlLevel) { 322 List<RolapProperty> list = new ArrayList<RolapProperty>(); 323 final MondrianDef.Expression nameExp = xmlLevel.getNameExp(); 324 325 if (nameExp != null) { 326 list.add(new RolapProperty( 327 Property.NAME.name, Property.Datatype.TYPE_STRING, 328 nameExp, null, null)); 329 } 330 for (int i = 0; i < xmlLevel.properties.length; i++) { 331 MondrianDef.Property property = xmlLevel.properties[i]; 332 list.add(new RolapProperty( 333 property.name, 334 convertPropertyTypeNameToCode(property.type), 335 xmlLevel.getPropertyExp(i), 336 property.formatter, property.caption)); 337 } 338 return list.toArray(new RolapProperty[list.size()]); 339 } 340 341 private static Property.Datatype convertPropertyTypeNameToCode(String type) { 342 if (type.equals("String")) { 343 return Property.Datatype.TYPE_STRING; 344 } else if (type.equals("Numeric")) { 345 return Property.Datatype.TYPE_NUMERIC; 346 } else if (type.equals("Boolean")) { 347 return Property.Datatype.TYPE_BOOLEAN; 348 } else { 349 throw Util.newError("Unknown property type '" + type + "'"); 350 } 351 } 352 353 private void checkColumn(MondrianDef.Column nameColumn) { 354 final RolapHierarchy rolapHierarchy = (RolapHierarchy) hierarchy; 355 if (nameColumn.table == null) { 356 final MondrianDef.Relation table = rolapHierarchy.getUniqueTable(); 357 if (table == null) { 358 throw Util.newError( 359 "must specify a table for level " + 360 getUniqueName() + 361 " because hierarchy has more than one table"); 362 } 363 nameColumn.table = table.getAlias(); 364 } else { 365 Util.assertTrue(rolapHierarchy.tableExists(nameColumn.table)); 366 } 367 } 368 369 void init(RolapCube cube, MondrianDef.CubeDimension xmlDimension) { 370 if (isAll()) { 371 this.levelReader = new AllLevelReaderImpl(); 372 } else if (levelType == LevelType.Null) { 373 this.levelReader = new NullLevelReader(); 374 } else if (xmlClosure != null) { 375 final RolapDimension dimension = ((RolapHierarchy) hierarchy) 376 .createClosedPeerDimension(this, xmlClosure, cube, xmlDimension); 377 378 dimension.init(cube, xmlDimension); 379 cube.registerDimension(dimension); 380 RolapLevel closedPeer = 381 (RolapLevel) dimension.getHierarchies()[0].getLevels()[1]; 382 this.levelReader = new ParentChildLevelReaderImpl(closedPeer); 383 } else { 384 this.levelReader = new RegularLevelReader(); 385 } 386 } 387 388 public boolean isAll() { 389 return hierarchy.hasAll() && (depth == 0); 390 } 391 392 public boolean areMembersUnique() { 393 return (depth == 0) || (depth == 1) && hierarchy.hasAll(); 394 } 395 396 public String getTableAlias() { 397 return keyExp.getTableAlias(); 398 } 399 400 public RolapProperty[] getProperties() { 401 return properties; 402 } 403 404 public Property[] getInheritedProperties() { 405 return inheritedProperties; 406 } 407 408 public int getApproxRowCount() { 409 return approxRowCount; 410 } 411 412 416 public enum HideMemberCondition { 417 418 Never, 419 420 421 IfBlankName, 422 423 424 IfParentsName 425 } 426 427 public OlapElement lookupChild(SchemaReader schemaReader, String name) { 428 return lookupChild(schemaReader, name, MatchType.EXACT); 429 } 430 431 public OlapElement lookupChild( 432 SchemaReader schemaReader, String name, MatchType matchType) 433 { 434 Member[] levelMembers = schemaReader.getLevelMembers(this, true); 435 if (levelMembers.length > 0) { 436 Member parent = levelMembers[0].getParentMember(); 437 return 438 RolapUtil.findBestMemberMatch( 439 Arrays.asList(levelMembers), 440 (RolapMember) parent, 441 this, 442 name, 443 matchType, 444 false); 445 } 446 return null; 447 } 448 449 453 boolean hasClosedPeer() { 454 return levelReader instanceof ParentChildLevelReaderImpl; 455 } 456 457 458 interface LevelReader { 459 467 boolean constrainRequest( 468 RolapMember member, 469 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 470 CellRequest request); 471 472 479 void constrainRegion( 480 StarColumnPredicate predicate, 481 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 482 RolapCacheRegion cacheRegion); 483 } 484 485 488 class RegularLevelReader implements LevelReader { 489 public boolean constrainRequest( 490 RolapMember member, 491 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 492 CellRequest request) { 493 assert member.getLevel() == RolapLevel.this; 494 if (member.getKey() == null) { 495 if (member == member.getHierarchy().getNullMember()) { 496 return true; 498 } else { 499 throw Util.newInternal("why is key null?"); 500 } 501 } 502 503 RolapStar.Column column = levelToColumnMap.get(RolapLevel.this); 504 if (column == null) { 505 return member != hierarchy.getDefaultMember() || 510 hierarchy.hasAll(); 511 } 512 513 final StarColumnPredicate predicate; 514 if (member.isCalculated()) { 515 predicate = null; 516 } else { 517 predicate = false ? new MemberColumnPredicate(column, member) : 518 new ValueColumnPredicate(column, member.getSqlKey()); 519 } 520 521 request.addConstrainedColumn(column, predicate); 524 if (request.extendedContext && 525 getNameExp() != null) { 526 RolapStar.Column nameColumn = column.getNameColumn(); 527 528 Util.assertTrue(nameColumn != null); 529 request.addConstrainedColumn(nameColumn, null); 530 } 531 532 if (member.isCalculated()) { 533 return false; 534 } 535 536 if (unique) { 539 return false; 540 } 541 542 RolapMember parent = member.getParentMember(); 544 while (true) { 545 if (parent == null) { 546 return false; 547 } 548 RolapLevel level = parent.getLevel(); 549 final LevelReader levelReader = level.levelReader; 550 if (levelReader == this) { 551 parent = parent.getParentMember(); 556 continue; 557 } 558 return levelReader.constrainRequest( 559 parent, levelToColumnMap, request); 560 } 561 } 562 563 public void constrainRegion( 564 StarColumnPredicate predicate, 565 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 566 RolapCacheRegion cacheRegion) 567 { 568 RolapStar.Column column = levelToColumnMap.get(RolapLevel.this); 569 if (column == null) { 570 return; 575 } 576 577 if (predicate instanceof MemberColumnPredicate) { 578 MemberColumnPredicate memberColumnPredicate = 579 (MemberColumnPredicate) predicate; 580 RolapMember member = memberColumnPredicate.getMember(); 581 assert member.getLevel() == RolapLevel.this; 582 assert !member.isCalculated(); 583 assert memberColumnPredicate.getMember().getKey() != null; 584 assert !member.isNull(); 585 586 MemberTuplePredicate predicate2 = 587 new MemberTuplePredicate( 588 levelToColumnMap, 589 member); 590 591 cacheRegion.addPredicate(column, predicate); 594 return; 595 } else if (predicate instanceof RangeColumnPredicate) { 596 RangeColumnPredicate rangeColumnPredicate = 597 (RangeColumnPredicate) predicate; 598 final ValueColumnPredicate lowerBound = 599 rangeColumnPredicate.getLowerBound(); 600 RolapMember lowerMember; 601 if (lowerBound == null) { 602 lowerMember = null; 603 } else if (lowerBound instanceof MemberColumnPredicate) { 604 MemberColumnPredicate memberColumnPredicate = 605 (MemberColumnPredicate) lowerBound; 606 lowerMember = memberColumnPredicate.getMember(); 607 } else { 608 throw new UnsupportedOperationException (); 609 } 610 final ValueColumnPredicate upperBound = 611 rangeColumnPredicate.getUpperBound(); 612 RolapMember upperMember; 613 if (upperBound == null) { 614 upperMember = null; 615 } else if (upperBound instanceof MemberColumnPredicate) { 616 MemberColumnPredicate memberColumnPredicate = 617 (MemberColumnPredicate) upperBound; 618 upperMember = memberColumnPredicate.getMember(); 619 } else { 620 throw new UnsupportedOperationException (); 621 } 622 MemberTuplePredicate predicate2 = 623 new MemberTuplePredicate( 624 levelToColumnMap, 625 lowerMember, 626 !rangeColumnPredicate.getLowerInclusive(), 627 upperMember, 628 !rangeColumnPredicate.getUpperInclusive()); 629 cacheRegion.addPredicate(predicate2); 632 return; 633 } 634 635 throw new UnsupportedOperationException (); 637 } 638 } 639 640 643 class ParentChildLevelReaderImpl extends RegularLevelReader { 644 648 private final RolapLevel closedPeer; 649 650 ParentChildLevelReaderImpl(RolapLevel closedPeer) { 651 this.closedPeer = closedPeer; 652 } 653 654 public boolean constrainRequest( 655 RolapMember member, 656 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 657 CellRequest request) { 658 659 if (member.getDataMember() == null) { 663 return super.constrainRequest( 667 member, levelToColumnMap, request); 668 } else if (request.drillThrough) { 669 member = (RolapMember) member.getDataMember(); 670 return super.constrainRequest( 671 member, levelToColumnMap, request); 672 } else { 673 RolapLevel level = closedPeer; 674 final RolapMember allMember = (RolapMember) 675 level.getHierarchy().getDefaultMember(); 676 assert allMember.isAll(); 677 member = new RolapMember(allMember, level, 678 member.getKey()); 679 return level.getLevelReader().constrainRequest( 680 member, levelToColumnMap, request); 681 } 682 } 683 684 public void constrainRegion( 685 StarColumnPredicate predicate, 686 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 687 RolapCacheRegion cacheRegion) 688 { 689 throw new UnsupportedOperationException (); 690 } 691 } 692 693 696 class AllLevelReaderImpl implements LevelReader { 697 public boolean constrainRequest( 698 RolapMember member, 699 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 700 CellRequest request) { 701 return false; 703 } 704 705 public void constrainRegion( 706 StarColumnPredicate predicate, 707 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 708 RolapCacheRegion cacheRegion) 709 { 710 } 712 } 713 714 717 class NullLevelReader implements LevelReader { 718 public boolean constrainRequest( 719 RolapMember member, 720 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 721 CellRequest request) { 722 return true; 723 } 724 725 public void constrainRegion( 726 StarColumnPredicate predicate, 727 Map<RolapLevel, RolapStar.Column> levelToColumnMap, 728 RolapCacheRegion cacheRegion) 729 { 730 } 731 } 732 } 733 734 | Popular Tags |