Commit | Line | Data |
---|---|---|
49ccd711 FT |
1 | package jagi.fs; |
2 | ||
3 | import java.util.*; | |
4 | import java.util.function.*; | |
5 | import java.util.logging.*; | |
6 | import java.lang.reflect.*; | |
7 | import java.io.*; | |
8 | import java.nio.file.*; | |
9 | import jagi.*; | |
10 | ||
11 | public class Handler implements Function<Map<Object, Object>, Map<Object, Object>> { | |
12 | private static final Logger log = Logger.getLogger("jagi-fs"); | |
13 | private Map<String, Function<Map<Object, Object>, Map<Object, Object>>> handlers = new HashMap<>(); | |
14 | private Map<String, Function<Map<Object, Object>, Map<Object, Object>>> exts = new HashMap<>(); | |
15 | ||
16 | @SuppressWarnings("unchecked") | |
17 | private static Function<Map<Object, Object>, Map<Object, Object>> resolve(ClassLoader loader, String nm) { | |
18 | Class<?> cl; | |
19 | try { | |
20 | cl = loader.loadClass(nm); | |
21 | } catch(ClassNotFoundException e) { | |
22 | try { | |
23 | cl = loader.loadClass(nm + ".Bootstrap"); | |
24 | } catch(ClassNotFoundException e2) { | |
25 | throw(new RuntimeException("could not find handler class or package: " + nm, e2)); | |
26 | } | |
27 | } | |
28 | Method wmain; | |
29 | try { | |
30 | wmain = cl.getDeclaredMethod("wmain", String[].class); | |
31 | int mod = wmain.getModifiers(); | |
32 | if(((mod & Modifier.STATIC) == 0) || ((mod & Modifier.PUBLIC) == 0)) | |
33 | throw(new NoSuchMethodException()); | |
34 | } catch(NoSuchMethodException e) { | |
35 | throw(new RuntimeException("could not find wmain method in " + cl.getName(), e)); | |
36 | } | |
37 | Object handler; | |
38 | try { | |
39 | handler = wmain.invoke(null, new Object[] {new String[] {}}); | |
40 | } catch(IllegalAccessException e) { | |
41 | throw(new RuntimeException("could not call wmain in " + cl.getName(), e)); | |
42 | } catch(InvocationTargetException e) { | |
43 | throw(new RuntimeException("wmain in " + cl.getName() + " failed", e.getCause())); | |
44 | } | |
45 | if(!(handler instanceof Function)) | |
46 | throw(new RuntimeException("wmain in " + cl.getName() + " returned " + ((handler == null) ? "null" : ("a " + handler.getClass())))); | |
47 | return((Function<Map<Object, Object>, Map<Object, Object>>)handler); | |
48 | } | |
49 | ||
50 | public Function<Map<Object, Object>, Map<Object, Object>> resolve(String nm) { | |
51 | synchronized(handlers) { | |
52 | Function<Map<Object, Object>, Map<Object, Object>> handler = handlers.get(nm); | |
53 | if(handler == null) | |
54 | handlers.put(nm, handler = resolve(Thread.currentThread().getContextClassLoader(), nm)); | |
55 | return(handler); | |
56 | } | |
57 | } | |
58 | ||
59 | public void addext(String ext, String name) { | |
60 | addext(ext, resolve(name)); | |
61 | } | |
62 | ||
63 | public void addext(String ext, Function<Map<Object, Object>, Map<Object, Object>> handler) { | |
64 | Map<String, Function<Map<Object, Object>, Map<Object, Object>>> exts = new HashMap<>(this.exts); | |
65 | synchronized(exts) { | |
66 | exts.put(ext, handler); | |
67 | } | |
68 | this.exts = exts; | |
69 | } | |
70 | ||
71 | { | |
72 | addext("jagi", new JavaHandler()); | |
73 | } | |
74 | ||
75 | public Map<Object, Object> apply(Map<Object, Object> req) { | |
76 | String filename = (String)req.get("SCRIPT_FILENAME"); | |
77 | if(filename == null) { | |
78 | log.warning("jagi-fs called without SCRIPT_FILENAME set"); | |
79 | return(Utils.simpleerror(500, "Internal Error", "The server is erroneously configured")); | |
80 | } | |
81 | Path path = Paths.get(filename); | |
82 | if(!Files.isReadable(path)) { | |
83 | log.warning(path + ": not readable"); | |
84 | return(Utils.simpleerror(500, "Internal Error", "The server is erroneously configured")); | |
85 | } | |
86 | String hname = (String)req.get("HTTP_X_ASH_JAVA_HANDLER"); | |
87 | if(hname != null) { | |
88 | Function<Map<Object, Object>, Map<Object, Object>> handler; | |
89 | try { | |
90 | handler = resolve(hname); | |
91 | } catch(Exception e) { | |
92 | log.log(Level.WARNING, "could not load handler " + hname, e); | |
93 | return(Utils.simpleerror(500, "Internal Error", "The server is erroneously configured")); | |
94 | } | |
95 | return(handler.apply(req)); | |
96 | } else { | |
97 | String base = path.getFileName().toString(); | |
98 | int p = base.lastIndexOf('.'); | |
99 | if(p < 0) { | |
100 | log.warning(path + ": no file extension"); | |
101 | return(Utils.simpleerror(500, "Internal Error", "The server is erroneously configured")); | |
102 | } | |
103 | String ext = base.substring(p + 1); | |
104 | Function<Map<Object, Object>, Map<Object, Object>> handler = exts.get(ext); | |
105 | if(handler == null) { | |
106 | log.warning("non-registered file extension: " + ext); | |
107 | return(Utils.simpleerror(500, "Internal Error", "The server is erroneously configured")); | |
108 | } | |
109 | return(handler.apply(req)); | |
110 | } | |
111 | } | |
112 | } |