001: /*
002: * Copyright 2006 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.saaj;
018:
019: import java.io.IOException;
020: import java.io.InputStream;
021: import java.util.Iterator;
022: import java.util.StringTokenizer;
023: import javax.xml.soap.MessageFactory;
024: import javax.xml.soap.MimeHeaders;
025: import javax.xml.soap.SOAPConstants;
026: import javax.xml.soap.SOAPException;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030: import org.springframework.beans.factory.InitializingBean;
031: import org.springframework.util.StringUtils;
032: import org.springframework.ws.WebServiceMessage;
033: import org.springframework.ws.soap.SoapMessageCreationException;
034: import org.springframework.ws.soap.SoapMessageFactory;
035: import org.springframework.ws.soap.SoapVersion;
036: import org.springframework.ws.soap.saaj.support.SaajUtils;
037: import org.springframework.ws.transport.TransportInputStream;
038:
039: /**
040: * SAAJ-specific implementation of the {@link org.springframework.ws.WebServiceMessageFactory WebServiceMessageFactory}.
041: * Wraps a SAAJ {@link MessageFactory}. This factory will use SAAJ 1.3 when found, or fall back to SAAJ 1.2 or even
042: * 1.1.
043: * <p/>
044: * A SAAJ {@link MessageFactory} can be injected to the {@link #SaajSoapMessageFactory(javax.xml.soap.MessageFactory)
045: * constructor}, or by the {@link #setMessageFactory(javax.xml.soap.MessageFactory)} property. When a SAAJ message
046: * factory is injected, the {@link #setSoapVersion(org.springframework.ws.soap.SoapVersion)} property is ignored.
047: *
048: * @author Arjen Poutsma
049: * @see org.springframework.ws.soap.saaj.SaajSoapMessage
050: * @since 1.0.0
051: */
052: public class SaajSoapMessageFactory implements SoapMessageFactory,
053: InitializingBean {
054:
055: private static final Log logger = LogFactory
056: .getLog(SaajSoapMessageFactory.class);
057:
058: private MessageFactory messageFactory;
059:
060: private String messageFactoryProtocol;
061:
062: private static final String CONTENT_TYPE = "Content-Type";
063:
064: /** Default, empty constructor. */
065: public SaajSoapMessageFactory() {
066: }
067:
068: /** Constructor that takes a message factory as an argument. */
069: public SaajSoapMessageFactory(MessageFactory messageFactory) {
070: this .messageFactory = messageFactory;
071: }
072:
073: /** Returns the SAAJ <code>MessageFactory</code> used. */
074: public MessageFactory getMessageFactory() {
075: return messageFactory;
076: }
077:
078: /** Sets the SAAJ <code>MessageFactory</code>. */
079: public void setMessageFactory(MessageFactory messageFactory) {
080: this .messageFactory = messageFactory;
081: }
082:
083: public void setSoapVersion(SoapVersion version) {
084: if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) {
085: if (SoapVersion.SOAP_11 == version) {
086: messageFactoryProtocol = SOAPConstants.SOAP_1_1_PROTOCOL;
087: } else if (SoapVersion.SOAP_12 == version) {
088: messageFactoryProtocol = SOAPConstants.SOAP_1_2_PROTOCOL;
089: } else {
090: throw new IllegalArgumentException("Invalid version ["
091: + version + "]. "
092: + "Expected the SOAP_11 or SOAP_12 constant");
093: }
094: } else if (SoapVersion.SOAP_11 != version) {
095: throw new IllegalArgumentException(
096: "SAAJ 1.1 and 1.2 only support SOAP 1.1");
097: }
098: }
099:
100: public void afterPropertiesSet() throws Exception {
101: if (messageFactory == null) {
102: try {
103: if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) {
104: if (!StringUtils.hasLength(messageFactoryProtocol)) {
105: messageFactoryProtocol = SOAPConstants.SOAP_1_1_PROTOCOL;
106: }
107: if (logger.isInfoEnabled()) {
108: logger
109: .info("Creating SAAJ 1.3 MessageFactory with "
110: + messageFactoryProtocol);
111: }
112: messageFactory = MessageFactory
113: .newInstance(messageFactoryProtocol);
114: } else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_12) {
115: logger.info("Creating SAAJ 1.2 MessageFactory");
116: messageFactory = MessageFactory.newInstance();
117: } else if (SaajUtils.getSaajVersion() == SaajUtils.SAAJ_11) {
118: logger.info("Creating SAAJ 1.1 MessageFactory");
119: messageFactory = MessageFactory.newInstance();
120: } else {
121: throw new IllegalStateException(
122: "SaajSoapMessageFactory requires SAAJ 1.1, which was not found on the classpath");
123: }
124: } catch (NoSuchMethodError ex) {
125: throw new SoapMessageCreationException(
126: "Could not create SAAJ MessageFactory. Is the version of the SAAJ specification interfaces ["
127: + SaajUtils.getSaajVersionString()
128: + "] the same as the version supported by the application server?",
129: ex);
130: } catch (SOAPException ex) {
131: throw new SoapMessageCreationException(
132: "Could not create SAAJ MessageFactory: "
133: + ex.getMessage(), ex);
134: }
135: }
136: if (logger.isTraceEnabled()) {
137: logger.trace("Using MessageFactory class ["
138: + messageFactory.getClass().getName() + "]");
139: }
140: }
141:
142: public WebServiceMessage createWebServiceMessage() {
143: try {
144: return new SaajSoapMessage(messageFactory.createMessage());
145: } catch (SOAPException ex) {
146: throw new SoapMessageCreationException(
147: "Could not create empty message: "
148: + ex.getMessage(), ex);
149: }
150: }
151:
152: public WebServiceMessage createWebServiceMessage(
153: InputStream inputStream) throws IOException {
154: MimeHeaders mimeHeaders = new MimeHeaders();
155: if (inputStream instanceof TransportInputStream) {
156: TransportInputStream transportInputStream = (TransportInputStream) inputStream;
157: for (Iterator headerNames = transportInputStream
158: .getHeaderNames(); headerNames.hasNext();) {
159: String headerName = (String) headerNames.next();
160: for (Iterator headerValues = transportInputStream
161: .getHeaders(headerName); headerValues.hasNext();) {
162: String headerValue = (String) headerValues.next();
163: StringTokenizer tokenizer = new StringTokenizer(
164: headerValue, ",");
165: while (tokenizer.hasMoreTokens()) {
166: mimeHeaders.addHeader(headerName, tokenizer
167: .nextToken().trim());
168: }
169: }
170: }
171: }
172: try {
173: return new SaajSoapMessage(messageFactory.createMessage(
174: mimeHeaders, inputStream));
175: } catch (SOAPException ex) {
176: // SAAJ 1.3 RI has a issue with handling multipart XOP content types which contain "startinfo" rather than
177: // "start-info", so let's try and do something about it
178: String contentType = StringUtils
179: .arrayToCommaDelimitedString(mimeHeaders
180: .getHeader(CONTENT_TYPE));
181: if (contentType.indexOf("startinfo") != -1) {
182: contentType = contentType.replace("startinfo",
183: "start-info");
184: mimeHeaders.setHeader(CONTENT_TYPE, contentType);
185: try {
186: return new SaajSoapMessage(messageFactory
187: .createMessage(mimeHeaders, inputStream));
188: } catch (SOAPException e) {
189: // fall-through
190: }
191: }
192: throw new SoapMessageCreationException(
193: "Could not create message from InputStream: "
194: + ex.getMessage(), ex);
195: }
196: }
197:
198: public String toString() {
199: StringBuffer buffer = new StringBuffer(
200: "SaajSoapMessageFactory[");
201: buffer.append(SaajUtils.getSaajVersionString());
202: if (SaajUtils.getSaajVersion() >= SaajUtils.SAAJ_13) {
203: buffer.append(',');
204: buffer.append(messageFactoryProtocol);
205: }
206: buffer.append(']');
207: return buffer.toString();
208: }
209: }
|