/**
* 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.jaxws;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.xml.namespace.QName;
import javax.xml.transform.dom.DOMSource;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.Dispatch;
import javax.xml.ws.WebServiceException;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.endpoint.ClientImpl;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.interceptor.Fault;
import org.apache.cxf.jaxws.support.JaxWsEndpointImpl;
import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
import org.apache.cxf.message.Message;
import org.apache.cxf.phase.AbstractPhaseInterceptor;
import org.apache.cxf.phase.Phase;
import org.apache.cxf.service.Service;
import org.apache.cxf.service.invoker.BeanInvoker;
import org.apache.cxf.service.model.BindingOperationInfo;
import org.apache.cxf.service.model.EndpointInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.transport.Destination;
import org.apache.cxf.wsdl.service.factory.ReflectionServiceFactoryBean;
import org.apache.hello_world_soap_http.BadRecordLitFault;
import org.apache.hello_world_soap_http.Greeter;
import org.apache.hello_world_soap_http.GreeterImpl;
import org.junit.Before;
import org.junit.Test;
public class JaxWsClientTest extends AbstractJaxWsTest {
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");
private final String address = "http://localhost:9000/SoapContext/SoapPort";
private Destination d;
@Before
public void setUp() throws Exception {
super.setUpBus();
EndpointInfo ei = new EndpointInfo(null, "http://schemas.xmlsoap.org/soap/http");
ei.setAddress(address);
d = localTransport.getDestination(ei, bus);
}
@Test
public void testCreate() throws Exception {
javax.xml.ws.Service s = javax.xml.ws.Service
.create(new QName("http://apache.org/hello_world_soap_http", "SoapPort"));
assertNotNull(s);
try {
s = javax.xml.ws.Service.create(new URL("file:/does/not/exist.wsdl"),
new QName("http://apache.org/hello_world_soap_http", "SoapPort"));
fail("did not throw exception");
} catch (WebServiceException sce) {
// ignore, this is expected
}
}
@Test
public void testRequestContext() 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);
InvocationHandler handler = Proxy.getInvocationHandler(greeter);
BindingProvider bp = null;
if (handler instanceof BindingProvider) {
bp = (BindingProvider)handler;
//System.out.println(bp.toString());
Map<String, Object> requestContext = bp.getRequestContext();
String reqAddr =
(String)requestContext.get(BindingProvider.ENDPOINT_ADDRESS_PROPERTY);
assertEquals("the address get from requestContext is not equal",
address, reqAddr);
} else {
fail("can't get the requset context");
}
}
@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);
final Greeter handler = s.getPort(portName, Greeter.class);
Map<String, Object> requestContext = ((BindingProvider)handler).getRequestContext();
requestContext.put(JaxWsClientProxy.THREAD_LOCAL_REQUEST_CONTEXT, Boolean.TRUE);
// future calls to getRequestContext() will use a thread local request context.
// That allows the request context to be threadsafe.
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() {
//requestContext in main thread shouldn't affect the requestContext in this thread
Map<String, Object> requestContext = ((BindingProvider)handler).getRequestContext();
result[0] = requestContext.get(key);
requestContext.remove(key);
result[1] = requestContext.get(key);
}
};
t.start();
t.join();
assertNull("thread shouldn't see the put", 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 testRequestContextPutAndRemoveEchoDispatch() throws Exception {
URL url = getClass().getResource("/wsdl/hello_world.wsdl");
javax.xml.ws.Service s = javax.xml.ws.Service
.create(url, serviceName);
final Dispatch<DOMSource> disp = s.createDispatch(portName, DOMSource.class,
javax.xml.ws.Service.Mode.PAYLOAD);
Map<String, Object> requestContext = disp.getRequestContext();
requestContext.put(JaxWsClientProxy.THREAD_LOCAL_REQUEST_CONTEXT, Boolean.TRUE);
// future calls to getRequestContext() will use a thread local request context.
// That allows the request context to be threadsafe.
requestContext = disp.getRequestContext();
final String key = "Hi";
requestContext.put(key, "ho");
final Object[] result = new Object[2];
Thread t = new Thread() {
public void run() {
//requestContext in main thread shouldn't affect the requestContext in this thread
Map<String, Object> requestContext = disp.getRequestContext();
result[0] = requestContext.get(key);
requestContext.remove(key);
result[1] = requestContext.get(key);
}
};
t.start();
t.join();
assertNull("thread shouldn't see the put", 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 testThreadLocalRequestContextIsIsolated() throws InterruptedException {
URL url = getClass().getResource("/wsdl/hello_world.wsdl");
javax.xml.ws.Service s = javax.xml.ws.Service.create(url, serviceName);
final Greeter handler = s.getPort(portName, Greeter.class);
final AtomicBoolean isPropertyAPresent = new AtomicBoolean(false);
// Makes request context thread local
ClientProxy.getClient(handler).setThreadLocalRequestContext(true);
// PropertyA should be added to the request context of current thread only
ClientProxy.getClient(handler).getRequestContext().put("PropertyA", "PropertyAVal");
Runnable checkRequestContext = new Runnable() {
@Override
public void run() {
if (ClientProxy.getClient(handler).getRequestContext().containsKey("PropertyA")) {
isPropertyAPresent.set(true);
}
}
};
Thread thread = new Thread(checkRequestContext);
thread.start();
thread.join(60000);
assertFalse("If we have per thread isolation propertyA should be not present in the context of another thread.",
isPropertyAPresent.get());
}
@Test
public void testEndpoint() throws Exception {
ReflectionServiceFactoryBean bean = new JaxWsServiceFactoryBean();
URL resource = getClass().getResource("/wsdl/hello_world.wsdl");
assertNotNull(resource);
bean.setWsdlURL(resource.toString());
bean.setBus(getBus());
bean.setServiceClass(GreeterImpl.class);
GreeterImpl greeter = new GreeterImpl();
BeanInvoker invoker = new BeanInvoker(greeter);
bean.setInvoker(invoker);
Service service = bean.create();
String namespace = "http://apache.org/hello_world_soap_http";
EndpointInfo ei = service.getServiceInfos().get(0).getEndpoint(new QName(namespace, "SoapPort"));
JaxWsEndpointImpl endpoint = new JaxWsEndpointImpl(getBus(), service, ei);
ClientImpl client = new ClientImpl(getBus(), endpoint);
BindingOperationInfo bop = ei.getBinding().getOperation(new QName(namespace, "sayHi"));
assertNotNull(bop);
bop = bop.getUnwrappedOperation();
assertNotNull(bop);
MessagePartInfo part = bop.getOutput().getMessageParts().get(0);
assertEquals(0, part.getIndex());
d.setMessageObserver(new MessageReplayObserver("sayHiResponse.xml"));
Object ret[] = client.invoke(bop, new Object[] {"hi"}, null);
assertNotNull(ret);
assertEquals("Wrong number of return objects", 1, ret.length);
// test fault handling
bop = ei.getBinding().getOperation(new QName(namespace, "testDocLitFault"));
bop = bop.getUnwrappedOperation();
d.setMessageObserver(new MessageReplayObserver("testDocLitFault.xml"));
try {
client.invoke(bop, new Object[] {"BadRecordLitFault"}, null);
fail("Should have returned a fault!");
} catch (BadRecordLitFault fault) {
assertEquals("foo", fault.getFaultInfo().trim());
assertEquals("Hadrian did it.", fault.getMessage());
}
try {
client.getEndpoint().getOutInterceptors().add(new NestedFaultThrower());
client.getEndpoint().getOutInterceptors().add(new FaultThrower());
client.invoke(bop, new Object[] {"BadRecordLitFault"}, null);
fail("Should have returned a fault!");
} catch (Fault fault) {
assertEquals(true, fault.getMessage().indexOf("Foo") >= 0);
}
client.close();
}
public static class NestedFaultThrower extends AbstractPhaseInterceptor<Message> {
public NestedFaultThrower() {
super(Phase.PRE_LOGICAL);
addBefore(FaultThrower.class.getName());
}
public void handleMessage(Message message) throws Fault {
boolean result = message.getInterceptorChain().doIntercept(message);
assertEquals("doIntercept not return false", result, false);
assertNotNull(message.getContent(Exception.class));
throw new Fault(message.getContent(Exception.class));
}
}
@Test
public void testClientProxyFactory() {
JaxWsProxyFactoryBean cf = new JaxWsProxyFactoryBean();
cf.setAddress("http://localhost:9000/test");
Greeter greeter = cf.create(Greeter.class);
/* .n.b. don't call call create with an argument and change the SEI. */
Greeter greeter2 = (Greeter) cf.create();
Greeter greeter3 = (Greeter) cf.create();
Client c = (Client)greeter;
Client c2 = (Client)greeter2;
Client c3 = (Client)greeter3;
assertNotSame(c, c2);
assertNotSame(c, c3);
assertNotSame(c3, c2);
assertNotSame(c.getEndpoint(), c2.getEndpoint());
assertNotSame(c.getEndpoint(), c3.getEndpoint());
assertNotSame(c3.getEndpoint(), c2.getEndpoint());
c3.getInInterceptors();
((BindingProvider)greeter).getRequestContext().put("test", "manny");
((BindingProvider)greeter2).getRequestContext().put("test", "moe");
((BindingProvider)greeter3).getRequestContext().put("test", "jack");
assertEquals("manny", ((BindingProvider)greeter).getRequestContext().get("test"));
assertEquals("moe", ((BindingProvider)greeter2).getRequestContext().get("test"));
assertEquals("jack", ((BindingProvider)greeter3).getRequestContext().get("test"));
}
public static class FaultThrower extends AbstractPhaseInterceptor<Message> {
public FaultThrower() {
super(Phase.PRE_LOGICAL);
}
public void handleMessage(Message message) throws Fault {
throw new Fault(new org.apache.cxf.common.i18n.Message("Foo", (ResourceBundle)null));
}
}
}