You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2012/08/13 18:06:44 UTC

svn commit: r1372485 - in /camel/trunk/camel-core/src: main/java/org/apache/camel/builder/xml/XPathBuilder.java test/java/org/apache/camel/processor/BeanOgnMethodWithXPathInjectionTest.java

Author: davsclaus
Date: Mon Aug 13 16:06:44 2012
New Revision: 1372485

URL: http://svn.apache.org/viewvc?rev=1372485&view=rev
Log:
CAMEL-5501: Optimized XPathBuilder to cleanup thread locals after evaluation. Optimized performance under load by only using 1 thread local. Ensures better GC as well when using @XPath annotation.

Added:
    camel/trunk/camel-core/src/test/java/org/apache/camel/processor/BeanOgnMethodWithXPathInjectionTest.java
      - copied, changed from r1372409, camel/trunk/camel-core/src/test/java/org/apache/camel/processor/BeanWithXPathInjectionTest.java
Modified:
    camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java

Modified: camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java?rev=1372485&r1=1372484&r2=1372485&view=diff
==============================================================================
--- camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java (original)
+++ camel/trunk/camel-core/src/main/java/org/apache/camel/builder/xml/XPathBuilder.java Mon Aug 13 16:06:44 2012
@@ -92,8 +92,8 @@ public class XPathBuilder implements Exp
     private final Queue<XPathExpression> pool = new ConcurrentLinkedQueue<XPathExpression>();
     private final Queue<XPathExpression> poolLogNamespaces = new ConcurrentLinkedQueue<XPathExpression>();
     private final String text;
-    private final ThreadLocal<MessageVariableResolver> variableResolver = new ThreadLocal<MessageVariableResolver>();
     private final ThreadLocal<Exchange> exchange = new ThreadLocal<Exchange>();
+    private final MessageVariableResolver variableResolver = new MessageVariableResolver(exchange);
     private XPathFactory xpathFactory;
     private Class<?> documentType = Document.class;
     // For some reason the default expression of "a/b" on a document such as
@@ -133,19 +133,23 @@ public class XPathBuilder implements Exp
     }
 
     public boolean matches(Exchange exchange) {
-        // add on completion so the thread locals is removed when exchange is done
-        exchange.addOnCompletion(new XPathBuilderOnCompletion());
-
-        Object booleanResult = evaluateAs(exchange, XPathConstants.BOOLEAN);
-        return exchange.getContext().getTypeConverter().convertTo(Boolean.class, booleanResult);
+        try {
+            Object booleanResult = evaluateAs(exchange, XPathConstants.BOOLEAN);
+            return exchange.getContext().getTypeConverter().convertTo(Boolean.class, booleanResult);
+        } finally {
+            // remove the thread local after usage
+            this.exchange.remove();
+        }
     }
 
     public <T> T evaluate(Exchange exchange, Class<T> type) {
-        // add on completion so the thread locals is removed when exchange is done
-        exchange.addOnCompletion(new XPathBuilderOnCompletion());
-
-        Object result = evaluate(exchange);
-        return exchange.getContext().getTypeConverter().convertTo(type, result);
+        try {
+            Object result = evaluate(exchange);
+            return exchange.getContext().getTypeConverter().convertTo(type, result);
+        } finally {
+            // remove the thread local after usage
+            this.exchange.remove();
+        }
     }
 
     /**
@@ -165,8 +169,7 @@ public class XPathBuilder implements Exp
         try {
             return matches(dummy);
         } finally {
-            // remove the dummy from the thread local after usage
-            variableResolver.remove();
+            // remove the thread local after usage
             exchange.remove();
         }
     }
@@ -189,8 +192,7 @@ public class XPathBuilder implements Exp
         try {
             return evaluate(dummy, type);
         } finally {
-            // remove the dummy from the thread local after usage
-            variableResolver.remove();
+            // remove the thread local after usage
             exchange.remove();
         }
     }
@@ -213,9 +215,8 @@ public class XPathBuilder implements Exp
         try {
             return evaluate(dummy, String.class);
         } finally {
-            // remove the dummy from the thread local after usage
-            variableResolver.remove();
-            exchange.remove();
+            // remove the thread local after usage
+            this.exchange.remove();
         }
     }
 
@@ -1006,12 +1007,7 @@ public class XPathBuilder implements Exp
     }
 
     private MessageVariableResolver getVariableResolver() {
-        MessageVariableResolver resolver = variableResolver.get();
-        if (resolver == null) {
-            resolver = new MessageVariableResolver(exchange);
-            variableResolver.set(resolver);
-        }
-        return resolver;
+        return variableResolver;
     }
 
     public void start() throws Exception {
@@ -1052,33 +1048,4 @@ public class XPathBuilder implements Exp
         }
     }
 
-    /**
-     * On completion class which cleanup thread local resources
-     */
-    private final class XPathBuilderOnCompletion extends SynchronizationAdapter {
-
-        @Override
-        public void onDone(Exchange exchange) {
-            // when the exchange is done, then cleanup thread locals if they are still
-            // pointing to this exchange that was done
-            if (exchange.equals(XPathBuilder.this.exchange.get())) {
-                // cleanup thread locals after usage
-                XPathBuilder.this.variableResolver.remove();
-                XPathBuilder.this.exchange.remove();
-            }
-        }
-
-        @Override
-        public boolean allowHandover() {
-            // this completion should not be handed over, as we want to execute it
-            // on current thread as the thread locals is bound the current thread
-            return false;
-        }
-
-        @Override
-        public String toString() {
-            return "XPathBuilderOnCompletion";
-        }
-    }
-
 }

Copied: camel/trunk/camel-core/src/test/java/org/apache/camel/processor/BeanOgnMethodWithXPathInjectionTest.java (from r1372409, camel/trunk/camel-core/src/test/java/org/apache/camel/processor/BeanWithXPathInjectionTest.java)
URL: http://svn.apache.org/viewvc/camel/trunk/camel-core/src/test/java/org/apache/camel/processor/BeanOgnMethodWithXPathInjectionTest.java?p2=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/BeanOgnMethodWithXPathInjectionTest.java&p1=camel/trunk/camel-core/src/test/java/org/apache/camel/processor/BeanWithXPathInjectionTest.java&r1=1372409&r2=1372485&rev=1372485&view=diff
==============================================================================
--- camel/trunk/camel-core/src/test/java/org/apache/camel/processor/BeanWithXPathInjectionTest.java (original)
+++ camel/trunk/camel-core/src/test/java/org/apache/camel/processor/BeanOgnMethodWithXPathInjectionTest.java Mon Aug 13 16:06:44 2012
@@ -28,15 +28,17 @@ import org.slf4j.LoggerFactory;
 /**
  * @version 
  */
-public class BeanWithXPathInjectionTest extends ContextTestSupport {
+public class BeanOgnMethodWithXPathInjectionTest extends ContextTestSupport {
     private static final transient Logger LOG = LoggerFactory.getLogger(BeanRouteTest.class);
     protected MyBean myBean = new MyBean();
+    protected MyOtherBean myOtherBean = new MyOtherBean(myBean);
 
     public void testSendMessage() throws Exception {
         String expectedBody = "<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'><env:Body>"
                               + "<foo>bar</foo></env:Body></env:Envelope>";
 
-        template.sendBodyAndHeader("direct:in", expectedBody, "foo", "bar");
+        Object out = template.requestBodyAndHeader("direct:in", expectedBody, "foo", "bar");
+        assertEquals("bar", out);
 
         assertEquals("bean body: " + myBean, expectedBody, myBean.body);
         assertEquals("bean foo: " + myBean, "bar", myBean.foo);
@@ -47,7 +49,8 @@ public class BeanWithXPathInjectionTest 
         String expectedBody = "<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'><env:Body>"
                               + "<foo>bar</foo></env:Body></env:Envelope>";
 
-        template.sendBodyAndHeader("direct:in", expectedBody, "foo", "bar");
+        Object out = template.requestBodyAndHeader("direct:in", expectedBody, "foo", "bar");
+        assertEquals("bar", out);
 
         assertEquals("bean body: " + myBean, expectedBody, myBean.body);
         assertEquals("bean foo: " + myBean, "bar", myBean.foo);
@@ -56,7 +59,8 @@ public class BeanWithXPathInjectionTest 
         String expectedBody2 = "<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'><env:Body>"
                 + "<foo>baz</foo></env:Body></env:Envelope>";
 
-        template.sendBodyAndHeader("direct:in", expectedBody2, "foo", "baz");
+        Object out2 = template.requestBodyAndHeader("direct:in", expectedBody2, "foo", "bar");
+        assertEquals("baz", out2);
 
         assertEquals("bean body: " + myBean, expectedBody2, myBean.body);
         assertEquals("bean foo: " + myBean, "baz", myBean.foo);
@@ -66,17 +70,33 @@ public class BeanWithXPathInjectionTest 
     protected Context createJndiContext() throws Exception {
         JndiContext answer = new JndiContext();
         answer.bind("myBean", myBean);
+        answer.bind("myOtherBean", myOtherBean);
         return answer;
     }
 
     protected RouteBuilder createRouteBuilder() {
         return new RouteBuilder() {
             public void configure() {
-                from("direct:in").beanRef("myBean");
+                from("direct:in")
+                    .transform().method("myOtherBean", "doSomething.read");
             }
         };
     }
 
+    public static class MyOtherBean {
+
+        private final MyBean inner;
+
+        public MyOtherBean(MyBean inner) {
+            this.inner = inner;
+        }
+
+        public MyBean doSomething() {
+            return inner;
+        }
+
+    }
+
     public static class MyBean {
         public String body;
         public String foo;
@@ -86,10 +106,11 @@ public class BeanWithXPathInjectionTest 
             return "MyBean[foo: " + foo + " body: " + body + "]";
         }
 
-        public void read(String body, @XPath("/soap:Envelope/soap:Body/foo/text()") String foo) {
+        public String read(String body, @XPath("/soap:Envelope/soap:Body/foo/text()") String foo) {
             this.foo = foo;
             this.body = body;
             LOG.info("read() method called on " + this);
+            return foo;
         }
     }
 }