View Javadoc

1   /*
2    * Copyright 2007 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.io.IOException;
20  import java.net.URI;
21  
22  import org.apache.commons.logging.Log;
23  import org.apache.commons.logging.LogFactory;
24  
25  import org.springframework.util.Assert;
26  import org.springframework.ws.context.MessageContext;
27  import org.springframework.ws.soap.SoapHeaderElement;
28  import org.springframework.ws.soap.SoapMessage;
29  import org.springframework.ws.soap.addressing.core.EndpointReference;
30  import org.springframework.ws.soap.addressing.core.MessageAddressingProperties;
31  import org.springframework.ws.soap.addressing.messageid.MessageIdStrategy;
32  import org.springframework.ws.soap.addressing.version.AddressingVersion;
33  import org.springframework.ws.soap.server.SoapEndpointInterceptor;
34  import org.springframework.ws.transport.WebServiceConnection;
35  import org.springframework.ws.transport.WebServiceMessageSender;
36  
37  /**
38   * {@link SoapEndpointInterceptor} implementation that deals with WS-Addressing headers. Stateful, and instatiated by
39   * the {@link AbstractAddressingEndpointMapping}.
40   *
41   * @author Arjen Poutsma
42   * @since 1.5.0
43   */
44  class AddressingEndpointInterceptor implements SoapEndpointInterceptor {
45  
46      private static final Log logger = LogFactory.getLog(AddressingEndpointInterceptor.class);
47  
48      private final AddressingVersion version;
49  
50      private final MessageIdStrategy messageIdStrategy;
51  
52      private final WebServiceMessageSender[] messageSenders;
53  
54      private URI replyAction;
55  
56      private URI faultAction;
57  
58      AddressingEndpointInterceptor(AddressingVersion version,
59                                    MessageIdStrategy messageIdStrategy,
60                                    WebServiceMessageSender[] messageSenders,
61                                    URI replyAction,
62                                    URI faultAction) {
63          Assert.notNull(version, "version must not be null");
64          Assert.notNull(messageIdStrategy, "messageIdStrategy must not be null");
65          Assert.notNull(messageSenders, "'messageSenders' must not be null");
66          this.version = version;
67          this.messageIdStrategy = messageIdStrategy;
68          this.messageSenders = messageSenders;
69          this.replyAction = replyAction;
70          this.faultAction = faultAction;
71      }
72  
73      public final boolean handleRequest(MessageContext messageContext, Object endpoint) throws Exception {
74          Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
75          SoapMessage request = (SoapMessage) messageContext.getRequest();
76          MessageAddressingProperties requestMap = version.getMessageAddressingProperties(request);
77          if (!version.hasRequiredProperties(requestMap)) {
78              version.addMessageAddressingHeaderRequiredFault((SoapMessage) messageContext.getResponse());
79              return false;
80          }
81          if (messageIdStrategy.isDuplicate(requestMap.getMessageId())) {
82              version.addInvalidAddressingHeaderFault((SoapMessage) messageContext.getResponse());
83              return false;
84          }
85          return true;
86      }
87  
88      public final boolean handleResponse(MessageContext messageContext, Object endpoint) throws Exception {
89          return handleResponseOrFault(messageContext, false);
90      }
91  
92      public final boolean handleFault(MessageContext messageContext, Object endpoint) throws Exception {
93          return handleResponseOrFault(messageContext, true);
94      }
95  
96      private boolean handleResponseOrFault(MessageContext messageContext, boolean isFault) throws Exception {
97          Assert.isInstanceOf(SoapMessage.class, messageContext.getRequest());
98          Assert.isInstanceOf(SoapMessage.class, messageContext.getResponse());
99          MessageAddressingProperties requestMap =
100                 version.getMessageAddressingProperties((SoapMessage) messageContext.getRequest());
101         EndpointReference replyEpr = !isFault ? requestMap.getReplyTo() : requestMap.getFaultTo();
102         if (handleNoneAddress(messageContext, replyEpr)) {
103             return false;
104         }
105         SoapMessage reply = (SoapMessage) messageContext.getResponse();
106         URI replyMessageId = getMessageId(reply);
107         URI action = isFault ? faultAction : replyAction;
108         MessageAddressingProperties replyMap = requestMap.getReplyProperties(replyEpr, action, replyMessageId);
109         version.addAddressingHeaders(reply, replyMap);
110         if (handleAnonymousAddress(messageContext, replyEpr)) {
111             return true;
112         }
113         else {
114             sendOutOfBand(messageContext, replyEpr);
115             return false;
116         }
117     }
118 
119     private boolean handleNoneAddress(MessageContext messageContext, EndpointReference replyEpr) {
120         if (replyEpr == null || version.hasNoneAddress(replyEpr)) {
121             if (logger.isDebugEnabled()) {
122                 logger.debug(
123                         "Request [" + messageContext.getRequest() + "] has [" + replyEpr + "] reply address; reply [" +
124                                 messageContext.getResponse() + "] discarded");
125             }
126             messageContext.clearResponse();
127             return true;
128         }
129         return false;
130     }
131 
132     private boolean handleAnonymousAddress(MessageContext messageContext, EndpointReference replyEpr) {
133         if (version.hasAnonymousAddress(replyEpr)) {
134             if (logger.isDebugEnabled()) {
135                 logger.debug("Request [" + messageContext.getRequest() + "] has [" + replyEpr +
136                         "] reply address; sending in-band reply [" + messageContext.getResponse() + "]");
137             }
138             return true;
139         }
140         return false;
141     }
142 
143     private void sendOutOfBand(MessageContext messageContext, EndpointReference replyEpr) throws IOException {
144         if (logger.isDebugEnabled()) {
145             logger.debug("Request [" + messageContext.getRequest() + "] has [" + replyEpr +
146                     "] reply address; sending out-of-band reply [" + messageContext.getResponse() + "]");
147         }
148 
149         boolean supported = false;
150         for (int i = 0; i < messageSenders.length; i++) {
151             if (messageSenders[i].supports(replyEpr.getAddress())) {
152                 supported = true;
153                 WebServiceConnection connection = null;
154                 try {
155                     connection = messageSenders[i].createConnection(replyEpr.getAddress());
156                     connection.send(messageContext.getResponse());
157                     break;
158                 }
159                 finally {
160                     messageContext.clearResponse();
161                     if (connection != null) {
162                         connection.close();
163                     }
164                 }
165             }
166         }
167         if (!supported && logger.isWarnEnabled()) {
168             logger.warn("Could not send out-of-band response to [" + replyEpr.getAddress() + "]. " +
169                     "Configure WebServiceMessageSenders which support this uri.");
170         }
171     }
172 
173     private URI getMessageId(SoapMessage response) {
174         URI responseMessageId = messageIdStrategy.newMessageId(response);
175         if (logger.isTraceEnabled()) {
176             logger.trace("Generated reply MessageID [" + responseMessageId + "] for [" + response + "]");
177         }
178         return responseMessageId;
179     }
180 
181     public boolean understands(SoapHeaderElement header) {
182         return version.understands(header);
183     }
184 }