Commit | Line | Data |
---|---|---|
13e578b1 FT |
1 | package dolda.jsvc.scgi; |
2 | ||
3 | import java.io.*; | |
4 | import java.net.*; | |
5 | import java.util.*; | |
a13bfa2c | 6 | import java.util.logging.*; |
13e578b1 FT |
7 | import dolda.jsvc.*; |
8 | import dolda.jsvc.util.*; | |
9 | import dolda.jsvc.j2ee.PosixArgs; | |
32994173 FT |
10 | import java.lang.management.ManagementFactory; |
11 | import javax.management.*; | |
13e578b1 FT |
12 | |
13 | public class DirServer extends Server { | |
14 | private final Map<File, DSContext> contexts = new HashMap<File, DSContext>(); | |
32994173 | 15 | public final Environment env; |
a13bfa2c | 16 | private final Logger logger = Logger.getLogger("dolda.jsvc.scgi.dirserver"); |
48d0e295 | 17 | private Thread sdhook = null, main = null; |
13e578b1 | 18 | |
22779185 | 19 | public DirServer(ServerSocket sk, Environment env) { |
13e578b1 | 20 | super(sk); |
22779185 | 21 | this.env = env; |
13e578b1 FT |
22 | } |
23 | ||
24 | private DSContext context(File file) throws ThreadContext.CreateException { | |
25 | synchronized(contexts) { | |
26 | DSContext ctx = contexts.get(file); | |
a13bfa2c | 27 | String act = "loaded %s as %s"; |
13e578b1 FT |
28 | if(ctx != null) { |
29 | if(ctx.mtime < file.lastModified()) { | |
ecbf3777 | 30 | ctx.tg.shutdown(); |
32994173 FT |
31 | try { |
32 | ManagementFactory.getPlatformMBeanServer().unregisterMBean(ctx.mbean.name); | |
33 | } catch(InstanceNotFoundException e) { | |
34 | } catch(MBeanRegistrationException e) { | |
35 | } | |
13e578b1 FT |
36 | contexts.remove(file); |
37 | ctx = null; | |
a13bfa2c | 38 | act = "reloaded %s as %s"; |
13e578b1 FT |
39 | } |
40 | } | |
41 | if(ctx == null) { | |
22779185 | 42 | ctx = new DSContext(file, env); |
32994173 FT |
43 | try { |
44 | ManagementFactory.getPlatformMBeanServer().registerMBean(ctx.mbean, ctx.mbean.name); | |
45 | } catch(InstanceAlreadyExistsException e) { | |
46 | } catch(MBeanRegistrationException e) { | |
47 | } catch(NotCompliantMBeanException e) { | |
48 | } | |
13e578b1 | 49 | contexts.put(file, ctx); |
a13bfa2c | 50 | logger.config(String.format(act, file, ctx.name())); |
13e578b1 FT |
51 | } |
52 | return(ctx); | |
53 | } | |
54 | } | |
55 | ||
56 | public void handle(Map<String, String> head, Socket sk) throws Exception { | |
57 | String filename = head.get("SCRIPT_FILENAME"); | |
58 | if(filename == null) | |
59 | throw(new Exception("Request for DirServer must contain SCRIPT_FILENAME")); | |
60 | File file = new File(filename); | |
61 | if(!file.exists() || !file.canRead()) | |
62 | throw(new Exception("Cannot access the requested JSvc file " + file.toString())); | |
63 | DSContext ctx = context(file); | |
64 | Request req = new ScgiRequest(sk, head); | |
65 | RequestThread w = ctx.tg.respond(req); | |
66 | w.start(); | |
67 | } | |
0de51374 | 68 | |
48d0e295 FT |
69 | private class ShutdownHandler extends Thread { |
70 | public void run() { | |
71 | sdhook = null; | |
72 | DirServer.this.stop(); | |
73 | try { | |
74 | main.join(); | |
75 | } catch(InterruptedException e) {} | |
76 | } | |
77 | } | |
78 | ||
0de51374 | 79 | protected void shutdown() { |
48d0e295 FT |
80 | try { |
81 | if(sdhook != null) | |
82 | Runtime.getRuntime().removeShutdownHook(sdhook); | |
83 | } catch(Exception e) {} | |
0de51374 FT |
84 | synchronized(contexts) { |
85 | for(Iterator<Map.Entry<File, DSContext>> i = contexts.entrySet().iterator(); i.hasNext();) { | |
86 | Map.Entry<File, DSContext> e = i.next(); | |
87 | DSContext ctx = e.getValue(); | |
88 | i.remove(); | |
89 | ctx.tg.shutdown(); | |
90 | } | |
91 | } | |
48d0e295 | 92 | super.shutdown(); |
32994173 FT |
93 | try { |
94 | ManagementFactory.getPlatformMBeanServer().unregisterMBean(dolda.jsvc.scgi.jmx.Server.name); | |
95 | } catch(InstanceNotFoundException e) { | |
96 | } catch(MBeanRegistrationException e) { | |
97 | } | |
0de51374 | 98 | } |
13e578b1 FT |
99 | |
100 | private static void usage(PrintStream out) { | |
c39ae6d2 | 101 | out.println("usage: dolda.jsvc.scgi.DirServer [-h] [-B BINDADDR] [-e CHARSET] [-d DATADIR] PORT"); |
13e578b1 FT |
102 | } |
103 | ||
104 | public static void main(String[] args) { | |
c39ae6d2 | 105 | PosixArgs opt = PosixArgs.getopt(args, "he:d:B:"); |
13e578b1 FT |
106 | if(opt == null) { |
107 | usage(System.err); | |
108 | System.exit(1); | |
109 | } | |
110 | String charset = null; | |
111 | File datroot = null; | |
c39ae6d2 FT |
112 | InetAddress bindaddr; |
113 | try { | |
f8ade485 | 114 | bindaddr = InetAddress.getByName(null); |
c39ae6d2 | 115 | } catch(UnknownHostException e) { |
f8ade485 | 116 | throw(new Error(e)); |
c39ae6d2 | 117 | } |
13e578b1 FT |
118 | for(char c : opt.parsed()) { |
119 | switch(c) { | |
120 | case 'e': | |
121 | charset = opt.arg; | |
122 | break; | |
123 | case 'd': | |
124 | datroot = new File(opt.arg); | |
125 | if(!datroot.exists() || !datroot.isDirectory()) { | |
126 | System.err.println(opt.arg + ": no such directory"); | |
127 | System.exit(1); | |
128 | } | |
129 | break; | |
c39ae6d2 FT |
130 | case 'B': |
131 | try { | |
132 | bindaddr = InetAddress.getByName(opt.arg); | |
133 | } catch(UnknownHostException e) { | |
134 | System.err.println(opt.arg + ": no such host"); | |
135 | System.exit(1); | |
136 | } | |
137 | break; | |
13e578b1 FT |
138 | case 'h': |
139 | usage(System.out); | |
140 | return; | |
141 | } | |
142 | } | |
143 | if(opt.rest.length < 1) { | |
144 | usage(System.err); | |
145 | System.exit(1); | |
146 | } | |
22779185 FT |
147 | Environment env = (datroot == null)?new Environment():new Environment(datroot); |
148 | env.initvm(); | |
13e578b1 FT |
149 | int port = Integer.parseInt(opt.rest[0]); |
150 | ServerSocket sk; | |
c39ae6d2 | 151 | SocketAddress saddr = new InetSocketAddress(bindaddr, port); |
13e578b1 | 152 | try { |
c39ae6d2 FT |
153 | sk = new ServerSocket(); |
154 | sk.bind(saddr); | |
13e578b1 | 155 | } catch(IOException e) { |
c39ae6d2 | 156 | System.err.println("could not bind to " + saddr + ": " + e.getMessage()); |
13e578b1 FT |
157 | System.exit(1); |
158 | return; /* Because javac is stupid. :-/ */ | |
159 | } | |
22779185 | 160 | DirServer s = new DirServer(sk, env); |
32994173 FT |
161 | try { |
162 | ManagementFactory.getPlatformMBeanServer().registerMBean(new dolda.jsvc.scgi.jmx.Server(s), dolda.jsvc.scgi.jmx.Server.name); | |
163 | } catch(InstanceAlreadyExistsException e) { | |
164 | } catch(MBeanRegistrationException e) { | |
165 | } catch(NotCompliantMBeanException e) { | |
166 | } | |
13e578b1 FT |
167 | if(charset != null) |
168 | s.headcs = charset; | |
169 | ||
48d0e295 FT |
170 | Runtime.getRuntime().addShutdownHook(s.sdhook = s.new ShutdownHandler()); |
171 | s.main = new Thread(s, "SCGI server thread"); | |
172 | s.main.start(); | |
13e578b1 FT |
173 | } |
174 | } |