KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tonbeller > jpivot > olap > query > ResultBase


1 /*
2  * ====================================================================
3  * This software is subject to the terms of the Common Public License
4  * Agreement, available at the following URL:
5  * http://www.opensource.org/licenses/cpl.html .
6  * Copyright (C) 2003-2004 TONBELLER AG.
7  * All Rights Reserved.
8  * You must accept the terms of that agreement to use this software.
9  * ====================================================================
10  *
11  *
12  */

13 package com.tonbeller.jpivot.olap.query;
14
15 import java.io.BufferedWriter JavaDoc;
16 import java.io.FileWriter JavaDoc;
17 import java.io.IOException JavaDoc;
18 import java.io.PrintWriter JavaDoc;
19 import java.util.ArrayList JavaDoc;
20 import java.util.Collections JavaDoc;
21 import java.util.Comparator JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.ListIterator JavaDoc;
26 import java.util.Map JavaDoc;
27
28 import com.tonbeller.jpivot.core.Model;
29 import com.tonbeller.jpivot.olap.model.Axis;
30 import com.tonbeller.jpivot.olap.model.Cell;
31 import com.tonbeller.jpivot.olap.model.Member;
32 import com.tonbeller.jpivot.olap.model.Position;
33 import com.tonbeller.jpivot.olap.model.Result;
34 import com.tonbeller.jpivot.olap.model.Visitor;
35 import com.tonbeller.jpivot.util.CubeIndexIterator;
36
37 /**
38  * base class for both Mondrian and XMLA result
39  */

40 public abstract class ResultBase implements Result {
41
42   private static String JavaDoc[] specialProps = { "arrow"};
43
44   protected List JavaDoc axesList;
45
46   protected List JavaDoc aCells;
47
48   protected Axis slicer;
49
50   protected Model model;
51
52   boolean overflow = false;
53
54   // c'tor
55
public ResultBase(Model model) {
56     aCells = new ArrayList JavaDoc();
57     axesList = new ArrayList JavaDoc();
58     this.model = model;
59   }
60
61   /**
62    * After the result was gotten, handle special measures, which are
63    * "invisible". Their meaning is a property for "another" cell, eg.
64    * [Measures].[Unit Sales_arrow] is the "arrow" property for
65    * [Measures].[Unit Sales]
66    */

67   void processSpecialProps() {
68   }
69
70   /**
71    * @see com.tonbeller.jpivot.olap.model.Result#getAxes()
72    */

73   public abstract Axis[] getAxes();
74
75   /**
76    * Returns the slicer.
77    *
78    * @return Slicer Axis
79    * @see com.tonbeller.jpivot.olap.model.Result#getSlicer()
80    */

81   public Axis getSlicer() {
82     return slicer;
83   }
84
85   /**
86    * Returns the cells.
87    *
88    * @return List of cells
89    * @see com.tonbeller.jpivot.olap.model.Result#getCells()
90    */

91   public List JavaDoc getCells() {
92     return aCells;
93   }
94
95   /**
96    * perform hierarchize not resorting siblings under parent
97    *
98    * this method is not fully tested we cannot use Result hierarchize, because
99    * by Quax navigation the prerequisits are not given Example (Customers
100    * Products): if by Quax navigation (CA, Drink) USA.children is split into
101    * {OR, WA) * Drink {CA} * { Drink + Drink.Children) CA would then come
102    * later in the result. Therefore : MDX hierarchize is needed
103    */

104   public void hierarchize(int iAxis) {
105     List JavaDoc posList = ((Axis) axesList.get(iAxis)).getPositions();
106     int nDim = axesList.size();
107     int indexForAxis = nDim - 1 - iAxis;
108     int[] ni = new int[nDim];
109     int[] iFull = new int[nDim];
110     for (int i = 0; i < nDim; i++) {
111       ni[i] = ((Axis) axesList.get(i)).getPositions().size() - 1;
112     }
113     int[] iSlice = new int[nDim - 1];
114     CubeIndexIterator cubit = null;
115     if (nDim > 1) {
116       full2slice(ni, iSlice, iAxis);
117       cubit = new CubeIndexIterator(iSlice, false);
118     }
119
120     // assign the cells
121
// c00 c01 c02 ... c0n
122
// c10 c11 c12 ... c1n
123
// ...
124
// cm0 cm1 cm2 ... cmn
125
// cell ordinal of cell [i,k] = c[i*(n+1) +k]
126
// n+1 = position size of axis 0 (columns)
127
// m+1 = position size of axis 1 (rows)
128
// iAxis=0 position=0 : c00, c10, ... cm0
129
// iAxis=0 position=1 : c01, c11, ... cm1
130
// iAxis=1 position=0 : c00, c01, ... c0n
131
// iAxis=1 position=1 : c10, c11, ... c1n
132

133     // for each position of iAxis we will get the slice
134
// of cells for the "other" axes
135

136     int iPos = 0;
137     int nDimension = 0;
138     for (Iterator JavaDoc iter = posList.iterator(); iter.hasNext(); iPos++) {
139       PositionBase pos = (PositionBase) iter.next();
140       if (nDimension == 0)
141         nDimension = pos.getMembers().length;
142       pos.number = iPos;
143       if (pos.cellList == null)
144         pos.cellList = new ArrayList JavaDoc();
145       else
146         pos.cellList.clear();
147       if (nDim > 1) {
148         cubit.reset();
149         while (true) {
150           int[] iCurrent = cubit.next();
151           if (iCurrent == null)
152             break;
153           slice2full(iCurrent, iFull, indexForAxis, iPos);
154           int ii = lindex(iFull, ni);
155           pos.cellList.add(aCells.get(ii));
156         }
157       } else {
158         // nDim <= 1
159
pos.cellList.add(aCells.get(iPos));
160       }
161     }
162
163     // sort
164
posList = sortPosList(posList, 0, nDim);
165
166     // rewrite cell list
167
int nc = aCells.size();
168     aCells.clear();
169     for (int i = 0; i < nc; i++)
170       aCells.add(null);
171     iPos = 0;
172     for (Iterator JavaDoc iter = posList.iterator(); iter.hasNext(); iPos++) {
173       PositionBase posBase = (PositionBase) iter.next();
174       if (nDim > 1) {
175         cubit.reset();
176         for (Iterator JavaDoc iterator = posBase.cellList.iterator(); iterator.hasNext();) {
177           Object JavaDoc cellObj = iterator.next();
178           int[] iCurrent = cubit.next();
179           if (iCurrent == null)
180             break;
181           slice2full(iCurrent, iFull, indexForAxis, iPos);
182           int ii = lindex(iFull, ni);
183           aCells.set(ii, cellObj);
184         }
185       } else {
186         // nDim <= 1
187
Object JavaDoc cellObj = posBase.cellList.get(0);
188         aCells.set(iPos, cellObj);
189       }
190       posBase.cellList.clear();
191     }
192
193   }
194
195   /**
196    *
197    * @param posList
198    * @param iDim
199    * @param nDim
200    * @return
201    */

202   private List JavaDoc sortPosList(List JavaDoc posList, final int iDim, int nDim) {
203
204     printPosList(posList, new PrintWriter JavaDoc(System.out), "Start sortPosList " + iDim);
205
206     if (posList.size() < 2)
207       return posList;
208
209     // collect members and assign first occurrence prio
210
final Map JavaDoc firstOcc = new HashMap JavaDoc();
211     int k = 0;
212     for (Iterator JavaDoc iter = posList.iterator(); iter.hasNext(); k++) {
213       PositionBase posb = (PositionBase) iter.next();
214       posb.parent = null;
215       Member m = posb.getMembers()[iDim];
216       if (!firstOcc.containsKey(m))
217         firstOcc.put(m, new Integer JavaDoc(k));
218     }
219
220     // first step
221
// sort by level and original position to assure
222
// that any child follows its parent
223
Collections.sort(posList, new Comparator JavaDoc() {
224       public int compare(Object JavaDoc o1, Object JavaDoc o2) {
225         // compare two positions
226
Position pos1 = (Position) o1;
227         Position pos2 = (Position) o2;
228         Member a1 = pos1.getMembers()[iDim];
229         Member a2 = pos2.getMembers()[iDim];
230
231         // if it is on different level, the descendant is higher
232
// otherwise - decide by original index
233
int level1 = ((MDXLevel) a1.getLevel()).getDepth();
234         int level2 = ((MDXLevel) a2.getLevel()).getDepth();
235         if (level1 == level2) {
236           return ((PositionBase) pos1).number - ((PositionBase) pos2).number;
237         } else {
238           return level1 - level2;
239         }
240       }
241     });
242
243     // second step
244
// establish parent child dependencies
245
int i = 0;
246     Outerloop: for (Iterator JavaDoc iter = posList.iterator(); iter.hasNext(); i++) {
247       PositionBase posb = (PositionBase) iter.next();
248       if (!iter.hasNext())
249         break;
250       MDXMember m = (MDXMember) posb.getMembers()[iDim];
251       int iLevel = ((MDXLevel) m.getLevel()).getDepth();
252       ListIterator JavaDoc lit = posList.listIterator(i + 1);
253       InnerLoop: while (lit.hasNext()) {
254         PositionBase posb2 = (PositionBase) lit.next();
255         if (posb2.parent != null)
256           continue;
257         MDXMember m2 = (MDXMember) posb2.getMembers()[iDim];
258         int iLevel2 = ((MDXLevel) m2.getLevel()).getDepth();
259         if (iLevel2 <= iLevel)
260           continue InnerLoop;
261         if (iLevel2 > iLevel + 1)
262           break InnerLoop;
263         // here iLevel2 = iLevel +1
264
if (m.getUniqueName().equals(m2.getParentUniqueName()))
265           posb2.parent = posb;
266       }
267     }
268
269     // third step
270
// sort by hierarchy and member first ocurrence
271
Collections.sort(posList, new Comparator JavaDoc() {
272       public int compare(Object JavaDoc o1, Object JavaDoc o2) {
273         // compare two positions
274
PositionBase pos1 = (PositionBase) o1;
275         PositionBase pos2 = (PositionBase) o2;
276         Member a1 = pos1.getMembers()[iDim];
277         Member a2 = pos2.getMembers()[iDim];
278         if (a1.equals(a2)) { return pos1.number - pos2.number; }
279
280         // if a1 and a2 are descendant, the descendant is higher
281
int level1 = ((MDXLevel) a1.getLevel()).getDepth();
282         int level2 = ((MDXLevel) a2.getLevel()).getDepth();
283         PositionBase par1 = null;
284         PositionBase par2 = null;
285         PositionBase parb = null;
286         if (level1 < level2) {
287           // a2 is possibly descendant of a1
288
parb = pos2;
289           for (int j = 0; j < level2 - level1; j++) {
290             if (parb != null)
291               parb = parb.parent;
292           }
293           if (parb != null) {
294             Member ab = parb.getMembers()[iDim];
295             if (ab.equals(a1))
296               return -1; // a2 is descendant of a1, a2 is higher
297
}
298           par1 = pos1;
299           par2 = parb;
300         } else if (level1 > level2) {
301           // a1 is possibly descendant of a2
302
parb = pos1;
303           for (int j = 0; j < level1 - level2; j++) {
304             if (parb != null)
305               parb = parb.parent;
306           }
307           if (parb != null) {
308             Member ab = parb.getMembers()[iDim];
309             if (ab.equals(a2))
310               return 1; // a1 is descendant of a2, a1 is higher
311
}
312           par1 = parb;
313           par2 = pos2;
314
315         } else {
316           // level1 = level2
317
par1 = pos1;
318           par2 = pos2;
319         }
320         // pos1 and pos2 are on equal level
321
if (par1 == null || par2 == null)
322           return pos1.number - pos2.number; // should not occur
323
// go up until we come to a common ancestor or null
324
Member apar1 = par1.getMembers()[iDim];
325         Member apar2 = par2.getMembers()[iDim];
326         PositionBase p1 = par1.parent;
327         PositionBase p2 = par2.parent;
328         while (p1 != null && p2 != null) {
329           Member ap1 = p1.getMembers()[iDim];
330           Member ap2 = p2.getMembers()[iDim];
331           if (ap1.equals(ap2))
332             break;
333           par1 = p1;
334           par2 = p2;
335           p1 = par1.parent;
336           p2 = par2.parent;
337           if (p1 == null || p2 == null)
338             break;
339           apar1 = ap1;
340           apar2 = ap2;
341         }
342
343         int retcode = ((Integer JavaDoc) firstOcc.get(apar1)).intValue()
344             - ((Integer JavaDoc) firstOcc.get(apar2)).intValue();
345
346         return retcode;
347       }
348     });
349
350     printPosList(posList, new PrintWriter JavaDoc(System.out), "Step 3 sortPosList " + iDim);
351
352     // last step
353
// sort sublists next hierarchy
354
if (iDim == nDim - 1)
355       return posList;
356     List JavaDoc newPosList = new ArrayList JavaDoc();
357     List JavaDoc subList = new ArrayList JavaDoc();
358     Member first = null;
359     for (Iterator JavaDoc iter = posList.iterator(); iter.hasNext();) {
360       PositionBase pb = (PositionBase) iter.next();
361       if (first == null) {
362         first = pb.getMembers()[iDim];
363         subList.add(pb);
364       } else {
365         Member current = pb.getMembers()[iDim];
366         if (current.equals(first)) {
367           subList.add(pb);
368         } else {
369           subList = sortPosList(subList, iDim + 1, nDim);
370           newPosList.addAll(subList);
371           subList.clear();
372           first = current;
373           subList.add(pb);
374         }
375       }
376     }
377     if (subList.size() > 1) {
378       subList = sortPosList(subList, iDim + 1, nDim);
379     }
380     newPosList.addAll(subList);
381
382     printPosList(newPosList, new PrintWriter JavaDoc(System.out), "End sortPosList " + iDim);
383
384     return newPosList;
385   }
386
387   /**
388    * print position list for debugging
389    */

390   private void printPosList(List JavaDoc posList, PrintWriter JavaDoc wout, String JavaDoc label) {
391     wout.println(label);
392     int n = 0;
393     for (Iterator JavaDoc iter = posList.iterator(); iter.hasNext(); n++) {
394       PositionBase pb = (PositionBase) iter.next();
395       Member[] members = pb.getMembers();
396       StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
397       for (int i = 0; i < members.length; i++) {
398         if (i == 0) {
399           sb.append(n);
400           sb.append(" ");
401           sb.append(pb.number);
402           sb.append(" ");
403         } else {
404           sb.append(" * ");
405         }
406
407         sb.append(members[i].getLabel());
408       }
409       wout.println(sb.toString());
410     }
411     wout.flush();
412   }
413
414   /**
415    * @param iFull
416    * full index array
417    * @param iSlice
418    * slice index array
419    * @param iAxis -
420    * index beeing omitted
421    */

422   private void full2slice(int[] iFull, int[] iSlice, int iAxis) {
423     if (iSlice.length == 0)
424       return; // 1-dimensional
425
int j = 0;
426     for (int i = 0; i < iFull.length; i++) {
427       if (i != iAxis)
428         iSlice[j++] = iFull[i];
429     }
430   }
431
432   /**
433    * @param iFull
434    * full index array
435    * @param iSlice
436    * slice index array
437    * @param iAxis -
438    * index beeing omitted
439    */

440   private void slice2full(int[] iSlice, int[] iFull, int iAxis, int iAxisVal) {
441     if (iSlice.length == 0) {
442       iFull[0] = iAxisVal;
443       return;
444     }
445
446     int j = 0;
447     for (int i = 0; i < iFull.length; i++) {
448       if (i != iAxis)
449         iFull[i] = iSlice[j++];
450       else
451         iFull[i] = iAxisVal;
452     }
453   }
454
455   /**
456    * linear index from index array
457    *
458    * @param iar
459    * @return
460    */

461   private int lindex(int[] iar, int[] ni) {
462
463     // 3 dim sample
464
// c000 c001 ... c00n ck00 ck01 ... ck01
465
// c010 c011 ... c01n ---> ck10 ck11 ... ck1n
466
// ...
467
// c0m1 c0m2 ... c0mn ckm1 ckm2 ckmn
468

469     /* kk*(n+1)*(m+1) + mm*(n+1) +nn */
470
471     int k = iar[0];
472     for (int j = 1; j < iar.length; j++)
473       k = k * (ni[j - 1] + 1) + iar[j];
474
475     return k;
476   }
477
478   /**
479    * @see com.tonbeller.jpivot.olap.model.Decorator#getRootDecoree()
480    */

481   public Object JavaDoc getRootDecoree() {
482     return this;
483   }
484
485   /**
486    * @see com.tonbeller.jpivot.olap.model.Visitable#accept
487    */

488
489   public void accept(Visitor visitor) {
490     visitor.visitResult(this);
491   }
492
493   /**
494    * Render Test Output to HTML
495    */

496   public static void renderHtml(Result result, String JavaDoc mdx, String JavaDoc outfile) throws IOException JavaDoc {
497     int i;
498
499     PrintWriter JavaDoc wout = new PrintWriter JavaDoc(new BufferedWriter JavaDoc(new FileWriter JavaDoc(outfile)));
500
501     Axis[] axes = result.getAxes();
502
503     wout.println("<HTML>");
504     wout.println("<HEAD>");
505     wout.println("<META HTTP-EQUIV=\"Content-Type\" CONTENT=\"text/html; charset=iso-8859-1\">");
506     wout.println("<TITLE>Result from MDX Query</TITLE>");
507     wout.println("</HEAD>");
508     wout.println("<BODY>");
509
510     wout.println("<h1>MDX Query Result</h1>");
511
512     //String mdx = ((MdxOlapModel) model).getCurrentMdx();
513
if (mdx != null ) {
514       wout.println("<p>");
515       wout.println(mdx);
516       wout.println("</p>");
517     }
518     wout.println("<table border=\"3\">");
519     wout.println("<thead><tr>");
520
521     if (axes.length == 0) {
522       // result is 0 dimensional
523
wout.println("<th>Slicer</th><th>Result</th>");
524       wout.println("</thead><tbody><tr>");
525
526       // slicer members as row header
527
renderSlicerRowHeader(result.getSlicer(), wout);
528
529       Cell cell = (Cell) result.getCells().get(0);
530       String JavaDoc value = cell.getFormattedValue();
531       wout.println("<td>" + value + "</td>");
532       wout.println("</tr>");
533     } else if (axes.length == 1) {
534       // result is 1 dimensional
535
// print position of axis 0 as column headers
536
renderColHeaders(wout, axes[0]);
537       wout.println("</tr></thead>");
538
539       wout.println("<tbody><tr>");
540       // slicer members as row header
541
renderSlicerRowHeader(result.getSlicer(), wout);
542
543       int n = 0;
544       for (i = 0; i < axes[0].getPositions().size(); i++) {
545         Cell cell = (Cell) result.getCells().get(n++);
546         String JavaDoc value = cell.getFormattedValue();
547         wout.println("<td>" + value + "</td>");
548       }
549       wout.println("</tr>");
550     } else if( axes.length == 2 ) {
551       // assume 2 dimensional
552
// print position of axis 0 as column headers
553
renderColHeaders(wout, axes[0]);
554
555       wout.println("</tr></thead>");
556
557       // print rows, each one starting with row headers
558
wout.println("<tbody>");
559       Position[] positions = (Position[]) axes[1].getPositions().toArray(new Position[0]);
560       int n = 0;
561       for (i = 0; i < positions.length; i++) {
562         wout.println("<tr>");
563         Member[] members = positions[i].getMembers();
564
565         String JavaDoc caption = "";
566         for (int j = 0; j < members.length; j++) {
567           if (j > 0)
568             caption = caption + "<br>" + members[j].getLabel();
569           else
570             caption = members[j].getLabel();
571         }
572         wout.println("<th>" + caption + "</th>");
573         for (int j = 0; j < axes[0].getPositions().size(); j++) {
574           Cell cell = (Cell) result.getCells().get(n++);
575           String JavaDoc value = cell.getFormattedValue();
576           wout.println("<td>" + value + "</td>");
577         }
578         wout.println("</tr>");
579       }
580     } else {
581       // cannot handle more than 2 axes
582
throw new IllegalArgumentException JavaDoc("ResultBase.renderHtml cannot handle more than 2 axes");
583     }
584
585     wout.println("</tbody>");
586
587     wout.println("</BODY></HTML>");
588     wout.close();
589   }
590
591   /**
592    * print column headers from axis
593    */

594   private static void renderColHeaders(PrintWriter JavaDoc wout, Axis axis) {
595     // print position of axis as column headers
596
wout.println("<th></th>");
597     Position[] positions = (Position[]) axis.getPositions().toArray(new Position[0]);
598     for (int i = 0; i < positions.length; i++) {
599       Member[] members = positions[i].getMembers();
600
601       String JavaDoc caption = "";
602       for (int j = 0; j < members.length; j++) {
603         if (j > 0)
604           caption = caption + "<br>" + members[j].getLabel();
605         else
606           caption = members[j].getLabel();
607       }
608       wout.println("<th>" + caption + "</th>");
609     }
610   }
611
612   /**
613    * print row header from slicer axis
614    */

615   private static void renderSlicerRowHeader(Axis slicerax, PrintWriter JavaDoc wout) {
616     Position[] positions = (Position[]) slicerax.getPositions().toArray(new Position[0]);
617     String JavaDoc caption = "";
618     for (int i = 0; i < positions.length; i++) {
619       Member[] members = positions[i].getMembers();
620       for (int j = 0; j < members.length; j++) {
621         if (j == 0 && i == 0)
622           caption = members[j].getLabel();
623         else
624           caption = caption + "<br>" + members[j].getLabel();
625       }
626     }
627     wout.println("<th>" + caption + "</th>");
628   }
629
630   /**
631    * print Result to print stream
632    *
633    * @param ps
634    * Output Print Stream
635    */

636   public void printOut(java.io.PrintStream JavaDoc ps) {
637     Axis[] axes = this.getAxes();
638     for (int i = 0; i < axes.length; i++) {
639       Axis a = axes[i];
640       ps.println("Axis " + i);
641       printAxis(ps, a);
642     }
643
644     Axis slicer = this.getSlicer();
645     ps.println("Slicer Axis ");
646     printAxis(ps, slicer);
647
648     Iterator JavaDoc it = aCells.iterator();
649     int ic = 0;
650     while (it.hasNext()) {
651       Cell c = (Cell) it.next();
652       String JavaDoc val = c.getFormattedValue();
653       ps.println("Cell " + ic++ + " Value=" + val);
654     }
655   }
656
657   /**
658    * print axis to standard out
659    */

660   private void printAxis(java.io.PrintStream JavaDoc ps, Axis a) {
661     List JavaDoc positions = a.getPositions();
662     Iterator JavaDoc it = positions.iterator();
663
664     int ip = 0;
665     while (it.hasNext()) {
666       Position p = (Position) it.next();
667       ps.println("Position " + ip++);
668       Member[] members = p.getMembers();
669       for (int j = 0; j < members.length; j++) {
670         Member m = members[j];
671         String JavaDoc mcap = m.getLabel();
672         int idep = m.getRootDistance();
673         ps.println("Member " + mcap + " depth=" + idep);
674       }
675     }
676   }
677
678   /**
679    * @return true, if the result was rolled back due to overflow condition
680    */

681   public boolean isOverflowOccured() {
682     return overflow;
683   }
684   
685   /**
686    * @return true, if the result was rolled back due to overflow condition
687    */

688   public void setOverflowOccured(boolean overflow) {
689     this.overflow = overflow;
690   }
691
692 } // ResultBase
693
Popular Tags