Merged core and core-tiger modules

This commit is contained in:
Arjen Poutsma
2010-02-01 10:37:45 +00:00
parent c0a085f700
commit acc0821277
32 changed files with 0 additions and 44 deletions

View File

@@ -0,0 +1,108 @@
/*
* 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.adapter;
import java.lang.reflect.Method;
import org.springframework.oxm.GenericMarshaller;
import org.springframework.oxm.GenericUnmarshaller;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.server.endpoint.MethodEndpoint;
/**
* Subclass of {@link MarshallingMethodEndpointAdapter} that supports {@link GenericMarshaller} and {@link
* GenericUnmarshaller}. More specifically, this adapter is aware of the {@link Method#getGenericParameterTypes()} and
* {@link Method#getGenericReturnType()}.
* <p/>
* Prefer to use this adapter rather than the plain {@link MarshallingMethodEndpointAdapter} in combination with Java 5
* marshallers, such as the {@link Jaxb2Marshaller}.
*
* @author Arjen Poutsma
* @since 1.0.2
*/
public class GenericMarshallingMethodEndpointAdapter extends MarshallingMethodEndpointAdapter {
/**
* Creates a new <code>GenericMarshallingMethodEndpointAdapter</code>. The {@link Marshaller} and {@link
* Unmarshaller} must be injected using properties.
*
* @see #setMarshaller(org.springframework.oxm.Marshaller)
* @see #setUnmarshaller(org.springframework.oxm.Unmarshaller)
*/
public GenericMarshallingMethodEndpointAdapter() {
}
/**
* Creates a new <code>GenericMarshallingMethodEndpointAdapter</code> with the given marshaller. If the given {@link
* Marshaller} also implements the {@link Unmarshaller} interface, it is used for both marshalling and
* unmarshalling. Otherwise, an exception is thrown.
* <p/>
* Note that all {@link Marshaller} implementations in Spring-WS also implement the {@link Unmarshaller} interface,
* so that you can safely use this constructor.
*
* @param marshaller object used as marshaller and unmarshaller
* @throws IllegalArgumentException when <code>marshaller</code> does not implement the {@link Unmarshaller}
* interface
*/
public GenericMarshallingMethodEndpointAdapter(Marshaller marshaller) {
super(marshaller);
}
/**
* Creates a new <code>GenericMarshallingMethodEndpointAdapter</code> with the given marshaller and unmarshaller.
*
* @param marshaller the marshaller to use
* @param unmarshaller the unmarshaller to use
*/
public GenericMarshallingMethodEndpointAdapter(Marshaller marshaller, Unmarshaller unmarshaller) {
super(marshaller, unmarshaller);
}
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
Method method = methodEndpoint.getMethod();
return supportsReturnType(method) && supportsParameters(method);
}
private boolean supportsReturnType(Method method) {
if (Void.TYPE.equals(method.getReturnType())) {
return true;
}
else {
if (getMarshaller() instanceof GenericMarshaller) {
return ((GenericMarshaller) getMarshaller()).supports(method.getGenericReturnType());
}
else {
return getMarshaller().supports(method.getReturnType());
}
}
}
private boolean supportsParameters(Method method) {
if (method.getParameterTypes().length != 1) {
return false;
}
else if (getUnmarshaller() instanceof GenericUnmarshaller) {
GenericUnmarshaller genericUnmarshaller = (GenericUnmarshaller) getUnmarshaller();
return genericUnmarshaller.supports(method.getGenericParameterTypes()[0]);
}
else {
return getUnmarshaller().supports(method.getParameterTypes()[0]);
}
}
}

View File

@@ -0,0 +1,175 @@
/*
* 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.adapter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Properties;
import javax.xml.namespace.QName;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMResult;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.ws.WebServiceMessage;
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.namespace.SimpleNamespaceContext;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Adapter that supports endpoint methods that use marshalling. Supports methods with the following signature:
* <pre>
* void handleMyMessage(@XPathParam("/root/child/text")String param);
* </pre>
* or
* <pre>
* Source handleMyMessage(@XPathParam("/root/child/text")String param1, @XPathParam("/root/child/number")double
* param2);
* </pre>
* I.e. methods that return either <code>void</code> or a {@link Source}, and have parameters annotated with {@link
* XPathParam} that specify the XPath expression that should be bound to that parameter. 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 Node}</li> <li>{@link NodeList}</li> </ul>
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class XPathParamAnnotationMethodEndpointAdapter extends AbstractMethodEndpointAdapter
implements InitializingBean {
private XPathFactory xpathFactory;
private Properties namespaces;
/** Sets namespaces used in the XPath expression. Maps prefixes to namespaces. */
public void setNamespaces(Properties namespaces) {
this.namespaces = namespaces;
}
public void afterPropertiesSet() throws Exception {
xpathFactory = XPathFactory.newInstance();
}
/** Supports methods with @XPathParam parameters, and return either <code>Source</code> or nothing. */
protected boolean supportsInternal(MethodEndpoint methodEndpoint) {
Method method = methodEndpoint.getMethod();
if (!(Source.class.isAssignableFrom(method.getReturnType()) || Void.TYPE.equals(method.getReturnType()))) {
return false;
}
Class<?>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
if (getXPathParamAnnotation(method, i) == null || !isSuportedType(parameterTypes[i])) {
return false;
}
}
return true;
}
private XPathParam getXPathParamAnnotation(Method method, int paramIdx) {
Annotation[][] paramAnnotations = method.getParameterAnnotations();
for (int annIdx = 0; annIdx < paramAnnotations[paramIdx].length; annIdx++) {
if (paramAnnotations[paramIdx][annIdx].annotationType().equals(XPathParam.class)) {
return (XPathParam) paramAnnotations[paramIdx][annIdx];
}
}
return null;
}
private boolean isSuportedType(Class<?> clazz) {
return Boolean.class.isAssignableFrom(clazz) || Boolean.TYPE.isAssignableFrom(clazz) ||
Double.class.isAssignableFrom(clazz) || Double.TYPE.isAssignableFrom(clazz) ||
Node.class.isAssignableFrom(clazz) || NodeList.class.isAssignableFrom(clazz) ||
String.class.isAssignableFrom(clazz);
}
protected void invokeInternal(MessageContext messageContext, MethodEndpoint methodEndpoint) throws Exception {
Element payloadElement = getRootElement(messageContext.getRequest().getPayloadSource());
Object[] args = getMethodArguments(payloadElement, methodEndpoint.getMethod());
Object result = methodEndpoint.invoke(args);
if (result != null && result instanceof Source) {
Source responseSource = (Source) result;
WebServiceMessage response = messageContext.getResponse();
transform(responseSource, response.getPayloadResult());
}
}
private Object[] getMethodArguments(Element payloadElement, Method method) throws XPathExpressionException {
Class<?>[] parameterTypes = method.getParameterTypes();
XPath xpath = createXPath();
Object[] args = new Object[parameterTypes.length];
for (int i = 0; i < parameterTypes.length; i++) {
String expression = getXPathParamAnnotation(method, i).value();
QName conversionType;
if (Boolean.class.isAssignableFrom(parameterTypes[i]) || Boolean.TYPE.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.BOOLEAN;
}
else
if (Double.class.isAssignableFrom(parameterTypes[i]) || Double.TYPE.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.NUMBER;
}
else if (Node.class.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.NODE;
}
else if (NodeList.class.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.NODESET;
}
else if (String.class.isAssignableFrom(parameterTypes[i])) {
conversionType = XPathConstants.STRING;
}
else {
throw new IllegalArgumentException("Invalid parameter type [" + parameterTypes[i] + "]. " +
"Supported are: Boolean, Double, Node, NodeList, and String.");
}
args[i] = xpath.evaluate(expression, payloadElement, conversionType);
}
return args;
}
private XPath createXPath() {
XPath xpath = xpathFactory.newXPath();
if (namespaces != null) {
SimpleNamespaceContext namespaceContext = new SimpleNamespaceContext();
namespaceContext.setBindings(namespaces);
xpath.setNamespaceContext(namespaceContext);
}
return xpath;
}
/**
* Returns the root element of the given source.
*
* @param source the source to get the root element from
* @return the root element
*/
private Element getRootElement(Source source) throws TransformerException {
DOMResult domResult = new DOMResult();
transform(source, domResult);
Document document = (Document) domResult.getNode();
return document.getDocumentElement();
}
}

View File

@@ -0,0 +1,54 @@
/*
* 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.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;
import org.springframework.stereotype.Component;
import org.springframework.ws.server.endpoint.mapping.AbstractAnnotationMethodEndpointMapping;
import org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping;
/**
* Indicates that an annotated class is an "Endpoint" (e.g. a web service endpoint).
* <p/>
* This annotation serves as a specialization of {@link Component @Component}, allowing for implementation classes to be
* autodetected through classpath scanning. Instances of this class are typically picked up by an {@link
* AbstractAnnotationMethodEndpointMapping} implementation, such as {@link SoapActionAnnotationMethodEndpointMapping}.
*
* @author Arjen Poutsma
* @see org.springframework.context.annotation.ClassPathBeanDefinitionScanner
* @since 1.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Endpoint {
/**
* The value may indicate a suggestion for a logical component name, to be turned into a Spring bean in case of an
* autodetected component.
*
* @return the suggested component name, if any
*/
String value() default "";
}

View File

@@ -0,0 +1,52 @@
/*
* 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.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 values signify the the request
* payload root element that is handled by the method.
*
* @author Arjen Poutsma
* @see org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping
* @since 1.0.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PayloadRoot {
/**
* Signifies the local part of the payload root element handled by the annotated method.
*
* @see #namespace()
*/
String localPart();
/**
* Signifies the namespace of the payload root element handled by the annotated method.
*
* @see #localPart()
*/
String namespace() default "";
}

View File

@@ -0,0 +1,41 @@
/*
* 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.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;
/**
* 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.XPathParamAnnotationMethodEndpointAdapter
* @since 1.0.0
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface XPathParam {
String value();
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
JDK 1.5+ annotations for Spring-WS endpoints.
</body>
</html>

View File

@@ -0,0 +1,76 @@
/*
* 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.mapping;
import java.lang.annotation.Annotation;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
/**
* 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/>
* The methods of each bean carrying @Endpoint will be registered using {@link #registerMethods(String)}.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public abstract class AbstractAnnotationMethodEndpointMapping extends AbstractMethodEndpointMapping {
private boolean detectEndpointsInAncestorContexts = false;
/**
* Set whether to detect endpoint beans in ancestor ApplicationContexts.
* <p/>
* Default is "false": Only endpoint beans in the current ApplicationContext will be detected, i.e. only in the
* context that this EndpointMapping itself is defined in (typically the current MessageDispatcherServlet's
* context).
* <p/>
* Switch this flag on to detect endpoint beans in ancestor contexts (typically the Spring root
* WebApplicationContext) as well.
*/
public void setDetectEndpointsInAncestorContexts(boolean detectEndpointsInAncestorContexts) {
this.detectEndpointsInAncestorContexts = detectEndpointsInAncestorContexts;
}
/** Returns the 'endpoint' annotation type. Default is {@link Endpoint}. */
protected Class<? extends Annotation> getEndpointAnnotationType() {
return Endpoint.class;
}
protected final void initApplicationContext() throws BeansException {
if (logger.isDebugEnabled()) {
logger.debug("Looking for endpoints in application context: " + getApplicationContext());
}
String[] beanNames = (this.detectEndpointsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (int i = 0; i < beanNames.length; i++) {
String beanName = beanNames[i];
Class endpointClass = getApplicationContext().getType(beanName);
if (endpointClass != null &&
AnnotationUtils.findAnnotation(endpointClass, getEndpointAnnotationType()) != null) {
registerMethods(beanName);
}
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.mapping;
import java.lang.reflect.Method;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerFactory;
import org.springframework.util.StringUtils;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointMapping;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.support.PayloadRootUtils;
/**
* 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;PayloadRoot(localPart = "Request",
* namespace = "http://springframework.org/spring-ws")
* public Source doSomethingWithRequest() {
* ...
* }
* }
* </pre>
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class PayloadRootAnnotationMethodEndpointMapping extends AbstractAnnotationMethodEndpointMapping {
private static TransformerFactory transformerFactory;
static {
transformerFactory = TransformerFactory.newInstance();
}
protected String getLookupKeyForMessage(MessageContext messageContext) throws Exception {
QName qName =
PayloadRootUtils.getPayloadRootQName(messageContext.getRequest().getPayloadSource(), transformerFactory)
;
return qName != null ? qName.toString() : null;
}
protected String getLookupKeyForMethod(Method method) {
PayloadRoot annotation = method.getAnnotation(PayloadRoot.class);
if (annotation != null) {
QName qname;
if (StringUtils.hasLength(annotation.localPart()) && StringUtils.hasLength(annotation.namespace())) {
qname = new QName(annotation.namespace(), annotation.localPart());
}
else {
qname = new QName(annotation.localPart());
}
return qname.toString();
}
else {
return null;
}
}
}

View File

@@ -0,0 +1,148 @@
/*
* Copyright 2008 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.soap.addressing.server;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.StringUtils;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.soap.addressing.core.MessageAddressingProperties;
import org.springframework.ws.soap.addressing.server.annotation.Action;
import org.springframework.ws.soap.addressing.server.annotation.Address;
/**
* Implementation of the {@link org.springframework.ws.server.EndpointMapping} interface that uses the {@link Action}
* annotation to map methods to a WS-Addressing <code>Action</code> header.
* <p/>
* Endpoints typically have the following form:
* <pre>
* &#64;Endpoint
* &#64;Address("mailto:joe@fabrikam123.example")
* public class MyEndpoint{
* &#64;Action("http://fabrikam123.example/mail/Delete")
* public Source doSomethingWithRequest() {
* ...
* }
* }
* </pre>
* <p/>
* If set, the {@link Address} annotation on the endpoint class should be equal to the {@link
* org.springframework.ws.soap.addressing.core.MessageAddressingProperties#getTo() destination} property of the
* incominging message.
*
* @author Arjen Poutsma
* @see Action
* @see Address
* @since 1.5.0
*/
public class AnnotationActionEndpointMapping extends AbstractActionMethodEndpointMapping implements BeanPostProcessor {
/** Returns the 'endpoint' annotation type. Default is {@link Endpoint}. */
protected Class<? extends Annotation> getEndpointAnnotationType() {
return Endpoint.class;
}
/**
* Returns the action value for the specified method. Default implementation looks for the {@link Action} annotation
* value.
*/
protected URI getActionForMethod(Method method) {
Action action = method.getAnnotation(Action.class);
if (action != null && StringUtils.hasText(action.value())) {
try {
return new URI(action.value());
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(
"Invalid Action annotation [" + action.value() + "] on [" + method + "]");
}
}
return null;
}
/**
* Returns the address property of the given {@link MethodEndpoint}, by looking for the {@link Address} annotation.
* The value of this property should match the {@link org.springframework.ws.soap.addressing.core.MessageAddressingProperties#getTo()
* destination} of incoming messages. Returns <code>null</code> if the anotation is not present, thus ignoring the
* destination property.
*
* @param endpoint the method endpoint to return the address for
* @return the endpoint address; or <code>null</code> to ignore the destination property
*/
protected URI getEndpointAddress(Object endpoint) {
MethodEndpoint methodEndpoint = (MethodEndpoint) endpoint;
Class endpointClass = methodEndpoint.getMethod().getDeclaringClass();
Address address = AnnotationUtils.findAnnotation(endpointClass, Address.class);
if (address != null && StringUtils.hasText(address.value())) {
return getActionUri(address.value(), methodEndpoint);
}
else {
return null;
}
}
protected URI getResponseAction(Object endpoint, MessageAddressingProperties map) {
MethodEndpoint methodEndpoint = (MethodEndpoint) endpoint;
Action action = methodEndpoint.getMethod().getAnnotation(Action.class);
if (action != null && StringUtils.hasText(action.output())) {
return getActionUri(action.output(), methodEndpoint);
}
else {
return super.getResponseAction(endpoint, map);
}
}
protected URI getFaultAction(Object endpoint, MessageAddressingProperties map) {
MethodEndpoint methodEndpoint = (MethodEndpoint) endpoint;
Action action = methodEndpoint.getMethod().getAnnotation(Action.class);
if (action != null && StringUtils.hasText(action.fault())) {
return getActionUri(action.fault(), methodEndpoint);
}
else {
return super.getResponseAction(endpoint, map);
}
}
private URI getActionUri(String action, MethodEndpoint methodEndpoint) {
try {
return new URI(action);
}
catch (URISyntaxException e) {
throw new IllegalArgumentException(
"Invalid Action annotation [" + action + "] on [" + methodEndpoint + "]");
}
}
public final Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
public final Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (AopUtils.getTargetClass(bean).getAnnotation(getEndpointAnnotationType()) != null) {
registerMethods(bean);
}
return bean;
}
}

View File

@@ -0,0 +1,49 @@
/*
* Copyright 2008 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.soap.addressing.server.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 WS-Addressing <code>Action</code> header that is handled by the method.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Action {
/** Signifies the value for the request WS-Addressing <code>Action</code> header that is handled by the method. */
String value();
/** Signifies the value for the response WS-Addressing <code>Action</code> header that is provided by the method. */
String output() default "";
/**
* Signifies the value for the fault response WS-Addressing <code>Action</code> header that is provided by the
* method.
*/
String fault() default "";
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright 2008 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.soap.addressing.server.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 with a WS-Addressing <code>Address</code>. If this annotation is applied, the {@link #value()} is
* compared to the {@link org.springframework.ws.soap.addressing.core.MessageAddressingProperties#getTo() destination}
* property of the incominging message.
*
* @author Arjen Poutsma
* @since 1.5.0
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Address {
/**
* The value may indicate a suggestion for a logical component name, to be turned into a Spring bean in case of an
* autodetected component.
*
* @return the suggested component name, if any
*/
String value();
}

View File

@@ -0,0 +1,52 @@
/*
* 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.soap.server.endpoint;
import javax.xml.namespace.QName;
import org.springframework.util.StringUtils;
import org.springframework.ws.soap.server.endpoint.annotation.FaultCode;
import org.springframework.ws.soap.server.endpoint.annotation.SoapFault;
/**
* Implementation of the {@link org.springframework.ws.server.EndpointExceptionResolver} interface that uses the {@link
* SoapFault} annotation to map exceptions to SOAP Faults.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class SoapFaultAnnotationExceptionResolver extends AbstractSoapFaultDefinitionExceptionResolver {
protected final SoapFaultDefinition getFaultDefinition(Object endpoint, Exception ex) {
SoapFault faultAnnotation = ex.getClass().getAnnotation(SoapFault.class);
if (faultAnnotation != null) {
SoapFaultDefinition definition = new SoapFaultDefinition();
if (faultAnnotation.faultCode() != FaultCode.CUSTOM) {
definition.setFaultCode(faultAnnotation.faultCode().value());
}
else if (StringUtils.hasLength(faultAnnotation.customFaultCode())) {
definition.setFaultCode(QName.valueOf(faultAnnotation.customFaultCode()));
}
definition.setFaultStringOrReason(faultAnnotation.faultStringOrReason());
definition.setLocale(StringUtils.parseLocaleString(faultAnnotation.locale()));
return definition;
}
else {
return null;
}
}
}

View File

@@ -0,0 +1,82 @@
/*
* 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.soap.server.endpoint.annotation;
import javax.xml.namespace.QName;
import org.springframework.ws.soap.SoapBody;
import org.springframework.ws.soap.soap11.Soap11Body;
/**
* Enumeration that represents the standard SOAP Fault codes for use with the JDK 1.5+ {@link SoapFault} annotation.
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public enum FaultCode {
/**
* Constant used to indicate that a fault must be created with a custom fault code. When this value is used, the
* <code>customFaultCode</code> string property must be used on {@link SoapFault}.
* <p/>
* Note that custom Fault Codes are only supported on SOAP 1.1.
*
* @see SoapFault#customFaultCode()
* @see Soap11Body#addFault(javax.xml.namespace.QName,String,java.util.Locale)
*/
CUSTOM(new QName("CUSTOM")),
/**
* Constant used to indicate that a <code>Client</code> fault must be created.
*
* @see SoapBody#addClientOrSenderFault(String,java.util.Locale)
*/
CLIENT(new QName("CLIENT")),
/**
* Constant <code>QName</code> used to indicate that a <code>Receiver</code> fault must be created.
*
* @see SoapBody#addServerOrReceiverFault(String,java.util.Locale)
*/
RECEIVER(new QName("RECEIVER")),
/**
* Constant <code>QName</code> used to indicate that a <code>Sender</code> fault must be created.
*
* @see SoapBody#addServerOrReceiverFault(String,java.util.Locale)
*/
SENDER(new QName("SENDER")),
/**
* Constant <code>QName</code> used to indicate that a <code>Server</code> fault must be created.
*
* @see SoapBody#addClientOrSenderFault(String,java.util.Locale)
*/
SERVER(new QName("SERVER"));
private final QName value;
private FaultCode(QName value) {
this.value = value;
}
public QName value() {
return value;
}
}

View File

@@ -0,0 +1,41 @@
/*
* 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.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;
/**
* Marks an endpoint method as the handler for an incoming request. The annotation value signifies the value for the
* request <code>SOAPAction</code> header that is handled by the method.
*
* @author Arjen Poutsma
* @see org.springframework.ws.soap.server.endpoint.mapping.SoapActionAnnotationMethodEndpointMapping
* @since 1.0.0
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SoapAction {
/** Signifies the value for the request <code>SOAPAction</code> header that is handled by the method. */
String value();
}

View File

@@ -0,0 +1,60 @@
/*
* 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.soap.server.endpoint.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.xml.namespace.QName;
/**
* Marks an exception class with the fault elements that should be returned whenever this exception is thrown.
*
* @author Arjen Poutsma
* @see org.springframework.ws.soap.server.endpoint.SoapFaultAnnotationExceptionResolver
* @since 1.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface SoapFault {
/** The fault code. */
FaultCode faultCode();
/**
* The custom fault code, to be used if {@link #faultCode()} is set to {@link FaultCode#CUSTOM}.
* <p/>
* The format used is that of {@link QName#toString()}, i.e. "{" + Namespace URI + "}" + local part, where the
* namespace is optional.
* <p/>
* Note that custom Fault Codes are only supported on SOAP 1.1.
*/
String customFaultCode() default "";
/** The fault string or reason text. By default, it is set to the exception message. */
String faultStringOrReason() default "";
/** The fault string locale. By default, it is English. */
String locale() default "en";
}

View File

@@ -0,0 +1,5 @@
<html>
<body>
JDK 1.5+ annotations for Spring-WS SOAP endpoints.
</body>
</html>

View File

@@ -0,0 +1,108 @@
/*
* 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.soap.server.endpoint.mapping;
import java.lang.reflect.Method;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
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.AbstractAnnotationMethodEndpointMapping;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.SoapEndpointInvocationChain;
import org.springframework.ws.soap.server.SoapEndpointMapping;
import org.springframework.ws.soap.server.endpoint.annotation.SoapAction;
/**
* 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/>
* Endpoints typically have the following form:
* <pre>
* &#64;Endpoint
* public class MyEndpoint{
* &#64;SoapAction("http://springframework.org/spring-ws/SoapAction")
* public Source doSomethingWithRequest() {
* ...
* }
* }
* </pre>
*
* @author Arjen Poutsma
* @since 1.0.0
*/
public class SoapActionAnnotationMethodEndpointMapping extends AbstractAnnotationMethodEndpointMapping
implements SoapEndpointMapping {
private String[] actorsOrRoles;
private boolean isUltimateReceiver = true;
public final void setActorOrRole(String actorOrRole) {
Assert.notNull(actorOrRole, "actorOrRole must not be null");
actorsOrRoles = new String[]{actorOrRole};
}
public final void setActorsOrRoles(String[] actorsOrRoles) {
Assert.notEmpty(actorsOrRoles, "actorsOrRoles must not be empty");
this.actorsOrRoles = actorsOrRoles;
}
public final void setUltimateReceiver(boolean ultimateReceiver) {
isUltimateReceiver = ultimateReceiver;
}
/**
* Creates a new <code>SoapEndpointInvocationChain</code> based on the given endpoint, and the set interceptors, and
* actors/roles.
*
* @param endpoint the endpoint
* @param interceptors the endpoint interceptors
* @return the created invocation chain
* @see #setInterceptors(org.springframework.ws.server.EndpointInterceptor[])
* @see #setActorsOrRoles(String[])
*/
protected final EndpointInvocationChain createEndpointInvocationChain(MessageContext messageContext,
Object endpoint,
EndpointInterceptor[] interceptors) {
return new SoapEndpointInvocationChain(endpoint, interceptors, actorsOrRoles, isUltimateReceiver);
}
protected String getLookupKeyForMessage(MessageContext messageContext) throws Exception {
if (messageContext.getRequest() instanceof SoapMessage) {
SoapMessage request = (SoapMessage) messageContext.getRequest();
String soapAction = request.getSoapAction();
if (StringUtils.hasLength(soapAction) && soapAction.charAt(0) == '"' &&
soapAction.charAt(soapAction.length() - 1) == '"') {
return soapAction.substring(1, soapAction.length() - 1);
}
else {
return soapAction;
}
}
else {
return null;
}
}
protected String getLookupKeyForMethod(Method method) {
SoapAction soapAction = method.getAnnotation(SoapAction.class);
return soapAction != null ? soapAction.value() : null;
}
}

View File

@@ -0,0 +1,46 @@
/*
* Copyright ${YEAR} 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.config;
import java.util.Map;
import junit.framework.TestCase;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter;
import org.springframework.ws.server.endpoint.adapter.XPathParamAnnotationMethodEndpointAdapter;
public class WebServicesNamespaceHandlerTigerTest extends TestCase {
private ApplicationContext applicationContext;
protected void setUp() throws Exception {
applicationContext =
new ClassPathXmlApplicationContext("webServicesNamespaceHandlerTest-tiger.xml", getClass());
}
public void testMarshallingEndpoints() throws Exception {
Map result = applicationContext.getBeansOfType(GenericMarshallingMethodEndpointAdapter.class);
assertFalse("no MarshallingMethodEndpointAdapter found", result.isEmpty());
}
public void testXpathEndpoints() throws Exception {
Map result = applicationContext.getBeansOfType(XPathParamAnnotationMethodEndpointAdapter.class);
assertFalse("no XPathParamAnnotationMethodEndpointAdapter found", result.isEmpty());
}
}

View File

@@ -0,0 +1,185 @@
package org.springframework.ws.server.endpoint.adapter;
import java.lang.reflect.Method;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
import org.springframework.oxm.GenericMarshaller;
import org.springframework.oxm.GenericUnmarshaller;
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.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
public class GenericMarshallingMethodEndpointAdapterTest extends TestCase {
private GenericMarshallingMethodEndpointAdapter adapter;
private boolean noResponseInvoked;
private GenericMarshaller marshallerMock;
private GenericUnmarshaller unmarshallerMock;
private boolean responseInvoked;
protected void setUp() throws Exception {
adapter = new GenericMarshallingMethodEndpointAdapter();
marshallerMock = createMock(GenericMarshaller.class);
adapter.setMarshaller(marshallerMock);
unmarshallerMock = createMock(GenericUnmarshaller.class);
adapter.setUnmarshaller(unmarshallerMock);
adapter.afterPropertiesSet();
}
public void testNoResponse() throws Exception {
WebServiceMessage messageMock = createMock(WebServiceMessage.class);
expect(messageMock.getPayloadSource()).andReturn(new StringSource("<request/>"));
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
MessageContext messageContext = new DefaultMessageContext(messageMock, factoryMock);
Method noResponse = getClass().getMethod("noResponse", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, noResponse);
expect(unmarshallerMock.unmarshal(isA(Source.class))).andReturn(new MyGenericType<MyType>());
replay(marshallerMock, unmarshallerMock, messageMock, factoryMock);
assertFalse("Method invoked", noResponseInvoked);
adapter.invoke(messageContext, methodEndpoint);
assertTrue("Method not invoked", noResponseInvoked);
verify(marshallerMock, unmarshallerMock, messageMock, factoryMock);
}
public void testNoRequestPayload() throws Exception {
WebServiceMessage messageMock = createMock(WebServiceMessage.class);
expect(messageMock.getPayloadSource()).andReturn(null);
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
MessageContext messageContext = new DefaultMessageContext(messageMock, factoryMock);
Method noResponse = getClass().getMethod("noResponse", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, noResponse);
replay(marshallerMock, unmarshallerMock, messageMock, factoryMock);
assertFalse("Method invoked", noResponseInvoked);
adapter.invoke(messageContext, methodEndpoint);
assertTrue("Method not invoked", noResponseInvoked);
verify(marshallerMock, unmarshallerMock, messageMock, factoryMock);
}
public void testResponse() throws Exception {
WebServiceMessage requestMock = createMock(WebServiceMessage.class);
expect(requestMock.getPayloadSource()).andReturn(new StringSource("<request/>"));
WebServiceMessage responseMock = createMock(WebServiceMessage.class);
expect(responseMock.getPayloadResult()).andReturn(new StringResult());
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
expect(factoryMock.createWebServiceMessage()).andReturn(responseMock);
MessageContext messageContext = new DefaultMessageContext(requestMock, factoryMock);
Method response = getClass().getMethod("response", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, response);
expect(unmarshallerMock.unmarshal(isA(Source.class))).andReturn(new MyGenericType<MyType>());
marshallerMock.marshal(isA(MyGenericType.class), isA(Result.class));
replay(marshallerMock, unmarshallerMock, requestMock, responseMock, factoryMock);
assertFalse("Method invoked", responseInvoked);
adapter.invoke(messageContext, methodEndpoint);
assertTrue("Method not invoked", responseInvoked);
verify(marshallerMock, unmarshallerMock, requestMock, responseMock, factoryMock);
}
public void testSupportedNoResponse() throws NoSuchMethodException {
Method noResponse = getClass().getMethod("noResponse", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, noResponse);
expect(unmarshallerMock.supports(noResponse.getGenericParameterTypes()[0])).andReturn(true);
replay(marshallerMock, unmarshallerMock);
assertTrue("Method unsupported", adapter.supportsInternal(methodEndpoint));
verify(marshallerMock, unmarshallerMock);
}
public void testSupportedResponse() throws NoSuchMethodException {
Method response = getClass().getMethod("response", MyGenericType.class);
MethodEndpoint methodEndpoint = new MethodEndpoint(this, response);
expect(unmarshallerMock.supports(response.getGenericParameterTypes()[0])).andReturn(true);
expect(marshallerMock.supports(response.getGenericReturnType())).andReturn(true);
replay(marshallerMock, unmarshallerMock);
assertTrue("Method unsupported", adapter.supportsInternal(methodEndpoint));
verify(marshallerMock, unmarshallerMock);
}
public void testUnsupportedMethodMultipleParams() throws NoSuchMethodException {
Method unsupported = getClass().getMethod("unsupportedMultipleParams", String.class, String.class);
replay(marshallerMock, unmarshallerMock);
assertFalse("Method supported", adapter.supportsInternal(new MethodEndpoint(this, unsupported)));
verify(marshallerMock, unmarshallerMock);
}
public void testUnsupportedMethodWrongParam() throws NoSuchMethodException {
Method unsupported = getClass().getMethod("unsupportedWrongParam", String.class);
expect(unmarshallerMock.supports(unsupported.getGenericParameterTypes()[0])).andReturn(false);
expect(marshallerMock.supports(unsupported.getGenericReturnType())).andReturn(true);
replay(marshallerMock, unmarshallerMock);
assertFalse("Method supported", adapter.supportsInternal(new MethodEndpoint(this, unsupported)));
verify(marshallerMock, unmarshallerMock);
}
public void testUnsupportedMethodWrongReturnType() throws NoSuchMethodException {
Method unsupported = getClass().getMethod("unsupportedWrongParam", String.class);
expect(marshallerMock.supports(unsupported.getGenericReturnType())).andReturn(false);
replay(marshallerMock, unmarshallerMock);
assertFalse("Method supported", adapter.supportsInternal(new MethodEndpoint(this, unsupported)));
verify(marshallerMock, unmarshallerMock);
}
public void noResponse(MyGenericType<MyType> type) {
noResponseInvoked = true;
}
public MyGenericType<MyType> response(MyGenericType<MyType> type) {
responseInvoked = true;
return type;
}
public void unsupportedMultipleParams(String s1, String s2) {
}
public String unsupportedWrongParam(String s) {
return s;
}
private static class MyType {
}
private static class MyGenericType<T> {
}
}

View File

@@ -0,0 +1,202 @@
/*
* 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.adapter;
import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
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.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
public class XPathParamAnnotationMethodEndpointAdapterTest extends TestCase {
private static final String CONTENTS = "<root><child><text>text</text><number>42.0</number></child></root>";
private XPathParamAnnotationMethodEndpointAdapter adapter;
private boolean supportedTypesInvoked = false;
private boolean supportedSourceInvoked;
private boolean namespacesInvoked;
protected void setUp() throws Exception {
adapter = new XPathParamAnnotationMethodEndpointAdapter();
adapter.afterPropertiesSet();
}
public void testUnsupportedInvalidParam() throws NoSuchMethodException {
MethodEndpoint endpoint = new MethodEndpoint(this, "unsupportedInvalidParamType", new Class[]{Integer.TYPE});
assertFalse("Method supported", adapter.supports(endpoint));
}
public void testUnsupportedInvalidReturnType() throws NoSuchMethodException {
MethodEndpoint endpoint = new MethodEndpoint(this, "unsupportedInvalidReturnType", new Class[]{String.class});
assertFalse("Method supported", adapter.supports(endpoint));
}
public void testUnsupportedInvalidParams() throws NoSuchMethodException {
MethodEndpoint endpoint =
new MethodEndpoint(this, "unsupportedInvalidParams", new Class[]{String.class, String.class});
assertFalse("Method supported", adapter.supports(endpoint));
}
public void testSupportedTypes() throws NoSuchMethodException {
MethodEndpoint endpoint = new MethodEndpoint(this, "supportedTypes",
new Class[]{Boolean.TYPE, Double.TYPE, Node.class, NodeList.class, String.class});
assertTrue("Not all types supported", adapter.supports(endpoint));
}
public void testSupportsStringSource() throws NoSuchMethodException {
MethodEndpoint endpoint = new MethodEndpoint(this, "supportedStringSource", new Class[]{String.class});
assertTrue("StringSource method not supported", adapter.supports(endpoint));
}
public void testSupportsSource() throws NoSuchMethodException {
MethodEndpoint endpoint = new MethodEndpoint(this, "supportedSource", new Class[]{String.class});
assertTrue("Source method not supported", adapter.supports(endpoint));
}
public void testSupportsVoid() throws NoSuchMethodException {
MethodEndpoint endpoint = new MethodEndpoint(this, "supportedVoid", new Class[]{String.class});
assertTrue("void method not supported", adapter.supports(endpoint));
}
public void testInvokeTypes() throws Exception {
WebServiceMessage messageMock = createMock(WebServiceMessage.class);
expect(messageMock.getPayloadSource()).andReturn(new StringSource(CONTENTS));
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
replay(messageMock, factoryMock);
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);
verify(messageMock, factoryMock);
}
public void testInvokeSource() throws Exception {
WebServiceMessage requestMock = createMock(WebServiceMessage.class);
WebServiceMessage responseMock = createMock(WebServiceMessage.class);
expect(requestMock.getPayloadSource()).andReturn(new StringSource(CONTENTS));
expect(responseMock.getPayloadResult()).andReturn(new StringResult());
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
expect(factoryMock.createWebServiceMessage()).andReturn(responseMock);
replay(requestMock, responseMock, factoryMock);
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);
verify(requestMock, responseMock, factoryMock);
}
public void testInvokeVoidDom() throws Exception {
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.newDocument();
String rootNamespace = "http://rootnamespace";
Element rootElement = document.createElementNS(rootNamespace, "root");
document.appendChild(rootElement);
String childNamespace = "http://childnamespace";
Element first = document.createElementNS(childNamespace, "child");
rootElement.appendChild(first);
Text text = document.createTextNode("value");
first.appendChild(text);
Element second = document.createElementNS(rootNamespace, "other-child");
rootElement.appendChild(second);
text = document.createTextNode("other-value");
second.appendChild(text);
WebServiceMessage requestMock = createMock(WebServiceMessage.class);
expect(requestMock.getPayloadSource()).andReturn(new DOMSource(first));
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
replay(requestMock, factoryMock);
Properties namespaces = new Properties();
namespaces.setProperty("root", rootNamespace);
namespaces.setProperty("child", childNamespace);
adapter.setNamespaces(namespaces);
MessageContext messageContext = new DefaultMessageContext(requestMock, factoryMock);
MethodEndpoint endpoint = new MethodEndpoint(this, "namespaces", new Class[]{Node.class});
adapter.invoke(messageContext, endpoint);
assertTrue("Method not invoked", namespacesInvoked);
}
public void supportedVoid(@XPathParam("/")String param1) {
}
public Source supportedSource(@XPathParam("/")String param1) {
supportedSourceInvoked = true;
return new StringSource("<response/>");
}
public StringSource supportedStringSource(@XPathParam("/")String param1) {
return null;
}
public void supportedTypes(@XPathParam("/root/child")boolean param1,
@XPathParam("/root/child/number")double param2,
@XPathParam("/root/child")Node param3,
@XPathParam("/root/*")NodeList param4,
@XPathParam("/root/child/text")String param5) {
supportedTypesInvoked = true;
assertTrue("Invalid boolean value", param1);
assertEquals("Invalid double value", 42D, param2, 0.00001D);
assertEquals("Invalid Node value", "child", param3.getLocalName());
assertEquals("Invalid NodeList value", 1, param4.getLength());
assertEquals("Invalid Node value", "child", param4.item(0).getLocalName());
assertEquals("Invalid Node value", "text", param5);
}
public void unsupportedInvalidParams(@XPathParam("/")String param1, String param2) {
}
public String unsupportedInvalidReturnType(@XPathParam("/")String param1) {
return null;
}
public void unsupportedInvalidParamType(@XPathParam("/")int param1) {
}
public void namespaces(@XPathParam(".")Node param) {
namespacesInvoked = true;
assertEquals("Invalid parameter", "child", param.getLocalName());
}
}

View File

@@ -0,0 +1,21 @@
/*
* Copyright 2008 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.mapping;
public @interface Log {
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright 2008 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.mapping;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
@Aspect
public class LogAspect {
private static final Log logger = LogFactory.getLog(LogAspect.class);
private boolean logInvoked = false;
public boolean isLogInvoked() {
return logInvoked;
}
@Pointcut("@annotation(org.springframework.ws.server.endpoint.mapping.Log)")
private void loggedMethod() {
}
@Around("loggedMethod()")
public void log(ProceedingJoinPoint joinPoint) throws Throwable {
logInvoked = true;
logger.info("Before: " + joinPoint.getSignature());
try {
joinPoint.proceed();
}
finally {
logger.info("After: " + joinPoint.getSignature());
}
}
}

View File

@@ -0,0 +1,28 @@
/*
* Copyright 2008 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.mapping;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
class OtherBean {
@PayloadRoot(localPart = "Request2", namespace = "http://springframework.org/spring-ws")
public void doIt() {
}
}

View File

@@ -0,0 +1,83 @@
/*
* 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.mapping;
import java.lang.reflect.Method;
import java.util.Collections;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Source;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointAdapter;
import org.springframework.ws.server.MessageDispatcher;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.adapter.PayloadMethodEndpointAdapter;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.soap.server.SoapMessageDispatcher;
public class PayloadRootAnnotationMethodEndpointMappingTest extends AbstractDependencyInjectionSpringContextTests {
private PayloadRootAnnotationMethodEndpointMapping mapping;
protected String getConfigPath() {
return "applicationContext.xml";
}
public void setMapping(PayloadRootAnnotationMethodEndpointMapping mapping) {
this.mapping = mapping;
}
public void testRegistration() throws NoSuchMethodException {
MethodEndpoint endpoint = mapping.lookupEndpoint("{http://springframework.org/spring-ws}Request");
assertNotNull("MethodEndpoint not registered", endpoint);
Method doIt = PayloadRootEndpoint.class.getMethod("doIt", Source.class);
MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doIt);
assertEquals("Invalid endpoint registered", expected, endpoint);
assertNull("Invalid endpoint registered",
mapping.lookupEndpoint("{http://springframework.org/spring-ws}Request2"));
}
public void testInvoke() throws Exception {
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage request = messageFactory.createMessage();
request.getSOAPBody().addBodyElement(QName.valueOf("{http://springframework.org/spring-ws}Request"));
MessageContext messageContext =
new DefaultMessageContext(new SaajSoapMessage(request), new SaajSoapMessageFactory(messageFactory));
EndpointAdapter adapter = new PayloadMethodEndpointAdapter();
MessageDispatcher messageDispatcher = new SoapMessageDispatcher();
messageDispatcher.setApplicationContext(applicationContext);
messageDispatcher.setEndpointMappings(Collections.singletonList(mapping));
messageDispatcher.setEndpointAdapters(Collections.singletonList(adapter));
messageDispatcher.receive(messageContext);
PayloadRootEndpoint endpoint = (PayloadRootEndpoint) applicationContext.getBean("endpoint");
assertTrue("doIt() not invoked on endpoint", endpoint.isDoItInvoked());
LogAspect aspect = (LogAspect) applicationContext.getBean("logAspect");
assertTrue("log() not invoked on aspect", aspect.isLogInvoked());
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2008 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.mapping;
import javax.xml.transform.Source;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
@Endpoint
public class PayloadRootEndpoint {
private static final Log logger = LogFactory.getLog(PayloadRootEndpoint.class);
private boolean doItInvoked = false;
public boolean isDoItInvoked() {
return doItInvoked;
}
@PayloadRoot(localPart = "Request", namespace = "http://springframework.org/spring-ws")
@org.springframework.ws.server.endpoint.mapping.Log
public void doIt(Source payload) {
doItInvoked = true;
logger.info("In doIt()");
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright ${YEAR} 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.soap.addressing.server;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPException;
import org.custommonkey.xmlunit.XMLTestCase;
import org.custommonkey.xmlunit.XMLUnit;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInvocationChain;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.soap.addressing.server.annotation.Action;
import org.springframework.ws.soap.addressing.server.annotation.Address;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
public class AnnotationActionMethodEndpointMappingTest extends XMLTestCase {
private StaticApplicationContext applicationContext;
private AnnotationActionEndpointMapping mapping;
private MessageFactory messageFactory;
protected void setUp() throws Exception {
messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
XMLUnit.setIgnoreWhitespace(true);
applicationContext = new StaticApplicationContext();
applicationContext.registerSingleton("mapping", AnnotationActionEndpointMapping.class);
mapping = (AnnotationActionEndpointMapping) applicationContext.getBean("mapping");
}
public void testNoAddress() throws Exception {
applicationContext.registerSingleton("endpoint", Endpoint1.class);
applicationContext.refresh();
MessageContext messageContext = createMessageContext();
EndpointInvocationChain chain = mapping.getEndpoint(messageContext);
assertNotNull("MethodEndpoint not registered", chain);
MethodEndpoint expected = new MethodEndpoint(applicationContext.getBean("endpoint"), "doIt", new Class[0]);
assertEquals("Invalid endpoint registered", expected, chain.getEndpoint());
}
public void testAddress() throws Exception {
applicationContext.registerSingleton("endpoint", Endpoint2.class);
applicationContext.refresh();
MessageContext messageContext = createMessageContext();
EndpointInvocationChain chain = mapping.getEndpoint(messageContext);
assertNotNull("MethodEndpoint not registered", chain);
MethodEndpoint expected = new MethodEndpoint(applicationContext.getBean("endpoint"), "doIt", new Class[0]);
assertEquals("Invalid endpoint registered", expected, chain.getEndpoint());
}
private MessageContext createMessageContext() throws SOAPException, IOException {
MimeHeaders mimeHeaders = new MimeHeaders();
mimeHeaders.addHeader("Content-Type", " application/soap+xml");
InputStream is = getClass().getResourceAsStream("valid.xml");
assertNotNull("Could not load valid.xml", is);
try {
SaajSoapMessage message = new SaajSoapMessage(messageFactory.createMessage(mimeHeaders, is));
return new DefaultMessageContext(message, new SaajSoapMessageFactory(messageFactory));
}
finally {
is.close();
}
}
@Endpoint
private static class Endpoint1 {
@Action("http://fabrikam123.example/mail/Delete")
public void doIt() {
}
}
@Endpoint
@Address("mailto:joe@fabrikam123.example")
private static class Endpoint2 {
@Action("http://fabrikam123.example/mail/Delete")
public void doIt() {
}
}
}

View File

@@ -0,0 +1,230 @@
/*
* 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.soap.server.endpoint;
import java.util.Locale;
import javax.xml.namespace.QName;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPMessage;
import junit.framework.TestCase;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.SoapVersion;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.soap.server.endpoint.annotation.FaultCode;
import org.springframework.ws.soap.server.endpoint.annotation.SoapFault;
import org.springframework.ws.soap.soap11.Soap11Fault;
import org.springframework.ws.soap.soap12.Soap12Fault;
public class SoapFaultAnnotationExceptionResolverTest extends TestCase {
private SoapFaultAnnotationExceptionResolver resolver;
protected void setUp() throws Exception {
resolver = new SoapFaultAnnotationExceptionResolver();
}
public void testResolveExceptionClientSoap11() throws Exception {
MessageFactory saajFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
SoapMessageFactory factory = new SaajSoapMessageFactory(saajFactory);
MessageContext context = new DefaultMessageContext(factory);
boolean result = resolver.resolveException(context, null, new MyClientException());
assertTrue("resolveException returns false", result);
assertTrue("Context has no response", context.hasResponse());
SoapMessage response = (SoapMessage) context.getResponse();
assertTrue("Resonse has no fault", response.getSoapBody().hasFault());
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getClientOrSenderFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "Client error", fault.getFaultStringOrReason());
assertNull("Detail on fault", fault.getFaultDetail());
}
public void testResolveExceptionSenderSoap12() throws Exception {
MessageFactory saajFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
SoapMessageFactory factory = new SaajSoapMessageFactory(saajFactory);
MessageContext context = new DefaultMessageContext(factory);
boolean result = resolver.resolveException(context, null, new MySenderException());
assertTrue("resolveException returns false", result);
assertTrue("Context has no response", context.hasResponse());
SoapMessage response = (SoapMessage) context.getResponse();
assertTrue("Resonse has no fault", response.getSoapBody().hasFault());
Soap12Fault fault = (Soap12Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_12.getClientOrSenderFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "Sender error", fault.getFaultReasonText(Locale.ENGLISH));
assertNull("Detail on fault", fault.getFaultDetail());
}
public void testResolveExceptionServerSoap11() throws Exception {
MessageFactory saajFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
SoapMessageFactory factory = new SaajSoapMessageFactory(saajFactory);
MessageContext context = new DefaultMessageContext(factory);
boolean result = resolver.resolveException(context, null, new MyServerException());
assertTrue("resolveException returns false", result);
assertTrue("Context has no response", context.hasResponse());
SoapMessage response = (SoapMessage) context.getResponse();
assertTrue("Resonse has no fault", response.getSoapBody().hasFault());
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getServerOrReceiverFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "Server error", fault.getFaultStringOrReason());
assertNull("Detail on fault", fault.getFaultDetail());
}
public void testResolveExceptionReceiverSoap12() throws Exception {
MessageFactory saajFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
SOAPMessage message = saajFactory.createMessage();
SoapMessageFactory factory = new SaajSoapMessageFactory(saajFactory);
MessageContext context = new DefaultMessageContext(new SaajSoapMessage(message), factory);
boolean result = resolver.resolveException(context, null, new MyReceiverException());
assertTrue("resolveException returns false", result);
assertTrue("Context has no response", context.hasResponse());
SoapMessage response = (SoapMessage) context.getResponse();
assertTrue("Resonse has no fault", response.getSoapBody().hasFault());
Soap12Fault fault = (Soap12Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_12.getServerOrReceiverFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "Receiver error", fault.getFaultReasonText(Locale.ENGLISH));
assertNull("Detail on fault", fault.getFaultDetail());
}
public void testResolveExceptionDefault() throws Exception {
SoapFaultDefinition defaultFault = new SoapFaultDefinition();
defaultFault.setFaultCode(SoapFaultDefinition.CLIENT);
defaultFault.setFaultStringOrReason("faultstring");
resolver.setDefaultFault(defaultFault);
MessageFactory saajFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
SoapMessageFactory factory = new SaajSoapMessageFactory(saajFactory);
MessageContext context = new DefaultMessageContext(factory);
boolean result = resolver.resolveException(context, null, new NonAnnotatedException());
assertTrue("resolveException returns false", result);
assertTrue("Context has no response", context.hasResponse());
SoapMessage response = (SoapMessage) context.getResponse();
assertTrue("Resonse has no fault", response.getSoapBody().hasFault());
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getClientOrSenderFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "faultstring", fault.getFaultStringOrReason());
assertNull("Detail on fault", fault.getFaultDetail());
}
public void testResolveExceptionCustom() throws Exception {
MessageFactory saajFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
SoapMessageFactory factory = new SaajSoapMessageFactory(saajFactory);
MessageContext context = new DefaultMessageContext(factory);
boolean result = resolver.resolveException(context, null, new MyCustomException());
assertTrue("resolveException returns false", result);
assertTrue("Context has no response", context.hasResponse());
SoapMessage response = (SoapMessage) context.getResponse();
assertTrue("Resonse has no fault", response.getSoapBody().hasFault());
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", new QName("http://springframework.org/spring-ws", "Fault"),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "MyCustomException thrown", fault.getFaultStringOrReason());
assertEquals("Invalid fault locale on fault", new Locale("nl"), fault.getFaultStringLocale());
}
public void testResolveExceptionInheritance() throws Exception {
MessageFactory saajFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
SoapMessageFactory factory = new SaajSoapMessageFactory(saajFactory);
MessageContext context = new DefaultMessageContext(factory);
boolean result = resolver.resolveException(context, null, new MySubClientException());
assertTrue("resolveException returns false", result);
assertTrue("Context has no response", context.hasResponse());
SoapMessage response = (SoapMessage) context.getResponse();
assertTrue("Resonse has no fault", response.getSoapBody().hasFault());
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getClientOrSenderFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "Client error", fault.getFaultStringOrReason());
assertNull("Detail on fault", fault.getFaultDetail());
}
public void testResolveExceptionExceptionMessage() throws Exception {
MessageFactory saajFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
SoapMessageFactory factory = new SaajSoapMessageFactory(saajFactory);
MessageContext context = new DefaultMessageContext(factory);
boolean result = resolver.resolveException(context, null, new NoStringOrReasonException("Exception message"));
assertTrue("resolveException returns false", result);
assertTrue("Context has no response", context.hasResponse());
SoapMessage response = (SoapMessage) context.getResponse();
assertTrue("Resonse has no fault", response.getSoapBody().hasFault());
Soap11Fault fault = (Soap11Fault) response.getSoapBody().getFault();
assertEquals("Invalid fault code on fault", SoapVersion.SOAP_11.getClientOrSenderFaultName(),
fault.getFaultCode());
assertEquals("Invalid fault string on fault", "Exception message", fault.getFaultStringOrReason());
assertNull("Detail on fault", fault.getFaultDetail());
}
@SoapFault(faultCode = FaultCode.CLIENT, faultStringOrReason = "Client error")
public class MyClientException extends Exception {
}
public class MySubClientException extends MyClientException {
}
@SoapFault(faultCode = FaultCode.CLIENT)
public class NoStringOrReasonException extends Exception {
public NoStringOrReasonException(String message) {
super(message);
}
}
@SoapFault(faultCode = FaultCode.SENDER, faultStringOrReason = "Sender error")
public class MySenderException extends Exception {
}
@SoapFault(faultCode = FaultCode.SERVER, faultStringOrReason = "Server error")
public class MyServerException extends Exception {
}
@SoapFault(faultCode = FaultCode.RECEIVER, faultStringOrReason = "Receiver error")
public class MyReceiverException extends Exception {
}
@SoapFault(faultCode = FaultCode.CUSTOM, customFaultCode = "{http://springframework.org/spring-ws}Fault",
faultStringOrReason = "MyCustomException thrown", locale = "nl")
public class MyCustomException extends Exception {
}
public class NonAnnotatedException extends Exception {
}
}

View File

@@ -0,0 +1,73 @@
/*
* 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.soap.server.endpoint.mapping;
import java.lang.reflect.Method;
import junit.framework.TestCase;
import static org.easymock.EasyMock.*;
import org.springframework.context.support.StaticApplicationContext;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.context.DefaultMessageContext;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.server.EndpointInvocationChain;
import org.springframework.ws.server.endpoint.MethodEndpoint;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.server.endpoint.annotation.SoapAction;
public class SoapActionAnnotationMethodEndpointMappingTest extends TestCase {
private SoapActionAnnotationMethodEndpointMapping mapping;
private StaticApplicationContext applicationContext;
protected void setUp() throws Exception {
applicationContext = new StaticApplicationContext();
applicationContext.registerSingleton("mapping", SoapActionAnnotationMethodEndpointMapping.class);
applicationContext.registerSingleton("endpoint", MyEndpoint.class);
applicationContext.refresh();
mapping = (SoapActionAnnotationMethodEndpointMapping) applicationContext.getBean("mapping");
}
public void testRegistration() throws Exception {
SoapMessage requestMock = createMock(SoapMessage.class);
expect(requestMock.getSoapAction()).andReturn("http://springframework.org/spring-ws/SoapAction");
WebServiceMessageFactory factoryMock = createMock(WebServiceMessageFactory.class);
replay(requestMock, factoryMock);
MessageContext context = new DefaultMessageContext(requestMock, factoryMock);
EndpointInvocationChain chain = mapping.getEndpoint(context);
assertNotNull("MethodEndpoint not registered", chain);
Method doIt = MyEndpoint.class.getMethod("doIt", new Class[0]);
MethodEndpoint expected = new MethodEndpoint("endpoint", applicationContext, doIt);
assertEquals("Invalid endpoint registered", expected, chain.getEndpoint());
verify(requestMock, factoryMock);
}
@Endpoint
private static class MyEndpoint {
@SoapAction("http://springframework.org/spring-ws/SoapAction")
public void doIt() {
}
}
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:sws="http://www.springframework.org/schema/web-services" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-1.5.xsd">
<sws:marshalling-endpoints/>
<bean id="marshaller" class="org.springframework.ws.config.DummyMarshaller"/>
<sws:xpath-endpoints>
<sws:namespace prefix="sws" uri="http://www.springframework.org/spring-ws"/>
</sws:xpath-endpoints>
</beans>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<aop:aspectj-autoproxy/>
<bean id="mapping"
class="org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping"/>
<bean id="endpoint" class="org.springframework.ws.server.endpoint.mapping.PayloadRootEndpoint"/>
<bean id="other" class="org.springframework.ws.server.endpoint.mapping.OtherBean"/>
<bean id="logAspect" class="org.springframework.ws.server.endpoint.mapping.LogAspect"/>
</beans>

View File

@@ -0,0 +1,17 @@
<S:Envelope xmlns:S="http://www.w3.org/2003/05/soap-envelope"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:f123="http://www.fabrikam123.example/svc53">
<S:Header>
<wsa:MessageID>uuid:aaaabbbb-cccc-dddd-eeee-ffffffffffff</wsa:MessageID>
<wsa:ReplyTo>
<wsa:Address>http://example.com/business/client1</wsa:Address>
</wsa:ReplyTo>
<wsa:To S:mustUnderstand="true">mailto:joe@fabrikam123.example</wsa:To>
<wsa:Action>http://fabrikam123.example/mail/Delete</wsa:Action>
</S:Header>
<S:Body>
<f123:Delete>
<maxCount>42</maxCount>
</f123:Delete>
</S:Body>
</S:Envelope>