Hello all,
   This is my first time posting to a mailing list so hopefully I'm doing
this correctly.

   We are running into an issue where we have multiple copies of the same
WAR loaded on a Tomcat instance each with its own context.xml.
The initial problem I was trying to diagnose was A JNDI lookup to a
Connection Pool in one of the WARs was returning the connection pool of one
of the others.
The problem only happens when the JNDI lookup is performed within a
parallelStream().

   I was able to produce a very simple WAR with a single servlet and a
context XML to reproduce the problem I'm having (See below).

   If you run the servlet from the first application, it works correctly.
You will see that it only ever looks up 'Test 1'.
When I run the servlet from the second application it will only return Test
1 in the first part (stream()) but a mix of 'Test 1' and 'Test 2' in the
parallelStream() part.

   Thanks in advance for any advice or comments to our issue.

-----------------------------------------------
My Environment:  (The problem happens to us on our CENTOS Linux
environments as well)
Server version: Apache Tomcat/8.5.9
Server built:   Dec 5 2016 20:18:12 UTC
Server number:  8.5.9.0
OS Name:        Windows 10
OS Version:     10.0
Architecture:   amd64
JVM Version:    1.8.0_111-b14
JVM Vendor:     Oracle Corporation

Runtime.getRuntime().availableProcessors() returns 12 on my machine.
CPU: Intel i7-5820K


My Test Servlet:
@WebServlet(urlPatterns = "/test")
public final class MyServlet extends HttpServlet
{
    private static List<Integer> someNumbers = generateNonsense();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException
    {
        StringBuilder answerBuilder = new StringBuilder();

        // This should be okay.
        someNumbers.stream().forEach( number ->
        {
            answerBuilder.append(".stream() Looked up ")
                    .append(lookupEnvironmentValue())
                    .append("<br/>");
        });

         // This is most likely bad
        someNumbers.parallelStream().forEach( number ->
        {
            synchronized (MyServlet.class)
            {
                answerBuilder.append(".parallelStream() Looked up ")
                        .append(lookupEnvironmentValue())
                        .append("<br/>");
            }
        });

        response.setContentType("text/html");
        response.getWriter().write(answerBuilder.toString());
    }

    private String lookupEnvironmentValue()
    {
        try
        {
            Context context = new InitialContext();
            return (String) context.lookup("java:comp/env/testName");
        }
        catch(NamingException e)
        {
            e.printStackTrace();
            return e.getMessage();
        }
    }

    private static List<Integer> generateNonsense()
    {
        List<Integer> nonsense = new ArrayList<>();
        for(int n=0; n<1000; n++)
            nonsense.add(n);

        return nonsense;
    }
}


My test context.xml
<Context path="/test1">
    <Environment name="testName" value="Test 1"  type="java.lang.String"
override="false"/>
</Context>


Preparing Tomcat:
Step 1: Download the core.zip of Tomcat 8, 8.5 or 9
Step 2: create a apache-tomcat-8.5.9/conf/Catalina/localhost directory
Step 3: create two files in this directory with the contents of my
context.xml: test1.xml and test2.xml and change the value and path in the
second one to '2'
Step 4: Create a WAR with just the sample servlet I have here. and then
drop them in apache-tomcat-8.5.9/webapps directory / call them test1.war
and test2.war
Step 5: Go into apache-tomcat-8.5.9/bin and catalina start to start it up.

The urls to test for me are:
http://localhost:8080/test1/test
http://localhost:8080/test2/test

Reply via email to