diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractActionEndpointMapping.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractActionEndpointMapping.java
new file mode 100644
index 00000000..e19c9a8c
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractActionEndpointMapping.java
@@ -0,0 +1,97 @@
+/*
+ * 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;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.util.Assert;
+
+/**
+ * @author Arjen Poutsma
+ * @since 1.5.0
+ */
+public abstract class AbstractActionEndpointMapping extends AbstractAddressingEndpointMapping
+ implements ApplicationContextAware {
+
+ // keys are action URIs, values are endpoints
+ private final Map endpointMap = new HashMap();
+
+ private ApplicationContext applicationContext;
+
+ /**
+ * Looks up an endpoint instance for the given action. All keys are tried in order.
+ *
+ * @param action the action URI
+ * @return the associated endpoint instance, or null if not found
+ */
+ protected Object lookupEndpoint(URI action) {
+ return endpointMap.get(action);
+ }
+
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+
+ /**
+ * Register the specified endpoint for the given action URI.
+ *
+ * @param action the action the bean should be mapped to
+ * @param endpoint the endpoint instance or endpoint bean name String (a bean name will automatically be resolved
+ * into the corresponding endpoint bean)
+ * @throws org.springframework.beans.BeansException
+ * if the endpoint couldn't be registered
+ * @throws IllegalStateException if there is a conflicting endpoint registered
+ */
+ protected void registerEndpoint(URI action, Object endpoint) throws BeansException, IllegalStateException {
+ Assert.notNull(action, "Action must not be null");
+ Assert.notNull(endpoint, "Endpoint object must not be null");
+ Object resolvedEndpoint = endpoint;
+
+ if (endpoint instanceof String) {
+ String endpointName = (String) endpoint;
+ if (applicationContext.isSingleton(endpointName)) {
+ resolvedEndpoint = applicationContext.getBean(endpointName);
+ }
+ }
+ Object mappedEndpoint = this.endpointMap.get(action);
+ if (mappedEndpoint != null) {
+ if (mappedEndpoint != resolvedEndpoint) {
+ throw new IllegalStateException("Cannot map endpoint [" + endpoint + "] to action [" + action +
+ "]: There is already endpoint [" + resolvedEndpoint + "] mapped.");
+ }
+ }
+ else {
+ this.endpointMap.put(action, resolvedEndpoint);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Mapped Action [" + action + "] onto endpoint [" + resolvedEndpoint + "]");
+ }
+ }
+ }
+
+ protected final Object getEndpointInternal(MessageAddressingProperties map) {
+ return getEndpointInternal(map.getTo(), map.getAction());
+ }
+
+ protected abstract Object getEndpointInternal(URI to, URI action);
+
+
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractActionMethodEndpointMapping.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractActionMethodEndpointMapping.java
new file mode 100644
index 00000000..5d3c559e
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AbstractActionMethodEndpointMapping.java
@@ -0,0 +1,78 @@
+/*
+ * 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;
+
+import java.lang.reflect.Method;
+import java.net.URI;
+
+import org.springframework.aop.support.AopUtils;
+import org.springframework.core.JdkVersion;
+import org.springframework.util.Assert;
+import org.springframework.ws.server.endpoint.MethodEndpoint;
+
+/**
+ * @author Arjen Poutsma
+ * @since 1.5.0
+ */
+public abstract class AbstractActionMethodEndpointMapping extends AbstractActionEndpointMapping {
+
+ /**
+ * Helper method that registers the methods of the given bean. This method iterates over the methods of the bean,
+ * and calls {@link #getActionForMethod(Method)} for each. If this returns a URI, the method is registered using
+ * {@link #registerEndpoint(URI, Object)}.
+ *
+ * @see #getActionForMethod (java.lang.reflect.Method)
+ */
+ protected void registerMethods(Object endpoint) {
+ Assert.notNull(endpoint, "'endpoint' must not be null");
+ Method[] methods = getEndpointClass(endpoint).getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ if (JdkVersion.isAtLeastJava15() && methods[i].isSynthetic() ||
+ methods[i].getDeclaringClass().equals(Object.class)) {
+ continue;
+ }
+ URI action = getActionForMethod(methods[i]);
+ if (action != null) {
+ registerEndpoint(action, new MethodEndpoint(endpoint, methods[i]));
+ }
+ }
+ }
+
+ /**
+ * Returns the the action URI for the given method. Returns null if the method is not to be registered,
+ * which is the default.
+ *
+ * @param method the method
+ * @return the action URI, or null if the method is not to be registered
+ */
+ protected URI getActionForMethod(Method method) {
+ return null;
+ }
+
+ /**
+ * Return the class or interface to use for method reflection.
+ *
XwsSecurityInterceptor.
- */
- public final void setPreInterceptors(EndpointInterceptor[] preInterceptors) {
- this.preInterceptors = preInterceptors;
- }
-
- /**
- * Set additional interceptors to be applied after the implicit WS-Addressing interceptor, e.g.
- * PayloadLoggingInterceptor.
- */
- public final void setPostInterceptors(EndpointInterceptor[] postInterceptors) {
- this.postInterceptors = postInterceptors;
- }
-
- /**
- * Sets the message id provider used for creating WS-Addressing MessageIds.
- *
- * By default, the {@link UuidMessageIdStrategy} is used on Java 5 and higher, and the {@link
- * RandomGuidMessageIdStrategy} on Java 1.4.
- */
- public final void setMessageIdProvider(MessageIdStrategy messageIdStrategy) {
- this.messageIdStrategy = messageIdStrategy;
- }
-
- public final void setMessageSenders(WebServiceMessageSender[] messageSenders) {
- this.messageSenders = messageSenders;
- }
-
- /**
- * Sets the WS-Addressing versions to be supported by this mapping.
- *
- * By default, this array is set to support {@link WsAddressing200408 the August 2004} and the {@link
- * WsAddressing200605 May 2006} versions of the specification.
- */
- public final void setVersions(WsAddressingVersion[] versions) {
- this.versions = versions;
- }
-
- public void afterPropertiesSet() throws Exception {
- if (logger.isInfoEnabled()) {
- logger.info("Supporting WS-Addressing " + Arrays.asList(versions));
- }
- }
-
- public final EndpointInvocationChain getEndpoint(MessageContext messageContext) throws TransformerException {
- Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
- SoapMessage request = (SoapMessage) messageContext.getRequest();
- for (int i = 0; i < versions.length; i++) {
- if (supports(versions[i], request)) {
- MessageAddressingProperties requestMap = versions[i].getMessageAddressingProperties(request);
- if (requestMap == null) {
- return null;
- }
- Object endpoint = getEndpointInternal(requestMap);
- if (endpoint == null) {
- return null;
- }
- return new SoapEndpointInvocationChain(endpoint, getAllEndpointInterceptors(versions[i]), actorsOrRoles,
- isUltimateReceiver);
- }
- }
- return null;
- }
-
- private boolean supports(WsAddressingVersion version, SoapMessage request) {
- SoapHeader header = request.getSoapHeader();
- if (header != null) {
- for (Iterator iterator = header.examineAllHeaderElements(); iterator.hasNext();) {
- SoapHeaderElement headerElement = (SoapHeaderElement) iterator.next();
- if (version.understands(headerElement)) {
- return true;
- }
- }
- }
- return false;
- }
-
- private EndpointInterceptor[] getAllEndpointInterceptors(WsAddressingVersion version) {
- // lazy init
- if (allInterceptors == null) {
- if (preInterceptors == null) {
- preInterceptors = new EndpointInterceptor[0];
- }
- if (postInterceptors == null) {
- postInterceptors = new EndpointInterceptor[0];
- }
- allInterceptors = new EndpointInterceptor[preInterceptors.length + postInterceptors.length + 1];
- System.arraycopy(preInterceptors, 0, allInterceptors, 0, preInterceptors.length);
- System.arraycopy(postInterceptors, 0, allInterceptors, preInterceptors.length + 1, postInterceptors.length);
- }
- allInterceptors[preInterceptors.length] =
- new WsAddressingEndpointInterceptor(version, messageIdStrategy, messageSenders);
- return allInterceptors;
- }
-
- /**
- * Lookup an endpoint for the given {@link MessageAddressingProperties}, returning null if no specific
- * one is found. This template method is called by {@link #getEndpoint(MessageContext)}.
- *
- * @param map the message addressing properties
- * @return the endpoint, or null
- */
- protected abstract Object getEndpointInternal(MessageAddressingProperties map);
-
-}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AddressingEndpointInterceptor.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AddressingEndpointInterceptor.java
index 91556904..67edb39c 100644
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AddressingEndpointInterceptor.java
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AddressingEndpointInterceptor.java
@@ -33,7 +33,7 @@ import org.springframework.ws.transport.WebServiceMessageSender;
/**
* {@link SoapEndpointInterceptor} implementation that deals with WS-Addressing headers. Stateful, and instatiated by
- * the {@link AbstractWsAddressingEndpointMapping}.
+ * the {@link AbstractAddressingEndpointMapping}.
*
* @author Arjen Poutsma
* @since 1.5.0
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/AnnotationActionMethodEndpointMapping.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AnnotationActionMethodEndpointMapping.java
new file mode 100644
index 00000000..3252d0a2
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/AnnotationActionMethodEndpointMapping.java
@@ -0,0 +1,94 @@
+/*
+ * 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;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+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.annotation.Action;
+import org.springframework.ws.soap.addressing.annotation.Address;
+
+/**
+ * @author Arjen Poutsma
+ * @since 1.5.0
+ */
+public class AnnotationActionMethodEndpointMapping extends AbstractActionMethodEndpointMapping
+ implements BeanPostProcessor {
+
+ /** Returns the 'endpoint' annotation type. Default is {@link Endpoint}. */
+ protected Class extends Annotation> getEndpointAnnotationType() {
+ return Endpoint.class;
+ }
+
+ public final Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+
+ public final Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ if (getEndpointClass(bean).getAnnotation(getEndpointAnnotationType()) != null) {
+ registerMethods(bean);
+ }
+ return bean;
+ }
+
+ protected URI getActionForMethod(Method method) {
+ Action action = method.getAnnotation(Action.class);
+ if (action != null) {
+ try {
+ return new URI(action.value());
+ }
+ catch (URISyntaxException e) {
+ // ignore
+ }
+ }
+ return null;
+ }
+
+ protected Object getEndpointInternal(URI to, URI action) {
+ MethodEndpoint methodEndpoint = (MethodEndpoint) lookupEndpoint(action);
+ if (methodEndpoint != null) {
+ // respect the Address annotation, if set
+ Class endpointClass = methodEndpoint.getMethod().getDeclaringClass();
+ Address address = AnnotationUtils.findAnnotation(endpointClass, Address.class);
+ if (address != null && StringUtils.hasText(address.value())) {
+ try {
+ URI addressUri = new URI(address.value());
+ if (to.equals(addressUri)) {
+ return methodEndpoint;
+ }
+ }
+ catch (URISyntaxException e) {
+ throw new IllegalArgumentException(
+ "Invalid Address annotation [" + address.value() + "] on [" + endpointClass + "]");
+ }
+ }
+ else {
+ // address not set
+ return methodEndpoint;
+ }
+ }
+ return null;
+ }
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/SimpleActionEndpointMapping.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/SimpleActionEndpointMapping.java
new file mode 100644
index 00000000..da6602d4
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/SimpleActionEndpointMapping.java
@@ -0,0 +1,142 @@
+/*
+ * 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;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+
+import org.springframework.beans.BeansException;
+
+/**
+ * Implementation of the EndpointMapping interface to map from WS-Addressing Action Message
+ * Addressing Property to endpoint beans. Supports both mapping to bean instances and mapping to bean names.
+ *
+ * The endpointMap property is suitable for populating the endpoint map with bean references, e.g. via the
+ * map element in XML bean definitions.
+ *
+ * Mappings to bean names can be set via the mappings property, in a form accepted by the
+ * java.util.Properties class, like as follows:
+ * + * http://www.springframework.org/spring-ws/samples/airline/BookFlight=bookFlightEndpoint + * http://www.springframework.org/spring-ws/samples/airline/GetFlights=getFlightsEndpoint + *+ * The syntax is WS_ADDRESSING_ACTION=ENDPOINT_BEAN_NAME. + * + * If set, the {@link #setAddress(URI) address} property should be equal to the {@link + * MessageAddressingProperties#getTo() destination} property of the incominging message. As such, it can be used to + * create multiple Endpoint References, by defining multiple
SimpleActionEndpointMapping bean definitions
+ * with different addressproperty values.
+ *
+ * @author Arjen Poutsma
+ * @see MessageAddressingProperties#getAction()
+ * @since 1.5.0
+ */
+public class SimpleActionEndpointMapping extends AbstractActionEndpointMapping {
+
+ // contents will be copied over to endpointMap
+ private final Map actionMap = new HashMap();
+
+ private URI address;
+
+ /**
+ * Map action URIs to endpoint bean names. This is the typical way of configuring this EndpointMapping.
+ *
+ * @param mappings properties with URLs as keys and bean names as values
+ * @see #setActionMap(java.util.Map)
+ */
+ public void setMappings(Properties mappings) throws URISyntaxException {
+ setActionMap(mappings);
+ }
+
+ /**
+ * Set a Map with action URIs as keys and handler beans (or handler bean names) as values. Convenient for population
+ * with bean references.
+ *
+ * @param actionMap map with action URIs as keys and beans as values
+ * @see #setMappings
+ */
+ public void setActionMap(Map actionMap) throws URISyntaxException {
+ Iterator it = actionMap.entrySet().iterator();
+ while (it.hasNext()) {
+ Map.Entry entry = (Map.Entry) it.next();
+ URI action;
+ if (entry.getKey() instanceof String) {
+ action = new URI((String) entry.getKey());
+ }
+ else if (entry.getKey() instanceof URI) {
+ action = (URI) entry.getKey();
+ }
+ else {
+ throw new IllegalArgumentException("Invalid key [" + entry.getKey() + "]; expected String or URI");
+ }
+ this.actionMap.put(action, entry.getValue());
+ }
+ }
+
+ /**
+ * Set the address property. If set, value of this property is compared to the {@link
+ * MessageAddressingProperties#getTo() destination} property of the incominging message.
+ *
+ * @param address the address URI
+ */
+ public void setAddress(URI address) {
+ this.address = address;
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ super.afterPropertiesSet();
+ registerEndpoints(actionMap);
+ }
+
+ protected Object getEndpointInternal(URI to, URI action) {
+ // MAP address much match the defined EPR address
+ if (address != null && !address.equals(to)) {
+ return null;
+ }
+ return lookupEndpoint(action);
+ }
+
+ /**
+ * Register all endpoints specified in the action map.
+ *
+ * @param actionMap Map with action URIs as keys and endppint beans or bean names as values
+ * @throws BeansException if an endpoint couldn't be registered
+ * @throws IllegalStateException if there is a conflicting endpoint registered
+ */
+ protected void registerEndpoints(Map actionMap) throws BeansException {
+ if (actionMap.isEmpty()) {
+ logger.warn("Neither 'actionMap' nor 'mappings' set on SimpleActionEndpointMapping");
+ }
+ else {
+ for (Iterator iterator = actionMap.entrySet().iterator(); iterator.hasNext();) {
+ Map.Entry entry = (Map.Entry) iterator.next();
+ URI action = (URI) entry.getKey();
+ Object endpoint = entry.getValue();
+ // Remove whitespace from endpoint bean name.
+ if (endpoint instanceof String) {
+ endpoint = ((String) endpoint).trim();
+ }
+ registerEndpoint(action, endpoint);
+ }
+ }
+ }
+
+}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingActionEndpointMapping.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingActionEndpointMapping.java
deleted file mode 100644
index f45c0fe2..00000000
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingActionEndpointMapping.java
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * 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;
-
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Properties;
-
-import org.springframework.beans.BeansException;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.util.Assert;
-
-/**
- * Implementation of the EndpointMapping interface to map from WS-Addressing Action headers to
- * endpoint beans. Supports both mapping to bean instances and mapping to bean names.
- *
- * The endpointMap property is suitable for populating the endpoint map with bean references, e.g. via the
- * map element in XML bean definitions.
- *
- * Mappings to bean names can be set via the mappings property, in a form accepted by the
- * java.util.Properties class, like as follows:
- * - * http://www.springframework.org/spring-ws/samples/airline/BookFlight=bookFlightEndpoint - * http://www.springframework.org/spring-ws/samples/airline/GetFlights=getFlightsEndpoint - *- * The syntax is WS_ADDRESSING_ACTION=ENDPOINT_BEAN_NAME. - * - * If set, the
destination property is used suitable for further endpoint determination. can be used to set
- * an EndpointReference destination (i.e. the To element). If this propert
- *
- * @author Arjen Poutsma
- * @since 1.5.0
- */
-public class WsAddressingActionEndpointMapping extends AbstractWsAddressingEndpointMapping
- implements ApplicationContextAware {
-
- // keys are action URIs, values are endpoints
- private final Map endpointMap = new HashMap();
-
- // contents will be copied over to endpointMap
- private final Map temporaryEndpointMap = new HashMap();
-
- private URI destination;
-
- private ApplicationContext applicationContext;
-
- public void setMappings(Properties mappings) throws URISyntaxException {
- setEndpointMap(mappings);
- }
-
- public void setEndpointMap(Map actionMap) throws URISyntaxException {
- Iterator it = actionMap.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- URI action;
- if (entry.getKey() instanceof String) {
- action = new URI((String) entry.getKey());
- }
- else if (entry.getKey() instanceof URI) {
- action = (URI) entry.getKey();
- }
- else {
- throw new IllegalArgumentException("Invalid key [" + entry.getKey() + "]; expected String or URI");
- }
- this.temporaryEndpointMap.put(action, entry.getValue());
- }
- }
-
- public void setDestination(URI destination) {
- this.destination = destination;
- }
-
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- this.applicationContext = applicationContext;
- registerEndpoints(temporaryEndpointMap);
- }
-
- protected Object getEndpointInternal(MessageAddressingProperties map) {
- // MAP address much match the defined EPR address
- if (destination != null && !destination.equals(map.getTo())) {
- return null;
- }
- return endpointMap.get(map.getAction());
- }
-
- protected void registerEndpoints(Map endpointMap) throws BeansException {
- if (endpointMap.isEmpty()) {
- logger.warn("Neither 'actionMap' nor 'mappings' set on WsAddressingActionEndpointMapping");
- }
- else {
- Iterator it = endpointMap.entrySet().iterator();
- while (it.hasNext()) {
- Map.Entry entry = (Map.Entry) it.next();
- URI action = (URI) entry.getKey();
- Object endpoint = entry.getValue();
- // Remove whitespace from endpoint bean name.
- if (endpoint instanceof String) {
- endpoint = ((String) endpoint).trim();
- }
- registerEndpoint(action, endpoint);
- }
- }
- }
-
- protected void registerEndpoint(URI action, Object endpoint) throws BeansException, IllegalStateException {
- Assert.notNull(action, "Action must not be null");
- Assert.notNull(endpoint, "Endpoint object must not be null");
- Object resolvedEndpoint = endpoint;
-
- if (endpoint instanceof String) {
- String endpointName = (String) endpoint;
- if (applicationContext.isSingleton(endpointName)) {
- resolvedEndpoint = applicationContext.getBean(endpointName);
- }
- }
- Object mappedEndpoint = this.endpointMap.get(action);
- if (mappedEndpoint != null) {
- if (mappedEndpoint != resolvedEndpoint) {
- throw new IllegalStateException("Cannot map endpoint [" + endpoint + "] to action [" + action +
- "]: There is already endpoint [" + resolvedEndpoint + "] mapped.");
- }
- }
- else {
- this.endpointMap.put(action, resolvedEndpoint);
- if (logger.isDebugEnabled()) {
- logger.debug("Mapped Action [" + action + "] onto endpoint [" + resolvedEndpoint + "]");
- }
- }
- }
-}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingEndpointInterceptor.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingEndpointInterceptor.java
deleted file mode 100644
index 4fdc2221..00000000
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/WsAddressingEndpointInterceptor.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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.addressing;
-
-import java.io.IOException;
-import java.net.URI;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import org.springframework.util.Assert;
-import org.springframework.ws.context.MessageContext;
-import org.springframework.ws.soap.SoapHeaderElement;
-import org.springframework.ws.soap.SoapMessage;
-import org.springframework.ws.soap.addressing.messageid.MessageIdStrategy;
-import org.springframework.ws.soap.server.SoapEndpointInterceptor;
-import org.springframework.ws.transport.WebServiceConnection;
-import org.springframework.ws.transport.WebServiceMessageSender;
-
-/**
- * {@link SoapEndpointInterceptor} implementation that deals with WS-Addressing headers. Stateful, and instatiated by
- * the {@link AbstractWsAddressingMapping}.
- *
- * @author Arjen Poutsma
- * @since 1.5.0
- */
-class WsAddressingEndpointInterceptor implements SoapEndpointInterceptor {
-
- private static final Log logger = LogFactory.getLog(WsAddressingEndpointInterceptor.class);
-
- private final WsAddressingVersion version;
-
- private final MessageIdStrategy messageIdStrategy;
-
- private final WebServiceMessageSender[] messageSenders;
-
- WsAddressingEndpointInterceptor(WsAddressingVersion version,
- MessageIdStrategy messageIdStrategy,
- WebServiceMessageSender[] messageSenders) {
- Assert.notNull(version, "version must not be null");
- Assert.notNull(messageIdStrategy, "messageIdStrategy must not be null");
- Assert.notNull(messageSenders, "messageSenders must not be null");
- this.version = version;
- this.messageIdStrategy = messageIdStrategy;
- this.messageSenders = messageSenders;
- }
-
- public boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
- Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
- SoapMessage request = (SoapMessage) messageContext.getRequest();
- MessageAddressingProperties requestMap = version.getMessageAddressingProperties(request);
- if (!requestMap.hasRequiredProperties()) {
- version.addMessageAddressingHeaderRequiredFault((SoapMessage) messageContext.getResponse());
- return false;
- }
- if (!requestMap.isValid() || messageIdStrategy.isDuplicate(requestMap.getMessageId())) {
- version.addInvalidAddressingHeaderFault((SoapMessage) messageContext.getResponse());
- return false;
- }
- return true;
- }
-
- public boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
- return handleResponseOrFault(messageContext, false);
- }
-
- public boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
- return handleResponseOrFault(messageContext, true);
- }
-
- private boolean handleResponseOrFault(MessageContext messageContext, boolean isFault) throws Exception {
- Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
- Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse());
- SoapMessage request = (SoapMessage) messageContext.getRequest();
- MessageAddressingProperties requestMap = version.getMessageAddressingProperties(request);
- EndpointReference replyEpr = isFault ? requestMap.getFaultTo() : requestMap.getReplyTo();
- if (handleNoneAddress(messageContext, replyEpr)) {
- return false;
- }
- URI responseMessageId = getMessageId(messageContext);
- MessageAddressingProperties replyMap = requestMap.getReplyProperties(replyEpr, null, responseMessageId);
- version.addAddressingHeaders((SoapMessage) messageContext.getResponse(), replyMap);
- if (handleAnonymousAddress(messageContext, replyEpr)) {
- return true;
- }
- else {
- sendOutOfBand(messageContext, replyEpr);
- return false;
- }
- }
-
- private boolean handleNoneAddress(MessageContext messageContext, EndpointReference replyEpr) {
- if (replyEpr == null || version.hasNoneAddress(replyEpr)) {
- if (logger.isDebugEnabled()) {
- logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
- "] reply address; reply [" + messageContext.getResponse() + "] discarded");
- }
- messageContext.clearResponse();
- return true;
- }
- return false;
- }
-
- private boolean handleAnonymousAddress(MessageContext messageContext, EndpointReference replyEpr) {
- if (version.hasAnonymousAddress(replyEpr)) {
- if (logger.isDebugEnabled()) {
- logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
- "] reply address; sending in-band reply [" + messageContext.getResponse() + "]");
- }
- return true;
- }
- return false;
- }
-
- private void sendOutOfBand(MessageContext messageContext, EndpointReference replyEpr) throws IOException {
- if (logger.isDebugEnabled()) {
- logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
- "] reply address; sending out-of-band reply [" + messageContext.getResponse() + "]");
- }
-
- boolean supported = false;
- for (int i = 0; i < messageSenders.length; i++) {
- if (messageSenders[i].supports(replyEpr.getAddress())) {
- supported = true;
- WebServiceConnection connection = null;
- try {
- connection = messageSenders[i].createConnection(replyEpr.getAddress());
- connection.send(messageContext.getResponse());
- break;
- }
- finally {
- messageContext.clearResponse();
- if (connection != null) {
- connection.close();
- }
- }
- }
- }
- if (!supported) {
- logger.warn("Could not send out-of-band response to [" + replyEpr.getAddress() + "]. " +
- "Configure WebServiceMessageSenders which support this uri.");
- }
- }
-
- private URI getMessageId(MessageContext messageContext) {
- URI responseMessageId = messageIdStrategy.newMessageId(messageContext);
- if (logger.isTraceEnabled()) {
- logger.trace("Generated reply MessageID [" + responseMessageId + "] for [" + messageContext + "]");
- }
- return responseMessageId;
- }
-
- public boolean understands(SoapHeaderElement header) {
- return version.understands(header);
- }
-}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/annotation/Action.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/annotation/Action.java
index dd1420f1..9a8bace3 100644
--- a/sandbox/src/main/java/org/springframework/ws/soap/addressing/annotation/Action.java
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/annotation/Action.java
@@ -23,6 +23,9 @@ 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 Action header that is handled by the method.
+ *
* @author Arjen Poutsma
* @since 1.5.0
*/
@@ -31,4 +34,13 @@ import java.lang.annotation.Target;
@Target(ElementType.METHOD)
public @interface Action {
+ /** Signifies the value for the request WS-Addressing Action header that is handled by the method. */
+ String value();
+
+ /**
+ * Explicit value of the WS-Addressing Action message addressing property for the output
+ * message of the operation.
+ */
+ String output() default "";
+
}
diff --git a/sandbox/src/main/java/org/springframework/ws/soap/addressing/annotation/Address.java b/sandbox/src/main/java/org/springframework/ws/soap/addressing/annotation/Address.java
new file mode 100644
index 00000000..63adfe5c
--- /dev/null
+++ b/sandbox/src/main/java/org/springframework/ws/soap/addressing/annotation/Address.java
@@ -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.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 Address. If this annotation is applied, the {@link #value()} is
+ * compared to the {@link org.springframework.ws.soap.addressing.MessageAddressingProperties#getTo() destination}
+ * property of the incominging message.
+ *
+ * as the handler for an incoming request. The annotation value signifies the value for the request WS-Addressing
+ * Action header that is handled by the method.
+ *
+ * @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();
+
+}
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/AnnotationActionMethodEndpointMappingTest.java b/sandbox/src/test/java/org/springframework/ws/soap/addressing/AnnotationActionMethodEndpointMappingTest.java
new file mode 100644
index 00000000..97c8c7a9
--- /dev/null
+++ b/sandbox/src/test/java/org/springframework/ws/soap/addressing/AnnotationActionMethodEndpointMappingTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import javax.xml.soap.SOAPException;
+
+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.annotation.Action;
+import org.springframework.ws.soap.addressing.annotation.Address;
+import org.springframework.ws.soap.saaj.SaajSoapMessage;
+import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
+
+public class AnnotationActionMethodEndpointMappingTest extends AbstractWsAddressingTestCase {
+
+ private StaticApplicationContext applicationContext;
+
+ private AnnotationActionMethodEndpointMapping mapping;
+
+ protected void onSetUp() throws Exception {
+ applicationContext = new StaticApplicationContext();
+ applicationContext.registerSingleton("mapping", AnnotationActionMethodEndpointMapping.class);
+ mapping = (AnnotationActionMethodEndpointMapping) 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 {
+ SaajSoapMessage message = loadSaajMessage("200408/valid.xml");
+ return new DefaultMessageContext(message, new SaajSoapMessageFactory(messageFactory));
+ }
+
+ @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() {
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressingActionEndpointMappingTest.java b/sandbox/src/test/java/org/springframework/ws/soap/addressing/SimpleActionEndpointMappingTest.java
similarity index 93%
rename from sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressingActionEndpointMappingTest.java
rename to sandbox/src/test/java/org/springframework/ws/soap/addressing/SimpleActionEndpointMappingTest.java
index cad9585d..681c0dde 100644
--- a/sandbox/src/test/java/org/springframework/ws/soap/addressing/WsAddressingActionEndpointMappingTest.java
+++ b/sandbox/src/test/java/org/springframework/ws/soap/addressing/SimpleActionEndpointMappingTest.java
@@ -28,16 +28,16 @@ import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor;
-public class WsAddressingActionEndpointMappingTest extends AbstractWsAddressingTestCase {
+public class SimpleActionEndpointMappingTest extends AbstractWsAddressingTestCase {
- private WsAddressingActionEndpointMapping mapping;
+ private SimpleActionEndpointMapping mapping;
private Endpoint1 endpoint1;
private Endpoint2 endpoint2;
protected void onSetUp() throws Exception {
- mapping = new WsAddressingActionEndpointMapping();
+ mapping = new SimpleActionEndpointMapping();
Map map = new HashMap();
endpoint1 = new Endpoint1();
endpoint2 = new Endpoint2();
@@ -46,7 +46,6 @@ public class WsAddressingActionEndpointMappingTest extends AbstractWsAddressingT
mapping.setPreInterceptors(new EndpointInterceptor[]{new PayloadLoggingInterceptor()});
mapping.setPostInterceptors(new EndpointInterceptor[]{new PayloadValidatingInterceptor()});
mapping.setActionMap(map);
- mapping.setApplicationContext(null);
mapping.afterPropertiesSet();
}