001: /*
002: * Copyright 2005 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.ws.soap.server;
018:
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Locale;
023: import javax.xml.namespace.QName;
024:
025: import org.springframework.util.ObjectUtils;
026: import org.springframework.util.StringUtils;
027: import org.springframework.ws.context.MessageContext;
028: import org.springframework.ws.server.EndpointInterceptor;
029: import org.springframework.ws.server.EndpointInvocationChain;
030: import org.springframework.ws.server.MessageDispatcher;
031: import org.springframework.ws.soap.SoapBody;
032: import org.springframework.ws.soap.SoapFault;
033: import org.springframework.ws.soap.SoapHeader;
034: import org.springframework.ws.soap.SoapHeaderElement;
035: import org.springframework.ws.soap.SoapMessage;
036: import org.springframework.ws.soap.soap11.Soap11Header;
037: import org.springframework.ws.soap.soap12.Soap12Header;
038:
039: /**
040: * SOAP-specific subclass of the {@link MessageDispatcher}. Adds functionality for adding actor roles to a endpoint
041: * invocation chain, and endpoint interception using {@link SoapEndpointInterceptor} objects.
042: *
043: * @author Arjen Poutsma
044: * @see org.springframework.ws.soap.SoapMessage
045: * @see SoapEndpointInterceptor
046: * @since 1.0.0
047: */
048: public class SoapMessageDispatcher extends MessageDispatcher {
049:
050: /** Default message used when creating a SOAP MustUnderstand fault. */
051: public static final String DEFAULT_MUST_UNDERSTAND_FAULT_STRING = "One or more mandatory SOAP header blocks not understood";
052:
053: private String mustUnderstandFaultString = DEFAULT_MUST_UNDERSTAND_FAULT_STRING;
054:
055: private Locale mustUnderstandFaultStringLocale = Locale.ENGLISH;
056:
057: /**
058: * Sets the message used for <code>MustUnderstand</code> fault. Default to {@link
059: * #DEFAULT_MUST_UNDERSTAND_FAULT_STRING}.
060: */
061: public void setMustUnderstandFaultString(
062: String mustUnderstandFaultString) {
063: this .mustUnderstandFaultString = mustUnderstandFaultString;
064: }
065:
066: /** Sets the locale of the message used for <code>MustUnderstand</code> fault. Default to {@link Locale#ENGLISH}. */
067: public void setMustUnderstandFaultStringLocale(
068: Locale mustUnderstandFaultStringLocale) {
069: this .mustUnderstandFaultStringLocale = mustUnderstandFaultStringLocale;
070: }
071:
072: /**
073: * Process the headers targeted at the actor or role fullfilled by the endpoint. Also processed the
074: * <code>MustUnderstand</code> headers in the incoming SOAP request message. Iterates over all SOAP headers which
075: * should be understood for this role, and determines whether these are supported. Generates a SOAP MustUnderstand
076: * fault if a header is not understood.
077: *
078: * @param mappedEndpoint the mapped EndpointInvocationChain
079: * @param messageContext the message context
080: * @return <code>true</code> if all necessary headers are understood; <code>false</code> otherwise
081: * @see SoapEndpointInvocationChain#getActorsOrRoles()
082: * @see org.springframework.ws.soap.SoapHeader#examineMustUnderstandHeaderElements(String)
083: */
084: protected boolean handleRequest(
085: EndpointInvocationChain mappedEndpoint,
086: MessageContext messageContext) {
087: if (messageContext.getRequest() instanceof SoapMessage) {
088: String[] actorsOrRoles = null;
089: boolean isUltimateReceiver = true;
090: if (mappedEndpoint instanceof SoapEndpointInvocationChain) {
091: SoapEndpointInvocationChain soapChain = (SoapEndpointInvocationChain) mappedEndpoint;
092: actorsOrRoles = soapChain.getActorsOrRoles();
093: isUltimateReceiver = soapChain.isUltimateReceiver();
094: }
095: return handleHeaders(mappedEndpoint, messageContext,
096: actorsOrRoles, isUltimateReceiver);
097: }
098: return true;
099: }
100:
101: private boolean handleHeaders(
102: EndpointInvocationChain mappedEndpoint,
103: MessageContext messageContext, String[] actorsOrRoles,
104: boolean isUltimateReceiver) {
105: SoapMessage soapRequest = (SoapMessage) messageContext
106: .getRequest();
107: SoapHeader soapHeader = soapRequest.getSoapHeader();
108: if (soapHeader == null) {
109: return true;
110: }
111: Iterator headerIterator;
112: if (soapHeader instanceof Soap11Header) {
113: headerIterator = ((Soap11Header) soapHeader)
114: .examineHeaderElementsToProcess(actorsOrRoles);
115: } else {
116: headerIterator = ((Soap12Header) soapHeader)
117: .examineHeaderElementsToProcess(actorsOrRoles,
118: isUltimateReceiver);
119: }
120: List notUnderstoodHeaderNames = new ArrayList();
121: while (headerIterator.hasNext()) {
122: SoapHeaderElement headerElement = (SoapHeaderElement) headerIterator
123: .next();
124: QName headerName = headerElement.getName();
125: if (logger.isDebugEnabled()) {
126: if (!headerElement.getMustUnderstand()) {
127: logger.debug("Handling header " + headerName);
128: } else {
129: logger.debug("Handling MustUnderstand header "
130: + headerName);
131: }
132: }
133: if (headerElement.getMustUnderstand()
134: && !headerUnderstood(mappedEndpoint, headerElement)) {
135: notUnderstoodHeaderNames.add(headerName);
136: }
137: }
138: if (notUnderstoodHeaderNames.isEmpty()) {
139: return true;
140: } else {
141: SoapMessage response = (SoapMessage) messageContext
142: .getResponse();
143: createMustUnderstandFault(response,
144: notUnderstoodHeaderNames, actorsOrRoles);
145: return false;
146: }
147: }
148:
149: /**
150: * Handles the request for a single SOAP actor/role. Iterates over all <code>MustUnderstand</code> headers for a
151: * specific SOAP 1.1 actor or SOAP 1.2 role, and determines whether these are understood by any of the registered
152: * <code>SoapEndpointInterceptor</code>. If they are, returns <code>true</code>. If they are not, a SOAP fault is
153: * created, and false is returned.
154: *
155: * @see SoapEndpointInterceptor#understands(org.springframework.ws.soap.SoapHeaderElement)
156: */
157: private boolean headerUnderstood(
158: EndpointInvocationChain mappedEndpoint,
159: SoapHeaderElement headerElement) {
160: EndpointInterceptor[] interceptors = mappedEndpoint
161: .getInterceptors();
162: for (int i = 0; i < interceptors.length; i++) {
163: EndpointInterceptor interceptor = interceptors[i];
164: if (interceptor instanceof SoapEndpointInterceptor
165: && ((SoapEndpointInterceptor) interceptor)
166: .understands(headerElement)) {
167: return true;
168: }
169: }
170: return false;
171: }
172:
173: private void createMustUnderstandFault(SoapMessage soapResponse,
174: List notUnderstoodHeaderNames, String[] actorsOrRoles) {
175: if (logger.isWarnEnabled()) {
176: logger
177: .warn("Could not handle mustUnderstand headers: "
178: + StringUtils
179: .collectionToCommaDelimitedString(notUnderstoodHeaderNames)
180: + ". Returning fault");
181: }
182: SoapBody responseBody = soapResponse.getSoapBody();
183: SoapFault fault = responseBody.addMustUnderstandFault(
184: mustUnderstandFaultString,
185: mustUnderstandFaultStringLocale);
186: if (!ObjectUtils.isEmpty(actorsOrRoles)) {
187: fault.setFaultActorOrRole(actorsOrRoles[0]);
188: }
189: SoapHeader header = soapResponse.getSoapHeader();
190: if (header instanceof Soap12Header) {
191: Soap12Header soap12Header = (Soap12Header) header;
192: for (Iterator iterator = notUnderstoodHeaderNames
193: .iterator(); iterator.hasNext();) {
194: QName headerName = (QName) iterator.next();
195: soap12Header.addNotUnderstoodHeaderElement(headerName);
196: }
197: }
198: }
199:
200: }
|