ohair@286: /* alanb@368: * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. ohair@286: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. ohair@286: * ohair@286: * This code is free software; you can redistribute it and/or modify it ohair@286: * under the terms of the GNU General Public License version 2 only, as ohair@286: * published by the Free Software Foundation. Oracle designates this ohair@286: * particular file as subject to the "Classpath" exception as provided ohair@286: * by Oracle in the LICENSE file that accompanied this code. ohair@286: * ohair@286: * This code is distributed in the hope that it will be useful, but WITHOUT ohair@286: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ohair@286: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ohair@286: * version 2 for more details (a copy is included in the LICENSE file that ohair@286: * accompanied this code). ohair@286: * ohair@286: * You should have received a copy of the GNU General Public License version ohair@286: * 2 along with this work; if not, write to the Free Software Foundation, ohair@286: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ohair@286: * ohair@286: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA ohair@286: * or visit www.oracle.com if you need additional information or have any ohair@286: * questions. ohair@286: */ ohair@286: ohair@286: package com.sun.xml.internal.messaging.saaj.soap; ohair@286: ohair@286: import java.io.*; ohair@286: import java.util.*; ohair@286: import java.util.logging.Level; ohair@286: import java.util.logging.Logger; ohair@286: ohair@286: import javax.activation.DataHandler; ohair@286: import javax.activation.DataSource; ohair@286: import javax.xml.soap.*; ohair@286: import javax.xml.transform.Source; ohair@286: import javax.xml.transform.stream.StreamSource; ohair@286: ohair@286: import com.sun.xml.internal.messaging.saaj.packaging.mime.Header; ohair@286: import com.sun.xml.internal.messaging.saaj.packaging.mime.internet.*; ohair@286: import com.sun.xml.internal.messaging.saaj.packaging.mime.util.*; ohair@286: import com.sun.xml.internal.messaging.saaj.packaging.mime.MessagingException; ohair@286: ohair@286: import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl; ohair@286: import com.sun.xml.internal.messaging.saaj.soap.impl.EnvelopeImpl; ohair@286: import com.sun.xml.internal.messaging.saaj.util.*; ohair@286: import com.sun.xml.internal.org.jvnet.mimepull.MIMEPart; ohair@286: ohair@286: /** ohair@286: * The message implementation for SOAP messages with ohair@286: * attachments. Messages for specific profiles will likely extend this ohair@286: * MessageImpl class and add more value for that particular profile. ohair@286: * ohair@286: * @author Anil Vijendran (akv@eng.sun.com) ohair@286: * @author Rajiv Mordani (rajiv.mordani@sun.com) ohair@286: * @author Manveen Kaur (manveen.kaur@sun.com) ohair@286: */ ohair@286: ohair@286: public abstract class MessageImpl ohair@286: extends SOAPMessage ohair@286: implements SOAPConstants { ohair@286: ohair@286: ohair@286: public static final String CONTENT_ID = "Content-ID"; ohair@286: public static final String CONTENT_LOCATION = "Content-Location"; ohair@286: ohair@286: protected static final Logger log = ohair@286: Logger.getLogger(LogDomainConstants.SOAP_DOMAIN, ohair@286: "com.sun.xml.internal.messaging.saaj.soap.LocalStrings"); ohair@286: ohair@286: protected static final int PLAIN_XML_FLAG = 1; // 00001 ohair@286: protected static final int MIME_MULTIPART_FLAG = 2; // 00010 ohair@286: protected static final int SOAP1_1_FLAG = 4; // 00100 ohair@286: protected static final int SOAP1_2_FLAG = 8; // 01000 ohair@286: //protected static final int MIME_MULTIPART_XOP_FLAG = 14; // 01110 ohair@286: protected static final int MIME_MULTIPART_XOP_SOAP1_1_FLAG = 6; // 00110 ohair@286: protected static final int MIME_MULTIPART_XOP_SOAP1_2_FLAG = 10; // 01010 ohair@286: protected static final int XOP_FLAG = 13; // 01101 ohair@286: protected static final int FI_ENCODED_FLAG = 16; // 10000 ohair@286: ohair@286: protected MimeHeaders headers; ohair@286: protected ContentType contentType; ohair@286: protected SOAPPartImpl soapPartImpl; ohair@286: protected FinalArrayList attachments; ohair@286: protected boolean saved = false; ohair@286: protected byte[] messageBytes; ohair@286: protected int messageByteCount; ohair@286: protected HashMap properties = new HashMap(); ohair@286: ohair@286: // used for lazy attachment initialization ohair@286: protected MimeMultipart multiPart = null; ohair@286: protected boolean attachmentsInitialized = false; ohair@286: ohair@286: /** ohair@286: * True if this part is encoded using Fast Infoset. ohair@286: * MIME -> application/fastinfoset ohair@286: */ ohair@286: protected boolean isFastInfoset = false; ohair@286: ohair@286: /** ohair@286: * True if the Accept header of this message includes ohair@286: * application/fastinfoset ohair@286: */ ohair@286: protected boolean acceptFastInfoset = false; ohair@286: ohair@286: protected MimeMultipart mmp = null; ohair@286: ohair@286: // if attachments are present, don't read the entire message in byte stream in saveTo() ohair@286: private boolean optimizeAttachmentProcessing = true; ohair@286: ohair@286: private InputStream inputStreamAfterSaveChanges = null; ohair@286: ohair@286: // switch back to old MimeMultipart incase of problem ohair@286: private static boolean switchOffBM = false; ohair@286: private static boolean switchOffLazyAttachment = false; ohair@286: private static boolean useMimePull = false; ohair@286: ohair@286: static { ohair@286: String s = SAAJUtil.getSystemProperty("saaj.mime.optimization"); ohair@286: if ((s != null) && s.equals("false")) { ohair@286: switchOffBM = true; ohair@286: } ohair@286: s = SAAJUtil.getSystemProperty("saaj.lazy.mime.optimization"); ohair@286: if ((s != null) && s.equals("false")) { ohair@286: switchOffLazyAttachment = true; ohair@286: } ohair@286: useMimePull = SAAJUtil.getSystemBoolean("saaj.use.mimepull"); ohair@286: ohair@286: } ohair@286: ohair@286: //property to indicate optimized serialization for lazy attachments ohair@286: private boolean lazyAttachments = false; ohair@286: ohair@286: // most of the times, Content-Types are already all lower cased. ohair@286: // String.toLowerCase() works faster in this case, so even if you ohair@286: // are only doing one comparison, it pays off to use String.toLowerCase() ohair@286: // than String.equalsIgnoreCase(). When you do more than one comparison, ohair@286: // the benefits of String.toLowerCase() dominates. ohair@286: // ohair@286: // ohair@286: // for FI, ohair@286: // use application/fastinfoset for SOAP 1.1 ohair@286: // use application/soap+fastinfoset for SOAP 1.2 ohair@286: // to speed up comparisons, test methods always use lower cases. ohair@286: ohair@286: /** ohair@286: * @param primary ohair@286: * must be all lower case ohair@286: * @param sub ohair@286: * must be all lower case ohair@286: */ ohair@286: private static boolean isSoap1_1Type(String primary, String sub) { ohair@286: return primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml") ohair@286: || primary.equalsIgnoreCase("text") && sub.equalsIgnoreCase("xml-soap") ohair@286: || primary.equals("application") ohair@286: && sub.equals("fastinfoset"); ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param type ohair@286: * must be all lower case ohair@286: */ ohair@286: private static boolean isEqualToSoap1_1Type(String type) { ohair@286: return type.startsWith("text/xml") || ohair@286: type.startsWith("application/fastinfoset"); ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param primary ohair@286: * must be all lower case ohair@286: * @param sub ohair@286: * must be all lower case ohair@286: */ ohair@286: private static boolean isSoap1_2Type(String primary, String sub) { ohair@286: return primary.equals("application") ohair@286: && (sub.equals("soap+xml") ohair@286: || sub.equals("soap+fastinfoset")); ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param type ohair@286: * must be all lower case ohair@286: */ ohair@286: private static boolean isEqualToSoap1_2Type(String type) { ohair@286: return type.startsWith("application/soap+xml") || ohair@286: type.startsWith("application/soap+fastinfoset"); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Construct a new message. This will be invoked before message ohair@286: * sends. ohair@286: */ ohair@286: protected MessageImpl() { ohair@286: this(false, false); ohair@286: attachmentsInitialized = true; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Construct a new message. This will be invoked before message ohair@286: * sends. ohair@286: */ ohair@286: protected MessageImpl(boolean isFastInfoset, boolean acceptFastInfoset) { ohair@286: this.isFastInfoset = isFastInfoset; ohair@286: this.acceptFastInfoset = acceptFastInfoset; ohair@286: ohair@286: headers = new MimeHeaders(); ohair@286: headers.setHeader("Accept", getExpectedAcceptHeader()); ohair@286: contentType = new ContentType(); ohair@286: } ohair@286: ohair@286: /** ohair@286: * Shallow copy. ohair@286: */ ohair@286: protected MessageImpl(SOAPMessage msg) { ohair@286: if (!(msg instanceof MessageImpl)) { ohair@286: // don't know how to handle this. ohair@286: } ohair@286: MessageImpl src = (MessageImpl) msg; ohair@286: this.headers = src.headers; ohair@286: this.soapPartImpl = src.soapPartImpl; ohair@286: this.attachments = src.attachments; ohair@286: this.saved = src.saved; ohair@286: this.messageBytes = src.messageBytes; ohair@286: this.messageByteCount = src.messageByteCount; ohair@286: this.properties = src.properties; ohair@286: this.contentType = src.contentType; ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param stat ohair@286: * the mask value obtained from {@link #identifyContentType(ContentType)} ohair@286: */ ohair@286: protected static boolean isSoap1_1Content(int stat) { ohair@286: return (stat & SOAP1_1_FLAG) != 0; ohair@286: } ohair@286: ohair@286: /** ohair@286: * @param stat ohair@286: * the mask value obtained from {@link #identifyContentType(ContentType)} ohair@286: */ ohair@286: protected static boolean isSoap1_2Content(int stat) { ohair@286: return (stat & SOAP1_2_FLAG) != 0; ohair@286: } ohair@286: ohair@286: private static boolean isMimeMultipartXOPSoap1_2Package(ContentType contentType) { ohair@286: String type = contentType.getParameter("type"); ohair@286: if (type == null) { ohair@286: return false; ohair@286: } ohair@286: type = type.toLowerCase(); ohair@286: if (!type.startsWith("application/xop+xml")) { ohair@286: return false; ohair@286: } ohair@286: String startinfo = contentType.getParameter("start-info"); ohair@286: if (startinfo == null) { ohair@286: return false; ohair@286: } ohair@286: startinfo = startinfo.toLowerCase(); ohair@286: return isEqualToSoap1_2Type(startinfo); ohair@286: } ohair@286: ohair@286: ohair@286: //private static boolean isMimeMultipartXOPPackage(ContentType contentType) { ohair@286: private static boolean isMimeMultipartXOPSoap1_1Package(ContentType contentType) { ohair@286: String type = contentType.getParameter("type"); ohair@286: if(type==null) ohair@286: return false; ohair@286: ohair@286: type = type.toLowerCase(); ohair@286: if(!type.startsWith("application/xop+xml")) ohair@286: return false; ohair@286: ohair@286: String startinfo = contentType.getParameter("start-info"); ohair@286: if(startinfo == null) ohair@286: return false; ohair@286: startinfo = startinfo.toLowerCase(); ohair@286: return isEqualToSoap1_1Type(startinfo); ohair@286: } ohair@286: ohair@286: private static boolean isSOAPBodyXOPPackage(ContentType contentType){ ohair@286: String primary = contentType.getPrimaryType(); ohair@286: String sub = contentType.getSubType(); ohair@286: ohair@286: if (primary.equalsIgnoreCase("application")) { ohair@286: if (sub.equalsIgnoreCase("xop+xml")) { ohair@286: String type = getTypeParameter(contentType); ohair@286: return isEqualToSoap1_2Type(type) || isEqualToSoap1_1Type(type); ohair@286: } ohair@286: } ohair@286: return false; ohair@286: } ohair@286: ohair@286: /** ohair@286: * Construct a message from an input stream. When messages are ohair@286: * received, there's two parts -- the transport headers and the ohair@286: * message content in a transport specific stream. ohair@286: */ ohair@286: protected MessageImpl(MimeHeaders headers, final InputStream in) ohair@286: throws SOAPExceptionImpl { ohair@286: contentType = parseContentType(headers); ohair@286: init(headers,identifyContentType(contentType),contentType,in); ohair@286: } ohair@286: ohair@286: private static ContentType parseContentType(MimeHeaders headers) throws SOAPExceptionImpl { ohair@286: final String ct; ohair@286: if (headers != null) ohair@286: ct = getContentType(headers); ohair@286: else { ohair@286: log.severe("SAAJ0550.soap.null.headers"); ohair@286: throw new SOAPExceptionImpl("Cannot create message: " + ohair@286: "Headers can't be null"); ohair@286: } ohair@286: ohair@286: if (ct == null) { ohair@286: log.severe("SAAJ0532.soap.no.Content-Type"); ohair@286: throw new SOAPExceptionImpl("Absent Content-Type"); ohair@286: } ohair@286: try { ohair@286: return new ContentType(ct); ohair@286: } catch (Throwable ex) { ohair@286: log.severe("SAAJ0535.soap.cannot.internalize.message"); ohair@286: throw new SOAPExceptionImpl("Unable to internalize message", ex); ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Construct a message from an input stream. When messages are ohair@286: * received, there's two parts -- the transport headers and the ohair@286: * message content in a transport specific stream. ohair@286: * ohair@286: * @param contentType ohair@286: * The parsed content type header from the headers variable. ohair@286: * This is redundant parameter, but it avoids reparsing this header again. ohair@286: * @param stat ohair@286: * The result of {@link #identifyContentType(ContentType)} over ohair@286: * the contentType parameter. This redundant parameter, but it avoids ohair@286: * recomputing this information again. ohair@286: */ ohair@286: protected MessageImpl(MimeHeaders headers, final ContentType contentType, int stat, final InputStream in) throws SOAPExceptionImpl { ohair@286: init(headers, stat, contentType, in); ohair@286: ohair@286: } ohair@286: ohair@286: private void init(MimeHeaders headers, int stat, final ContentType contentType, final InputStream in) throws SOAPExceptionImpl { ohair@286: this.headers = headers; ohair@286: ohair@286: try { ohair@286: ohair@286: // Set isFastInfoset/acceptFastInfoset flag based on MIME type ohair@286: if ((stat & FI_ENCODED_FLAG) > 0) { ohair@286: isFastInfoset = acceptFastInfoset = true; ohair@286: } ohair@286: ohair@286: // If necessary, inspect Accept header to set acceptFastInfoset ohair@286: if (!isFastInfoset) { ohair@286: String[] values = headers.getHeader("Accept"); ohair@286: if (values != null) { ohair@286: for (int i = 0; i < values.length; i++) { ohair@286: StringTokenizer st = new StringTokenizer(values[i], ","); ohair@286: while (st.hasMoreTokens()) { ohair@286: final String token = st.nextToken().trim(); ohair@286: if (token.equalsIgnoreCase("application/fastinfoset") || ohair@286: token.equalsIgnoreCase("application/soap+fastinfoset")) { ohair@286: acceptFastInfoset = true; ohair@286: break; ohair@286: } ohair@286: } ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: if (!isCorrectSoapVersion(stat)) { ohair@286: log.log( ohair@286: Level.SEVERE, ohair@286: "SAAJ0533.soap.incorrect.Content-Type", ohair@286: new String[] { ohair@286: contentType.toString(), ohair@286: getExpectedContentType()}); ohair@286: throw new SOAPVersionMismatchException( ohair@286: "Cannot create message: incorrect content-type for SOAP version. Got: " ohair@286: + contentType ohair@286: + " Expected: " ohair@286: + getExpectedContentType()); ohair@286: } ohair@286: ohair@286: if ((stat & PLAIN_XML_FLAG) != 0) { ohair@286: if (isFastInfoset) { ohair@286: getSOAPPart().setContent( ohair@286: FastInfosetReflection.FastInfosetSource_new(in)); ohair@286: } else { ohair@286: initCharsetProperty(contentType); ohair@286: getSOAPPart().setContent(new StreamSource(in)); ohair@286: } ohair@286: } ohair@286: else if ((stat & MIME_MULTIPART_FLAG) != 0) { ohair@286: DataSource ds = new DataSource() { ohair@286: public InputStream getInputStream() { ohair@286: return in; ohair@286: } ohair@286: ohair@286: public OutputStream getOutputStream() { ohair@286: return null; ohair@286: } ohair@286: ohair@286: public String getContentType() { ohair@286: return contentType.toString(); ohair@286: } ohair@286: ohair@286: public String getName() { ohair@286: return ""; ohair@286: } ohair@286: }; ohair@286: ohair@286: multiPart = null; ohair@286: if (useMimePull) { ohair@286: multiPart = new MimePullMultipart(ds,contentType); ohair@286: } else if (switchOffBM) { ohair@286: multiPart = new MimeMultipart(ds,contentType); ohair@286: } else { ohair@286: multiPart = new BMMimeMultipart(ds,contentType); ohair@286: } ohair@286: ohair@286: String startParam = contentType.getParameter("start"); ohair@286: MimeBodyPart soapMessagePart = null; ohair@286: InputStream soapPartInputStream = null; ohair@286: String contentID = null; ohair@286: String contentIDNoAngle = null; ohair@286: if (switchOffBM || switchOffLazyAttachment) { ohair@286: if(startParam == null) { ohair@286: soapMessagePart = multiPart.getBodyPart(0); ohair@286: for (int i = 1; i < multiPart.getCount(); i++) { ohair@286: initializeAttachment(multiPart, i); ohair@286: } ohair@286: } else { ohair@286: soapMessagePart = multiPart.getBodyPart(startParam); ohair@286: for (int i = 0; i < multiPart.getCount(); i++) { ohair@286: contentID = multiPart.getBodyPart(i).getContentID(); ohair@286: // Old versions of AXIS2 put angle brackets around the content ohair@286: // id but not the start param ohair@286: contentIDNoAngle = (contentID != null) ? ohair@286: contentID.replaceFirst("^<", "").replaceFirst(">$", "") : null; ohair@286: if(!startParam.equals(contentID) && !startParam.equals(contentIDNoAngle)) ohair@286: initializeAttachment(multiPart, i); ohair@286: } ohair@286: } ohair@286: } else { ohair@286: if (useMimePull) { ohair@286: MimePullMultipart mpMultipart = (MimePullMultipart)multiPart; ohair@286: MIMEPart sp = mpMultipart.readAndReturnSOAPPart(); ohair@286: soapMessagePart = new MimeBodyPart(sp); ohair@286: soapPartInputStream = sp.readOnce(); ohair@286: } else { ohair@286: BMMimeMultipart bmMultipart = ohair@286: (BMMimeMultipart) multiPart; ohair@286: InputStream stream = bmMultipart.initStream(); ohair@286: ohair@286: SharedInputStream sin = null; ohair@286: if (stream instanceof SharedInputStream) { ohair@286: sin = (SharedInputStream) stream; ohair@286: } ohair@286: ohair@286: String boundary = "--" + ohair@286: contentType.getParameter("boundary"); ohair@286: byte[] bndbytes = ASCIIUtility.getBytes(boundary); ohair@286: if (startParam == null) { ohair@286: soapMessagePart = ohair@286: bmMultipart.getNextPart(stream, bndbytes, sin); ohair@286: bmMultipart.removeBodyPart(soapMessagePart); ohair@286: } else { ohair@286: MimeBodyPart bp = null; ohair@286: try { ohair@286: while (!startParam.equals(contentID) && !startParam.equals(contentIDNoAngle)) { ohair@286: bp = bmMultipart.getNextPart( ohair@286: stream, bndbytes, sin); ohair@286: contentID = bp.getContentID(); ohair@286: // Old versions of AXIS2 put angle brackets around the content ohair@286: // id but not the start param ohair@286: contentIDNoAngle = (contentID != null) ? ohair@286: contentID.replaceFirst("^<", "").replaceFirst(">$", "") : null; ohair@286: } ohair@286: soapMessagePart = bp; ohair@286: bmMultipart.removeBodyPart(bp); ohair@286: } catch (Exception e) { ohair@286: throw new SOAPExceptionImpl(e); ohair@286: } ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: if (soapPartInputStream == null && soapMessagePart != null) { ohair@286: soapPartInputStream = soapMessagePart.getInputStream(); ohair@286: } ohair@286: ohair@286: ContentType soapPartCType = new ContentType( ohair@286: soapMessagePart.getContentType()); ohair@286: initCharsetProperty(soapPartCType); ohair@286: String baseType = soapPartCType.getBaseType().toLowerCase(); ohair@286: if(!(isEqualToSoap1_1Type(baseType) ohair@286: || isEqualToSoap1_2Type(baseType) ohair@286: || isSOAPBodyXOPPackage(soapPartCType))) { ohair@286: log.log(Level.SEVERE, ohair@286: "SAAJ0549.soap.part.invalid.Content-Type", ohair@286: new Object[] {baseType}); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Bad Content-Type for SOAP Part : " + ohair@286: baseType); ohair@286: } ohair@286: ohair@286: SOAPPart soapPart = getSOAPPart(); ohair@286: setMimeHeaders(soapPart, soapMessagePart); ohair@286: soapPart.setContent(isFastInfoset ? ohair@286: (Source) FastInfosetReflection.FastInfosetSource_new( ohair@286: soapPartInputStream) : ohair@286: (Source) new StreamSource(soapPartInputStream)); ohair@286: } else { ohair@286: log.severe("SAAJ0534.soap.unknown.Content-Type"); ohair@286: throw new SOAPExceptionImpl("Unrecognized Content-Type"); ohair@286: } ohair@286: } catch (Throwable ex) { ohair@286: log.severe("SAAJ0535.soap.cannot.internalize.message"); ohair@286: throw new SOAPExceptionImpl("Unable to internalize message", ex); ohair@286: } ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: public boolean isFastInfoset() { ohair@286: return isFastInfoset; ohair@286: } ohair@286: ohair@286: public boolean acceptFastInfoset() { ohair@286: return acceptFastInfoset; ohair@286: } ohair@286: ohair@286: public void setIsFastInfoset(boolean value) { ohair@286: if (value != isFastInfoset) { ohair@286: isFastInfoset = value; ohair@286: if (isFastInfoset) { ohair@286: acceptFastInfoset = true; ohair@286: } ohair@286: saved = false; // ensure transcoding if necessary ohair@286: } ohair@286: } ohair@286: ohair@286: public Object getProperty(String property) { ohair@286: return (String) properties.get(property); ohair@286: } ohair@286: ohair@286: public void setProperty(String property, Object value) { ohair@286: verify(property, value); ohair@286: properties.put(property, value); ohair@286: } ohair@286: ohair@286: private void verify(String property, Object value) { ohair@286: if (property.equalsIgnoreCase(SOAPMessage.WRITE_XML_DECLARATION)) { ohair@286: if (!("true".equals(value) || "false".equals(value))) ohair@286: throw new RuntimeException( ohair@286: property + " must have value false or true"); ohair@286: ohair@286: try { ohair@286: EnvelopeImpl env = (EnvelopeImpl) getSOAPPart().getEnvelope(); ohair@286: if ("true".equalsIgnoreCase((String)value)) { ohair@286: env.setOmitXmlDecl("no"); ohair@286: } else if ("false".equalsIgnoreCase((String)value)) { ohair@286: env.setOmitXmlDecl("yes"); ohair@286: } ohair@286: } catch (Exception e) { ohair@286: log.log(Level.SEVERE, "SAAJ0591.soap.exception.in.set.property", ohair@286: new Object[] {e.getMessage(), "javax.xml.soap.write-xml-declaration"}); ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: return; ohair@286: } ohair@286: ohair@286: if (property.equalsIgnoreCase(SOAPMessage.CHARACTER_SET_ENCODING)) { ohair@286: try { ohair@286: ((EnvelopeImpl) getSOAPPart().getEnvelope()).setCharsetEncoding((String)value); ohair@286: } catch (Exception e) { ohair@286: log.log(Level.SEVERE, "SAAJ0591.soap.exception.in.set.property", ohair@286: new Object[] {e.getMessage(), "javax.xml.soap.character-set-encoding"}); ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: protected abstract boolean isCorrectSoapVersion(int contentTypeId); ohair@286: ohair@286: protected abstract String getExpectedContentType(); ohair@286: protected abstract String getExpectedAcceptHeader(); ohair@286: ohair@286: /** ohair@286: * Sniffs the Content-Type header so that we can determine how to process. ohair@286: * ohair@286: *

ohair@286: * In the absence of type attribute we assume it to be text/xml. ohair@286: * That would mean we're easy on accepting the message and ohair@286: * generate the correct thing (as the SWA spec also specifies ohair@286: * that the type parameter should always be text/xml) ohair@286: * ohair@286: * @return ohair@286: * combination of flags, such as PLAIN_XML_CODE and MIME_MULTIPART_CODE. ohair@286: */ ohair@286: // SOAP1.2 allow SOAP1.2 content type ohair@286: static int identifyContentType(ContentType ct) ohair@286: throws SOAPExceptionImpl { ohair@286: // TBD ohair@286: // Is there anything else we need to verify here? ohair@286: ohair@286: String primary = ct.getPrimaryType().toLowerCase(); ohair@286: String sub = ct.getSubType().toLowerCase(); ohair@286: ohair@286: if (primary.equals("multipart")) { ohair@286: if (sub.equals("related")) { ohair@286: String type = getTypeParameter(ct); ohair@286: if (isEqualToSoap1_1Type(type)) { ohair@286: return (type.equals("application/fastinfoset") ? ohair@286: FI_ENCODED_FLAG : 0) | MIME_MULTIPART_FLAG | SOAP1_1_FLAG; ohair@286: } ohair@286: else if (isEqualToSoap1_2Type(type)) { ohair@286: return (type.equals("application/soap+fastinfoset") ? ohair@286: FI_ENCODED_FLAG : 0) | MIME_MULTIPART_FLAG | SOAP1_2_FLAG; ohair@286: /*} else if (isMimeMultipartXOPPackage(ct)) { ohair@286: return MIME_MULTIPART_XOP_FLAG;*/ ohair@286: } else if (isMimeMultipartXOPSoap1_1Package(ct)) { ohair@286: return MIME_MULTIPART_XOP_SOAP1_1_FLAG; ohair@286: } else if (isMimeMultipartXOPSoap1_2Package(ct)) { ohair@286: return MIME_MULTIPART_XOP_SOAP1_2_FLAG; ohair@286: } else { ohair@286: log.severe("SAAJ0536.soap.content-type.mustbe.multipart"); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Content-Type needs to be Multipart/Related " ohair@286: + "and with \"type=text/xml\" " ohair@286: + "or \"type=application/soap+xml\""); ohair@286: } ohair@286: } else { ohair@286: log.severe("SAAJ0537.soap.invalid.content-type"); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Invalid Content-Type: " + primary + '/' + sub); ohair@286: } ohair@286: } ohair@286: else if (isSoap1_1Type(primary, sub)) { ohair@286: return (primary.equalsIgnoreCase("application") ohair@286: && sub.equalsIgnoreCase("fastinfoset") ? ohair@286: FI_ENCODED_FLAG : 0) ohair@286: | PLAIN_XML_FLAG | SOAP1_1_FLAG; ohair@286: } ohair@286: else if (isSoap1_2Type(primary, sub)) { ohair@286: return (primary.equalsIgnoreCase("application") ohair@286: && sub.equalsIgnoreCase("soap+fastinfoset") ? ohair@286: FI_ENCODED_FLAG : 0) ohair@286: | PLAIN_XML_FLAG | SOAP1_2_FLAG; ohair@286: } else if(isSOAPBodyXOPPackage(ct)){ ohair@286: return XOP_FLAG; ohair@286: } else { ohair@286: log.severe("SAAJ0537.soap.invalid.content-type"); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Invalid Content-Type:" ohair@286: + primary ohair@286: + '/' ohair@286: + sub ohair@286: + ". Is this an error message instead of a SOAP response?"); ohair@286: } ohair@286: } ohair@286: ohair@286: /** ohair@286: * Obtains the type parameter of the Content-Type header. Defaults to "text/xml". ohair@286: */ ohair@286: private static String getTypeParameter(ContentType contentType) { ohair@286: String p = contentType.getParameter("type"); ohair@286: if(p!=null) ohair@286: return p.toLowerCase(); ohair@286: else ohair@286: return "text/xml"; ohair@286: } ohair@286: ohair@286: public MimeHeaders getMimeHeaders() { ohair@286: return this.headers; ohair@286: } ohair@286: ohair@286: final static String getContentType(MimeHeaders headers) { ohair@286: String[] values = headers.getHeader("Content-Type"); ohair@286: if (values == null) ohair@286: return null; ohair@286: else ohair@286: return values[0]; ohair@286: } ohair@286: ohair@286: /* ohair@286: * Get the complete ContentType value along with optional parameters. ohair@286: */ ohair@286: public String getContentType() { ohair@286: return getContentType(this.headers); ohair@286: } ohair@286: ohair@286: public void setContentType(String type) { ohair@286: headers.setHeader("Content-Type", type); ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: private ContentType contentType() { ohair@286: ContentType ct = null; ohair@286: try { ohair@286: String currentContent = getContentType(); ohair@286: if (currentContent == null) { ohair@286: return this.contentType; ohair@286: } ohair@286: ct = new ContentType(currentContent); ohair@286: } catch (Exception e) { ohair@286: // what to do here? ohair@286: } ohair@286: return ct; ohair@286: } ohair@286: ohair@286: /* ohair@286: * Return the MIME type string, without the parameters. ohair@286: */ ohair@286: public String getBaseType() { ohair@286: return contentType().getBaseType(); ohair@286: } ohair@286: ohair@286: public void setBaseType(String type) { ohair@286: ContentType ct = contentType(); ohair@286: ct.setParameter("type", type); ohair@286: headers.setHeader("Content-Type", ct.toString()); ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: public String getAction() { ohair@286: return contentType().getParameter("action"); ohair@286: } ohair@286: ohair@286: public void setAction(String action) { ohair@286: ContentType ct = contentType(); ohair@286: ct.setParameter("action", action); ohair@286: headers.setHeader("Content-Type", ct.toString()); ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: public String getCharset() { ohair@286: return contentType().getParameter("charset"); ohair@286: } ohair@286: ohair@286: public void setCharset(String charset) { ohair@286: ContentType ct = contentType(); ohair@286: ct.setParameter("charset", charset); ohair@286: headers.setHeader("Content-Type", ct.toString()); ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: /** ohair@286: * All write methods (i.e setters) should call this method in ohair@286: * order to make sure that a save is necessary since the state ohair@286: * has been modified. ohair@286: */ ohair@286: private final void needsSave() { ohair@286: saved = false; ohair@286: } ohair@286: ohair@286: public boolean saveRequired() { ohair@286: return saved != true; ohair@286: } ohair@286: ohair@286: public String getContentDescription() { ohair@286: String[] values = headers.getHeader("Content-Description"); ohair@286: if (values != null && values.length > 0) ohair@286: return values[0]; ohair@286: return null; ohair@286: } ohair@286: ohair@286: public void setContentDescription(String description) { ohair@286: headers.setHeader("Content-Description", description); ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: public abstract SOAPPart getSOAPPart(); ohair@286: ohair@286: public void removeAllAttachments() { ohair@286: try { ohair@286: initializeAllAttachments(); ohair@286: } catch (Exception e) { ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: ohair@286: if (attachments != null) { ohair@286: attachments.clear(); ohair@286: needsSave(); ohair@286: } ohair@286: } ohair@286: ohair@286: public int countAttachments() { ohair@286: try { ohair@286: initializeAllAttachments(); ohair@286: } catch (Exception e) { ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: if (attachments != null) ohair@286: return attachments.size(); ohair@286: return 0; ohair@286: } ohair@286: ohair@286: public void addAttachmentPart(AttachmentPart attachment) { ohair@286: try { ohair@286: initializeAllAttachments(); ohair@286: this.optimizeAttachmentProcessing = true; ohair@286: } catch (Exception e) { ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: if (attachments == null) ohair@286: attachments = new FinalArrayList(); ohair@286: ohair@286: attachments.add(attachment); ohair@286: ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: static private final Iterator nullIter = Collections.EMPTY_LIST.iterator(); ohair@286: ohair@286: public Iterator getAttachments() { ohair@286: try { ohair@286: initializeAllAttachments(); ohair@286: } catch (Exception e) { ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: if (attachments == null) ohair@286: return nullIter; ohair@286: return attachments.iterator(); ohair@286: } ohair@286: ohair@286: private void setFinalContentType(String charset) { ohair@286: ContentType ct = contentType(); ohair@286: if (ct == null) { ohair@286: ct = new ContentType(); ohair@286: } ohair@286: String[] split = getExpectedContentType().split("/"); ohair@286: ct.setPrimaryType(split[0]); ohair@286: ct.setSubType(split[1]); ohair@286: ct.setParameter("charset", charset); ohair@286: headers.setHeader("Content-Type", ct.toString()); ohair@286: } ohair@286: ohair@286: private class MimeMatchingIterator implements Iterator { ohair@286: public MimeMatchingIterator(MimeHeaders headers) { ohair@286: this.headers = headers; ohair@286: this.iter = attachments.iterator(); ohair@286: } ohair@286: ohair@286: private Iterator iter; ohair@286: private MimeHeaders headers; ohair@286: private Object nextAttachment; ohair@286: ohair@286: public boolean hasNext() { ohair@286: if (nextAttachment == null) ohair@286: nextAttachment = nextMatch(); ohair@286: return nextAttachment != null; ohair@286: } ohair@286: ohair@286: public Object next() { ohair@286: if (nextAttachment != null) { ohair@286: Object ret = nextAttachment; ohair@286: nextAttachment = null; ohair@286: return ret; ohair@286: } ohair@286: ohair@286: if (hasNext()) ohair@286: return nextAttachment; ohair@286: ohair@286: return null; ohair@286: } ohair@286: ohair@286: Object nextMatch() { ohair@286: while (iter.hasNext()) { ohair@286: AttachmentPartImpl ap = (AttachmentPartImpl) iter.next(); ohair@286: if (ap.hasAllHeaders(headers)) ohair@286: return ap; ohair@286: } ohair@286: return null; ohair@286: } ohair@286: ohair@286: public void remove() { ohair@286: iter.remove(); ohair@286: } ohair@286: } ohair@286: ohair@286: public Iterator getAttachments(MimeHeaders headers) { ohair@286: try { ohair@286: initializeAllAttachments(); ohair@286: } catch (Exception e) { ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: if (attachments == null) ohair@286: return nullIter; ohair@286: ohair@286: return new MimeMatchingIterator(headers); ohair@286: } ohair@286: ohair@286: public void removeAttachments(MimeHeaders headers) { ohair@286: try { ohair@286: initializeAllAttachments(); ohair@286: } catch (Exception e) { ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: if (attachments == null) ohair@286: return ; ohair@286: ohair@286: Iterator it = new MimeMatchingIterator(headers); ohair@286: while (it.hasNext()) { ohair@286: int index = attachments.indexOf(it.next()); ohair@286: attachments.set(index, null); ohair@286: } ohair@286: FinalArrayList f = new FinalArrayList(); ohair@286: for (int i = 0; i < attachments.size(); i++) { ohair@286: if (attachments.get(i) != null) { ohair@286: f.add(attachments.get(i)); ohair@286: } ohair@286: } ohair@286: attachments = f; ohair@286: // needsSave(); ohair@286: } ohair@286: ohair@286: public AttachmentPart createAttachmentPart() { ohair@286: return new AttachmentPartImpl(); ohair@286: } ohair@286: ohair@286: public AttachmentPart getAttachment(SOAPElement element) ohair@286: throws SOAPException { ohair@286: try { ohair@286: initializeAllAttachments(); ohair@286: } catch (Exception e) { ohair@286: throw new RuntimeException(e); ohair@286: } ohair@286: String uri; ohair@286: String hrefAttr = element.getAttribute("href"); ohair@286: if ("".equals(hrefAttr)) { ohair@286: Node node = getValueNodeStrict(element); ohair@286: String swaRef = null; ohair@286: if (node != null) { ohair@286: swaRef = node.getValue(); ohair@286: } ohair@286: if (swaRef == null || "".equals(swaRef)) { ohair@286: return null; ohair@286: } else { ohair@286: uri = swaRef; ohair@286: } ohair@286: } else { ohair@286: uri = hrefAttr; ohair@286: } ohair@286: return getAttachmentPart(uri); ohair@286: } ohair@286: ohair@286: private Node getValueNodeStrict(SOAPElement element) { ohair@286: Node node = (Node)element.getFirstChild(); ohair@286: if (node != null) { ohair@286: if (node.getNextSibling() == null ohair@286: && node.getNodeType() == org.w3c.dom.Node.TEXT_NODE) { ohair@286: return node; ohair@286: } else { ohair@286: return null; ohair@286: } ohair@286: } ohair@286: return null; ohair@286: } ohair@286: ohair@286: ohair@286: private AttachmentPart getAttachmentPart(String uri) throws SOAPException { ohair@286: AttachmentPart _part; ohair@286: try { ohair@286: if (uri.startsWith("cid:")) { ohair@286: // rfc2392 ohair@286: uri = '<'+uri.substring("cid:".length())+'>'; ohair@286: ohair@286: MimeHeaders headersToMatch = new MimeHeaders(); ohair@286: headersToMatch.addHeader(CONTENT_ID, uri); ohair@286: ohair@286: Iterator i = this.getAttachments(headersToMatch); ohair@286: _part = (i == null) ? null : (AttachmentPart)i.next(); ohair@286: } else { ohair@286: // try content-location ohair@286: MimeHeaders headersToMatch = new MimeHeaders(); ohair@286: headersToMatch.addHeader(CONTENT_LOCATION, uri); ohair@286: ohair@286: Iterator i = this.getAttachments(headersToMatch); ohair@286: _part = (i == null) ? null : (AttachmentPart)i.next(); ohair@286: } ohair@286: ohair@286: // try auto-generated JAXRPC CID ohair@286: if (_part == null) { ohair@286: Iterator j = this.getAttachments(); ohair@286: ohair@286: while (j.hasNext()) { ohair@286: AttachmentPart p = (AttachmentPart)j.next(); ohair@286: String cl = p.getContentId(); ohair@286: if (cl != null) { ohair@286: // obtain the partname ohair@286: int eqIndex = cl.indexOf("="); ohair@286: if (eqIndex > -1) { ohair@286: cl = cl.substring(1, eqIndex); ohair@286: if (cl.equalsIgnoreCase(uri)) { ohair@286: _part = p; ohair@286: break; ohair@286: } ohair@286: } ohair@286: } ohair@286: } ohair@286: } ohair@286: ohair@286: } catch (Exception se) { ohair@286: log.log(Level.SEVERE, "SAAJ0590.soap.unable.to.locate.attachment", new Object[] {uri}); ohair@286: throw new SOAPExceptionImpl(se); ohair@286: } ohair@286: return _part; ohair@286: } ohair@286: ohair@286: private final InputStream getHeaderBytes() ohair@286: throws IOException { ohair@286: SOAPPartImpl sp = (SOAPPartImpl) getSOAPPart(); ohair@286: return sp.getContentAsStream(); ohair@286: } ohair@286: ohair@286: private String convertToSingleLine(String contentType) { ohair@286: StringBuffer buffer = new StringBuffer(); ohair@286: for (int i = 0; i < contentType.length(); i ++) { ohair@286: char c = contentType.charAt(i); ohair@286: if (c != '\r' && c != '\n' && c != '\t') ohair@286: buffer.append(c); ohair@286: } ohair@286: return buffer.toString(); ohair@286: } ohair@286: ohair@286: private MimeMultipart getMimeMessage() throws SOAPException { ohair@286: try { ohair@286: SOAPPartImpl soapPart = (SOAPPartImpl) getSOAPPart(); ohair@286: MimeBodyPart mimeSoapPart = soapPart.getMimePart(); ohair@286: ohair@286: /* ohair@286: * Get content type from this message instead of soapPart ohair@286: * to ensure agreement if soapPart is transcoded (XML <-> FI) ohair@286: */ ohair@286: ContentType soapPartCtype = new ContentType(getExpectedContentType()); ohair@286: ohair@286: if (!isFastInfoset) { ohair@286: soapPartCtype.setParameter("charset", initCharset()); ohair@286: } ohair@286: mimeSoapPart.setHeader("Content-Type", soapPartCtype.toString()); ohair@286: ohair@286: MimeMultipart headerAndBody = null; ohair@286: ohair@286: if (!switchOffBM && !switchOffLazyAttachment && ohair@286: (multiPart != null) && !attachmentsInitialized) { ohair@286: headerAndBody = new BMMimeMultipart(); ohair@286: headerAndBody.addBodyPart(mimeSoapPart); ohair@286: if (attachments != null) { ohair@286: for (Iterator eachAttachment = attachments.iterator(); ohair@286: eachAttachment.hasNext();) { ohair@286: headerAndBody.addBodyPart( ohair@286: ((AttachmentPartImpl) eachAttachment.next()) ohair@286: .getMimePart()); ohair@286: } ohair@286: } ohair@286: InputStream in = ((BMMimeMultipart)multiPart).getInputStream(); ohair@286: if (!((BMMimeMultipart)multiPart).lastBodyPartFound() && ohair@286: !((BMMimeMultipart)multiPart).isEndOfStream()) { ohair@286: ((BMMimeMultipart)headerAndBody).setInputStream(in); ohair@286: ((BMMimeMultipart)headerAndBody).setBoundary( ohair@286: ((BMMimeMultipart)multiPart).getBoundary()); ohair@286: ((BMMimeMultipart)headerAndBody). ohair@286: setLazyAttachments(lazyAttachments); ohair@286: } ohair@286: ohair@286: } else { ohair@286: headerAndBody = new MimeMultipart(); ohair@286: headerAndBody.addBodyPart(mimeSoapPart); ohair@286: ohair@286: for (Iterator eachAttachement = getAttachments(); ohair@286: eachAttachement.hasNext(); ohair@286: ) { ohair@286: headerAndBody.addBodyPart( ohair@286: ((AttachmentPartImpl) eachAttachement.next()) ohair@286: .getMimePart()); ohair@286: } ohair@286: } ohair@286: ohair@286: ContentType contentType = headerAndBody.getContentType(); ohair@286: ohair@286: ParameterList l = contentType.getParameterList(); ohair@286: ohair@286: // set content type depending on SOAP version ohair@286: l.set("type", getExpectedContentType()); ohair@286: l.set("boundary", contentType.getParameter("boundary")); ohair@286: ContentType nct = new ContentType("multipart", "related", l); ohair@286: ohair@286: headers.setHeader( ohair@286: "Content-Type", ohair@286: convertToSingleLine(nct.toString())); ohair@286: // TBD ohair@286: // Set content length MIME header here. ohair@286: ohair@286: return headerAndBody; ohair@286: } catch (SOAPException ex) { ohair@286: throw ex; ohair@286: } catch (Throwable ex) { ohair@286: log.severe("SAAJ0538.soap.cannot.convert.msg.to.multipart.obj"); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Unable to convert SOAP message into " ohair@286: + "a MimeMultipart object", ohair@286: ex); ohair@286: } ohair@286: } ohair@286: ohair@286: private String initCharset() { ohair@286: ohair@286: String charset = null; ohair@286: ohair@286: String[] cts = getMimeHeaders().getHeader("Content-Type"); ohair@286: if ((cts != null) && (cts[0] != null)) { ohair@286: charset = getCharsetString(cts[0]); ohair@286: } ohair@286: ohair@286: if (charset == null) { ohair@286: charset = (String) getProperty(CHARACTER_SET_ENCODING); ohair@286: } ohair@286: ohair@286: if (charset != null) { ohair@286: return charset; ohair@286: } ohair@286: ohair@286: return "utf-8"; ohair@286: } ohair@286: ohair@286: private String getCharsetString(String s) { ohair@286: try { ohair@286: int index = s.indexOf(";"); ohair@286: if(index < 0) ohair@286: return null; ohair@286: ParameterList pl = new ParameterList(s.substring(index)); ohair@286: return pl.get("charset"); ohair@286: } catch(Exception e) { ohair@286: return null; ohair@286: } ohair@286: } ohair@286: ohair@286: public void saveChanges() throws SOAPException { ohair@286: ohair@286: // suck in all the data from the attachments and have it ohair@286: // ready for writing/sending etc. ohair@286: ohair@286: String charset = initCharset(); ohair@286: ohair@286: /*if (countAttachments() == 0) {*/ ohair@286: int attachmentCount = (attachments == null) ? 0 : attachments.size(); ohair@286: if (attachmentCount == 0) { ohair@286: if (!switchOffBM && !switchOffLazyAttachment && ohair@286: !attachmentsInitialized && (multiPart != null)) { ohair@286: // so there might be attachments ohair@286: attachmentCount = 1; ohair@286: } ohair@286: } ohair@286: ohair@286: try { ohair@286: if ((attachmentCount == 0) && !hasXOPContent()) { ohair@286: InputStream in; ohair@286: try{ ohair@286: /* ohair@286: * Not sure why this is called getHeaderBytes(), but it actually ohair@286: * returns the whole message as a byte stream. This stream could ohair@286: * be either XML of Fast depending on the mode. ohair@286: */ ohair@286: in = getHeaderBytes(); ohair@286: // no attachments, hence this property can be false ohair@286: this.optimizeAttachmentProcessing = false; ohair@286: if (SOAPPartImpl.lazyContentLength) { ohair@286: inputStreamAfterSaveChanges = in; ohair@286: } ohair@286: } catch (IOException ex) { ohair@286: log.severe("SAAJ0539.soap.cannot.get.header.stream"); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Unable to get header stream in saveChanges: ", ohair@286: ex); ohair@286: } ohair@286: ohair@286: if (in instanceof ByteInputStream) { ohair@286: ByteInputStream bIn = (ByteInputStream)in; ohair@286: messageBytes = bIn.getBytes(); ohair@286: messageByteCount = bIn.getCount(); ohair@286: } ohair@286: ohair@286: setFinalContentType(charset); ohair@286: /* ohair@286: headers.setHeader( ohair@286: "Content-Type", ohair@286: getExpectedContentType() + ohair@286: (isFastInfoset ? "" : "; charset=" + charset));*/ ohair@286: if (messageByteCount > 0) { ohair@286: headers.setHeader( ohair@286: "Content-Length", ohair@286: Integer.toString(messageByteCount)); ohair@286: } ohair@286: } else { ohair@286: if(hasXOPContent()) ohair@286: mmp = getXOPMessage(); ohair@286: else ohair@286: mmp = getMimeMessage(); ohair@286: } ohair@286: } catch (Throwable ex) { ohair@286: log.severe("SAAJ0540.soap.err.saving.multipart.msg"); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Error during saving a multipart message", ohair@286: ex); ohair@286: } ohair@286: ohair@286: // FIX ME -- SOAP Action replaced by Content-Type optional parameter action ohair@286: /* ohair@286: if(isCorrectSoapVersion(SOAP1_1_FLAG)) { ohair@286: ohair@286: String[] soapAction = headers.getHeader("SOAPAction"); ohair@286: ohair@286: if (soapAction == null || soapAction.length == 0) ohair@286: headers.setHeader("SOAPAction", "\"\""); ohair@286: ohair@286: } ohair@286: */ ohair@286: ohair@286: saved = true; ohair@286: } ohair@286: ohair@286: private MimeMultipart getXOPMessage() throws SOAPException { ohair@286: try { ohair@286: MimeMultipart headerAndBody = new MimeMultipart(); ohair@286: SOAPPartImpl soapPart = (SOAPPartImpl)getSOAPPart(); ohair@286: MimeBodyPart mimeSoapPart = soapPart.getMimePart(); ohair@286: ContentType soapPartCtype = ohair@286: new ContentType("application/xop+xml"); ohair@286: soapPartCtype.setParameter("type", getExpectedContentType()); ohair@286: String charset = initCharset(); ohair@286: soapPartCtype.setParameter("charset", charset); ohair@286: mimeSoapPart.setHeader("Content-Type", soapPartCtype.toString()); ohair@286: headerAndBody.addBodyPart(mimeSoapPart); ohair@286: ohair@286: for (Iterator eachAttachement = getAttachments(); ohair@286: eachAttachement.hasNext(); ohair@286: ) { ohair@286: headerAndBody.addBodyPart( ohair@286: ((AttachmentPartImpl) eachAttachement.next()) ohair@286: .getMimePart()); ohair@286: } ohair@286: ohair@286: ContentType contentType = headerAndBody.getContentType(); ohair@286: ohair@286: ParameterList l = contentType.getParameterList(); ohair@286: ohair@286: //lets not write start-info for now till we get servlet fix done ohair@286: l.set("start-info", getExpectedContentType());//+";charset="+initCharset()); ohair@286: ohair@286: // set content type depending on SOAP version ohair@286: l.set("type", "application/xop+xml"); ohair@286: ohair@286: if (isCorrectSoapVersion(SOAP1_2_FLAG)) { ohair@286: String action = getAction(); ohair@286: if(action != null) ohair@286: l.set("action", action); ohair@286: } ohair@286: ohair@286: l.set("boundary", contentType.getParameter("boundary")); ohair@286: ContentType nct = new ContentType("Multipart", "Related", l); ohair@286: headers.setHeader( ohair@286: "Content-Type", ohair@286: convertToSingleLine(nct.toString())); ohair@286: // TBD ohair@286: // Set content length MIME header here. ohair@286: ohair@286: return headerAndBody; ohair@286: } catch (SOAPException ex) { ohair@286: throw ex; ohair@286: } catch (Throwable ex) { ohair@286: log.severe("SAAJ0538.soap.cannot.convert.msg.to.multipart.obj"); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Unable to convert SOAP message into " ohair@286: + "a MimeMultipart object", ohair@286: ex); ohair@286: } ohair@286: ohair@286: } ohair@286: ohair@286: private boolean hasXOPContent() throws ParseException { ohair@286: String type = getContentType(); ohair@286: if(type == null) ohair@286: return false; ohair@286: ContentType ct = new ContentType(type); ohair@286: //return isMimeMultipartXOPPackage(ct) || isSOAPBodyXOPPackage(ct); ohair@286: return isMimeMultipartXOPSoap1_1Package(ct) || ohair@286: isMimeMultipartXOPSoap1_2Package(ct) || isSOAPBodyXOPPackage(ct); ohair@286: ohair@286: } ohair@286: ohair@286: public void writeTo(OutputStream out) throws SOAPException, IOException { ohair@286: if (saveRequired()){ ohair@286: this.optimizeAttachmentProcessing = true; ohair@286: saveChanges(); ohair@286: } ohair@286: ohair@286: if(!optimizeAttachmentProcessing){ ohair@286: if (SOAPPartImpl.lazyContentLength && messageByteCount <= 0) { ohair@286: byte[] buf = new byte[1024]; ohair@286: ohair@286: int length = 0; ohair@286: while( (length = inputStreamAfterSaveChanges.read(buf)) != -1) { ohair@286: out.write(buf,0, length); ohair@286: messageByteCount += length; ohair@286: } ohair@286: if (messageByteCount > 0) { ohair@286: headers.setHeader( ohair@286: "Content-Length", ohair@286: Integer.toString(messageByteCount)); ohair@286: } ohair@286: } else { ohair@286: out.write(messageBytes, 0, messageByteCount); ohair@286: } ohair@286: } ohair@286: else{ ohair@286: try{ ohair@286: if(hasXOPContent()){ ohair@286: mmp.writeTo(out); ohair@286: }else{ ohair@286: mmp.writeTo(out); ohair@286: if (!switchOffBM && !switchOffLazyAttachment && ohair@286: (multiPart != null) && !attachmentsInitialized) { ohair@286: ((BMMimeMultipart)multiPart).setInputStream( ohair@286: ((BMMimeMultipart)mmp).getInputStream()); ohair@286: } ohair@286: } ohair@286: } catch(Exception ex){ ohair@286: log.severe("SAAJ0540.soap.err.saving.multipart.msg"); ohair@286: throw new SOAPExceptionImpl( ohair@286: "Error during saving a multipart message", ohair@286: ex); ohair@286: } ohair@286: } ohair@286: ohair@286: if(isCorrectSoapVersion(SOAP1_1_FLAG)) { ohair@286: ohair@286: String[] soapAction = headers.getHeader("SOAPAction"); ohair@286: ohair@286: if (soapAction == null || soapAction.length == 0) ohair@286: headers.setHeader("SOAPAction", "\"\""); ohair@286: ohair@286: } ohair@286: ohair@286: messageBytes = null; ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: public SOAPBody getSOAPBody() throws SOAPException { ohair@286: SOAPBody body = getSOAPPart().getEnvelope().getBody(); ohair@286: /*if (body == null) { ohair@286: throw new SOAPException("No SOAP Body was found in the SOAP Message"); ohair@286: }*/ ohair@286: return body; ohair@286: } ohair@286: ohair@286: public SOAPHeader getSOAPHeader() throws SOAPException { ohair@286: SOAPHeader hdr = getSOAPPart().getEnvelope().getHeader(); ohair@286: /*if (hdr == null) { ohair@286: throw new SOAPException("No SOAP Header was found in the SOAP Message"); ohair@286: }*/ ohair@286: return hdr; ohair@286: } ohair@286: ohair@286: private void initializeAllAttachments () ohair@286: throws MessagingException, SOAPException { ohair@286: if (switchOffBM || switchOffLazyAttachment) { ohair@286: return; ohair@286: } ohair@286: ohair@286: if (attachmentsInitialized || (multiPart == null)) { ohair@286: return; ohair@286: } ohair@286: ohair@286: if (attachments == null) ohair@286: attachments = new FinalArrayList(); ohair@286: ohair@286: int count = multiPart.getCount(); ohair@286: for (int i=0; i < count; i++ ) { ohair@286: initializeAttachment(multiPart.getBodyPart(i)); ohair@286: } ohair@286: attachmentsInitialized = true; ohair@286: //multiPart = null; ohair@286: needsSave(); ohair@286: } ohair@286: ohair@286: private void initializeAttachment(MimeBodyPart mbp) throws SOAPException { ohair@286: AttachmentPartImpl attachmentPart = new AttachmentPartImpl(); ohair@286: DataHandler attachmentHandler = mbp.getDataHandler(); ohair@286: attachmentPart.setDataHandler(attachmentHandler); ohair@286: ohair@286: AttachmentPartImpl.copyMimeHeaders(mbp, attachmentPart); ohair@286: attachments.add(attachmentPart); ohair@286: } ohair@286: ohair@286: private void initializeAttachment(MimeMultipart multiPart, int i) ohair@286: throws Exception { ohair@286: MimeBodyPart currentBodyPart = multiPart.getBodyPart(i); ohair@286: AttachmentPartImpl attachmentPart = new AttachmentPartImpl(); ohair@286: ohair@286: DataHandler attachmentHandler = currentBodyPart.getDataHandler(); ohair@286: attachmentPart.setDataHandler(attachmentHandler); ohair@286: ohair@286: AttachmentPartImpl.copyMimeHeaders(currentBodyPart, attachmentPart); ohair@286: addAttachmentPart(attachmentPart); ohair@286: } ohair@286: ohair@286: private void setMimeHeaders(SOAPPart soapPart, ohair@286: MimeBodyPart soapMessagePart) throws Exception { ohair@286: ohair@286: // first remove the existing content-type ohair@286: soapPart.removeAllMimeHeaders(); ohair@286: // add everything present in soapMessagePart ohair@286: List headers = soapMessagePart.getAllHeaders(); ohair@286: int sz = headers.size(); ohair@286: for( int i=0; i