/*
// This software is subject to the terms of the Eclipse Public License v1.0
// Agreement, available at the following URL:
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (C) 2004-2005 Julian Hyde
// Copyright (C) 2005-2012 Pentaho and others
// All Rights Reserved.
*/
package mondrian.olap.fun;
import mondrian.calc.*;
import mondrian.calc.impl.GenericCalc;
import mondrian.mdx.ResolvedFunCall;
import mondrian.olap.*;
import java.util.List;
/**
* Definition of the <code>Properties</code> MDX function.
*
* @author jhyde
* @since Mar 23, 2006
*/
class PropertiesFunDef extends FunDefBase {
static final ResolverImpl Resolver = new ResolverImpl();
public PropertiesFunDef(
String name,
String signature,
String description,
Syntax syntax,
int returnType,
int[] parameterTypes)
{
super(name, signature, description, syntax, returnType, parameterTypes);
}
public Calc compileCall(ResolvedFunCall call, ExpCompiler compiler) {
final MemberCalc memberCalc = compiler.compileMember(call.getArg(0));
final StringCalc stringCalc = compiler.compileString(call.getArg(1));
return new GenericCalc(call) {
public Object evaluate(Evaluator evaluator) {
return properties(
memberCalc.evaluateMember(evaluator),
stringCalc.evaluateString(evaluator));
}
public Calc[] getCalcs() {
return new Calc[] {memberCalc, stringCalc};
}
};
}
static Object properties(Member member, String s) {
boolean matchCase = MondrianProperties.instance().CaseSensitive.get();
Object o = member.getPropertyValue(s, matchCase);
if (o == null) {
if (!Util.isValidProperty(s, member.getLevel())) {
throw new MondrianEvaluationException(
"Property '" + s
+ "' is not valid for member '" + member + "'");
}
}
return o;
}
/**
* Resolves calls to the <code>PROPERTIES</code> MDX function.
*/
private static class ResolverImpl extends ResolverBase {
private static final int[] PARAMETER_TYPES = {
Category.Member, Category.String
};
private ResolverImpl() {
super(
"Properties",
"<Member>.Properties(<String Expression>)",
"Returns the value of a member property.",
Syntax.Method);
}
private boolean matches(
Exp[] args,
int[] parameterTypes,
Validator validator,
List<Conversion> conversions)
{
if (parameterTypes.length != args.length) {
return false;
}
for (int i = 0; i < args.length; i++) {
if (!validator.canConvert(
i, args[i], parameterTypes[i], conversions))
{
return false;
}
}
return true;
}
public FunDef resolve(
Exp[] args,
Validator validator,
List<Conversion> conversions)
{
if (!matches(args, PARAMETER_TYPES, validator, conversions)) {
return null;
}
int returnType = deducePropertyCategory(args[0], args[1]);
return new PropertiesFunDef(
getName(), getSignature(), getDescription(), getSyntax(),
returnType, PARAMETER_TYPES);
}
/**
* Deduces the category of a property. This is possible only if the
* name is a string literal, and the member's hierarchy is unambigous.
* If the type cannot be deduced, returns {@link Category#Value}.
*
* @param memberExp Expression for the member
* @param propertyNameExp Expression for the name of the property
* @return Category of the property
*/
private int deducePropertyCategory(
Exp memberExp,
Exp propertyNameExp)
{
if (!(propertyNameExp instanceof Literal)) {
return Category.Value;
}
String propertyName =
(String) ((Literal) propertyNameExp).getValue();
Hierarchy hierarchy = memberExp.getType().getHierarchy();
if (hierarchy == null) {
return Category.Value;
}
Level[] levels = hierarchy.getLevels();
Property property = lookupProperty(
levels[levels.length - 1], propertyName);
if (property == null) {
// we'll likely get a runtime error
return Category.Value;
} else {
switch (property.getType()) {
case TYPE_BOOLEAN:
return Category.Logical;
case TYPE_NUMERIC:
return Category.Numeric;
case TYPE_STRING:
return Category.String;
case TYPE_DATE:
case TYPE_TIME:
case TYPE_TIMESTAMP:
return Category.DateTime;
default:
throw Util.badValue(property.getType());
}
}
}
public boolean requiresExpression(int k) {
return true;
}
}
}
// End PropertiesFunDef.java