/** * 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.io.ByteArrayInputStream; import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.TreeSet; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import javax.xml.ws.Provider; import org.w3c.dom.Document; import org.xml.sax.SAXException; import org.apache.cxf.binding.soap.SoapMessage; import org.apache.cxf.continuations.SuspendedInvocationException; import org.apache.cxf.headers.Header; import org.apache.cxf.interceptor.Fault; import org.apache.cxf.jaxws.service.Hello; import org.apache.cxf.message.Exchange; import org.apache.cxf.message.ExchangeImpl; import org.apache.cxf.message.Message; import org.apache.cxf.message.MessageContentsList; import org.apache.cxf.message.MessageImpl; import org.apache.cxf.phase.Phase; import org.apache.cxf.phase.PhaseInterceptorChain; import org.apache.cxf.service.Service; import org.apache.cxf.service.invoker.Factory; import org.apache.cxf.service.invoker.MethodDispatcher; import org.apache.cxf.service.model.BindingOperationInfo; import org.easymock.EasyMock; import org.junit.Assert; import org.junit.Test; public class JAXWSMethodInvokerTest extends Assert { private static final QName TEST_HEADER_NAME = new QName("testHeader"); Factory factory = EasyMock.createMock(Factory.class); Object target = EasyMock.createMock(Hello.class); @Test public void testFactoryBeans() throws Throwable { Exchange ex = EasyMock.createMock(Exchange.class); EasyMock.reset(factory); factory.create(ex); EasyMock.expectLastCall().andReturn(target); EasyMock.replay(factory); JAXWSMethodInvoker jaxwsMethodInvoker = new JAXWSMethodInvoker(factory); Object object = jaxwsMethodInvoker.getServiceObject(ex); assertEquals("the target object and service object should be equal ", object, target); EasyMock.verify(factory); } @Test public void testSuspendedException() throws Throwable { Exception originalException = new RuntimeException(); ContinuationService serviceObject = new ContinuationService(originalException); Method serviceMethod = ContinuationService.class.getMethod("invoke", new Class[]{}); Exchange ex = new ExchangeImpl(); Message inMessage = new MessageImpl(); ex.setInMessage(inMessage); inMessage.setExchange(ex); inMessage.put(Message.REQUESTOR_ROLE, Boolean.TRUE); JAXWSMethodInvoker jaxwsMethodInvoker = prepareJAXWSMethodInvoker(ex, serviceObject, serviceMethod); try { jaxwsMethodInvoker.invoke(ex, new MessageContentsList(new Object[]{})); fail("Suspended invocation swallowed"); } catch (SuspendedInvocationException suspendedEx) { assertSame(suspendedEx, serviceObject.getSuspendedException()); assertSame(originalException, suspendedEx.getRuntimeException()); } } @Test public void testFaultAvoidHeadersCopy() throws Throwable { ExceptionService serviceObject = new ExceptionService(); Method serviceMethod = ExceptionService.class.getMethod("invoke", new Class[]{}); Exchange ex = new ExchangeImpl(); prepareInMessage(ex, false); JAXWSMethodInvoker jaxwsMethodInvoker = prepareJAXWSMethodInvoker(ex, serviceObject, serviceMethod); try { jaxwsMethodInvoker.invoke(ex, new MessageContentsList(new Object[]{})); fail("Expected fault"); } catch (Fault fault) { Message outMsg = ex.getOutMessage(); Assert.assertNull(outMsg); } } @Test public void testFaultHeadersCopy() throws Throwable { ExceptionService serviceObject = new ExceptionService(); Method serviceMethod = ExceptionService.class.getMethod("invoke", new Class[]{}); Exchange ex = new ExchangeImpl(); prepareInMessage(ex, true); Message msg = new MessageImpl(); SoapMessage outMessage = new SoapMessage(msg); ex.setOutMessage(outMessage); JAXWSMethodInvoker jaxwsMethodInvoker = prepareJAXWSMethodInvoker(ex, serviceObject, serviceMethod); try { jaxwsMethodInvoker.invoke(ex, new MessageContentsList(new Object[]{})); fail("Expected fault"); } catch (Fault fault) { Message outMsg = ex.getOutMessage(); Assert.assertNotNull(outMsg); @SuppressWarnings("unchecked") List<Header> headers = (List<Header>)outMsg.get(Header.HEADER_LIST); Assert.assertEquals(1, headers.size()); Assert.assertEquals(TEST_HEADER_NAME, headers.get(0).getName()); } } @Test public void testProviderInterpretNullAsOneway() throws Throwable { NullableProviderService serviceObject = new NullableProviderService(); Method serviceMethod = NullableProviderService.class.getMethod("invoke", new Class[]{Source.class}); Exchange ex = new ExchangeImpl(); Message inMessage = new MessageImpl(); inMessage.setInterceptorChain(new PhaseInterceptorChain(new TreeSet<Phase>())); ex.setInMessage(inMessage); inMessage.setExchange(ex); inMessage.put(Message.REQUESTOR_ROLE, Boolean.TRUE); JAXWSMethodInvoker jaxwsMethodInvoker = prepareJAXWSMethodInvoker(ex, serviceObject, serviceMethod); // request-response with non-null response ex.setOneWay(false); MessageContentsList obj = (MessageContentsList)jaxwsMethodInvoker.invoke( ex, new MessageContentsList(new Object[]{new StreamSource()})); assertEquals(1, obj.size()); assertNotNull(obj.get(0)); assertFalse(ex.isOneWay()); // oneway with non-null response ex.setOneWay(true); obj = (MessageContentsList)jaxwsMethodInvoker.invoke( ex, new MessageContentsList(new Object[]{new StreamSource()})); assertNull(obj); assertTrue(ex.isOneWay()); // request-response with null response, interpretNullAsOneway not set so // default should be true ex.setOneWay(false); serviceObject.setNullable(true); obj = (MessageContentsList)jaxwsMethodInvoker.invoke( ex, new MessageContentsList(new Object[]{new StreamSource()})); assertNull(obj); assertTrue(ex.isOneWay()); // request-response with null response, interpretNullAsOneway disabled ex.setOneWay(false); serviceObject.setNullable(true); inMessage.put("jaxws.provider.interpretNullAsOneway", Boolean.FALSE); obj = (MessageContentsList)jaxwsMethodInvoker.invoke( ex, new MessageContentsList(new Object[]{new StreamSource()})); assertEquals(1, obj.size()); assertNull(obj.get(0)); assertFalse(ex.isOneWay()); // request-response with null response, interpretNullAsOneway explicitly enabled ex.setOneWay(false); serviceObject.setNullable(true); inMessage.put("jaxws.provider.interpretNullAsOneway", Boolean.TRUE); obj = (MessageContentsList)jaxwsMethodInvoker .invoke(ex, new MessageContentsList(new Object[]{new StreamSource()})); assertNull(obj); assertTrue(ex.isOneWay()); } private JAXWSMethodInvoker prepareJAXWSMethodInvoker(Exchange ex, Object serviceObject, Method serviceMethod) throws Throwable { EasyMock.reset(factory); factory.create(ex); EasyMock.expectLastCall().andReturn(serviceObject).anyTimes(); factory.release(ex, serviceObject); EasyMock.expectLastCall().anyTimes(); EasyMock.replay(factory); BindingOperationInfo boi = new BindingOperationInfo(); ex.put(BindingOperationInfo.class, boi); Service serviceClass = EasyMock.createMock(Service.class); serviceClass.size(); EasyMock.expectLastCall().andReturn(0).anyTimes(); serviceClass.isEmpty(); EasyMock.expectLastCall().andReturn(true).anyTimes(); ex.put(Service.class, serviceClass); MethodDispatcher md = EasyMock.createMock(MethodDispatcher.class); serviceClass.get(MethodDispatcher.class.getName()); EasyMock.expectLastCall().andReturn(md).anyTimes(); md.getMethod(boi); EasyMock.expectLastCall().andReturn(serviceMethod).anyTimes(); EasyMock.replay(md); EasyMock.replay(serviceClass); // initialize the contextCache ex.getInMessage().getContextualProperty("dummy"); return new JAXWSMethodInvoker(factory); } public static class ContinuationService { private RuntimeException ex; public ContinuationService(Exception throwable) { ex = new SuspendedInvocationException(throwable); } public void invoke() { throw ex; } public Throwable getSuspendedException() { return ex; } } public static class NullableProviderService implements Provider<Source> { private boolean nullable; public void setNullable(boolean nullable) { this.nullable = nullable; } public Source invoke(Source request) { return nullable ? null : request; } } public static class ExceptionService { private Throwable ex = new RuntimeException("Test Exception"); public void invoke() { throw new Fault(ex); } } private Message prepareInMessage(Exchange ex, boolean copyHeadersByFault) throws ParserConfigurationException, SAXException, IOException { Message inMessage = new MessageImpl(); inMessage.setExchange(ex); inMessage.put(JAXWSMethodInvoker.COPY_SOAP_HEADERS_BY_FAULT, Boolean.valueOf(copyHeadersByFault)); List<Header> headers = new ArrayList<>(); DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document headerDoc = builder.parse(new ByteArrayInputStream("<test:testValue xmlns:test=\"test\"/>" .getBytes())); Header testHeader = new Header(TEST_HEADER_NAME, headerDoc.getDocumentElement()); headers.add(testHeader); inMessage.put(Header.HEADER_LIST, headers); ex.setInMessage(inMessage); return inMessage; } }