
org.pivot4j.impl.QueryAdapter Maven / Gradle / Ivy
The newest version!
/*
* ====================================================================
* 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 .
* You must accept the terms of that agreement to use this software.
* ====================================================================
*/
package org.pivot4j.impl;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.NullArgumentException;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.olap4j.Axis;
import org.olap4j.CellSet;
import org.olap4j.CellSetAxis;
import org.olap4j.OlapException;
import org.olap4j.Position;
import org.olap4j.metadata.Dimension;
import org.olap4j.metadata.Hierarchy;
import org.olap4j.metadata.Member;
import org.pivot4j.PivotException;
import org.pivot4j.el.ExpressionEvaluator;
import org.pivot4j.mdx.AbstractExpVisitor;
import org.pivot4j.mdx.CompoundId;
import org.pivot4j.mdx.Exp;
import org.pivot4j.mdx.ExpressionParameter;
import org.pivot4j.mdx.FunCall;
import org.pivot4j.mdx.Literal;
import org.pivot4j.mdx.MdxParser;
import org.pivot4j.mdx.MdxStatement;
import org.pivot4j.mdx.MemberParameter;
import org.pivot4j.mdx.QueryAxis;
import org.pivot4j.mdx.Syntax;
import org.pivot4j.mdx.ValueParameter;
import org.pivot4j.mdx.impl.MdxParserImpl;
import org.pivot4j.state.Bookmarkable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Adapt the MDX query to the model
*/
public class QueryAdapter implements Bookmarkable {
private Logger logger = LoggerFactory.getLogger(getClass());
private PivotModelImpl model;
// Array of query axis state object
private Map quaxes;
private boolean useQuax = false;
private boolean axesSwapped = false;
private Quax quaxToSort;
private MdxStatement parsedQuery;
private MdxStatement cloneQuery;
private Collection listeners = new LinkedList();
private QuaxChangeListener quaxListener = new QuaxChangeListener() {
public void quaxChanged(QuaxChangeEvent e) {
onQuaxChanged(e.getQuax(), e.isChangedByNavigator());
}
};
/**
* @param model
*/
public QueryAdapter(PivotModelImpl model) {
if (model == null) {
throw new NullArgumentException("model");
}
this.model = model;
}
public void initialize() {
this.useQuax = false;
this.axesSwapped = false;
this.quaxToSort = null;
this.parsedQuery = parseQuery(model.getMdx());
this.cloneQuery = null;
List queryAxes = parsedQuery.getAxes();
this.quaxes = new LinkedHashMap(queryAxes.size());
for (QueryAxis queryAxis : queryAxes) {
Quax quax = new Quax(queryAxis.getAxis().axisOrdinal(), model);
quax.addChangeListener(quaxListener);
quaxes.put(queryAxis.getAxis(), quax);
}
}
public boolean isInitialized() {
if (quaxes == null || quaxes.isEmpty()) {
return false;
}
for (Quax quax : quaxes.values()) {
if (!quax.isInitialized()) {
return false;
}
}
return true;
}
public boolean isValid() {
if (parsedQuery == null || parsedQuery.getAxes() == null) {
return false;
}
List axes = parsedQuery.getAxes();
int axisCount = 0;
for (QueryAxis qa : axes) {
if (qa.getExp() != null) {
axisCount++;
}
}
return axisCount >= 2;
}
/**
* @return the model
*/
public PivotModelImpl getModel() {
return model;
}
public String getCubeName() {
CompoundId cube = parsedQuery.getCube();
if (cube != null && !cube.getNames().isEmpty()) {
return cube.getNames().get(0).getUnquotedName();
}
return null;
}
/**
* Register change listener
*
* @param listener
*/
public void addChangeListener(QueryChangeListener listener) {
listeners.add(listener);
}
/**
* Unregister change listener
*
* @param listener
*/
public void removeChangeListener(QueryChangeListener listener) {
listeners.remove(listener);
}
protected void fireQueryChanged() {
fireQueryChanged(true);
}
protected void fireQueryChanged(boolean update) {
if (update) {
this.useQuax = true;
updateQuery();
}
QueryChangeEvent e = new QueryChangeEvent(this);
List copiedListeners = new ArrayList(
listeners);
for (QueryChangeListener listener : copiedListeners) {
listener.queryChanged(e);
}
}
/**
* @return the XMLA Query object
*/
public MdxStatement getParsedQuery() {
return parsedQuery;
}
/**
* @param evaluated
* @return
*/
public String getCurrentMdx(final boolean evaluated) {
MdxStatement stmt = parsedQuery.copy();
stmt.accept(new AbstractExpVisitor() {
@Override
public void visitMemberParameter(MemberParameter exp) {
exp.setEvaluated(evaluated);
}
@Override
public void visitValueParameter(ValueParameter exp) {
exp.setEvaluated(evaluated);
}
});
return stmt.toMdx();
}
/**
* @param evaluator
*/
public void evaluate(final ExpressionEvaluator evaluator) {
parsedQuery.accept(new AbstractExpVisitor() {
@Override
public void visitMemberParameter(MemberParameter exp) {
evaluate(exp, evaluator);
}
@Override
public void visitValueParameter(ValueParameter exp) {
evaluate(exp, evaluator);
}
});
}
/**
* @param exp
* @param evaluator
*/
protected void evaluate(ExpressionParameter exp,
ExpressionEvaluator evaluator) {
String expression = StringUtils.trimToNull(exp.getExpression());
if (expression == null) {
exp.setResult("");
} else {
Object result = evaluator.evaluate(
"${" + exp.getExpression() + "}",
model.getExpressionContext());
exp.setResult(ObjectUtils.toString(result));
}
}
/**
* @return
*/
public Quax getQuax(Axis axis) {
if (!isInitialized()) {
getModel().getCellSet();
}
return quaxes.get(axis);
}
/**
* @param axis
* @return
*/
public Quax createQuax(Axis axis) {
if (!isInitialized()) {
getModel().getCellSet();
}
Quax quax = new Quax(axis.axisOrdinal(), getModel());
quax.initialize(new ArrayList());
quax.addChangeListener(quaxListener);
quaxes.put(axis, quax);
return quax;
}
public Set getAxes() {
return Collections.unmodifiableSet(quaxes.keySet());
}
/**
* @return true if quax is to be used
*/
public boolean getUseQuax() {
return useQuax;
}
/**
* @return true, if axes are currently swapped
*/
public boolean isAxesSwapped() {
return axesSwapped;
}
/**
* @param axesSwapped
*/
public void setAxesSwapped(boolean axesSwapped) {
this.axesSwapped = axesSwapped;
}
public void swapAxes() {
QueryAxis columnAxis = parsedQuery.getAxis(Axis.COLUMNS);
QueryAxis rowAxis = parsedQuery.getAxis(Axis.ROWS);
if (columnAxis != null && rowAxis != null) {
Exp exp = columnAxis.getExp();
columnAxis.setExp(rowAxis.getExp());
rowAxis.setExp(exp);
Quax columnQuax = quaxes.get(Axis.COLUMNS);
Quax rowQuax = quaxes.get(Axis.ROWS);
quaxes.put(Axis.COLUMNS, rowQuax);
quaxes.put(Axis.ROWS, columnQuax);
setAxesSwapped(!axesSwapped);
fireQueryChanged();
}
}
public boolean isNonEmpty() {
boolean nonEmpty = true;
List queryAxes = parsedQuery.getAxes();
for (QueryAxis axis : queryAxes) {
nonEmpty &= axis.isNonEmpty();
}
return !queryAxes.isEmpty() && nonEmpty;
}
/**
* @param nonEmpty
*/
public void setNonEmpty(boolean nonEmpty) {
boolean changed = nonEmpty != isNonEmpty();
if (changed) {
List queryAxes = parsedQuery.getAxes();
for (QueryAxis axis : queryAxes) {
axis.setNonEmpty(nonEmpty);
}
fireQueryChanged(false);
}
}
/**
* @return the quaxToSort
*/
public Quax getQuaxToSort() {
return quaxToSort;
}
/**
* @param quaxToSort
* the quaxToSort to set
*/
public void setQuaxToSort(Quax quaxToSort) {
this.quaxToSort = quaxToSort;
updateQuery();
}
protected boolean isSortOnQuery() {
return model.isSorting() && model.getSortPosMembers() != null
&& !model.getSortPosMembers().isEmpty();
}
/**
* @return ordinal of quax to sort, if sorting is active
*/
protected int activeQuaxToSort() {
if (isSortOnQuery()) {
return quaxToSort.getOrdinal();
} else {
return -1;
}
}
/**
* find the Quax for a specific dimension
*
* @param dim
* Dimension
* @return Quax containg dimension
*/
public Quax findQuax(Dimension dim) {
if (!isInitialized()) {
getModel().getCellSet();
}
for (Quax quax : quaxes.values()) {
if (quax.dimIdx(dim) >= 0) {
return quax;
}
}
return null;
}
/**
* Update the Query Object before Execute. The current query is build from -
* the original query - adding the drilldown groups - apply pending swap
* axes - apply pending sorts.
*/
public MdxStatement updateQuery() {
// if quax is to be used, generate axes from quax
if (useQuax) {
int iQuaxToSort = activeQuaxToSort();
for (Quax quax : quaxes.values()) {
if (quax.getPosTreeRoot() == null) {
continue;
}
boolean doHierarchize = false;
if (quax.isHierarchizeNeeded()
&& quax.getOrdinal() != iQuaxToSort) {
doHierarchize = true;
if (logger.isDebugEnabled()) {
logger.debug("MDX Generation added Hierarchize()");
}
}
Exp eSet = quax.genExp(doHierarchize);
Axis axis = Axis.Factory.forOrdinal(quax.getOrdinal());
if (isAxesSwapped()) {
if (axis == Axis.COLUMNS) {
axis = Axis.ROWS;
} else if (axis == Axis.ROWS) {
axis = Axis.COLUMNS;
}
}
QueryAxis queryAxis = parsedQuery.getAxis(axis);
if (queryAxis == null) {
parsedQuery.setAxis(new QueryAxis(axis, eSet, model
.getDefaultNonEmpty()));
} else {
queryAxis.setExp(eSet);
}
}
}
// generate order function if neccessary
if (!useQuax) {
// if Quax is used, the axis exp's are re-generated every time.
// if not -
// adding a sort to the query must not be permanent.
// Therefore, we clone the orig state of the query object and
// use
// the clone furthermore in order to avoid duplicate "Order"
// functions.
if (cloneQuery == null) {
if (isSortOnQuery()) {
this.cloneQuery = parsedQuery.copy();
}
} else {
// reset to original state
if (isSortOnQuery()) {
this.parsedQuery = cloneQuery.copy();
} else {
this.parsedQuery = cloneQuery;
}
}
}
addSortToQuery();
return parsedQuery;
}
/**
* Apply sort to query
*/
public void addSortToQuery() {
if (isSortOnQuery()) {
switch (model.getSortCriteria()) {
case ASC:
case DESC:
case BASC:
case BDESC:
// call sort
orderAxis(parsedQuery);
break;
case TOPCOUNT:
topBottomAxis(parsedQuery, "TopCount");
break;
case BOTTOMCOUNT:
topBottomAxis(parsedQuery, "BottomCount");
break;
default:
// do nothing
return;
}
}
}
/**
* Add Order Funcall to QueryAxis
*
* @param pq
*/
protected void orderAxis(MdxStatement pq) {
// Order(TopCount) is allowed, Order(Order) is not permitted
QueryAxis qa = pq.getAxis(Axis.Factory.forOrdinal(quaxToSort
.getOrdinal()));
Exp setForAx = qa.getExp();
// setForAx is the top level Exp of the axis
// put an Order FunCall around
List args = new ArrayList(3);
// the set to be sorted is the set representing the query axis
args.add(setForAx);
// if we got more than 1 position member, generate a tuple for the 2.arg
Exp sortExp;
List sortPosMembers = model.getSortPosMembers();
if (sortPosMembers == null) {
return;
}
QuaxUtil utils = new QuaxUtil(model.getCube(),
model.getMemberHierarchyCache());
if (sortPosMembers.size() > 1) {
List memberExp = new ArrayList(sortPosMembers.size());
for (Member member : sortPosMembers) {
memberExp.add(utils.expForMember(member));
}
sortExp = new FunCall("()", Syntax.Parentheses, memberExp);
} else {
sortExp = utils.expForMember(sortPosMembers.get(0));
}
args.add(sortExp);
args.add(Literal.createString(model.getSortCriteria().name()));
FunCall order = new FunCall("Order", Syntax.Function, args);
qa.setExp(order);
}
/**
* Add Top/BottomCount Funcall to QueryAxis
*
* @param pq
* @param function
*/
protected void topBottomAxis(MdxStatement pq, String function) {
if (quaxToSort == null) {
return;
}
// TopCount(TopCount) and TopCount(Order) is not permitted
QueryAxis qa = pq.getAxis(Axis.Factory.forOrdinal(quaxToSort
.getOrdinal()));
Exp setForAx = qa.getExp();
Exp sortExp;
List sortPosMembers = model.getSortPosMembers();
if (sortPosMembers == null) {
return;
}
QuaxUtil utils = new QuaxUtil(model.getCube(),
model.getMemberHierarchyCache());
// if we got more than 1 position member, generate a tuple
if (sortPosMembers.size() > 1) {
List memberExp = new ArrayList(sortPosMembers.size());
for (Member member : sortPosMembers) {
memberExp.add(utils.expForMember(member));
}
sortExp = new FunCall("()", Syntax.Parentheses, memberExp);
} else {
sortExp = utils.expForMember(sortPosMembers.get(0));
}
List args = new ArrayList(3);
// the set representing the query axis
args.add(setForAx);
args.add(Literal.create(model.getTopBottomCount()));
args.add(sortExp);
FunCall topbottom = new FunCall(function, Syntax.Function, args);
qa.setExp(topbottom);
}
/**
* @param mdxQuery
*/
protected MdxStatement parseQuery(String mdxQuery) {
MdxParser parser = new MdxParserImpl();
return parser.parse(mdxQuery);
}
/**
* After the startup query was run: get the current positions as array of
* array of member. Called from Model.getResult after the query was
* executed.
*
* @param cellSet
* the result which redefines the query axes
*/
public void afterExecute(CellSet cellSet) {
List axes = cellSet.getAxes();
Map axisMap = new HashMap();
for (CellSetAxis axis : axes) {
axisMap.put(axis.getAxisOrdinal(), axis);
}
// initialization: get the result positions and set it to quax
// if the quaxes are not yet used to generate the query
if (!useQuax) {
for (CellSetAxis axis : axes) {
List positions = axis.getPositions();
Axis targetAxis = axis.getAxisOrdinal();
if (axesSwapped) {
if (axis.getAxisOrdinal() == Axis.COLUMNS) {
targetAxis = Axis.ROWS;
} else if (axis.getAxisOrdinal() == Axis.ROWS) {
targetAxis = Axis.COLUMNS;
}
}
Quax quax = quaxes.get(targetAxis);
if (quax != null) {
quax.initialize(positions);
}
}
} else {
// hierarchize result if neccessary
for (Quax quax : quaxes.values()) {
Axis targetAxis = Axis.Factory.forOrdinal(quax.getOrdinal());
if (axesSwapped) {
if (quax.getOrdinal() == Axis.COLUMNS.axisOrdinal()) {
targetAxis = Axis.ROWS;
} else if (quax.getOrdinal() == Axis.ROWS.axisOrdinal()) {
targetAxis = Axis.COLUMNS;
}
}
CellSetAxis cellSetAxis = axisMap.get(targetAxis);
if (cellSetAxis != null) {
List positions = cellSetAxis.getPositions();
// after a result for CalcSet.GENERATE was gotten
// we have to re-initialize the quax,
// so that we can navigate.
if (quax.getGenerateMode() == CalcSetMode.Generate) {
quax.resetGenerate();
quax.initialize(positions);
} else {
// unknown function members are collected
// - always for a "Sticky generate" unknown function
// - on first result for any other unknown function
int nDimension = quax.getNDimension();
for (int j = 0; j < nDimension; j++) {
// collect members for unknown functions on quax
if (quax.isUnknownFunction(j)) {
List members = memListForHier(j,
positions);
quax.setHierMemberList(j, members);
}
}
}
}
}
}
if (logger.isDebugEnabled()) {
// print the result positions to logger
for (CellSetAxis axis : axes) {
List positions = axis.getPositions();
logger.debug("Positions of axis "
+ axis.getAxisOrdinal().axisOrdinal());
if (positions.size() == 0) {
// the axis does not have any positions
logger.debug("0 positions");
} else {
int nDimension = positions.get(0).getMembers().size();
for (Position position : positions) {
List members = position.getMembers();
StringBuilder sb = new StringBuilder();
for (int j = 0; j < nDimension; j++) {
if (j > 0) {
sb.append(" * ");
}
List memsj = new ArrayList(j + 1);
for (int k = 0; k <= j; k++) {
memsj.add(members.get(k));
}
if (this.canExpand(memsj)) {
sb.append("(+)");
} else if (this.canCollapse(memsj)) {
sb.append("(-)");
} else {
sb.append(" ");
}
sb.append(members.get(j).getUniqueName());
}
logger.debug(sb.toString());
}
}
}
}
}
/**
* Extract members of hier from Result
*
* @param hierIndex
* @return members of hier
*/
protected List memListForHier(int hierIndex,
List positions) {
List members = new ArrayList();
for (Position position : positions) {
Member member = position.getMembers().get(hierIndex);
if (!members.contains(member)) {
members.add(member);
}
}
return members;
}
/**
* Create set expression for list of members
*
* @param members
* @return set expression
*/
protected Object createMemberSet(List members) {
List exps = new ArrayList(members.size());
QuaxUtil utils = new QuaxUtil(model.getCube(),
model.getMemberHierarchyCache());
for (Member member : members) {
exps.add(utils.expForMember(member));
}
return new FunCall("{}", Syntax.Braces, exps);
}
/**
* Find out, whether a member can be expanded. this is true, if - the member
* is on an axis and - the member is not yet expanded and - the member has
* children
*
* @param member
* Member to be expanded
* @return true if the member can be expanded
*/
public boolean canExpand(Member member) {
// a calculated member cannot be expanded
if (member.isCalculated()) {
return false;
}
try {
if (member.getChildMemberCount() <= 0) {
return false;
}
} catch (OlapException e) {
throw new PivotException(e);
}
Dimension dim = member.getLevel().getHierarchy().getDimension();
Quax quax = findQuax(dim);
return (quax == null) ? false : quax.canExpand(member);
}
/**
* @param pathMembers
* Members to be expanded
* @return true if the member can be expanded
*/
public boolean canExpand(List pathMembers) {
if (pathMembers.isEmpty()) {
return false;
}
Member member = pathMembers.get(pathMembers.size() - 1);
// a calculated member cannot be expanded
if (member.isCalculated()) {
return false;
}
try {
if (member.getChildMemberCount() <= 0) {
return false;
}
} catch (OlapException e) {
throw new PivotException(e);
}
Dimension dim = member.getLevel().getHierarchy().getDimension();
Quax quax = findQuax(dim);
return (quax == null) ? false : quax.canExpand(pathMembers);
}
/**
* @param member
* Member to be collapsed
* @return true if the member can be collapsed
*/
public boolean canCollapse(Member member) {
// a calculated member cannot be collapsed
if (member.isCalculated()) {
return false;
}
Dimension dim = member.getLevel().getHierarchy().getDimension();
Quax quax = findQuax(dim);
return (quax == null) ? false : quax.canCollapse(member);
}
/**
* @param pathMembers
* positions to be collapsed
* @return true if the position can be collapsed
*/
public boolean canCollapse(List pathMembers) {
if (pathMembers.isEmpty()) {
return false;
}
Member member = pathMembers.get(pathMembers.size() - 1);
// a calculated member cannot be expanded
if (member.isCalculated()) {
return false;
}
Dimension dim = member.getLevel().getHierarchy().getDimension();
Quax quax = findQuax(dim);
return (quax == null) ? false : quax.canCollapse(pathMembers);
}
/**
* Expand a member in all positions this is done by applying
* ToggleDrillState to the Query
*
* @param member
* member to be expanded
*/
public void expand(Member member) {
Dimension dim = member.getLevel().getHierarchy().getDimension();
Quax quax = findQuax(dim);
if (logger.isInfoEnabled()) {
logger.info("Expand member{}", getPositionString(null, member));
}
if ((quax == null) || !quax.canExpand(member)) {
String msg = "Expand member failed for " + member.getUniqueName();
throw new PivotException(msg);
}
quax.expand(member);
}
/**
* Expand a member in a specific position
*
* @param pathMembers
* members to be expanded
*/
public void expand(List pathMembers) {
Member member = pathMembers.get(pathMembers.size() - 1);
Dimension dim = member.getLevel().getHierarchy().getDimension();
Quax quax = findQuax(dim);
if (logger.isInfoEnabled()) {
logger.info("Expand path{}", getPositionString(pathMembers, null));
}
if ((quax == null) || !quax.canExpand(pathMembers)) {
String msg = "Expand failed for"
+ getPositionString(pathMembers, null);
throw new PivotException(msg);
}
quax.expand(pathMembers);
}
/**
* Collapse a member in all positions
*
* @param member
* Member to be collapsed
*/
public void collapse(Member member) {
Dimension dim = member.getLevel().getHierarchy().getDimension();
if (logger.isInfoEnabled()) {
logger.info("Collapse " + member.getUniqueName());
}
Quax quax = findQuax(dim);
if (quax == null) {
String msg = "Collapse quax was null " + member.getUniqueName();
throw new PivotException(msg);
}
quax.collapse(member);
}
/**
* Collapse a member in a specific position
*
* @param pathMembers
* Positions to be collapsed
*/
public void collapse(List pathMembers) {
if (logger.isDebugEnabled()) {
logger.debug("Collapse{}", getPositionString(pathMembers, null));
}
Member member = pathMembers.get(pathMembers.size() - 1);
Dimension dim = member.getLevel().getHierarchy().getDimension();
Quax quax = findQuax(dim);
if (quax == null) {
String msg = "Target quax was null"
+ getPositionString(pathMembers, null);
throw new PivotException(msg);
}
quax.collapse(pathMembers);
}
/**
* Drill down is possible if member
has children
*
* @param member
* Member to drill down
*/
public boolean canDrillDown(Member member) {
try {
if (member.getChildMemberCount() <= 0) {
return false;
}
} catch (OlapException e) {
throw new PivotException(e);
}
Dimension dim = member.getLevel().getHierarchy().getDimension();
Quax quax = findQuax(dim);
return (quax == null) ? false : quax.canDrillDown(member);
}
/**
* 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 hierarchy) {
Quax quax = findQuax(hierarchy.getDimension());
return (quax == null) ? false : quax.canDrillUp(hierarchy);
}
/**
* After switch to Qubon mode: replaces the members. Let H
be
* the hierarchy that member belongs to. Then drillDown will replace all
* members from H
that are currently visible with the children
* of member
.
*/
public void drillDown(Member member) {
// switch to Qubon mode, if not yet in
Quax quax = findQuax(member.getLevel().getHierarchy().getDimension());
if (quax == null) {
String msg = "Target quax was null"
+ getPositionString(null, member);
throw new PivotException(msg);
}
// replace dimension iDim by monMember.children
quax.drillDown(member);
if (logger.isInfoEnabled()) {
logger.info("Drill down{}", getPositionString(null, member));
}
}
/**
* After switch to Qubon mode: replaces all visible members of hier with the
* members of the next higher level.
*/
public void drillUp(Hierarchy hierarchy) {
// switch to Qubon mode, if not yet in
Quax quax = findQuax(hierarchy.getDimension());
if (quax == null) {
String msg = "Drill up hierarchy quax was null "
+ hierarchy.getCaption();
throw new PivotException(msg);
}
quax.drillUp(hierarchy);
if (logger.isInfoEnabled()) {
logger.info("Drill up hierarchy {}", hierarchy.getCaption());
}
}
/**
* @param exp
*/
public void changeSlicer(Exp exp) {
parsedQuery.setSlicer(exp);
fireQueryChanged(false);
}
/**
* Display position member for debugging purposes
*
* @param posMembers
* @param member
* @return
*/
protected String getPositionString(List posMembers, Member member) {
StringBuilder sb = new StringBuilder();
if (posMembers != null) {
sb.append(" Position=");
int i = 0;
for (Member m : posMembers) {
if (i > 0) {
sb.append(" ");
}
sb.append(m.getUniqueName());
i++;
}
}
if (member != null) {
sb.append(" Member=");
sb.append(member.getUniqueName());
}
return sb.toString();
}
/**
* @param quax
* @param changedByNavigator
*/
protected void onQuaxChanged(Quax quax, boolean changedByNavigator) {
// if the axis to sort (normaly *not* the measures)
// was changed by the Navi GUI, we want to switch sorting off
if (changedByNavigator && model.isSorting() && quax == getQuaxToSort()) {
if (logger.isDebugEnabled()) {
logger.debug("Quax changed by navi - switch sorting off");
}
model.setSorting(false);
}
fireQueryChanged();
}
/**
* @see org.pivot4j.state.Bookmarkable#saveState()
*/
public Serializable saveState() {
Serializable[] state = new Serializable[4];
state[0] = isAxesSwapped();
state[1] = getUseQuax();
if (quaxToSort == null) {
state[2] = -1;
} else {
state[2] = quaxToSort.getOrdinal();
}
if (getUseQuax()) {
Serializable[] quaxStates = new Serializable[quaxes.size()];
int i = 0;
for (Axis axis : quaxes.keySet()) {
Quax quax = quaxes.get(axis);
if (quax == null) {
quaxStates[i++] = new Serializable[] { axis.axisOrdinal(),
null };
} else {
quaxStates[i++] = new Serializable[] { axis.axisOrdinal(),
quax.saveState() };
}
}
state[3] = quaxStates;
} else {
state[3] = null;
}
return state;
}
/**
* @see org.pivot4j.state.Bookmarkable#restoreState(java.io.Serializable)
*/
public void restoreState(Serializable state) {
Serializable[] states = (Serializable[]) state;
this.axesSwapped = (Boolean) states[0];
this.useQuax = (Boolean) states[1];
int quaxOrdinal = (Integer) states[2];
this.quaxToSort = null;
if (quaxOrdinal > -1) {
for (Quax quax : quaxes.values()) {
if (quaxOrdinal == quax.getOrdinal()) {
this.quaxToSort = quax;
break;
}
}
}
if (useQuax) {
Serializable[] quaxStates = (Serializable[]) states[3];
// reset the quaxes to current state
if (quaxes.size() != quaxStates.length) {
throw new IllegalArgumentException(
"Stored quax state is not compatible with the current MDX.");
}
for (int i = 0; i < quaxStates.length; i++) {
Serializable[] quaxState = (Serializable[]) quaxStates[i];
int ordinal = (Integer) quaxState[0];
Axis axis = Axis.Factory.forOrdinal(ordinal);
if (quaxState[1] == null) {
quaxes.remove(axis);
} else {
quaxes.get(axis).restoreState(quaxState[1]);
}
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy