View Javadoc

1   /*
2    * Copyright 2008 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 {@link 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 {@link #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 {@link #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 endpointMap = new HashMap();
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      protected final Object getEndpointInternal(MessageAddressingProperties map) {
93          URI action = map.getAction();
94          if (logger.isDebugEnabled()) {
95              logger.debug("Looking up endpoint for action [" + action + "]");
96          }
97          Object endpoint = lookupEndpoint(action);
98          if (endpoint != null) {
99              URI endpointAddress = getEndpointAddress(endpoint);
100             if (endpointAddress == null || endpointAddress.equals(map.getTo())) {
101                 return endpoint;
102             }
103         }
104         return null;
105     }
106 
107     /**
108      * Returns the address property of the given endpoint. The value of this property should match the {@link
109      * MessageAddressingProperties#getTo() destination} of incoming messages. May return <code>null</code>  to ignore
110      * the destination.
111      *
112      * @param endpoint the endpoint to return the address for
113      * @return the endpoint address; or <code>null</code> to ignore the destination property
114      */
115     protected abstract URI getEndpointAddress(Object endpoint);
116 
117     /**
118      * Looks up an endpoint instance for the given action. All keys are tried in order.
119      *
120      * @param action the action URI
121      * @return the associated endpoint instance, or <code>null</code> if not found
122      */
123     protected Object lookupEndpoint(URI action) {
124         return endpointMap.get(action);
125     }
126 
127     /**
128      * Register the specified endpoint for the given action URI.
129      *
130      * @param action   the action the bean should be mapped to
131      * @param endpoint the endpoint instance or endpoint bean name String (a bean name will automatically be resolved
132      *                 into the corresponding endpoint bean)
133      * @throws org.springframework.beans.BeansException
134      *                               if the endpoint couldn't be registered
135      * @throws IllegalStateException if there is a conflicting endpoint registered
136      */
137     protected void registerEndpoint(URI action, Object endpoint) throws BeansException, IllegalStateException {
138         Assert.notNull(action, "Action must not be null");
139         Assert.notNull(endpoint, "Endpoint object must not be null");
140         Object resolvedEndpoint = endpoint;
141 
142         if (endpoint instanceof String) {
143             String endpointName = (String) endpoint;
144             if (applicationContext.isSingleton(endpointName)) {
145                 resolvedEndpoint = applicationContext.getBean(endpointName);
146             }
147         }
148         Object mappedEndpoint = this.endpointMap.get(action);
149         if (mappedEndpoint != null) {
150             if (mappedEndpoint != resolvedEndpoint) {
151                 throw new IllegalStateException("Cannot map endpoint [" + endpoint + "] to action [" + action +
152                         "]: There is already endpoint [" + resolvedEndpoint + "] mapped.");
153             }
154         }
155         else {
156             this.endpointMap.put(action, resolvedEndpoint);
157             if (logger.isDebugEnabled()) {
158                 logger.debug("Mapped Action [" + action + "] onto endpoint [" + resolvedEndpoint + "]");
159             }
160         }
161     }
162 
163     protected URI getResponseAction(Object endpoint, MessageAddressingProperties requestMap) {
164         URI requestAction = requestMap.getAction();
165         if (requestAction != null) {
166             return URI.create(requestAction.toString() + getOutputActionSuffix());
167         }
168         else {
169             return null;
170         }
171     }
172 
173     protected URI getFaultAction(Object endpoint, MessageAddressingProperties requestMap) {
174         URI requestAction = requestMap.getAction();
175         if (requestAction != null) {
176             return URI.create(requestAction.toString() + getFaultActionSuffix());
177         }
178         else {
179             return null;
180         }
181     }
182 
183 }