Skip to content

Commit

Permalink
Moved MethodEndpoint functionality to core-tiger module. (Fixed #SWS-20)
Browse files Browse the repository at this point in the history
  • Loading branch information
poutsma committed Apr 11, 2007
1 parent f07ea88 commit 68347ec
Show file tree
Hide file tree
Showing 28 changed files with 264 additions and 192 deletions.
30 changes: 30 additions & 0 deletions core-tiger/pom.xml
@@ -0,0 +1,30 @@
<?xml version="1.0"?>
<project>
<parent>
<artifactId>spring-ws</artifactId>
<groupId>org.springframework.ws</groupId>
<version>1.0-m4-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-ws-core-tiger</artifactId>
<name>Spring WS Core - Java 5</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Spring-WS dependencies -->
<dependency>
<groupId>org.springframework.ws</groupId>
<artifactId>spring-ws-core</artifactId>
</dependency>
</dependencies>
</project>
Expand Up @@ -23,9 +23,6 @@
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
Expand All @@ -36,6 +33,7 @@
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.annotation.XPathParam;
import org.springframework.xml.dom.DomUtils;
import org.springframework.xml.namespace.SimpleNamespaceContext;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
Expand Down Expand Up @@ -106,7 +104,8 @@ private boolean isSuportedType(Class<?> clazz) {

protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
try {
Element payloadElement = getMessagePayloadElement(messageContext.getRequest());
Element payloadElement =
DomUtils.getRootElement(messageContext.getRequest().getPayloadSource(), getTransformerFactory());
Object[] args = getMethodArguments(payloadElement, methodEndpoint.getMethod());
Object result = methodEndpoint.invoke(args);
if (result != null && result instanceof Source) {
Expand All @@ -126,19 +125,6 @@ protected void invokeInternal(MessageContext messageContext, MethodEndpoint meth
}
}

private Element getMessagePayloadElement(WebServiceMessage message) throws TransformerException {
if (message.getPayloadSource() instanceof DOMSource) {
DOMSource domSource = (DOMSource) message.getPayloadSource();
if (domSource.getNode().getNodeType() == Node.ELEMENT_NODE) {
return (Element) domSource.getNode();
}
}
Transformer transformer = createTransformer();
DOMResult domResult = new DOMResult();
transformer.transform(message.getPayloadSource(), domResult);
return (Element) domResult.getNode().getFirstChild();
}

private Object[] getMethodArguments(Element payloadElement, Method method) throws XPathExpressionException {
Class[] parameterTypes = method.getParameterTypes();
XPath xpath = createXPath();
Expand Down
Expand Up @@ -22,14 +22,14 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.ws.server.endpoint.mapping.AbstractAnnotationEndpointMapping;
import org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationEndpointMapping;
import org.springframework.ws.server.endpoint.mapping.AbstractAnnotationMethodEndpointMapping;
import org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping;

/**
* Marks a class as an endpoint.
* <p/>
* Instances of this class are typically picked up by an {@link AbstractAnnotationEndpointMapping} implementation, such
* as {@link SoapActionAnnotationEndpointMapping}.
* Instances of this class are typically picked up by an {@link AbstractAnnotationMethodEndpointMapping} implementation,
* such as {@link SoapActionAnnotationMethodEndpointMapping}.
*
* @author Arjen Poutsma
*/
Expand Down
Expand Up @@ -16,14 +16,23 @@

package org.springframework.ws.server.endpoint.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Marks an endpoint method as the handler for an incoming request. The annotation value signifies the value for the
* request payload root element that is handled by the method.
*
* @author Arjen Poutsma
* @see org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PayloadRootQName {
@Documented
public @interface PayloadRoot {

String value();

Expand Down
Expand Up @@ -21,15 +21,18 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/** @author Arjen Poutsma */
/**
* Indicates that a method parameter should be bound to an XPath expression. The annotation value signifies the XPath
* expression to use. The parameter can be of the following types: <ul> <li><code>boolean</code>, or {@link
* Boolean}</li> <li><code>double</code>, or {@link Double}</li> <li>{@link String}</li> <li>{@link
* org.w3c.dom.Node}</li> <li>{@link org.w3c.dom.NodeList}</li> </ul>
*
* @author Arjen Poutsma
* @see org.springframework.ws.server.endpoint.adapter.XPathParamAnnotationEndpointAdapter
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface XPathParam {

/**
* The XPathParam value.
*
* @return the
*/
String value();
}
Expand Up @@ -26,15 +26,17 @@
* Abstract base for {@link org.springframework.ws.server.EndpointMapping} implementations that map classes tagged with
* an annotation. By default the annotation is {@link Endpoint}, but this can be overriden in subclasses.
* <p/>
* Each bean
* The methods of each bean carrying @Endpoint will be registered using {@link #registerMethods(Object)}.
*
* @author Arjen Poutsma
*/
public abstract class AbstractAnnotationEndpointMapping extends AbstractMethodEndpointMapping
public abstract class AbstractAnnotationMethodEndpointMapping extends AbstractMethodEndpointMapping
implements BeanPostProcessor {

public final Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
registerMethods(bean);
if (getEndpointClass(bean).getAnnotation(getEndpointAnnotationType()) != null) {
registerMethods(bean);
}
return bean;
}

Expand Down
Expand Up @@ -18,20 +18,34 @@

import java.lang.reflect.Method;
import javax.xml.namespace.QName;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMResult;

import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.annotation.PayloadRootQName;
import org.springframework.ws.server.EndpointMapping;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.xml.dom.DomUtils;
import org.springframework.xml.namespace.QNameUtils;
import org.w3c.dom.Element;

/** @author Arjen Poutsma */
public class PayloadRootQNameMethodEndpointMapping extends AbstractAnnotationEndpointMapping {
/**
* Implementation of the {@link EndpointMapping} interface that uses the {@link PayloadRoot} annotation to map methods
* to request payload root elements.
* <p/>
* Endpoints typically have the following form:
* <pre>
* &#64;Endpoint
* public class MyEndpoint{
* &#64;Payload("{http://springframework.org/spring-ws}Request")
* public Source doSomethingWithRequest() {
* ...
* }
* }
* </pre>
*
* @author Arjen Poutsma
*/
public class PayloadRootAnnotationMethodEndpointMapping extends AbstractAnnotationMethodEndpointMapping {

private static TransformerFactory transformerFactory;

Expand All @@ -40,22 +54,15 @@ public class PayloadRootQNameMethodEndpointMapping extends AbstractAnnotationEnd
}

protected String getLookupKeyForMessage(MessageContext messageContext) throws Exception {
Element payloadElement = getMessagePayloadElement(messageContext.getRequest());
Element payloadElement =
DomUtils.getRootElement(messageContext.getRequest().getPayloadSource(), transformerFactory);
QName qName = QNameUtils.getQNameForNode(payloadElement);
return qName != null ? qName.toString() : null;
}

protected String getLookupKeyForMethod(Method method) {
PayloadRootQName annotation = AnnotationUtils.getAnnotation(method, PayloadRootQName.class);
PayloadRoot annotation = AnnotationUtils.getAnnotation(method, PayloadRoot.class);
return annotation != null ? annotation.value() : null;
}

private Element getMessagePayloadElement(WebServiceMessage message) throws TransformerException {
Transformer transformer = transformerFactory.newTransformer();
DOMResult domResult = new DOMResult();
transformer.transform(message.getPayloadSource(), domResult);
return (Element) domResult.getNode().getFirstChild();
}


}
Expand Up @@ -16,14 +16,22 @@

package org.springframework.ws.soap.server.endpoint.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/** @author Arjen Poutsma */
/**
* Marks an endpoint method as the handler for an incoming request. The annotation value signifies the value for the
* request SOAPAction header that is handled by the method.
*
* @author Arjen Poutsma
* @see org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SoapAction {

String value();
Expand Down
@@ -0,0 +1,5 @@
<html>
<body>
JDK 1.5+ annotations for Spring-WS SOAP endpoints.
</body>
</html>
Expand Up @@ -24,35 +24,30 @@
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInterceptor;
import org.springframework.ws.server.EndpointInvocationChain;
import org.springframework.ws.server.endpoint.mapping.AbstractAnnotationEndpointMapping;
import org.springframework.ws.server.endpoint.mapping.AbstractAnnotationMethodEndpointMapping;
import org.springframework.ws.soap.SoapEndpointMapping;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.SoapEndpointInvocationChain;
import org.springframework.ws.soap.server.endpoint.annotation.SoapAction;

/**
* Implementation of the <code>EndpointMapping</code> interface to map from <code>SOAPAction</code> headers to endpoint
* beans. Supports both mapping to bean instances and mapping to bean names: the latter is required for prototype
* handlers.
* Implementation of the {@link org.springframework.ws.server.EndpointMapping} interface that uses the {@link
* SoapAction} annotation to map methods to the request SOAPAction header.
* <p/>
* The <code>endpointMap</code> property is suitable for populating the endpoint map with bean references, e.g. via the
* map element in XML bean definitions.
* <p/>
* Mappings to bean names can be set via the <code>mappings</code> property, in a form accepted by the
* <code>java.util.Properties</code> class, like as follows:
* Endpoints typically have the following form:
* <pre>
* http://www.springframework.org/spring-ws/samples/airline/BookFlight=bookFlightEndpoint
* http://www.springframework.org/spring-ws/samples/airline/GetFlights=getFlightsEndpoint
* &#64;Endpoint
* public class MyEndpoint{
* &#64;SoapAction("http://springframework.org/spring-ws/SoapAction")
* public Source doSomethingWithRequest() {
* ...
* }
* }
* </pre>
* The syntax is SOAP_ACTION=ENDPOINT_BEAN_NAME.
* <p/>
* This endpoint mapping does not read from the request message, and therefore is more suitable for message contexts
* which directly read from the transport request (such as the <code>AxiomSoapMessageContextFactory</code> with the
* <code>payloadCaching</code> disabled).
*
* @author Arjen Poutsma
*/
public class SoapActionAnnotationEndpointMapping extends AbstractAnnotationEndpointMapping
public class SoapActionAnnotationMethodEndpointMapping extends AbstractAnnotationMethodEndpointMapping
implements SoapEndpointMapping {

private String[] actorsOrRoles;
Expand Down
Expand Up @@ -19,19 +19,22 @@
import javax.xml.transform.Source;

import junit.framework.TestCase;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.MockWebServiceMessage;
import org.springframework.ws.MockWebServiceMessageFactory;
import org.easymock.MockControl;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.annotation.XPathParam;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class XPathParamAnnotationEndpointAdapterTest extends TestCase {

private static final String CONTENTS = "<root><child><text>text</text><number>42.0</number></child></root>";

private XPathParamAnnotationEndpointAdapter adapter;

private boolean supportedTypesInvoked = false;
Expand Down Expand Up @@ -81,22 +84,44 @@ public void testSupportsVoid() throws NoSuchMethodException {
}

public void testInvokeTypes() throws Exception {
MockWebServiceMessage request =
new MockWebServiceMessage(new ClassPathResource("nonamespaces.xml", getClass()));
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
MockControl messageControl = MockControl.createControl(WebServiceMessage.class);
WebServiceMessage messageMock = (WebServiceMessage) messageControl.getMock();
messageControl.expectAndReturn(messageMock.getPayloadSource(), new StringSource(CONTENTS));
messageControl.replay();
MockControl factoryControl = MockControl.createControl(WebServiceMessageFactory.class);
WebServiceMessageFactory factoryMock = (WebServiceMessageFactory) factoryControl.getMock();
factoryControl.replay();

MessageContext messageContext = new DefaultMessageContext(messageMock, factoryMock);
MethodEndpoint endpoint = new MethodEndpoint(this, "supportedTypes",
new Class[]{Boolean.TYPE, Double.TYPE, Node.class, NodeList.class, String.class});
adapter.invoke(messageContext, endpoint);
assertTrue("Method not invoked", supportedTypesInvoked);

messageControl.verify();
factoryControl.verify();

}

public void testInvokeSource() throws Exception {
MockWebServiceMessage request =
new MockWebServiceMessage(new ClassPathResource("nonamespaces.xml", getClass()));
MessageContext messageContext = new DefaultMessageContext(request, new MockWebServiceMessageFactory());
MockControl messageControl = MockControl.createControl(WebServiceMessage.class);
WebServiceMessage requestMock = (WebServiceMessage) messageControl.getMock();
WebServiceMessage responseMock = (WebServiceMessage) messageControl.getMock();
messageControl.expectAndReturn(requestMock.getPayloadSource(), new StringSource(CONTENTS));
messageControl.expectAndReturn(responseMock.getPayloadResult(), new StringResult());
messageControl.replay();
MockControl factoryControl = MockControl.createControl(WebServiceMessageFactory.class);
WebServiceMessageFactory factoryMock = (WebServiceMessageFactory) factoryControl.getMock();
factoryControl.expectAndReturn(factoryMock.createWebServiceMessage(), responseMock);
factoryControl.replay();

MessageContext messageContext = new DefaultMessageContext(requestMock, factoryMock);
MethodEndpoint endpoint = new MethodEndpoint(this, "supportedSource", new Class[]{String.class});
adapter.invoke(messageContext, endpoint);
assertTrue("Method not invoked", supportedSourceInvoked);

messageControl.verify();
factoryControl.verify();
}

public void supportedVoid(@XPathParam("/")String param1) {
Expand Down

0 comments on commit 68347ec

Please sign in to comment.