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) { | |
101 | out.println("usage: dolda.jsvc.scgi.DirServer [-h] [-e CHARSET] [-d DATADIR] PORT"); | |
102 | } | |
103 | ||
104 | public static void main(String[] args) { | |
105 | PosixArgs opt = PosixArgs.getopt(args, "h"); | |
106 | if(opt == null) { | |
107 | usage(System.err); | |
108 | System.exit(1); | |
109 | } | |
110 | String charset = null; | |
111 | File datroot = null; | |
112 | for(char c : opt.parsed()) { | |
113 | switch(c) { | |
114 | case 'e': | |
115 | charset = opt.arg; | |
116 | break; | |
117 | case 'd': | |
118 | datroot = new File(opt.arg); | |
119 | if(!datroot.exists() || !datroot.isDirectory()) { | |
120 | System.err.println(opt.arg + ": no such directory"); | |
121 | System.exit(1); | |
122 | } | |
123 | break; | |
124 | case 'h': | |
125 | usage(System.out); | |
126 | return; | |
127 | } | |
128 | } | |
129 | if(opt.rest.length < 1) { | |
130 | usage(System.err); | |
131 | System.exit(1); | |
132 | } | |
22779185 FT |
133 | Environment env = (datroot == null)?new Environment():new Environment(datroot); |
134 | env.initvm(); | |
13e578b1 FT |
135 | int port = Integer.parseInt(opt.rest[0]); |
136 | ServerSocket sk; | |
137 | try { | |
138 | sk = new ServerSocket(port); | |
139 | } catch(IOException e) { | |
140 | System.err.println("could not bind to port " + port + ": " + e.getMessage()); | |
141 | System.exit(1); | |
142 | return; /* Because javac is stupid. :-/ */ | |
143 | } | |
22779185 | 144 | DirServer s = new DirServer(sk, env); |
32994173 FT |
145 | try { |
146 | ManagementFactory.getPlatformMBeanServer().registerMBean(new dolda.jsvc.scgi.jmx.Server(s), dolda.jsvc.scgi.jmx.Server.name); | |
147 | } catch(InstanceAlreadyExistsException e) { | |
148 | } catch(MBeanRegistrationException e) { | |
149 | } catch(NotCompliantMBeanException e) { | |
150 | } | |
13e578b1 FT |
151 | if(charset != null) |
152 | s.headcs = charset; | |
153 | ||
48d0e295 FT |
154 | Runtime.getRuntime().addShutdownHook(s.sdhook = s.new ShutdownHandler()); |
155 | s.main = new Thread(s, "SCGI server thread"); | |
156 | s.main.start(); | |
13e578b1 FT |
157 | } |
158 | } |