⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 quax.java

📁 OLAP 的客户端代码
💻 JAVA
📖 第 1 页 / 共 5 页
字号:
/*
 * ====================================================================
 * This software is subject to the terms of the Common Public License
 * Agreement, available at the following URL:
 *   http://www.opensource.org/licenses/cpl.html .
 * Copyright (C) 2003-2004 TONBELLER AG.
 * All Rights Reserved.
 * You must accept the terms of that agreement to use this software.
 * ====================================================================
 *
 * 
 */
package com.tonbeller.jpivot.olap.query;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.tonbeller.jpivot.olap.model.Dimension;
import com.tonbeller.jpivot.olap.model.Hierarchy;
import com.tonbeller.jpivot.olap.model.Level;
import com.tonbeller.jpivot.olap.model.Member;
import com.tonbeller.jpivot.olap.model.Position;
import com.tonbeller.jpivot.olap.navi.CalcSet;
import com.tonbeller.jpivot.util.TreeNode;
import com.tonbeller.jpivot.util.TreeNodeCallback;

public class Quax {

  static Logger logger = Logger.getLogger(Quax.class);

  protected int nDimension;

  private Hierarchy[] hiers;

  //  currently, we can handle the following Funcalls
  //  member.children, member.descendants, level.members
  // other funcalls are "unknown functions"
  private UnknownFunction[] unknownFunctions;

  protected TreeNode posTreeRoot = null; // Position tree used in normal mode

  private int ordinal; // ordinal of query axis, never changed by swap

  private boolean qubonMode = false;

  private boolean hierarchizeNeeded = false;

  // if there are multiple hiers on this quax,
  //  "nHierExclude" hierarchies (from right to left)
  //  will *not* be included to the Hierarchize Function.
  // So MDX like
  // Crossjoin(Hierarchize(Dim1.A + Dim1.A.Children), {Measures.A.
  // Measures.B})
  // will be generated, so that the Measures are excluded from Hierarchize.
  private int nHierExclude = 0;

  private int generateMode = 0;

  private int generateIndex = -1; // we handle generate for only 1 dimension

  private Object expGenerate = null;

  private Collection changeListeners = new ArrayList();

  private QuaxUti uti;

  private Map canExpandMemberMap = new HashMap();

  private Map canExpandPosMap = new HashMap();

  private Map canCollapseMemberMap = new HashMap();

  private Map canCollapsePosMap = new HashMap();

  /**
   * c'tor
   * 
   * @param ordinal
   */
  public Quax(int ordinal) {
    this.ordinal = ordinal;
    qubonMode = false;
  }

  /**
   * register change listener
   * 
   * @param listener
   */
  public void addChangeListener(QuaxChangeListener listener) {
    changeListeners.add(listener);
  }

  /**
   * unregister change listener
   * 
   * @param listener
   */
  public void removeChangeListener(QuaxChangeListener listener) {
    changeListeners.remove(listener);
  }

  /**
   * handle change
   * 
   * @param source
   *          Originator of the quax change
   * @param changedMemberSet
   *          true if the memberset was changed by the navigator
   */
  public void changed(Object source, boolean changedMemberSet) {
    for (Iterator iter = changeListeners.iterator(); iter.hasNext();) {
      QuaxChangeListener listener = (QuaxChangeListener) iter.next();
      listener.quaxChanged(this, source, changedMemberSet);
    }
    canExpandMemberMap.clear();
    canExpandPosMap.clear();
    canCollapseMemberMap.clear();
    canCollapsePosMap.clear();

  }

  /**
   * Initialize quax from result positions
   * 
   * @param result
   */
  public void init(List positions) {
    Member[][] aPosMem;
    int nDimension = 0;
    hierarchizeNeeded = false;
    nHierExclude = 0;
    qubonMode = true;

    if (positions.size() == 0) {
      // the axis does not have any positions
      aPosMem = new Member[0][0];
      setHiers(new Hierarchy[0]);
      setHiers(hiers);
      return;
    } else {
      nDimension = ((Position) positions.get(0)).getMembers().length;
      aPosMem = new Member[positions.size()][nDimension];

      int j = 0;
      PositionLoop: for (Iterator iter = positions.iterator(); iter.hasNext();) {
        Position pos = (Position) iter.next();
        aPosMem[j++] = pos.getMembers();
      }
    }
    Hierarchy[] hiers = new Hierarchy[nDimension];
    for (int j = 0; j < hiers.length; j++) {
      Member m = aPosMem[0][j];
      hiers[j] = m.getLevel().getHierarchy();
    }
    setHiers(hiers);
    initPositions(aPosMem);

    // initialize the dimension flags
    // if there is only one set node per dimension,
    //  we are in qubon mode
    posTreeRoot.walkTree(new TreeNodeCallback() {

      /**
       * callback check qubon mode
       */
      public int handleTreeNode(TreeNode node) {
        int iDim = node.getLevel();

        if (iDim == Quax.this.nDimension)
          return TreeNodeCallback.BREAK; // bottom reached

        if (node.getChildren().size() == 1) {
          return TreeNodeCallback.CONTINUE; // continue next level
        } else {
          // more than one child - break out
          Quax.this.qubonMode = false;
          return TreeNodeCallback.BREAK;
        }
      }
    });

    if (qubonMode)
      nHierExclude = nDimension - 1; // nothing hierarchized

  }

  /**
   * Initialize position member arrays after first result gotten
   * 
   * @param aPosMemStart
   */
  private void initPositions(Member[][] aPosMemStart) {
    // no positions - no tree
    if (aPosMemStart.length == 0) {
      posTreeRoot = null;
      return;
    }

    // before the position tree is created,
    //  we want to hierarchize
    /*
     * if (nDimension > 1) hierarchizePositions(aPosMemStart);
     */

    // init position tree
    posTreeRoot = new TreeNode(null); // root
    int iEnd = addToPosTree(aPosMemStart, 0, aPosMemStart.length, 0, posTreeRoot);
    while (iEnd < aPosMemStart.length) {
      iEnd = addToPosTree(aPosMemStart, iEnd, aPosMemStart.length, 0, posTreeRoot);
    }

    // try to factor out the members of the last dimension
    posTreeRoot.walkTree(new TreeNodeCallback() {

      /**
       * callback create member set for last dimension
       */
      public int handleTreeNode(TreeNode node) {
        int iDim1 = node.getLevel();

        if (iDim1 == Quax.this.nDimension - 1) {
          if (node.getChildren().size() <= 1)
            return TreeNodeCallback.CONTINUE_SIBLING; // continue
          // next
          // sibling
          // more than one child in last dimension
          // create a single set function node
          Object[] memArray = new Object[node.getChildren().size()];
          int i = 0;
          for (Iterator iter = node.getChildren().iterator(); iter.hasNext();) {
            TreeNode child = (TreeNode) iter.next();
            memArray[i++] = child.getReference();
          }
          node.getChildren().clear();
          Object oFun = uti.createFunCall("{}", memArray, QuaxUti.FUNTYPE_BRACES);
          TreeNode newChild = new TreeNode(oFun);
          node.addChildNode(newChild);
          return TreeNodeCallback.CONTINUE_SIBLING; // continue next
          // sibling
        }
        return TreeNodeCallback.CONTINUE;
      }
    });

    unknownFunctions = new UnknownFunction[nDimension];
    for (int i = 0; i < nDimension; i++) {
      unknownFunctions[i] = null;
    }
    if (logger.isDebugEnabled())
      logger.debug("after initPositions " + this.toString());
  }

  /**
   * add members of dimension to tree recursively
   * 
   * @param aPosMem
   *          positon member array
   * @param iStartPos
   *          start position for this dimension
   * @param iEndPos
   *          start position for this dimension
   * @param iDim
   *          index of this dimension
   * @param parentNode
   *          parent node (previous dimension)
   * @return index of position where the member of this dimension changes
   */
  protected int addToPosTree(Member[][] aPosMem, int iStartPos, int iEndPos, int iDim,
      TreeNode parentNode) {
    Member currentOfDim = aPosMem[iStartPos][iDim];
    Object o = uti.objForMember(currentOfDim);
    TreeNode newNode = new TreeNode(o);
    parentNode.addChildNode(newNode);

    // check range where member of this dimension is constant
    int iEndRange = iStartPos + 1;
    for (; iEndRange < iEndPos; iEndRange++) {
      if (aPosMem[iEndRange][iDim] != aPosMem[iStartPos][iDim])
        break;
    }
    int nextDim = iDim + 1;
    if (nextDim < nDimension) {
      int iEndChild = addToPosTree(aPosMem, iStartPos, iEndRange, nextDim, newNode);
      while (iEndChild < iEndRange) {
        iEndChild = addToPosTree(aPosMem, iEndChild, iEndRange, nextDim, newNode);
      }
    }
    return iEndRange;
  }

  /**
   * find out, whether axis contains dimension
   * 
   * @param monDim
   * @return index of dimension, -1 if not there
   */
  public int dimIdx(Dimension dim) {
    if (hiers == null || hiers.length == 0)
      return -1; // quax was not initialized yet
    for (int i = 0; i < hiers.length; i++) {
      if (hiers[i].getDimension().equals(dim))
        return i;
    }
    return -1;
  }

  /**
   * regenerate the position tree as crossjoin between sets
   * 
   * @param hiersChanged
   *          indicates that the hierarchies were changed
   */
  public void regeneratePosTree(Object[] sets, boolean hiersChanged) {
    if (hiersChanged) {
      nDimension = sets.length;
      hiers = new Hierarchy[nDimension];
      for (int i = 0; i < nDimension; i++) {
        try {
          hiers[i] = uti.hierForExp(sets[i]);
        } catch (CannotHandleException e) {
          logger.fatal("could not determine Hierarchy for set");
          logger.fatal(e);
          throw new IllegalArgumentException(e.getMessage());
        }
      }
      unknownFunctions = new UnknownFunction[nDimension];
      generateIndex = 0;
      generateMode = 0;
    }
    if (posTreeRoot == null)
      return;
    posTreeRoot.getChildren().clear();
    TreeNode current = posTreeRoot;
    // it would be fine, if we could get rid of an existing Hierarchize
    // - but this is not easy to decide.
    // we will not do it, if there is a "children" function call
    //  not on the highest Level. This indicates that we have drilled
    //  down any member.
    nHierExclude = 0;
    int nChildrenFound = 0;
    boolean childrenFound = false;
    for (int i = 0; i < nDimension; i++) {
      TreeNode newNode;
      if (sets[i] instanceof SetExp) {
        SetExp setx = (SetExp) sets[i];
        newNode = new TreeNode(setx.getOExp());
        int mode = setx.getMode();
        if (mode > 0) {
          generateMode = mode;
          generateIndex = i;
          expGenerate = setx.getOExp();
        }
      } else {
        // can we remove an existing "hierarchize needed"?
        boolean bChildrenFound = findChildrenCall(sets[i], 0);
        if (bChildrenFound) {
          childrenFound = true;
          nChildrenFound = i + 1;
        }

        newNode = new TreeNode(sets[i]);
        if (generateIndex == i && generateMode == CalcSet.STICKY) {
          // there was a sticky generate on this hier
          //  reset, if set expression is different now
          if (!sets[i].equals(expGenerate))
            resetGenerate();
        }
      }
      current.addChildNode(newNode);
      current = newNode;
      if (uti.canHandle(newNode.getReference())) {
        unknownFunctions[i] = null;
      } else {
        unknownFunctions[i] = new UnknownFunction(i, newNode.getReference());
      }
    }
    qubonMode = true;
    nHierExclude = nDimension - nChildrenFound;

    if (!childrenFound)
      hierarchizeNeeded = false;
  }

  /**
   * recursively find "children" Funcall
   */
  private boolean findChildrenCall(Object oExp, int level) {
    if (!uti.isFunCall(oExp))
      return false; // member or level or ...
    if (level > 0 && uti.isFunCallTo(oExp, "children"))
      return true;
    int nArgs = uti.funCallArgCount(oExp);
    for (int i = 0; i < nArgs; i++) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -