package org.smoothbuild.lang.function.nativ; import static org.smoothbuild.lang.message.Messages.containsErrors; import static org.smoothbuild.task.base.Computer.nativeCallComputer; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; import org.smoothbuild.db.values.ValuesDb; import org.smoothbuild.lang.expr.Expression; import org.smoothbuild.lang.function.base.AbstractFunction; import org.smoothbuild.lang.function.base.Signature; import org.smoothbuild.lang.function.def.DefinedFunction; import org.smoothbuild.lang.message.CodeLocation; import org.smoothbuild.lang.message.ErrorMessage; import org.smoothbuild.lang.message.Message; import org.smoothbuild.lang.plugin.Container; import org.smoothbuild.lang.value.Value; import org.smoothbuild.task.base.Computer; import org.smoothbuild.task.exec.ContainerImpl; import com.google.common.hash.HashCode; /** * Smooth Function implemented natively in java. * * @see DefinedFunction */ public class NativeFunction extends AbstractFunction { private final Method method; private final HashCode hash; private final boolean isCacheable; public NativeFunction(Method method, Signature signature, boolean isCacheable, HashCode hash) { super(signature); this.method = method; this.hash = hash; this.isCacheable = isCacheable; } public HashCode hash() { return hash; } public boolean isCacheable() { return isCacheable; } public Expression createCallExpression(List<Expression> args, boolean isGenerated, CodeLocation codeLocation) { return new Expression(type(), args, codeLocation) { public Computer createComputer(ValuesDb valuesDb) { return nativeCallComputer(NativeFunction.this, isGenerated, codeLocation); } }; } public Value invoke(ContainerImpl container, List<Value> arguments) { try { Value result = (Value) method.invoke(null, createArguments(container, arguments)); if (result == null && !containsErrors(container.messages())) { container.log(new ErrorMessage("Native function " + name() + " has faulty implementation: it returned 'null' but logged no error.")); } return result; } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof Message) { container.log((Message) cause); } else { throw new RuntimeException(e); } return null; } } private static Object[] createArguments(Container container, List<Value> arguments) { Object[] nativeArguments = new Object[1 + arguments.size()]; nativeArguments[0] = container; for (int i = 0; i < arguments.size(); i++) { nativeArguments[i + 1] = arguments.get(i); } return nativeArguments; } }