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