1 /*
2  * Copyright 2005-2014 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.ws.soap.addressing.server;
18
19 import java.lang.annotation.Annotation;
20 import java.lang.reflect.Method;
21 import java.net.URI;
22 import java.net.URISyntaxException;
23
24 import org.springframework.aop.support.AopUtils;
25 import org.springframework.beans.BeansException;
26 import org.springframework.beans.factory.config.BeanPostProcessor;
27 import org.springframework.core.annotation.AnnotationUtils;
28 import org.springframework.util.StringUtils;
29 import org.springframework.ws.server.endpoint.MethodEndpoint;
30 import org.springframework.ws.server.endpoint.annotation.Endpoint;
31 import org.springframework.ws.soap.addressing.core.MessageAddressingProperties;
32 import org.springframework.ws.soap.addressing.server.annotation.Action;
33 import org.springframework.ws.soap.addressing.server.annotation.Address;
34
35 /**
36  * Implementation of the {@link org.springframework.ws.server.EndpointMapping} interface that uses the
37  * {@link Action @Action} annotation to map methods to a WS-Addressing {@code Action} header.
38  *
39  * <p>Endpoints typically have the following form:
40  * <pre>
41  * &#64;Endpoint
42  * &#64;Address("mailto:joe@fabrikam123.example")
43  * public class MyEndpoint{
44  *      &#64;Action("http://fabrikam123.example/mail/Delete")
45  *      public Source doSomethingWithRequest() {
46  *         ...
47  *      }
48  * }
49  * </pre>
50  *
51  * <p>If set, the {@link Address @Address} annotation on the endpoint class should be equal to the {@link
52  * org.springframework.ws.soap.addressing.core.MessageAddressingProperties#getTo() destination} property of the
53  * incoming message.
54  *
55  * @author Arjen Poutsma
56  * @see Action
57  * @see Address
58  * @since 1.5.0
59  */

60 public class AnnotationActionEndpointMapping extends AbstractActionMethodEndpointMapping implements BeanPostProcessor {
61
62     /** Returns the 'endpoint' annotation type. Default is {@link Endpoint}. */
63     protected Class<? extends Annotation> getEndpointAnnotationType() {
64         return Endpoint.class;
65     }
66
67     /**
68      * Returns the action value for the specified method. Default implementation looks for the {@link Action} annotation
69      * value.
70      */

71     @Override
72     protected URI getActionForMethod(Method method) {
73         Action action = method.getAnnotation(Action.class);
74         if (action != null && StringUtils.hasText(action.value())) {
75             try {
76                 return new URI(action.value());
77             }
78             catch (URISyntaxException e) {
79                 throw new IllegalArgumentException(
80                         "Invalid Action annotation [" + action.value() + "] on [" + method + "]");
81             }
82         }
83         return null;
84     }
85
86     /**
87      * Returns the address property of the given {@link MethodEndpoint}, by looking for the {@link Address} annotation.
88      * The value of this property should match the {@link org.springframework.ws.soap.addressing.core.MessageAddressingProperties#getTo()
89      * destination} of incoming messages. Returns {@code nullif the anotation is not present, thus ignoring the
90      * destination property.
91      *
92      * @param endpoint the method endpoint to return the address for
93      * @return the endpoint address; or {@code null} to ignore the destination property
94      */

95     @Override
96     protected URI getEndpointAddress(Object endpoint) {
97         MethodEndpoint methodEndpoint = (MethodEndpoint) endpoint;
98         Class<?> endpointClass = methodEndpoint.getMethod().getDeclaringClass();
99         Address address = AnnotationUtils.findAnnotation(endpointClass, Address.class);
100         if (address != null && StringUtils.hasText(address.value())) {
101             return getActionUri(address.value(), methodEndpoint);
102         }
103         else {
104             return null;
105         }
106     }
107
108     @Override
109     protected URI getResponseAction(Object endpoint, MessageAddressingProperties map) {
110         MethodEndpoint methodEndpoint = (MethodEndpoint) endpoint;
111         Action action = methodEndpoint.getMethod().getAnnotation(Action.class);
112         if (action != null && StringUtils.hasText(action.output())) {
113             return getActionUri(action.output(), methodEndpoint);
114         }
115         else {
116             return super.getResponseAction(endpoint, map);
117         }
118     }
119
120     @Override
121     protected URI getFaultAction(Object endpoint, MessageAddressingProperties map) {
122         MethodEndpoint methodEndpoint = (MethodEndpoint) endpoint;
123         Action action = methodEndpoint.getMethod().getAnnotation(Action.class);
124         if (action != null && StringUtils.hasText(action.fault())) {
125             return getActionUri(action.fault(), methodEndpoint);
126         }
127         else {
128             return super.getResponseAction(endpoint, map);
129         }
130     }
131
132     private URI getActionUri(String action, MethodEndpoint methodEndpoint) {
133         try {
134             return new URI(action);
135         }
136         catch (URISyntaxException e) {
137             throw new IllegalArgumentException(
138                     "Invalid Action annotation [" + action + "] on [" + methodEndpoint + "]");
139         }
140     }
141
142     @Override
143     public final Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
144         return bean;
145     }
146
147     @Override
148     public final Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
149         if (AopUtils.getTargetClass(bean).getAnnotation(getEndpointAnnotationType()) != null) {
150             registerMethods(bean);
151         }
152         return bean;
153     }
154 }
155