001 /* 002 // $Id: //open/mondrian/src/main/mondrian/olap/fun/PropertiesFunDef.java#16 $ 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) 2005-2006 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.olap.*; 013 import mondrian.calc.*; 014 import mondrian.calc.impl.GenericCalc; 015 import mondrian.mdx.ResolvedFunCall; 016 017 /** 018 * Definition of the <code>Properties</code> MDX function. 019 * 020 * @author jhyde 021 * @version $Id: //open/mondrian/src/main/mondrian/olap/fun/PropertiesFunDef.java#16 $ 022 * @since Mar 23, 2006 023 */ 024 class PropertiesFunDef extends FunDefBase { 025 static final ResolverImpl Resolver = new ResolverImpl(); 026 027 public PropertiesFunDef( 028 String name, 029 String signature, 030 String description, 031 Syntax syntax, 032 int returnType, 033 int[] parameterTypes) { 034 super(name, signature, description, syntax, returnType, parameterTypes); 035 } 036 037 public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) { 038 final MemberCalc memberCalc = compiler.compileMember(call.getArg(0)); 039 final StringCalc stringCalc = compiler.compileString(call.getArg(1)); 040 return new GenericCalc(call) { 041 public Object evaluate(Evaluator evaluator) { 042 return properties( 043 memberCalc.evaluateMember(evaluator), 044 stringCalc.evaluateString(evaluator)); 045 } 046 047 public Calc[] getCalcs() { 048 return new Calc[] {memberCalc, stringCalc}; 049 } 050 }; 051 } 052 053 static Object properties(Member member, String s) { 054 boolean matchCase = MondrianProperties.instance().CaseSensitive.get(); 055 Object o = member.getPropertyValue(s, matchCase); 056 if (o == null) { 057 if (!Util.isValidProperty(member, s)) { 058 throw new MondrianEvaluationException( 059 "Property '" + s + 060 "' is not valid for member '" + member + "'"); 061 } 062 } 063 return o; 064 } 065 066 /** 067 * Resolves calls to the <code>PROPERTIES</code> MDX function. 068 */ 069 private static class ResolverImpl extends ResolverBase { 070 private ResolverImpl() { 071 super("Properties", 072 "<Member>.Properties(<String Expression>)", 073 "Returns the value of a member property.", 074 Syntax.Method); 075 } 076 077 public FunDef resolve( 078 Exp[] args, Validator validator, int[] conversionCount) { 079 final int[] argTypes = new int[]{Category.Member, Category.String}; 080 final Exp propertyNameExp = args[1]; 081 final Exp memberExp = args[0]; 082 if ((args.length != 2) || 083 (memberExp.getCategory() != Category.Member) || 084 (propertyNameExp.getCategory() != Category.String)) { 085 return null; 086 } 087 int returnType = deducePropertyCategory(memberExp, propertyNameExp); 088 return new PropertiesFunDef( 089 getName(), getSignature(), getDescription(),getSyntax(), 090 returnType, argTypes); 091 } 092 093 /** 094 * Deduces the category of a property. This is possible only if the 095 * name is a string literal, and the member's hierarchy is unambigous. 096 * If the type cannot be deduced, returns {@link Category#Value}. 097 * 098 * @param memberExp Expression for the member 099 * @param propertyNameExp Expression for the name of the property 100 * @return Category of the property 101 */ 102 private int deducePropertyCategory( 103 Exp memberExp, 104 Exp propertyNameExp) 105 { 106 if (!(propertyNameExp instanceof Literal)) { 107 return Category.Value; 108 } 109 String propertyName = (String) ((Literal) propertyNameExp).getValue(); 110 Hierarchy hierarchy = memberExp.getType().getHierarchy(); 111 if (hierarchy == null) { 112 return Category.Value; 113 } 114 Level[] levels = hierarchy.getLevels(); 115 Property property = lookupProperty( 116 levels[levels.length - 1], propertyName); 117 if (property == null) { 118 // we'll likely get a runtime error 119 return Category.Value; 120 } else { 121 switch (property.getType()) { 122 case TYPE_BOOLEAN: 123 return Category.Logical; 124 case TYPE_NUMERIC: 125 return Category.Numeric; 126 case TYPE_STRING: 127 return Category.String; 128 default: 129 throw Util.badValue(property.getType()); 130 } 131 } 132 } 133 134 public boolean requiresExpression(int k) { 135 return true; 136 } 137 } 138 } 139 140 // End PropertiesFunDef.java 141