KickJava   Java API By Example, From Geeks To Geeks.

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


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
14 package com.tonbeller.jpivot.olap.query;
15
16 import java.util.ArrayList JavaDoc;
17 import java.util.Iterator JavaDoc;
18 import java.util.List JavaDoc;
19
20 import org.apache.log4j.Logger;
21
22 import com.tonbeller.jpivot.core.Extension;
23 import com.tonbeller.jpivot.core.ModelSupport;
24 import com.tonbeller.jpivot.olap.model.Axis;
25 import com.tonbeller.jpivot.olap.model.Dimension;
26 import com.tonbeller.jpivot.olap.model.Hierarchy;
27 import com.tonbeller.jpivot.olap.model.Member;
28 import com.tonbeller.jpivot.olap.model.Position;
29 import com.tonbeller.jpivot.olap.model.Result;
30 import com.tonbeller.jpivot.olap.navi.CalcSet;
31 import com.tonbeller.jpivot.olap.navi.SortRank;
32
33 /**
34  * Adapt the MDX query to the model
35  */

36 public abstract class QueryAdapter {
37
38   static Logger logger = Logger.getLogger(QueryAdapter.class);
39
40   protected ModelSupport model;
41
42   protected Quax[] quaxes; // Array of query axis state object
43
protected boolean useQuax = false;
44   protected boolean axesSwapped = false;
45   protected boolean genMDXHierarchize = false;
46   protected SortRankBase sortMan = null;
47
48   /**
49    * c'tor
50    * @param model
51    */

52   protected QueryAdapter(ModelSupport model) {
53     this.model = model;
54     Extension sortExt = model.getExtension(SortRank.ID);
55     if (sortExt != null) {
56       sortMan = (SortRankBase) sortExt;
57     }
58     axesSwapped = false;
59   }
60
61   /**
62    * @return
63    */

64   public Quax[] getQuaxes() {
65     return quaxes;
66   }
67
68   /**
69    * @param quaxs
70    */

71   public void setQuaxes(Quax[] quaxes) {
72     this.quaxes = quaxes;
73   }
74
75   /**
76     * find the Quax for a specific dimension
77     * @param dim Dimension
78     * @return Quax containg dimension
79     */

80   public Quax findQuax(Dimension dim) {
81     for (int i = 0; i < quaxes.length; i++) {
82       if (quaxes[i].dimIdx(dim) >= 0)
83         return quaxes[i];
84     }
85     return null;
86   }
87
88   /**
89    * after the startup query was run:
90    * get the current positions as array of array of member.
91    * Called from Model.getResult after the query was executed.
92    * @param result the result which redefines the query axes
93    */

94   public void afterExecute(Result result) {
95
96     Axis[] axes = result.getAxes();
97
98     // initialization: get the result positions and set it to quax
99
// if the quaxes are not yet used to generate the query
100
if (!useQuax) {
101       AxisLoop : for (int i = 0; i < axes.length; i++) {
102         List JavaDoc positions = axes[i].getPositions();
103         quaxes[iASwap(i)].init(positions);
104       } //AxisLoop
105
} else {
106       // hierarchize result if neccessary
107
int iQuaxToSort = -1;
108       if (sortMan != null)
109         iQuaxToSort = sortMan.activeQuaxToSort();
110       if (!genMDXHierarchize) {
111         // not active currently
112
Hierarchize : for (int i = 0; i < quaxes.length; i++) {
113           if (quaxes[i].isHierarchizeNeeded() && i != iQuaxToSort)
114              ((ResultBase) result).hierarchize(iASwap(i));
115         }
116       }
117
118       QuaxLoop : for (int i = 0; i < quaxes.length; i++) {
119
120         List JavaDoc positions = axes[iASwap(i)].getPositions();
121
122         // after a result for CalcSet.GENERATE was gotten
123
// we have to re-initialize the quax,
124
// so that we can navigate.
125
if (quaxes[i].getGenerateMode() == CalcSet.GENERATE) {
126           quaxes[i].resetGenerate();
127           quaxes[i].init(positions);
128           continue QuaxLoop;
129         }
130
131         // unknown function members are collected
132
// - always for a "STICKY generate" unknown function
133
// - on first result for any other unknown function
134
int nDimension = quaxes[i].getNDimension();
135         for (int j = 0; j < nDimension; j++) {
136           // collect members for unknown functions on quax
137
if (quaxes[i].isUnknownFunction(j)) {
138             List JavaDoc memList = memListForHier(j, positions);
139             quaxes[i].setHierMemberList(j, memList);
140           }
141         } // for dimensions of quax
142
} // QuaxLoop
143
}
144
145     if (logger.isDebugEnabled()) {
146       // print the result positions to logger
147
AxisLoop : for (int i = 0; i < axes.length; i++) {
148         List JavaDoc positions = axes[i].getPositions();
149         logger.debug("Positions of axis " + i);
150
151         if (positions.size() == 0) {
152           // the axis does not have any positions
153
logger.debug("0 positions");
154         } else {
155           int nDimension = ((Position) positions.get(0)).getMembers().length;
156           PositionLoop : for (Iterator JavaDoc iter = positions.iterator(); iter.hasNext();) {
157             Position pos = (Position) iter.next();
158             Member[] mems = pos.getMembers();
159             StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
160             for (int j = 0; j < nDimension; j++) {
161               if (j > 0)
162                 sb.append(" * ");
163               Member[] memsj = new Member[j + 1];
164               for (int k = 0; k <= j; k++)
165                 memsj[k] = mems[k];
166               if (this.canExpand(memsj))
167                 sb.append("(+)");
168               else if (this.canCollapse(memsj))
169                 sb.append("(-)");
170               else
171                 sb.append(" ");
172               sb.append(((MDXElement) mems[j]).getUniqueName());
173             }
174             logger.debug(sb.toString());
175           } //PositionLoop
176
}
177
178       } //AxisLoop
179
}
180   }
181
182   /**
183    * extract members of hier from Result
184    * @param hierIndex
185    * @return members of hier
186    */

187   private List JavaDoc memListForHier(int hierIndex, List JavaDoc positions) {
188     List JavaDoc memList = new ArrayList JavaDoc();
189     PositionLoop : for (Iterator JavaDoc iter = positions.iterator(); iter.hasNext();) {
190       Position pos = (Position) iter.next();
191       Member m = pos.getMembers()[hierIndex];
192       if (!memList.contains(m))
193         memList.add(m);
194     }
195     return memList;
196   }
197
198   /**
199    * create set expression for list of members
200    * @param memList
201    * @return set expression
202    */

203   protected abstract Object JavaDoc createMemberSet(List JavaDoc memList);
204
205   // ***************
206
// Expand Collapse
207
// ***************
208

209   /**
210     * find out, whether a member can be expanded.
211     * this is true, if
212     * - the member is on an axis and
213     * - the member is not yet expanded and
214     * - the member has children
215     * @see com.tonbeller.jpivot.olap.navi.DrillExpand#canExpand(Member)
216     * @param Member to be expanded
217     * @return true if the member can be expanded
218     */

219   public abstract boolean canExpand(Member member);
220
221   /**
222     * @see com.tonbeller.jpivot.olap.navi.DrillExpand#canExpand(Member)
223     * @param position position to be expanded
224     * @param Member to be expanded
225     * @return true if the member can be expanded
226     */

227   public abstract boolean canExpand(Member[] pathMembers);
228
229   /**
230    * @see com.tonbeller.jpivot.olap.navi.DrillExpand#canExpand(Member)
231    * @param Member to be collapsed
232    * @return true if the member can be collapsed
233    */

234   public abstract boolean canCollapse(Member member);
235
236   /**
237    * @see com.tonbeller.jpivot.olap.navi.DrillExpand#canCollapse(Member)
238    * @param position position to be expanded
239    * @return true if the position can be collapsed
240    */

241   public abstract boolean canCollapse(Member[] pathMembers);
242
243   /**
244    * expand a member in all positions
245    * this is done by applying ToggleDrillState to the Query
246    *
247    * @see com.tonbeller.jpivot.olap.navi.DrillExpand#expand(Member)
248    * @param Member member to be expanded
249    */

250   public void expand(Member member) {
251     Dimension dim = member.getLevel().getHierarchy().getDimension();
252     Quax quax = findQuax(dim);
253     if (logger.isInfoEnabled())
254       logger.info("expand Member" + poString(null, member));
255     if ((quax == null) || !quax.canExpand(member)) {
256       logger.fatal("Expand Member failed for" + ((MDXElement) member).getUniqueName());
257       //throw new java.lang.IllegalArgumentException("cannot expand");
258
return;
259     }
260     quax.expand(member);
261     model.fireModelChanged();
262   }
263
264   /**
265    * expand a member in a specific position
266    *
267    * @see com.tonbeller.jpivot.olap.navi.DrillExpand#expand(Member)
268    * @param position position to be expanded
269    * @param Member member to be expanded
270    */

271   public void expand(Member[] pathMembers) {
272     Member member = pathMembers[pathMembers.length - 1];
273     Dimension dim = member.getLevel().getHierarchy().getDimension();
274     Quax quax = findQuax(dim);
275
276     if (logger.isDebugEnabled())
277       logger.info("expand Path" + poString(pathMembers, null));
278     if ((quax == null) || !quax.canExpand(pathMembers)) {
279       logger.fatal("Expand failed for" + poString(pathMembers, null));
280       throw new java.lang.IllegalArgumentException JavaDoc("cannot expand");
281     }
282
283     quax.expand(pathMembers);
284     model.fireModelChanged();
285   }
286
287   /**
288    * collapse a member in all positions
289    *
290    * @see com.tonbeller.jpivot.olap.navi.DrillExpand#expand(Member)
291    * @param Member member to be collapsed
292    */

293   public void collapse(Member member) {
294     Dimension dim = member.getLevel().getHierarchy().getDimension();
295
296     if (logger.isInfoEnabled()) {
297       logger.info("collapse " + ((MDXElement) member).getUniqueName());
298     }
299     Quax quax = findQuax(dim);
300     if (quax == null) {
301       logger.info("collapse Quax was null " + ((MDXElement) member).getUniqueName());
302       return;
303     }
304     quax.collapse(member);
305
306     model.fireModelChanged();
307   }
308
309   /**
310     * collapse a member in a specific position
311     *
312     * @see com.tonbeller.jpivot.olap.navi.DrillExpand#expand(Member)
313     * @param position position to be collapsed
314     */

315   public void collapse(Member[] pathMembers) {
316
317     if (logger.isDebugEnabled()) {
318       logger.debug("collapse" + poString(pathMembers, null));
319     }
320
321     Member member = pathMembers[pathMembers.length - 1];
322     Dimension dim = member.getLevel().getHierarchy().getDimension();
323     Quax quax = findQuax(dim);
324     if (quax == null) {
325       logger.debug("collapse Quax was null" + poString(pathMembers, null));
326       return;
327     }
328
329     quax.collapse(pathMembers);
330     model.fireModelChanged();
331   }
332
333   // ************
334
// DrillReplace
335
// ************
336

337   /**
338    * drill down is possible if <code>member</code> has children
339    */

340   public abstract boolean canDrillDown(Member member);
341
342   /**
343    * drill up is possible if
344    * at least one member in the tree is not at the top level of this hierarchy.
345    */

346   public boolean canDrillUp(Hierarchy hier) {
347
348     Quax quax = findQuax(hier.getDimension());
349     return (quax == null) ? false : quax.canDrillUp(hier);
350   }
351
352   /**
353    * After switch to Qubon mode:
354    * replaces the members. Let <code>H</code> be the hierarchy
355    * that member belongs to. Then drillDown will replace all members from <code>H</code>
356    * that are currently visible with the children of <code>member</code>.
357    */

358   public void drillDown(Member member) {
359
360     // switch to Qubon mode, if not yet in
361
Quax quax = findQuax(member.getLevel().getHierarchy().getDimension());
362
363     if (quax == null) {
364         logger.info("drillDown Quax was null" + poString(null, member));
365         return;
366     }
367
368     // replace dimension iDim by monMember.children
369
quax.drillDown(member);
370
371     model.fireModelChanged();
372
373     if (logger.isInfoEnabled()) {
374       logger.info("drillDown " + poString(null, member));
375     }
376   }
377
378   /**
379    * After switch to Qubon mode:
380    * replaces all visible members of hier with the members of the
381    * next higher level.
382    */

383   public void drillUp(Hierarchy hier) {
384
385     // switch to Qubon mode, if not yet in
386
Quax quax = findQuax(hier.getDimension());
387     if (quax == null) {
388         logger.info("drillUp Hierarchy Quax was null" + hier.getLabel());
389         return;
390     }
391     quax.drillUp(hier);
392
393     model.fireModelChanged();
394
395     if (logger.isInfoEnabled())
396       logger.info("drillUp Hierarchy " + hier.getLabel());
397   }
398
399   // ********
400
// misc
401
// ********
402

403   /**
404    * @return true, if axes are currently swapped
405    */

406   public boolean isSwapAxes() {
407     return axesSwapped;
408   }
409
410   /**
411    * swap axis index if neccessary
412    * @param original index
413    * @return swapped index
414    */

415   public int iASwap(int i) {
416     if (axesSwapped)
417       return (i + 1) % 2;
418     else
419       return i;
420   }
421
422   /**
423    * check, whether a parent.children Funcall is on any axis
424    */

425   /*
426   public boolean isChildrenOnAxis(Member parent) {
427     Quax quax = findQuax(parent.getLevel().getHierarchy().getDimension());
428     return quax.isChildrenOnAxis(parent);
429   }
430   */

431
432   // ********
433
// Internal
434
// ********
435

436   /**
437    * display position member for debugging purposes
438    * @param posMembers
439    * @param member
440    * @return
441    */

442   protected String JavaDoc poString(Member[] posMembers, Member member) {
443     StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
444     if (posMembers != null) {
445       sb.append(" Position=");
446       for (int i = 0; i < posMembers.length; i++) {
447         if (i > 0)
448           sb.append(" ");
449         sb.append(((MDXElement) posMembers[i]).getUniqueName());
450       }
451     }
452     if (member != null) {
453       sb.append(" Member=");
454       sb.append(((MDXElement) member).getUniqueName());
455     }
456     return sb.toString();
457   }
458
459
460   /**
461    * @return true if quas is to be used
462    */

463   public boolean isUseQuax() {
464     return useQuax;
465   }
466
467   /**
468    * @param b - true if quas is to be used
469    */

470   public void setUseQuax(boolean b) {
471     useQuax = b;
472   }
473
474   // ********
475
// Interface QueryAdapterHolder
476
// ********
477

478   /**
479    * ask a QueryAdapterHolder to get a query adapter
480    */

481   public interface QueryAdapterHolder {
482     QueryAdapter getQueryAdapter();
483   }
484
485 } //QueryAdapter
486
Popular Tags