Author: dkulp
Date: Mon Mar 17 10:44:57 2008
New Revision: 637990
URL: http://svn.apache.org/viewvc?rev=637990&view=rev
Log:
[CXF-1410] Allow proxies to be configured such that the request context is
thread local like the response context
Added:
incubator/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxws/JaxWsClientThreadTest.java
(with props)
Modified:
incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java
incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsProxyFactoryBean.java
incubator/cxf/trunk/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/JaxWsClientTest.java
Modified:
incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java
URL:
http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java?rev=637990&r1=637989&r2=637990&view=diff
==============================================================================
---
incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java
(original)
+++
incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsClientProxy.java
Mon Mar 17 10:44:57 2008
@@ -25,6 +25,7 @@
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;
import java.util.logging.Logger;
@@ -59,10 +60,44 @@
public class JaxWsClientProxy extends org.apache.cxf.frontend.ClientProxy
implements
InvocationHandler, BindingProvider {
+
+ /*
+ * modification are echoed back to the shared map
+ */
+ public static class EchoContext extends HashMap<String, Object> {
+ final Map<String, Object> shared;
+ public EchoContext(Map<String, Object> sharedMap) {
+ super(sharedMap);
+ shared = sharedMap;
+ }
+
+ public Object put(String key, Object value) {
+ shared.put(key, value);
+ return super.put(key, value);
+ }
+
+ public void putAll(Map<? extends String, ? extends Object> t) {
+ shared.putAll(t);
+ super.putAll(t);
+ }
+
+ public Object remove(Object key) {
+ shared.remove(key);
+ return super.remove(key);
+ }
+
+ public void reload() {
+ super.clear();
+ super.putAll(shared);
+ }
+ }
+ public static final String THREAD_LOCAL_REQUEST_CONTEXT =
"thread.local.request.context";
private static final Logger LOG =
LogUtils.getL7dLogger(JaxWsClientProxy.class);
- protected Map<String, Object> requestContext = new
ConcurrentHashMap<String, Object>();
+ protected Map<String, Object> currentRequestContext = new
ConcurrentHashMap<String, Object>();
+ protected ThreadLocal <EchoContext> requestContext =
+ new ThreadLocal<EchoContext>();
protected ThreadLocal <Map<String, Object>> responseContext =
new ThreadLocal<Map<String, Object>>();
@@ -80,8 +115,8 @@
private void setupEndpointAddressContext(Endpoint endpoint) {
// NOTE for jms transport the address would be null
if (null != endpoint && null !=
endpoint.getEndpointInfo().getAddress()) {
- getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
- endpoint.getEndpointInfo().getAddress());
+
currentRequestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
+ endpoint.getEndpointInfo().getAddress());
}
}
@@ -232,19 +267,47 @@
}
}
+ public boolean isThreadLocalRequestContext() {
+ if (currentRequestContext.containsKey(THREAD_LOCAL_REQUEST_CONTEXT)) {
+ Object o = currentRequestContext.get(THREAD_LOCAL_REQUEST_CONTEXT);
+ boolean local = false;
+ if (o instanceof Boolean) {
+ local = ((Boolean)o).booleanValue();
+ } else {
+ local = Boolean.parseBoolean(o.toString());
+ }
+ return local;
+ }
+ return false;
+ }
+ public void setThreadLocalRequestContext(boolean b) {
+ currentRequestContext.put(THREAD_LOCAL_REQUEST_CONTEXT, b);
+ }
+
private Map<String, Object> getRequestContextCopy() {
Map<String, Object> realMap = new HashMap<String, Object>();
WrappedMessageContext ctx = new WrappedMessageContext(realMap,
Scope.APPLICATION);
- for (Map.Entry<String, Object> ent : requestContext.entrySet()) {
- ctx.put(ent.getKey(), ent.getValue());
+ // thread local contexts reflect currentRequestContext as of
+ // last call to getRequestContext()
+ if (isThreadLocalRequestContext()
+ && null != requestContext.get()) {
+ ctx.putAll(requestContext.get());
+ } else {
+ ctx.putAll(currentRequestContext);
}
return realMap;
}
-
+
public Map<String, Object> getRequestContext() {
- return requestContext;
+ if (isThreadLocalRequestContext()) {
+ if (null == requestContext.get()) {
+ requestContext.set(new EchoContext(currentRequestContext));
+ }
+ return requestContext.get();
+ }
+ return currentRequestContext;
}
public Map<String, Object> getResponseContext() {
Modified:
incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsProxyFactoryBean.java
URL:
http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsProxyFactoryBean.java?rev=637990&r1=637989&r2=637990&view=diff
==============================================================================
---
incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsProxyFactoryBean.java
(original)
+++
incubator/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/JaxWsProxyFactoryBean.java
Mon Mar 17 10:44:57 2008
@@ -66,6 +66,7 @@
protected ClientProxy clientClientProxy(Client c) {
JaxWsClientProxy cp = new JaxWsClientProxy(c,
((JaxWsEndpointImpl)c.getEndpoint()).getJaxwsBinding());
+ cp.getRequestContext().putAll(this.getProperties());
buildHandlerChain(cp);
return cp;
}
Modified:
incubator/cxf/trunk/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/JaxWsClientTest.java
URL:
http://svn.apache.org/viewvc/incubator/cxf/trunk/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/JaxWsClientTest.java?rev=637990&r1=637989&r2=637990&view=diff
==============================================================================
---
incubator/cxf/trunk/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/JaxWsClientTest.java
(original)
+++
incubator/cxf/trunk/rt/frontend/jaxws/src/test/java/org/apache/cxf/jaxws/JaxWsClientTest.java
Mon Mar 17 10:44:57 2008
@@ -106,6 +106,43 @@
}
@Test
+ public void testRequestContextPutAndRemoveEcho() throws Exception {
+ URL url = getClass().getResource("/wsdl/hello_world.wsdl");
+ javax.xml.ws.Service s = javax.xml.ws.Service
+ .create(url, serviceName);
+ Greeter greeter = s.getPort(portName, Greeter.class);
+ final InvocationHandler handler = Proxy.getInvocationHandler(greeter);
+
+ Map<String, Object> requestContext =
((BindingProvider)handler).getRequestContext();
+ requestContext.put(JaxWsClientProxy.THREAD_LOCAL_REQUEST_CONTEXT,
Boolean.TRUE);
+
+ //re-get the context so it's not a thread safe variant
+ requestContext = ((BindingProvider)handler).getRequestContext();
+
+ final String key = "Hi";
+
+ requestContext.put(key, "ho");
+
+ final Object[] result = new Object[2];
+ Thread t = new Thread() {
+ public void run() {
+ Map<String, Object> requestContext =
((BindingProvider)handler).getRequestContext();
+ result[0] = requestContext.get(key);
+ requestContext.remove(key);
+ result[1] = requestContext.get(key);
+ }
+ };
+ t.start();
+ t.join();
+
+ assertEquals("thread sees the put", "ho", result[0]);
+ assertNull("thread did not remove the put", result[1]);
+
+ assertEquals("main thread does not see removal",
+ "ho", requestContext.get(key));
+ }
+
+ @Test
public void testEndpoint() throws Exception {
ReflectionServiceFactoryBean bean = new JaxWsServiceFactoryBean();
URL resource = getClass().getResource("/wsdl/hello_world.wsdl");
Added:
incubator/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxws/JaxWsClientThreadTest.java
URL:
http://svn.apache.org/viewvc/incubator/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxws/JaxWsClientThreadTest.java?rev=637990&view=auto
==============================================================================
---
incubator/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxws/JaxWsClientThreadTest.java
(added)
+++
incubator/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxws/JaxWsClientThreadTest.java
Mon Mar 17 10:44:57 2008
@@ -0,0 +1,121 @@
+/**
+ * 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.cxf.systest.jaxws;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+import javax.xml.ws.BindingProvider;
+import javax.xml.ws.soap.SOAPFaultException;
+
+import org.apache.cxf.jaxws.JaxWsClientProxy;
+import org.apache.cxf.test.AbstractCXFTest;
+import org.apache.hello_world_soap_http.Greeter;
+import org.junit.Test;
+
+public class JaxWsClientThreadTest extends AbstractCXFTest {
+
+ private final QName serviceName = new
QName("http://apache.org/hello_world_soap_http", "SOAPService");
+ private final QName portName = new
QName("http://apache.org/hello_world_soap_http", "SoapPort");
+
+ @Test
+ public void testRequestContextThreadSafety() throws Throwable {
+
+ URL url = getClass().getResource("/wsdl/hello_world.wsdl");
+ javax.xml.ws.Service s = javax.xml.ws.Service.create(url, serviceName);
+ final Greeter greeter = s.getPort(portName, Greeter.class);
+ final InvocationHandler handler = Proxy.getInvocationHandler(greeter);
+
+
((BindingProvider)handler).getRequestContext().put(JaxWsClientProxy.THREAD_LOCAL_REQUEST_CONTEXT,
+ Boolean.TRUE);
+
+ Map<String, Object> requestContext =
((BindingProvider)handler).getRequestContext();
+
+ String address =
(String)requestContext.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
+
+ final Throwable errorHolder[] = new Throwable[1];
+
+ Runnable r = new Runnable() {
+ public void run() {
+ try {
+ final String protocol = "http-" +
Thread.currentThread().getId();
+ for (int i = 0; i < 70; i++) {
+ String threadSpecificaddress = protocol +
"://localhost:80/" + i;
+ Map<String, Object> requestContext =
((BindingProvider)handler)
+ .getRequestContext();
+
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
+ threadSpecificaddress);
+ assertEquals("we get what we set",
threadSpecificaddress, requestContext
+
.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY));
+ try {
+ greeter.greetMe("Hi");
+ } catch (SOAPFaultException expected) {
+ //expected.getCause().printStackTrace();
+ MalformedURLException mue =
(MalformedURLException)expected
+ .getCause().getCause();
+ assertTrue("protocol contains thread id from
context", mue.getMessage()
+ .indexOf(protocol) != 0);
+ }
+
+
requestContext.remove(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
+ assertTrue("property is null", requestContext
+
.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY) == null);
+
+ }
+ } catch (Throwable t) {
+ // capture assert failures
+ errorHolder[0] = t;
+ }
+ }
+ };
+
+ final int numThreads = 5;
+ Thread[] threads = new Thread[numThreads];
+ for (int i = 0; i < numThreads; i++) {
+ threads[i] = new Thread(r);
+ }
+ for (int i = 0; i < numThreads; i++) {
+ threads[i].start();
+ }
+ for (int i = 0; i < numThreads; i++) {
+ threads[i].join();
+ }
+ if (errorHolder[0] != null) {
+ throw errorHolder[0];
+ }
+
+ // main thread contextValues are un changed
+ assertTrue("address from existing context has not changed",
address.equals(requestContext
+ .get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY)));
+
+ // get the latest values
+ ((JaxWsClientProxy.EchoContext)requestContext).reload();
+ assertTrue("address is different", !address.equals(requestContext
+ .get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY)));
+ // verify value reflects what other threads were doing
+ assertTrue("property is null from last thread execution",
requestContext
+ .get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY) == null);
+ }
+}
+
Propchange:
incubator/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxws/JaxWsClientThreadTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
incubator/cxf/trunk/systests/src/test/java/org/apache/cxf/systest/jaxws/JaxWsClientThreadTest.java
------------------------------------------------------------------------------
svn:keywords = Rev Date