All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.boreal.model.functions.JavaMethodInvoker Maven / Gradle / Ivy

The newest version!
package fr.boreal.model.functions;

import fr.boreal.model.logicalElements.api.Literal;
import fr.boreal.model.logicalElements.api.Term;
import fr.boreal.model.logicalElements.factory.api.TermFactory;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Optional;
import java.util.stream.Stream;

/**
 * Invoker implementation using java methods as black boxes
 * @author Florent Tornil
 *
 */
public class JavaMethodInvoker implements Invoker {

	private final Method method;
	private final int method_arg_count;

	private final Class last_arg_type;

	private final TermFactory termFactory;

	/////////////////////////////////////////////////
	// Constructors
	/////////////////////////////////////////////////

	/**
	 * @param termFactory a term factory
	 * @param class_file_path path of the .class file
	 * @param class_full_name name of the .class file
	 * @param method_name name of the method to call
	 * @throws ClassNotFoundException iff the given class is not found
	 * @throws IOException iff the given class file cannot be accessed
	 * @throws NoSuchMethodException iff the given method is not found in the given class
	 */
	public JavaMethodInvoker(TermFactory termFactory, String class_file_path, String class_full_name,
			String method_name) throws ClassNotFoundException, IOException, NoSuchMethodException {

		this.termFactory = termFactory;

		File class_file = new File(class_file_path);
		URL url = class_file.toURI().toURL();
		URLClassLoader loader = new URLClassLoader(new URL[] { url });

		Class invoked_class = loader.loadClass(class_full_name);
		loader.close();

		Optional opt_m = Stream.of(invoked_class.getMethods()).filter(m -> m.getName().equals(method_name))
				.findAny();
		if (opt_m.isPresent()) {
			this.method = opt_m.get();
			this.method_arg_count = method.getParameterCount();
			this.last_arg_type = this.method.getParameterTypes()[this.method_arg_count - 1];
		} else {
			throw new NoSuchMethodException("Method " + method_name + " does not exist for class " + class_full_name);
		}
	}

	/////////////////////////////////////////////////
	// Public methods
	/////////////////////////////////////////////////

	@Override
	public Optional invoke(Term... terms) {

		Object[] args = new Object[terms.length];

		for (int i = 0; i < terms.length; ++i) {
			if (terms[i] instanceof Literal) {
				args[i] = ((Literal)terms[i]).value();
			} else {
				args[i] = terms[i].label();
			}
		}

		// If the last argument of the method is a variadic parameter,
		// we need to group all the remaining arguments into a single array.
		// The resulting array will be of type Object[],
		// ensuring that the method can handle the arguments correctly.
		if (last_arg_type.isArray()) {
			Object[] final_args = Arrays.copyOf(args, this.method_arg_count);
			final_args[this.method_arg_count - 1] = Arrays.copyOfRange(
					args, this.method_arg_count - 1, args.length);
			args = final_args;
		}

		try {
			Object result = this.method.invoke(null, args);
			return Optional.ofNullable(termFactory.createOrGetLiteral((result.getClass().cast(result))));
		} catch (IllegalAccessException e) {
			throw new IllegalStateException(String.format("Failed to access method %s.", method.getName()), e);
		} catch (IllegalArgumentException e) {
			throw new IllegalArgumentException(String.format("Method %s was called with incorrect arguments: %s.",
					method.getName(), Arrays.toString(args)), e);
		} catch (InvocationTargetException e) {
			Throwable cause = e.getCause();
			throw new RuntimeException(String.format("Method %s threw an exception during execution.",
					method.getName()), cause);
		}
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy