Added event-driven server.
[jagi.git] / src / jagi / scgi / Bootstrap.java
CommitLineData
49ccd711
FT
1package jagi.scgi;
2
3import jagi.*;
4import java.lang.reflect.*;
5import java.util.*;
6import java.util.function.*;
7import java.io.*;
8import java.net.*;
9import java.nio.channels.*;
10
11public class Bootstrap {
12 private static InetSocketAddress resolveinaddr(String spec) {
13 int p = spec.indexOf(':');
14 SocketAddress bind;
15 if(p >= 0) {
16 InetAddress host;
17 try {
18 if(spec.charAt(0) == '[') {
19 p = spec.indexOf(']');
20 if((p < 0) || (spec.charAt(p + 1) != ':'))
21 throw(new IllegalArgumentException("invalid address syntax: " + spec));
22 host = InetAddress.getByName(spec.substring(1, p));
23 p++;
24 } else {
25 host = InetAddress.getByName(spec.substring(0, p));
26 }
27 } catch(UnknownHostException e) {
28 throw(new IllegalArgumentException("could not resolve inet host: " + spec, e));
29 }
30 try {
31 return(new InetSocketAddress(host, Integer.parseInt(spec.substring(p + 1))));
32 } catch(NumberFormatException e) {
33 throw(new IllegalArgumentException("not a valid port number: " + spec.substring(p + 1), e));
34 }
35 } else {
36 try {
37 return(new InetSocketAddress(Integer.parseInt(spec)));
38 } catch(NumberFormatException e) {
39 throw(new IllegalArgumentException("not a valid port number: " + spec, e));
40 }
41 }
42 }
43
44 private static ServerSocketChannel tcplisten(String spec) {
45 SocketAddress bind;
46 try {
47 bind = resolveinaddr(spec);
48 } catch(IllegalArgumentException e) {
49 System.err.println("scgi-jagi: " + e.getMessage());
50 System.exit(1);
51 return(null);
52 }
53 try {
54 ServerSocketChannel sk = ServerSocketChannel.open();
55 sk.bind(bind);
56 return(sk);
57 } catch(IOException e) {
58 System.err.println("scgi-jagi: could not create TCP socket: " + e.getMessage());
59 System.exit(1);
60 return(null);
61 }
62 }
63
64 private static ServerSocketChannel getstdin() {
65 Channel stdin;
66 try {
67 stdin = System.inheritedChannel();
68 } catch(IOException e) {
69 System.err.println("scgi-jagi: could not get stdin channel: " + e.getMessage());
70 System.exit(1);
71 return(null);
72 }
73 if(!(stdin instanceof ServerSocketChannel)) {
74 System.err.println("scgi-jagi: stdin is not a listening socket");
75 System.exit(1);
76 return(null);
77 }
78 return((ServerSocketChannel)stdin);
79 }
80
81 private static Function gethandler(ClassLoader loader, String nm, String... args) {
82 Class<?> cl;
83 try {
84 cl = loader.loadClass(nm);
85 } catch(ClassNotFoundException e) {
86 try {
87 cl = loader.loadClass(nm + ".Bootstrap");
88 } catch(ClassNotFoundException e2) {
89 System.err.println("scgi-jagi: could not find handler class or package: " + nm);
90 System.exit(1);
91 return(null);
92 }
93 }
94 Method wmain;
95 try {
96 wmain = cl.getDeclaredMethod("wmain", String[].class);
97 int mod = wmain.getModifiers();
98 if(((mod & Modifier.STATIC) == 0) || ((mod & Modifier.PUBLIC) == 0))
99 throw(new NoSuchMethodException());
100 } catch(NoSuchMethodException e) {
101 System.err.println("scgi-jagi: could not find wmain method in " + cl.getName());
102 System.exit(1);
103 return(null);
104 }
105 Object handler;
106 try {
107 handler = wmain.invoke(null, new Object[] {args});
108 } catch(IllegalAccessException e) {
109 System.err.println("scgi-jagi: could not call wmain in " + cl.getName());
110 System.exit(1);
111 return(null);
112 } catch(InvocationTargetException e) {
113 System.err.println("scgi-jagi: wmain in " + cl.getName() + " failed");
114 e.printStackTrace(System.err);
115 System.exit(1);
116 return(null);
117 }
118 if(!(handler instanceof Function)) {
119 System.err.println("scgi-jagi: wmain in " + cl.getName() + " returned " + ((handler == null) ? "null" : ("a " + handler.getClass())));
120 System.exit(1);
121 return(null);
122 }
123 return((Function)handler);
124 }
125
126 private static void usage(PrintStream out) {
127 out.println("usage: jagi.jar [-h] [-T [HOST:]PORT] HANDLER-CLASS [ARGS...]");
128 }
129
130 public static void main(String[] args) {
131 PosixArgs opt = PosixArgs.getopt(args, "hT:");
132 if(opt == null) {
133 usage(System.err);
134 System.exit(1);
135 return;
136 }
137 String tcpspec = null;
138 ClassLoader loader = Bootstrap.class.getClassLoader();
139 for(char c : opt.parsed()) {
140 switch(c) {
141 case 'h':
142 usage(System.out);
143 System.exit(0);
144 break;
145 case 'T':
146 tcpspec = opt.arg;
147 break;
148 }
149 }
150 if(opt.rest.length < 1) {
151 usage(System.err);
152 System.exit(1);
153 return;
154 }
155 Function handler = gethandler(loader, opt.rest[0], Arrays.copyOfRange(opt.rest, 1, opt.rest.length));
156 ServerSocketChannel sk;
157 if(tcpspec != null) {
158 sk = tcplisten(tcpspec);
159 } else {
160 sk = getstdin();
161 }
965619c0 162 Runnable server = new EventServer(sk, handler);
49ccd711
FT
163 try {
164 server.run();
165 } catch(Throwable e) {
166 System.err.println("scgi-jagi: server exited abnormally");
167 e.printStackTrace();
168 System.exit(1);
169 }
170 System.exit(0);
171 }
172}