Extended SCGI DirServer with some logging.
[jsvc.git] / src / dolda / jsvc / scgi / DirServer.java
1 package dolda.jsvc.scgi;
2
3 import java.io.*;
4 import java.net.*;
5 import java.util.*;
6 import java.util.logging.*;
7 import dolda.jsvc.*;
8 import dolda.jsvc.util.*;
9 import dolda.jsvc.j2ee.PosixArgs;
10
11 public class DirServer extends Server {
12     private final Map<File, DSContext> contexts = new HashMap<File, DSContext>();
13     private final File datroot;
14     private final Logger logger = Logger.getLogger("dolda.jsvc.scgi.dirserver");
15     
16     public DirServer(ServerSocket sk, File datroot) {
17         super(sk);
18         this.datroot = datroot;
19     }
20
21     private DSContext context(File file) throws ThreadContext.CreateException {
22         synchronized(contexts) {
23             DSContext ctx = contexts.get(file);
24             String act = "loaded %s as %s";
25             if(ctx != null) {
26                 if(ctx.mtime < file.lastModified()) {
27                     ctx.tg.destroy();
28                     contexts.remove(file);
29                     ctx = null;
30                     act = "reloaded %s as %s";
31                 }
32             }
33             if(ctx == null) {
34                 ctx = new DSContext(file, datroot);
35                 contexts.put(file, ctx);
36                 logger.config(String.format(act, file, ctx.name()));
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     }
54
55     private static void usage(PrintStream out) {
56         out.println("usage: dolda.jsvc.scgi.DirServer [-h] [-e CHARSET] [-d DATADIR] PORT");
57     }
58     
59     public static void main(String[] args) {
60         PosixArgs opt = PosixArgs.getopt(args, "h");
61         if(opt == null) {
62             usage(System.err);
63             System.exit(1);
64         }
65         String charset = null;
66         File datroot = null;
67         for(char c : opt.parsed()) {
68             switch(c) {
69             case 'e':
70                 charset = opt.arg;
71                 break;
72             case 'd':
73                 datroot = new File(opt.arg);
74                 if(!datroot.exists() || !datroot.isDirectory()) {
75                     System.err.println(opt.arg + ": no such directory");
76                     System.exit(1);
77                 }
78                 break;
79             case 'h':
80                 usage(System.out);
81                 return;
82             }
83         }
84         if(opt.rest.length < 1) {
85             usage(System.err);
86             System.exit(1);
87         }
88         if(datroot == null) {
89             datroot = new File(System.getProperty("user.home"), ".jsvc");
90             if(!datroot.exists() || !datroot.isDirectory())
91                 datroot = null;
92         }
93         int port = Integer.parseInt(opt.rest[0]);
94         ServerSocket sk;
95         try {
96             sk = new ServerSocket(port);
97         } catch(IOException e) {
98             System.err.println("could not bind to port " + port + ": " + e.getMessage());
99             System.exit(1);
100             return; /* Because javac is stupid. :-/ */
101         }
102         DirServer s = new DirServer(sk, datroot);
103         if(charset != null)
104             s.headcs = charset;
105         
106         new Thread(s, "SCGI server thread").start();
107     }
108 }