5 import java.util.function.*;
6 import java.util.logging.*;
7 import java.lang.reflect.*;
8 import java.nio.file.*;
10 public class JavaHandler implements Function<Map<Object, Object>, Map<Object, Object>> {
11 private static final Logger log = Logger.getLogger("jagi-fs");
12 private final Map<ClassLoader, Function<Map<Object, Object>, Map<Object, Object>>> handlers = new WeakHashMap<>();
14 public static class HandlerException extends RuntimeException {
15 public final Path file;
17 public HandlerException(Path file, String msg, Throwable cause) {
21 public HandlerException(Path file, String msg) {
22 this(file, msg, null);
25 public String getMessage() {
26 return(file + ": " + super.getMessage());
30 @SuppressWarnings("unchecked")
31 private static Function<Map<Object, Object>, Map<Object, Object>> makehandler(Compiler.Module mod) {
34 main = mod.code().loadClass("Main");
35 } catch(ClassNotFoundException e) {
36 throw(new HandlerException(mod.file, "no Main class"));
39 Method wmain = main.getDeclaredMethod("wmain", String[].class);
40 int attr = wmain.getModifiers();
41 if(((attr & Modifier.STATIC) == 0) || ((attr & Modifier.PUBLIC) == 0))
42 throw(new NoSuchMethodException());
43 Object handler = wmain.invoke(null, new Object[] {new String[] {}});
44 if(!(handler instanceof Function))
45 throw(new HandlerException(mod.file, "wmain in " + main.getName() + " returned " + ((handler == null) ? "null" : ("a " + handler.getClass()))));
46 return((Function<Map<Object, Object>, Map<Object, Object>>)handler);
47 } catch(IllegalAccessException e) {
48 throw(new HandlerException(mod.file, "could not call wmain", e));
49 } catch(InvocationTargetException e) {
50 throw(new HandlerException(mod.file, "wmain failed", e.getCause()));
51 } catch(NoSuchMethodException e) {
53 if(Function.class.isAssignableFrom(main)) {
55 Constructor<? extends Function> cons = main.asSubclass(Function.class).getConstructor();
56 Function handler = cons.newInstance();
57 return((Function<Map<Object, Object>, Map<Object, Object>>)handler);
58 } catch(NoSuchMethodException e) {
59 } catch(InvocationTargetException e) {
60 throw(new HandlerException(mod.file, "constructor failed", e.getCause()));
61 } catch(ReflectiveOperationException e) {
62 throw(new HandlerException(mod.file, "could not construct Main", e));
65 throw(new HandlerException(mod.file, "no wmain and not directly applicable"));
68 private Function<Map<Object, Object>, Map<Object, Object>> gethandler(Compiler.Module mod) {
69 ClassLoader code = mod.code();
70 synchronized(handlers) {
71 Function<Map<Object, Object>, Map<Object, Object>> ret = handlers.get(code);
73 handlers.put(code, ret = makehandler(mod));
78 public Map<Object, Object> apply(Map<Object, Object> req) {
79 Compiler.Module mod = Compiler.get().module(Paths.get((String)req.get("SCRIPT_FILENAME")));
82 } catch(Compiler.CompilationException e) {
83 log.warning(String.format("Could not compile %s:\n%s", mod.file, e.messages()));
84 return(Utils.simpleerror(500, "Internal Error", "Could not load JAGI handler"));
85 } catch(Exception e) {
86 log.log(Level.WARNING, String.format("Error occurred when loading %s", mod.file), e);
87 return(Utils.simpleerror(500, "Internal Error", "Could not load JAGI handler"));
89 Function<Map<Object, Object>, Map<Object, Object>> handler;
91 handler = gethandler(mod);
92 } catch(HandlerException e) {
93 Throwable cause = e.getCause();
95 log.log(Level.WARNING, cause, e::getMessage);
97 log.log(Level.WARNING, e::getMessage);
98 return(Utils.simpleerror(500, "Internal Error", "Invalid JAGI handler"));
100 return(handler.apply(req));