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<Compiler.Module, 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"));
37 } catch(NoClassDefFoundError e) {
38 throw(new HandlerException(mod.file, "class not found: " + e.getMessage()));
41 Method wmain = main.getDeclaredMethod("wmain", String[].class);
42 int attr = wmain.getModifiers();
43 if(((attr & Modifier.STATIC) == 0) || ((attr & Modifier.PUBLIC) == 0))
44 throw(new NoSuchMethodException());
45 Object handler = wmain.invoke(null, new Object[] {new String[] {}});
46 if(!(handler instanceof Function))
47 throw(new HandlerException(mod.file, "wmain in " + main.getName() + " returned " + ((handler == null) ? "null" : ("a " + handler.getClass()))));
48 return((Function<Map<Object, Object>, Map<Object, Object>>)handler);
49 } catch(IllegalAccessException e) {
50 throw(new HandlerException(mod.file, "could not call wmain", e));
51 } catch(InvocationTargetException e) {
52 throw(new HandlerException(mod.file, "wmain failed", e.getCause()));
53 } catch(NoSuchMethodException e) {
55 if(Function.class.isAssignableFrom(main)) {
57 Constructor<? extends Function> cons = main.asSubclass(Function.class).getConstructor();
58 Function handler = cons.newInstance();
59 return((Function<Map<Object, Object>, Map<Object, Object>>)handler);
60 } catch(NoSuchMethodException e) {
61 } catch(InvocationTargetException e) {
62 throw(new HandlerException(mod.file, "constructor failed", e.getCause()));
63 } catch(ReflectiveOperationException e) {
64 throw(new HandlerException(mod.file, "could not construct Main", e));
67 throw(new HandlerException(mod.file, "no wmain and not directly applicable"));
70 private Function<Map<Object, Object>, Map<Object, Object>> gethandler(Compiler.File file) {
71 Compiler.Module mod = file.mod();
72 synchronized(handlers) {
73 Function<Map<Object, Object>, Map<Object, Object>> ret = handlers.get(mod);
75 handlers.put(mod, ret = makehandler(mod));
80 public Map<Object, Object> apply(Map<Object, Object> req) {
81 Compiler.File file = Compiler.get().file(Paths.get((String)req.get("SCRIPT_FILENAME")));
84 } catch(Compiler.CompilationException e) {
85 log.warning(String.format("Could not compile %s:\n%s", file.name, e.messages()));
86 return(Utils.simpleerror(500, "Internal Error", "Could not load JAGI handler"));
87 } catch(Exception e) {
88 log.log(Level.WARNING, String.format("Error occurred when loading %s", file.name), e);
89 return(Utils.simpleerror(500, "Internal Error", "Could not load JAGI handler"));
91 Function<Map<Object, Object>, Map<Object, Object>> handler;
93 handler = gethandler(file);
94 } catch(HandlerException e) {
95 Throwable cause = e.getCause();
97 log.log(Level.WARNING, cause, e::getMessage);
99 log.log(Level.WARNING, e::getMessage);
100 return(Utils.simpleerror(500, "Internal Error", "Invalid JAGI handler"));
102 return(handler.apply(req));