📄 quax.java
字号:
// to the remove list.
int nArgs = uti.funCallArgCount(oExp);
List removeMembers = new ArrayList();
for (int i = 0; i < nArgs; i++) {
Object oSetMember = uti.funCallArg(oExp, i);
if (uti.checkDescendantO(mPath[iDim], oSetMember)) {
removeMembers.add(oSetMember);
}
}
int nRemove = removeMembers.size();
if (nRemove == nArgs) {
// all memers in set are descendants, remove the node
removeList.add(node); // add to delete list
} else if (nRemove > 0) {
// remove descendant nodes from set
Object[] remaining = new Object[nArgs - nRemove];
int j = 0;
for (int i = 0; i < nArgs; i++) {
Object oSetMember = uti.funCallArg(oExp, i);
if (!removeMembers.contains(oSetMember))
remaining[j++] = oSetMember;
}
if (remaining.length == 1) {
node.setReference(remaining[0]); // single
// member
} else {
Object newSet = uti.createFunCall("{}", remaining, QuaxUti.FUNTYPE_BRACES);
node.setReference(newSet);
}
}
} else if (uti.isFunCallTo(oExp, "Union")) {
// HHTASK Cleanup, always use removeDescendantsFromFunCall
Object oRemain = removeDescendantsFromFunCall(oExp, mPath[iDim], iDim);
if (oRemain == null)
removeList.add(node);
else
node.setReference(oRemain);
}
return TreeNodeCallback.CONTINUE_SIBLING;
} else if (uti.isMember(oExp)) {
if (uti.checkDescendantO(mPath[iDim], oExp))
removeList.add(node);
}
return TreeNodeCallback.CONTINUE_SIBLING;
// always break on level iDim, next sibling
} else {
// should never get here
logger.error("unexpected tree node level " + idi + " " + uti.memberString(mPath));
}
return TreeNodeCallback.BREAK;
} // handleTreeNode
});
// remove nodes collected in work list
for (Iterator iter = removeList.iterator(); iter.hasNext();) {
TreeNode nodeToRemove = (TreeNode) iter.next();
removePathToNode(nodeToRemove);
}
// any dimension left and including iDim will *not* be excluded from
// hierarchize
int n = nDimension - iDim - 1;
if (n < nHierExclude)
nHierExclude = n;
if (logger.isDebugEnabled()) {
logger.debug("after collapse " + this.toString());
}
changed(this, false);
} // collapse
/**
* check, whether a member path can be collapsed this is true if there is a child position path
*
* @param pathMembers
* position path to be collapsed
*/
public boolean canCollapse(Member member) {
// we only allow expand / collapse for a dimension
// left of a "sticky topcount"
if (!allowNavigate(member, false))
return false;
// first check the cache
if (canCollapseMemberMap.containsKey(member)) {
Boolean bCanCollapse = (Boolean) canCollapseMemberMap.get(member);
return bCanCollapse.booleanValue();
}
// loop over Position Tree
// can collapse, if we find a descendant of monMember
boolean b = findMemberChild(member);
// cache the result
Boolean bool = new Boolean(b);
canCollapseMemberMap.put(member, bool);
return b;
}
/**
* remove child nodes of monMember
*
* @param monMember
* member to be collapsed
*/
public void collapse(final Member member) {
if (qubonMode) {
resolveUnions();
if (logger.isDebugEnabled()) {
logger.debug("collapse member after resolveUnions " + this.toString());
}
}
final int iDim = this.dimIdx(uti.dimForMember(member));
final List nodesForMember = new ArrayList();
// update the position member tree
// wherever we find a descendant node of monMember, split and remove it
// collect all descendant nodes for monMember in workList
posTreeRoot.walkChildren(new TreeNodeCallback() {
/**
* callback find node matching member Path exactly
*/
public int handleTreeNode(TreeNode node) {
int iDimNode = node.getLevel() - 1;
if (iDimNode < iDim)
return TreeNodeCallback.CONTINUE; // we are below iDim,
// don't care
// iDimNode == iDim
// node Exp must contain children of member[iDim]
Object oExp = node.getReference();
if (uti.isMember(oExp)) {
if (uti.checkDescendantO(member, oExp))
nodesForMember.add(node);
} else {
// must be FunCall
if (isDescendantOfMemberInFunCall(oExp, member, iDimNode))
nodesForMember.add(node);
}
return TreeNodeCallback.CONTINUE_SIBLING; // continue next
// sibling
}
});
for (Iterator iter = nodesForMember.iterator(); iter.hasNext();) {
TreeNode node = (TreeNode) iter.next();
Object oExp = node.getReference();
if (uti.isMember(oExp)) {
removePathToNode(node);
} else {
// FunCall
Object oComplement = removeDescendantsFromFunCall(oExp, member, iDim);
if (oComplement == null)
removePathToNode(node);
else
node.setReference(oComplement); // replace node object by complement
}
}
if (logger.isDebugEnabled()) {
logger.debug("after collapse " + this.toString());
}
changed(this, false);
} // collapse
// ==========
// Drill Down
// ==========
/**
* drill down is possible if there is no sticky generate
*/
public boolean canDrillDown(Member member) {
return allowNavigate(member, true);
}
/**
* drill down
*
* @param monMember
* drill down member
*/
public void drillDown(Member member) {
final int iDim = this.dimIdx(uti.dimForMember(member));
// collect the Exp's of all dimensions except iDim
Object[] sets = new Object[nDimension];
Object oMember = uti.objForMember(member);
Object fChildren = uti.createFunCall("Children", new Object[] { oMember},
QuaxUti.FUNTYPE_PROPERTY);
DimensionLoop: for (int i = 0; i < nDimension; i++) {
if (i == iDim) {
// replace drilldown dimension by member.children
sets[i] = fChildren;
} else {
// generate exp for all nodes of this dimension
sets[i] = genExpForDim(i);
}
} // DimensionLoop
// regenerate the position tree as crossjoin of sets
regeneratePosTree(sets, false);
changed(this, false);
}
// ==========
// Drill Up
// ==========
/**
* drill up is possible if at least one member in the tree is not at the top level of this
* hierarchy.
*/
public boolean canDrillUp(Hierarchy hier) {
final int iDim = this.dimIdx(hier.getDimension());
if (!allowNavigate(iDim, true))
return false;
int ret = posTreeRoot.walkChildren(new TreeNodeCallback() {
/**
* callback check for member of hierarchy not on top level
*/
public int handleTreeNode(TreeNode node) {
int iDimNode = node.getLevel() - 1;
if (iDimNode < iDim)
return TreeNodeCallback.CONTINUE;
// iDimNode == workInt
Object oExp = node.getReference();
if (!uti.isMember(oExp)) {
// FunCall
if (isFunCallNotTopLevel(oExp, iDimNode))
return TreeNodeCallback.BREAK; // got it
else
return TreeNodeCallback.CONTINUE_SIBLING;
} else {
// member
if (uti.levelDepthForMember(oExp) > 0)
return TreeNodeCallback.BREAK; // got it
else
return TreeNodeCallback.CONTINUE_SIBLING;
} // member
} // handlePositionTreeNode
});
return (ret == TreeNodeCallback.BREAK);
}
/**
* drill down
*
* @param monMember
* drill down member
*/
public void drillUp(Hierarchy hier) {
int iDim = dimIdx(hier.getDimension());
// collect the Exp's of all dimensions
Object[] sets = new Object[nDimension];
DimensionLoop: for (int i = 0; i < nDimension; i++) {
if (i == iDim) {
// replace drillup dimension by drillup set
sets[i] = drillupExp(iDim, hier);
} else {
sets[i] = genExpForDim(i);
}
} // DimensionLoop
// regenerate the position tree as crossjoin of sets
regeneratePosTree(sets, false);
changed(this, false);
}
// ==========
// Query Axis Set
// ==========
/**
* MDX Generation
* generate Exp from tree
*
* @return Exp for axis set
*/
public Object genExp(boolean genHierarchize) {
if (generateMode > 0 && generateIndex > 0)
return genGenerateExp(genHierarchize);
else
return genNormalExp(genHierarchize);
}
/**
* Normal MDX Generation - no Generate
*
* @return Exp for axis set
*/
private Object genNormalExp(boolean genHierarchize) {
ExpGenerator expGenerator = new ExpGenerator(uti);
if (!genHierarchize) {
// no Hierarchize
expGenerator.init(posTreeRoot, hiers);
Object exp = expGenerator.genExp();
return exp;
}
// do we need a special hierarchize ?
// this will be true, if nHierExclude > 0
if (nHierExclude == 0) {
// no special hierarchize needed
expGenerator.init(posTreeRoot, hiers);
Object exp = expGenerator.genExp();
// Hierarchize around "everything"
Object eHier = uti
.createFunCall("Hierarchize", new Object[] { exp}, QuaxUti.FUNTYPE_FUNCTION);
return eHier;
}
// special hierarchize to be generated
// the Qubon Mode Hierarchies are factored out,
// as they consist only of a single set of members.
// the left expression will be generated and then hierarchized,
// *before* beeing crossjoined to the right Expression.
return genLeftRight(expGenerator, nDimension - nHierExclude, nHierExclude);
}
/**
* generate an expression
* with hierarchize for the hierarchies < nHierExclude
* without hierarchize for the hierarchies >= nHierExclude
*/
private Object genLeftRight(ExpGenerator expGenerator, int nLeft, int nRight) {
// generate left expression to be hierarchized
Object leftExp = null;
if (nLeft > 0) {
TreeNode leftRoot = posTreeRoot.deepCopyPrune(nLeft);
leftRoot.setReference(null);
Hierarchy[] leftHiers = new Hierarchy[nLeft];
for (int i = 0; i < leftHiers.length; i++) {
leftHiers[i] = hiers[i];
}
expGenerator.init(leftRoot, leftHiers);
leftExp = expGenerator.genExp();
leftExp = uti.createFunCall("Hierarchize", new Object[] { leftExp}, QuaxUti.FUNTYPE_FUNCTION);
}
// generate the right expression, not to be hierarchized
Object rightExp = null;
Hierarchy[] rightHiers = new Hierarchy[nRight];
for (int i = 0; i < nRight; i++) {
rightHiers[i] = hiers[nLeft + i];
}
// go down to the first hier to be excluded from hierarchize
// note: the subtree tree under any node of the hierarchy above
// is always the same, so we can replicate any subtree under
// a node of hierarchy nLeft-1
TreeNode rightRoot = new TreeNode(null);
TreeNode current = posTreeRoot;
for (int i = 0; i < nLeft; i++) {
List list = current.getChildren();
current = (TreeNode) list.get(0);
}
List list = current.getChildren();
for (Iterator iter = list.iterator(); iter.hasNext();) {
TreeNode node = (TreeNode) iter.next();
TreeNode cnode = node.deepCopy();
rightRoot.addChildNode(cnode);
}
expGenerator.init(rightRoot, rightHiers);
rightExp = expGenerator.genExp();
if (leftExp == null)
return rightExp;
Object exp = uti.createFunCall("CrossJoin", new Object[] { leftExp, rightExp},
QuaxUti.FUNTYPE_FUNCTION);
return exp;
}
/**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -