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

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