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 (!requestMap.hasRequiredProperties()) {
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("Request " + messageContext.getRequest() + "] has [" + replyEpr +
123                         "] reply address; reply [" + messageContext.getResponse() + "] discarded");
124             }
125             messageContext.clearResponse();
126             return true;
127         }
128         return false;
129     }
130 
131     private boolean handleAnonymousAddress(MessageContext messageContext, EndpointReference replyEpr) {
132         if (version.hasAnonymousAddress(replyEpr)) {
133             if (logger.isDebugEnabled()) {
134                 logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
135                         "] reply address; sending in-band reply [" + messageContext.getResponse() + "]");
136             }
137             return true;
138         }
139         return false;
140     }
141 
142     private void sendOutOfBand(MessageContext messageContext, EndpointReference replyEpr) throws IOException {
143         if (logger.isDebugEnabled()) {
144             logger.debug("Request " + messageContext.getRequest() + "] has [" + replyEpr +
145                     "] reply address; sending out-of-band reply [" + messageContext.getResponse() + "]");
146         }
147 
148         boolean supported = false;
149         for (int i = 0; i < messageSenders.length; i++) {
150             if (messageSenders[i].supports(replyEpr.getAddress())) {
151                 supported = true;
152                 WebServiceConnection connection = null;
153                 try {
154                     connection = messageSenders[i].createConnection(replyEpr.getAddress());
155                     connection.send(messageContext.getResponse());
156                     break;
157                 }
158                 finally {
159                     messageContext.clearResponse();
160                     if (connection != null) {
161                         connection.close();
162                     }
163                 }
164             }
165         }
166         if (!supported && logger.isWarnEnabled()) {
167             logger.warn("Could not send out-of-band response to [" + replyEpr.getAddress() + "]. " +
168                     "Configure WebServiceMessageSenders which support this uri.");
169         }
170     }
171 
172     private URI getMessageId(SoapMessage response) {
173         URI responseMessageId = messageIdStrategy.newMessageId(response);
174         if (logger.isTraceEnabled()) {
175             logger.trace("Generated reply MessageID [" + responseMessageId + "] for [" + response + "]");
176         }
177         return responseMessageId;
178     }
179 
180     public boolean understands(SoapHeaderElement header) {
181         return version.understands(header);
182     }
183 }