ConcurrentModificationException in camel-jetty DefaultHttpBinding.doWriteResponse

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

ConcurrentModificationException in camel-jetty DefaultHttpBinding.doWriteResponse

jspyeatt
I'm running camel 2.15.2 and have been performing some load tests on a jetty consumer component with some POST requests.

My endpoint uri looks like this  
jetty:http://0.0.0.0:8080/pe-eh/v1/event?httpMethodRestrict=POST&maxThreads=200&minThreads=5

I can consistently produce the stack trace seen below without putting much load on the system (2 threads each sending a request about every 10ms).

Has anyone else seen this? I'm not seeing any real jetty uri options that I can use to tune this further.

2015-11-11 11:21:04,550 WARN  ServletHandler - /pe-eh/v1/event
java.util.ConcurrentModificationException
        at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:859)
        at java.util.ArrayList$Itr.next(ArrayList.java:831)
        at org.apache.camel.component.http.DefaultHttpBinding.doWriteResponse(DefaultHttpBinding.java:286)
        at org.apache.camel.component.http.DefaultHttpBinding.writeResponse(DefaultHttpBinding.java:231)
        at org.apache.camel.component.jetty.CamelContinuationServlet.service(CamelContinuationServlet.java:198)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
        at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:684)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1496)
        at org.apache.camel.component.jetty.CamelFilterWrapper.doFilter(CamelFilterWrapper.java:45)

Here appears to be the offending code.
    public void doWriteResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException {
        // set the status code in the response. Default is 200.
        if (message.getHeader(Exchange.HTTP_RESPONSE_CODE) != null) {
            int code = message.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class);
            response.setStatus(code);
        }
        // set the content type in the response.
        String contentType = MessageHelper.getContentType(message);
        if (contentType != null) {
            response.setContentType(contentType);
        }

        // append headers
        // must use entrySet to ensure case of keys is preserved
        for (Map.Entry<String, Object> entry : message.getHeaders().entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            // use an iterator as there can be multiple values. (must not use a delimiter)
            final Iterator<?> it = ObjectHelper.createIterator(value, null);
            while (it.hasNext()) {
                String headerValue = exchange.getContext().getTypeConverter().convertTo(String.class, it.next());
                if (headerValue != null && headerFilterStrategy != null
                        && !headerFilterStrategy.applyFilterToCamelHeaders(key, headerValue, exchange)) {
                    response.addHeader(key, headerValue);
                }
            }
        }

        // write the body.
        if (message.getBody() != null) {
            if (GZIPHelper.isGzip(message)) {
                doWriteGZIPResponse(message, response, exchange);
            } else {
                doWriteDirectResponse(message, response, exchange);
            }
        }
    }