atom feed5 messages in org.apache.tomcat.usersTomcat 8, 8.5 and 9 returning another...
FromSent OnAttachments
Christopher ZinnJan 8, 2017 2:04 pm 
Mark ThomasJan 9, 2017 6:29 am 
Mark ThomasJan 9, 2017 8:57 am 
Christopher ZinnJan 9, 2017 11:57 am 
Mark ThomasJan 9, 2017 12:32 pm 
Subject:Tomcat 8, 8.5 and 9 returning another apps environment with context.lookup() from a .parallelStream()
From:Christopher Zinn (chri@gmail.com)
Date:Jan 8, 2017 2:04:10 pm
List:org.apache.tomcat.users

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