Commit | Line | Data |
---|---|---|
49ccd711 FT |
1 | package jagi.fs; |
2 | ||
3 | import jagi.*; | |
4 | import java.util.*; | |
5 | import java.util.function.*; | |
6 | import java.util.logging.*; | |
7 | import java.lang.reflect.*; | |
8 | import java.nio.file.*; | |
9 | ||
10 | public class JavaHandler implements Function<Map<Object, Object>, Map<Object, Object>> { | |
11 | private static final Logger log = Logger.getLogger("jagi-fs"); | |
e8892ea0 | 12 | private final Map<Compiler.Module, Function<Map<Object, Object>, Map<Object, Object>>> handlers = new WeakHashMap<>(); |
49ccd711 FT |
13 | |
14 | public static class HandlerException extends RuntimeException { | |
15 | public final Path file; | |
16 | ||
17 | public HandlerException(Path file, String msg, Throwable cause) { | |
18 | super(msg, cause); | |
19 | this.file = file; | |
20 | } | |
21 | public HandlerException(Path file, String msg) { | |
22 | this(file, msg, null); | |
23 | } | |
24 | ||
25 | public String getMessage() { | |
26 | return(file + ": " + super.getMessage()); | |
27 | } | |
28 | } | |
29 | ||
30 | @SuppressWarnings("unchecked") | |
31 | private static Function<Map<Object, Object>, Map<Object, Object>> makehandler(Compiler.Module mod) { | |
32 | Class<?> main; | |
33 | try { | |
e8892ea0 | 34 | main = mod.code.loadClass("Main"); |
49ccd711 FT |
35 | } catch(ClassNotFoundException e) { |
36 | throw(new HandlerException(mod.file, "no Main class")); | |
f452d623 FT |
37 | } catch(NoClassDefFoundError e) { |
38 | throw(new HandlerException(mod.file, "class not found: " + e.getMessage())); | |
49ccd711 FT |
39 | } |
40 | try { | |
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) { | |
54 | } | |
55 | if(Function.class.isAssignableFrom(main)) { | |
56 | try { | |
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)); | |
65 | } | |
66 | } | |
67 | throw(new HandlerException(mod.file, "no wmain and not directly applicable")); | |
68 | } | |
69 | ||
e8892ea0 FT |
70 | private Function<Map<Object, Object>, Map<Object, Object>> gethandler(Compiler.File file) { |
71 | Compiler.Module mod = file.mod(); | |
49ccd711 | 72 | synchronized(handlers) { |
e8892ea0 | 73 | Function<Map<Object, Object>, Map<Object, Object>> ret = handlers.get(mod); |
49ccd711 | 74 | if(ret == null) |
e8892ea0 | 75 | handlers.put(mod, ret = makehandler(mod)); |
49ccd711 FT |
76 | return(ret); |
77 | } | |
78 | } | |
79 | ||
80 | public Map<Object, Object> apply(Map<Object, Object> req) { | |
e8892ea0 | 81 | Compiler.File file = Compiler.get().file(Paths.get((String)req.get("SCRIPT_FILENAME"))); |
49ccd711 | 82 | try { |
e8892ea0 | 83 | file.update(); |
49ccd711 | 84 | } catch(Compiler.CompilationException e) { |
e8892ea0 | 85 | log.warning(String.format("Could not compile %s:\n%s", file.name, e.messages())); |
49ccd711 FT |
86 | return(Utils.simpleerror(500, "Internal Error", "Could not load JAGI handler")); |
87 | } catch(Exception e) { | |
e8892ea0 | 88 | log.log(Level.WARNING, String.format("Error occurred when loading %s", file.name), e); |
49ccd711 FT |
89 | return(Utils.simpleerror(500, "Internal Error", "Could not load JAGI handler")); |
90 | } | |
91 | Function<Map<Object, Object>, Map<Object, Object>> handler; | |
92 | try { | |
e8892ea0 | 93 | handler = gethandler(file); |
49ccd711 FT |
94 | } catch(HandlerException e) { |
95 | Throwable cause = e.getCause(); | |
96 | if(cause != null) | |
97 | log.log(Level.WARNING, cause, e::getMessage); | |
98 | else | |
99 | log.log(Level.WARNING, e::getMessage); | |
100 | return(Utils.simpleerror(500, "Internal Error", "Invalid JAGI handler")); | |
101 | } | |
102 | return(handler.apply(req)); | |
103 | } | |
104 | } |