Initial commit.
[jagi.git] / src / jagi / fs / Handler.java
CommitLineData
49ccd711
FT
1package jagi.fs;
2
3import java.util.*;
4import java.util.function.*;
5import java.util.logging.*;
6import java.lang.reflect.*;
7import java.io.*;
8import java.nio.file.*;
9import jagi.*;
10
11public 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}