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) 2001-2002 Julian Hyde 008// Copyright (C) 2004-2005 TONBELLER AG 009// Copyright (C) 2007-2008 StrateBI 010// Copyright (C) 2008-2012 Pentaho and others 011// All Rights Reserved. 012*/ 013package mondrian.rolap; 014 015import mondrian.olap.*; 016import mondrian.rolap.TupleReader.MemberBuilder; 017import mondrian.rolap.sql.MemberChildrenConstraint; 018import mondrian.rolap.sql.TupleConstraint; 019import mondrian.util.ConcatenableList; 020 021import org.apache.log4j.Logger; 022 023import java.util.*; 024 025/** 026 * <code>NoCacheMemberReader</code> implements {@link MemberReader} but 027 * without doing any kind of caching and avoiding to read all members. 028 * 029 * @author jlopez, lcanals 030 * @since 06 October, 2007 031 */ 032public class NoCacheMemberReader implements MemberReader, MemberCache { 033 private static final Logger LOGGER = 034 Logger.getLogger(NoCacheMemberReader.class); 035 036 private final SqlConstraintFactory sqlConstraintFactory = 037 SqlConstraintFactory.instance(); 038 039 private final MemberReader source; 040 041 042 NoCacheMemberReader(MemberReader source) { 043 this.source = source; 044 if (!source.setCache(this)) { 045 throw Util.newInternal( 046 "MemberSource (" + source + ", " + source.getClass() 047 + ") does not support cache-writeback"); 048 } 049 } 050 051 // implementes MemberCache 052 public boolean isMutable() { 053 return false; 054 } 055 056 // implementes MemberCache 057 public RolapMember removeMember(Object key) { 058 return null; 059 } 060 061 // implementes MemberCache 062 public RolapMember removeMemberAndDescendants(Object key) { 063 return null; 064 } 065 066 // implement MemberReader 067 public RolapHierarchy getHierarchy() { 068 return source.getHierarchy(); 069 } 070 071 // implement MemberCache 072 public boolean setCache(MemberCache cache) { 073 return false; 074 } 075 076 // implement MemberCache 077 public Object makeKey(final RolapMember parent, final Object key) { 078 LOGGER.debug("Entering makeKey"); 079 return new MemberKey(parent, key); 080 } 081 082 public synchronized RolapMember getMember(final Object key) { 083 return getMember(key, true); 084 } 085 086 public RolapMember getMember( 087 final Object key, 088 final boolean mustCheckCacheStatus) 089 { 090 LOGGER.debug("Returning null member: no cache"); 091 return null; 092 } 093 094 095 // implement MemberCache 096 public Object putMember(final Object key, final RolapMember value) { 097 LOGGER.debug("putMember void for no caching"); 098 return value; 099 } 100 101 // implement MemberReader 102 public List<RolapMember> getMembers() { 103 System.out.println("NoCache getMembers"); 104 List<RolapMember> v = new ArrayList<RolapMember>(); 105 RolapLevel[] levels = (RolapLevel[]) getHierarchy().getLevels(); 106 // todo: optimize by walking to children for members we know about 107 for (RolapLevel level : levels) { 108 List<RolapMember> membersInLevel = 109 getMembersInLevel(level); 110 v.addAll(membersInLevel); 111 } 112 return v; 113 } 114 115 public List<RolapMember> getRootMembers() { 116 LOGGER.debug("Getting root members"); 117 return source.getRootMembers(); 118 } 119 120 public List<RolapMember> getMembersInLevel( 121 final RolapLevel level) 122 { 123 TupleConstraint constraint = 124 sqlConstraintFactory.getLevelMembersConstraint(null); 125 return getMembersInLevel(level, constraint); 126 } 127 128 public List<RolapMember> getMembersInLevel( 129 final RolapLevel level, final TupleConstraint constraint) 130 { 131 LOGGER.debug("Entering getMembersInLevel"); 132 return source.getMembersInLevel( 133 level, constraint); 134 } 135 136 public RolapMember getMemberByKey( 137 RolapLevel level, List<Comparable> keyValues) 138 { 139 return source.getMemberByKey(level, keyValues); 140 } 141 142 public void getMemberChildren( 143 final RolapMember parentMember, 144 final List<RolapMember> children) 145 { 146 MemberChildrenConstraint constraint = 147 sqlConstraintFactory.getMemberChildrenConstraint(null); 148 getMemberChildren(parentMember, children, constraint); 149 } 150 151 public Map<? extends Member, Access> getMemberChildren( 152 final RolapMember parentMember, 153 final List<RolapMember> children, 154 final MemberChildrenConstraint constraint) 155 { 156 List<RolapMember> parentMembers = new ArrayList<RolapMember>(); 157 parentMembers.add(parentMember); 158 return getMemberChildren(parentMembers, children, constraint); 159 } 160 161 public void getMemberChildren( 162 final List<RolapMember> parentMembers, 163 final List<RolapMember> children) 164 { 165 MemberChildrenConstraint constraint = 166 sqlConstraintFactory.getMemberChildrenConstraint(null); 167 getMemberChildren(parentMembers, children, constraint); 168 } 169 170 public Map<? extends Member, Access> getMemberChildren( 171 final List<RolapMember> parentMembers, 172 final List<RolapMember> children, 173 final MemberChildrenConstraint constraint) 174 { 175 assert (constraint != null); 176 LOGGER.debug("Entering getMemberChildren"); 177 return 178 source.getMemberChildren( 179 parentMembers, children, constraint); 180 } 181 182 public RolapMember lookupMember( 183 final List<Id.Segment> uniqueNameParts, 184 final boolean failIfNotFound) 185 { 186 return RolapUtil.lookupMember(this, uniqueNameParts, failIfNotFound); 187 } 188 189 public List<RolapMember> getChildrenFromCache( 190 final RolapMember member, 191 final MemberChildrenConstraint constraint) 192 { 193 return null; 194 } 195 196 public List<RolapMember> getLevelMembersFromCache( 197 final RolapLevel level, 198 final TupleConstraint constraint) 199 { 200 return null; 201 } 202 203 public void putChildren( 204 final RolapMember member, 205 final MemberChildrenConstraint constraint, 206 final List<RolapMember> children) 207 { 208 } 209 210 public void putChildren( 211 final RolapLevel level, 212 final TupleConstraint constraint, 213 final List<RolapMember> children) 214 { 215 } 216 217 public RolapMember getLeadMember(RolapMember member, int n) { 218 if (n == 0 || member.isNull()) { 219 return member; 220 } else { 221 SiblingIterator iter = new SiblingIterator(this, member); 222 if (n > 0) { 223 RolapMember sibling = null; 224 while (n-- > 0) { 225 if (!iter.hasNext()) { 226 return (RolapMember) member.getHierarchy() 227 .getNullMember(); 228 } 229 sibling = iter.nextMember(); 230 } 231 return sibling; 232 } else { 233 n = -n; 234 RolapMember sibling = null; 235 while (n-- > 0) { 236 if (!iter.hasPrevious()) { 237 return (RolapMember) member.getHierarchy() 238 .getNullMember(); 239 } 240 sibling = iter.previousMember(); 241 } 242 return sibling; 243 } 244 } 245 } 246 247 public void getMemberRange( 248 final RolapLevel level, 249 final RolapMember startMember, 250 final RolapMember endMember, 251 final List<RolapMember> list) 252 { 253 assert startMember != null : "pre"; 254 assert endMember != null : "pre"; 255 assert startMember.getLevel() == endMember.getLevel() 256 : "pre: startMember.getLevel() == endMember.getLevel()"; 257 258 if (compare(startMember, endMember, false) > 0) { 259 return; 260 } 261 list.add(startMember); 262 if (startMember.equals(endMember)) { 263 return; 264 } 265 SiblingIterator siblings = new SiblingIterator(this, startMember); 266 while (siblings.hasNext()) { 267 final RolapMember member = siblings.nextMember(); 268 list.add(member); 269 if (member.equals(endMember)) { 270 return; 271 } 272 } 273 throw Util.newInternal( 274 "sibling iterator did not hit end point, start=" 275 + startMember + ", end=" + endMember); 276 } 277 278 public int getMemberCount() { 279 return source.getMemberCount(); 280 } 281 282 public int compare( 283 final RolapMember m1, 284 final RolapMember m2, 285 final boolean siblingsAreEqual) 286 { 287 if (Util.equals(m1, m2)) { 288 return 0; 289 } 290 if (Util.equals(m1.getParentMember(), m2.getParentMember())) { 291 // including case where both parents are null 292 if (siblingsAreEqual) { 293 return 0; 294 } else if (m1.getParentMember() == null) { 295 // at this point we know that both parent members are null. 296 int pos1 = -1, pos2 = -1; 297 List<RolapMember> siblingList = getRootMembers(); 298 for (int i = 0, n = siblingList.size(); i < n; i++) { 299 RolapMember child = siblingList.get(i); 300 if (child.equals(m1)) { 301 pos1 = i; 302 } 303 if (child.equals(m2)) { 304 pos2 = i; 305 } 306 } 307 if (pos1 == -1) { 308 throw Util.newInternal(m1 + " not found among siblings"); 309 } 310 if (pos2 == -1) { 311 throw Util.newInternal(m2 + " not found among siblings"); 312 } 313 Util.assertTrue(pos1 != pos2); 314 return pos1 < pos2 ? -1 : 1; 315 } else { 316 List<RolapMember> children = new ArrayList<RolapMember>(); 317 getMemberChildren(m1.getParentMember(), children); 318 int pos1 = -1, pos2 = -1; 319 for (int i = 0, n = children.size(); i < n; i++) { 320 RolapMember child = children.get(i); 321 if (child.equals(m1)) { 322 pos1 = i; 323 } 324 if (child.equals(m2)) { 325 pos2 = i; 326 } 327 } 328 if (pos1 == -1) { 329 throw Util.newInternal(m1 + " not found among siblings"); 330 } 331 if (pos2 == -1) { 332 throw Util.newInternal(m2 + " not found among siblings"); 333 } 334 assert pos1 != pos2; 335 return pos1 < pos2 ? -1 : 1; 336 } 337 } 338 int levelDepth1 = m1.getLevel().getDepth(); 339 int levelDepth2 = m2.getLevel().getDepth(); 340 if (levelDepth1 < levelDepth2) { 341 final int c = compare(m1, m2.getParentMember(), false); 342 return (c == 0) ? -1 : c; 343 344 } else if (levelDepth1 > levelDepth2) { 345 final int c = compare(m1.getParentMember(), m2, false); 346 return (c == 0) ? 1 : c; 347 348 } else { 349 return compare(m1.getParentMember(), m2.getParentMember(), false); 350 } 351 } 352 353 /** 354 * <code>SiblingIterator</code> helps traverse a hierarchy of members, by 355 * remembering the position at each level. Each SiblingIterator has a 356 * parent, to which it defers when the last child of the current member is 357 * reached. 358 */ 359 class SiblingIterator { 360 private final MemberReader reader; 361 private final SiblingIterator parentIterator; 362 private List<? extends Member> siblings; 363 private int position; 364 365 SiblingIterator(MemberReader reader, RolapMember member) { 366 this.reader = reader; 367 RolapMember parent = member.getParentMember(); 368 List<RolapMember> siblingList; 369 if (parent == null) { 370 siblingList = reader.getRootMembers(); 371 this.parentIterator = null; 372 } else { 373 siblingList = new ArrayList<RolapMember>(); 374 reader.getMemberChildren(parent, siblingList); 375 this.parentIterator = new SiblingIterator(reader, parent); 376 } 377 this.siblings = siblingList; 378 this.position = -1; 379 for (int i = 0; i < this.siblings.size(); i++) { 380 if (siblings.get(i).equals(member)) { 381 this.position = i; 382 break; 383 } 384 } 385 if (this.position == -1) { 386 throw Util.newInternal( 387 "member " + member + " not found among its siblings"); 388 } 389 } 390 391 boolean hasNext() { 392 return (this.position < this.siblings.size() - 1) 393 || (parentIterator != null) 394 && parentIterator.hasNext(); 395 } 396 397 Object next() { 398 return nextMember(); 399 } 400 401 RolapMember nextMember() { 402 if (++this.position >= this.siblings.size()) { 403 if (parentIterator == null) { 404 throw Util.newInternal("there is no next member"); 405 } 406 RolapMember parent = parentIterator.nextMember(); 407 List<RolapMember> siblingList = new ArrayList<RolapMember>(); 408 reader.getMemberChildren(parent, siblingList); 409 this.siblings = siblingList; 410 this.position = 0; 411 } 412 return (RolapMember) this.siblings.get(this.position); 413 } 414 415 boolean hasPrevious() { 416 return (this.position > 0) 417 || (parentIterator != null) 418 && parentIterator.hasPrevious(); 419 } 420 421 Object previous() { 422 return previousMember(); 423 } 424 425 RolapMember previousMember() { 426 if (--this.position < 0) { 427 if (parentIterator == null) { 428 throw Util.newInternal("there is no next member"); 429 } 430 RolapMember parent = parentIterator.previousMember(); 431 List<RolapMember> siblingList = new ArrayList<RolapMember>(); 432 reader.getMemberChildren(parent, siblingList); 433 this.siblings = siblingList; 434 this.position = this.siblings.size() - 1; 435 } 436 return (RolapMember) this.siblings.get(this.position); 437 } 438 } 439 440 public MemberBuilder getMemberBuilder() { 441 return source.getMemberBuilder(); 442 } 443 444 public RolapMember getDefaultMember() { 445 RolapMember defaultMember = 446 (RolapMember) getHierarchy().getDefaultMember(); 447 if (defaultMember != null) { 448 return defaultMember; 449 } 450 return getRootMembers().get(0); 451 } 452 453 public int getLevelMemberCount(RolapLevel level) { 454 // No need to cache the result: the caller saves the result by calling 455 // RolapLevel.setApproxRowCount 456 return source.getLevelMemberCount(level); 457 } 458 459 public RolapMember desubstitute(RolapMember member) { 460 return member; 461 } 462 463 public RolapMember substitute(RolapMember member) { 464 return member; 465 } 466 467 public RolapMember getMemberParent(RolapMember member) { 468 // This method deals with ragged hierarchies but not access-controlled 469 // hierarchies - assume these have RestrictedMemberReader possibly 470 // wrapped in a SubstitutingMemberReader. 471 RolapMember parentMember = member.getParentMember(); 472 // Skip over hidden parents. 473 while (parentMember != null && parentMember.isHidden()) { 474 parentMember = parentMember.getParentMember(); 475 } 476 return parentMember; 477 } 478 479 /** 480 * Reads the children of <code>member</code> into <code>result</code>. 481 * 482 * @param result Children are written here, in order 483 * @param members Members whose children to read 484 * @param constraint restricts the returned members if possible (optional 485 * optimization) 486 */ 487 protected void readMemberChildren( 488 List<RolapMember> members, 489 List<RolapMember> result, 490 MemberChildrenConstraint constraint) 491 { 492 List<RolapMember> children = new ConcatenableList<RolapMember>(); 493 source.getMemberChildren(members, children, constraint); 494 // Put them in a temporary hash table first. Register them later, when 495 // we know their size (hence their 'cost' to the cache pool). 496 Map<RolapMember, List<RolapMember>> tempMap = 497 new HashMap<RolapMember, List<RolapMember>>(); 498 for (RolapMember member1 : members) { 499 //noinspection unchecked 500 tempMap.put(member1, Collections.EMPTY_LIST); 501 } 502 for (final RolapMember child : children) { 503 // todo: We could optimize here. If members.length is small, it's 504 // more efficient to drive from members, rather than hashing 505 // children.length times. We could also exploit the fact that the 506 // result is sorted by ordinal and therefore, unless the "members" 507 // contains members from different levels, children of the same 508 // member will be contiguous. 509 assert child != null : "child"; 510 final RolapMember parentMember = child.getParentMember(); 511 List<RolapMember> list = tempMap.get(parentMember); 512 if (list == null) { 513 // The list is null if, due to dropped constraints, we now 514 // have a children list of a member we didn't explicitly 515 // ask for it. Adding it to the cache would be viable, but 516 // let's ignore it. 517 continue; 518 } else if (list == Collections.EMPTY_LIST) { 519 list = new ArrayList<RolapMember>(); 520 tempMap.put(parentMember, list); 521 } 522 list.add(child); 523 result.add(child); 524 } 525 } 526} 527 528// End NoCacheMemberReader.java