Author: dvryaboy Date: Wed Apr 7 13:15:51 2010 New Revision: 931531 URL: http://svn.apache.org/viewvc?rev=931531&view=rev Log: PIG-1354: UDFs for dynamic invocation of simple Java methods
Added: hadoop/pig/trunk/src/org/apache/pig/builtin/GenericInvoker.java hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForDouble.java hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForFloat.java hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForInt.java hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForLong.java hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForString.java hadoop/pig/trunk/src/org/apache/pig/builtin/Invoker.java hadoop/pig/trunk/test/org/apache/pig/test/TestInvoker.java Modified: hadoop/pig/trunk/CHANGES.txt Modified: hadoop/pig/trunk/CHANGES.txt URL: http://svn.apache.org/viewvc/hadoop/pig/trunk/CHANGES.txt?rev=931531&r1=931530&r2=931531&view=diff ============================================================================== --- hadoop/pig/trunk/CHANGES.txt (original) +++ hadoop/pig/trunk/CHANGES.txt Wed Apr 7 13:15:51 2010 @@ -24,6 +24,8 @@ INCOMPATIBLE CHANGES IMPROVEMENTS +PIG-1354: UDFs for dynamic invocation of simple Java methods (dvryaboy) + PIG-1316: TextLoader should use Bzip2TextInputFormat for bzip files so that bzip files can be efficiently processed by splitting the files (pradeepkth) Added: hadoop/pig/trunk/src/org/apache/pig/builtin/GenericInvoker.java URL: http://svn.apache.org/viewvc/hadoop/pig/trunk/src/org/apache/pig/builtin/GenericInvoker.java?rev=931531&view=auto ============================================================================== --- hadoop/pig/trunk/src/org/apache/pig/builtin/GenericInvoker.java (added) +++ hadoop/pig/trunk/src/org/apache/pig/builtin/GenericInvoker.java Wed Apr 7 13:15:51 2010 @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package org.apache.pig.builtin; + +import java.io.IOException; + +import org.apache.pig.EvalFunc; +import org.apache.pig.backend.executionengine.ExecException; +import org.apache.pig.data.DataType; +import org.apache.pig.data.Tuple; +import org.apache.pig.impl.logicalLayer.FrontendException; +import org.apache.pig.impl.logicalLayer.schema.Schema; +import org.apache.pig.impl.logicalLayer.schema.Schema.FieldSchema; +/** + * The generic Invoker class does all the common grunt work of setting up an invoker. + * Class-specific non-generic extensions of this class are needed for Pig to know what type + * of return to expect from exec, and to find the appropriate classes through reflection. + * All they have to do is implement the constructors that call into super(). Note that the + * no-parameter constructor is <b>required</b>, if nonsensical, for Pig to do its work. + * <p> + * + * This UDF allows one to dynamically invoke Java methods that return a <code>T</code> + * <p> + * Usage of the Invoker family of UDFs (adjust as appropriate): + * <p> + *<pre> + * {...@code + * -- invoking a static method + * DEFINE StringToLong InvokeForLong('java.lang.Long.valueOf', 'String') + * longs = FOREACH strings GENERATE StringToLong(some_chararray); + * + * -- invoking a method on an object + * DEFINE StringConcat InvokeForString('java.lang.String.concat', 'String String', 'false') + * concatenations = FOREACH strings GENERATE StringConcat(str1, str2); + * } + * </pre> + * <p> + * The first argument to the constructor is the full path to desired method.<br> + * The second argument is a list of classes of the method parameters.<br> + * If the method is not static, the first element in this list is the object to invoke the method on.<br> + * The third argument is the keyword "static" (or "true") to signify that the method is static. <br> + * The third argument is optional, and true by default.<br> + * <p> + * @param <T> + */ +public abstract class GenericInvoker<T> extends EvalFunc<T> { + + private Invoker<T> invoker_; + + public GenericInvoker() {} + + public GenericInvoker(String fullName, String paramSpecsStr) + throws ClassNotFoundException, FrontendException, SecurityException, NoSuchMethodException { + invoker_ = new Invoker<T>(fullName, paramSpecsStr); + } + + public GenericInvoker(String fullName, String paramSpecsStr, String isStatic) + throws ClassNotFoundException, FrontendException, SecurityException, NoSuchMethodException { + invoker_ = new Invoker<T>(fullName, paramSpecsStr, isStatic); + } + + @Override + public T exec(Tuple input) throws IOException { + if (invoker_ == null) { + throw new ExecException("exec() attempted on an unitialized invoker. " + + "Invokers must be constructed with the method to invoke, and parameter signature to same."); + } + return invoker_.invoke(input); + } + + @Override + public Schema outputSchema(Schema input) { + if (invoker_ == null) return null; + FieldSchema fs = new FieldSchema(null, DataType.findType(invoker_.getReturnType())); + return new Schema(fs); + } +} Added: hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForDouble.java URL: http://svn.apache.org/viewvc/hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForDouble.java?rev=931531&view=auto ============================================================================== --- hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForDouble.java (added) +++ hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForDouble.java Wed Apr 7 13:15:51 2010 @@ -0,0 +1,37 @@ +/* + * 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. + */ +package org.apache.pig.builtin; + +import org.apache.pig.impl.logicalLayer.FrontendException; + +/** + * @see GenericInvoker + */ +public class InvokeForDouble extends GenericInvoker<Double> { + + public InvokeForDouble() {} + + public InvokeForDouble(String fullName, String paramSpecsStr) throws FrontendException, SecurityException, ClassNotFoundException, NoSuchMethodException { + super(fullName, paramSpecsStr); + } + + public InvokeForDouble(String fullName, String paramSpecsStr, String isStatic) + throws ClassNotFoundException, FrontendException, SecurityException, NoSuchMethodException { + super(fullName, paramSpecsStr, isStatic); + } + } Added: hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForFloat.java URL: http://svn.apache.org/viewvc/hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForFloat.java?rev=931531&view=auto ============================================================================== --- hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForFloat.java (added) +++ hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForFloat.java Wed Apr 7 13:15:51 2010 @@ -0,0 +1,38 @@ +/* + * 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. + */ +package org.apache.pig.builtin; + +import org.apache.pig.impl.logicalLayer.FrontendException; + +/** + * @see GenericInvoker + */ + +public class InvokeForFloat extends GenericInvoker<Float> { + + public InvokeForFloat() {} + + public InvokeForFloat(String fullName, String paramSpecsStr) throws FrontendException, SecurityException, ClassNotFoundException, NoSuchMethodException { + super(fullName, paramSpecsStr); + } + + public InvokeForFloat(String fullName, String paramSpecsStr, String isStatic) + throws ClassNotFoundException, FrontendException, SecurityException, NoSuchMethodException { + super(fullName, paramSpecsStr, isStatic); + } + } \ No newline at end of file Added: hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForInt.java URL: http://svn.apache.org/viewvc/hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForInt.java?rev=931531&view=auto ============================================================================== --- hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForInt.java (added) +++ hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForInt.java Wed Apr 7 13:15:51 2010 @@ -0,0 +1,37 @@ +/* + * 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. + */ +package org.apache.pig.builtin; + +import org.apache.pig.impl.logicalLayer.FrontendException; + +/** + * @see GenericInvoker + */ +public class InvokeForInt extends GenericInvoker<Integer> { + + public InvokeForInt() {} + + public InvokeForInt(String fullName, String paramSpecsStr) throws FrontendException, SecurityException, ClassNotFoundException, NoSuchMethodException { + super(fullName, paramSpecsStr); + } + + public InvokeForInt(String fullName, String paramSpecsStr, String isStatic) + throws ClassNotFoundException, FrontendException, SecurityException, NoSuchMethodException { + super(fullName, paramSpecsStr, isStatic); + } +} Added: hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForLong.java URL: http://svn.apache.org/viewvc/hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForLong.java?rev=931531&view=auto ============================================================================== --- hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForLong.java (added) +++ hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForLong.java Wed Apr 7 13:15:51 2010 @@ -0,0 +1,37 @@ +/* + * 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. + */ +package org.apache.pig.builtin; + +import org.apache.pig.impl.logicalLayer.FrontendException; + +/** + * @see GenericInvoker + */ +public class InvokeForLong extends GenericInvoker<Long> { + + public InvokeForLong() {} + + public InvokeForLong(String fullName, String paramSpecsStr) throws FrontendException, SecurityException, ClassNotFoundException, NoSuchMethodException { + super(fullName, paramSpecsStr); + } + + public InvokeForLong(String fullName, String paramSpecsStr, String isStatic) + throws ClassNotFoundException, FrontendException, SecurityException, NoSuchMethodException { + super(fullName, paramSpecsStr, isStatic); + } +} Added: hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForString.java URL: http://svn.apache.org/viewvc/hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForString.java?rev=931531&view=auto ============================================================================== --- hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForString.java (added) +++ hadoop/pig/trunk/src/org/apache/pig/builtin/InvokeForString.java Wed Apr 7 13:15:51 2010 @@ -0,0 +1,38 @@ +/* + * 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. + */ + +package org.apache.pig.builtin; + +import org.apache.pig.impl.logicalLayer.FrontendException; + +/** + * @see GenericInvoker + */ +public class InvokeForString extends GenericInvoker<String> { + + public InvokeForString() {} + + public InvokeForString(String fullName, String paramSpecsStr) throws FrontendException, SecurityException, ClassNotFoundException, NoSuchMethodException { + super(fullName, paramSpecsStr); + } + + public InvokeForString(String fullName, String paramSpecsStr, String isStatic) + throws ClassNotFoundException, FrontendException, SecurityException, NoSuchMethodException { + super(fullName, paramSpecsStr, isStatic); + } +} Added: hadoop/pig/trunk/src/org/apache/pig/builtin/Invoker.java URL: http://svn.apache.org/viewvc/hadoop/pig/trunk/src/org/apache/pig/builtin/Invoker.java?rev=931531&view=auto ============================================================================== --- hadoop/pig/trunk/src/org/apache/pig/builtin/Invoker.java (added) +++ hadoop/pig/trunk/src/org/apache/pig/builtin/Invoker.java Wed Apr 7 13:15:51 2010 @@ -0,0 +1,150 @@ +/* + * 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. + */ + +package org.apache.pig.builtin; + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Arrays; + +import org.apache.pig.backend.executionengine.ExecException; +import org.apache.pig.data.Tuple; +import org.apache.pig.impl.logicalLayer.FrontendException; + +public class Invoker<T> { + + private Method method_; + private Class<?>[] paramClasses_; + + private boolean isStatic_; + private Class<?> selfClass_; + private Type returnType_; + + public Invoker(String fullName, String paramSpecsStr) throws ClassNotFoundException, FrontendException, SecurityException, NoSuchMethodException { + this(fullName, paramSpecsStr, "true"); + } + + public Invoker(String fullName, String paramSpecsStr, String isStatic) throws ClassNotFoundException, FrontendException, SecurityException, NoSuchMethodException { + String className = fullName.substring(0, fullName.lastIndexOf('.')); + String methodName = fullName.substring(fullName.lastIndexOf('.')+1); + Class<?> klazz = Class.forName(className); + String[] paramSpecs = paramSpecsStr.split(" "); + isStatic_ = "static".equalsIgnoreCase(isStatic) || "true".equals(isStatic); + paramClasses_ = new Class<?>[paramSpecs.length]; + for (int i = 0; i < paramSpecs.length; i++) { + paramClasses_[i] = stringToClass(paramSpecs[i]); + } + if (!isStatic_) { + selfClass_ = paramClasses_[0]; + } + method_ = klazz.getMethod(methodName, (isStatic_ ? paramClasses_ : dropFirstClass(paramClasses_))); + returnType_ = method_.getGenericReturnType(); + } + + public Type getReturnType() { + return returnType_; + } + + private static Class<?>[] dropFirstClass(Class<?>[] original) { + if (original.length < 2) { + return new Class[0]; + } else { + return Arrays.copyOfRange(original, 1, original.length-1); + } + } + + private static Object[] dropFirstObject(Object[] original) { + if (original.length < 2) { + return new Object[0]; + } else { + return Arrays.copyOfRange(original, 1, original.length-1); + } + } + + private static Class<?> stringToClass(String klass) throws FrontendException { + if ("string".equalsIgnoreCase(klass)) { + return String.class; + } else if ("int".equalsIgnoreCase(klass)) { + return Integer.TYPE; + } else if ("double".equalsIgnoreCase(klass)) { + return Double.TYPE; + } else if ("float".equalsIgnoreCase(klass)){ + return Float.TYPE; + } else if ("long".equalsIgnoreCase(klass)) { + return Long.TYPE; + } else { + throw new FrontendException("unable to find mathing class for " + klass); + } + + } + + private static Class<?> unPrimitivize(Class<?> klass) { + if (klass.equals(Integer.TYPE)) { + return Integer.class; + } if (klass.equals(Long.TYPE)) { + return Long.class; + } else if (klass.equals(Float.TYPE)) { + return Float.class; + } else if (klass.equals(Double.TYPE)) { + return Double.class; + } else { + return klass; + } + } + + private Object[] tupleToArgs(Tuple t) throws ExecException { + if ( (t == null && paramClasses_ != null) || (t != null && t.size() != paramClasses_.length)) { + throw new ExecException("unable to match function arguments to declared signature."); + } + if (t == null) { + return null; + } + Object[] args = new Object[t.size()]; + for (int i = 0; i < t.size(); i++) { + args[i] = unPrimitivize(paramClasses_[i]).cast(t.get(i)); + } + return args; + } + + @SuppressWarnings("unchecked") + public T invoke(Tuple input) throws IOException { + Object[] args = tupleToArgs(input); + try { + if (!isStatic_) { + return (T) method_.invoke(selfClass_.cast(args[0]), dropFirstObject(args)); + } else { + return (T) method_.invoke(null, args); + } + } catch (IllegalArgumentException e) { + throw new ExecException(e); + } catch (IllegalAccessException e) { + throw new ExecException(e); + } catch (InvocationTargetException e) { + throw new ExecException(e); + } + } + +} + + + + + + Added: hadoop/pig/trunk/test/org/apache/pig/test/TestInvoker.java URL: http://svn.apache.org/viewvc/hadoop/pig/trunk/test/org/apache/pig/test/TestInvoker.java?rev=931531&view=auto ============================================================================== --- hadoop/pig/trunk/test/org/apache/pig/test/TestInvoker.java (added) +++ hadoop/pig/trunk/test/org/apache/pig/test/TestInvoker.java Wed Apr 7 13:15:51 2010 @@ -0,0 +1,139 @@ +/* + * 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. + */ + +package org.apache.pig.test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.apache.pig.EvalFunc; +import org.apache.pig.builtin.InvokeForDouble; +import org.apache.pig.builtin.InvokeForFloat; +import org.apache.pig.builtin.InvokeForInt; +import org.apache.pig.builtin.InvokeForLong; +import org.apache.pig.builtin.InvokeForString; +import org.apache.pig.data.Tuple; +import org.apache.pig.data.TupleFactory; +import org.junit.Test; + +/** need more tests -- non-String funcs and especially the full path through the pig interpreter. + * I tested manually, seems to work, but + * should really add more here. + */ +public class TestInvoker { + + private final TupleFactory tf_ = TupleFactory.getInstance(); + @Test + public void testStringInvoker() throws SecurityException, ClassNotFoundException, NoSuchMethodException, IOException { + + // Test non-static method + InvokeForString is = new InvokeForString("java.lang.String.toUpperCase", "String", "false"); + assertEquals("FOO", is.exec(tf_.newTuple("foo"))); + + // both "static" and "true" should work + // Test static method + is = new InvokeForString("java.lang.String.valueOf", "int", "true"); + Tuple t = tf_.newTuple(1); + t.set(0,231); + assertEquals("231", is.exec(t)); + + // test default (should be static) + is = new InvokeForString("java.lang.String.valueOf", "int"); + assertEquals("231", is.exec(t)); + + // Test method with multiple args + is = new InvokeForString(TestInvoker.class.getName()+".concatStrings", "String String"); + t = tf_.newTuple(2); + t.set(0, "foo"); + t.set(1, "bar"); + assertEquals("foobar", is.exec(t)); + } + + @Test + public void testLongInvoker() throws SecurityException, ClassNotFoundException, NoSuchMethodException, NumberFormatException, IOException { + InvokeForLong il = new InvokeForLong("java.lang.Long.valueOf", "String"); + Tuple t = tf_.newTuple(1); + String arg = "245"; + t.set(0, arg); + assertEquals(Long.valueOf(arg), il.exec(t)); + } + + @Test + public void testIntInvoker() throws SecurityException, ClassNotFoundException, NoSuchMethodException, NumberFormatException, IOException { + InvokeForInt il = new InvokeForInt("java.lang.Integer.valueOf", "String"); + Tuple t = tf_.newTuple(1); + String arg = "245"; + t.set(0, arg); + assertEquals(Integer.valueOf(arg), il.exec(t)); + } + + @Test + public void testDoubleInvoker() throws SecurityException, ClassNotFoundException, NoSuchMethodException, NumberFormatException, IOException { + InvokeForDouble il = new InvokeForDouble("java.lang.Double.valueOf", "String"); + Tuple t = tf_.newTuple(1); + String arg = "245"; + t.set(0, arg); + assertEquals(Double.valueOf(arg), il.exec(t)); + } + + @Test + public void testFloatInvoker() throws SecurityException, ClassNotFoundException, NoSuchMethodException, NumberFormatException, IOException { + InvokeForFloat il = new InvokeForFloat("java.lang.Float.valueOf", "String"); + Tuple t = tf_.newTuple(1); + String arg = "245.3"; + t.set(0, arg); + assertEquals(Float.valueOf(arg), il.exec(t)); + } + + public static String concatStrings(String str1, String str2) { + return str1.concat(str2); + } + + @Test + public void testSpeed() throws IOException, SecurityException, ClassNotFoundException, NoSuchMethodException { + EvalFunc<Double> log = new Log(); + Tuple tup = tf_.newTuple(1); + long start = System.currentTimeMillis(); + for (int i=0; i < 1000000; i++) { + tup.set(0, (double) i); + log.exec(tup); + } + long staticSpeed = (System.currentTimeMillis()-start); + start = System.currentTimeMillis(); + log = new InvokeForDouble("java.lang.Math.log", "Double", "static"); + for (int i=0; i < 1000000; i++) { + tup.set(0, (double) i); + log.exec(tup); + } + long dynamicSpeed = System.currentTimeMillis()-start; + System.err.println("Dynamic to static ratio: "+((float) dynamicSpeed)/staticSpeed); + assertTrue( ((float) dynamicSpeed)/staticSpeed < 5); + } + + private class Log extends EvalFunc<Double> { + + @Override + public Double exec(Tuple input) throws IOException { + Double d = (Double) input.get(0); + return Math.log(d); + } + + } +}