Add a VM shutdown hook in DirServer to shut down contexts properly.
[jsvc.git] / src / dolda / jsvc / scgi / DirServer.java
CommitLineData
13e578b1
FT
1package dolda.jsvc.scgi;
2
3import java.io.*;
4import java.net.*;
5import java.util.*;
a13bfa2c 6import java.util.logging.*;
13e578b1
FT
7import dolda.jsvc.*;
8import dolda.jsvc.util.*;
9import dolda.jsvc.j2ee.PosixArgs;
10
11public class DirServer extends Server {
12 private final Map<File, DSContext> contexts = new HashMap<File, DSContext>();
22779185 13 private final Environment env;
a13bfa2c 14 private final Logger logger = Logger.getLogger("dolda.jsvc.scgi.dirserver");
48d0e295 15 private Thread sdhook = null, main = null;
13e578b1 16
22779185 17 public DirServer(ServerSocket sk, Environment env) {
13e578b1 18 super(sk);
22779185 19 this.env = env;
13e578b1
FT
20 }
21
22 private DSContext context(File file) throws ThreadContext.CreateException {
23 synchronized(contexts) {
24 DSContext ctx = contexts.get(file);
a13bfa2c 25 String act = "loaded %s as %s";
13e578b1
FT
26 if(ctx != null) {
27 if(ctx.mtime < file.lastModified()) {
ecbf3777 28 ctx.tg.shutdown();
13e578b1
FT
29 contexts.remove(file);
30 ctx = null;
a13bfa2c 31 act = "reloaded %s as %s";
13e578b1
FT
32 }
33 }
34 if(ctx == null) {
22779185 35 ctx = new DSContext(file, env);
13e578b1 36 contexts.put(file, ctx);
a13bfa2c 37 logger.config(String.format(act, file, ctx.name()));
13e578b1
FT
38 }
39 return(ctx);
40 }
41 }
42
43 public void handle(Map<String, String> head, Socket sk) throws Exception {
44 String filename = head.get("SCRIPT_FILENAME");
45 if(filename == null)
46 throw(new Exception("Request for DirServer must contain SCRIPT_FILENAME"));
47 File file = new File(filename);
48 if(!file.exists() || !file.canRead())
49 throw(new Exception("Cannot access the requested JSvc file " + file.toString()));
50 DSContext ctx = context(file);
51 Request req = new ScgiRequest(sk, head);
52 RequestThread w = ctx.tg.respond(req);
53 w.start();
54 }
0de51374 55
48d0e295
FT
56 private class ShutdownHandler extends Thread {
57 public void run() {
58 sdhook = null;
59 DirServer.this.stop();
60 try {
61 main.join();
62 } catch(InterruptedException e) {}
63 }
64 }
65
0de51374 66 protected void shutdown() {
48d0e295
FT
67 try {
68 if(sdhook != null)
69 Runtime.getRuntime().removeShutdownHook(sdhook);
70 } catch(Exception e) {}
0de51374
FT
71 synchronized(contexts) {
72 for(Iterator<Map.Entry<File, DSContext>> i = contexts.entrySet().iterator(); i.hasNext();) {
73 Map.Entry<File, DSContext> e = i.next();
74 DSContext ctx = e.getValue();
75 i.remove();
76 ctx.tg.shutdown();
77 }
78 }
48d0e295 79 super.shutdown();
0de51374 80 }
13e578b1
FT
81
82 private static void usage(PrintStream out) {
83 out.println("usage: dolda.jsvc.scgi.DirServer [-h] [-e CHARSET] [-d DATADIR] PORT");
84 }
85
86 public static void main(String[] args) {
87 PosixArgs opt = PosixArgs.getopt(args, "h");
88 if(opt == null) {
89 usage(System.err);
90 System.exit(1);
91 }
92 String charset = null;
93 File datroot = null;
94 for(char c : opt.parsed()) {
95 switch(c) {
96 case 'e':
97 charset = opt.arg;
98 break;
99 case 'd':
100 datroot = new File(opt.arg);
101 if(!datroot.exists() || !datroot.isDirectory()) {
102 System.err.println(opt.arg + ": no such directory");
103 System.exit(1);
104 }
105 break;
106 case 'h':
107 usage(System.out);
108 return;
109 }
110 }
111 if(opt.rest.length < 1) {
112 usage(System.err);
113 System.exit(1);
114 }
22779185
FT
115 Environment env = (datroot == null)?new Environment():new Environment(datroot);
116 env.initvm();
13e578b1
FT
117 int port = Integer.parseInt(opt.rest[0]);
118 ServerSocket sk;
119 try {
120 sk = new ServerSocket(port);
121 } catch(IOException e) {
122 System.err.println("could not bind to port " + port + ": " + e.getMessage());
123 System.exit(1);
124 return; /* Because javac is stupid. :-/ */
125 }
22779185 126 DirServer s = new DirServer(sk, env);
13e578b1
FT
127 if(charset != null)
128 s.headcs = charset;
129
48d0e295
FT
130 Runtime.getRuntime().addShutdownHook(s.sdhook = s.new ShutdownHandler());
131 s.main = new Thread(s, "SCGI server thread");
132 s.main.start();
13e578b1
FT
133 }
134}