001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/ValidMeasureFunDef.java#10 $ 003 // This software is subject to the terms of the Common Public License 004 // Agreement, available at the following URL: 005 // http://www.opensource.org/licenses/cpl.html. 006 // Copyright (C) 2006-2008 Julian Hyde and others 007 // All Rights Reserved. 008 // You must accept the terms of that agreement to use this software. 009 */ 010 package mondrian.olap.fun; 011 012 import mondrian.calc.*; 013 import mondrian.calc.impl.GenericCalc; 014 import mondrian.mdx.ResolvedFunCall; 015 import mondrian.olap.*; 016 import mondrian.olap.type.TypeUtil; 017 import mondrian.rolap.RolapCube; 018 import mondrian.rolap.RolapMember; 019 020 import java.util.*; 021 022 /** 023 * Definition of the <code>ValidMeasure</code> MDX function. 024 * 025 * <p>Returns a valid measure in a virtual cube by forcing inapplicable 026 * dimensions to their top level. 027 * 028 * <p>Syntax: 029 * <blockquote><code> 030 * ValidMeasure(<Tuple>) 031 * </code></blockquote> 032 * 033 * @author kwalker, mpflug 034 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/ValidMeasureFunDef.java#10 $ 035 */ 036 public class ValidMeasureFunDef extends FunDefBase 037 { 038 static final ValidMeasureFunDef instance = new ValidMeasureFunDef(); 039 040 private ValidMeasureFunDef() { 041 super( 042 "ValidMeasure", 043 "Returns a valid measure in a virtual cube by forcing inapplicable dimensions to their top level.", 044 "fnt"); 045 } 046 047 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 048 final Calc calc; 049 final Exp arg = call.getArg(0); 050 if (TypeUtil.couldBeMember(arg.getType())) { 051 calc = compiler.compileMember(arg); 052 } else { 053 calc = compiler.compileTuple(arg); 054 } 055 return new CalcImpl(call, calc); 056 } 057 058 private static class CalcImpl 059 extends GenericCalc { 060 private final Calc calc; 061 062 public CalcImpl(ResolvedFunCall call, Calc calc) { 063 super(call); 064 this.calc = calc; 065 } 066 067 public Object evaluate(Evaluator evaluator) { 068 final List<Member> memberList; 069 if (calc instanceof MemberCalc) { 070 memberList = new ArrayList<Member>(1); 071 memberList.add(((MemberCalc) calc).evaluateMember(evaluator)); 072 } else { 073 final Member[] tupleMembers = 074 ((TupleCalc)calc).evaluateTuple(evaluator); 075 memberList = Arrays.asList(tupleMembers); 076 } 077 RolapCube baseCube = null; 078 RolapCube virtualCube = (RolapCube) evaluator.getCube(); 079 // find the measure in the tuple 080 int measurePosition = -1; 081 for (int i = 0; i < memberList.size(); i++) { 082 if (memberList.get(i).getDimension().isMeasures()) { 083 measurePosition = i; 084 break; 085 } 086 } 087 // problem: if measure is in two base cubes 088 baseCube = 089 getBaseCubeofMeasure( 090 evaluator, memberList.get(measurePosition), baseCube); 091 List<Dimension> vMinusBDimensions = 092 getDimensionsToForceToAllLevel(virtualCube, baseCube, memberList); 093 // declare members array and fill in with all needed members 094 final List<Member> validMeasureMembers = 095 new ArrayList<Member>(memberList); 096 // start adding to validMeasureMembers at right place 097 for (Dimension vMinusBDimension : vMinusBDimensions) { 098 final Hierarchy hierarchy = vMinusBDimension.getHierarchy(); 099 if (hierarchy.hasAll()) { 100 validMeasureMembers.add(hierarchy.getAllMember()); 101 } else { 102 validMeasureMembers.add(hierarchy.getDefaultMember()); 103 } 104 } 105 // this needs to be done before validmeasuremembers are set on the 106 // context since calculated members defined on a non joining 107 // dimension might have been pulled to default member 108 List<Member> calculatedMembers = 109 getCalculatedMembersFromContext(evaluator); 110 111 evaluator.setContext(validMeasureMembers); 112 113 for (Member member : calculatedMembers) { 114 evaluator.setContext(member); 115 } 116 117 return evaluator.evaluateCurrent(); 118 } 119 120 private List<Member> getCalculatedMembersFromContext(Evaluator evaluator) { 121 Member[] currentMembers = evaluator.getMembers(); 122 List<Member> calculatedMembers = new ArrayList<Member>(); 123 for (Member currentMember : currentMembers) { 124 if (currentMember.isCalculated()) { 125 calculatedMembers.add(currentMember); 126 } 127 } 128 return calculatedMembers; 129 } 130 131 132 public Calc[] getCalcs() { 133 return new Calc[]{calc}; 134 } 135 136 private RolapCube getBaseCubeofMeasure( 137 Evaluator evaluator, Member member, RolapCube baseCube) { 138 final Cube[] cubes = evaluator.getSchemaReader().getCubes(); 139 for (Cube cube1 : cubes) { 140 RolapCube cube = (RolapCube) cube1; 141 if (!cube.isVirtual()) { 142 for (RolapMember measure : cube.getMeasuresMembers()) { 143 if (measure.getName().equals(member.getName())) { 144 baseCube = cube; 145 } 146 } 147 } 148 if (baseCube != null) { 149 break; 150 } 151 } 152 return baseCube; 153 } 154 155 private List<Dimension> getDimensionsToForceToAllLevel( 156 RolapCube virtualCube, 157 RolapCube baseCube, 158 List<Member> memberList) 159 { 160 List<Dimension> vMinusBDimensions = new ArrayList<Dimension>(); 161 Set<Dimension> virtualCubeDims = new HashSet<Dimension>(); 162 virtualCubeDims.addAll(Arrays.asList(virtualCube.getDimensions())); 163 164 Set<Dimension> nonJoiningDims = 165 baseCube.nonJoiningDimensions(virtualCubeDims); 166 167 for (Dimension nonJoiningDim : nonJoiningDims) { 168 if (!isDimInMembersList(memberList, nonJoiningDim)) { 169 vMinusBDimensions.add(nonJoiningDim); 170 } 171 } 172 return vMinusBDimensions; 173 } 174 175 private boolean isDimInMembersList( 176 List<Member> members, 177 Dimension dimension) 178 { 179 for (Member member : members) { 180 if (member.getName().equalsIgnoreCase(dimension.getName())) { 181 return true; 182 } 183 } 184 return false; 185 } 186 187 public boolean dependsOn(Dimension dimension) { 188 // depends on all dimensions 189 return butDepends(getCalcs(), dimension); 190 } 191 } 192 } 193 194 // End ValidMeasureFunDef.java