001 /* 002 // $Id: //open/mondrian/src/main/mondrian/rolap/RolapAxis.java#19 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2005-2008 Julian Hyde 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 011 package mondrian.rolap; 012 013 014 import mondrian.olap.Axis; 015 import mondrian.olap.Member; 016 import mondrian.olap.Position; 017 import mondrian.util.UnsupportedList; 018 import org.apache.log4j.Logger; 019 import java.util.Collection; 020 import java.util.Collections; 021 import java.util.ListIterator; 022 import java.util.Iterator; 023 import java.util.ArrayList; 024 import java.util.List; 025 import java.util.ListIterator; 026 import java.util.NoSuchElementException; 027 028 /** 029 * Derived classes of RolapAxis implements the Axis interface which are 030 * specializations based upon the number of Positions, how each Position's 031 * Members are orgainized and whether the Members/Member[]s are in a List 032 * or an Iterable. 033 * 034 * @author <a>Richard M. Emberson</a> 035 * @version $Id: //open/mondrian/src/main/mondrian/rolap/RolapAxis.java#19 $ 036 */ 037 public abstract class RolapAxis implements Axis { 038 private static final Logger LOGGER = Logger.getLogger(RolapAxis.class); 039 040 public static String toString(Axis axis) { 041 List<Position> pl = axis.getPositions(); 042 return toString(pl); 043 } 044 public static String toString(List<Position> pl) { 045 StringBuilder buf = new StringBuilder(); 046 for (Position p : pl) { 047 buf.append('{'); 048 boolean firstTime = true; 049 for (Member m : p) { 050 if (! firstTime) { 051 buf.append(", "); 052 } 053 buf.append(m.getUniqueName()); 054 firstTime = false; 055 } 056 buf.append('}'); 057 buf.append('\n'); 058 } 059 return buf.toString(); 060 } 061 /** 062 * A Wrapper has many uses. In particular, if one is using Java 5 or 063 * above, one can create a Wrapper that is also a memory usage listener. 064 * Then one can place an Axis implementation into a Wrapper where the 065 * initial implementation is in-memory, large-memory-usage and 066 * cpu fast. The on the first memory notification it can be migrated 067 * to an in-memory, small-memory-usage and cpu slower. On a subsequent 068 * memory notification it can be migrated to an on-disk, low-memory and 069 * cpu slow implementation. 070 */ 071 public static class Wrapper extends RolapAxis { 072 private final Axis axis; 073 protected Wrapper(Axis axis) { 074 super(); 075 this.axis = axis; 076 } 077 public List<Position> getPositions() { 078 return this.axis.getPositions(); 079 } 080 } 081 082 /** 083 * The NoPosition Axis implementation is an Axis that has no Positions, 084 * the size of the list of positions is zero. 085 */ 086 public static class NoPosition extends RolapAxis { 087 public NoPosition() { 088 super(); 089 } 090 public List<Position> getPositions() { 091 return Collections.EMPTY_LIST; 092 } 093 } 094 095 /** 096 * The PositionList Axis implementation takes a List of positions. 097 */ 098 public static class PositionList extends RolapAxis { 099 protected final List<Position> positions; 100 public PositionList(List<Position> positions) { 101 super(); 102 this.positions = positions; 103 } 104 public List<Position> getPositions() { 105 return positions; 106 } 107 } 108 109 /** 110 * A SingleEmptyPosition has a single Position and the Position has 111 * no Members. 112 */ 113 public static class SingleEmptyPosition extends RolapAxis { 114 public SingleEmptyPosition() { 115 } 116 public List<Position> getPositions() { 117 return Collections.singletonList((Position) new EmptyPosition()); 118 } 119 static class EmptyPosition extends PositionBase { 120 EmptyPosition() { 121 } 122 public int size() { 123 return 0; 124 } 125 public Member get(int index) { 126 throw new IndexOutOfBoundsException( 127 "Index: " + index + ", Size: 0"); 128 } 129 } 130 } 131 132 /** 133 * A MemberIterable takes an Iterable<Member> where each Position has 134 * a single Member from the corresponding location in the iterator. 135 * If the client request any of the List, non-Iterable, API, then 136 * a List is materialized from the Iterable. 137 */ 138 public static class MemberIterable extends RolapAxis { 139 private Iterable<Member> iter; 140 private List<Member> list; 141 public MemberIterable(Iterable<Member> iter) { 142 this.iter = iter; 143 this.list = null; 144 } 145 public synchronized List<Position> getPositions() { 146 return (list == null) 147 ? new MemberIterable.PositionWrapper() 148 : new MemberIterable.PositionList(); 149 } 150 protected synchronized void materialize() { 151 //System.out.println("RolapAxis.materialize: 1"); 152 if (list == null) { 153 Iterator<Member> it = iter.iterator(); 154 list = new ArrayList<Member>(); 155 while (it.hasNext()) { 156 list.add(it.next()); 157 } 158 // allow gc of iter 159 iter = null; 160 } 161 } 162 163 164 /** 165 * This List<Position> starts life with a List<Position> 166 * implementation 167 * that is based upon an non-List (Iterable). If all accesses 168 * are simply through iteration, then the initial implementation 169 * remains, but if the client uses either the 'size' or 'get' methods 170 * then the Iterable is materialized into a List. 171 */ 172 class PositionWrapper extends PositionListUnsupported { 173 List<Position> positionList; 174 PositionWrapper() { 175 positionList = new PositionIter(); 176 } 177 protected synchronized void materialize() { 178 //System.out.println("RolapAxis.materialize: 2"); 179 if (LOGGER.isDebugEnabled()) { 180 LOGGER.debug( 181 "PositionWrapper.materialize: Member iter.class=" 182 + iter.getClass().getName()); 183 } 184 RolapAxis.MemberIterable.this.materialize(); 185 positionList = new MemberIterable.PositionList(); 186 } 187 public int size() { 188 try { 189 return positionList.size(); 190 } catch (UnsupportedOperationException ex) { 191 this.materialize(); 192 return positionList.size(); 193 } 194 } 195 public Position get(int index) { 196 try { 197 return positionList.get(index); 198 } catch (UnsupportedOperationException ex) { 199 this.materialize(); 200 return positionList.get(index); 201 } 202 } 203 public Iterator<Position> iterator() { 204 return positionList.iterator(); 205 } 206 } 207 208 /** 209 * PositionIter is a List<Position> that only support the 210 * 'iterator' method. This assumes that one iterates over Positions 211 * and for each Postion one iterates over Members. In this case, 212 * each Position has a single Member. 213 */ 214 class PositionIter extends PositionIterBase { 215 private Iterator<Member> it; 216 PositionIter() { 217 it = iter.iterator(); 218 } 219 public Iterator<Position> iterator() { 220 return new Iterator<Position>() { 221 public boolean hasNext() { 222 return it.hasNext(); 223 } 224 public Position next() { 225 return new MemberIterable.MIPosition(it.next()); 226 } 227 public void remove() { 228 throw new UnsupportedOperationException("remove"); 229 } 230 }; 231 } 232 } 233 234 /** 235 * A List<Member> which only implements the 'iterator' method. 236 * Each Iterator<Member> has only one Member. 237 */ 238 class MIPosition extends PositionBase { 239 Member member; 240 MIPosition(Member member) { 241 this.member = member; 242 } 243 public int size() { 244 return 1; 245 } 246 public Member get(int index) { 247 if (index != 0) { 248 throw new IndexOutOfBoundsException( 249 "Index: " + index + ", Size: 1"); 250 } 251 return member; 252 } 253 254 public Iterator<Member> iterator() { 255 return new Iterator<Member>() { 256 public boolean hasNext() { 257 return (member != null); 258 } 259 public Member next() { 260 try { 261 return member; 262 } finally { 263 member = null; 264 } 265 } 266 public void remove() { 267 throw new UnsupportedOperationException("remove"); 268 } 269 }; 270 } 271 } 272 273 /** 274 * Each Position has a single Member. 275 */ 276 class PositionList extends PositionListBase { 277 PositionList() { 278 } 279 public int size() { 280 return list.size(); 281 } 282 public Position get(int index) { 283 return new MemberIterable.MLPosition(index); 284 } 285 } 286 287 /** 288 * Allows access only the the Member at the given offset. 289 */ 290 class MLPosition extends PositionBase { 291 protected final int offset; 292 MLPosition(int offset) { 293 this.offset = offset; 294 } 295 public int size() { 296 return 1; 297 } 298 public Member get(int index) { 299 if (index != 0) { 300 throw new IndexOutOfBoundsException( 301 "Index: " + index + ", Size: 1"); 302 } 303 return list.get(offset); 304 } 305 } 306 } 307 308 309 310 /** 311 * A MemberList takes a List<Member> where each Position has 312 * a single Member from the corresponding location in the list. 313 */ 314 public static class MemberList extends RolapAxis { 315 private final List<Member> list; 316 public MemberList(List<Member> list) { 317 this.list = list; 318 } 319 public List<Position> getPositions() { 320 return new MemberList.PositionList(); 321 } 322 /** 323 * Each Position has a single Member. 324 */ 325 class PositionList extends PositionListBase { 326 PositionList() { 327 } 328 public int size() { 329 return list.size(); 330 } 331 public Position get(int index) { 332 return new MemberList.MLPosition(index); 333 } 334 public Iterator<Position> iterator() { 335 return new Iterator<Position>() { 336 private final Iterator it = list.iterator(); 337 private int cursor = 0; 338 public boolean hasNext() { 339 return it.hasNext(); 340 } 341 public Position next() { 342 it.next(); 343 return get(cursor++); 344 } 345 public void remove() { 346 throw new UnsupportedOperationException(); 347 } 348 }; 349 } 350 } 351 352 /** 353 * Allows access only the the Member at the given offset. 354 */ 355 class MLPosition extends PositionBase { 356 protected final int offset; 357 MLPosition(int offset) { 358 this.offset = offset; 359 } 360 public int size() { 361 return 1; 362 } 363 public Member get(int index) { 364 if (index != 0) { 365 throw new IndexOutOfBoundsException( 366 "Index: " + index + ", Size: 1"); 367 } 368 return list.get(offset); 369 } 370 } 371 } 372 373 /** 374 * A MemberArrayIterable takes an Iterable<Member[]> where 375 * each Position has 376 * an array of Members from the corresponding location in the iterator. 377 * If the client request any of the List, non-Iterable, API, then 378 * a List is materialized from the Iterable. 379 */ 380 public static class MemberArrayIterable extends RolapAxis { 381 private Iterable<Member[]> iter; 382 private List<Member[]> list; 383 private int len; 384 public MemberArrayIterable(Iterable<Member[]> iter) { 385 this.iter = iter; 386 this.list = null; 387 this.len = 0; 388 } 389 public synchronized List<Position> getPositions() { 390 return (list == null) 391 ? new MemberArrayIterable.PositionWrapper() 392 : new MemberArrayIterable.PositionList(); 393 } 394 protected synchronized void materialize() { 395 //System.out.println("RolapAxis.materialize: 3"); 396 if (list == null) { 397 Iterator<Member[]> it = iter.iterator(); 398 list = new ArrayList<Member[]>(); 399 while (it.hasNext()) { 400 list.add(it.next()); 401 } 402 // allow gc of iter 403 iter = null; 404 405 len = (list.size() == 0) ? 0 : list.get(0).length; 406 } 407 } 408 409 /** 410 * This List<Position> starts life with a List<Position> 411 * implementation 412 * that is based upon an non-List (Iterable). If all accesses 413 * are simply through iteration, then the initial implementation 414 * remains, but if the client uses either the 'size' or 'get' methods 415 * then the Iterable is materialized into a List. 416 */ 417 class PositionWrapper extends PositionListUnsupported { 418 List<Position> positionList; 419 PositionWrapper() { 420 positionList = new PositionIter(); 421 } 422 protected synchronized void materialize() { 423 //System.out.println("RolapAxis.materialize: 4"); 424 if (LOGGER.isDebugEnabled()) { 425 LOGGER.debug( 426 "PositionWrapper.materialize: Member[] iter.class=" 427 + ((iter != null) ? iter.getClass().getName() : null)); 428 } 429 RolapAxis.MemberArrayIterable.this.materialize(); 430 positionList = new MemberArrayIterable.PositionList(); 431 } 432 public int size() { 433 try { 434 return positionList.size(); 435 } catch (UnsupportedOperationException ex) { 436 this.materialize(); 437 return positionList.size(); 438 } 439 } 440 public Position get(int index) { 441 try { 442 return positionList.get(index); 443 } catch (UnsupportedOperationException ex) { 444 this.materialize(); 445 return positionList.get(index); 446 } 447 } 448 public Iterator<Position> iterator() { 449 return positionList.iterator(); 450 } 451 } 452 453 /** 454 * PositionIter is a List<Position> that only support the 455 * 'iterator' method. This assumes that one iterates over Positions 456 * and for each Postion one iterates over Members. Each Position 457 * has two or more Members. 458 */ 459 class PositionIter extends PositionIterBase { 460 private Iterator<Member[]> it; 461 PositionIter() { 462 it = iter.iterator(); 463 } 464 public Iterator<Position> iterator() { 465 return new Iterator<Position>() { 466 int nextCnt = 0; 467 public boolean hasNext() { 468 return it.hasNext(); 469 } 470 public Position next() { 471 nextCnt++; 472 return new MemberArrayIterable.MIPosition(it.next()); 473 } 474 public void remove() { 475 throw new UnsupportedOperationException("remove"); 476 } 477 }; 478 } 479 } 480 /** 481 * A List<Member> which only implements the 'iterator' method. 482 * Each Iterator<Member> two or more Members. 483 */ 484 class MIPosition extends PositionBase { 485 Member[] members; 486 MIPosition(Member[] members) { 487 this.members = members; 488 } 489 public int size() { 490 return members.length; 491 } 492 public Member get(int index) { 493 return members[index]; 494 } 495 public Iterator<Member> iterator() { 496 return new Iterator<Member>() { 497 int index = 0; 498 public boolean hasNext() { 499 return (index < members.length); 500 } 501 public Member next() { 502 return members[index++]; 503 } 504 public void remove() { 505 throw new UnsupportedOperationException("remove"); 506 } 507 }; 508 } 509 } 510 511 /** 512 * Each Position has two or more Members. 513 */ 514 class PositionList extends PositionListBase { 515 PositionList() { 516 } 517 public int size() { 518 return list.size(); 519 } 520 public Position get(int index) { 521 return new MemberArrayIterable.MALPosition(index); 522 } 523 } 524 525 /** 526 * Allows access only the the Member at the given offset. 527 */ 528 class MALPosition extends PositionBase { 529 protected final int offset; 530 MALPosition(int offset) { 531 this.offset = offset; 532 } 533 public int size() { 534 return RolapAxis.MemberArrayIterable.this.len; 535 } 536 public Member get(int index) { 537 if (index > RolapAxis.MemberArrayIterable.this.len) { 538 throw new IndexOutOfBoundsException( 539 "Index: " + 540 index + 541 ", Size: " + 542 RolapAxis.MemberArrayIterable.this.len); 543 } 544 return list.get(offset)[index]; 545 } 546 } 547 } 548 549 550 551 /** 552 * A MemberArrayList takes a List<Member[]> where each Position has 553 * the Member's from the corresponding location in the list. 554 * It is assumed that each element of the list has an array of Members of 555 * the same size. 556 */ 557 public static class MemberArrayList extends RolapAxis { 558 private final List<Member[]> list; 559 private final int len; 560 public MemberArrayList(List<Member[]> list) { 561 this.list = list; 562 this.len = (list.size() == 0) ? 0 : list.get(0).length; 563 } 564 public List<Position> getPositions() { 565 return new MemberArrayList.PositionList(); 566 } 567 /** 568 * Each Position has an array of Member. 569 */ 570 class PositionList extends PositionListBase { 571 PositionList() { 572 } 573 public int size() { 574 return list.size(); 575 } 576 public Position get(int index) { 577 if (index >= list.size()) { 578 throw new IndexOutOfBoundsException(); 579 } 580 return new MemberArrayList.MALPosition(index); 581 } 582 } 583 /** 584 * Allows access only the the Member at the given offset plus index. 585 */ 586 class MALPosition extends PositionBase { 587 protected final int offset; 588 MALPosition(int offset) { 589 this.offset = offset; 590 } 591 public int size() { 592 return RolapAxis.MemberArrayList.this.len; 593 } 594 public Member get(int index) { 595 if (index > RolapAxis.MemberArrayList.this.len) { 596 throw new IndexOutOfBoundsException( 597 "Index: " + 598 index + 599 ", Size: " + 600 RolapAxis.MemberArrayList.this.len); 601 } 602 return list.get(offset)[index]; 603 } 604 } 605 } 606 607 /** 608 * A List<Member> for which all methods throw the 609 * UnsupportedOperationException exception when invoked. Derived classes 610 * can implement those methods that they require. 611 */ 612 protected static abstract class PositionUnsupported 613 extends UnsupportedList<Member> 614 implements Position { 615 protected PositionUnsupported() { 616 } 617 } 618 /** 619 * The PositionBase is an abstract implementation of the Position 620 * interface and provides both Iterator<Member> and 621 * ListIterator<Member> implementations. 622 */ 623 protected static abstract class PositionBase extends PositionUnsupported { 624 protected PositionBase() { 625 } 626 public ListIterator<Member> listIterator() { 627 return new ListItr(0); 628 } 629 public ListIterator<Member> listIterator(int index) { 630 return new ListItr(index); 631 } 632 public Iterator<Member> iterator() { 633 return new Itr(); 634 } 635 } 636 637 protected static abstract class PositionListUnsupported 638 extends UnsupportedList<Position> { 639 protected PositionListUnsupported() { 640 } 641 } 642 643 protected static abstract class PositionIterBase 644 extends PositionListUnsupported { 645 protected PositionIterBase() { 646 super(); 647 } 648 public abstract Iterator<Position> iterator(); 649 } 650 651 /** 652 * The PositionListBase is an abstract implementation of the 653 * List<Position> 654 * interface and provides both Iterator<Position> and 655 * ListIterator<Position> implementations. 656 */ 657 protected static abstract class PositionListBase 658 extends PositionListUnsupported { 659 protected PositionListBase() { 660 super(); 661 } 662 public abstract int size(); 663 public abstract Position get(int index); 664 665 // Collection 666 public boolean isEmpty() { 667 return (size() == 0); 668 } 669 public ListIterator<Position> listIterator() { 670 return new ListItr(0); 671 } 672 public ListIterator<Position> listIterator(int index) { 673 return new ListItr(index); 674 } 675 public Iterator<Position> iterator() { 676 return new Itr(); 677 } 678 } 679 680 protected RolapAxis() { 681 } 682 public abstract List<Position> getPositions(); 683 } 684 // End RolapAxis.java