/*
* © Copyright FOCONIS AG, 2014
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*
*/
package org.openntf.formula.impl;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.openntf.formula.FormulaContext;
import org.openntf.formula.FormulaReturnException;
import org.openntf.formula.ValueHolder;
import org.openntf.formula.annotation.ParamCount;
public class AtFunctionGeneric extends AtFunction {
// How this works:
//
// You define static methods in your class, starting with "at". There are two types of allowed return types:
//
// 1) Methods returning a ValueHolder. You must do multi value handling inside your function
// you may specify a "FormulaContext ctx" as first parameter (optional) and a "ValueHolder[] params"
// 2) Methods returning something else. MultiValueHandling is done automatically.
// you may specify a "FormulaContext ctx" as first parameter (optional) and the remaining parameter that the function needs
//
protected Method method;
protected int paramCount;
protected boolean useContext;
protected Class<?> varArgClass;
protected int minArgs = -1;
protected int maxArgs = -1;
public AtFunctionGeneric(final String image, final Method method) {
super(image);
this.method = method;
Class<?>[] pt = method.getParameterTypes();
paramCount = pt.length;
if (method.isVarArgs()) {
varArgClass = pt[paramCount - 1].getComponentType();
}
if (paramCount >= 1) {
if (FormulaContext.class.isAssignableFrom(pt[0])) {
useContext = true;
paramCount--;
}
}
ParamCount pc = method.getAnnotation(ParamCount.class);
if (pc != null) {
minArgs = pc.value()[0];
maxArgs = pc.value()[pc.value().length - 1];
}
}
public int getMinArgs() {
return minArgs;
}
public int getMaxArgs() {
return maxArgs;
}
public ValueHolder evaluate(final FormulaContext ctx, final ValueHolder[] params) throws FormulaReturnException {
try {
switch (paramCount) {
case 0:
if (useContext) {
return (ValueHolder) method.invoke(null, new Object[] { ctx });
} else {
return (ValueHolder) method.invoke(null, (Object[]) null);
}
case 1:
if (useContext) {
return (ValueHolder) method.invoke(null, new Object[] { ctx, params });
} else {
return (ValueHolder) method.invoke(null, new Object[] { params });
}
default:
throw new IllegalArgumentException("Illegal parameter count: " + paramCount);
}
} catch (IllegalAccessException iax) {
throw new RuntimeException("Unexpected error while invoking method " + method.getName(), iax);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof RuntimeException)
throw (RuntimeException) e.getCause();
if (e.getCause() instanceof FormulaReturnException)
throw (FormulaReturnException) e.getCause();
throw new RuntimeException("Unexpected error occured in method " + method.getName(), e);
}
}
/* (non-Javadoc)
* @see org.openntf.formula.impl.AtFunction#getPrefix()
*/
@Override
protected String getPrefix() {
return method.getDeclaringClass().getSimpleName();
}
public boolean checkParamCount(final int i) {
if (minArgs != -1 && i < minArgs)
return false;
if (maxArgs != -1 && i > maxArgs)
return false;
return true;
}
}