LUCENE-5207: load available javascript functions from resource file (properties)

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/branches/lucene5207@1523114 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Uwe Schindler 2013-09-13 21:38:36 +00:00
parent b23b6276cc
commit ada121d6b0
3 changed files with 76 additions and 45 deletions

View File

@ -236,7 +236,7 @@ public class JavascriptCompiler {
recursiveCompile(current.getChild(argument), ComputedType.DOUBLE);
}
methodVisitor.visitMethodInsn(INVOKESTATIC, method.klass, method.method, method.signature);
methodVisitor.visitMethodInsn(INVOKESTATIC, method.klass, method.method, method.descriptor);
typeCompile(expected, ComputedType.DOUBLE);
break;

View File

@ -16,11 +16,16 @@ package org.apache.lucene.expressions.js;
* limitations under the License.
*/
import java.io.IOException;
import java.io.Reader;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.MathUtil;
import org.objectweb.asm.Type;
@ -32,59 +37,48 @@ class JavascriptFunction {
private static final Map<String, JavascriptFunction> methods = new HashMap<String, JavascriptFunction>();
static {
try {
addFunction("abs", Math.class.getMethod("abs", double.class));
addFunction("acos", Math.class.getMethod("acos", double.class));
addFunction("acosh", MathUtil.class.getMethod("acosh", double.class));
addFunction("asin", Math.class.getMethod("asin", double.class));
addFunction("asinh", MathUtil.class.getMethod("asinh", double.class));
addFunction("atan", Math.class.getMethod("atan", double.class));
addFunction("atan2", Math.class.getMethod("atan2", double.class, double.class));
addFunction("atanh", MathUtil.class.getMethod("atanh", double.class));
addFunction("ceil", Math.class.getMethod("ceil", double.class));
addFunction("cos", Math.class.getMethod("cos", double.class));
addFunction("cosh", Math.class.getMethod("cosh", double.class));
addFunction("exp", Math.class.getMethod("exp", double.class));
addFunction("floor", Math.class.getMethod("floor", double.class));
addFunction("ln", Math.class.getMethod("log", double.class));
addFunction("log10", Math.class.getMethod("log10", double.class));
addFunction("logn", MathUtil.class.getMethod("log", double.class, double.class));
addFunction("max", Math.class.getMethod("max", double.class, double.class));
addFunction("min", Math.class.getMethod("min", double.class, double.class));
addFunction("pow", Math.class.getMethod("pow", double.class, double.class));
addFunction("sin", Math.class.getMethod("sin", double.class));
addFunction("sinh", Math.class.getMethod("sinh", double.class));
addFunction("sqrt", Math.class.getMethod("sqrt", double.class));
addFunction("tan", Math.class.getMethod("tan", double.class));
addFunction("tanh", Math.class.getMethod("tanh", double.class));
} catch (NoSuchMethodException e) {
final Properties props = new Properties();
try (Reader in = IOUtils.getDecodingReader(JavascriptFunction.class,
JavascriptFunction.class.getSimpleName() + ".properties", IOUtils.CHARSET_UTF_8)) {
props.load(in);
}
for (final String call : props.stringPropertyNames()) {
final String[] vals = props.getProperty(call).split(",");
if (vals.length != 3) {
throw new Error("Syntax error while reading Javascript functions from resource");
}
final Class<?> clazz = Class.forName(vals[0].trim());
final String methodName = vals[1].trim();
final int arity = Integer.parseInt(vals[2].trim());
@SuppressWarnings({"rawtypes", "unchecked"}) Class[] args = new Class[arity];
Arrays.fill(args, double.class);
methods.put(call, new JavascriptFunction(call, clazz.getMethod(methodName, args)));
}
} catch (NoSuchMethodException | ClassNotFoundException | IOException e) {
throw new Error("Cannot resolve function", e);
}
}
private static void addFunction(String call, Method method) {
methods.put(call, new JavascriptFunction(call, method));
}
public static JavascriptFunction getMethod(String call, int arguments) {
public static JavascriptFunction getMethod(String call, int arity) {
JavascriptFunction method = methods.get(call);
if (method == null) {
throw new IllegalArgumentException("Unrecognized method call (" + call + ").");
}
if (arguments != method.arguments && method.arguments != -1) {
throw new IllegalArgumentException("Expected (" + method.arguments + ") arguments for method call (" +
call + "), but found (" + arguments + ").");
if (arity != method.arity && method.arity != -1) {
throw new IllegalArgumentException("Expected (" + method.arity + ") arguments for method call (" +
call + "), but found (" + arity + ").");
}
return method;
}
public final String call;
public final int arguments;
public final int arity;
public final String klass;
public final String method;
public final String signature;
public final String descriptor;
private JavascriptFunction(String call, Method method) {
// do some checks if the signature is "compatible":
@ -95,17 +89,10 @@ class JavascriptFunction {
throw new Error(method + " does not return a double.");
}
final Class<?>[] paramTypes = method.getParameterTypes();
for (final Class<?> paramType : paramTypes) {
if (paramType != double.class) {
throw new Error(method + " may only take parameters of type 'double'.");
}
}
this.call = call;
this.arguments = paramTypes.length;
this.arity = method.getParameterTypes().length;
this.klass = Type.getInternalName(method.getDeclaringClass());
this.method = method.getName();
this.signature = Type.getMethodDescriptor(method);
this.descriptor = Type.getMethodDescriptor(method);
}
}

View File

@ -0,0 +1,44 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
# This properties file contains all Javascript functions as keys.
# The values are the implementing class, the static method name, and
# the number of double parameters.
abs = java.lang.Math, abs, 1
acos = java.lang.Math, acos, 1
acosh = org.apache.lucene.util.MathUtil, acosh, 1
asin = java.lang.Math, asin, 1
asinh = org.apache.lucene.util.MathUtil, asinh, 1
atan = java.lang.Math, atan, 1
atan2 = java.lang.Math, atan2, 2
atanh = org.apache.lucene.util.MathUtil, atanh, 1
ceil = java.lang.Math, ceil, 1
cos = java.lang.Math, cos, 1
cosh = java.lang.Math, cosh, 1
exp = java.lang.Math, exp, 1
floor = java.lang.Math, floor, 1
ln = java.lang.Math, log, 1
log10 = java.lang.Math, log10, 1
logn = org.apache.lucene.util.MathUtil, log, 2
max = java.lang.Math, max, 2
min = java.lang.Math, min, 2
pow = java.lang.Math, pow, 2
sin = java.lang.Math, sin, 1
sinh = java.lang.Math, sinh, 1
sqrt = java.lang.Math, sqrt, 1
tan = java.lang.Math, tan, 1
tanh = java.lang.Math, tanh, 1