diff --git a/changelog.txt b/changelog.txt index 50faca03..1eb80049 100644 --- a/changelog.txt +++ b/changelog.txt @@ -22,6 +22,9 @@ Package org.springframework.ws.client.core could be closed before returned. Package org.springframework.ws.server.endpoint +* added MarshallingMethodEndpointAdapter + +Package org.springframework.ws.server.endpoint.mapping * added XPathPayloadEndpointMapping (#SWS-85). Package org.springframework.ws.soap.saaj diff --git a/sandbox/src/main/java/org/springframework/ws/server/endpoint/MarshallingMethodEndpointAdapter.java b/sandbox/src/main/java/org/springframework/ws/server/endpoint/MarshallingMethodEndpointAdapter.java new file mode 100644 index 00000000..84fb6446 --- /dev/null +++ b/sandbox/src/main/java/org/springframework/ws/server/endpoint/MarshallingMethodEndpointAdapter.java @@ -0,0 +1,96 @@ +/* + * Copyright 2007 the original author or authors. + * + * Licensed 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.springframework.ws.server.endpoint; + +import java.lang.reflect.Method; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; +import org.springframework.util.Assert; +import org.springframework.ws.WebServiceMessage; +import org.springframework.ws.context.MessageContext; +import org.springframework.ws.server.EndpointMapping; + +/** + * Adapter that supports endpoint methods that use marshalling. Supports methods with the following signature: + *
+ * void handleMyMessage(MyUnmarshalledType request);
+ * 
+ * or + *
+ * MyMarshalledType handleMyMessage(MyUnmarshalledType request);
+ * 
+ * I.e. methods that take a single parameter that {@link Unmarshaller#supports(Class) is supported} by the {@link + * Unmarshaller}, and return either void or a type {@link Marshaller#supports(Class) supported} by the + * {@link Marshaller}. The method can have any name, as long as it is mapped by an {@link EndpointMapping}. + *

+ * This endpoint needs a Marshaller and Unmarshaller, both of which can be set using + * properties. + * + * @author Arjen Poutsma + * @see #setMarshaller(org.springframework.oxm.Marshaller) + * @see #setUnmarshaller(org.springframework.oxm.Unmarshaller) + */ +public class MarshallingMethodEndpointAdapter extends AbstractMethodEndpointAdapter implements InitializingBean { + + private Marshaller marshaller; + + private Unmarshaller unmarshaller; + + public void setMarshaller(Marshaller marshaller) { + this.marshaller = marshaller; + } + + public void setUnmarshaller(Unmarshaller unmarshaller) { + this.unmarshaller = unmarshaller; + } + + public void afterPropertiesSet() throws Exception { + Assert.notNull(marshaller, "marshaller is required"); + Assert.notNull(unmarshaller, "unmarshaller is required"); + } + + /** + * Supports a method with a single, unmarshallable parameter, and that return void or a marshallable + * type. + * + * @see Marshaller#supports(Class) + * @see Unmarshaller#supports(Class) + */ + protected boolean supportsInternal(MethodEndpoint methodEndpoint) { + Method method = methodEndpoint.getMethod(); + return (Void.TYPE.isAssignableFrom(method.getReturnType()) || marshaller.supports(method.getReturnType())) && + method.getParameterTypes().length == 1 && unmarshaller.supports(method.getParameterTypes()[0]); + } + + protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception { + WebServiceMessage request = messageContext.getRequest(); + Object requestObject = unmarshaller.unmarshal(request.getPayloadSource()); + if (logger.isDebugEnabled()) { + logger.debug("Unmarshalled payload request to [" + requestObject + "]"); + } + Object responseObject = methodEndpoint.invoke(new Object[]{requestObject}); + if (responseObject != null) { + if (logger.isDebugEnabled()) { + logger.debug("Marshalling [" + responseObject + "] to response payload"); + } + WebServiceMessage response = messageContext.getResponse(); + marshaller.marshal(responseObject, response.getPayloadResult()); + } + } +} diff --git a/sandbox/src/test/java/org/springframework/ws/server/endpoint/MarshallingMethodEndpointAdapterTest.java b/sandbox/src/test/java/org/springframework/ws/server/endpoint/MarshallingMethodEndpointAdapterTest.java new file mode 100644 index 00000000..abf55ad7 --- /dev/null +++ b/sandbox/src/test/java/org/springframework/ws/server/endpoint/MarshallingMethodEndpointAdapterTest.java @@ -0,0 +1,149 @@ +package org.springframework.ws.server.endpoint; + +import java.lang.reflect.Method; + +import junit.framework.TestCase; +import org.easymock.MockControl; +import org.springframework.oxm.Marshaller; +import org.springframework.oxm.Unmarshaller; +import org.springframework.ws.MockWebServiceMessageFactory; +import org.springframework.ws.context.DefaultMessageContext; +import org.springframework.ws.context.MessageContext; + +public class MarshallingMethodEndpointAdapterTest extends TestCase { + + private MarshallingMethodEndpointAdapter adapter; + + private boolean noResponseInvoked; + + private MockControl marshallerControl; + + private Marshaller marshallerMock; + + private MockControl unmarshallerControl; + + private Unmarshaller unmarshallerMock; + + private MessageContext messageContext; + + private boolean responseInvoked; + + protected void setUp() throws Exception { + adapter = new MarshallingMethodEndpointAdapter(); + marshallerControl = MockControl.createControl(Marshaller.class); + marshallerMock = (Marshaller) marshallerControl.getMock(); + adapter.setMarshaller(marshallerMock); + unmarshallerControl = MockControl.createControl(Unmarshaller.class); + unmarshallerMock = (Unmarshaller) unmarshallerControl.getMock(); + adapter.setUnmarshaller(unmarshallerMock); + adapter.afterPropertiesSet(); + messageContext = new DefaultMessageContext(new MockWebServiceMessageFactory()); + } + + public void testNoResponse() throws Exception { + Method noResponse = getClass().getMethod("noResponse", new Class[]{MyType.class}); + MethodEndpoint methodEndpoint = new MethodEndpoint(this, noResponse); + unmarshallerMock.unmarshal(messageContext.getRequest().getPayloadSource()); + unmarshallerControl.setMatcher(MockControl.ALWAYS_MATCHER); + unmarshallerControl.setReturnValue(new MyType()); + marshallerControl.replay(); + unmarshallerControl.replay(); + assertFalse("Method invoked", noResponseInvoked); + adapter.invoke(messageContext, methodEndpoint); + assertTrue("Method not invoked", noResponseInvoked); + marshallerControl.verify(); + unmarshallerControl.verify(); + } + + public void testResponse() throws Exception { + Method response = getClass().getMethod("response", new Class[]{MyType.class}); + MethodEndpoint methodEndpoint = new MethodEndpoint(this, response); + unmarshallerMock.unmarshal(messageContext.getRequest().getPayloadSource()); + unmarshallerControl.setMatcher(MockControl.ALWAYS_MATCHER); + unmarshallerControl.setReturnValue(new MyType()); + marshallerMock.marshal(new MyType(), messageContext.getResponse().getPayloadResult()); + marshallerControl.setMatcher(MockControl.ALWAYS_MATCHER); + marshallerControl.replay(); + unmarshallerControl.replay(); + assertFalse("Method invoked", responseInvoked); + adapter.invoke(messageContext, methodEndpoint); + assertTrue("Method not invoked", responseInvoked); + marshallerControl.verify(); + unmarshallerControl.verify(); + + } + + public void testSupportedNoResponse() throws NoSuchMethodException { + Method noResponse = getClass().getMethod("noResponse", new Class[]{MyType.class}); + MethodEndpoint methodEndpoint = new MethodEndpoint(this, noResponse); + unmarshallerControl.expectAndReturn(unmarshallerMock.supports(MyType.class), true); + marshallerControl.replay(); + unmarshallerControl.replay(); + assertTrue("Method unsupported", adapter.supportsInternal(methodEndpoint)); + marshallerControl.verify(); + unmarshallerControl.verify(); + } + + public void testSupportedResponse() throws NoSuchMethodException { + Method response = getClass().getMethod("response", new Class[]{MyType.class}); + MethodEndpoint methodEndpoint = new MethodEndpoint(this, response); + unmarshallerControl.expectAndReturn(unmarshallerMock.supports(MyType.class), true); + marshallerControl.expectAndReturn(marshallerMock.supports(MyType.class), true); + marshallerControl.replay(); + unmarshallerControl.replay(); + assertTrue("Method unsupported", adapter.supportsInternal(methodEndpoint)); + marshallerControl.verify(); + unmarshallerControl.verify(); + } + + public void testUnsupportedMethodMultipleParams() throws NoSuchMethodException { + Method unsupported = getClass().getMethod("unsupportedMultipleParams", new Class[]{String.class, String.class}); + marshallerControl.replay(); + unmarshallerControl.replay(); + assertFalse("Method supported", adapter.supportsInternal(new MethodEndpoint(this, unsupported))); + marshallerControl.verify(); + unmarshallerControl.verify(); + } + + public void testUnsupportedMethodWrongParam() throws NoSuchMethodException { + Method unsupported = getClass().getMethod("unsupportedWrongParam", new Class[]{String.class}); + unmarshallerControl.expectAndReturn(unmarshallerMock.supports(String.class), false); + marshallerControl.expectAndReturn(marshallerMock.supports(String.class), true); + marshallerControl.replay(); + unmarshallerControl.replay(); + assertFalse("Method supported", adapter.supportsInternal(new MethodEndpoint(this, unsupported))); + marshallerControl.verify(); + unmarshallerControl.verify(); + } + + public void testUnsupportedMethodWrongReturnType() throws NoSuchMethodException { + Method unsupported = getClass().getMethod("unsupportedWrongParam", new Class[]{String.class}); + marshallerControl.expectAndReturn(marshallerMock.supports(String.class), false); + marshallerControl.replay(); + unmarshallerControl.replay(); + assertFalse("Method supported", adapter.supportsInternal(new MethodEndpoint(this, unsupported))); + marshallerControl.verify(); + unmarshallerControl.verify(); + } + + public void noResponse(MyType type) { + noResponseInvoked = true; + + } + + public MyType response(MyType type) { + responseInvoked = true; + return new MyType(); + } + + public void unsupportedMultipleParams(String s1, String s2) { + } + + public String unsupportedWrongParam(String s) { + return s; + } + + public static class MyType { + + } +} \ No newline at end of file