Author: raulk
Date: Sun Oct 21 21:47:11 2012
New Revision: 1400729
URL: http://svn.apache.org/viewvc?rev=1400729&view=rev
Log:
Fixed CAMEL-5722 Classloader mixup when consumers across bundles share the same
camel-jetty port
Added:
camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/JettyClassloaderCheckProcessor.java
camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/OSGiJettyCamelContextsClassloaderTest.java
camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext1.xml
camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext2.xml
Modified:
camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/CamelServlet.java
camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
Modified:
camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/CamelServlet.java
URL:
http://svn.apache.org/viewvc/camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/CamelServlet.java?rev=1400729&r1=1400728&r2=1400729&view=diff
==============================================================================
---
camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/CamelServlet.java
(original)
+++
camel/trunk/components/camel-http/src/main/java/org/apache/camel/component/http/CamelServlet.java
Sun Oct 21 21:47:11 2012
@@ -154,4 +154,43 @@ public class CamelServlet extends HttpSe
this.servletName = servletName;
}
+ /**
+ * Override the Thread Context ClassLoader if need be.
+ * @param exchange
+ * @return old classloader if overridden; otherwise returns null
+ */
+ protected ClassLoader overrideTccl(final Exchange exchange) {
+ ClassLoader oldClassLoader =
Thread.currentThread().getContextClassLoader();
+ ClassLoader appCtxCl =
exchange.getContext().getApplicationContextClassLoader();
+ if (oldClassLoader == null || appCtxCl == null) {
+ return null;
+ }
+
+ if (!oldClassLoader.equals(appCtxCl)) {
+ Thread.currentThread().setContextClassLoader(appCtxCl);
+ if (log.isTraceEnabled()) {
+ log.trace("Overrode TCCL for exchangeId {} to {} on thread
{}",
+ new Object[] {exchange.getExchangeId(), appCtxCl,
Thread.currentThread().getName()});
+ }
+ return oldClassLoader;
+ }
+ return null;
+ }
+
+ /**
+ * Restore the Thread Context ClassLoader if the Old TCCL is not null.
+ * @param exchange
+ * @param oldTccl
+ */
+ protected void restoreTccl(final Exchange exchange, ClassLoader oldTccl) {
+ if (oldTccl == null) {
+ return;
+ }
+ Thread.currentThread().setContextClassLoader(oldTccl);
+ if (log.isTraceEnabled()) {
+ log.trace("Restored TCCL for exchangeId {} to {} on thread {}",
+ new String[] {exchange.getExchangeId(),
oldTccl.toString(), Thread.currentThread().getName()});
+ }
+ }
+
}
Modified:
camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
URL:
http://svn.apache.org/viewvc/camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java?rev=1400729&r1=1400728&r2=1400729&view=diff
==============================================================================
---
camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
(original)
+++
camel/trunk/components/camel-jetty/src/main/java/org/apache/camel/component/jetty/CamelContinuationServlet.java
Sun Oct 21 21:47:11 2012
@@ -115,8 +115,11 @@ public class CamelContinuationServlet ex
// must suspend before we process the exchange
continuation.suspend();
+ ClassLoader oldTccl = overrideTccl(exchange);
+
log.trace("Processing request for exchangeId: {}",
exchange.getExchangeId());
// use the asynchronous API to process the exchange
+
consumer.getAsyncProcessor().process(exchange, new AsyncCallback()
{
public void done(boolean doneSync) {
// check if the exchange id is already expired
@@ -132,6 +135,10 @@ public class CamelContinuationServlet ex
}
});
+ if (oldTccl != null) {
+ restoreTccl(exchange, oldTccl);
+ }
+
// return to let Jetty continuation to work as it will resubmit
and invoke the service
// method again when its resumed
return;
Added:
camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/JettyClassloaderCheckProcessor.java
URL:
http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/JettyClassloaderCheckProcessor.java?rev=1400729&view=auto
==============================================================================
---
camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/JettyClassloaderCheckProcessor.java
(added)
+++
camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/JettyClassloaderCheckProcessor.java
Sun Oct 21 21:47:11 2012
@@ -0,0 +1,31 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.itest.osgi.jetty;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.Processor;
+
+public class JettyClassloaderCheckProcessor implements Processor {
+
+ public void process(Exchange exchange) throws Exception {
+ ClassLoader contextCl =
exchange.getContext().getApplicationContextClassLoader();
+ ClassLoader tccl = Thread.currentThread().getContextClassLoader();
+ String classloaders = contextCl.equals(tccl) + " --- " + contextCl + "
--- " + tccl;
+ exchange.getOut().setBody(classloaders);
+ }
+
+}
Added:
camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/OSGiJettyCamelContextsClassloaderTest.java
URL:
http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/OSGiJettyCamelContextsClassloaderTest.java?rev=1400729&view=auto
==============================================================================
---
camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/OSGiJettyCamelContextsClassloaderTest.java
(added)
+++
camel/trunk/tests/camel-itest-osgi/src/test/java/org/apache/camel/itest/osgi/jetty/OSGiJettyCamelContextsClassloaderTest.java
Sun Oct 21 21:47:11 2012
@@ -0,0 +1,88 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.itest.osgi.jetty;
+
+import org.apache.camel.itest.osgi.OSGiIntegrationTestSupport;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.Configuration;
+import org.ops4j.pax.exam.junit.JUnit4TestRunner;
+import org.ops4j.pax.swissbox.tinybundles.dp.Constants;
+
+import static org.ops4j.pax.exam.CoreOptions.provision;
+import static org.ops4j.pax.exam.OptionUtils.combine;
+import static org.ops4j.pax.swissbox.tinybundles.core.TinyBundles.newBundle;
+
+/**
+ * CAMEL-5722: Test to verify that routes sitting in different bundles but
listening on the same Jetty port,
+ * and thus, sharing the same container-wide Jetty Connector, do not share the
classloader. The TCCL should
+ * be different in each case, as for each route it should be the Classloader
of their containing bundle.
+ */
+@RunWith(JUnit4TestRunner.class)
+public class OSGiJettyCamelContextsClassloaderTest extends
OSGiIntegrationTestSupport {
+
+ @Test
+ public void testClassloadersAreCongruent() throws Exception {
+ // Wait a while to let all the service started
+ Thread.sleep(3000);
+ // test context 1
+ String endpointURI1 = "http://localhost:9010/camel-context-1/";
+ String response1 = template.requestBody(endpointURI1, "Hello World",
String.class);
+ System.out.println("Response from Context 1: " + response1);
+ assertEquals("Camel Context 1 classloaders unequal", "true",
response1.split(" --- ")[0]);
+
+ // test context 2
+ String endpointURI2 = "http://localhost:9010/camel-context-2/";
+ String response2 = template.requestBody(endpointURI2, "Hello World",
String.class);
+ System.out.println("Response from Context 2: " + response2);
+ assertEquals("Camel Context 2 classloaders unequal", "true",
response2.split(" --- ")[0]);
+
+ // contexts's both classloaders toString() representation must contain
the bundle symbolic ID
+ // definition of "both classloaders": the Camel Context classloader
and the Thread classloader during processing
+
assertTrue(response1.matches(".*CamelContextBundle1.*CamelContextBundle1.*"));
+
assertTrue(response2.matches(".*CamelContextBundle2.*CamelContextBundle2.*"));
+
+ }
+
+ @Configuration
+ public static Option[] configure() {
+ Option[] options = combine(
+ getDefaultCamelKarafOptions(),
+ // using the features to install the other camel components
+ loadCamelFeatures("camel-jetty"),
+ //set up the camel context bundle1
+
provision(newBundle().add("META-INF/spring/Classloader-CamelContext1.xml",
OSGiJettyCamelContextsClassloaderTest.class.getResource("Classloader-CamelContext1.xml"))
+ .add(JettyClassloaderCheckProcessor.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME,
"org.apache.camel.itest.osgi.CamelContextBundle1")
+ .set(Constants.BUNDLE_NAME, "CamelContext1")
+ .set(Constants.DYNAMICIMPORT_PACKAGE, "*")
+ .build()),
+
+ //set up the camel context bundle1
+
provision(newBundle().add("META-INF/spring/Classloader-CamelContext2.xml",
OSGiJettyCamelContextsClassloaderTest.class.getResource("Classloader-CamelContext2.xml"))
+ .add(JettyClassloaderCheckProcessor.class)
+ .set(Constants.BUNDLE_SYMBOLICNAME,
"org.apache.camel.itest.osgi.CamelContextBundle2")
+ .set(Constants.BUNDLE_NAME, "CamelContext2")
+ .set(Constants.DYNAMICIMPORT_PACKAGE, "*")
+ .build()));
+
+ return options;
+ }
+
+
+}
Added:
camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext1.xml
URL:
http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext1.xml?rev=1400729&view=auto
==============================================================================
---
camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext1.xml
(added)
+++
camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext1.xml
Sun Oct 21 21:47:11 2012
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:camel="http://camel.apache.org/schema/spring"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+ <bean id="jettyProcessor"
class="org.apache.camel.itest.osgi.jetty.JettyClassloaderCheckProcessor" />
+
+ <camelContext id="camelContext1"
xmlns="http://camel.apache.org/schema/spring">
+ <camel:route>
+ <camel:from uri="jetty:http://0.0.0.0:9010/camel-context-1/"/>
+ <camel:process ref="jettyProcessor"/>
+ </camel:route>
+ </camelContext>
+
+</beans>
Added:
camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext2.xml
URL:
http://svn.apache.org/viewvc/camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext2.xml?rev=1400729&view=auto
==============================================================================
---
camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext2.xml
(added)
+++
camel/trunk/tests/camel-itest-osgi/src/test/resources/org/apache/camel/itest/osgi/jetty/Classloader-CamelContext2.xml
Sun Oct 21 21:47:11 2012
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:camel="http://camel.apache.org/schema/spring"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
+
+ <bean id="jettyProcessor"
class="org.apache.camel.itest.osgi.jetty.JettyClassloaderCheckProcessor" />
+
+ <camelContext id="camelContext2"
xmlns="http://camel.apache.org/schema/spring">
+ <camel:route>
+ <camel:from uri="jetty:http://0.0.0.0:9010/camel-context-2/"/>
+ <camel:process ref="jettyProcessor"/>
+ </camel:route>
+ </camelContext>
+
+</beans>