View Javadoc

1   /*
2    * Copyright 2005-2010 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.net.URI;
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  import org.springframework.beans.BeansException;
24  import org.springframework.context.ApplicationContext;
25  import org.springframework.context.ApplicationContextAware;
26  import org.springframework.util.Assert;
27  import org.springframework.ws.soap.addressing.core.MessageAddressingProperties;
28  
29  /**
30   * Abstract base class for WS-Addressing <code>Action</code>-mapped [email protected] org.springframework.ws.server.EndpointMapping}
31   * implementations. Provides infrastructure for mapping endpoints to actions.
32   * <p/>
33   * By default, this mapping creates a <code>Action</code> for reply messages based on the request message, plus the
34   * extra [email protected] #setOutputActionSuffix(String) suffix}, and a   * By default, this mapping creates a <code>Action</code>
35   * for reply messages based on the request message, plus the extra [email protected] #setOutputActionSuffix(String) suffix}.
36   *
37   * @author Arjen Poutsma
38   * @since 1.5.0
39   */
40  public abstract class AbstractActionEndpointMapping extends AbstractAddressingEndpointMapping
41          implements ApplicationContextAware {
42  
43      /** The defaults suffix to add to the request <code>Action</code> for reply messages. */
44      public static final String DEFAULT_OUTPUT_ACTION_SUFFIX = "Response";
45  
46      /** The defaults suffix to add to response <code>Action</code> for reply messages. */
47      public static final String DEFAULT_FAULT_ACTION_SUFFIX = "Fault";
48  
49      // keys are action URIs, values are endpoints
50      private final Map<URI, Object> endpointMap = new HashMap<URI, Object>();
51  
52      private String outputActionSuffix = DEFAULT_OUTPUT_ACTION_SUFFIX;
53  
54      private String faultActionSuffix = DEFAULT_OUTPUT_ACTION_SUFFIX;
55  
56      private ApplicationContext applicationContext;
57  
58      /** Returns the suffix to add to request <code>Action</code>s for reply messages. */
59      public String getOutputActionSuffix() {
60          return outputActionSuffix;
61      }
62  
63      /**
64       * Sets the suffix to add to request <code>Action</code>s for reply messages.
65       *
66       * @see #DEFAULT_OUTPUT_ACTION_SUFFIX
67       */
68      public void setOutputActionSuffix(String outputActionSuffix) {
69          Assert.hasText(outputActionSuffix, "'outputActionSuffix' must not be empty");
70          this.outputActionSuffix = outputActionSuffix;
71      }
72  
73      /** Returns the suffix to add to request <code>Action</code>s for reply fault messages. */
74      public String getFaultActionSuffix() {
75          return faultActionSuffix;
76      }
77  
78      /**
79       * Sets the suffix to add to request <code>Action</code>s for reply fault messages.
80       *
81       * @see #DEFAULT_FAULT_ACTION_SUFFIX
82       */
83      public void setFaultActionSuffix(String faultActionSuffix) {
84          Assert.hasText(faultActionSuffix, "'faultActionSuffix' must not be empty");
85          this.faultActionSuffix = faultActionSuffix;
86      }
87  
88      public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
89          this.applicationContext = applicationContext;
90      }
91  
92      @Override
93      protected final Object getEndpointInternal(MessageAddressingProperties map) {
94          URI action = map.getAction();
95          if (logger.isDebugEnabled()) {
96              logger.debug("Looking up endpoint for action [" + action + "]");
97          }
98          Object endpoint = lookupEndpoint(action);
99          if (endpoint != null) {
100             URI endpointAddress = getEndpointAddress(endpoint);
101             if (endpointAddress == null || endpointAddress.equals(map.getTo())) {
102                 return endpoint;
103             }
104         }
105         return null;
106     }
107 
108     /**
109      * Returns the address property of the given endpoint. The value of this property should match the [email protected]
110      * MessageAddressingProperties#getTo() destination} of incoming messages. May return <code>null</code>  to ignore
111      * the destination.
112      *
113      * @param endpoint the endpoint to return the address for
114      * @return the endpoint address; or <code>null</code> to ignore the destination property
115      */
116     protected abstract URI getEndpointAddress(Object endpoint);
117 
118     /**
119      * Looks up an endpoint instance for the given action. All keys are tried in order.
120      *
121      * @param action the action URI
122      * @return the associated endpoint instance, or <code>null</code> if not found
123      */
124     protected Object lookupEndpoint(URI action) {
125         return endpointMap.get(action);
126     }
127 
128     /**
129      * Register the specified endpoint for the given action URI.
130      *
131      * @param action   the action the bean should be mapped to
132      * @param endpoint the endpoint instance or endpoint bean name String (a bean name will automatically be resolved
133      *                 into the corresponding endpoint bean)
134      * @throws org.springframework.beans.BeansException
135      *                               if the endpoint couldn't be registered
136      * @throws IllegalStateException if there is a conflicting endpoint registered
137      */
138     protected void registerEndpoint(URI action, Object endpoint) throws BeansException, IllegalStateException {
139         Assert.notNull(action, "Action must not be null");
140         Assert.notNull(endpoint, "Endpoint object must not be null");
141         Object resolvedEndpoint = endpoint;
142 
143         if (endpoint instanceof String) {
144             String endpointName = (String) endpoint;
145             if (applicationContext.isSingleton(endpointName)) {
146                 resolvedEndpoint = applicationContext.getBean(endpointName);
147             }
148         }
149         Object mappedEndpoint = this.endpointMap.get(action);
150         if (mappedEndpoint != null) {
151             if (mappedEndpoint != resolvedEndpoint) {
152                 throw new IllegalStateException("Cannot map endpoint [" + endpoint + "] to action [" + action +
153                         "]: There is already endpoint [" + resolvedEndpoint + "] mapped.");
154             }
155         }
156         else {
157             this.endpointMap.put(action, resolvedEndpoint);
158             if (logger.isDebugEnabled()) {
159                 logger.debug("Mapped Action [" + action + "] onto endpoint [" + resolvedEndpoint + "]");
160             }
161         }
162     }
163 
164     @Override
165     protected URI getResponseAction(Object endpoint, MessageAddressingProperties requestMap) {
166         URI requestAction = requestMap.getAction();
167         if (requestAction != null) {
168             return URI.create(requestAction.toString() + getOutputActionSuffix());
169         }
170         else {
171             return null;
172         }
173     }
174 
175     @Override
176     protected URI getFaultAction(Object endpoint, MessageAddressingProperties requestMap) {
177         URI requestAction = requestMap.getAction();
178         if (requestAction != null) {
179             return URI.create(requestAction.toString() + getFaultActionSuffix());
180         }
181         else {
182             return null;
183         }
184     }
185 
186 }