Commit | Line | Data |
---|---|---|
c9837b5e FT |
1 | package dolda.jsvc; |
2 | ||
3 | import java.util.logging.*; | |
4 | import java.lang.reflect.*; | |
5 | ||
6 | public class ThreadContext extends ThreadGroup { | |
7 | private Logger logger = Logger.getLogger("dolda.jsvc.context"); | |
8 | private ThreadGroup workers; | |
9 | private long reqs = 0; | |
4b8346e1 | 10 | private final ServerContext ctx; |
c9837b5e FT |
11 | public final Responder root; |
12 | ||
4b8346e1 | 13 | public ThreadContext(ThreadGroup parent, String name, ServerContext ctx, Class<?> bootclass) { |
c9837b5e | 14 | super((parent == null)?(Thread.currentThread().getThreadGroup()):parent, name); |
4b8346e1 | 15 | this.ctx = ctx; |
c9837b5e FT |
16 | workers = new ThreadGroup(this, "Worker threads") { |
17 | public void uncaughtException(Thread t, Throwable e) { | |
18 | logger.log(Level.SEVERE, "Worker thread terminated with an uncaught exception", e); | |
19 | } | |
20 | }; | |
21 | root = bootstrap(bootclass); | |
22 | } | |
23 | ||
24 | public void uncaughtException(Thread t, Throwable e) { | |
25 | logger.log(Level.SEVERE, "Service thread " + t.toString() + " terminated with an uncaught exception", e); | |
26 | } | |
27 | ||
4b8346e1 FT |
28 | public ServerContext server() { |
29 | return(ctx); | |
30 | } | |
31 | ||
c9837b5e | 32 | public void shutdown() { |
c9837b5e FT |
33 | if(root instanceof ContextResponder) |
34 | ((ContextResponder)root).destroy(); | |
a0b186f8 FT |
35 | try { |
36 | long last = 0; | |
37 | while(true) { | |
38 | long now = System.currentTimeMillis(); | |
39 | if(now - last > 10000) { | |
40 | interrupt(); | |
41 | last = now; | |
42 | } | |
43 | Thread[] th = new Thread[1]; | |
44 | if(enumerate(th) < 1) | |
45 | break; | |
46 | th[0].join(10000); | |
47 | } | |
48 | } catch(InterruptedException e) { | |
49 | logger.log(Level.WARNING, "Interrupted while trying to shut down all service threads. Some may remain.", e); | |
50 | } | |
51 | destroy(); | |
c9837b5e FT |
52 | } |
53 | ||
54 | public RequestThread respond(Request req) { | |
55 | return(new RequestThread(root, req, workers, "Worker thread " + reqs++)); | |
56 | } | |
57 | ||
58 | private Responder bootstrap(final Class<?> bootclass) { | |
59 | final Throwable[] err = new Throwable[1]; | |
60 | final Responder[] res = new Responder[1]; | |
61 | Thread boot = new Thread(this, "JSvc boot thread") { | |
62 | public void run() { | |
63 | try { | |
64 | Method cm = bootclass.getMethod("responder"); | |
65 | Object resp = cm.invoke(null); | |
66 | if(!(resp instanceof Responder)) | |
67 | throw(new ClassCastException("JSvc bootstrapper did not return a responder")); | |
68 | res[0] = (Responder)resp; | |
69 | } catch(NoSuchMethodException e) { | |
70 | logger.log(Level.SEVERE, "Invalid JSvc bootstrapper specified", e); | |
71 | err[0] = e; | |
72 | } catch(IllegalAccessException e) { | |
73 | logger.log(Level.SEVERE, "Invalid JSvc bootstrapper specified", e); | |
74 | err[0] = e; | |
75 | } catch(InvocationTargetException e) { | |
76 | logger.log(Level.SEVERE, "JSvc bootstrapper failed", e); | |
77 | err[0] = e; | |
78 | } | |
79 | } | |
80 | }; | |
81 | boot.start(); | |
82 | try { | |
83 | boot.join(); | |
84 | } catch(InterruptedException e) { | |
85 | logger.log(Level.WARNING, "Interrupted during bootstrapping", e); | |
86 | boot.interrupt(); | |
87 | Thread.currentThread().interrupt(); | |
88 | } | |
89 | if(err[0] != null) | |
90 | throw(new RuntimeException(err[0])); | |
91 | if(res[0] == null) { | |
92 | logger.log(Level.SEVERE, "No responder returned in spite of no error having happened."); | |
93 | throw(new NullPointerException("No responder returned in spite of no error having happened.")); | |
94 | } | |
95 | return(res[0]); | |
96 | } | |
4b8346e1 FT |
97 | |
98 | public static ThreadContext current() { | |
99 | for(ThreadGroup tg = Thread.currentThread().getThreadGroup(); tg != null; tg = tg.getParent()) { | |
100 | if(tg instanceof ThreadContext) | |
101 | return((ThreadContext)tg); | |
102 | } | |
103 | return(null); | |
104 | } | |
c9837b5e | 105 | } |