From 4f6bba1ec05f5458dd81d5b00ec9599f940977d6 Mon Sep 17 00:00:00 2001 From: markt Date: Thu, 30 Jun 2011 11:58:36 +0000 Subject: [PATCH] Improve the handling for Servlets that implement the deprecated SingleThreadModel when embedding Tomcat. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@1141495 13f79535-47bb-0310-9956-ffa450edef68 --- java/org/apache/catalina/startup/Tomcat.java | 30 ++++++++-- .../apache/catalina/core/TestStandardWrapper.java | 68 ++++++++++++++++++++-- webapps/docs/changelog.xml | 4 ++ 3 files changed, 92 insertions(+), 10 deletions(-) diff --git a/java/org/apache/catalina/startup/Tomcat.java b/java/org/apache/catalina/startup/Tomcat.java index 7004e3b73..2281ae98f 100644 --- a/java/org/apache/catalina/startup/Tomcat.java +++ b/java/org/apache/catalina/startup/Tomcat.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Stack; import java.util.logging.Level; import java.util.logging.Logger; @@ -812,18 +813,35 @@ public class Tomcat { public static class ExistingStandardWrapper extends StandardWrapper { private Servlet existing; boolean init = false; - + + @SuppressWarnings("deprecation") public ExistingStandardWrapper( Servlet existing ) { this.existing = existing; + if (existing instanceof javax.servlet.SingleThreadModel) { + singleThreadModel = true; + instancePool = new Stack(); + } } @Override public synchronized Servlet loadServlet() throws ServletException { - if (!init) { - existing.init(facade); - init = true; + if (singleThreadModel) { + Servlet instance; + try { + instance = existing.getClass().newInstance(); + } catch (InstantiationException e) { + throw new ServletException(e); + } catch (IllegalAccessException e) { + throw new ServletException(e); + } + instance.init(facade); + return instance; + } else { + if (!init) { + existing.init(facade); + init = true; + } + return existing; } - return existing; - } @Override public long getAvailable() { diff --git a/test/org/apache/catalina/core/TestStandardWrapper.java b/test/org/apache/catalina/core/TestStandardWrapper.java index e1f4d3418..795e63fea 100644 --- a/test/org/apache/catalina/core/TestStandardWrapper.java +++ b/test/org/apache/catalina/core/TestStandardWrapper.java @@ -21,9 +21,11 @@ import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.CountDownLatch; import javax.servlet.Servlet; import javax.servlet.ServletConfig; @@ -329,6 +331,8 @@ public class TestStandardWrapper extends TomcatBaseTest { } + public static final int BUG51445_THREAD_COUNT = 5; + public void testBug51445() throws Exception { Tomcat tomcat = getTomcatInstance(); @@ -341,29 +345,85 @@ public class TestStandardWrapper extends TomcatBaseTest { tomcat.start(); - ByteChunk res = getUrl("http://localhost:" + getPort() + "/"); + // Start the threads + Bug51445Thread[] threads = new Bug51445Thread[5]; + for (int i = 0; i < BUG51445_THREAD_COUNT; i ++) { + threads[i] = new Bug51445Thread(getPort()); + threads[i].start(); + } + + // Wait for threads to finish + for (int i = 0; i < BUG51445_THREAD_COUNT; i ++) { + threads[i].join(); + } + + Set servlets = new HashSet(); + // Check the result + for (int i = 0; i < BUG51445_THREAD_COUNT; i ++) { + String[] results = threads[i].getResult().split(","); + assertEquals(2, results.length); + assertEquals("10", results[0]); + System.out.println(results[1]); + assertFalse(servlets.contains(results[1])); + servlets.add(results[1]); + } - assertEquals("10", res.toString()); } + private static class Bug51445Thread extends Thread { + + private int port; + private String result; + + public Bug51445Thread(int port) { + this.port = port; + } + + @Override + public void run() { + try { + ByteChunk res = getUrl("http://localhost:" + port + "/"); + result = res.toString(); + } catch (IOException ioe) { + result = ioe.getMessage(); + } + } + + public String getResult() { + return result; + } + } /** * SingleThreadModel servlet that sets a value in the init() method. */ @SuppressWarnings("deprecation") - private static class Bug51445Servlet extends HttpServlet + public static class Bug51445Servlet extends HttpServlet implements javax.servlet.SingleThreadModel { private static final long serialVersionUID = 1L; + private static final CountDownLatch latch = + new CountDownLatch(BUG51445_THREAD_COUNT); + private int data = 0; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - + + // Ensure all threads have their own instance of the servlet + latch.countDown(); + try { + latch.await(); + } catch (InterruptedException e) { + // Ignore + } + resp.setContentType("text/plain"); resp.getWriter().print(data); + resp.getWriter().print(","); + resp.getWriter().print(hashCode()); } @Override diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 6a0ea14ea..b5481e71d 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -172,6 +172,10 @@ the target Servlet does not call startAsync() or complete() that Tomcat calls complete() once the target Servlet exits. (markt) + + Improve the handling for Servlets that implement the deprecated + SingleThreadModel when embedding Tomcat. (markt) + -- 2.11.0