From c9837b5e87402fa1375fe6d3dd80cb3405edda42 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Tue, 13 Oct 2009 19:21:15 +0200 Subject: [PATCH] Made thread management more predictable. --- src/dolda/jsvc/ThreadContext.java | 75 +++++++++++++++++++++++++++++++++++ src/dolda/jsvc/j2ee/Servlet.java | 31 +++------------ src/dolda/jsvc/util/ErrorHandler.java | 2 +- 3 files changed, 82 insertions(+), 26 deletions(-) create mode 100644 src/dolda/jsvc/ThreadContext.java diff --git a/src/dolda/jsvc/ThreadContext.java b/src/dolda/jsvc/ThreadContext.java new file mode 100644 index 0000000..f21d04c --- /dev/null +++ b/src/dolda/jsvc/ThreadContext.java @@ -0,0 +1,75 @@ +package dolda.jsvc; + +import java.util.logging.*; +import java.lang.reflect.*; + +public class ThreadContext extends ThreadGroup { + private Logger logger = Logger.getLogger("dolda.jsvc.context"); + private ThreadGroup workers; + private long reqs = 0; + public final Responder root; + + public ThreadContext(ThreadGroup parent, String name, Class bootclass) { + super((parent == null)?(Thread.currentThread().getThreadGroup()):parent, name); + workers = new ThreadGroup(this, "Worker threads") { + public void uncaughtException(Thread t, Throwable e) { + logger.log(Level.SEVERE, "Worker thread terminated with an uncaught exception", e); + } + }; + root = bootstrap(bootclass); + } + + public void uncaughtException(Thread t, Throwable e) { + logger.log(Level.SEVERE, "Service thread " + t.toString() + " terminated with an uncaught exception", e); + } + + public void shutdown() { + interrupt(); + if(root instanceof ContextResponder) + ((ContextResponder)root).destroy(); + } + + public RequestThread respond(Request req) { + return(new RequestThread(root, req, workers, "Worker thread " + reqs++)); + } + + private Responder bootstrap(final Class bootclass) { + final Throwable[] err = new Throwable[1]; + final Responder[] res = new Responder[1]; + Thread boot = new Thread(this, "JSvc boot thread") { + public void run() { + try { + Method cm = bootclass.getMethod("responder"); + Object resp = cm.invoke(null); + if(!(resp instanceof Responder)) + throw(new ClassCastException("JSvc bootstrapper did not return a responder")); + res[0] = (Responder)resp; + } catch(NoSuchMethodException e) { + logger.log(Level.SEVERE, "Invalid JSvc bootstrapper specified", e); + err[0] = e; + } catch(IllegalAccessException e) { + logger.log(Level.SEVERE, "Invalid JSvc bootstrapper specified", e); + err[0] = e; + } catch(InvocationTargetException e) { + logger.log(Level.SEVERE, "JSvc bootstrapper failed", e); + err[0] = e; + } + } + }; + boot.start(); + try { + boot.join(); + } catch(InterruptedException e) { + logger.log(Level.WARNING, "Interrupted during bootstrapping", e); + boot.interrupt(); + Thread.currentThread().interrupt(); + } + if(err[0] != null) + throw(new RuntimeException(err[0])); + if(res[0] == null) { + logger.log(Level.SEVERE, "No responder returned in spite of no error having happened."); + throw(new NullPointerException("No responder returned in spite of no error having happened.")); + } + return(res[0]); + } +} diff --git a/src/dolda/jsvc/j2ee/Servlet.java b/src/dolda/jsvc/j2ee/Servlet.java index 165b0f2..4372652 100644 --- a/src/dolda/jsvc/j2ee/Servlet.java +++ b/src/dolda/jsvc/j2ee/Servlet.java @@ -8,16 +8,9 @@ import javax.servlet.http.*; import javax.servlet.*; public class Servlet extends HttpServlet { - private Responder root; - private ThreadGroup workers; - private long reqs = 0; + private ThreadContext tg; public void init() throws ServletException { - workers = new ThreadGroup("JSvc worker threads") { - public void uncaughtException(Thread t, Throwable e) { - log("Worker thread terminated with an uncaught exception", e); - } - }; Properties sprop = new Properties(); try { InputStream pi = Servlet.class.getClassLoader().getResourceAsStream("jsvc.properties"); @@ -32,30 +25,19 @@ public class Servlet extends HttpServlet { String clnm = (String)sprop.get("jsvc.bootstrap"); if(clnm == null) throw(new ServletException("No JSvc bootstrapper specified")); + Class bc; try { - Class rc = Class.forName(clnm); - Method cm = rc.getMethod("responder"); - Object resp = cm.invoke(null); - if(!(resp instanceof Responder)) - throw(new ServletException("JSvc bootstrapper did not return a responder")); - root = (Responder)resp; + bc = Class.forName(clnm); } catch(ClassNotFoundException e) { throw(new ServletException("Invalid JSvc bootstrapper specified", e)); - } catch(NoSuchMethodException e) { - throw(new ServletException("Invalid JSvc bootstrapper specified", e)); - } catch(IllegalAccessException e) { - throw(new ServletException("Invalid JSvc bootstrapper specified", e)); - } catch(InvocationTargetException e) { - throw(new ServletException("JSvc bootstrapper failed", e)); } + tg = new ThreadContext(null, "JSvc service", bc); ServletContext ctx = getServletContext(); ctx.setAttribute("jsvc.starttime", System.currentTimeMillis()); } public void destroy() { - workers.interrupt(); - if(root instanceof ContextResponder) - ((ContextResponder)root).destroy(); + tg.shutdown(); } public void service(HttpServletRequest req, HttpServletResponse resp) { @@ -65,9 +47,8 @@ public class Servlet extends HttpServlet { } catch(UnsupportedEncodingException e) { throw(new Error(e)); } - long mynum = reqs++; Request rr = new J2eeRequest(getServletConfig(), req, resp); - RequestThread w = new RequestThread(root, rr, workers, "Worker thread " + mynum); + RequestThread w = tg.respond(rr); w.start(); try { w.join(); diff --git a/src/dolda/jsvc/util/ErrorHandler.java b/src/dolda/jsvc/util/ErrorHandler.java index f1149e8..d840ee7 100644 --- a/src/dolda/jsvc/util/ErrorHandler.java +++ b/src/dolda/jsvc/util/ErrorHandler.java @@ -7,7 +7,7 @@ import java.util.logging.*; public class ErrorHandler implements Responder { private Responder next; - private static Logger logger = Logger.getLogger("jsvc.error"); + private static Logger logger = Logger.getLogger("dolda.jsvc.context"); public ErrorHandler(Responder next) { this.next = next; -- 2.11.0